Docs and Components sidebars do not start collapsed like the app shell #28

Open AtlantisPleb opened this 7h ago

Outcome

A reader who collapses sidebar sections sees them stay collapsed on first paint everywhere the collapsible sidebar exists — homepage, /docs, and /components — instead of watching sections paint open and snap shut.

Evidence

Collapsed sections persist correctly across reloads on the homepage (app shell) but not on /docs; /components shares the docs layout machinery and is presumed affected the same way.

What the investigation established

The transport is shared end-to-end and is not the suspect:

  • .SidebarSection hook writes one cookie (sidebar_sections, path=/) on every toggle.
  • OpenAgentsWeb.Plugs.SidebarSections (in :browser, so it serves /docs and /components too) reads that cookie into the session.
  • UserAuth.on_mount(:mount_current_user) assigns :sidebar_sections in every live session, including :docs and :components.
  • All three layouts feed the same Layouts.sidebar_section/1, whose seed is Map.get(state, id, default_open) — reader choice beats default.

Two real asymmetries remain as prime suspects:

  1. Section ids are namespaced per surface by title slug (sidebar-section-<title-slug>), so a choice made on one surface never applies to another. The homepage shell and the docs nav share zero ids; each surface must be collapsed independently, and any mismatch between what the reader collapsed and what each layout renders reads as "forgot".
  2. The docs layout force-opens the active section: open={Enum.any?(section.items, &(&1.slug == @active_page))} is passed as the default, and while reader choice overrides it via state, any gap in id or state delivery silently falls back to open-on-active — the opposite of collapsed-first.

Work

  • Reproduce in a browser with a clean profile: collapse every section on /docs, reload, record which reopen; do the same on /components and on the homepage for comparison.
  • Trace whether :sidebar_sections reaches the docs layout on a cold GET versus a LiveView navigation, and fix whichever hop loses it.
  • Decide deliberately whether collapse state should be global (one namespace of ids across surfaces) or per surface; either answer is fine, but the current implicit per-surface behavior must become explicit and documented in Plugs.SidebarSections.
  • Keep the active-page override only where it is documented intent, and make sure it cannot mask a lost preference.

Acceptance criteria

  • Collapsing sections on /docs survives reload and navigation, exactly as the homepage behaves.
  • Same for /components.
  • Whatever scoping rule is chosen (global or per surface), a test pins it.

Verification

LiveView tests seeding the session value and asserting first-paint open attributes for all three layouts; a manual pixel pass with a clean profile; mix precommit.

  1. AtlantisPleb opened this issue 7h ago
Sign in with GitHub to comment on this issue.