mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-06-15 07:14:08 +00:00
fix(webui): show platform-specific new chat shortcut
This commit is contained in:
parent
54d8d3010b
commit
87bd56468c
@ -55,12 +55,29 @@ interface SidebarProps {
|
|||||||
hostChromeInset?: boolean;
|
hostChromeInset?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NavigatorWithUserAgentData = Navigator & {
|
||||||
|
userAgentData?: { platform?: string };
|
||||||
|
};
|
||||||
|
|
||||||
|
function isApplePlatform(): boolean {
|
||||||
|
if (typeof navigator === "undefined") return false;
|
||||||
|
const platform = navigator.platform || "";
|
||||||
|
const userAgentPlatform =
|
||||||
|
(navigator as NavigatorWithUserAgentData).userAgentData?.platform || "";
|
||||||
|
return /mac|iphone|ipad|ipod/i.test(`${platform} ${userAgentPlatform}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function newChatShortcutLabel(): string {
|
||||||
|
return isApplePlatform() ? "⌘⇧O" : "Ctrl+Shift+O";
|
||||||
|
}
|
||||||
|
|
||||||
export function Sidebar(props: SidebarProps) {
|
export function Sidebar(props: SidebarProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [menuPortalContainer, setMenuPortalContainer] =
|
const [menuPortalContainer, setMenuPortalContainer] =
|
||||||
useState<HTMLElement | null>(null);
|
useState<HTMLElement | null>(null);
|
||||||
const collapsed = Boolean(props.collapsed);
|
const collapsed = Boolean(props.collapsed);
|
||||||
const toggleLabel = t("thread.header.toggleSidebar");
|
const toggleLabel = t("thread.header.toggleSidebar");
|
||||||
|
const newChatShortcut = newChatShortcutLabel();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav
|
<nav
|
||||||
@ -124,7 +141,8 @@ export function Sidebar(props: SidebarProps) {
|
|||||||
label={t("sidebar.newChat")}
|
label={t("sidebar.newChat")}
|
||||||
onClick={props.onNewChat}
|
onClick={props.onNewChat}
|
||||||
icon={<SquarePen className="h-4 w-4" />}
|
icon={<SquarePen className="h-4 w-4" />}
|
||||||
shortcut="Cmd/Ctrl+Shift+O"
|
shortcut={newChatShortcut}
|
||||||
|
ariaKeyShortcuts="Meta+Shift+O Control+Shift+O"
|
||||||
/>
|
/>
|
||||||
<SidebarActionButton
|
<SidebarActionButton
|
||||||
collapsed={collapsed}
|
collapsed={collapsed}
|
||||||
@ -215,6 +233,7 @@ function SidebarActionButton({
|
|||||||
active = false,
|
active = false,
|
||||||
className,
|
className,
|
||||||
shortcut,
|
shortcut,
|
||||||
|
ariaKeyShortcuts,
|
||||||
}: {
|
}: {
|
||||||
collapsed: boolean;
|
collapsed: boolean;
|
||||||
label: string;
|
label: string;
|
||||||
@ -223,6 +242,7 @@ function SidebarActionButton({
|
|||||||
active?: boolean;
|
active?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
shortcut?: string;
|
shortcut?: string;
|
||||||
|
ariaKeyShortcuts?: string;
|
||||||
}) {
|
}) {
|
||||||
const title = shortcut ? `${label} (${shortcut})` : collapsed ? label : undefined;
|
const title = shortcut ? `${label} (${shortcut})` : collapsed ? label : undefined;
|
||||||
|
|
||||||
@ -232,6 +252,7 @@ function SidebarActionButton({
|
|||||||
variant="ghost"
|
variant="ghost"
|
||||||
aria-label={label}
|
aria-label={label}
|
||||||
aria-current={active ? "page" : undefined}
|
aria-current={active ? "page" : undefined}
|
||||||
|
aria-keyshortcuts={ariaKeyShortcuts}
|
||||||
title={title}
|
title={title}
|
||||||
onClick={() => onClick()}
|
onClick={() => onClick()}
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|||||||
@ -15,6 +15,13 @@ let mockSessions: ChatSummary[] = [];
|
|||||||
const HERO_GREETING_PATTERN =
|
const HERO_GREETING_PATTERN =
|
||||||
/What should we work on\?|Where should we start\?|What are we building today\?|What should we tackle together\?/;
|
/What should we work on\?|Where should we start\?|What are we building today\?|What should we tackle together\?/;
|
||||||
|
|
||||||
|
function setNavigatorPlatform(platform: string): void {
|
||||||
|
Object.defineProperty(window.navigator, "platform", {
|
||||||
|
configurable: true,
|
||||||
|
value: platform,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function jsonResponse(body: unknown): Response {
|
function jsonResponse(body: unknown): Response {
|
||||||
return {
|
return {
|
||||||
ok: true,
|
ok: true,
|
||||||
@ -200,6 +207,7 @@ describe("App layout", () => {
|
|||||||
attachSpy.mockReset();
|
attachSpy.mockReset();
|
||||||
runStatusHandlers.clear();
|
runStatusHandlers.clear();
|
||||||
window.history.replaceState(null, "", "/");
|
window.history.replaceState(null, "", "/");
|
||||||
|
setNavigatorPlatform("Linux x86_64");
|
||||||
localStorage.removeItem("nanobot-webui.sidebar.completed-runs.v1");
|
localStorage.removeItem("nanobot-webui.sidebar.completed-runs.v1");
|
||||||
vi.mocked(fetchBootstrap).mockReset().mockResolvedValue({
|
vi.mocked(fetchBootstrap).mockReset().mockResolvedValue({
|
||||||
token: "tok",
|
token: "tok",
|
||||||
@ -1409,9 +1417,27 @@ describe("App layout", () => {
|
|||||||
await waitFor(() => expect(connectSpy).toHaveBeenCalled());
|
await waitFor(() => expect(connectSpy).toHaveBeenCalled());
|
||||||
const sidebar = screen.getByRole("navigation", { name: "Sidebar navigation" });
|
const sidebar = screen.getByRole("navigation", { name: "Sidebar navigation" });
|
||||||
|
|
||||||
|
const newChatButton = within(sidebar).getByRole("button", { name: "New chat" });
|
||||||
|
expect(newChatButton).toHaveAttribute(
|
||||||
|
"title",
|
||||||
|
"New chat (Ctrl+Shift+O)",
|
||||||
|
);
|
||||||
|
expect(newChatButton).toHaveAttribute(
|
||||||
|
"aria-keyshortcuts",
|
||||||
|
"Meta+Shift+O Control+Shift+O",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses macOS shortcut glyphs in the sidebar title", async () => {
|
||||||
|
setNavigatorPlatform("MacIntel");
|
||||||
|
render(<App />);
|
||||||
|
|
||||||
|
await waitFor(() => expect(connectSpy).toHaveBeenCalled());
|
||||||
|
const sidebar = screen.getByRole("navigation", { name: "Sidebar navigation" });
|
||||||
|
|
||||||
expect(within(sidebar).getByRole("button", { name: "New chat" })).toHaveAttribute(
|
expect(within(sidebar).getByRole("button", { name: "New chat" })).toHaveAttribute(
|
||||||
"title",
|
"title",
|
||||||
"New chat (Cmd/Ctrl+Shift+O)",
|
"New chat (⌘⇧O)",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user