Skip to main content

Documentation Index

Fetch the complete documentation index at: https://grantmaster.dev/llms.txt

Use this file to discover all available pages before exploring further.

Engineering reference: For service contracts, EventBus events, and data-layer details see src/features/command-palette/command-palette.md.

Command Palette

Overview

The command-palette feature provides a global keyboard-triggered command palette (⌘K / Ctrl+K) that allows users to navigate, create entities, run contextual actions, and invoke AI assistance — all from a single search interface. The palette operates in four modes driven by query prefix, and uses a static singleton ActionRegistry populated at module load time via side-effect imports.

Data Model

Firestore Collections

None. The command palette is a pure UI feature with no Firestore persistence. Recent items are stored in localStorage.

Key TypeScript Types

// A single registerable action
interface CommandAction {
  id: string;
  label: string;
  description?: string;
  icon: ComponentType<{ className?: string }>;
  group: 'navigation' | 'create' | 'context' | 'ai';
  action: string | (() => void);  // String = navigate; function = execute directly
  keywords?: string[];            // Extra fuzzy-match terms
  permission?: Permission;        // RBAC gate — hidden if user lacks this
  routeContext?: string;          // Boosts score when user is on matching route
  shortcut?: string;              // Display-only hint
  priority?: number;              // Lower = higher priority within group
  section?: string;               // Visual section label
}

// Recently visited item (localStorage)
interface RecentItem {
  id: string;
  label: string;
  path: string;
  icon: string;       // lucide-react icon name
  type: string;       // project | expense | journal | etc.
  timestamp: number;
}

// Palette display mode
type PaletteMode = 'default' | 'search' | 'action' | 'ai';

Key Behaviors

Mode Switching

The palette mode is determined by the current query value (usePaletteMode):
  • default — empty query; shows recent items and top actions
  • search — query entered; fuzzy-matches against action registry
  • action — query starts with >; shows only actions (not navigation)
  • ai — query starts with ?; routes to AI fallback (AIFallback component)

Action Registry

ActionRegistry is a static singleton Map<id, CommandAction>. Actions are registered at module load time via three action files imported as side effects in index.ts:
  • navigationActions.ts — page-level navigation (go to projects, grants, etc.)
  • createActions.ts — create-new shortcuts (new expense, new project, etc.)
  • contextActions.ts — context-sensitive actions based on current route
The registry provides:
  • register(action) / registerMany(actions[]) — add actions
  • unregister(id) — remove actions (used for dynamic context actions)
  • getAll() — all registered actions
  • getByGroup(group) — filter by group
  • search(query) — fuzzy match with scoring: exact label match (+100), label starts with (+80), label contains (+60), keyword match (+40), description match (+30)

RBAC Filtering

Actions with a permission field are hidden at render time from users who lack that permission. This is enforced in ActionList using the RBAC context.

Recent Items

useRecentItems reads from localStorage key grantmaster:recent-items. Items are written when the user navigates via the palette. The list is capped at 10 entries, deduplicated by path, and sorted by timestamp descending.

Context Boosting

When searching, actions whose routeContext matches the current pathname receive a score bonus, surfacing route-relevant actions higher in results.

Service Contract

No service files. Logic is encapsulated in hooks and the registry.
ExportOwnsDescription
ActionRegistryGlobal action storeStatic class; singleton Map; fuzzy search
useCommandPaletteOpen/close/toggle stateExposes isOpen, open, close, toggle
usePaletteModeMode derivationDerives PaletteMode from query string
useRecentItemslocalStorage persistenceRecent items read/write, deduplication

Events

Emitted

None. The command palette is a pure UI feature.

Consumed

None.

Dependencies

Depends on:
  • contexts/RBACContext — permission checks for action visibility
  • React Router — navigate() for navigation actions
  • localStorage — recent items persistence
Depended on by:
  • All features that register actions (via navigationActions.ts, createActions.ts, contextActions.ts)
  • The app shell (components/layout/) — renders UnifiedCommandPalette

File Structure

command-palette/
├── actions/
│   ├── contextActions.ts           # Route-sensitive actions
│   ├── createActions.ts            # Entity creation shortcuts
│   └── navigationActions.ts        # Page navigation actions
├── components/
│   ├── AIFallback.tsx              # AI query mode handler
│   ├── ActionList.tsx              # Filtered action results with RBAC
│   ├── PaletteFooter.tsx           # Mode hint footer
│   ├── RecentItems.tsx             # localStorage recent items display
│   ├── SearchResults.tsx           # Combined recent + action results
│   └── UnifiedCommandPalette.tsx   # Root modal container
├── hooks/
│   ├── useCommandPalette.ts        # Open/close state
│   ├── usePaletteMode.ts           # Mode derivation from query
│   └── useRecentItems.ts           # localStorage recent items
├── registry.ts                     # ActionRegistry singleton
├── types.ts                        # CommandAction, RecentItem, PaletteMode
└── index.ts                        # Barrel; side-effect imports register actions