A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.
This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).
Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
114 lines
2.8 KiB
TypeScript
114 lines
2.8 KiB
TypeScript
'use client'
|
|
|
|
import { useEffect, useCallback, useRef } from 'react'
|
|
import { KEYBOARD_SHORTCUTS } from '@/lib/companion/constants'
|
|
|
|
interface UseKeyboardShortcutsOptions {
|
|
onPauseResume?: () => void
|
|
onExtend?: () => void
|
|
onNextPhase?: () => void
|
|
onCloseModal?: () => void
|
|
onShowHelp?: () => void
|
|
enabled?: boolean
|
|
}
|
|
|
|
export function useKeyboardShortcuts({
|
|
onPauseResume,
|
|
onExtend,
|
|
onNextPhase,
|
|
onCloseModal,
|
|
onShowHelp,
|
|
enabled = true,
|
|
}: UseKeyboardShortcutsOptions) {
|
|
// Track if we're in an input field
|
|
const isInputFocused = useRef(false)
|
|
|
|
const handleKeyDown = useCallback(
|
|
(event: KeyboardEvent) => {
|
|
if (!enabled) return
|
|
|
|
// Don't trigger shortcuts when typing in inputs
|
|
const target = event.target as HTMLElement
|
|
const isInput =
|
|
target.tagName === 'INPUT' ||
|
|
target.tagName === 'TEXTAREA' ||
|
|
target.tagName === 'SELECT' ||
|
|
target.isContentEditable
|
|
|
|
if (isInput) {
|
|
isInputFocused.current = true
|
|
// Only allow Escape in inputs
|
|
if (event.key !== 'Escape') return
|
|
} else {
|
|
isInputFocused.current = false
|
|
}
|
|
|
|
// Handle shortcuts
|
|
switch (event.key) {
|
|
case KEYBOARD_SHORTCUTS.PAUSE_RESUME:
|
|
if (!isInput) {
|
|
event.preventDefault()
|
|
onPauseResume?.()
|
|
}
|
|
break
|
|
|
|
case KEYBOARD_SHORTCUTS.EXTEND_5MIN:
|
|
case KEYBOARD_SHORTCUTS.EXTEND_5MIN.toUpperCase():
|
|
if (!isInput) {
|
|
event.preventDefault()
|
|
onExtend?.()
|
|
}
|
|
break
|
|
|
|
case KEYBOARD_SHORTCUTS.NEXT_PHASE:
|
|
case KEYBOARD_SHORTCUTS.NEXT_PHASE.toUpperCase():
|
|
if (!isInput) {
|
|
event.preventDefault()
|
|
onNextPhase?.()
|
|
}
|
|
break
|
|
|
|
case KEYBOARD_SHORTCUTS.CLOSE_MODAL:
|
|
event.preventDefault()
|
|
onCloseModal?.()
|
|
break
|
|
|
|
case KEYBOARD_SHORTCUTS.SHOW_HELP:
|
|
if (!isInput) {
|
|
event.preventDefault()
|
|
onShowHelp?.()
|
|
}
|
|
break
|
|
}
|
|
},
|
|
[enabled, onPauseResume, onExtend, onNextPhase, onCloseModal, onShowHelp]
|
|
)
|
|
|
|
useEffect(() => {
|
|
if (!enabled) return
|
|
|
|
document.addEventListener('keydown', handleKeyDown)
|
|
return () => document.removeEventListener('keydown', handleKeyDown)
|
|
}, [enabled, handleKeyDown])
|
|
|
|
return {
|
|
isInputFocused: isInputFocused.current,
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Hook to display keyboard shortcut hints
|
|
*/
|
|
export function useKeyboardShortcutHints(show: boolean) {
|
|
const shortcuts = [
|
|
{ key: 'Leertaste', action: 'Pause/Fortsetzen', code: 'space' },
|
|
{ key: 'E', action: '+5 Minuten', code: 'e' },
|
|
{ key: 'N', action: 'Naechste Phase', code: 'n' },
|
|
{ key: 'Esc', action: 'Modal schliessen', code: 'escape' },
|
|
]
|
|
|
|
if (!show) return null
|
|
|
|
return shortcuts
|
|
}
|