Skip to content

Palettes cannot recolor the threads-list unread marker: proposal for a dedicated --unread-dot theme token #2462

Description

@ben-vargas

The workflow

I wanted unread threads to stand out in the sidebar, so I made a custom palette (Settings → Appearance → Palette → Create / bb theme set) intending to recolor the threads-list unread marker to a bright accent. There is no theme token for the marker, so a palette cannot target it: the only levers are overriding --muted-foreground (which recolors every secondary-text surface in the app) or writing CSS against compiled Tailwind utility class names, which silently breaks whenever the implementation classes change.

What happens today

The unread marker's color is a hardcoded alpha step on the secondary-text token, in both consumers:

The working custom-palette workaround (fragile by construction, keyed to compiled class names):

span.size-\[5px\].rounded-full.bg-muted-foreground\/60 {
  background-color: oklch(0.6 0.2 145) !important;
}

What you would expect

A dedicated --unread-dot role token, following the same pattern as --version-upgrade/--surface-attention: defined in both mode blocks of theme.css as color-mix(in oklab, var(--muted-foreground) 60%, transparent) (the exact mix the current utility compiles to, so default rendering and palettes that re-anchor --muted-foreground are pixel-identical), bridged as --color-unread-dot, with both consumers on bg-unread-dot. A palette then recolors the marker with one line and nothing else moves.

Prototype (reviewed and tested, rebased on 31d66d9d4): ben-vargas@c635944 (branch feat/unread-dot-theme-token). 7 files, +44/−2:

  • theme.css token + Tailwind bridge; theme.test.ts guards (bridge registered; both modes pin the exact 60% oklab derivation, as the visual-parity invariant).
  • Mobile lockstep: --color-unread-dot in global.css, theme.native.ts regenerated via theme:generate (unreadDot on every palette × mode; regeneration reproduces the committed file byte-identically), mobile glyph consumer updated.
  • bb-cli/references/theming.md token-table row.
  • Verified: turbo run test --filter=@bb/app --filter=@bb/mobile passes (including generate-native-theme.test.ts / theme-vars.test.ts); typecheck for @bb/app, @bb/mobile, @bb/server clean.

Happy to open the PR if this gets sign-off.

Context and alternatives

The sibling working-status glyphs have the identical gap, but I deliberately left them out of the prototype because the token shape there is a design decision I'd rather leave to you. SIDEBAR_WORKING_STATUS_COLOR_CLASS (text-muted-foreground/50,

export const SIDEBAR_WORKING_STATUS_COLOR_CLASS = "text-muted-foreground/50";
) is shared by seven indicator kinds — the runtime spinner plus the shine-animated workflow / background-agent / background-command / plan-mode / goal / working-draft glyphs. A single family-wide --working-status token preserves the current one-tier semantics but recolors all seven together; per-kind tokens allow finer theming but split a deliberately unified tier. If you have a preference, I'm glad to do a follow-up matching this prototype's pattern.

Ruled out: overriding --muted-foreground in a palette (recolors all secondary text); scoping the override to the marker via its wrapper ([data-sidebar-thread-trailing-indicator]) still keys on implementation DOM rather than a token contract.

Checks

  • I searched open and closed issues for the same request.
  • If an agent wrote this, the body ends with > AGENT GENERATED.

AGENT GENERATED

Metadata

Metadata

Assignees

No one assigned

    Labels

    uiApp shell, sidebar, composer, rendering

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions