import { useCallback, useMemo, useState } from "react" import { Command } from "cmdk" import { useNavigate } from "@tanstack/react-router" import { AlertTriangle, CornerDownLeft } from "lucide-react" import { useMC, usePaletteOffen } from "@/app/store" import { api } from "@/lib/api" import { cn } from "@/lib/utils" import { GRUPPEN_TITEL, befehle, suchtext, type Befehl, type BefehlsGruppe, } from "@/app/palette/register" // Befehlspalette 2.0 (v3-Umbau P6, Spezifikation §4.6). // // Vorher listete sie die elf Navigations-Einträge — ein Sprungbrett. Jetzt tippt man, // WAS man will, nicht wo es liegt: springen, tun, finden, oder den Text direkt als Idee // an Lucy geben. Das Register steht in app/palette/register.ts. // // Die Rückfrage ist keine Höflichkeit, sondern Absicht: Die Palette ist schnell genug, // dass „Strg+K, mot, Enter" den Motor neu startet, bevor man es zu Ende gedacht hat. // Befehle mit `rueckfrage` halten deshalb an und sagen erst, was passieren wird. const GRUPPEN_REIHE: BefehlsGruppe[] = ["gehe", "tun", "finden", "lucy"] export function CommandPalette() { const offen = usePaletteOffen() const palette = useMC((s) => s.palette) const melden = useMC((s) => s.melden) const navigate = useNavigate() const [text, setText] = useState("") const [nachfrage, setNachfrage] = useState(null) const [laeuft, setLaeuft] = useState(false) const schliessen = useCallback(() => { palette(false) setText("") setNachfrage(null) }, [palette]) const ausfuehren = useCallback(async (b: Befehl) => { setLaeuft(true) try { await b.ausfuehren({ text, navigate: (pfad) => navigate({ to: pfad }), schublade: (tab) => navigate({ to: ".", search: (a) => ({ ...a, system: tab }) }), melden, api, }) schliessen() } catch (e) { // Der echte Grund aus ApiError.detail (P1/B-14) — nicht „Fehler". melden("fehler", e instanceof Error ? e.message : String(e)) setNachfrage(null) } finally { setLaeuft(false) } }, [text, navigate, melden, schliessen]) const liste = useMemo(() => befehle(text), [text]) return ( (o ? palette(true) : schliessen())} label="Befehlspalette" className="fixed inset-0 z-50 flex items-start justify-center overscroll-contain bg-black/50 p-4 pt-[12vh]" onClick={schliessen} shouldFilter={!nachfrage} >
e.stopPropagation()} > {nachfrage ? ( // ── Zweistufige Rückfrage ────────────────────────────────────────

{nachfrage.rueckfrage}

) : ( <> Nichts gefunden. {GRUPPEN_REIHE.map((gruppe) => { const eintraege = liste.filter((b) => b.gruppe === gruppe) if (!eintraege.length) return null return ( {eintraege.map((b) => ( (b.rueckfrage ? setNachfrage(b) : ausfuehren(b))} className="flex cursor-pointer items-center gap-3 rounded-md px-3 py-2 text-sm text-foreground aria-selected:bg-accent aria-selected:text-accent-foreground" > ))} ) })}
↑↓ wählen esc schließt
)}
) }