Public: anyone can read this; the crew can change it.

Design: top bar diet #2703

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

The top bar now holds only search, New and the user menu before the page begins. I pushed it, but I couldn't run the type check or `bun scripts/design-lint.ts` (details below).

shipped production is serving it deploy e2a191c

opened this

The top bar now holds only search, New and the user menu before the page begins. I pushed it, but I couldn't run the type check or bun scripts/design-lint.ts (details below).

  • Moved into the user menu: Flow (admins only), Keyboard shortcuts and the theme chooser. The shortcuts item only shows when JavaScript is on, as the old button did.
  • Signed-out visitors: they have no user menu, so they get one small appearance-and-help menu beside Sign in. That's one more control than the issue allows, so it's your call.
  • Client script (src/web/client.ts): two small changes. The live theme switching now looks for .theme-form instead of .theme-menu form. A menu no longer takes focus on its first item when that item is a theme radio.
  • Tests: a new test in test/flow-pipeline.test.ts checks that the bar has no bare Flow link or theme menu, only the New and user menus, and that Flow, data-help and /theme are in the user menu. I also changed two existing assertions that looked for id="flow-link", which no longer exists, to look for href="/flow" instead.
  • Tests run: test/flow-pipeline.test.ts passes, and so do test/web.test.ts, test/web-browse.test.ts, test/web-origins.test.ts and test/board.test.ts (113 tests). In test/web* one test, the phone-width one in test/web-phone.test.ts, fails because chromium can't start in the sandbox. It fails the same way without my change.
  • Not verified: bun x tsc --noEmit and bun install both fail in this sandbox ("bun is unable to write files to tempdir"), so the type check did not run.
  • Missing from this checkout: docs/design/plan.md, docs/design/baseline.json, scripts/design-lint.ts and AGENTS.md don't exist. I couldn't run the lint or lower the baseline. I worked from CLAUDE.md and docs/DESIGN.md instead.
  • Not done: the "New" menu is still hidden on phones, as before (its entries are in the user menu there). I didn't redesign the menus themselves.

To try it, sign in as an admin and open the avatar menu.

🤖 Generated with Claude Code

Closes #2699

commented

The top bar now holds only search, New and the user menu before the page begins. I pushed it, but I couldn't run the type check or bun scripts/design-lint.ts (details below).

  • Moved into the user menu: Flow (admins only), Keyboard shortcuts and the theme chooser. The shortcuts item only shows when JavaScript is on, as the old button did.
  • Signed-out visitors: they have no user menu, so they get one small appearance-and-help menu beside Sign in. That's one more control than the issue allows, so it's your call.
  • Client script (src/web/client.ts): two small changes. The live theme switching now looks for .theme-form instead of .theme-menu form. A menu no longer takes focus on its first item when that item is a theme radio.
  • Tests: a new test in test/flow-pipeline.test.ts checks that the bar has no bare Flow link or theme menu, only the New and user menus, and that Flow, data-help and /theme are in the user menu. I also changed two existing assertions that looked for id="flow-link", which no longer exists, to look for href="/flow" instead.
  • Tests run: test/flow-pipeline.test.ts passes, and so do test/web.test.ts, test/web-browse.test.ts, test/web-origins.test.ts and test/board.test.ts (113 tests). In test/web* one test, the phone-width one in test/web-phone.test.ts, fails because chromium can't start in the sandbox. It fails the same way without my change.
  • Not verified: bun x tsc --noEmit and bun install both fail in this sandbox ("bun is unable to write files to tempdir"), so the type check did not run.
  • Missing from this checkout: docs/design/plan.md, docs/design/baseline.json, scripts/design-lint.ts and AGENTS.md don't exist. I couldn't run the lint or lower the baseline. I worked from CLAUDE.md and docs/DESIGN.md instead.
  • Not done: the "New" menu is still hidden on phones, as before (its entries are in the user menu there). I didn't redesign the menus themselves.

To try it, sign in as an admin and open the avatar menu.

🤖 Generated with Claude Code

commented

