// Ribbon-Inhaltsleiste (docs/design/ribbon-ui-plan.md) — rendert den INHALT des // aktiven Ribbon-Tabs. Die Tab-REITER selbst sitzen in der TopBar-Zeile (eine // Leiste: globales Chrome + Tabs), damit es nur ZWEI Bänder gibt: TopBar-Zeile // (mit Tabs) oben, Ribbon-Inhalt darunter. Der aktive Tab wird als `tab`-Prop // hereingereicht (State liegt in App, geteilt mit der TopBar). // // Werkzeug-Elemente laufen über `onSelectTool` (gekoppelte Befehle inklusive, wie // in der Sidebar); Befehls-Elemente über `onRunCommand` (engine.start). Der // „Ansichten"-Tab trägt reichen Custom-Inhalt (`viewsContent`, aus der TopBar // gemergt) statt datengetriebener Item-Gruppen. // // Bezeichner englisch, UI-Text/Kommentare deutsch (CONVENTIONS.md). import type { ReactNode } from "react"; import { t } from "../../i18n"; import { ToolIcon } from "../../panels/ToolsPanel"; import { getTool } from "../../tools/tools"; import type { ToolId } from "../../tools/types"; import { getCommand } from "../../commands/registry"; import { RIBBON_TABS } from "./ribbonItems"; import type { RibbonItem, RibbonTabId } from "./ribbonItems"; import { CommandIcon } from "./CommandIcon"; export interface RibbonBarProps { /** Aktiver Tab (State liegt in App, geteilt mit den Reitern in der TopBar). */ tab: RibbonTabId; /** Aktives Werkzeug (Highlight der `tool`-Elemente). */ activeTool: ToolId; /** Name des laufenden Engine-Befehls (Highlight der `command`-Elemente). */ activeCommand: string | null; /** Ob Boden-gebundene (`floorOnly`) Werkzeuge nutzbar sind (aktives Geschoss). */ toolsEnabled: boolean; /** Werkzeug aktivieren (gleicher Pfad wie die Sidebar). */ onSelectTool: (id: ToolId) => void; /** Engine-Befehl starten (Ändern-Gruppe u. a.). */ onRunCommand: (name: string) => void; /** * Reicher Inhalt des „Ansichten"-Tabs (aus der TopBar gemergte Ansichts-/Zoom-/ * Darstellungs-Steuerung, `ViewRibbonTab`). Von App geliefert, damit dessen * Setter/State dort bleiben. Fehlt er, zeigt der Tab den Leer-Hinweis. */ viewsContent?: ReactNode; } /** Aktivierungs-/Highlight-Kontext, den jeder Button-Typ braucht. */ interface ButtonCtx { activeTool: ToolId; activeCommand: string | null; toolsEnabled: boolean; onSelectTool: (id: ToolId) => void; onRunCommand: (name: string) => void; } /** Ein einzelner Ribbon-Button (Werkzeug ODER Befehl). */ function RibbonButton({ item, ctx }: { item: RibbonItem; ctx: ButtonCtx }) { if (item.kind === "tool") { const tool = getTool(item.id); // Nur Boden-gebundene Werkzeuge sind ohne aktives Geschoss gesperrt; freie // 2D-Werkzeuge (Linie/Kreis/…) bleiben auch auf Zeichnungsebenen nutzbar. const disabled = !!tool.floorOnly && !ctx.toolsEnabled; const active = ctx.activeTool === item.id; const label = t(tool.labelKey); return ( ); } // Befehls-Element: Label aus der Befehls-Registry ableiten. const cmd = getCommand(item.name); const label = cmd ? t(cmd.labelKey) : item.name; const active = ctx.activeCommand === item.name; return ( ); } /** * Die Tab-REITER — als eigene Komponente exportiert, weil sie in der TopBar-Zeile * gerendert werden (nicht hier). Rein gesteuert über `tab`/`onTab`. */ export function RibbonTabs({ tab, onTab, }: { tab: RibbonTabId; onTab: (id: RibbonTabId) => void; }) { return (
{RIBBON_TABS.map((tt) => ( ))}
); } export function RibbonBar(props: RibbonBarProps) { const current = RIBBON_TABS.find((tt) => tt.id === props.tab) ?? RIBBON_TABS[0]; const ctx: ButtonCtx = { activeTool: props.activeTool, activeCommand: props.activeCommand, toolsEnabled: props.toolsEnabled, onSelectTool: props.onSelectTool, onRunCommand: props.onRunCommand, }; return (
{/* Inhalt des aktiven Tabs. Der „Ansichten"-Tab trägt reichen Custom-Inhalt (ViewRibbonTab) statt der datengetriebenen Item-Gruppen. */}
{current.id === "views" && props.viewsContent ? ( props.viewsContent ) : current.groups.length === 0 ? (
{t("ribbon.empty")}
) : ( current.groups.map((g) => (
{g.items.map((item) => ( ))}
{t(g.titleKey)}
)) )}
); }