# Cmd/Ctrl+K Command Palette — Design **Task:** t-paliad-044 **Author:** cronus (inventor) **Date:** 2026-04-26 **Status:** Design — awaiting m's go/no-go before coder shift --- ## Decision: Option B — full command palette (with strict scope guardrails) The brief offered two scopes. Rationale for picking B: 1. **`pwa-baseline.md` is explicit** — multi-entity sites ship a command palette; single-entity sites can skip it. Paliad has 8 entity types (projects, deadlines, appointments, glossary, courts, checklists, links, users), so it is squarely in the "ship a palette" bucket. 2. **80% of the infrastructure already exists.** `frontend/src/client/search.ts` has sectioned grouped results, keyboard navigation (↑↓ / ↵ / Esc), i18n group headers, debounce + AbortController, an in-flight cancellation pattern, and language-switch re-render. Adding an *Actions* section on top is incremental, not a rewrite. 3. **Patent lawyers are heavy keyboard users on desktop.** The HLC / HLC-Munich audience drafts long documents; Cmd+K → "Neue Frist" without leaving the keyboard is genuinely valuable. Sidebar nav is already always-visible on desktop, so the *navigate-to* actions are quality-of-life — but the *create* actions ("Neue Frist", "Neuer Termin", "Neues Projekt") are real time saves. 4. **Going A first feels like a half-step.** A "/" key alias for Cmd+K is five lines of code, but everyone who hits Cmd+K and sees only entity search will wonder where "Gehe zu Dashboard" / "Neue Frist anlegen" are. We'd be back here in two weeks anyway. 5. **Template value.** Paliad is the first paliad-stack PWA to fully implement the pwa-baseline `SearchPalette` reference. Doing it right here makes the pattern reusable for the next mAi PWA project. --- ## Scope guardrails (what is NOT in this design) - ❌ Fuzzy matching library — substring match on DE+EN labels is sufficient for ~20 actions and small entity result sets. Add `fuse.js` only if the catalog passes ~50 entries, which is unlikely to happen in 2026. - ❌ Recently-used persistence / localStorage MRU — defer. We can add a `paliad-palette-recent` key later if telemetry shows users repeating the same 3-4 actions. - ❌ Action groups beyond Aktionen / Projekte / Fristen / … — no meta-categories like "Werkzeuge", "Wissen". Keep flat. - ❌ Extension API or plugin registry — the action catalog is a single static array in `palette-actions.ts`. Future sections can be added by editing that file; no need for a registration callback. - ❌ Cross-project search — out of scope per task brief. - ❌ AI-powered ranking — out of scope per task brief. - ❌ Action shortcut keys beyond Cmd+K itself (e.g. `g d` to go to Dashboard). Maybe later; not now. - ❌ Recent entities — show entity results only when the user types. --- ## Trigger surface | Trigger | Behavior | Platform | |---------------------|----------------------------------------------|----------| | `Cmd+K` (Mac) | Open palette + focus input. `preventDefault`. | desktop | | `Ctrl+K` (Win/Lin) | Same. | desktop | | `/` (slash) | Same — kept for muscle memory (shipped t-paliad-026). | desktop | | Click sidebar input | Same — focuses the input directly. | desktop | | `Esc` | Close + clear input. | all | | BottomNav menu → drawer → search input | Existing path on mobile. | mobile | ### Why not a dedicated mobile slot The BottomNav (5 slots: Start / Projekte / Anlegen / Agenda / Menü) is full. Replacing one would degrade an established pattern. The mobile sidebar drawer (opened via Menü or hamburger) already contains the same `#global-search-input`, so a tap-search path exists. **Mobile users get the palette via the drawer, not a dedicated button.** Revisit if telemetry shows mobile users searching often enough to justify a topbar search icon. ### Browser-native Ctrl+K suppression `Ctrl+K` in Firefox/Chrome focuses the URL bar's "search engine" submenu (rare but exists). In Safari, `Cmd+L` focuses the URL bar but `Cmd+K` is unbound. We `preventDefault()` on the document-level keydown handler whenever the key combo matches and **only** when a textarea / input is not already focused with a non-`#global-search-input` element — same skip-rule as the existing `/` shortcut. --- ## UX shape ### Empty state (Cmd+K just pressed, input empty) Show all actions, sectioned under "Aktionen". Don't fetch entity search. The user can see the catalog at a glance — this is the "discoverability mode" of the palette. ``` ┌──────────────────────────────────────────────────┐ │ 🔍 ____________________________________________ │ ← #global-search-input ├──────────────────────────────────────────────────┤ │ AKTIONEN │ │ 📊 Gehe zu Dashboard │ │ 📁 Gehe zu Projekte │ │ ⏰ Gehe zu Fristen │ │ 📅 Gehe zu Termine │ │ 🗓 Gehe zu Agenda │ │ 📖 Gehe zu Glossar │ │ 🏛 Gehe zu Gerichte │ │ 🔗 Gehe zu Links │ │ ✓ Gehe zu Checklisten │ │ ⬇ Gehe zu Downloads │ │ ⚙ Gehe zu Einstellungen │ │ ➕ Neue Frist anlegen │ │ ➕ Neuer Termin anlegen │ │ ➕ Neues Projekt anlegen │ │ 🌐 Sprache umschalten (DE → EN) │ │ 📌 Sidebar anheften / lösen │ │ ✉ Kolleg:in einladen │ │ ↪ Abmelden │ ├──────────────────────────────────────────────────┤ │ ↑↓ Navigieren · ↵ Öffnen · Esc Schließen │ ← footer hint └──────────────────────────────────────────────────┘ ``` ### Filtered state (user typed at least 1 char) Both Actions (filtered by substring on DE+EN labels) AND entity search results (via existing `/api/search?q=...`) render together, Actions on top. ``` Query: "frist" ┌──────────────────────────────────────────────────┐ │ 🔍 frist │ ├──────────────────────────────────────────────────┤ │ AKTIONEN │ │ ⏰ Gehe zu Fristen │ │ ➕ Neue Frist anlegen │ │ FRISTEN │ │ ⏰ Klagebeantwortung — UPC-2024-0042 │ │ ⏰ Replik einreichen — Patent EP1234567 │ │ GLOSSAR │ │ 📖 Frist (Definition + Berechnung) │ └──────────────────────────────────────────────────┘ ``` ### Footer keyboard hints A small `