Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions apps/desktop/src/electron/ElectronMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions apps/web/src/components/CommandPalette.logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export function buildProjectActionItems(input: {
valuePrefix: string;
icon: (project: Project) => ReactNode;
runProject: (project: Project) => Promise<void>;
shortcutCommand?: KeybindingCommand;
}): CommandPaletteActionItem[] {
return input.projects.map((project) => ({
kind: "action",
Expand All @@ -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);
},
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/components/CommandPalette.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,7 @@ function OpenCommandPaletteDialog() {
buildProjectActionItems({
projects,
valuePrefix: "new-thread-in",
shortcutCommand: "chat.new",
icon: (project) => (
<ProjectFavicon
environmentId={project.environmentId}
Expand Down
36 changes: 20 additions & 16 deletions apps/web/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ const PROJECT_GROUPING_MODE_LABELS: Record<SidebarProjectGroupingMode, string> =
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(
Expand Down Expand Up @@ -635,21 +637,21 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP
data-thread-selection-safe
data-testid={`thread-archive-confirm-${thread.id}`}
aria-label={`Confirm archive ${thread.title}`}
className="absolute top-1/2 right-1 inline-flex h-5 -translate-y-1/2 cursor-pointer items-center rounded-full bg-destructive/12 px-2 text-[10px] font-medium text-destructive transition-colors hover:bg-destructive/18 focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-destructive/40"
className="absolute top-1/2 right-1 inline-flex h-5 -translate-y-1/2 cursor-pointer items-center rounded-md bg-destructive/12 px-2 text-[10px] font-medium text-destructive transition-colors hover:bg-destructive/18 focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-destructive/40"
onPointerDown={stopPropagationOnPointerDown}
onClick={handleConfirmArchiveClick}
>
Confirm
</button>
) : !isThreadRunning ? (
appSettingsConfirmThreadArchive ? (
<div className="pointer-events-none absolute top-1/2 right-1 -translate-y-1/2 opacity-0 transition-opacity duration-150 max-sm:pointer-events-auto max-sm:opacity-100 group-hover/menu-sub-item:pointer-events-auto group-hover/menu-sub-item:opacity-100 group-focus-within/menu-sub-item:pointer-events-auto group-focus-within/menu-sub-item:opacity-100">
<div className="pointer-events-none absolute top-1/2 right-0.5 -translate-y-1/2 opacity-0 transition-opacity duration-150 max-sm:pointer-events-auto max-sm:opacity-100 group-hover/menu-sub-item:pointer-events-auto group-hover/menu-sub-item:opacity-100 group-focus-within/menu-sub-item:pointer-events-auto group-focus-within/menu-sub-item:opacity-100">
<button
type="button"
data-thread-selection-safe
data-testid={`thread-archive-${thread.id}`}
aria-label={`Archive ${thread.title}`}
className="inline-flex size-5 cursor-pointer items-center justify-center text-muted-foreground/60 transition-colors hover:text-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring"
className={SIDEBAR_ICON_ACTION_BUTTON_CLASS}
onPointerDown={stopPropagationOnPointerDown}
onClick={handleStartArchiveConfirmation}
>
Expand All @@ -660,13 +662,13 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP
<Tooltip>
<TooltipTrigger
render={
<div className="pointer-events-none absolute top-1/2 right-1 -translate-y-1/2 opacity-0 transition-opacity duration-150 max-sm:pointer-events-auto max-sm:opacity-100 group-hover/menu-sub-item:pointer-events-auto group-hover/menu-sub-item:opacity-100 group-focus-within/menu-sub-item:pointer-events-auto group-focus-within/menu-sub-item:opacity-100">
<div className="pointer-events-none absolute top-1/2 right-0.5 -translate-y-1/2 opacity-0 transition-opacity duration-150 max-sm:pointer-events-auto max-sm:opacity-100 group-hover/menu-sub-item:pointer-events-auto group-hover/menu-sub-item:opacity-100 group-focus-within/menu-sub-item:pointer-events-auto group-focus-within/menu-sub-item:opacity-100">
<button
type="button"
data-thread-selection-safe
data-testid={`thread-archive-${thread.id}`}
aria-label={`Archive ${thread.title}`}
className="inline-flex size-5 cursor-pointer items-center justify-center text-muted-foreground/60 transition-colors hover:text-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring"
className={SIDEBAR_ICON_ACTION_BUTTON_CLASS}
onPointerDown={stopPropagationOnPointerDown}
onClick={handleArchiveImmediateClick}
>
Expand Down Expand Up @@ -712,7 +714,7 @@ const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowP
</Tooltip>
) : (
<span
className={`text-[10px] ${
className={`text-[10px] tabular-nums ${
isHighlighted
? "text-foreground/72 dark:text-foreground/82"
: "text-muted-foreground/40"
Expand Down Expand Up @@ -1495,12 +1497,14 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec
...(options?.isDisabled?.(singleMember) ? { disabled: true } : {}),
}),
label,
...(action === "delete" ? { icon: "trash" } : {}),
};
}

return {
id: `${action}:submenu`,
label,
...(action === "delete" ? { icon: "trash" } : {}),
children: project.memberProjects.map((member) =>
makeLeaf(action, member, {
...(options?.destructive ? { destructive: true } : {}),
Expand All @@ -1512,10 +1516,10 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec

const clicked = await api.contextMenu.show(
[
buildTargetedItem("rename", "Rename project"),
buildTargetedItem("grouping", "Project grouping…"),
buildTargetedItem("copy-path", "Copy Project Path"),
buildTargetedItem("delete", "Remove project", {
buildTargetedItem("rename", "Rename"),
buildTargetedItem("grouping", "Group into..."),
buildTargetedItem("copy-path", "Copy Path"),
buildTargetedItem("delete", "Remove", {
destructive: true,
}),
],
Expand Down Expand Up @@ -1931,7 +1935,7 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec
{ id: "mark-unread", label: "Mark unread" },
{ id: "copy-path", label: "Copy Path" },
{ id: "copy-thread-id", label: "Copy Thread ID" },
{ id: "delete", label: "Delete", destructive: true },
{ id: "delete", label: "Delete", destructive: true, icon: "trash" },
],
position,
);
Expand Down Expand Up @@ -2073,12 +2077,12 @@ const SidebarProjectItem = memo(function SidebarProjectItem(props: SidebarProjec
<Tooltip>
<TooltipTrigger
render={
<div className="pointer-events-none absolute top-1 right-1.5 opacity-0 transition-opacity duration-150 max-sm:pointer-events-auto max-sm:opacity-100 group-hover/project-header:pointer-events-auto group-hover/project-header:opacity-100 group-focus-within/project-header:pointer-events-auto group-focus-within/project-header:opacity-100">
<div className="pointer-events-none absolute top-[calc(50%+1px)] right-0.5 -translate-y-1/2 opacity-0 transition-opacity duration-150 max-sm:pointer-events-auto max-sm:opacity-100 group-hover/project-header:pointer-events-auto group-hover/project-header:opacity-100 group-focus-within/project-header:pointer-events-auto group-focus-within/project-header:opacity-100">
<button
type="button"
aria-label={`Create new thread in ${project.displayName}`}
data-testid="new-thread-button"
className="inline-flex size-5 cursor-pointer items-center justify-center rounded-md text-muted-foreground/60 hover:bg-secondary hover:text-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring"
className={SIDEBAR_ICON_ACTION_BUTTON_CLASS}
onClick={handleCreateThreadClick}
>
<SquarePenIcon className="size-3.5" />
Expand Down Expand Up @@ -2316,7 +2320,7 @@ function ProjectSortMenu({
<Tooltip>
<TooltipTrigger
render={
<MenuTrigger className="inline-flex size-5 cursor-pointer items-center justify-center rounded-md text-muted-foreground/60 transition-colors hover:bg-accent hover:text-foreground" />
<MenuTrigger className="inline-flex h-6 min-w-6 cursor-pointer items-center justify-center rounded-md px-[calc(--spacing(1)-1px)] text-muted-foreground/60 transition-colors hover:bg-accent hover:text-foreground" />
}
>
<ArrowUpDownIcon className="size-3.5" />
Expand Down Expand Up @@ -2654,7 +2658,7 @@ const SidebarProjectsContent = memo(function SidebarProjectsContent(
/>
}
>
<SearchIcon className="size-3.5" />
<SearchIcon className="size-3.5 text-muted-foreground/70" />
<span className="flex-1 truncate text-left text-xs">Search</span>
{commandPaletteShortcutLabel ? (
<Kbd className="h-4 min-w-0 rounded-sm px-1.5 text-[10px]">
Expand Down Expand Up @@ -2711,7 +2715,7 @@ const SidebarProjectsContent = memo(function SidebarProjectsContent(
type="button"
aria-label="Add project"
data-testid="sidebar-add-project-trigger"
className="inline-flex size-5 cursor-pointer items-center justify-center rounded-md text-muted-foreground/60 transition-colors hover:bg-accent hover:text-foreground"
className="inline-flex h-6 min-w-6 cursor-pointer items-center justify-center rounded-md px-[calc(--spacing(1)-1px)] text-muted-foreground/60 transition-colors hover:bg-accent hover:text-foreground"
onClick={openAddProject}
/>
}
Expand Down
Loading
Loading