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:
2026-06-18 11:47:36 +02:00
parent c1390bfe06
commit d6c110fc3b
41 changed files with 2416 additions and 448 deletions

View File

@@ -0,0 +1,50 @@
<template>
<RouterLink
:to="to"
:aria-current="active ? 'page' : undefined"
:class="orientation === 'col' ? colClass : rowClass"
>
<span class="relative">
<component :is="icon" :size="orientation === 'col' ? 20 : 18" :stroke-width="1.75" />
<span
v-if="badge"
class="absolute -right-1.5 -top-1.5 flex h-3.5 min-w-3.5 items-center justify-center rounded-full bg-amber-500 px-1 text-[9px] font-semibold text-amber-950"
>
{{ badge }}
</span>
</span>
<span :class="orientation === 'col' ? 'text-[10px]' : 'flex-1'">{{ label }}</span>
<span
v-if="badge && orientation === 'row'"
class="rounded-full bg-amber-500/20 px-1.5 text-[11px] font-semibold text-amber-300"
>
{{ badge }}
</span>
</RouterLink>
</template>
<script setup lang="ts">
import { computed, type Component } from 'vue';
import type { RouteLocationRaw } from 'vue-router';
const props = withDefaults(
defineProps<{
to: RouteLocationRaw;
icon: Component;
label: string;
badge?: number;
active?: boolean;
orientation?: 'row' | 'col';
}>(),
{ orientation: 'row' },
);
const rowClass = computed(() => [
'flex items-center gap-2.5 rounded-lg px-3 py-2 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-emerald-500/70',
props.active ? 'bg-zinc-800 text-zinc-100' : 'text-zinc-400 hover:bg-zinc-800/50 hover:text-zinc-200',
]);
const colClass = computed(() => [
'flex flex-1 flex-col items-center gap-0.5 py-2 transition-colors focus-visible:outline-none',
props.active ? 'text-emerald-400' : 'text-zinc-500 hover:text-zinc-300',
]);
</script>