From 7f47a6443c1296233dfc68d76a788639565201ab Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Tue, 9 Jun 2026 16:08:43 -0700 Subject: [PATCH 1/3] feat(web): polish web context menu fallback and sidebar icon actions Ported from #2451. Co-authored-by: ss Co-Authored-By: Claude Opus 4.8 --- apps/desktop/src/electron/ElectronMenu.ts | 6 + .../src/components/CommandPalette.logic.ts | 2 + apps/web/src/components/CommandPalette.tsx | 1 + apps/web/src/components/Sidebar.tsx | 39 ++-- apps/web/src/contextMenuFallback.ts | 193 ++++++++++++++++-- packages/contracts/src/ipc.ts | 8 + 6 files changed, 220 insertions(+), 29 deletions(-) diff --git a/apps/desktop/src/electron/ElectronMenu.ts b/apps/desktop/src/electron/ElectronMenu.ts index 66b809b2ac7..005c86e0868 100644 --- a/apps/desktop/src/electron/ElectronMenu.ts +++ b/apps/desktop/src/electron/ElectronMenu.ts @@ -44,6 +44,12 @@ function normalizeContextMenuItems(source: readonly ContextMenuItem[]): ContextM continue; } + // Header items are decorative section labels for the web fallback only — + // Electron's native menu has no equivalent affordance, so we skip them. + if (sourceItem.header === true) { + continue; + } + const normalizedItem: ContextMenuItem = { id: sourceItem.id, label: sourceItem.label, diff --git a/apps/web/src/components/CommandPalette.logic.ts b/apps/web/src/components/CommandPalette.logic.ts index 4484232c2b8..982950be5e5 100644 --- a/apps/web/src/components/CommandPalette.logic.ts +++ b/apps/web/src/components/CommandPalette.logic.ts @@ -95,6 +95,7 @@ export function buildProjectActionItems(input: { valuePrefix: string; icon: (project: Project) => ReactNode; runProject: (project: Project) => Promise; + shortcutCommand?: KeybindingCommand; }): CommandPaletteActionItem[] { return input.projects.map((project) => ({ kind: "action", @@ -103,6 +104,7 @@ export function buildProjectActionItems(input: { title: project.name, description: project.cwd, icon: input.icon(project), + ...(input.shortcutCommand !== undefined ? { shortcutCommand: input.shortcutCommand } : {}), run: async () => { await input.runProject(project); }, diff --git a/apps/web/src/components/CommandPalette.tsx b/apps/web/src/components/CommandPalette.tsx index 3dc5a3acb74..d89b8c792cd 100644 --- a/apps/web/src/components/CommandPalette.tsx +++ b/apps/web/src/components/CommandPalette.tsx @@ -647,6 +647,7 @@ function OpenCommandPaletteDialog() { buildProjectActionItems({ projects, valuePrefix: "new-thread-in", + shortcutCommand: "chat.new", icon: (project) => ( = repository_path: "Group by repository path", separate: "Keep separate", }; +const SIDEBAR_ICON_ACTION_BUTTON_CLASS = + "inline-flex h-6 min-w-6 cursor-pointer items-center justify-center rounded-md px-[calc(--spacing(1)-1px)] text-muted-foreground/60 hover:text-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring"; function clampSidebarThreadPreviewCount(value: number): SidebarThreadPreviewCount { return Math.min( @@ -637,13 +639,13 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP ) : !isThreadRunning ? ( appSettingsConfirmThreadArchive ? ( -
+