Refactor hotkey setting UI (#506)
* refactor hotkeys setting * update UI * refactor * fix toast
This commit is contained in:
129
enjoy/src/renderer/components/preferences/hotkeys-settings.tsx
Normal file
129
enjoy/src/renderer/components/preferences/hotkeys-settings.tsx
Normal file
@@ -0,0 +1,129 @@
|
||||
import { t } from "i18next";
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
Button,
|
||||
toast,
|
||||
} from "@renderer/components/ui";
|
||||
import { HotKeysSettingsProviderContext } from "@renderer/context";
|
||||
import { useContext, useMemo, useEffect } from "react";
|
||||
|
||||
export const HotkeysSettings = ({
|
||||
open,
|
||||
name,
|
||||
keyName,
|
||||
onOpenChange,
|
||||
}: {
|
||||
open: boolean;
|
||||
name: string;
|
||||
keyName: string;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
}) => {
|
||||
const {
|
||||
changeHotkey,
|
||||
currentHotkeys,
|
||||
recordingHotkeys,
|
||||
resetRecordingHotkeys,
|
||||
startRecordingHotkeys,
|
||||
stopRecordingHotkeys,
|
||||
isRecording,
|
||||
} = useContext(HotKeysSettingsProviderContext);
|
||||
|
||||
const joinedKeys = useMemo(
|
||||
() => [...recordingHotkeys].join("+"),
|
||||
[recordingHotkeys]
|
||||
);
|
||||
|
||||
const changeKeyMap = async () => {
|
||||
const ret = (await changeHotkey(keyName, recordingHotkeys)) as unknown as {
|
||||
error: "conflict" | "invalid";
|
||||
data: string | string[];
|
||||
input: string;
|
||||
};
|
||||
stopRecordingHotkeys();
|
||||
const { error, data, input } = ret ?? {};
|
||||
|
||||
if (error === "conflict") {
|
||||
toast.error(
|
||||
t("customizeShortcutsConflictToast", {
|
||||
input,
|
||||
otherHotkeyName: (data as string[])
|
||||
.map((str) => t(str.charAt(0).toLowerCase() + str.slice(1)))
|
||||
.join(","),
|
||||
})
|
||||
);
|
||||
} else if (error === "invalid") {
|
||||
toast.error(t("customizeShortcutsInvalidToast"));
|
||||
} else {
|
||||
toast.success(t("customizeShortcutsUpdated"));
|
||||
onOpenChange(false);
|
||||
}
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
stopRecordingHotkeys();
|
||||
resetRecordingHotkeys();
|
||||
};
|
||||
|
||||
// ensure recording disabled when dialog close
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
stopRecordingHotkeys();
|
||||
};
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<AlertDialog open={open} onOpenChange={onOpenChange}>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>{name}</AlertDialogTitle>
|
||||
</AlertDialogHeader>
|
||||
<div>
|
||||
{isRecording ? (
|
||||
<div className="">
|
||||
<div className="flex justify-center mb-4">
|
||||
<Button variant="secondary">
|
||||
{joinedKeys.length > 0 ? (
|
||||
<span className="text-sm">{joinedKeys}</span>
|
||||
) : (
|
||||
<span className="font-mono">-</span>
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="py-2 text-center text-sm text-muted-foreground">
|
||||
{t("customizeShortcutsRecordingTip")}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="">
|
||||
<div className="flex justify-center mb-4">
|
||||
<Button
|
||||
variant="outline"
|
||||
className="font-mono"
|
||||
onClick={() => {
|
||||
startRecordingHotkeys();
|
||||
}}
|
||||
>
|
||||
{currentHotkeys[keyName]}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="py-2 text-center text-sm text-muted-foreground">
|
||||
{t("customizeShortcutsTip")}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<AlertDialogFooter>
|
||||
<Button disabled={!isRecording || !joinedKeys} onClick={changeKeyMap}>
|
||||
{t("save")}
|
||||
</Button>
|
||||
<AlertDialogCancel onClick={reset}>{t("cancel")}</AlertDialogCancel>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
);
|
||||
};
|
||||
@@ -1,8 +1,10 @@
|
||||
import { t } from "i18next";
|
||||
import { Separator } from "@renderer/components/ui";
|
||||
import { HotKeysSettingsProviderContext, Hotkey } from "@/renderer/context";
|
||||
import {
|
||||
Separator,
|
||||
} from "@renderer/components/ui";
|
||||
import { HotKeysSettingsProviderContext, Hotkey } from "@renderer/context";
|
||||
import { HotkeysSettings } from "@renderer/components";
|
||||
import { useContext, useState } from "react";
|
||||
import { ChangeHotkeyDialog } from "../change-hotkey-dialog";
|
||||
|
||||
export const Hotkeys = () => {
|
||||
const [open, setOpen] = useState(false);
|
||||
@@ -10,27 +12,15 @@ export const Hotkeys = () => {
|
||||
name: string;
|
||||
keyName: string;
|
||||
} | null>(null);
|
||||
const {
|
||||
currentHotkeys,
|
||||
startRecordingHotkeys,
|
||||
stopRecordingHotkeys,
|
||||
} = useContext(HotKeysSettingsProviderContext);
|
||||
const { currentHotkeys } = useContext(HotKeysSettingsProviderContext);
|
||||
|
||||
const commandOrCtrl = navigator.platform.includes("Mac") ? "Cmd" : "Ctrl";
|
||||
|
||||
const handleItemSelected = (item: { name: string; keyName: Hotkey }) => {
|
||||
setOpen(true);
|
||||
startRecordingHotkeys();
|
||||
setSelectedItem(item);
|
||||
};
|
||||
|
||||
const handleOpenChange = (open: boolean) => {
|
||||
setOpen(open);
|
||||
if (!open) {
|
||||
stopRecordingHotkeys();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="font-semibold mb-4 capitilized">{t("hotkeys")}</div>
|
||||
@@ -39,8 +29,8 @@ export const Hotkeys = () => {
|
||||
|
||||
<div className="flex items-center justify-between py-4">
|
||||
<div className="flex items-center space-x-2">{t("quitApp")}</div>
|
||||
<kbd className="bg-muted px-2 py-1 rounded-md text-sm text-muted-foreground cursor-not-allowed">
|
||||
{commandOrCtrl} + Q
|
||||
<kbd className="bg-muted px-2 py-1 rounded-md text-sm text-muted-foreground cursor-not-allowed capitalize">
|
||||
{commandOrCtrl}+Q
|
||||
</kbd>
|
||||
</div>
|
||||
|
||||
@@ -53,11 +43,11 @@ export const Hotkeys = () => {
|
||||
<kbd
|
||||
onClick={() =>
|
||||
handleItemSelected({
|
||||
name: "Open preferences",
|
||||
name: t("openPreferences"),
|
||||
keyName: "OpenPreferences",
|
||||
})
|
||||
}
|
||||
className="bg-muted px-2 py-1 rounded-md text-sm text-muted-foreground cursor-pointer"
|
||||
className="bg-muted px-2 py-1 rounded-md text-sm text-muted-foreground cursor-pointer capitalize"
|
||||
>
|
||||
{currentHotkeys.OpenPreferences}
|
||||
</kbd>
|
||||
@@ -77,7 +67,7 @@ export const Hotkeys = () => {
|
||||
keyName: "PlayOrPause",
|
||||
})
|
||||
}
|
||||
className="bg-muted px-2 py-1 rounded-md text-sm text-muted-foreground cursor-pointer"
|
||||
className="bg-muted px-2 py-1 rounded-md text-sm text-muted-foreground cursor-pointer capitalize"
|
||||
>
|
||||
{currentHotkeys.PlayOrPause}
|
||||
</kbd>
|
||||
@@ -96,7 +86,7 @@ export const Hotkeys = () => {
|
||||
keyName: "StartOrStopRecording",
|
||||
})
|
||||
}
|
||||
className="bg-muted px-2 py-1 rounded-md text-sm text-muted-foreground cursor-pointer"
|
||||
className="bg-muted px-2 py-1 rounded-md text-sm text-muted-foreground cursor-pointer capitalize"
|
||||
>
|
||||
{currentHotkeys.StartOrStopRecording}
|
||||
</kbd>
|
||||
@@ -115,7 +105,7 @@ export const Hotkeys = () => {
|
||||
keyName: "PlayOrPauseRecording",
|
||||
})
|
||||
}
|
||||
className="bg-muted px-2 py-1 rounded-md text-sm text-muted-foreground cursor-pointer"
|
||||
className="bg-muted px-2 py-1 rounded-md text-sm text-muted-foreground cursor-pointer capitalize"
|
||||
>
|
||||
{currentHotkeys.PlayOrPauseRecording}
|
||||
</kbd>
|
||||
@@ -153,7 +143,7 @@ export const Hotkeys = () => {
|
||||
keyName: "PlayNextSegment",
|
||||
})
|
||||
}
|
||||
className="bg-muted px-2 py-1 rounded-md text-sm text-muted-foreground cursor-pointer"
|
||||
className="bg-muted px-2 py-1 rounded-md text-sm text-muted-foreground cursor-pointer capitalize"
|
||||
>
|
||||
{currentHotkeys.PlayNextSegment}
|
||||
</kbd>
|
||||
@@ -172,7 +162,7 @@ export const Hotkeys = () => {
|
||||
keyName: "Compare",
|
||||
})
|
||||
}
|
||||
className="bg-muted px-2 py-1 rounded-md text-sm text-muted-foreground cursor-pointer"
|
||||
className="bg-muted px-2 py-1 rounded-md text-sm text-muted-foreground cursor-pointer capitalize"
|
||||
>
|
||||
{currentHotkeys.Compare}
|
||||
</kbd>
|
||||
@@ -181,12 +171,12 @@ export const Hotkeys = () => {
|
||||
<Separator />
|
||||
</div>
|
||||
|
||||
<ChangeHotkeyDialog
|
||||
<HotkeysSettings
|
||||
open={open}
|
||||
keyName={selectedItem?.keyName}
|
||||
name={selectedItem?.name}
|
||||
onOpenChange={handleOpenChange}
|
||||
onOpenChange={setOpen}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
};
|
||||
@@ -1,6 +1,8 @@
|
||||
export * from "./preferences";
|
||||
export * from "./about";
|
||||
|
||||
export * from "./hotkeys";
|
||||
export * from "./hotkeys-settings";
|
||||
|
||||
export * from "./default-engine-settings";
|
||||
export * from "./openai-settings";
|
||||
|
||||
Reference in New Issue
Block a user