import { useEffect, useState } from 'react'; import { Command } from 'cmdk'; import { Box, Database, Github, Image, Clock, Search, Settings, FileText, Activity, LayoutGrid, } from 'lucide-react'; interface CommandItem { id: string; label: string; description?: string; icon: typeof Box; shortcut?: string; action: () => void; category?: string; } interface CommandPaletteProps { open: boolean; onClose: () => void; onAddService?: (type: string) => void; onNavigate?: (path: string) => void; } export function CommandPalette({ open, onClose, onAddService, onNavigate, }: CommandPaletteProps) { if (!open) return null; return ( ); } function CommandPaletteContent({ onClose, onAddService, onNavigate, }: Omit) { const [search, setSearch] = useState(''); useEffect(() => { const down = (e: KeyboardEvent) => { if (e.key === 'k' && (e.metaKey || e.ctrlKey)) { e.preventDefault(); onClose(); } }; document.addEventListener('keydown', down); return () => document.removeEventListener('keydown', down); }, [onClose]); const commands: CommandItem[] = [ { id: 'add-web', label: 'Add Web Service', description: 'Deploy a web application', icon: Box, shortcut: 'W', category: 'Create', action: () => { onAddService?.('web'); onClose(); }, }, { id: 'add-worker', label: 'Add Worker Service', description: 'Deploy a background worker', icon: Clock, shortcut: 'K', category: 'Create', action: () => { onAddService?.('worker'); onClose(); }, }, { id: 'add-database', label: 'Add Database', description: 'Provision a PostgreSQL database', icon: Database, shortcut: 'D', category: 'Create', action: () => { onAddService?.('database'); onClose(); }, }, { id: 'add-cron', label: 'Add Cron Job', description: 'Schedule a recurring task', icon: Clock, category: 'Create', action: () => { onAddService?.('cron'); onClose(); }, }, { id: 'connect-github', label: 'Connect GitHub Repo', description: 'Link a repository for auto-deploy', icon: Github, category: 'Connect', action: () => { onClose(); }, }, { id: 'deploy-image', label: 'Deploy Docker Image', description: 'Deploy from a container registry', icon: Image, category: 'Connect', action: () => { onClose(); }, }, { id: 'goto-canvas', label: 'Go to Canvas', icon: LayoutGrid, shortcut: 'C', category: 'Navigate', action: () => { onNavigate?.('canvas'); onClose(); }, }, { id: 'goto-logs', label: 'Go to Logs', icon: FileText, shortcut: 'L', category: 'Navigate', action: () => { onNavigate?.('logs'); onClose(); }, }, { id: 'goto-metrics', label: 'Go to Metrics', icon: Activity, shortcut: 'M', category: 'Navigate', action: () => { onNavigate?.('observability'); onClose(); }, }, { id: 'goto-settings', label: 'Go to Settings', icon: Settings, shortcut: 'S', category: 'Navigate', action: () => { onNavigate?.('settings'); onClose(); }, }, ]; const filteredCommands = commands.filter( (cmd) => cmd.label.toLowerCase().includes(search.toLowerCase()) || cmd.description?.toLowerCase().includes(search.toLowerCase()) || cmd.category?.toLowerCase().includes(search.toLowerCase()) ); const groupedCommands = filteredCommands.reduce( (acc, cmd) => { const category = cmd.category || 'Other'; if (!acc[category]) acc[category] = []; acc[category].push(cmd); return acc; }, {} as Record ); return (
ESC
No results found. {Object.entries(groupedCommands).map(([category, items]) => (
{category}
{items.map((item) => { const Icon = item.icon; return (
{item.label}
{item.description && (
{item.description}
)}
{item.shortcut && ( {item.shortcut} )}
); })}
))}
↑↓ Navigate
↵ Select
⌘K Toggle
); }