Repository navigation
Make the sidebar navigation a provider slot with rail and list placements - #5584
Merged
Merged
Conversation
ymichael
force-pushed
the
bb/undo-left-rail-changes-thr_mgqwa2yese
branch
2 times, most recently
from
October 16, 2026 03:56
2bd7d5c to
e462ac6
Compare
…ents bb draws the sidebar navigation through app.slots.experimental_sidebarNavigation again, restored under its pre-0.46 names so released navigation plugins load unmodified. Registrations declare a placement: rail (a fixed column that stays when the sidebar collapses, with the framed macOS title bar) or list (rows above the thread list, Settings in the footer, Back to app rows, and the header slot). bb ships two providers through the same contract, Rail and Top list, picked with sidebar.navigationProvider in Settings -> Appearance -> Navigation; Automatic prefers an installed plugin provider and falls back to Rail. The navigation model now carries Home, Customize, reorder, and each panel's experimental_useBadge value (folded in from #5524), so every provider draws the same badges. experimental_sidebarHeader returns for list placements. Plugin SDK 0.6.52. Fixes #5360 Fixes #5327 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The navigation region is a nav element again, as it was before #5229, so plugins that find their column with closest("nav"), such as Nav Rail, dock as designed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ExperimentalBadge gains text (a short visible value, at most 8 characters, exclusive with count) and tone (neutral, warning, or critical, drawn with bb's theme colors). The Top list and More menu draw the count or text in a pill colored by tone; the icon-only rail draws counts and a tone-colored dot for text. More's dot takes the strongest hidden tone. The shape follows the 30 bb-community plugins that drew experimental_sidebarAccessory: counts, short statuses, percentages, and fractions, with red, amber, or neutral colors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Badges use solid fills from the theme: a muted gray for neutral, attention amber with a new --attention-foreground for warning, and destructive red for critical. On the rail every count and dot sits in a ring painted with the rail's own background, so it reads against the icon instead of over it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ge fields Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Top list pins New thread and More and scrolls the destinations between them, capped near 40% of the window, with fades while more rows sit above or below. Before, enough plugin panels or a short window pushed the thread list out of view and clipped More, as the pre-0.46 rows also did. The shared navigation region stays uncapped so plugin providers keep managing their own height. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eded Top list rows get the 0.45 hover "…" button again, with the same menu as right-click (shared with the rail's context menu), always shown on touch devices; a badge fades out while the button shows in its place. Rows draw the split pane map beside the label when their page is open in a split. More only appears when a destination is hidden, since each row's menu reaches Customize. shared-ui now exports its sidebar hover-action classes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rail said "Customize rail" and the Top list said "Customize sidebar", but the editor only picks which destinations show and in what order. One name now covers the menu items and the editor title on both providers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The list layout put the footer in the bottom grid row the rail uses, outside the column that holds the navigation and thread list. Docking plugins such as Nav Rail inset the elements after the navigation in that column, as they did in 0.45, so they missed the footer: Settings and the footer actions sat under the rail at the window's edge and the rail's tint stopped above them. List placements now render the footer after the thread list in the same column; only the rail keeps the separate row beside its Settings button. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Settings -> Appearance called it "Header", which read as any header in the app. It now matches the "Sidebar footer" setting below it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Sidebar" alone read as the whole sidebar, beside separate Sidebar header and Sidebar footer settings. It names the part it changes now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rail keeps New thread in the sidebar header, so a header provider never mounts there. The setting now says so and is disabled instead of offering a choice that has no effect. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The sidebar header was a separate exclusive slot with its own setting, so users could pair a header with a navigation it did not belong to, and the setting did nothing with a rail. A navigation registration now takes an optional headerComponent that renders beside the sidebar toggle while that navigation is active. bb's Rail supplies New thread as its header through the same resolution, and a crashing plugin header falls back to the header of bb's provider for the same placement. experimental_sidebarHeader stays as an untyped runtime alias: a plugin's header joins each of its navigations without a headerComponent, so Nav Rail, Compact Nav, and Collapsible Navigation keep working. The Sidebar header setting and the sidebar.headerProvider preference are removed. Top list draws New thread as a regular row again, as in 0.45: it follows the saved order and visibility and appears in Customize. The rail keeps it pinned in its header and out of Customize. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bb's two sidebar navigation layouts now ship as the bundled, default-enabled Navigation plugin (plugins/navigation), registered through experimental_sidebarNavigation like any other provider and kept on the forkable list. The host keeps only the placement layout, Settings, the customize editor, and the navigation model. Whether a provider is built-in now comes from the plugin's install source instead of per-picker constants, so every replacement slot labels built-in providers "(built-in)", lists them after installed plugins, and prefers an installed plugin under Automatic. Shortcut pill, overflow fade, and the split pane mini-map move into shared-ui and the component registry so the app and both sidebar plugins share one copy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ymichael
force-pushed
the
bb/undo-left-rail-changes-thr_mgqwa2yese
branch
from
October 16, 2026 18:58
1d50964 to
5a0cc8d
Compare
ymichael
added a commit
that referenced
this pull request
Oct 17, 2026
## Human comments ## What was wrong Follow-up to #5584 (reported in #5584 (comment): "when top list enabled, right and left edges are not equal"). In the framed macOS desktop window, the window frame left an 8px lip on the right and bottom of the card. With the Rail placement, the rail fills the left side. With the list placement (Top list) there is no rail, and the frame had no leading lip, so the sidebar card (and the content card when the sidebar is collapsed) sat flush against the window's left edge. The collapsed title-bar reserve also assumed a rail was present, so the page title overlapped the sidebar toggle in Top list. ## What changed - `apps/app/src/components/ui/sidebar.tsx`, `apps/app/src/app.css`: with the list placement, the frame gains a leading lip (`--bb-window-frame-leading-lip`), so the sidebar card and the collapsed content card are inset 8px on the left, matching the right and bottom. `SidebarProvider` publishes `--bb-window-card-collapsed-left`: the rail width for Rail, the leading lip for Top list. - `apps/app/src/lib/bb-desktop.ts`: `MACOS_TITLE_BAR_COLLAPSED_SIDEBAR_RESERVE_CLASS` subtracts `--bb-window-card-collapsed-left` instead of assuming a rail, so the title clears the toggle when the sidebar is collapsed in Top list. - Rail placement and non-macOS or unframed windows are unchanged. No wire, CLI, or plugin API changes. ## How you verified - Added cases to `apps/app/src/components/ui/sidebar.test.tsx` for the leading lip and the published collapsed-left offset under both placements. - `pnpm exec turbo run typecheck lint --filter=@bb/app` and the sidebar/layout/secondary-panel tests pass. - Measured in the real Electron app via CDP, window 1280px wide: - Top list open: left gap 0 -> 8px; right and bottom gaps stay 8px. - Top list collapsed: left gap 0 -> 8px; the title now clears the sidebar toggle. - Rail open and collapsed: unchanged. > AGENT GENERATED 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Human comments
What was wrong
#5229 (0.46.0) made the icon rail the only sidebar navigation and removed the plugin API that let a plugin draw it (
experimental_sidebarNavigation,experimental_sidebarHeader, and their hooks).experimental_sidebarAccessory(Navigation rail (0.46.0) has nowhere to show plugin counts: experimental_sidebarAccessory is no longer shown #5327). 30 bb-community plugins draw one.The old slot only covered rows above the thread list, so the rail and the slot could not coexist.
What changed
One navigation slot with a declared placement.
app.slots.experimental_sidebarNavigationis restored under its pre-0.46 names. Registrations declareplacement: "rail" | "list";listis the default, so older plugins keep working.navigation/rail, the default) and Top list (navigation/top-list) are the bundled Navigation plugin (see below), so they use exactly the contract a third-party provider gets.<nav>element again, as before Make the navigation rail the only sidebar layout and remove the sidebar navigation plugin API #5229, and list placements keep the footer after the thread list in the same column, as 0.45 did. Plugins that find their column withclosest("nav")and inset what follows, such as Nav Rail, therefore dock with the footer beside the rail.sidebar/sidebarNavigationProvider.ts):sidebar.navigationProvider(Settings → Appearance → Navigation) selects Automatic or a provider by plugin key.__builtin__andnavigation/navigationread as Automatic.experimental_Originalrenders the built-in provider for the same placement, or nothing when the Navigation plugin is disabled.Rail and Top list are a bundled, forkable plugin (
plugins/navigation).headerComponent, using onlyexperimental_useSidebarNavigation,experimental_useSidebarNavigationSplit,experimental_SidebarNavigationIcon, and registry components. It is default-enabled, onscripts/forkable-plugins.json, and served by the demo server.Built-in providers come from the install source.
Shared model (
SidebarNavigationModel.tsx,lib/plugin-sidebar-navigation.ts):experimental_useSidebarNavigation()returnsisHomeActive, and its actions includegoHome(),setOrder(), andopenCustomize().openCustomize()opens bb's editor in a popover beside any provider, after open menus close, and returns focus to the control that opened it. bb's menus and the editor call it "Customize navigation" on every provider.experimental_useBadgevalue is in the model asitem.badge. The badge sources mount once in the model instead of in the rail.Badges (supersedes #5524).
experimental_useBadgeand its compatibility handling forexperimental_sidebarAccessory(the field is dropped with a warning), plus Tasks' migration to the hook.ExperimentalBadgeis{ count?, text?, tone?, label }:textis a short visible value of at most 8 characters, such as "NEW", "73%", or "2 down", and cannot be combined withcount;toneisneutral(the default),warning, orcritical, and bb owns the colors.experimental_sidebarAccessory: 12 drew one count, 8 several numbers or a fraction, 5 a short status, 3 a percentage, and 18 used red, amber, or an accent color for state.--attention-foregroundfor warning, and destructive red for critical.9+) and a tone-colored dot for text, each cut out of the icon by a ring in the rail's own background.99+), the text, or a dot.experimental_Accessoryfield show none until they readitem.badge.Header. A navigation's optional
headerComponentrenders in the sidebar header row while it is active, replacing the separateexperimental_sidebarHeaderslot and itssidebar.headerProvidersetting; that slot remains as an untyped runtime alias so a pre-0.46 plugin's header joins its navigation. The thread list setting is now Sidebar thread list.Plugin SDK 0.6.53.
ExperimentalBadgeToneand the new badge fields.placement.sidebarNavigationoption andsidebarNavigationCalls).>=0.6.53. No server/daemon wire change.Docs.
docs/configuration.md, the customization guide, and the plugin-authoring references (newfrontend-sidebar-navigation.md, plusfrontend-core-slots.mdand the API indexes).docs/api_to_audit.mdentries with stabilization items and the core callers on the same path.navigation/*keys, and the built-in-aware Automatic rule.How you verified
Empty header correction (
8cee6a05da): the new regression test fails before the fix; all 24 affected sidebar, header, and Settings tests pass after it, along with app lint and typecheck. The rendered macOS simulation confirms an 8-pixel inset above Top list and the retained 48-pixel Settings Search row.Desktop spacing fix (
fb133df5d9): both regression tests fail before the fix and pass after it. The 62 focused app layout, sidebar chrome/header, and Settings tests pass; app lint and typecheck pass. An isolated browser with simulated macOS chrome confirms Rail and Top list use identical title-bar/toggle coordinates and Settings Search height, with no extra window-control gutter. Compact windows retain their floating toggle. This renderer check does not verify native Electron window behavior.Windows CI timeout fix (
ae0adb0fa6): the two ACP restart tests use the same 30-second allowance as similar process-restart tests. All 499 ACP tests pass locally (4 skipped), along with lint and typecheck; Windows confirmation remains with CI.Full typecheck, lint, and test run is left to CI on this branch (rebased onto
399d63d277). The rail and its Settings cell keep the spacing from Compact the macOS app frame around the traffic lights and move headers into the title bar #5529 (compact macOS frame) and Align sidebar rail and footer icons to the row rhythm #5609 (row-rhythm alignment), and the app typecheck passes after the rebase. Locally, the affected app, SDK, Plugin Guide, Tasks, guide, mobile, and server suites passed before the last rebase; the mobile theme andglobal.csswere regenerated for the new--attention-foregroundtoken.check-plugin-sdk-version.mjsandcheck-npm-version-guard.mjspass at 0.6.53.Navigation plugin commit (
5a0cc8d599):scripts/check-plugin-forks.mjs plugins/navigation plugins/thread-list: both copies install, typecheck, test, andbb plugin buildoutside the monorepo with published packages only (Thread list passed on a re-run after one vitest worker start timeout under load).PluginSettings.test.tsx) failed under the parallel run and passed alone.test/fixtures/navigation-plugin.ts; the plugin's own drawing (count caps, text badges, More's tone, menus, the header button) is tested portably inplugins/navigation/app.test.tsx.399d63d277: turbo typecheck and lint pass for every package affected relative to main (155 tasks); Navigation, Thread list, plugin registry, and 231 app test files pass.pnpm start:worktreewith the bundled plugin and the installed Nav Rail, Compact Nav, and Collapsible Navigation plugins. I confirmed the server and plugins come up, but did not repeat the visual pass below after this commit.New and updated tests:
sidebarNavigationProvider.test.ts);openCustomize, pinned built-ins, crash fallback, and Original (SidebarNavigationHost.test.tsx);SidebarNavigationList.test.tsx);AppSidebar.test.tsx);SidebarNavigationRail.test.tsx);Manual checks with
pnpm start:worktreein headless Chromium at 1440×900 (light and dark) and 390×844, plus the packaged macOS desktop app (pnpm desktop:worktree), with Rail and Top list on the framed and unframed windows:examples/plugins/sidebar-navigationplugin: Customize, Original, the crash fallback, pinning Rail over it, a reload without a rail flash, and removal falling back to Rail.Not verified: iOS Safari and the native mobile shell; the header alignment on macOS after the header moved into the plugin. A pinned plugin key that is not installed shows an empty rail-width column on the first load until frontends settle, then falls back.
Follow-up commits on this branch.
fb133df5d9keeps the macOS window chrome stable when switching between rail and list placements (AppLayout.tsx,SidebarChrome.tsx, with tests and docs).8cee6a05daremoves the empty header row above Top list navigation (AppSidebar.tsx, with a test).ae0adb0fa6gives the ACP restart tests enough time on Windows (provider-bridge-acp-nexttest timeouts only).8cee6a05da: 48 checks passed or skipped.Supersedes #5524.
Fixes #5360
Fixes #5327
🤖 Generated with Claude Code