diff --git a/src/browser/components/AddSectionButton/AddSectionButton.tsx b/src/browser/components/AddSectionButton/AddSectionButton.tsx index 0a8248027a..beff820652 100644 --- a/src/browser/components/AddSectionButton/AddSectionButton.tsx +++ b/src/browser/components/AddSectionButton/AddSectionButton.tsx @@ -28,10 +28,7 @@ export const AddSectionButton: React.FC = ({ onCreateSect if (isCreating) { return ( -
-
- -
+
= ({ onCreateSect }} placeholder="Section name..." data-testid="add-section-input" - className="bg-background/50 text-foreground min-w-0 flex-1 rounded border border-white/20 px-1.5 py-0.5 text-[11px] outline-none select-text" + className="bg-background/50 text-foreground ml-6 min-w-0 flex-1 rounded border border-white/20 px-1.5 py-0.5 text-[11px] outline-none select-text" />
); diff --git a/src/browser/components/AgentListItem/AgentListItem.stories.tsx b/src/browser/components/AgentListItem/AgentListItem.stories.tsx index f3e8ba8628..962e7039bb 100644 --- a/src/browser/components/AgentListItem/AgentListItem.stories.tsx +++ b/src/browser/components/AgentListItem/AgentListItem.stories.tsx @@ -541,7 +541,7 @@ async function assertNestedConnectorContinuity( ); for (const trunk of ancestorTrunks) { await expect(trunk).toHaveAttribute("data-trunk-active", expectedTrunkActive); - await expect(trunk.style.left).toBe("20px"); + await expect(trunk.style.left).toBe("16px"); } } diff --git a/src/browser/components/AgentListItem/AgentListItem.tsx b/src/browser/components/AgentListItem/AgentListItem.tsx index a5b6fd7f7d..2718307494 100644 --- a/src/browser/components/AgentListItem/AgentListItem.tsx +++ b/src/browser/components/AgentListItem/AgentListItem.tsx @@ -74,6 +74,7 @@ interface AgentListItemBaseProps { projectPath: string; isSelected: boolean; depth?: number; + sectionId?: string; } /** Props for regular (persisted) workspace items */ @@ -122,7 +123,7 @@ const SHOW_INLINE_ACTIONS_ON_WIDE_TOUCH = /** Calculate left padding based on nesting depth */ function getItemPaddingLeft(depth?: number): number { const safeDepth = typeof depth === "number" && Number.isFinite(depth) ? Math.max(0, depth) : 0; - return 12 + Math.min(32, safeDepth) * 12; + return 8 + Math.min(32, safeDepth) * 12; } type VisualState = "active" | "idle" | "seen" | "hidden" | "error" | "question"; @@ -255,7 +256,7 @@ function ActionButtonWrapper(props: { children: React.ReactNode }) { return (
{/* Keep the kebab trigger aligned with the title row. */} @@ -269,9 +270,19 @@ function ActionButtonWrapper(props: { children: React.ReactNode }) { // ───────────────────────────────────────────────────────────────────────────── function DraftAgentListItemInner(props: DraftAgentListItemProps) { - const { projectPath, isSelected, depth, draft } = props; + const { projectPath, isSelected, depth, sectionId, draft } = props; const paddingLeft = getItemPaddingLeft(depth); const hasPromptPreview = draft.promptPreview.length > 0; + const draftBorderStyle: React.CSSProperties = { + backgroundImage: [ + "repeating-linear-gradient(to right, var(--color-border) 0 8px, transparent 8px 14px)", + "repeating-linear-gradient(to right, var(--color-border) 0 8px, transparent 8px 14px)", + "repeating-linear-gradient(to bottom, var(--color-border) 0 8px, transparent 8px 14px)", + ].join(", "), + backgroundSize: "100% 1.5px, 100% 1.5px, 1.5px 100%", + backgroundPosition: "left top, left bottom, left top", + backgroundRepeat: "no-repeat", + }; const ctxMenu = useContextMenuPosition({ longPress: true }); @@ -279,10 +290,11 @@ function DraftAgentListItemInner(props: DraftAgentListItemProps) {
{ if (ctxMenu.suppressClickIfLongPress()) return; draft.onOpen(); @@ -602,7 +614,7 @@ function RegularAgentListItemInner(props: AgentListItemProps) { !isSelected && visualState === "idle" ? "text-content-primary" : !isSelected && visualState === "seen" - ? "text-content-secondary" + ? "text-content-tertiary" : "text-content-primary"; const paddingLeft = getItemPaddingLeft(depth); @@ -640,6 +652,7 @@ function RegularAgentListItemInner(props: AgentListItemProps) { className={cn( LIST_ITEM_BASE_CLASSES, "group/row", + sectionId != null ? "ml-8" : "ml-6.5", isDragging && "opacity-50", isRemoving && "opacity-70", // Keep hover styles enabled for initializing workspaces so the row feels interactive. diff --git a/src/browser/components/ProjectSidebar/ProjectSidebar.tsx b/src/browser/components/ProjectSidebar/ProjectSidebar.tsx index 9aba22c1e0..8bfa6abc2e 100644 --- a/src/browser/components/ProjectSidebar/ProjectSidebar.tsx +++ b/src/browser/components/ProjectSidebar/ProjectSidebar.tsx @@ -259,6 +259,7 @@ interface DraftAgentListItemWrapperProps { draftId: string; draftNumber: number; isSelected: boolean; + sectionId?: string; onOpen: () => void; onDelete: () => void; } @@ -295,6 +296,7 @@ function DraftAgentListItemWrapper(props: DraftAgentListItemWrapperProps) { variant="draft" projectPath={props.projectPath} isSelected={props.isSelected} + sectionId={props.sectionId} draft={{ draftId: props.draftId, draftNumber: props.draftNumber, @@ -356,7 +358,7 @@ const ProjectDragLayer: React.FC = () => {
- +
{basename} @@ -1337,7 +1339,7 @@ const ProjectSidebarInner: React.FC = ({ className="flex-1 overflow-x-hidden overflow-y-auto" > {multiProjectWorkspaces.length > 0 && ( -
+
@@ -1574,8 +1574,12 @@ const ProjectSidebarInner: React.FC = ({ id={workspaceListId} role="region" aria-label={`Workspaces for ${projectName}`} - className="pt-1" + className="relative pt-1" > + @@ -2369,7 +2374,7 @@ const ProjectSidebarInner: React.FC = ({ ) ) : unsectionedDrafts.length === 0 ? (
- No unsectioned workspaces + No unsectioned chats
) : null} diff --git a/src/browser/components/SectionHeader/SectionHeader.tsx b/src/browser/components/SectionHeader/SectionHeader.tsx index ab63700005..cd4ee58f4e 100644 --- a/src/browser/components/SectionHeader/SectionHeader.tsx +++ b/src/browser/components/SectionHeader/SectionHeader.tsx @@ -72,12 +72,7 @@ export const SectionHeader: React.FC = ({ return (
{/* Expand/Collapse Button */} @@ -88,8 +83,7 @@ export const SectionHeader: React.FC = ({ aria-expanded={isExpanded} > @@ -116,7 +110,8 @@ export const SectionHeader: React.FC = ({
- {/* Add Workspace — always visible on touch devices */} + {/* Add Chat — always visible on touch devices */} - New workspace + New chat
); diff --git a/src/browser/stories/App.phoneViewports.stories.tsx b/src/browser/stories/App.phoneViewports.stories.tsx index 15504da0b1..0f54df180f 100644 --- a/src/browser/stories/App.phoneViewports.stories.tsx +++ b/src/browser/stories/App.phoneViewports.stories.tsx @@ -319,7 +319,7 @@ export const IPhone16eSidebarWithSections: AppStory = { // The actual visibility assertion (opacity via CSS media query) is // validated by the Chromatic snapshot in touch mode — the Storybook // test runner doesn't emulate pointer:coarse media queries. - within(sectionHeader as HTMLElement).getByLabelText("New workspace in section"); + within(sectionHeader as HTMLElement).getByLabelText("New chat in section"); }, { timeout: 10_000 } ); diff --git a/src/browser/styles/globals.css b/src/browser/styles/globals.css index 42f44942f4..7cc5fb8058 100644 --- a/src/browser/styles/globals.css +++ b/src/browser/styles/globals.css @@ -116,6 +116,7 @@ --color-text-secondary: hsl(0 0% 42%); --color-content-primary: hsl(0 0% 100%); --color-content-secondary: hsla(240, 5%, 65%); + --color-content-tertiary: hsla(240, 5%, 34%); --color-muted-foreground: hsl(0 0% 60%); --color-secondary: hsl(0 0% 42%); --color-surface-primary: hsla(240, 10%, 4%, 1); @@ -410,13 +411,14 @@ --color-background: hsl(210 33% 98%); --color-background-secondary: hsl(210 36% 95%); - --color-border: hsl(210 24% 82%); + --color-border: hsla(240, 5%, 26%); --color-foreground: hsl(210 18% 16%); --color-text: hsl(210 18% 16%); --color-text-light: hsl(210 15% 28%); --color-text-secondary: hsl(210 12% 42%); --color-content-primary: hsl(240 10% 4%); --color-content-secondary: hsla(240, 5%, 34%); + --color-content-tertiary: hsl(240, 4%, 46%); --color-muted-foreground: hsl(210 14% 48%); --color-secondary: hsl(210 18% 60%); --color-surface-primary: hsla(0, 0%, 100%, 1); @@ -675,6 +677,7 @@ --color-text-secondary: #6f6e69; --color-content-primary: #100f0f; --color-content-secondary: #575653; + --color-content-tertiary: #6f6e69; --color-muted-foreground: #6f6e69; --color-secondary: #6f6e69; --color-surface-primary: #fffcf0; @@ -905,6 +908,7 @@ --color-text-secondary: #575653; --color-content-primary: #fffcf0; --color-content-secondary: #878580; + --color-content-tertiary: #575653; --color-muted-foreground: #878580; --color-secondary: #575653; --color-surface-primary: #100f0f; diff --git a/tests/ui/chat/sections.test.ts b/tests/ui/chat/sections.test.ts index 3ebe9533ea..f10ac65143 100644 --- a/tests/ui/chat/sections.test.ts +++ b/tests/ui/chat/sections.test.ts @@ -265,9 +265,7 @@ describeIntegration("Workspace Sections", () => { const sectionHeader = view.container.querySelector(`[data-section-id="${sectionId}"]`); expect(sectionHeader).not.toBeNull(); - const addButton = sectionHeader!.querySelector( - 'button[aria-label="New workspace in section"]' - ); + const addButton = sectionHeader!.querySelector('button[aria-label="New chat in section"]'); expect(addButton).not.toBeNull(); // Click the add button - this should navigate to create page with section context