Command Palette & Context Cycling System
A comprehensive keyboard-driven navigation system with Cmd+K/Ctrl+K command palette and Shift+Tab context cycling that adapts to your current page.
Features Overview
1. Command Palette (Cmd+K / Ctrl+K)
Context-aware command menu that adapts to your current page:
| Page | Available Commands |
|---|---|
| League NotebookLM | Upload, validate, view analysis, edit |
| Chat Mode | Sports/league search, filtering |
| Markets | Betting platform, market type search |
| Global | Navigation, quick actions |
2. Context Cycler (Shift+Tab)
Page-aware context switching:
| Page | Cycles Through |
|---|---|
| League Workspace | Your leagues |
| Chat Mode | Sport archetypes (Combat, Racing, Team) |
| Markets Page | Market types (Player Props, Totals, Parlays) |
| Global | Recent workspaces |
Installation
Wrap Your App
In your root layout (app/layout.tsx or app/(dashboard)/layout.tsx):
import { CommandPaletteProvider } from '@/components/command-palette'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<AuthProvider>
<CommandPaletteProvider>
{children}
</CommandPaletteProvider>
</AuthProvider>
</body>
</html>
)
}Install Dependencies (if needed)
npm install framer-motion cmdkKeyboard Shortcuts
Global Shortcuts
| Shortcut | Action |
|---|---|
Cmd+K / Ctrl+K | Open command palette |
Shift+Tab | Open context cycler |
Esc | Close any modal |
ββ | Navigate items |
Enter | Select item |
Navigation Shortcuts (when palette is open)
| Shortcut | Action |
|---|---|
G H | Go to Home |
G L | Go to My Leagues |
G E | Go to Explore |
G C | Go to Chat |
Action Shortcuts
| Shortcut | Action |
|---|---|
Cmd+N | Create new league |
Cmd+F | Focus search |
Cmd+E | Edit current league |
Cmd+V | Validate data |
Cmd+Shift+E | Export fingerprint JSON |
Context-Aware Behavior
Path: /dashboard/leagues/[id]
Command Palette shows:
- β Upload Document
- β Validate Data
- β View Fingerprint
- β Edit League Info
- β Sport Archetype Compliance
- β Platform Compatibility
- β Export JSON
- β View Analytics
- β Settings
Context Cycler shows:
- Your leagues (cycle through them quickly)
Programmatic Control
Open Command Palette
import { useCommandPalette } from '@/components/command-palette'
function MyComponent() {
const { openCommandPalette, setLeagueContext } = useCommandPalette()
return (
<Button onClick={openCommandPalette}>
Open Command Palette
</Button>
)
}Setting Specific Contexts
// Set league context
useCommandPalette().setLeagueContext('league-123', 'Pro Curling League')
// Set chat context (sport archetypes)
useCommandPalette().setChatContext()
// Set market context
useCommandPalette().setMarketContext()Listening to Custom Events
useEffect(() => {
const handleContextSwitch = (event: CustomEvent) => {
console.log('Context switched:', event.detail)
}
window.addEventListener('switch-context', handleContextSwitch)
return () => window.removeEventListener('switch-context', handleContextSwitch)
}, [])
// Listen for sport archetype search
window.addEventListener('search-sport-archetype', (event: CustomEvent) => {
const archetype = event.detail.archetype
// Filter leagues by archetype
})
// Listen for platform search
window.addEventListener('search-platform', (event: CustomEvent) => {
const platform = event.detail.platform
// Filter leagues by platform compatibility
})Adding Custom Commands
// In CommandPalette.tsx, add to the appropriate command group
const customCommands: CommandGroup = {
heading: 'Custom Actions',
actions: [
{
id: 'custom-action',
label: 'My Custom Action',
description: 'Does something awesome',
icon: Sparkles,
shortcut: ['Cmd', 'Shift', 'X'],
onSelect: () => {
// Your custom logic
},
},
],
}Adding Custom Context Items
// Add your custom context type
export type ContextType = 'league' | 'sport-archetype' | 'betting-market' | 'your-custom-type' | 'recent'
// Define your custom items
const yourCustomItems: ContextItem[] = [
{
id: 'item-1',
label: 'Custom Item 1',
sublabel: 'Description',
icon: YourIcon,
color: 'from-blue-500 to-purple-500',
onSelect: () => {
// Your logic
},
},
]Integration Examples
Chat with Context Switching
'use client'
import { useEffect, useState } from 'react'
export function ChatPage() {
const [sportArchetype, setSportArchetype] = useState('team_sports')
useEffect(() => {
const handleSwitch = (event: CustomEvent) => {
if (event.detail.type === 'sport-archetype') {
setSportArchetype(event.detail.value)
}
}
window.addEventListener('switch-context', handleSwitch)
return () => window.removeEventListener('switch-context', handleSwitch)
}, [])
return (
<div>
<h1>Chat - {sportArchetype}</h1>
{/* Chat interface filtered by current archetype */}
</div>
)
}Markets with Dynamic Filtering
'use client'
import { useEffect, useState } from 'react'
export function MarketsPage() {
const [marketType, setMarketType] = useState('player-props')
useEffect(() => {
const handleSwitch = (event: CustomEvent) => {
if (event.detail.type === 'betting-market') {
setMarketType(event.detail.value)
}
}
window.addEventListener('switch-context', handleSwitch)
return () => window.removeEventListener('switch-context', handleSwitch)
}, [])
return (
<div>
<h1>Markets - {marketType}</h1>
{/* Markets filtered by current type */}
</div>
)
}Configuration
Auto-Close Behavior
The context cycler automatically closes after 3 seconds of inactivity:
// Change timeout duration in ContextCycler.tsx
const timer = setTimeout(() => {
setOpen(false)
}, 3000) // Change this valueBadge Indicators
{
id: 'action',
label: 'My Action',
badge: 'New', // Shows badge
shortcut: ['Cmd', 'X'], // Shows keyboard shortcut
onSelect: () => {},
}Search with Keywords
{
id: 'combat',
label: 'Combat Sports',
keywords: ['mma', 'boxing', 'martial', 'fighting', 'ufc'],
onSelect: () => {},
}Architecture
CommandPaletteProvider (Root)
βββ CommandPalette (Cmd+K)
β βββ Context Detection
β βββ Command Groups
β βββ Search & Filter
βββ ContextCycler (Shift+Tab)
βββ Context Detection
βββ Item Lists
βββ Auto-Close TimerFiles
| File | Purpose |
|---|---|
CommandPalette.tsx | Main command palette component |
ContextCycler.tsx | Context switching component |
CommandPaletteProvider.tsx | Global provider and orchestrator |
index.ts | Barrel exports |
Dependencies
cmdk- Command menu componentframer-motion- Animationslucide-react- Iconstailwindcss- Stylingshadcn/ui- UI components
Accessibility
- β Full keyboard navigation
- β ARIA labels and roles
- β Focus management
- β Screen reader compatible
- β High contrast support
Troubleshooting
| Issue | Solution |
|---|---|
| Command Palette Not Opening | Ensure CommandPaletteProvider wraps your app |
| Context Cycler Not Showing Items | Create some items first (leagues, etc.) |
| Keyboard Shortcuts Not Working | Check for conflicts with browser/OS shortcuts |