Skip to content

Commit

Permalink
Merge pull request ChatGPTNextWeb#5396 from DDMeaqua/feat-shortcutkey
Browse files Browse the repository at this point in the history
feat: add shortcut key
  • Loading branch information
Dogtiti authored Sep 12, 2024
2 parents 35f77f4 + 45306bb commit 1234dea
Show file tree
Hide file tree
Showing 6 changed files with 212 additions and 0 deletions.
48 changes: 48 additions & 0 deletions app/components/chat.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -646,3 +646,51 @@
bottom: 30px;
}
}

.shortcut-key-container {
padding: 10px;
overflow-y: auto;
display: flex;
flex-direction: column;
}

.shortcut-key-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 16px;
}

.shortcut-key-item {
display: flex;
justify-content: space-between;
align-items: center;
overflow: hidden;
padding: 10px;
background-color: var(--white);
}

.shortcut-key-title {
font-size: 14px;
color: var(--black);
}

.shortcut-key-keys {
display: flex;
gap: 8px;
}

.shortcut-key {
display: flex;
align-items: center;
justify-content: center;
border: var(--border-in-light);
border-radius: 8px;
padding: 4px;
background-color: var(--gray);
min-width: 32px;
}

.shortcut-key span {
font-size: 12px;
color: var(--black);
}
138 changes: 138 additions & 0 deletions app/components/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import SizeIcon from "../icons/size.svg";
import QualityIcon from "../icons/hd.svg";
import StyleIcon from "../icons/palette.svg";
import PluginIcon from "../icons/plugin.svg";
import ShortcutkeyIcon from "../icons/shortcutkey.svg";

import {
ChatMessage,
Expand Down Expand Up @@ -440,6 +441,7 @@ export function ChatActions(props: {
showPromptHints: () => void;
hitBottom: boolean;
uploading: boolean;
setShowShortcutKeyModal: React.Dispatch<React.SetStateAction<boolean>>;
}) {
const config = useAppConfig();
const navigate = useNavigate();
Expand Down Expand Up @@ -758,6 +760,12 @@ export function ChatActions(props: {
}}
/>
)}

<ChatAction
onClick={() => props.setShowShortcutKeyModal(true)}
text={Locale.Chat.ShortcutKey.Title}
icon={<ShortcutkeyIcon />}
/>
</div>
);
}
Expand Down Expand Up @@ -832,6 +840,67 @@ export function DeleteImageButton(props: { deleteImage: () => void }) {
);
}

export function ShortcutKeyModal(props: { onClose: () => void }) {
const isMac = navigator.platform.toUpperCase().indexOf("MAC") >= 0;
const shortcuts = [
{
title: Locale.Chat.ShortcutKey.newChat,
keys: isMac ? ["⌘", "Shift", "O"] : ["Ctrl", "Shift", "O"],
},
{ title: Locale.Chat.ShortcutKey.focusInput, keys: ["Shift", "Esc"] },
{
title: Locale.Chat.ShortcutKey.copyLastCode,
keys: isMac ? ["⌘", "Shift", ";"] : ["Ctrl", "Shift", ";"],
},
{
title: Locale.Chat.ShortcutKey.copyLastMessage,
keys: isMac ? ["⌘", "Shift", "C"] : ["Ctrl", "Shift", "C"],
},
{
title: Locale.Chat.ShortcutKey.showShortcutKey,
keys: isMac ? ["⌘", "/"] : ["Ctrl", "/"],
},
];
return (
<div className="modal-mask">
<Modal
title={Locale.Chat.ShortcutKey.Title}
onClose={props.onClose}
actions={[
<IconButton
type="primary"
text={Locale.UI.Confirm}
icon={<ConfirmIcon />}
key="ok"
onClick={() => {
props.onClose();
}}
/>,
]}
>
<div className={styles["shortcut-key-container"]}>
<div className={styles["shortcut-key-grid"]}>
{shortcuts.map((shortcut, index) => (
<div key={index} className={styles["shortcut-key-item"]}>
<div className={styles["shortcut-key-title"]}>
{shortcut.title}
</div>
<div className={styles["shortcut-key-keys"]}>
{shortcut.keys.map((key, i) => (
<div key={i} className={styles["shortcut-key"]}>
<span>{key}</span>
</div>
))}
</div>
</div>
))}
</div>
</div>
</Modal>
</div>
);
}

