Skip to content

Commit 0a7b445

Browse files
authored
feat: service list popup box supports keyboard-only operation (#359)
* feat: service list popup box supports keyboard-only operation * docs: update changelog
1 parent 62cbb95 commit 0a7b445

3 files changed

Lines changed: 46 additions & 14 deletions

File tree

docs/content.en/docs/release-notes/_index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Information about release notes of Coco Server is provided here.
1818
- feat: add font icon for search list #342
1919
- feat: add a border to the main window in Windows 10 #343
2020
- feat: mobile terminal adaptation about style #348
21+
- feat: service list popup box supports keyboard-only operation #359
2122

2223
### Bug fix
2324

src/components/Assistant/ChatHeader.tsx

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { useConnectStore } from "@/stores/connectStore";
3232
import platformAdapter from "@/utils/platformAdapter";
3333
import VisibleKey from "../Common/VisibleKey";
3434
import { useShortcutsStore } from "@/stores/shortcutsStore";
35+
import { useKeyPress } from "ahooks";
3536

3637
interface ChatHeaderProps {
3738
onCreateNewChat: () => void;
@@ -85,7 +86,8 @@ export function ChatHeader({
8586

8687
const fetchServers = useCallback(
8788
async (resetSelection: boolean) => {
88-
platformAdapter.commands("list_coco_servers")
89+
platformAdapter
90+
.commands("list_coco_servers")
8991
.then((res: any) => {
9092
const enabledServers = (res as IServer[]).filter(
9193
(server) => server.enabled !== false
@@ -164,6 +166,33 @@ export function ChatHeader({
164166
platformAdapter.emitEvent("open_settings", "connect");
165167
};
166168

169+
useKeyPress(["uparrow", "downarrow"], (_, key) => {
170+
const isOpen = serverListButtonRef.current?.dataset["open"] != null;
171+
const length = serverList.length;
172+
173+
if (!isOpen || length <= 1) return;
174+
175+
const currentIndex = serverList.findIndex((server) => {
176+
return server.id === currentService?.id;
177+
});
178+
179+
let nextIndex = currentIndex;
180+
181+
if (key === "uparrow") {
182+
nextIndex = currentIndex > 0 ? currentIndex - 1 : length - 1;
183+
} else if (key === "downarrow") {
184+
nextIndex = currentIndex < serverList.length - 1 ? currentIndex + 1 : 0;
185+
}
186+
187+
switchServer(serverList[nextIndex]);
188+
});
189+
190+
const handleRefresh = async () => {
191+
setIsRefreshing(true);
192+
await fetchServers(false);
193+
setTimeout(() => setIsRefreshing(false), 1000);
194+
};
195+
167196
return (
168197
<header
169198
className="flex items-center justify-between py-2 px-3"
@@ -280,22 +309,22 @@ export function ChatHeader({
280309
onClick={openSettings}
281310
className="p-1 rounded-md hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-500 dark:text-gray-400"
282311
>
283-
<Settings className="h-4 w-4 text-[#0287FF]" />
312+
<VisibleKey shortcut=",">
313+
<Settings className="h-4 w-4 text-[#0287FF]" />
314+
</VisibleKey>
284315
</button>
285316
<button
286-
onClick={async () => {
287-
setIsRefreshing(true);
288-
await fetchServers(false);
289-
setTimeout(() => setIsRefreshing(false), 1000);
290-
}}
317+
onClick={handleRefresh}
291318
className="p-1 rounded-md hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-500 dark:text-gray-400"
292319
disabled={isRefreshing}
293320
>
294-
<RefreshCw
295-
className={`h-4 w-4 text-[#0287FF] transition-transform duration-1000 ${
296-
isRefreshing ? "animate-spin" : ""
297-
}`}
298-
/>
321+
<VisibleKey shortcut="R" onKeypress={handleRefresh}>
322+
<RefreshCw
323+
className={`h-4 w-4 text-[#0287FF] transition-transform duration-1000 ${
324+
isRefreshing ? "animate-spin" : ""
325+
}`}
326+
/>
327+
</VisibleKey>
299328
</button>
300329
</div>
301330
</div>

src/components/Common/VisibleKey.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { FC, ReactNode } from "react";
55
interface VisibleKeyProps {
66
shortcut: string;
77
children: ReactNode;
8-
onKeypress: () => void;
8+
onKeypress?: () => void;
99
}
1010

1111
const VisibleKey: FC<VisibleKeyProps> = (props) => {
@@ -18,7 +18,9 @@ const VisibleKey: FC<VisibleKeyProps> = (props) => {
1818
return state.modifierKeyPressed;
1919
});
2020

21-
useKeyPress(`${modifierKey}.${shortcut}`, onKeypress);
21+
useKeyPress(`${modifierKey}.${shortcut}`, () => {
22+
onKeypress?.();
23+
});
2224

2325
return modifierKeyPressed ? (
2426
<div className="size-4 flex items-center justify-center font-normal text-xs text-[#333] leading-[14px] bg-[#ccc] dark:bg-[#6B6B6B] rounded-md shadow-[-6px_0px_6px_2px_#fff] dark:shadow-[-6px_0px_6px_2px_#000]">

0 commit comments

Comments
 (0)