# Central Command Bar Die zentrale Command Bar bietet eine einheitliche Schnellsuche und Navigation über alle Manacore-Apps hinweg. Sie wird mit `Cmd/Ctrl+K` aktiviert und bietet Suche, Quick Actions und Tastatur-Navigation. ## Architektur ``` ┌─────────────────────────────────────────────────────────────┐ │ @manacore/shared-ui │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ CommandBar.svelte │ │ │ │ - Suche mit Debounce (150ms) │ │ │ │ - Quick Actions │ │ │ │ - Tastatur-Navigation │ │ │ │ - Ergebnis-Anzeige mit Avataren │ │ │ └─────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ ┌────────────────────┼────────────────────┐ │ │ │ ┌────▼────┐ ┌─────▼────┐ ┌─────▼────┐ │ Todo │ │ Calendar │ │ Contacts │ │ │ │ │ │ │ │ Sucht │ │ Sucht │ │ Sucht │ │ Tasks │ │ Events │ │ Kontakte │ └─────────┘ └──────────┘ └──────────┘ ``` ## Package | Package | Beschreibung | |---------|--------------| | `@manacore/shared-ui` | CommandBar Svelte-Komponente + TypeScript-Typen | ## Keyboard Shortcut | Shortcut | Aktion | |----------|--------| | `Cmd/Ctrl+K` | Command Bar öffnen | | `↑↓` | Navigation durch Ergebnisse | | `Enter` | Auswahl bestätigen | | `Escape` | Schließen | ## TypeScript Interfaces ### CommandBarItem Ein Suchergebnis: ```typescript interface CommandBarItem { id: string; // Eindeutige ID title: string; // Haupttext (z.B. Name, Titel) subtitle?: string; // Untertitel (z.B. Datum, E-Mail) icon?: string; // Icon-Name imageUrl?: string; // Avatar/Bild URL isFavorite?: boolean; // Favorit-Markierung (zeigt Herz-Icon) } ``` ### QuickAction Eine Schnellaktion (ohne Suche): ```typescript interface QuickAction { id: string; // Eindeutige ID label: string; // Anzeigetext icon: string; // Icon-Name href?: string; // Link-Ziel (optional) shortcut?: string; // Tastenkürzel-Anzeige onclick?: () => void; // Click-Handler (alternativ zu href) } ``` ### Unterstützte Icons Die CommandBar unterstützt folgende eingebaute Icons: | Icon-Name | Beschreibung | |-----------|--------------| | `plus` | Plus-Zeichen (Neu erstellen) | | `heart` | Herz (Favoriten) | | `tag` | Tag/Label | | `upload` | Upload (Import) | | `calendar` | Kalender | | `clock` | Uhr | | `check` | Häkchen | | `settings` | Zahnrad (Einstellungen) | | `list` | Liste | ## Komponenten-Props ```typescript interface Props { open: boolean; // Sichtbarkeit onClose: () => void; // Schließen-Handler onSearch: (query: string) => Promise; // Such-Funktion onSelect: (item: CommandBarItem) => void; // Auswahl-Handler quickActions?: QuickAction[]; // Schnellaktionen placeholder?: string; // Suchfeld-Placeholder emptyText?: string; // Text bei leeren Ergebnissen searchingText?: string; // Text während Suche } ``` ## Nutzung ### Basis-Beispiel ```svelte (commandBarOpen = false)} onSearch={handleSearch} onSelect={handleSelect} {quickActions} placeholder="Suchen..." emptyText="Keine Ergebnisse" searchingText="Suche..." /> ``` ## App-spezifische Implementierungen ### Todo App ```typescript // Quick Actions const quickActions: QuickAction[] = [ { id: 'new', label: 'Neue Aufgabe erstellen', icon: 'plus', href: '/task/new', shortcut: 'N' }, { id: 'kanban', label: 'Kanban-Board', icon: 'list', href: '/kanban' }, { id: 'stats', label: 'Statistiken', icon: 'chart', href: '/statistics' }, { id: 'settings', label: 'Einstellungen', icon: 'settings', href: '/settings' }, ]; // Suche: Tasks durchsuchen async function handleSearch(query: string): Promise { const tasks = await getTasks({ search: query }); return tasks.slice(0, 10).map((task) => ({ id: task.id, title: task.title, subtitle: task.isCompleted ? '✓ Erledigt' : task.dueDate ? new Date(task.dueDate).toLocaleDateString('de-DE') : 'Kein Datum', })); } // Auswahl: Zu Task navigieren function handleSelect(item: CommandBarItem) { goto(`/task/${item.id}`); } ``` ### Calendar App ```typescript // Quick Actions const quickActions: QuickAction[] = [ { id: 'new', label: 'Neuen Termin erstellen', icon: 'plus', href: '/event/new', shortcut: 'N' }, { id: 'today', label: 'Zu Heute springen', icon: 'calendar', onclick: () => viewStore.goToToday() }, { id: 'agenda', label: 'Agenda anzeigen', icon: 'list', href: '/agenda' }, { id: 'settings', label: 'Einstellungen', icon: 'settings', href: '/settings' }, ]; // Suche: Events durchsuchen async function handleSearch(query: string): Promise { const result = await searchEvents(query); if (result.error || !result.data) return []; return result.data.slice(0, 10).map((event) => ({ id: event.id, title: event.title, subtitle: format(new Date(event.startTime), 'dd. MMM yyyy, HH:mm', { locale: de }), })); } // Auswahl: Zu Event navigieren function handleSelect(item: CommandBarItem) { goto(`/event/${item.id}`); } ``` ### Contacts App ```typescript // Quick Actions const quickActions: QuickAction[] = [ { id: 'new', label: 'Neuen Kontakt erstellen', icon: 'plus', href: '/contacts/new', shortcut: 'N' }, { id: 'favorites', label: 'Favoriten anzeigen', icon: 'heart', href: '/favorites' }, { id: 'tags', label: 'Tags verwalten', icon: 'tag', href: '/tags' }, { id: 'import', label: 'Kontakte importieren', icon: 'upload', href: '/data?tab=import' }, ]; // Suche: Kontakte durchsuchen async function handleSearch(query: string): Promise { const response = await contactsApi.list({ search: query, limit: 10 }); return (response.contacts || []).map((contact) => ({ id: contact.id, title: contact.displayName || [contact.firstName, contact.lastName].filter(Boolean).join(' ') || contact.email || 'Unbekannt', subtitle: contact.company || contact.email, imageUrl: contact.photoUrl, isFavorite: contact.isFavorite, })); } // Auswahl: Kontakt-Modal öffnen function handleSelect(item: CommandBarItem) { goto(`/contacts/${item.id}`); } ``` ## Funktionen ### Suche - **Debounce:** 150ms Verzögerung für Performance - **Loading-State:** Spinner während der Suche - **Empty State:** Konfigurierbare Meldung bei keinen Ergebnissen - **Limit:** Ergebnisse werden typischerweise auf 10 begrenzt ### Quick Actions Wenn kein Suchtext eingegeben ist, werden Quick Actions angezeigt: - Navigation mit Pfeiltasten - Ausführung mit Enter - Keyboard-Shortcuts werden rechts angezeigt ### Ergebnis-Anzeige - **Avatar:** Bild oder Initialen - **Titel:** Haupttext - **Untertitel:** Zusatzinfo (grau) - **Favorit:** Herz-Icon wenn `isFavorite: true` - **Hover:** Visuelles Feedback bei Maus-Over ### Keyboard Navigation | Taste | Aktion | |-------|--------| | `↑` / `↓` | Durch Ergebnisse navigieren | | `Enter` | Ausgewähltes Element öffnen | | `Escape` | Command Bar schließen | ## Styling Die Command Bar verwendet ein dunkles Theme mit CSS-Variablen: ```css .command-modal { background: #1a1a1a; border: 1px solid #333; border-radius: 12px; max-width: 560px; } .command-result.selected { background: #2a2a2a; } .result-avatar { background: #3b82f6; /* Primary Color */ } .result-favorite { color: #ef4444; /* Rot für Herz */ } ``` ### Animationen - **Fade In:** Backdrop erscheint mit 0.15s - **Slide In:** Modal gleitet von oben mit 0.2s - **Loading Spinner:** Rotation Animation ## Integration in Layout Typischerweise wird die CommandBar im App-Layout integriert: ```svelte
{@render children()}
(commandBarOpen = false)} onSearch={handleSearch} onSelect={handleSelect} {quickActions} /> ``` ## Dateien ### @manacore/shared-ui | Datei | Beschreibung | |-------|--------------| | `src/command-bar/CommandBar.svelte` | Hauptkomponente | | `src/command-bar/index.ts` | Exports | | `src/index.ts` | Package-Export | ## Vorteile - **Einheitliche UX:** Gleiche Interaktion in allen Apps - **Schnelle Navigation:** Sofortiger Zugriff auf häufige Aktionen - **Tastatur-fokussiert:** Optimiert für Power-User - **Flexibel:** App-spezifische Such-Logik und Quick Actions - **Responsive:** Funktioniert auf Desktop und Mobile ## Best Practices 1. **Such-Performance:** Limit auf 10 Ergebnisse setzen 2. **Quick Actions:** Maximal 4-5 Aktionen für Übersichtlichkeit 3. **Sinnvolle Shortcuts:** Mnemonische Kürzel (N=Neu, S=Settings) 4. **Gute Subtitles:** Zusätzliche Info für eindeutige Identifikation 5. **Keyboard First:** Cmd+K sollte immer funktionieren, auch in Input-Feldern