L'IDE (/ide) devient l'unique interface sur tous les supports (navigateur, PWA, app Electron chargent la même SPA). Tout le cycle de vie de l'ancien monde est réintégré dans l'IDE ; AppShell et les vues Dashboard / Sessions / Groups / GroupView / SessionView sont supprimés. - Infra: pile de modals Teleport (stores/modals.ts + ModalHost) et menu contextuel (useContextMenu + ContextMenu), montés dans IdeShell sans le démonter (attaches WS du dock préservées). - Explorer: créer worktree (branche + baseRef + session), travailler sur main, prune, promote (escalade force), supprimer worktree, commit/push, masquer/ supprimer repo, ajouter dépôt local ou cloner. - Sessions: create/kill/resume/fork, hide/unhide, archive/unarchive, masquer les découvertes, supervision AttentionList + réponse aux dialogues. - Groupes: create/delete, composition, lancement de session de groupe (ouvre le terminal dans le dock). - Compte: Réglages et Aide en overlays par-dessus l'IDE ; langue, push/PWA, tokens, connexions git, RGPD, déconnexion. Command Palette et deep-links recâblés pour rester dans l'IDE. - Routes: les anciens chemins rendent IdeShell via meta (overlay/panel/ terminal) ; /workspace/:repoId/:wt inchangé (contrat extension VS Code). Mobile: nav à 6 panneaux (explorer/editor/terminal/git/sessions/groups). La grille multi-terminaux de groupe est retirée (supplantée par la session de groupe unique P6 via --add-dir + le dock multi-onglets).
72 lines
3.1 KiB
Vue
72 lines
3.1 KiB
Vue
<template>
|
|
<nav class="flex w-[var(--ide-activitybar-w)] shrink-0 flex-col items-center gap-1 border-r border-border bg-surface-1 py-2">
|
|
<button
|
|
v-for="item in items"
|
|
:key="item.view"
|
|
type="button"
|
|
class="relative flex h-10 w-10 items-center justify-center rounded-lg transition-colors"
|
|
:class="isActive(item.view) ? 'bg-surface-3 text-fg' : 'text-fg-subtle hover:bg-surface-2 hover:text-fg'"
|
|
:title="item.label"
|
|
:aria-label="item.label"
|
|
@click="ide.toggleActivity(item.view)"
|
|
>
|
|
<component :is="item.icon" :size="20" :stroke-width="1.75" />
|
|
<span
|
|
v-if="item.badge"
|
|
class="absolute top-1 right-1 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"
|
|
>
|
|
{{ item.badge }}
|
|
</span>
|
|
</button>
|
|
|
|
<div class="mt-auto flex flex-col items-center gap-1">
|
|
<button
|
|
v-for="l in links"
|
|
:key="l.key"
|
|
type="button"
|
|
:title="l.label"
|
|
:aria-label="l.label"
|
|
class="flex h-10 w-10 items-center justify-center rounded-lg text-fg-subtle transition-colors hover:bg-surface-2 hover:text-fg"
|
|
@click="l.onSelect"
|
|
>
|
|
<component :is="l.icon" :size="20" :stroke-width="1.75" />
|
|
</button>
|
|
</div>
|
|
</nav>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, defineAsyncComponent } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { Boxes, FolderTree, GitCompare, LifeBuoy, LogOut, Settings, SquareTerminal } from '@lucide/vue';
|
|
import { useIdeStore, type ActivityView } from '../../stores/ide';
|
|
import { useModalsStore } from '../../stores/modals';
|
|
import { useNav } from '../../composables/useNav';
|
|
import { useSession } from '../../composables/useSession';
|
|
|
|
const { t } = useI18n();
|
|
const ide = useIdeStore();
|
|
const modals = useModalsStore();
|
|
const { waitingCount } = useNav();
|
|
const { logout } = useSession();
|
|
|
|
// Overlays chargés en lazy : SettingsView/HelpView (lourds) restent hors du chunk principal de l'IDE.
|
|
const SettingsOverlay = defineAsyncComponent(() => import('./overlays/SettingsOverlay.vue'));
|
|
const HelpOverlay = defineAsyncComponent(() => import('./overlays/HelpOverlay.vue'));
|
|
|
|
const isActive = (v: ActivityView): boolean => ide.activeActivity === v && ide.leftVisible;
|
|
|
|
const items = computed(() => [
|
|
{ view: 'explorer' as ActivityView, icon: FolderTree, label: t('ide.activity.explorer'), badge: 0 },
|
|
{ view: 'git' as ActivityView, icon: GitCompare, label: t('ide.activity.git'), badge: 0 },
|
|
{ view: 'sessions' as ActivityView, icon: SquareTerminal, label: t('ide.activity.sessions'), badge: waitingCount.value },
|
|
{ view: 'groups' as ActivityView, icon: Boxes, label: t('ide.activity.groups'), badge: 0 },
|
|
]);
|
|
|
|
const links = computed(() => [
|
|
{ key: 'settings', icon: Settings, label: t('nav.settings'), onSelect: () => void modals.open(SettingsOverlay) },
|
|
{ key: 'help', icon: LifeBuoy, label: t('nav.help'), onSelect: () => void modals.open(HelpOverlay) },
|
|
{ key: 'logout', icon: LogOut, label: t('common.logout'), onSelect: () => void logout() },
|
|
]);
|
|
</script>
|