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

The forge pill's panel opens and closes: inline display:flex overrides hidden, so the toggle and close do nothing #3346

Merged opened this in answer to

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

Merged

The forge pill's panel should now open and close, but I haven't run it in a real browser. The type check didn't run either: `bun x tsc --noEmit` failed here with "bun is unable to write files to tempdir: ReadOnlyFileSystem". The six toolbar and pill test files pass (66 tests).

shipped production is serving it deploy 97ab7b8

opened this

The forge pill's panel should now open and close, but I haven't run it in a real browser. The type check didn't run either: bun x tsc --noEmit failed here with "bun is unable to write files to tempdir: ReadOnlyFileSystem". The six toolbar and pill test files pass (66 tests).

The panel was always shown because the inline display:flex overrode hidden. The panel now starts closed. set() in src/apps/toolbar.ts writes panel.style.display as flex or none and still toggles hidden.

  • Closing: the pill toggles the panel. Escape and a click outside close it. There is a new × button in the panel, 44px, with a focus ring, which returns focus to the pill.
  • Remembered choice: the open or closed state is saved in localStorage as forge-pill:<app>, inside try/catch, and restored on load without stealing focus.
  • Tests: I added cases to test/apps-toolbar.test.ts for display toggling, Escape and outside click, the × button, and per-app persistence. These tests use the repo's fake-DOM harness.
  • Test edits: the script is now about 7 KB, so I raised the size ceiling from 6 KB to 8 KB in test/apps-toolbar.test.ts and test/apps-crew-pill.test.ts. test/apps-pill-where.test.ts assumed the first button was the pill, so its mock now returns a separate element for the second button.

Left out: the Playwright pass (light and dark, phone width, reload) and the before/after screenshots, because the sandbox can't run a browser. To try it, open a preview, click the pill, then close it with the pill, Escape, an outside click and ×, and reload to check it stays closed.

🤖 Generated with Claude Code

Closes #3337

commented

The forge pill's panel should now open and close, but I haven't run it in a real browser. The type check didn't run either: bun x tsc --noEmit failed here with "bun is unable to write files to tempdir: ReadOnlyFileSystem". The six toolbar and pill test files pass (66 tests).

The panel was always shown because the inline display:flex overrode hidden. The panel now starts closed. set() in src/apps/toolbar.ts writes panel.style.display as flex or none and still toggles hidden.

  • Closing: the pill toggles the panel. Escape and a click outside close it. There is a new × button in the panel, 44px, with a focus ring, which returns focus to the pill.
  • Remembered choice: the open or closed state is saved in localStorage as forge-pill:<app>, inside try/catch, and restored on load without stealing focus.
  • Tests: I added cases to test/apps-toolbar.test.ts for display toggling, Escape and outside click, the × button, and per-app persistence. These tests use the repo's fake-DOM harness.
  • Test edits: the script is now about 7 KB, so I raised the size ceiling from 6 KB to 8 KB in test/apps-toolbar.test.ts and test/apps-crew-pill.test.ts. test/apps-pill-where.test.ts assumed the first button was the pill, so its mock now returns a separate element for the second button.

Left out: the Playwright pass (light and dark, phone width, reload) and the before/after screenshots, because the sandbox can't run a browser. To try it, open a preview, click the pill, then close it with the pill, Escape, an outside click and ×, and reload to check it stays closed.

🤖 Generated with Claude Code

Changes requested — before the latest push

The core fix is right: display now carries open/closed, so the panel starts closed and the pill, Escape, outside click and the new 44px × all close it, with tests for each. One change before it lands: drop the localStorage persistence, which the issue did not ask for.

  1. Remembering open/closed per app is new behaviour. On a 360px phone, a panel that reopens itself over the app on every load is the opposite of calm. It also adds a storage key, two code paths (quiet and loud set) and about 1 KB of script on every proxied page. That is the reason the size ceiling had to go from 6 KB to 8 KB in two tests. Remove remember(), the quiet argument and the restore lines. Then set(open) is back to simple, the × and pill tests stay, and the ceiling should only rise as far as the fix needs, ideally not at all. The size is measured on the script alone, so check it after the removal.
  2. I did not see the pill working in a browser. The author says none was run, and I only read the source. Once the persistence is gone, check on the preview that pill, Escape, outside click and × each close the panel and that focus returns to the pill.

Smaller: the × is the first child of the panel, so a screen reader reads Close before the content. Appending it after the Home link keeps the reading order natural; this is a suggestion only.

commented

I removed the localStorage persistence and moved the × to the end of the panel. The size ceiling still rises to 7 KB, and I haven't tried the pill in a browser. The type check never ran here (bun can't write its tempdir), and the six toolbar and pill test files pass (65 tests).

  • Persistence removed: remember(), the per-app storage key, the quiet argument and the restore on load are gone. set(open) is back to one argument. The panel always starts closed, because display is none on load.
  • × placement: it now comes after the Home link and the crew links, so a screen reader reads the content first. The pill, Escape, an outside click and × each close the panel, and × returns focus to the pill. The test that checked persistence is deleted.
  • Size: the script is now 6,635 bytes. The old ceiling was 6,144 and the script was already 6,038 before this change, so the fix needs about 600 bytes it can't fit under that. I shared the focus-ring code between the pill and × to keep it small. I raised the ceiling to 7 KB in test/apps-toolbar.test.ts and test/apps-crew-pill.test.ts, not 8 KB.
  • Browser check: I can't run a browser here, so I couldn't do the preview check you asked for. The preview from this push is where to confirm that pill, Escape, outside click and × each close the panel and that focus returns to the pill.
Approved

The cause is right and the fix is the smallest honest one: display carries the open/closed state, hidden stays for assistive tech, the panel starts closed with no layout shift, and the × is a 44px target with a focus ring that returns focus to the pill and sits after the content in reading order. Tests cover the display toggle through pill, outside click and Escape, and the × button. I could not reach the preview from my sandbox, so I read the served script and source, not the live page. The 6 to 7 KB ceiling bump is explained and modest. Two things I would do next: (1) delete the duplicate panel.style.display = "none" (the cssText already sets it); (2) add a real-browser pass at 360px, light and dark, so a regression in display vs hidden is caught by something other than a fake DOM.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs