SDK modules added/enhanced: - compliance-hub, compliance-scope, consent-management, notfallplan - audit-report, workflow, source-policy, dsms - advisory-board documentation section - TOM dashboard components, TOM generator SDM mapping - DSFA: mitigation library, risk catalog, threshold analysis, source attribution - VVT: baseline catalog, profiling engine, types - Loeschfristen: baseline catalog, compliance engine, export, profiling, types - Compliance scope: engine, profiling, golden tests, types Existing SDK pages updated: - dsfa/[id], tom, vvt, loeschfristen, advisory-board — expanded functionality - SDKSidebar, StepHeader — new navigation items and layout - SDK layout, context, types — expanded type system Other admin-v2 changes: - AI agents page, RAG pipeline DSFA integration - GridOverlay component updates - Companion feature (development + education) - Compliance advisor SOUL definition 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
|
|
}
|