From 765b710bf57051e5268160c5f94beaeceb8fcd1e Mon Sep 17 00:00:00 2001 From: brennanb2025 Date: Fri, 1 May 2026 15:30:17 -0700 Subject: [PATCH] feat(sidebar): bold unread workspaces instead of bell icon Replaces the per-worktree bell affordance with a bold-title treatment for unread workspaces, and drops the now-unused Mark Read/Unread context-menu entry. The 'unread' card property still gates the emphasis, so users can opt out. PR# label de-bolded to match the softer title weight on read cards. Co-authored-by: Orca --- docs/bold-instead-of-bell.md | 312 ++++++++++++++++++ .../src/components/sidebar/SidebarHeader.tsx | 2 +- .../src/components/sidebar/WorktreeCard.tsx | 94 +++--- .../components/sidebar/WorktreeCardMeta.tsx | 2 +- .../sidebar/WorktreeContextMenu.tsx | 10 - .../src/components/tab-bar/SortableTab.tsx | 8 +- 6 files changed, 363 insertions(+), 65 deletions(-) create mode 100644 docs/bold-instead-of-bell.md diff --git a/docs/bold-instead-of-bell.md b/docs/bold-instead-of-bell.md new file mode 100644 index 00000000000..98104e1dc55 --- /dev/null +++ b/docs/bold-instead-of-bell.md @@ -0,0 +1,312 @@ +# Bold/Non-Bold Worktree Card Unread Indicator + +## Goal + +Replace the yellow bell glyph on each sidebar workspace card with a +**bold / non-bold** treatment of the card title — matching the visual +language already used by the inline agent activity rows under the +experimental agent-status toggle (`DashboardAgentRow.tsx:262`). Unread +**state** (what flips `worktree.isUnread`, what clears it, where it's +persisted) stays exactly as it is today. The change is purely visual +plus the removal of the now-unused manual toggle paths. + +## Why + +The amber `FilledBellIcon` on the sidebar card is the only remaining +surface in the sidebar that encodes "needs attention" as a colored +glyph. Agent rows already express the same semantic as a weight change +(`font-semibold text-foreground` vs `font-normal text-muted-foreground` +— see `DashboardAgentRow.tsx:262` and the comment block above it: "one +attention axis, not two"). Extending that rule to the workspace card +collapses the two axes on the sidebar into one, reclaims the left-rail +real estate the bell occupies, and removes a duplicate use of amber — +which also signals CI `pending`, conflict operations, and sparse +checkout on the same card. + +This change is deliberately scoped to the **sidebar `WorktreeCard`**. +`FilledBellIcon` also has a caller in `SortableTab.tsx:266` for +tab-bar unread; that surface is **explicitly out of scope** (see +"Out of scope" below) and the helper stays exported. + +## Today's behavior (the bell) + +- `worktree.isUnread` (a `WorktreeMeta` boolean, persisted) drives a + bell icon rendered on the **left rail** of `WorktreeCard`, gated by + the `'unread'` card property: + - `src/renderer/src/components/sidebar/WorktreeCard.tsx:380–404` + renders `` when + unread, or a ghost `` (hover-reveal) when read. + - Clicking the icon toggles via `handleToggleUnreadQuick` + (`WorktreeCard.tsx:320–327`) → `updateWorktreeMeta({ isUnread: !… })`. + - The context menu has a parallel toggle + (`WorktreeContextMenu.tsx:67–69, 172–175`) that is also going away + (see "Remove manual toggle paths" below). +- The unread flag is also flipped by activation/ack cascades in + `src/renderer/src/store/slices/worktrees.ts` (around L372, L407, L480, + L595, L669) and by the CLI orchestration handler + (`src/cli/handlers/orchestration.ts:71`). **None of this changes.** + Activation continues to clear unread automatically, which is the + dominant way unread becomes read today — and after this change, the + *only* manual way. +- Property toggle in `SidebarHeader.tsx:29` is `{ id: 'unread', label: + 'Unread indicator' }`. Label may change; the id stays the same for + settings persistence compatibility. + +## Reference: how agent rows do bold/non-bold + +`WorktreeCardAgents` derives a per-row `isUnvisited` flag from the ack +map (`WorktreeCardAgents.tsx:151`) and passes it to +`DashboardAgentRow`, which switches classes at +`DashboardAgentRow.tsx:262`: + +``` +isUnvisited ? 'font-semibold text-foreground' : 'font-normal text-muted-foreground' +``` + +We apply the same two-class pattern to the workspace card's title row. + +> Note: agent-row "unvisited" is derived at render time from an ack map +> keyed on `stateStartedAt`; workspace `isUnread` is a persisted boolean +> on `WorktreeMeta`. We're mirroring the *visual language*, not the +> underlying state model. The two systems remain independent. + +## Target behavior + +### The rule: bold = unread + +**On a read card (`worktree.isUnread === false`), no text in the card +body is rendered at `font-semibold` or heavier.** Bold is reserved as +the unread signal. This applies to: + +- The title (`displayName`) — today `font-semibold text-foreground` + (`WorktreeCard.tsx:430`) → on read cards becomes + `font-normal text-muted-foreground`. +- The repo badge label — today `font-semibold text-foreground` + (`WorktreeCard.tsx:508`) → drops to `font-normal text-foreground` + on read cards to preserve hierarchy (the repo label must not read + heavier than the workspace title above it). + +Small chrome labels already using `font-medium` (`primary`, `sparse`, +`conflict`, Folder-kind badge) stay as-is — they're visually distinct +from bold title copy and are *not* part of the "bold = unread" signal. + +**On an unread card (`worktree.isUnread === true`) and the `'unread'` +card property is enabled:** + +- The title renders `font-semibold text-foreground`. +- The repo badge label goes back to `font-semibold text-foreground` + so the hierarchy stays coherent. +- The yellow bell does **not** render anywhere on the card. + +**When the card property `'unread'` is off:** + +- The card is always rendered as if read, regardless of the store flag. + This preserves the existing opt-out — users who previously hid the + bell via this property retain an equivalent "quiet mode." + +### Interactions + +- **Activation remains the only way to clear unread manually.** Clicking + the card activates the workspace, which runs the existing cascade in + `worktrees.ts` and clears `isUnread`. The title de-bolds as part of + the next render. This is how ~all read-state transitions already + happen today; the bell's click target and the context-menu "Mark + Read / Mark Unread" item were the manual escape hatches, and they + both go away (see next section). +- No Alt-click, middle-click, or other hidden gesture is introduced. + +## Changes + +### 1. `WorktreeCard.tsx` + +- Delete the unread-button block (lines ~380–404): + - The `` + ` - - - {unreadTooltip} - - - )} +