2026-03-25 16:47:22 +01:00
|
|
|
import type { ShortcutKey } from "@/lib/actions/keybinding";
|
2026-01-31 00:20:04 +01:00
|
|
|
|
|
|
|
|
export type TActionCategory =
|
|
|
|
|
| "playback"
|
|
|
|
|
| "navigation"
|
|
|
|
|
| "editing"
|
|
|
|
|
| "selection"
|
|
|
|
|
| "history"
|
|
|
|
|
| "timeline"
|
2026-03-25 16:47:22 +01:00
|
|
|
| "controls"
|
|
|
|
|
| "assets";
|
2026-01-31 00:20:04 +01:00
|
|
|
|
|
|
|
|
export interface TActionDefinition {
|
|
|
|
|
description: string;
|
|
|
|
|
category: TActionCategory;
|
|
|
|
|
defaultShortcuts?: ShortcutKey[];
|
|
|
|
|
args?: Record<string, unknown>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const ACTIONS = {
|
|
|
|
|
"toggle-play": {
|
|
|
|
|
description: "Play/Pause",
|
|
|
|
|
category: "playback",
|
|
|
|
|
defaultShortcuts: ["space", "k"],
|
|
|
|
|
},
|
|
|
|
|
"stop-playback": {
|
|
|
|
|
description: "Stop playback",
|
|
|
|
|
category: "playback",
|
|
|
|
|
},
|
|
|
|
|
"seek-forward": {
|
|
|
|
|
description: "Seek forward 1 second",
|
|
|
|
|
category: "playback",
|
|
|
|
|
defaultShortcuts: ["l"],
|
|
|
|
|
args: { seconds: "number" },
|
|
|
|
|
},
|
|
|
|
|
"seek-backward": {
|
|
|
|
|
description: "Seek backward 1 second",
|
|
|
|
|
category: "playback",
|
|
|
|
|
defaultShortcuts: ["j"],
|
|
|
|
|
args: { seconds: "number" },
|
|
|
|
|
},
|
|
|
|
|
"frame-step-forward": {
|
|
|
|
|
description: "Frame step forward",
|
|
|
|
|
category: "navigation",
|
|
|
|
|
defaultShortcuts: ["right"],
|
|
|
|
|
},
|
|
|
|
|
"frame-step-backward": {
|
|
|
|
|
description: "Frame step backward",
|
|
|
|
|
category: "navigation",
|
|
|
|
|
defaultShortcuts: ["left"],
|
|
|
|
|
},
|
|
|
|
|
"jump-forward": {
|
|
|
|
|
description: "Jump forward 5 seconds",
|
|
|
|
|
category: "navigation",
|
|
|
|
|
defaultShortcuts: ["shift+right"],
|
|
|
|
|
args: { seconds: "number" },
|
|
|
|
|
},
|
|
|
|
|
"jump-backward": {
|
|
|
|
|
description: "Jump backward 5 seconds",
|
|
|
|
|
category: "navigation",
|
|
|
|
|
defaultShortcuts: ["shift+left"],
|
|
|
|
|
args: { seconds: "number" },
|
|
|
|
|
},
|
|
|
|
|
"goto-start": {
|
|
|
|
|
description: "Go to timeline start",
|
|
|
|
|
category: "navigation",
|
|
|
|
|
defaultShortcuts: ["home", "enter"],
|
|
|
|
|
},
|
|
|
|
|
"goto-end": {
|
|
|
|
|
description: "Go to timeline end",
|
|
|
|
|
category: "navigation",
|
|
|
|
|
defaultShortcuts: ["end"],
|
|
|
|
|
},
|
|
|
|
|
split: {
|
|
|
|
|
description: "Split elements at playhead",
|
|
|
|
|
category: "editing",
|
|
|
|
|
defaultShortcuts: ["s"],
|
|
|
|
|
},
|
|
|
|
|
"split-left": {
|
|
|
|
|
description: "Split and remove left",
|
|
|
|
|
category: "editing",
|
|
|
|
|
defaultShortcuts: ["q"],
|
|
|
|
|
},
|
|
|
|
|
"split-right": {
|
|
|
|
|
description: "Split and remove right",
|
|
|
|
|
category: "editing",
|
|
|
|
|
defaultShortcuts: ["w"],
|
|
|
|
|
},
|
|
|
|
|
"delete-selected": {
|
|
|
|
|
description: "Delete selected elements",
|
|
|
|
|
category: "editing",
|
|
|
|
|
defaultShortcuts: ["backspace", "delete"],
|
|
|
|
|
},
|
|
|
|
|
"copy-selected": {
|
|
|
|
|
description: "Copy selected elements",
|
|
|
|
|
category: "editing",
|
|
|
|
|
defaultShortcuts: ["ctrl+c"],
|
|
|
|
|
},
|
|
|
|
|
"paste-copied": {
|
|
|
|
|
description: "Paste elements at playhead",
|
|
|
|
|
category: "editing",
|
|
|
|
|
defaultShortcuts: ["ctrl+v"],
|
|
|
|
|
},
|
|
|
|
|
"toggle-snapping": {
|
|
|
|
|
description: "Toggle snapping",
|
|
|
|
|
category: "editing",
|
|
|
|
|
defaultShortcuts: ["n"],
|
|
|
|
|
},
|
2026-02-23 07:09:26 +01:00
|
|
|
"toggle-ripple-editing": {
|
|
|
|
|
description: "Toggle ripple editing",
|
|
|
|
|
category: "editing",
|
|
|
|
|
},
|
2026-01-31 00:20:04 +01:00
|
|
|
"select-all": {
|
|
|
|
|
description: "Select all elements",
|
|
|
|
|
category: "selection",
|
|
|
|
|
defaultShortcuts: ["ctrl+a"],
|
|
|
|
|
},
|
2026-03-25 16:47:22 +01:00
|
|
|
"cancel-interaction": {
|
|
|
|
|
description: "Cancel current interaction",
|
|
|
|
|
category: "controls",
|
|
|
|
|
defaultShortcuts: ["escape"],
|
|
|
|
|
},
|
2026-03-02 13:13:07 +01:00
|
|
|
"deselect-all": {
|
|
|
|
|
description: "Deselect all elements",
|
|
|
|
|
category: "selection",
|
|
|
|
|
},
|
2026-01-31 00:20:04 +01:00
|
|
|
"duplicate-selected": {
|
|
|
|
|
description: "Duplicate selected element",
|
|
|
|
|
category: "selection",
|
|
|
|
|
defaultShortcuts: ["ctrl+d"],
|
|
|
|
|
},
|
|
|
|
|
"toggle-elements-muted-selected": {
|
|
|
|
|
description: "Mute/unmute selected elements",
|
|
|
|
|
category: "selection",
|
|
|
|
|
},
|
|
|
|
|
"toggle-elements-visibility-selected": {
|
|
|
|
|
description: "Show/hide selected elements",
|
|
|
|
|
category: "selection",
|
|
|
|
|
},
|
|
|
|
|
"toggle-bookmark": {
|
|
|
|
|
description: "Toggle bookmark at playhead",
|
|
|
|
|
category: "timeline",
|
|
|
|
|
},
|
|
|
|
|
undo: {
|
|
|
|
|
description: "Undo",
|
|
|
|
|
category: "history",
|
|
|
|
|
defaultShortcuts: ["ctrl+z"],
|
|
|
|
|
},
|
|
|
|
|
redo: {
|
|
|
|
|
description: "Redo",
|
|
|
|
|
category: "history",
|
|
|
|
|
defaultShortcuts: ["ctrl+shift+z", "ctrl+y"],
|
|
|
|
|
},
|
2026-03-25 16:47:22 +01:00
|
|
|
"remove-media-asset": {
|
|
|
|
|
description: "Remove media asset",
|
|
|
|
|
category: "assets",
|
|
|
|
|
args: { projectId: "string", assetId: "string" },
|
|
|
|
|
},
|
|
|
|
|
"remove-media-assets": {
|
|
|
|
|
description: "Remove media assets",
|
|
|
|
|
category: "assets",
|
|
|
|
|
args: { projectId: "string", assetIds: "string[]" },
|
|
|
|
|
},
|
2026-01-31 00:20:04 +01:00
|
|
|
} as const satisfies Record<string, TActionDefinition>;
|
|
|
|
|
|
|
|
|
|
export type TAction = keyof typeof ACTIONS;
|
|
|
|
|
|
2026-03-25 16:47:22 +01:00
|
|
|
export function getActionDefinition({
|
|
|
|
|
action,
|
|
|
|
|
}: {
|
|
|
|
|
action: TAction;
|
|
|
|
|
}): TActionDefinition {
|
2026-01-31 00:20:04 +01:00
|
|
|
return ACTIONS[action];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function getDefaultShortcuts(): Record<ShortcutKey, TAction> {
|
|
|
|
|
const shortcuts: Record<string, TAction> = {};
|
|
|
|
|
|
|
|
|
|
for (const [action, def] of Object.entries(ACTIONS) as Array<
|
|
|
|
|
[TAction, TActionDefinition]
|
|
|
|
|
>) {
|
|
|
|
|
if (def.defaultShortcuts) {
|
|
|
|
|
for (const shortcut of def.defaultShortcuts) {
|
|
|
|
|
shortcuts[shortcut] = action;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return shortcuts as Record<ShortcutKey, TAction>;
|
|
|
|
|
}
|