feat(ui): menus déroulants + fenêtres flottantes, barre unique et sélecteur de projet (#16)

Lot A du sprint UI rework : réorganisation de la navigation racine.

- shared/ui/MenuBar.tsx : barre de menus unique avec menus déroulants
- shared/ui/FloatingWindow.tsx : primitive de fenêtre flottante réutilisable
  (socle du lot C #17 fenêtre dédiée gestion tickets)
- shared/ui/zIndex.ts : échelle z-index étendue pour les fenêtres flottantes
- App : intègre la barre unique et le sélecteur de projet permanent
- ProjectsView : sélecteur de projet permanent

Tests : tsc --noEmit clean, suite complète 527/527, suites impactées 33/33.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-06 20:55:37 +02:00
parent 0218e3271f
commit c55f948d25
9 changed files with 933 additions and 353 deletions

View File

@ -8,9 +8,9 @@ import { useEffect, useState } from "react";
import type { DomainEvent, HealthReport } from "@/domain";
import { ProjectsView } from "@/features/projects";
import { FirstRunWizard, ProfilesSettings } from "@/features/first-run";
import { FirstRunWizard } from "@/features/first-run";
import { AnnouncementsProvider } from "@/features/announcements";
import { Button, Panel, Spinner, Toolbar } from "@/shared";
import { Panel, Spinner, Toolbar } from "@/shared";
import { useGateways, shouldUseMock } from "./di";
export function App() {
@ -20,7 +20,6 @@ export function App() {
const [events, setEvents] = useState<DomainEvent[]>([]);
// First-run gating: null while loading, then true (wizard) / false (normal).
const [firstRun, setFirstRun] = useState<boolean | null>(null);
const [showSettings, setShowSettings] = useState(false);
useEffect(() => {
let unsub: (() => void) | undefined;
@ -89,15 +88,6 @@ export function App() {
</span>
)}
</span>
{!firstRun && (
<Button
size="sm"
variant={showSettings ? "secondary" : "ghost"}
onClick={() => setShowSettings((v) => !v)}
>
{showSettings ? "Close settings" : "AI Profiles"}
</Button>
)}
</Toolbar>
</header>
@ -117,16 +107,9 @@ export function App() {
<FirstRunWizard onDone={() => setFirstRun(false)} />
</div>
</div>
) : showSettings ? (
// Settings is a full scrollable view (its "Configure profiles" reopens
// the wizard, which can also exceed the viewport height).
<div className="flex flex-1 justify-center overflow-y-auto p-6">
<div className="w-full max-w-2xl">
<ProfilesSettings />
</div>
</div>
) : (
// ProjectsView owns the full remaining area (its own IDE layout).
// ProjectsView owns the full remaining area (its own IDE layout,
// single menu bar, and the AI Profiles view switch — ticket #16).
<ProjectsView />
)}
</div>