From f2195154f6a94e3ac324465c1adc6150180a186e Mon Sep 17 00:00:00 2001 From: DDMeaqua Date: Mon, 9 Sep 2024 18:55:37 +0800 Subject: [PATCH 1/8] feat: add shortcut key --- app/components/chat.module.scss | 49 +++++++++++++ app/components/chat.tsx | 118 ++++++++++++++++++++++++++++++++ app/locales/cn.ts | 9 +++ app/locales/en.ts | 8 +++ app/locales/tw.ts | 8 +++ 5 files changed, 192 insertions(+) diff --git a/app/components/chat.module.scss b/app/components/chat.module.scss index 7176399cc36..98972f623bd 100644 --- a/app/components/chat.module.scss +++ b/app/components/chat.module.scss @@ -646,3 +646,52 @@ 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(250px, 1fr)); + gap: 16px; +} + +.shortcut-key-item { + display: flex; + flex-direction: column; + overflow: hidden; + border: 1px solid #ddd; + border-radius: 10px; + padding: 10px; + background-color: #fff; +} + +.shortcut-key-title { + font-size: 14px; + color: #333; + margin-bottom: 8px; +} + +.shortcut-key-keys { + display: flex; + gap: 8px; +} + +.shortcut-key { + display: flex; + align-items: center; + justify-content: center; + border: 1px solid #ddd; + border-radius: 8px; + padding: 4px; + background-color: #f9f9f9; + min-width: 32px; +} + +.shortcut-key span { + font-size: 12px; +} \ No newline at end of file diff --git a/app/components/chat.tsx b/app/components/chat.tsx index dad1933ace9..ab94ab41dcd 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -829,6 +829,57 @@ export function DeleteImageButton(props: { deleteImage: () => void }) { ); } +export function ShortcutKeyModal(props: { onClose: () => void }) { + const shortcuts = [ + { title: Locale.Chat.ShortcutKey.newChat, keys: ["⌘", "Shift", "o"] }, + { title: Locale.Chat.ShortcutKey.focusInput, keys: ["Shift", "Esc"] }, + { title: Locale.Chat.ShortcutKey.copyLastCode, keys: ["⌘", "Shift", ";"] }, + { + title: Locale.Chat.ShortcutKey.copyLastMessage, + keys: ["⌘", "Shift", "c"], + }, + { title: Locale.Chat.ShortcutKey.showShortcutKey, keys: ["⌘", "/"] }, + ]; + return ( +
+ } + key="ok" + onClick={() => { + props.onClose(); + }} + />, + ]} + > +
+
+ {shortcuts.map((shortcut, index) => ( +
+
+ {shortcut.title} +
+
+ {shortcut.keys.map((key, i) => ( +
+ {key} +
+ ))} +
+
+ ))} +
+
+
+
+ ); +} + function _Chat() { type RenderMessage = ChatMessage & { preview?: boolean }; @@ -1373,6 +1424,69 @@ function _Chat() { setAttachImages(images); } + // 快捷键 + const [showShortcutKeyModal, setShowShortcutKeyModal] = useState(false); + + useEffect(() => { + const handleKeyDown = (event) => { + // 打开新聊天 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(".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 (
@@ -1760,6 +1874,10 @@ function _Chat() { }} /> )} + + {showShortcutKeyModal && ( + setShowShortcutKeyModal(false)} /> + )}
); } diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 33e368f69f4..24f707e4018 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -1,3 +1,4 @@ +import { ShortcutKeyModal } from "../components/chat"; import { getClientConfig } from "../config/client"; import { SubmitKey } from "../store/config"; @@ -81,6 +82,14 @@ const cn = { SaveAs: "存为面具", }, IsContext: "预设提示词", + ShortcutKey: { + Title: "键盘快捷方式", + newChat: "打开新聊天", + focusInput: "聚焦输入框", + copyLastMessage: "复制最后一个回复", + copyLastCode: "复制最后一个代码块", + showShortcutKey: "显示快捷方式", + }, }, Export: { Title: "分享聊天记录", diff --git a/app/locales/en.ts b/app/locales/en.ts index 403b9b687e7..09b76f1fa12 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -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", diff --git a/app/locales/tw.ts b/app/locales/tw.ts index 6b2c0fd65b1..c54a7b8c5ae 100644 --- a/app/locales/tw.ts +++ b/app/locales/tw.ts @@ -81,6 +81,14 @@ const tw = { SaveAs: "另存新檔", }, IsContext: "預設提示詞", + ShortcutKey: { + Title: "鍵盤快捷方式", + newChat: "打開新聊天", + focusInput: "聚焦輸入框", + copyLastMessage: "複製最後一個回覆", + copyLastCode: "複製最後一個代碼塊", + showShortcutKey: "顯示快捷方式", + }, }, Export: { Title: "將聊天記錄匯出為 Markdown", From 7804182d0d027f630497c911652cd877ea0cc30a Mon Sep 17 00:00:00 2001 From: DDMeaqua Date: Mon, 9 Sep 2024 19:18:12 +0800 Subject: [PATCH 2/8] fix: type error --- app/components/chat.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/components/chat.tsx b/app/components/chat.tsx index ab94ab41dcd..085292585fc 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -1428,7 +1428,7 @@ function _Chat() { const [showShortcutKeyModal, setShowShortcutKeyModal] = useState(false); useEffect(() => { - const handleKeyDown = (event) => { + const handleKeyDown = (event: any) => { // 打开新聊天 command + shift + o if ( (event.metaKey || event.ctrlKey) && @@ -1453,7 +1453,8 @@ function _Chat() { event.code === "Semicolon" ) { event.preventDefault(); - const copyCodeButton = document.querySelectorAll(".copy-code-button"); + const copyCodeButton = + document.querySelectorAll(".copy-code-button"); if (copyCodeButton.length > 0) { copyCodeButton[copyCodeButton.length - 1].click(); } From 61245e3d7e41064bc9b5a431848489a3d82c2ef5 Mon Sep 17 00:00:00 2001 From: DDMeaqua Date: Mon, 9 Sep 2024 19:29:10 +0800 Subject: [PATCH 3/8] fix: dark theme css --- app/components/chat.module.scss | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/components/chat.module.scss b/app/components/chat.module.scss index 98972f623bd..5145188ec53 100644 --- a/app/components/chat.module.scss +++ b/app/components/chat.module.scss @@ -664,15 +664,17 @@ display: flex; flex-direction: column; overflow: hidden; - border: 1px solid #ddd; + border: var(--border-in-light); border-radius: 10px; padding: 10px; - background-color: #fff; + background-color: var(--white); + box-shadow: var(--card-shadow); + transition: background-color 0.3s ease, box-shadow 0.3s ease; } .shortcut-key-title { font-size: 14px; - color: #333; + color: var(--black); margin-bottom: 8px; } @@ -685,13 +687,14 @@ display: flex; align-items: center; justify-content: center; - border: 1px solid #ddd; + border: var(--border-in-light); border-radius: 8px; padding: 4px; - background-color: #f9f9f9; + background-color: var(--gray); min-width: 32px; } .shortcut-key span { font-size: 12px; + color: var(--black); } \ No newline at end of file From e578c5f3ade565bc179ac2b639fa4d64b7d12a05 Mon Sep 17 00:00:00 2001 From: DDMeaqua Date: Tue, 10 Sep 2024 12:01:51 +0800 Subject: [PATCH 4/8] =?UTF-8?q?chore:=20=E6=A0=B7=E5=BC=8F=E6=9B=B4?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/components/chat.module.scss | 10 +++------- app/components/chat.tsx | 20 +++++++++++++++----- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/app/components/chat.module.scss b/app/components/chat.module.scss index 5145188ec53..73542fc67f1 100644 --- a/app/components/chat.module.scss +++ b/app/components/chat.module.scss @@ -656,26 +656,22 @@ .shortcut-key-grid { display: grid; - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); gap: 16px; } .shortcut-key-item { display: flex; - flex-direction: column; + justify-content: space-between; + align-items: center; overflow: hidden; - border: var(--border-in-light); - border-radius: 10px; padding: 10px; background-color: var(--white); - box-shadow: var(--card-shadow); - transition: background-color 0.3s ease, box-shadow 0.3s ease; } .shortcut-key-title { font-size: 14px; color: var(--black); - margin-bottom: 8px; } .shortcut-key-keys { diff --git a/app/components/chat.tsx b/app/components/chat.tsx index 085292585fc..a91c8af7e4d 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -830,15 +830,25 @@ 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: ["⌘", "Shift", "o"] }, + { + 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: ["⌘", "Shift", ";"] }, + { + title: Locale.Chat.ShortcutKey.copyLastCode, + keys: isMac ? ["⌘", "Shift", ";"] : ["Ctrl", "Shift", ";"], + }, { title: Locale.Chat.ShortcutKey.copyLastMessage, - keys: ["⌘", "Shift", "c"], + keys: isMac ? ["⌘", "Shift", "C"] : ["Ctrl", "Shift", "C"], + }, + { + title: Locale.Chat.ShortcutKey.showShortcutKey, + keys: isMac ? ["⌘", "/"] : ["Ctrl", "/"], }, - { title: Locale.Chat.ShortcutKey.showShortcutKey, keys: ["⌘", "/"] }, ]; return (
@@ -1424,7 +1434,7 @@ function _Chat() { setAttachImages(images); } - // 快捷键 + // 快捷键 shortcut keys const [showShortcutKeyModal, setShowShortcutKeyModal] = useState(false); useEffect(() => { From 18e2403b01943ad245e84756695aa9db0a70ad3b Mon Sep 17 00:00:00 2001 From: DDMeaqua Date: Tue, 10 Sep 2024 14:30:51 +0800 Subject: [PATCH 5/8] =?UTF-8?q?chore:=20=E6=9B=B4=E6=8D=A2icon?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/components/chat.tsx | 9 +++++++++ app/icons/shortcutkey.svg | 1 + 2 files changed, 10 insertions(+) create mode 100644 app/icons/shortcutkey.svg diff --git a/app/components/chat.tsx b/app/components/chat.tsx index a91c8af7e4d..1fc10c35c9c 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -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, @@ -437,6 +438,7 @@ export function ChatActions(props: { showPromptHints: () => void; hitBottom: boolean; uploading: boolean; + setShowShortcutKeyModal: () => void; }) { const config = useAppConfig(); const navigate = useNavigate(); @@ -755,6 +757,12 @@ export function ChatActions(props: { }} /> )} + + props.setShowShortcutKeyModal(true)} + text={Locale.Chat.ShortcutKey.Title} + icon={} + />
); } @@ -1814,6 +1822,7 @@ function _Chat() { setUserInput("/"); onSearch(""); }} + setShowShortcutKeyModal={setShowShortcutKeyModal} />