managarten/docs/central-services/COMMAND-BAR.md
Till-JS ee42b6cc76 feat: major update with network graphs, themes, todo extensions, and more
## New Features

### Network Graph Visualization (Contacts, Calendar, Todo)
- D3.js force simulation for physics-based layout
- Zoom & pan with mouse/touchpad
- Keyboard shortcuts: +/- zoom, 0 reset, Esc deselect, / search, F focus
- Filtering by tags, company/location/project, connection strength
- Shared components in @manacore/shared-ui

### Central Tags API (mana-core-auth)
- CRUD endpoints for tags
- Schema: tags table with userId, name, color, app
- Shared tag components in @manacore/shared-ui

### Custom Themes System
- Theme editor with live preview and color picker
- Community theme gallery
- Theme sharing (public, unlisted, private)
- Backend API in mana-core-auth

### Todo App Extensions
- Glass-pill design for task input and items
- Settings page with 20+ preferences
- Task edit modal with inline editing
- Statistics page with visualizations
- PWA support with offline capabilities
- Multiple kanban boards

### Contacts App Features
- Duplicate detection
- Photo upload
- Batch operations
- Enhanced favorites page with multiple view modes
- Alphabet view improvements
- Search modal

### Help System
- @manacore/shared-help-content
- @manacore/shared-help-ui
- @manacore/shared-help-types

### Other Features
- Themes page for all apps
- Referral system frontend
- CommandBar (global search)
- Skeleton loaders
- Settings page improvements

## Bug Fixes
- Network graph simulation initialization
- Database schema TEXT for user_id columns (Better Auth compatibility)
- Various styling fixes

## Documentation
- Daily report for 2025-12-10
- CI/CD deployment guide

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 02:37:46 +01:00

12 KiB

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:

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):

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

interface Props {
  open: boolean;                               // Sichtbarkeit
  onClose: () => void;                        // Schließen-Handler
  onSearch: (query: string) => Promise<CommandBarItem[]>;  // 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

<script lang="ts">
  import { goto } from '$app/navigation';
  import { CommandBar } from '@manacore/shared-ui';
  import type { CommandBarItem, QuickAction } from '@manacore/shared-ui';

  let commandBarOpen = $state(false);

  // Quick Actions definieren
  const quickActions: QuickAction[] = [
    { id: 'new', label: 'Neu erstellen', icon: 'plus', href: '/new', shortcut: 'N' },
    { id: 'settings', label: 'Einstellungen', icon: 'settings', href: '/settings' },
  ];

  // Such-Funktion implementieren
  async function handleSearch(query: string): Promise<CommandBarItem[]> {
    const results = await api.search(query);
    return results.map((item) => ({
      id: item.id,
      title: item.name,
      subtitle: item.description,
    }));
  }

  // Auswahl verarbeiten
  function handleSelect(item: CommandBarItem) {
    goto(`/item/${item.id}`);
  }

  // Keyboard Shortcut registrieren
  function handleKeydown(event: KeyboardEvent) {
    if ((event.ctrlKey || event.metaKey) && event.key === 'k') {
      event.preventDefault();
      commandBarOpen = true;
    }
  }
</script>

<svelte:window onkeydown={handleKeydown} />

<CommandBar
  bind:open={commandBarOpen}
  onClose={() => (commandBarOpen = false)}
  onSearch={handleSearch}
  onSelect={handleSelect}
  {quickActions}
  placeholder="Suchen..."
  emptyText="Keine Ergebnisse"
  searchingText="Suche..."
/>

App-spezifische Implementierungen

Todo App

// 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<CommandBarItem[]> {
  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

// 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<CommandBarItem[]> {
  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

// 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<CommandBarItem[]> {
  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:

.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:

<!-- src/routes/(app)/+layout.svelte -->
<script lang="ts">
  import { CommandBar } from '@manacore/shared-ui';

  let commandBarOpen = $state(false);

  function handleKeydown(event: KeyboardEvent) {
    // Cmd/Ctrl+K funktioniert auch in Input-Feldern
    if ((event.ctrlKey || event.metaKey) && event.key === 'k') {
      event.preventDefault();
      commandBarOpen = true;
    }
  }
</script>

<svelte:window onkeydown={handleKeydown} />

<!-- Haupt-Layout -->
<PillNavigation ... />

<main>
  {@render children()}
</main>

<!-- Command Bar (global) -->
<CommandBar
  bind:open={commandBarOpen}
  onClose={() => (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