81 行
2.7 KiB
TypeScript
81 行
2.7 KiB
TypeScript
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from '@/components/ui/dialog'
|
|
import { formatKeyBinding, SHORTCUT_DEFINITIONS } from '@/lib/keyboardShortcuts'
|
|
import { useUITranslation } from '@/lib/useUITranslation'
|
|
|
|
import type { FC } from 'react'
|
|
|
|
import type { KeyBinding, ShortcutActionId, ShortcutScope } from '@/lib/keyboardShortcuts'
|
|
|
|
type Props = {
|
|
open: boolean
|
|
onOpenChange: (open: boolean) => void
|
|
activeScope: ShortcutScope
|
|
effectiveBindings: Record<ShortcutActionId, KeyBinding | null>
|
|
conflictActionIds: Set<ShortcutActionId>
|
|
availableActionIds: Set<ShortcutActionId>
|
|
}
|
|
|
|
|
|
const ShortcutHelpDialog: FC<Props> = props => {
|
|
const { open, onOpenChange, activeScope, effectiveBindings,
|
|
conflictActionIds, availableActionIds } = props
|
|
const { label } = useUITranslation ('settings')
|
|
const rows = SHORTCUT_DEFINITIONS
|
|
.filter (definition =>
|
|
definition.scope === 'global' || definition.scope === activeScope)
|
|
.filter (definition => availableActionIds.has (definition.id))
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogContent className="max-w-3xl px-6 pb-6 pt-7"
|
|
closeLabel={label ('actions.close')}>
|
|
<DialogHeader className="pl-8">
|
|
<DialogTitle>{label ('shortcuts.title')}</DialogTitle>
|
|
<DialogDescription>
|
|
{label ('shortcuts.description')}
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<div className="overflow-x-auto">
|
|
<table className="w-full min-w-[40rem] table-fixed border-collapse text-sm">
|
|
<thead className="border-b border-border">
|
|
<tr>
|
|
<th className="p-2 text-left">{label ('shortcuts.operation')}</th>
|
|
<th className="p-2 text-left">{label ('shortcuts.scope')}</th>
|
|
<th className="p-2 text-left">{label ('shortcuts.key')}</th>
|
|
<th className="p-2 text-left">{label ('shortcuts.conflict')}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{rows.map (row => (
|
|
<tr key={row.id} className="border-b border-border/60 last:border-b-0">
|
|
<td className="p-2">{label (`shortcuts.actions.${row.id}`)}</td>
|
|
<td className="p-2">{label (`shortcuts.scopes.${row.scope}`)}</td>
|
|
<td className="p-2 font-mono">
|
|
{effectiveBindings[row.id] == null
|
|
? label ('shortcuts.unassigned')
|
|
: <span lang="en">{formatKeyBinding (effectiveBindings[row.id])}</span>}
|
|
</td>
|
|
<td className="p-2">
|
|
{conflictActionIds.has (row.id)
|
|
? <span className="text-red-600 dark:text-red-400">
|
|
{label ('shortcuts.conflicting')}
|
|
</span>
|
|
: label ('shortcuts.none')}
|
|
</td>
|
|
</tr>))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>)
|
|
}
|
|
|
|
export default ShortcutHelpDialog
|