feat(web): coquille IDE + arbre de projets unifié (route /ide)
Some checks failed
CI / Build & test (Node 24) (push) Has been cancelled
CI / Pack & boot smoke (Node 22) (push) Has been cancelled
CI / No em/en dashes (push) Has been cancelled
CI / Build & test (Node 22) (push) Has been cancelled

components/ide/ : IdeShell (grille barre d'activité + panneau gauche + zone centrale + dock + barre de statut, splitters persistés, réconciliation des ressources ouvertes contre les données live), ActivityBar (Explorer/Git/Sessions/Groupes + Réglages/Aide), PrimarySidebar, ProjectTree + ProjectTreeNode (arbre unique repos -> worktrees -> sessions, fichiers embarqués via FileTree en mode sans chrome, dépliage paresseux), StatusBar.

Route /ide (layout 'ide'), entrée de nav « IDE », namespace i18n ide (EN/FR). Clics de l'arbre pilotent le store (contexte worktree, ouverture de fichier/terminal). Centre et dock en placeholders (remplis en B4/B5). FileTree gagne un mode embedded. 427 tests.
This commit is contained in:
2026-07-17 17:08:35 +02:00
parent 6acd4a16fd
commit c96d929c7a
13 changed files with 446 additions and 11 deletions

View File

@@ -1,12 +1,12 @@
<template>
<div class="flex h-full flex-col">
<div class="flex items-center gap-1 px-2 py-1 text-[11px] font-semibold uppercase tracking-wide text-zinc-500">
<div :class="embedded ? '' : 'flex h-full flex-col'">
<div v-if="!embedded" class="flex items-center gap-1 px-2 py-1 text-[11px] font-semibold uppercase tracking-wide text-zinc-500">
<FolderTree :size="13" /> {{ t('workspace.files') }}
<button type="button" class="ml-auto rounded p-0.5 hover:bg-zinc-800 hover:text-zinc-300" :title="t('common.refresh')" @click="load">
<RefreshCw :size="12" />
</button>
</div>
<div class="min-h-0 flex-1 overflow-auto px-1 pb-2">
<div :class="embedded ? '' : 'min-h-0 flex-1 overflow-auto px-1 pb-2'">
<p v-if="loading" class="px-2 py-1 text-xs text-zinc-600">{{ t('fs.loading') }}</p>
<p v-else-if="error" class="px-2 py-1 text-xs text-rose-400">{{ error }}</p>
<p v-else-if="entries.length === 0" class="px-2 py-1 text-xs text-zinc-600">{{ t('fs.empty') }}</p>
@@ -15,7 +15,7 @@
:key="e.path"
:entry="e"
:wt="wt"
:depth="0"
:depth="depth"
:active="active"
@open="(p) => emit('open', p)"
/>
@@ -31,7 +31,10 @@ import type { FsEntry, FsListResponse } from '@arboretum/shared';
import { api } from '../../lib/api';
import FileTreeNode from './FileTreeNode.vue';
const props = defineProps<{ wt: string; active: string | null }>();
const props = withDefaults(defineProps<{ wt: string; active: string | null; embedded?: boolean; depth?: number }>(), {
embedded: false,
depth: 0,
});
const emit = defineEmits<{ open: [relPath: string] }>();
const { t } = useI18n();