feat: MVP-5 Sprint 2 - Command Palette and Global Shortcuts
- Add Command Palette (Ctrl+K / Cmd+K) with search and navigation - Add global keyboard shortcuts: g h (dashboard), g n (notes), n (new note) - Add keyboard shortcuts help dialog (?) - Add shortcuts provider component - Shortcuts ignore inputs/textareas for proper UX
This commit is contained in:
65
src/hooks/use-global-shortcuts.ts
Normal file
65
src/hooks/use-global-shortcuts.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
|
||||
const SHORTCUTS: Record<string, string> = {
|
||||
'g h': '/', // go to dashboard
|
||||
'g n': '/notes', // go to notes
|
||||
'n': '/new', // new note
|
||||
'/': '/notes', // focus search (navigate to notes)
|
||||
'?': 'show-help', // show shortcuts dialog
|
||||
}
|
||||
|
||||
export function useGlobalShortcuts() {
|
||||
const router = useRouter()
|
||||
const [showHelp, setShowHelp] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
let keystroke = ''
|
||||
let timeout: NodeJS.Timeout
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
// Ignore if in input/textarea/contenteditable
|
||||
const target = e.target as HTMLElement
|
||||
if (target.tagName === 'INPUT' ||
|
||||
target.tagName === 'TEXTAREA' ||
|
||||
target.isContentEditable) {
|
||||
return
|
||||
}
|
||||
|
||||
// Handle ? for help
|
||||
if (e.key === '?' && !e.shiftKey) {
|
||||
e.preventDefault()
|
||||
setShowHelp(true)
|
||||
return
|
||||
}
|
||||
|
||||
// Track g + key combos
|
||||
if (e.key === 'g' && !e.metaKey && !e.ctrlKey) {
|
||||
keystroke = 'g'
|
||||
clearTimeout(timeout)
|
||||
timeout = setTimeout(() => { keystroke = '' }, 500)
|
||||
return
|
||||
}
|
||||
|
||||
if (keystroke === 'g') {
|
||||
const combo = 'g ' + e.key
|
||||
if (SHORTCUTS[combo]) {
|
||||
e.preventDefault()
|
||||
router.push(SHORTCUTS[combo])
|
||||
keystroke = ''
|
||||
}
|
||||
}
|
||||
|
||||
// Direct shortcuts
|
||||
if (e.key === 'n' && !e.metaKey && !e.ctrlKey) {
|
||||
e.preventDefault()
|
||||
router.push('/new')
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('keydown', handleKeyDown)
|
||||
return () => window.removeEventListener('keydown', handleKeyDown)
|
||||
}, [router])
|
||||
|
||||
return { showHelp, setShowHelp }
|
||||
}
|
||||
Reference in New Issue
Block a user