feat: display keyboard shortcuts on toolbar buttons (#788)

- Add shortcut hints to toolbar buttons via tooltip text
- Integrate useKeyboardShortcutsHelp hook for consistent shortcut retrieval
- Timeline toolbar: split, duplicate, delete, snapping, bookmark buttons
- Preview toolbar: play/pause button
- Format: tooltip text appended with '(Key)' or '(Key1 or Key2)'
- Gracefully handle actions without defined shortcuts
This commit is contained in:
Senthil Raja R 2026-05-17 07:57:16 +05:30 committed by GitHub
parent fbe3db74d7
commit 6fdb1559aa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 53 additions and 18 deletions

View File

@ -4,6 +4,7 @@ import { useState, useEffect } from "react";
import { useEditor } from "@/editor/use-editor";
import { formatTimecode } from "opencut-wasm";
import { invokeAction } from "@/actions";
import { useKeyboardShortcutsHelp } from "@/actions/use-keyboard-shortcuts-help";
import { EditableTimecode } from "@/components/editable-timecode";
import { Button } from "@/components/ui/button";
import {
@ -24,6 +25,11 @@ import { PREVIEW_ZOOM_PRESETS } from "@/preview/zoom";
import { usePreviewViewport } from "./preview-viewport";
import { GridPopover } from "./guide-popover";
import { usePreviewStore } from "@/preview/preview-store";
import {
Tooltip,
TooltipTrigger,
TooltipContent,
} from "@/components/ui/tooltip";
import type { MediaTime } from "@/wasm";
export function PreviewToolbar({
@ -133,14 +139,24 @@ function ZoomSelect() {
function PlayPauseButton() {
const isPlaying = useEditor((e) => e.playback.getIsPlaying());
const { shortcuts } = useKeyboardShortcutsHelp();
const shortcut = shortcuts.find((s) => s.action === "toggle-play");
const tooltipText = shortcut
? `Play/Pause (${shortcut.keys.join(" or ")})`
: "Play/Pause";
return (
<Button
variant="text"
size="icon"
onClick={() => invokeAction("toggle-play")}
>
<HugeiconsIcon icon={isPlaying ? PauseIcon : PlayIcon} />
</Button>
<Tooltip delayDuration={200}>
<TooltipTrigger asChild>
<Button
variant="text"
size="icon"
onClick={() => invokeAction("toggle-play")}
>
<HugeiconsIcon icon={isPlaying ? PauseIcon : PlayIcon} />
</Button>
</TooltipTrigger>
<TooltipContent>{tooltipText}</TooltipContent>
</Tooltip>
);
}

View File

@ -19,6 +19,7 @@ import { TIMELINE_ZOOM_MAX } from "@/timeline/scale";
import { sliderToZoom, zoomToSlider } from "@/timeline/zoom-utils";
import { ScenesView } from "@/components/editor/scenes-view";
import { type TActionWithOptionalArgs, invokeAction } from "@/actions";
import { useKeyboardShortcutsHelp } from "@/actions/use-keyboard-shortcuts-help";
import {
canToggleSourceAudio,
getSourceAudioActionLabel,
@ -143,18 +144,21 @@ function ToolbarLeftSection() {
<div className="flex items-center gap-1">
<TooltipProvider delayDuration={500}>
<ToolbarButton
action="split"
icon={<HugeiconsIcon icon={ScissorIcon} />}
tooltip="Split element"
onClick={({ event }) => handleAction({ action: "split", event })}
/>
<ToolbarButton
action="split-left"
icon={<HugeiconsIcon icon={AlignLeftIcon} />}
tooltip="Split left"
onClick={({ event }) => handleAction({ action: "split-left", event })}
/>
<ToolbarButton
action="split-right"
icon={<HugeiconsIcon icon={AlignRightIcon} />}
tooltip="Split right"
onClick={({ event }) =>
@ -163,6 +167,7 @@ function ToolbarLeftSection() {
/>
<ToolbarButton
action="toggle-source-audio"
icon={
<HugeiconsIcon
icon={isSelectedSourceAudioSeparated ? Unlink02Icon : Link02Icon}
@ -176,6 +181,7 @@ function ToolbarLeftSection() {
/>
<ToolbarButton
action="duplicate-selected"
icon={<HugeiconsIcon icon={Copy01Icon} />}
tooltip="Duplicate element"
onClick={({ event }) =>
@ -191,6 +197,7 @@ function ToolbarLeftSection() {
/>
<ToolbarButton
action="delete-selected"
icon={<HugeiconsIcon icon={Delete02Icon} />}
tooltip="Delete element"
onClick={({ event }) =>
@ -200,16 +207,15 @@ function ToolbarLeftSection() {
<div className="bg-border mx-1 h-6 w-px" />
<Tooltip>
<ToolbarButton
icon={<HugeiconsIcon icon={Bookmark02Icon} />}
isActive={isCurrentlyBookmarked}
tooltip={isCurrentlyBookmarked ? "Remove bookmark" : "Add bookmark"}
onClick={({ event }) =>
handleAction({ action: "toggle-bookmark", event })
}
/>
</Tooltip>
<ToolbarButton
action="toggle-bookmark"
icon={<HugeiconsIcon icon={Bookmark02Icon} />}
isActive={isCurrentlyBookmarked}
tooltip={isCurrentlyBookmarked ? "Remove bookmark" : "Add bookmark"}
onClick={({ event }) =>
handleAction({ action: "toggle-bookmark", event })
}
/>
<GraphEditorPopover
open={graphEditor.open}
@ -284,6 +290,7 @@ function ToolbarRightSection({
<div className="flex items-center gap-1">
<TooltipProvider delayDuration={500}>
<ToolbarButton
action="toggle-snapping"
icon={<HugeiconsIcon icon={MagnetIcon} />}
isActive={snappingEnabled}
tooltip="Auto snapping"
@ -291,6 +298,7 @@ function ToolbarRightSection({
/>
<ToolbarButton
action="toggle-ripple-editing"
icon={<OcRippleIcon size={24} className="scale-110" />}
isActive={rippleEditingEnabled}
tooltip="Ripple editing"
@ -337,6 +345,7 @@ function ToolbarButton({
disabled,
isActive,
buttonWrapper,
action,
}: {
icon: React.ReactNode;
tooltip: string;
@ -344,7 +353,17 @@ function ToolbarButton({
disabled?: boolean;
isActive?: boolean;
buttonWrapper?: (button: React.ReactElement) => React.ReactElement;
action?: TActionWithOptionalArgs;
}) {
const { shortcuts } = useKeyboardShortcutsHelp();
const shortcut = action
? shortcuts.find((s) => s.action === action)
: null;
const tooltipContent = shortcut
? `${tooltip} (${shortcut.keys.join(" or ")})`
: tooltip;
const button = (
<Button
variant={isActive ? "secondary" : "text"}
@ -370,7 +389,7 @@ function ToolbarButton({
return (
<Tooltip delayDuration={200}>
<TooltipTrigger asChild>{trigger}</TooltipTrigger>
<TooltipContent>{tooltip}</TooltipContent>
<TooltipContent>{tooltipContent}</TooltipContent>
</Tooltip>
);
}