mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
refactor: shortcuts help
This commit is contained in:
@@ -19,96 +19,7 @@ import {
|
|||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "./ui/dialog";
|
} from "./ui/dialog";
|
||||||
|
|
||||||
const ShortcutItem = ({
|
export function KeyboardShortcutsHelp() {
|
||||||
shortcut,
|
|
||||||
isRecording,
|
|
||||||
onStartRecording,
|
|
||||||
}: {
|
|
||||||
shortcut: KeyboardShortcut;
|
|
||||||
isRecording: boolean;
|
|
||||||
onStartRecording: (shortcut: KeyboardShortcut) => void;
|
|
||||||
}) => {
|
|
||||||
// Filter out lowercase duplicates for display - if both "j" and "J" exist, only show "J"
|
|
||||||
const displayKeys = shortcut.keys.filter((key: string) => {
|
|
||||||
if (
|
|
||||||
key.includes("Cmd") &&
|
|
||||||
shortcut.keys.includes(key.replace("Cmd", "Ctrl"))
|
|
||||||
)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
{shortcut.icon && (
|
|
||||||
<div className="text-muted-foreground">{shortcut.icon}</div>
|
|
||||||
)}
|
|
||||||
<span className="text-sm">{shortcut.description}</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-1">
|
|
||||||
{displayKeys.map((key: string, index: number) => (
|
|
||||||
<div key={key} className="flex items-center gap-1">
|
|
||||||
<div className="flex items-center">
|
|
||||||
{key.split("+").map((keyPart: string, partIndex: number) => {
|
|
||||||
const keyId = `${shortcut.id}-${index}-${partIndex}`;
|
|
||||||
return (
|
|
||||||
<EditableShortcutKey
|
|
||||||
key={keyId}
|
|
||||||
isRecording={isRecording}
|
|
||||||
onStartRecording={() => onStartRecording(shortcut)}
|
|
||||||
>
|
|
||||||
{keyPart}
|
|
||||||
</EditableShortcutKey>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
{index < displayKeys.length - 1 && (
|
|
||||||
<span className="text-xs text-muted-foreground">or</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const EditableShortcutKey = ({
|
|
||||||
children,
|
|
||||||
isRecording,
|
|
||||||
onStartRecording,
|
|
||||||
}: {
|
|
||||||
children: React.ReactNode;
|
|
||||||
isRecording: boolean;
|
|
||||||
onStartRecording: () => void;
|
|
||||||
}) => {
|
|
||||||
const handleClick = (e: React.MouseEvent) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
onStartRecording();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
variant="text"
|
|
||||||
size="sm"
|
|
||||||
className={`inline-flex font-sans text-xs rounded px-2 min-w-6 min-h-6 leading-none items-center justify-center shadow-xs border mr-1 cursor-pointer hover:bg-opacity-80 ${
|
|
||||||
isRecording
|
|
||||||
? "border-primary bg-primary/10"
|
|
||||||
: "border bg-accent"
|
|
||||||
}`}
|
|
||||||
onClick={handleClick}
|
|
||||||
title={
|
|
||||||
isRecording ? "Press any key combination..." : "Click to edit shortcut"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const KeyboardShortcutsHelp = () => {
|
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [recordingShortcut, setRecordingShortcut] =
|
const [recordingShortcut, setRecordingShortcut] =
|
||||||
useState<KeyboardShortcut | null>(null);
|
useState<KeyboardShortcut | null>(null);
|
||||||
@@ -237,15 +148,98 @@ export const KeyboardShortcutsHelp = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<DialogFooter className="flex-shrink-0 p-6 pt-4">
|
<DialogFooter className="flex-shrink-0 p-6 pt-4">
|
||||||
<Button
|
<Button size="sm" variant="destructive" onClick={resetToDefaults}>
|
||||||
size="sm"
|
|
||||||
variant="destructive"
|
|
||||||
onClick={resetToDefaults}
|
|
||||||
>
|
|
||||||
Reset to Default
|
Reset to Default
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
function ShortcutItem({
|
||||||
|
shortcut,
|
||||||
|
isRecording,
|
||||||
|
onStartRecording,
|
||||||
|
}: {
|
||||||
|
shortcut: KeyboardShortcut;
|
||||||
|
isRecording: boolean;
|
||||||
|
onStartRecording: (shortcut: KeyboardShortcut) => void;
|
||||||
|
}) {
|
||||||
|
// Filter out lowercase duplicates for display - if both "j" and "J" exist, only show "J"
|
||||||
|
const displayKeys = shortcut.keys.filter((key: string) => {
|
||||||
|
if (
|
||||||
|
key.includes("Cmd") &&
|
||||||
|
shortcut.keys.includes(key.replace("Cmd", "Ctrl"))
|
||||||
|
)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
{shortcut.icon && (
|
||||||
|
<div className="text-muted-foreground">{shortcut.icon}</div>
|
||||||
|
)}
|
||||||
|
<span className="text-sm">{shortcut.description}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
{displayKeys.map((key: string, index: number) => (
|
||||||
|
<div key={key} className="flex items-center gap-1">
|
||||||
|
<div className="flex items-center">
|
||||||
|
{key.split("+").map((keyPart: string, partIndex: number) => {
|
||||||
|
const keyId = `${shortcut.id}-${index}-${partIndex}`;
|
||||||
|
return (
|
||||||
|
<EditableShortcutKey
|
||||||
|
key={keyId}
|
||||||
|
isRecording={isRecording}
|
||||||
|
onStartRecording={() => onStartRecording(shortcut)}
|
||||||
|
>
|
||||||
|
{keyPart}
|
||||||
|
</EditableShortcutKey>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
{index < displayKeys.length - 1 && (
|
||||||
|
<span className="text-xs text-muted-foreground">or</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function EditableShortcutKey({
|
||||||
|
children,
|
||||||
|
isRecording,
|
||||||
|
onStartRecording,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
isRecording: boolean;
|
||||||
|
onStartRecording: () => void;
|
||||||
|
}) {
|
||||||
|
const handleClick = (e: React.MouseEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
onStartRecording();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant="text"
|
||||||
|
size="sm"
|
||||||
|
className={`inline-flex font-sans text-xs rounded px-2 min-w-6 min-h-6 leading-none items-center justify-center shadow-xs border mr-1 cursor-pointer hover:bg-opacity-80 ${
|
||||||
|
isRecording ? "border-primary bg-primary/10" : "border bg-accent"
|
||||||
|
}`}
|
||||||
|
onClick={handleClick}
|
||||||
|
title={
|
||||||
|
isRecording ? "Press any key combination..." : "Click to edit shortcut"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user