feat: refonte UX du dashboard (coquille, tri/filtre/pagination, ⌘K, toasts)
Refonte front (packages/web) : coquille applicative partagée (sidebar desktop + barre d'onglets mobile + PageHeader, langue/push/logout centralisés) pilotée par route.meta.layout ; design system (BaseButton/BaseBadge/SegmentedControl/EmptyState/ SkeletonRow, anneau de focus, icônes @lucide/vue) ; tri/filtre/recherche/pagination côté client via useListControls (+ synchro URL) sur sessions/worktrees/groupes ; section « À traiter », palette de commandes ⌘K, toasts. Aucune modif serveur/protocole/DB.
This commit is contained in:
36
packages/web/src/composables/useNav.ts
Normal file
36
packages/web/src/composables/useNav.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { computed, type Component } from 'vue';
|
||||
import { useRoute, type RouteLocationRaw } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { GitBranch, TerminalSquare, Boxes } from '@lucide/vue';
|
||||
import { useSessionsStore } from '../stores/sessions';
|
||||
|
||||
export interface NavEntry {
|
||||
key: string;
|
||||
to: RouteLocationRaw;
|
||||
icon: Component;
|
||||
label: string;
|
||||
match: string[]; // noms de routes considérés actifs pour cet item
|
||||
badge: number;
|
||||
}
|
||||
|
||||
/** Définition unique de la navigation, partagée par la sidebar et la barre d'onglets. */
|
||||
export function useNav() {
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const sessions = useSessionsStore();
|
||||
|
||||
// sessions vivantes bloquées sur un dialogue (le cœur de la supervision mobile).
|
||||
const waitingCount = computed(
|
||||
() => sessions.sessions.filter((s) => s.live && s.activity === 'waiting').length,
|
||||
);
|
||||
|
||||
const items = computed<NavEntry[]>(() => [
|
||||
{ key: 'worktrees', to: { name: 'dashboard' }, icon: GitBranch, label: t('nav.worktrees'), match: ['dashboard'], badge: 0 },
|
||||
{ key: 'sessions', to: { name: 'sessions' }, icon: TerminalSquare, label: t('nav.sessions'), match: ['sessions', 'session'], badge: waitingCount.value },
|
||||
{ key: 'groups', to: { name: 'groups' }, icon: Boxes, label: t('nav.groups'), match: ['groups', 'group'], badge: 0 },
|
||||
]);
|
||||
|
||||
const isActive = (match: string[]): boolean => match.includes(String(route.name));
|
||||
|
||||
return { items, isActive, waitingCount };
|
||||
}
|
||||
Reference in New Issue
Block a user