Files
arboretum/packages/web/src/composables/useNav.ts
Johan LEROY 693e6736de feat(web): lien « Buy me a coffee » (nav, réglages, funding)
- constante BUYMEACOFFEE_URL ; item de nav « Offrez-moi un café »
- section support dans les Réglages + i18n EN/FR
- champ `funding` dans le package.json publié ; mentions README EN/FR
2026-06-18 17:02:30 +02:00

51 lines
2.4 KiB
TypeScript

import { computed, type Component } from 'vue';
import { useRoute, type RouteLocationRaw } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { Boxes, Coffee, GitBranch, LifeBuoy, Settings, TerminalSquare } from '@lucide/vue';
import { useSessionsStore } from '../stores/sessions';
import GiteaIcon from '../components/ui/GiteaIcon.vue';
import { BUYMEACOFFEE_URL, REPO_SOURCE_URL } from '../lib/constants';
export interface NavEntry {
key: string;
/** route interne (exclusif avec `href`). */
to?: RouteLocationRaw;
/** lien externe ouvert dans un nouvel onglet (exclusif avec `to`). */
href?: string;
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,
);
// Onglets principaux : barre du bas mobile + haut de sidebar.
const primary = 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 },
]);
// Onglets secondaires : réglages, aide, et lien externe « Code source » (en dur, toujours présent).
const secondary = computed<NavEntry[]>(() => [
{ key: 'settings', to: { name: 'settings' }, icon: Settings, label: t('nav.settings'), match: ['settings'], badge: 0 },
{ key: 'help', to: { name: 'help' }, icon: LifeBuoy, label: t('nav.help'), match: ['help'], badge: 0 },
{ key: 'gitea', href: REPO_SOURCE_URL, icon: GiteaIcon, label: t('nav.gitea'), match: [], badge: 0 },
{ key: 'buymeacoffee', href: BUYMEACOFFEE_URL, icon: Coffee, label: t('nav.buymeacoffee'), match: [], badge: 0 },
]);
const isActive = (match: string[]): boolean => match.includes(String(route.name));
return { primary, secondary, isActive, waitingCount };
}