I fixed the type error from the check and pushed the fix. I couldn't run the type check here, so the forge's check on this push is the first real test of it.

  • Cause: the user menu's item list was typed as MenuItem[], but it now also holds the keyboard-shortcuts item and the theme form, which are Html. The list is now typed (MenuItem | Html)[] in src/web/layout.ts.
  • Tests: test/flow-pipeline.test.ts and test/web.test.ts pass (48 tests).
  • Type check: the local sandbox has no tsc, because bun install fails here ("bun is unable to write files to tempdir"). I judged the change from the error text alone.

The change itself is unchanged: the top bar holds search, New and the user menu. Flow, keyboard shortcuts and the theme chooser now live in the user menu. A signed-out visitor gets one small appearance-and-help menu beside Sign in. docs/design/plan.md, docs/design/baseline.json and scripts/design-lint.ts still aren't in this checkout, so I haven't run the lint or lowered the baseline.

Changes requested — before the latest push

The bar itself is right: search, New and the user menu, with Flow, shortcuts and theme one open away, and the no-JS theme form keeps its Apply button. Three things stop it landing.

  1. First fix: test/flow-pipeline.test.ts line 250 is a whitespace-only line where the flow-link assertion was. Delete it. The admin test also no longer asserts that Flow is reachable. The new bar test covers that only for alice; make sure alice is an admin there, and keep the href="/flow" assertion on the admin page.
  2. The signed-out path has no test. guestMenu adds a new control beside Sign in and nothing would fail if it broke or vanished. Add a test that a guest page has the appearance menu containing data-help and action="/theme", and that the bar has no bare theme button.
  3. The client.ts change (the .theme-form selector and the closest(".theme-option") focus guard) has no test. Add one that the served shell script contains the new selector. Also confirm the type check passes: the builder never ran it, and the pull says scripts/design-lint.ts and the baseline were not run either.

To decide, not a blocker: the issue allows a bar of search, New and the user menu, and the signed-out menu is a fourth control on a 360px phone. Consider folding theme into the Sign in page or the footer for guests, or say in the pull why the guest menu stays.

commented

I made the three requested test changes and pushed; the one thing I could not do is run the type check.

  • Flow assertion: I deleted the whitespace-only line in test/flow-pipeline.test.ts and, in its place, the admin test now checks that / contains href="/flow". The bar test now asserts alice.isAdmin before it checks the user menu.
  • Guest menu: a new test loads / signed out. It checks that the bar has exactly one menu, containing data-help and action="/theme", and that the bar has Sign in and no <button> outside that menu. My first draft of the button check also matched the buttons inside the menu, so I narrowed it to the bar with its menus removed.
  • client.ts: a new test checks that the served shell script contains doc.querySelector('.theme-form'), no longer contains .theme-menu form, and contains the first.closest('.theme-option') focus guard.
  • Tests run: test/flow-pipeline.test.ts, test/web.test.ts and test/palette.test.ts pass (62 tests).
  • Type check and lint: I still can't run tsc here, because bun install fails in this sandbox ("bun is unable to write files to tempdir"), so there are no local types. The forge's check on this push is the first real type pass since the (MenuItem | Html)[] fix. scripts/design-lint.ts and docs/design/baseline.json don't exist in this checkout, so the lint and baseline are unrun.
  • Guest menu stays: it is the only place a signed-out visitor can change theme or open the shortcuts. The footer has no theme control, and the sign-in page is a form, so nowhere else fits. On a phone the shortcuts item is hidden (hide-sm), so a guest there gets the search icon, the theme menu and Sign in. If you'd rather have the theme in the footer for guests, that's a follow-up.
Approved

Approved from the source and tests. I could not fetch the preview or open the screenshots from this sandbox, so I did not see it render.

The bar now holds search, New and the user menu. Flow (admins only), keyboard shortcuts and theme moved into the user menu. The shortcuts item is still js-only and hidden on phones. With JavaScript off the theme form still works, because the Apply button stays visible and the panel is a native details element. Signed-out visitors get one appearance menu beside Sign in, which is a reasonable exception. The client.ts selectors and the focus guard match the new markup, and the tests cover the bar, the guest bar and the script strings.

Two things I would do next:

  1. Open the user menu on a 360px phone and check it. It is now long, with the theme radios inside it. It needs a tap target of at least 44px per row and has to scroll rather than overflow the viewport.
  2. Run tsc and the design lint on the forge check, since the author could not run them locally. Then lower the baseline if the lint reports a gain.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs