6.5 KiB
Implementation Plan: Enhanced Rundown Keyboard Shortcuts
This document outlines the plan to extend the keyboard shortcuts for the Rundown feature, including functionality for Duplicate, Delete, Cut, and improved navigation (Home/End, PageUp/PageDown).
Files to Modify
apps/client/src/features/rundown/hooks/useRundownCommands.tsapps/client/src/features/rundown/hooks/useRundownKeyboard.ts
Step 1: Logic Implementation (useRundownCommands.ts)
We need to add the underlying logic for the new actions.
1. cloneEntry
Create a function to clone the currently selected entry.
- Action: Use
entryActions.clone. - Logic:
- If no cursor, return.
- Call
clone(cursor, { after: cursor }).
2. selectEdge
Create a function to jump to the top or bottom of the list.
- Arguments:
direction: 'top' | 'bottom'. - Logic:
- Use
getFirstNormal(entries, order)for'top'. - Use
getLastNormal(entries, order)for'bottom'. - Call
setSelectedEventswith the result.
- Use
3. selectPage
Create a function to move selection by a "page" (e.g., 10 items).
- Arguments:
cursor: string | null,direction: 'up' | 'down'. - Constant:
PAGE_SIZE = 10. - Logic:
- Use
getNextNormal/getPreviousNormalin a loop (up toPAGE_SIZEtimes) to find the target entry. - Call
setSelectedEventswith the result.
- Use
4. cutEntry
While "Cut" is often a compound action in the keyboard hook (Copy + Delete), implementing a helper here allows for cleaner handling if additional logic is needed later.
- Logic:
- Set copy ID (requires access to
entryCopyStoreor passed via props, but current pattern passessetEntryCopyIdtouseRundownKeyboardseparately). - Note: Since
setEntryCopyIdis separate, we can handle "Cut" composition inuseRundownKeyboard.tsor add acutcommand here that combines them if we bringsetEntryCopyIdinto commands. Recommendation: Handle composition inuseRundownKeyboard.tsto matching existing patterns, or add a specificcutEntryif complex.
- Set copy ID (requires access to
Update Return Interface: Ensure selectEdge, selectPage, and cloneEntry are returned from the hook.
Step 2: Keyboard Mapping (useRundownKeyboard.ts)
Update the UseRundownKeyboardOptions interface and the useHotkeys hook configuration.
1. Update Interface
Update UseRundownKeyboardOptions['commands'] to include:
interface UseRundownKeyboardOptions {
// ... existing
commands: {
// ... existing
cloneEntry: (cursor: EntryId | null) => void;
selectEdge: (direction: 'top' | 'bottom') => void;
selectPage: (cursor: EntryId | null, direction: 'up' | 'down') => void;
};
// ... existing
}
2. Add Hotkeys implementation
Add the following mappings to the useHotkeys array:
- Note:
mod + D(Clone) does not collide withalt + D(Add Delay).
| Action | Shortcut | Handler Logic |
|---|---|---|
| Clone | mod + D |
commands.cloneEntry(cursor) |
| Delete | mod + Delete |
commands.deleteAtCursor(cursor) |
| Cut | mod + X |
() => { setEntryCopyId(cursor); commands.deleteAtCursor(cursor); } |
| Home | Home |
commands.selectEdge('top') |
| End | End |
commands.selectEdge('bottom') |
| Page Up | PageUp |
commands.selectPage(cursor, 'up') |
| Page Down | PageDown |
commands.selectPage(cursor, 'down') |
Note: Ensure { preventDefault: true, usePhysicalKeys: true } is used for navigation keys to prevent browser scrolling.
Step 3: UI Updates for Discoverability
To ensure users can discover these new features, we must update the UI to reflect new shortcuts.
1. Update Context Menus
Add "Clone" and "Delete" options (or ensure they use the new keyboard shortcuts in their labels) to the context menus of rundown items.
Files to Modify:
apps/client/src/features/rundown/rundown-event/RundownEvent.tsxapps/client/src/features/rundown/rundown-group/RundownGroup.tsxapps/client/src/features/rundown/rundown-milestone/RundownMilestone.tsx
Changes:
- Locate
useContextMenuimplementation. - Add/Update
Cloneoption with shortcut labelMod+D. - Ensure
Deleteoption shows correctMod/Delshortcut.
2. Update Empty State Shortcuts
Update the shortcut list displayed when no event is selected.
File to Modify:
apps/client/src/features/rundown/entry-editor/EventEditorEmpty.tsx
Changes:
- Add rows to the shortcut table for:
- Clone Entry:
Mod + D - Delete Entry:
Mod + Delete/Delete - Navigation:
Home,End,PgUp,PgDn(Group under "Navigation")
- Clone Entry:
Step 4: UX Review & Interface Improvements
1. EventEditorEmpty Redesign
The current table-based layout is rigid. We will refactor apps/client/src/features/rundown/entry-editor/EventEditorEmpty.tsx to use a sleek CSS Grid layout.
- Action: Replace
<table>withdivbased grid. - Visuals: Use subtle headers for groups (Navigation, Editing, System).
- Refinement: Ensure
<Kbd>components use a flat, minimal design.
2. Global Shortcuts Dialog
- Decision: Implement a Global Shortcuts Dialog triggered by
?(Shift + /). - Rationale: Users lose the
EventEditorEmptyreference once they add content. A persistent dialog ensures "recognition over recall".
3. Context Menu Implementation Guide
We will enhance the context menu to display shortcuts inline.
A. Update Type Definition
Modify apps/client/src/common/components/dropdown-menu/DropdownMenu.tsx:
type DropdownMenuItem = {
// ... existing fields
shortcut?: string; // New field
};
B. Update Component Rendering
In apps/client/src/common/components/dropdown-menu/DropdownMenu.tsx, update the render loop to display the shortcut:
<BaseMenu.Item className={style.item}>
<span className={style.labelContainer}>
{item.icon && <item.icon />}
{item.label}
</span>
{item.type === 'item' && item.shortcut && (
<span className={style.shortcut}>{item.shortcut}</span>
)}
</BaseMenu.Item>
Note: Update DropdownMenu.module.scss to use justify-content: space-between on the item.
C. Update Usage in RundownEvent.tsx
Add shortcuts to the context menu options:
{
type: 'item',
label: 'Clone',
icon: IoDuplicateOutline,
shortcut: `${deviceMod}+D`,
onClick: () => clone(eventId, { after: eventId }),
},
{
type: 'item',
label: 'Delete',
icon: IoTrash,
shortcut: 'Del',
onClick: () => { /* ... */ },
}