function _Chat() {
type RenderMessage = ChatMessage & { preview?: boolean };

Expand Down Expand Up @@ -1376,6 +1445,70 @@ function _Chat() {
setAttachImages(images);
}

// 快捷键 shortcut keys
const [showShortcutKeyModal, setShowShortcutKeyModal] = useState(false);

useEffect(() => {
const handleKeyDown = (event: any) => {
// 打开新聊天 command + shift + o
if (
(event.metaKey || event.ctrlKey) &&
event.shiftKey &&
event.key.toLowerCase() === "o"
) {
event.preventDefault();
setTimeout(() => {
chatStore.newSession();
navigate(Path.Chat);
}, 10);
}
// 聚焦聊天输入 shift + esc
else if (event.shiftKey && event.key.toLowerCase() === "escape") {
event.preventDefault();
inputRef.current?.focus();
}
// 复制最后一个代码块 command + shift + ;
else if (
(event.metaKey || event.ctrlKey) &&
event.shiftKey &&
event.code === "Semicolon"
) {
event.preventDefault();
const copyCodeButton =
document.querySelectorAll<HTMLElement>(".copy-code-button");
if (copyCodeButton.length > 0) {
copyCodeButton[copyCodeButton.length - 1].click();
}
}
// 复制最后一个回复 command + shift + c
else if (
(event.metaKey || event.ctrlKey) &&
event.shiftKey &&
event.key.toLowerCase() === "c"
) {
event.preventDefault();
const lastNonUserMessage = messages
.filter((message) => message.role !== "user")
.pop();
if (lastNonUserMessage) {
const lastMessageContent = getMessageTextContent(lastNonUserMessage);
copyToClipboard(lastMessageContent);
}
}
// 展示快捷键 command + /
else if ((event.metaKey || event.ctrlKey) && event.key === "/") {
event.preventDefault();
setShowShortcutKeyModal(true);
}
};

window.addEventListener("keydown", handleKeyDown);

return () => {
window.removeEventListener("keydown", handleKeyDown);
};
}, [messages, chatStore, navigate]);

return (
<div className={styles.chat} key={session.id}>
<div className="window-header" data-tauri-drag-region>
Expand Down Expand Up @@ -1692,6 +1825,7 @@ function _Chat() {
setUserInput("/");
onSearch("");
}}
setShowShortcutKeyModal={setShowShortcutKeyModal}
/>
<label
className={`${styles["chat-input-panel-inner"]} ${
Expand Down Expand Up @@ -1763,6 +1897,10 @@ function _Chat() {
}}
/>
)}

{showShortcutKeyModal && (
<ShortcutKeyModal onClose={() => setShowShortcutKeyModal(false)} />
)}
</div>
);
}
Expand Down
1 change: 1 addition & 0 deletions app/icons/shortcutkey.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions app/locales/cn.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ShortcutKeyModal } from "../components/chat";
import { getClientConfig } from "../config/client";
import { SubmitKey } from "../store/config";

Expand Down Expand Up @@ -81,6 +82,14 @@ const cn = {
SaveAs: "存为面具",
},
IsContext: "预设提示词",
ShortcutKey: {
Title: "键盘快捷方式",
newChat: "打开新聊天",
focusInput: "聚焦输入框",
copyLastMessage: "复制最后一个回复",
copyLastCode: "复制最后一个代码块",
showShortcutKey: "显示快捷方式",
},
},
Export: {
Title: "分享聊天记录",
Expand Down
8 changes: 8 additions & 0 deletions app/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ const en: LocaleType = {
SaveAs: "Save as Mask",
},
IsContext: "Contextual Prompt",
ShortcutKey: {
Title: "Keyboard Shortcuts",
newChat: "Open New Chat",
focusInput: "Focus Input Field",
copyLastMessage: "Copy Last Reply",
copyLastCode: "Copy Last Code Block",
showShortcutKey: "Show Shortcuts",
},
},
Export: {
Title: "Export Messages",
Expand Down
8 changes: 8 additions & 0 deletions app/locales/tw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ const tw = {
SaveAs: "另存新檔",
},
IsContext: "預設提示詞",
ShortcutKey: {
Title: "鍵盤快捷方式",
newChat: "打開新聊天",
focusInput: "聚焦輸入框",
copyLastMessage: "複製最後一個回覆",
copyLastCode: "複製最後一個代碼塊",
showShortcutKey: "顯示快捷方式",
},
},
Export: {
Title: "將聊天記錄匯出為 Markdown",
Expand Down

0 comments on commit 1234dea

Please sign in to comment.