From 32bd5b3c650a619651e1ab248e1e89a086b1c34f Mon Sep 17 00:00:00 2001 From: Alejandro Tamayo Date: Fri, 17 Apr 2026 21:44:53 +0200 Subject: [PATCH] ui(agents): light-theme overlays + draggable top strip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Overlays (Dropdown, Popover, ContextMenu, Select) used to hardcode a `dark` class on their content, producing a dark surface in the otherwise light UI. Replaced the hardcoded class with an opt-in `forceDark` prop (default `false`) across all four primitives, so every dropdown / popover / context menu / select follows the active theme by default. Added a 32px draggable strip at the top of the main content pane in `agents-layout.tsx` so window dragging works from any view (previously only the sidebar top was draggable). Added `-webkit-app-region: no-drag` carve-outs to interactive elements that sit inside the strip — AgentsHeaderControls hamburger, NewChatForm mobile fallback, SubChatSelector tabs and Plus button, AutomationsView / InboxView / AutomationsDetailView headers — so buttons remain clickable while empty gaps stay draggable. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/renderer/components/ui/context-menu.tsx | 22 +++++++++++----- src/renderer/components/ui/dropdown-menu.tsx | 26 ++++++++++++++----- src/renderer/components/ui/popover.tsx | 2 +- src/renderer/components/ui/select.tsx | 9 ++++--- .../features/agents/main/new-chat-form.tsx | 4 +++ .../agents/ui/agents-header-controls.tsx | 4 +++ .../features/agents/ui/archive-popover.tsx | 1 - .../features/agents/ui/sub-chat-selector.tsx | 16 ++++++++---- .../automations/automations-detail-view.tsx | 12 ++++++++- .../features/automations/automations-view.tsx | 8 ++++++ .../features/automations/inbox-view.tsx | 16 ++++++++++-- .../features/layout/agents-layout.tsx | 12 ++++++++- 12 files changed, 106 insertions(+), 26 deletions(-) diff --git a/src/renderer/components/ui/context-menu.tsx b/src/renderer/components/ui/context-menu.tsx index 9d5271d33..2c806d6f5 100644 --- a/src/renderer/components/ui/context-menu.tsx +++ b/src/renderer/components/ui/context-menu.tsx @@ -48,11 +48,18 @@ ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName const ContextMenuSubContent = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( + React.ComponentPropsWithoutRef & { + forceDark?: boolean + } +>(({ className, forceDark = false, ...props }, ref) => ( )) @@ -60,14 +67,17 @@ ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName const ContextMenuContent = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( + React.ComponentPropsWithoutRef & { + forceDark?: boolean + } +>(({ className, forceDark = false, ...props }, ref) => ( , - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( + React.ComponentPropsWithoutRef & { + forceDark?: boolean + } +>(({ className, forceDark = false, ...props }, ref) => ( )) @@ -60,13 +67,20 @@ DropdownMenuSubContent.displayName = const DropdownMenuContent = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, sideOffset = 4, ...props }, ref) => ( + React.ComponentPropsWithoutRef & { + forceDark?: boolean + } +>(({ className, sideOffset = 4, forceDark = false, ...props }, ref) => ( diff --git a/src/renderer/components/ui/popover.tsx b/src/renderer/components/ui/popover.tsx index c9fdddbab..b86ccb3c4 100644 --- a/src/renderer/components/ui/popover.tsx +++ b/src/renderer/components/ui/popover.tsx @@ -22,7 +22,7 @@ const PopoverContent = React.forwardRef< } >( ( - { className, align = "center", sideOffset = 4, forceDark = true, ...props }, + { className, align = "center", sideOffset = 4, forceDark = false, ...props }, ref, ) => ( diff --git a/src/renderer/components/ui/select.tsx b/src/renderer/components/ui/select.tsx index a9e531230..7b3287b75 100644 --- a/src/renderer/components/ui/select.tsx +++ b/src/renderer/components/ui/select.tsx @@ -98,8 +98,10 @@ SelectScrollDownButton.displayName = const SelectContent = React.forwardRef< React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, position = "popper", ...props }, ref) => ( + React.ComponentPropsWithoutRef & { + forceDark?: boolean + } +>(({ className, children, position = "popper", forceDark = false, ...props }, ref) => ( diff --git a/src/renderer/features/agents/ui/agents-header-controls.tsx b/src/renderer/features/agents/ui/agents-header-controls.tsx index 9e4858673..82b141a86 100644 --- a/src/renderer/features/agents/ui/agents-header-controls.tsx +++ b/src/renderer/features/agents/ui/agents-header-controls.tsx @@ -39,6 +39,10 @@ export function AgentsHeaderControls({ onClick={onToggleSidebar} className="h-6 w-6 p-0 hover:bg-foreground/10 transition-[background-color,transform] duration-150 ease-out active:scale-[0.97] text-foreground flex-shrink-0 rounded-md relative" aria-label="Open sidebar" + style={{ + // @ts-expect-error - WebKit-specific property + WebkitAppRegion: "no-drag", + }} > {/* Unseen changes indicator */} diff --git a/src/renderer/features/agents/ui/archive-popover.tsx b/src/renderer/features/agents/ui/archive-popover.tsx index a8af3d2f5..1842a293a 100644 --- a/src/renderer/features/agents/ui/archive-popover.tsx +++ b/src/renderer/features/agents/ui/archive-popover.tsx @@ -508,7 +508,6 @@ export const ArchivePopover = memo(function ArchivePopover({ trigger }: ArchiveP side="right" align="end" sideOffset={8} - forceDark={false} className="w-[250px] h-[400px] p-0 flex flex-col overflow-hidden" onKeyDown={handleKeyDown} tabIndex={-1} diff --git a/src/renderer/features/agents/ui/sub-chat-selector.tsx b/src/renderer/features/agents/ui/sub-chat-selector.tsx index b890510da..d17cb3875 100644 --- a/src/renderer/features/agents/ui/sub-chat-selector.tsx +++ b/src/renderer/features/agents/ui/sub-chat-selector.tsx @@ -679,10 +679,6 @@ export function SubChatSelector({
{/* Left gradient - visibility controlled via ref */}
{/* Icon: question icon (priority) OR loading spinner OR mode icon with badge (hide when editing) */} {editingSubChatId !== subChat.id && ( @@ -914,7 +914,13 @@ export function SubChatSelector({ {/* Plus button - absolute positioned on right with gradient cover */} {(isMobile || (!isMobile && subChatsSidebarMode === "tabs")) && ( -
+
{/* Gradient to cover content peeking from the left */}
diff --git a/src/renderer/features/automations/automations-detail-view.tsx b/src/renderer/features/automations/automations-detail-view.tsx index 71ecb1a98..684a232dc 100644 --- a/src/renderer/features/automations/automations-detail-view.tsx +++ b/src/renderer/features/automations/automations-detail-view.tsx @@ -411,11 +411,21 @@ export function AutomationsDetailView() { -
+
{!isCreateMode && ( <> diff --git a/src/renderer/features/automations/automations-view.tsx b/src/renderer/features/automations/automations-view.tsx index ec3d31418..6474d6862 100644 --- a/src/renderer/features/automations/automations-view.tsx +++ b/src/renderer/features/automations/automations-view.tsx @@ -136,6 +136,10 @@ export function AutomationsView() { onClick={handleSidebarToggle} className="h-7 w-7 p-0 flex items-center justify-center hover:bg-foreground/10 transition-[background-color,transform] duration-150 ease-out active:scale-[0.97] flex-shrink-0 rounded-md text-muted-foreground hover:text-foreground" aria-label={isMobile ? "Back to chats" : "Open sidebar"} + style={{ + // @ts-expect-error - WebKit-specific property + WebkitAppRegion: "no-drag", + }} > @@ -150,6 +154,10 @@ export function AutomationsView() {
-
+