From ca6c218af4e39ea41ef17530e7aeeac34863eea6 Mon Sep 17 00:00:00 2001 From: Bersabel Tadesse Date: Tue, 1 Sep 2026 14:33:25 -0700 Subject: [PATCH 1/6] Align command palette controls and metadata --- .../commands/CommandPalette.test.tsx | 9 ++++--- .../src/components/commands/PaletteShell.tsx | 24 ++++++++++--------- .../commands/ThreadSearchPaletteMode.tsx | 15 ++++++++---- apps/app/src/components/ui/tab-pill.tsx | 3 +++ 4 files changed, 32 insertions(+), 19 deletions(-) diff --git a/apps/app/src/components/commands/CommandPalette.test.tsx b/apps/app/src/components/commands/CommandPalette.test.tsx index deea6ea1bb..996a7c46ea 100644 --- a/apps/app/src/components/commands/CommandPalette.test.tsx +++ b/apps/app/src/components/commands/CommandPalette.test.tsx @@ -528,13 +528,14 @@ describe("CommandPalette", () => { const modeSelect = screen.getByRole("button", { name: "Threads search" }); expectAttribute(modeSelect, "aria-pressed", "true"); expect(modeSelect.querySelector('[data-icon="Search"]')).not.toBeNull(); + expectClasses(modeSelect.parentElement, "border-border/70", "bg-background/70"); expectAttribute( screen.getByRole("button", { name: "Return to commands" }), "data-tab-pill-close", ); - expect( - screen.getByRole("button", { name: "Thread scope" }).textContent, - ).toContain("All"); + const scope = screen.getByRole("button", { name: "Thread scope" }); + expect(scope.textContent).toContain("All"); + expectClasses(scope, "text-subtle-foreground", "opacity-70"); expectText(screen.getByTestId("command-palette"), "Split"); const footer = screen .getByTestId("command-palette") @@ -855,6 +856,7 @@ describe("CommandPalette", () => { expectClasses( row.querySelector("[data-palette-thread-metadata]"), "text-subtle-foreground", + "opacity-70", ); } expectClasses( @@ -937,6 +939,7 @@ describe("CommandPalette", () => { expectClasses( row.querySelector("[data-palette-thread-metadata]"), "text-subtle-foreground", + "opacity-70", ); } expect(results.querySelector("[data-palette-thread-state]")).toBeNull(); diff --git a/apps/app/src/components/commands/PaletteShell.tsx b/apps/app/src/components/commands/PaletteShell.tsx index 89eeddadb7..73d6e25048 100644 --- a/apps/app/src/components/commands/PaletteShell.tsx +++ b/apps/app/src/components/commands/PaletteShell.tsx @@ -4,6 +4,11 @@ import { Icon } from "@bb/shared-ui/icon"; import { useScrollOverflowState } from "@/components/thread/timeline/useScrollOverflowState"; import { TabPill } from "@/components/ui/tab-pill"; +export const PALETTE_FOOTER_CONTROL_SURFACE_CLASS = + "border border-border/70 bg-background/70 shadow-xs"; +export const PALETTE_FOOTER_KEYCAP_CLASS = `inline-flex min-w-5 items-center justify-center rounded px-1.5 py-0.5 font-mono text-xs leading-none text-muted-foreground ${PALETTE_FOOTER_CONTROL_SURFACE_CLASS}`; +export const PALETTE_FOOTER_LABEL_CLASS = "text-subtle-foreground opacity-70"; + interface PaletteModeChipProps { clearLabel: string; icon: Parameters[0]["name"]; @@ -67,9 +72,7 @@ export function PaletteShell({ className="flex h-10 items-center gap-2 px-3" data-palette-input-frame > - {modeChip === undefined ? null : ( - - )} + {modeChip === undefined ? null : } ( {index === 0 ? null : ( - + / )} - - {keys} - + {keys} ))} - + {hint.label} @@ -169,6 +170,7 @@ function PaletteModeChip({ label={label} title={label} isActive + className={PALETTE_FOOTER_CONTROL_SURFACE_CLASS} onSelect={() => undefined} leadingVisual={} closeAction={{ onClose: onClear, closeLabel: clearLabel }} diff --git a/apps/app/src/components/commands/ThreadSearchPaletteMode.tsx b/apps/app/src/components/commands/ThreadSearchPaletteMode.tsx index c567fa667f..ada14a68c4 100644 --- a/apps/app/src/components/commands/ThreadSearchPaletteMode.tsx +++ b/apps/app/src/components/commands/ThreadSearchPaletteMode.tsx @@ -35,7 +35,7 @@ import { } from "@/lib/command-palette/palette-thread-search"; import { windowPaletteThreadSearchText } from "@/lib/command-palette/palette-thread-search-window"; import type { PaletteModeViewProps } from "@/lib/command-palette/palette-mode"; -import { PaletteShell } from "./PaletteShell"; +import { PALETTE_FOOTER_LABEL_CLASS, PaletteShell } from "./PaletteShell"; export function ThreadSearchPaletteMode({ onExit, @@ -253,8 +253,7 @@ export function ThreadSearchPaletteMode({ ? "Searching threads" : trimmedQuery.length === 1 ? "Type at least 2 characters" - : (navigation.isLoading || archivedThreads.isLoading) && - result.isRecent + : (navigation.isLoading || archivedThreads.isLoading) && result.isRecent ? "Loading recent threads" : result.isRecent ? "No recent threads" @@ -349,7 +348,10 @@ function ThreadSearchScopeFilter({ aria-haspopup="listbox" aria-expanded={open} aria-label="Thread scope" - className="inline-flex items-center gap-1.5 rounded-md px-2 py-1 text-xs text-subtle-foreground outline-none hover:bg-state-hover hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring" + className={cn( + "inline-flex items-center gap-1.5 rounded-md px-2 py-1 text-xs outline-none hover:bg-state-hover hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring", + PALETTE_FOOTER_LABEL_CLASS, + )} onClick={() => setOpen((value) => !value)} onKeyDown={(event) => { if (event.key === "ArrowDown" || event.key === "ArrowUp") { @@ -478,7 +480,10 @@ function ThreadSearchPaletteRow({ /> diff --git a/apps/app/src/components/ui/tab-pill.tsx b/apps/app/src/components/ui/tab-pill.tsx index 99ffdb98d5..7bdc0c4a94 100644 --- a/apps/app/src/components/ui/tab-pill.tsx +++ b/apps/app/src/components/ui/tab-pill.tsx @@ -23,6 +23,7 @@ interface TabPillCloseAction { interface TabPillProps { label: string; + className?: string; ariaLabel?: string; ariaKeyshortcuts?: string; iconOnly?: boolean; @@ -39,6 +40,7 @@ interface TabPillProps { export function TabPill({ label, + className, ariaLabel, ariaKeyshortcuts, iconOnly = false, @@ -72,6 +74,7 @@ export function TabPill({ isActive ? cn(CONTEXT_SELECTION_SURFACE_CLASS, "text-foreground") : "text-muted-foreground hover:bg-state-hover", + className, )} >