"use client"; import { useEffect } from "react"; import { ArrowLeft, SlidersHorizontal } from "lucide-react"; import { findPart } from "@/lib/hive/find-part"; import type { HiveCatalog, HiveState } from "@/lib/hive/types"; import { GLASS_PILL, GLASS_SURFACE } from "./hive-glass"; import { formatAmount } from "./hive-scene/scene-model"; // DOM overlay of focus mode (spec 9.4): glass „Zurück“ pill, the part's name // and its state as small glass chips, „Ändern“ for parts with a sheet. // Esc leaves focus mode unless a dialog (sheet) has the keyboard. export interface FocusChip { key: string; text: string; } /** Chips for the focused part: frame count of a box, every state field with its value. */ export function focusChips(state: HiveState, catalog: HiveCatalog, id: string): FocusChip[] { const part = findPart(state, id); const type = part ? catalog.partTypes.get(part.partTypeId) : undefined; if (!part || !type) return []; const chips: FocusChip[] = []; if (type.kind === "BOX") { const frames = (part.frames ?? []).filter((frame) => frame.type !== "NONE").length; chips.push({ key: "frames", text: frames === 1 ? "1 Rähmchen" : `${frames} Rähmchen` }); } for (const field of type.stateSchema) { const raw = part.state[field.key]; if (field.kind === "level") { const value = typeof raw === "number" ? raw : 0; chips.push({ key: field.key, text: `${field.label} ${formatAmount(value, field.unit)} von ${formatAmount(field.max, field.unit)}` }); } else { const index = Math.max(0, field.options.indexOf(String(raw))); chips.push({ key: field.key, text: `${field.label}: ${field.optionLabels[index] ?? field.options[index]}` }); } } const inserts = (part.inserts ?? []).map((insert) => catalog.partTypes.get(insert.partTypeId)?.kind); if (type.kind === "FLOOR") chips.push({ key: "insert", text: inserts.includes("FLOOR_INSERT") ? "Bausperre drin" : "ohne Bausperre" }); return chips; } export interface HiveFocusBarProps { /** Part in focus mode; nothing is rendered without one. */ focusedId: string | null; name: string; chips: FocusChip[]; /** Shows „Ändern“ (the part has a sheet and the user may edit). */ canEdit: boolean; onEdit: () => void; onBack: () => void; } export function HiveFocusBar({ focusedId, name, chips, canEdit, onEdit, onBack }: HiveFocusBarProps) { useEffect(() => { if (!focusedId) return; const onKey = (event: KeyboardEvent) => { if (event.key !== "Escape" || event.defaultPrevented) return; // A sheet handles its own Esc. if (event.target instanceof Element && event.target.closest("[role='dialog'], [role='alertdialog']")) return; onBack(); }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [focusedId, onBack]); if (!focusedId) return null; // Fades in (150 ms); only at motion `full` it also slides down (motion-full variant, spec 9.8). return (

{name}

{chips.length > 0 || canEdit ? ( ) : null}
); }