Skip to content

Put "design one bin" where someone looking for it would look - #11

Open
Oliver-Johnson wants to merge 1 commit into
mainfrom
claude/design-one-bin-entry
Open

Put "design one bin" where someone looking for it would look#11
Oliver-Johnson wants to merge 1 commit into
mainfrom
claude/design-one-bin-entry

Conversation

@Oliver-Johnson

@Oliver-Johnson Oliver-Johnson commented Aug 19, 2026

Copy link
Copy Markdown
Owner

Closes #6.

The two ways into "design one bin" were the bottom of panel 03 — which only appears with nothing selected — and a button under the drawer map. Both sit below a large panel about laying out a whole drawer. Someone who arrives wanting one bin that fits one thing has to read past the thing they are not doing to find the thing they are.

Where it went, and why not in the nav

A prominent control now sits directly beneath the nav, in the header, above every panel.

Not inside the nav, deliberately. The nav is a row of page links, and it carries the working layout across them via data-carry. An action sitting in that row reads like a fourth page, and this is a mode switch rather than a destination — different mechanism, different meaning.

Kept off the shared furniture

The header is shared furniture: chrome.js runs on the Baseplates page and every guide page too. So the markup lives in src/bins/template.html and chrome.js is untouched — the cheapest way to keep a bins-only control off pages that have no such mode. There's a case pinning that the Baseplates page didn't sprout a button for a mode it doesn't have.

Wired through the existing loop

for (const id of ['scratchBin', 'scratchBinMap', 'scratchBinTop']) — the loop the other two entry points already share, rather than a third copy of the handler. A change to what starting a loose bin means can't now reach two of the three.

Hidden from inside the mode

Once you're designing one bin, the way in is noise — the way out is what the focus bar is for. It's hidden by body.binfocus, the same class that hides everything else focus takes away, so it follows the project's convention that what focus hides is a CSS list rather than JS assignments.

What I did not do

Both older entry points are left in place. Three ways in is arguably one too many now, and I raised that in #6 — but which to drop is a taste question about your own UI, not one I should answer while you're asleep. Say the word and I'll remove one.

Verification

Four new cases in test/ui/entry-point.spec.js, proven to bite:

ablation result
button not added to the handler loop 2 of 4 fail
body.binfocus hide rule removed only the get-out-of-the-way case fails
both in place all 4 pass

The first case (position in the header, above the bin panel) passes under both ablations by design — it's about placement, which neither ablation touches.

  • build.js --check clean; the id audit rose 145→147 present.
  • Headless suite all green.
  • Built pages regenerated with node build.js. style.css is embedded in every page, so all five outputs change.

🤖 Generated with Claude Code


Update: a regression CI caught and I did not

The first push of this branch broke two existing cases at 375–390 px, and it was a real regression, not flakiness:

  • on-screen.spec.js:115 — the drawer map must keep ≥120 px above the fold at 390 px wide. This block pushed it to 97 px. That case exists precisely to stop the map being shoved down a phone screen.
  • export.spec.js:290 — the 375 px audit refuses any element owning text below 12 px. The sentence beside the button was font-size:11.5px.

Cause: I ran the new spec locally rather than the suite, so CI found it instead of me.

Fix, following the pattern already in the stylesheet rather than inventing one: there is an existing @media(max-width:980px) block that lifts text to 12 px and controls to 40 px tap targets. The explanatory span sat outside it. It is now hidden there — the button label carries the meaning and the gloss is a desktop luxury. That removes the sub-12 px text from the audit and returns the height to the map.

Re-verified: 170 passed, 0 failed at --workers=2 locally, plus build.js --check clean and all eight headless suites green.

Rebase note

Rebased onto c88f512 (post-#7). No conflicts — #7 changed exactly one line of index.html as an in-place substitution, in a different region from this branch's style.css edits, so nothing shifted. build.js --check confirms the committed pages match what the sources generate.

@Oliver-Johnson
Oliver-Johnson force-pushed the claude/design-one-bin-entry branch from bc5b8ae to 750ab9b Compare August 20, 2026 12:21
The two ways in were the bottom of panel 03 -- which only appears with nothing
selected -- and a button under the drawer map. Both sit below a large panel
about laying out a whole drawer, so someone who arrived wanting one bin that
fits one thing had to read past the thing they were not doing to find the thing
they were.

It goes under the nav rather than in it. The nav is a row of page links and
carries the layout across them; an action sitting in that row reads like a
fourth page, and it is a mode switch rather than a destination.

The markup is in the bins template, so chrome.js -- which runs on the baseplates
page and every guide page too -- is untouched. A case pins that the baseplates
page did not sprout a control for a mode it does not have.

Wired through the loop the other two entry points already share rather than a
third copy of the handler, so a change to what starting a loose bin means cannot
reach two of the three.

Hidden once you are already in the mode, by the class that hides everything else
focus takes away. The way in is noise from inside; the way out is what the focus
bar is for.

The sentence beside the button is desktop only. At 390 px it wrapped to three
lines of 11.5 px text, which broke two existing cases at once: the 375 px audit
refuses any element owning text under 12 px, and the extra height pushed the
drawer map down until only 97 px of it were above the fold, against the 120 px
on-screen.spec.js requires. Both were caught by CI and not by me, because I ran
the new spec rather than the suite. The button says what it does; the gloss is
what goes.

Both older entry points are left alone. Three ways in is arguably one too many
now, but which of them to drop is a taste question and not mine to answer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@Oliver-Johnson Oliver-Johnson left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: looks good — nits only. The cleanest of the four.

Independent review; I did not write this.

The judgement calls are all right, and they are the ones that would have been easy to get wrong:

  • Under the nav rather than in it. A mode switch in a row of page links that carry state via data-carry would have been a genuine confusion, and the reasoning for keeping it out is stated where the next person will find it.
  • Markup in src/bins/template.html, chrome.js untouched. Right call, and case 4 pins it rather than trusting it.
  • Reusing the existing handler loop instead of a third copy — the same instinct the handover records as having cost three bugs when it was not followed.
  • Hidden via the body.binfocus CSS list, not JS assignments, which is the project's stated convention for exactly this.
  • Owning the CI regression in the PR body, including why it happened (ran the new spec, not the suite). That is more useful than a clean history.

All four ablations reproduce

Ran them rather than trusting the table:

ablation result
drop scratchBinTop from the handler loop 2 failed (opens the same loose bin, gets out of the way), 2 passed
remove body.binfocus header .quickstart{display:none} 1 failed (gets out of the way), 3 passed
neither 4 passed

Exactly as the body claims. Note the build stays green under the first ablation — the id audit checks that every $('id') exists in the template, not that every button is wired — so case 2 is carrying real weight there.

Nits, none blocking

  1. Two buttons now read "Design one bin on its own", verbatim. #scratchBinTop (template.html:52) and #scratchBin (template.html:245). Anyone navigating by a screen reader's button list gets two identical entries with no way to tell them apart. You have already flagged that three entry points is one too many and left the decision to Oliver — that is the right call, but if all three survive, the two survivors should at least not share a label. #scratchBin's in-panel copy could become something like "…or design one bin on its own".

  2. The gloss disappears below 980px, not below ~400px. The regression it was fixing was at 375–390px, but @media(max-width:980px) also covers tablets and any half-screen desktop window, where there is plenty of room for it. Following the stylesheet's existing breakpoint rather than inventing one is defensible and I would not block on it — but a narrower query, or shrinking the max-width: 52ch instead of hiding, would keep the sentence where it still fits.

  3. Comment style. Two of the new lines use ASCII -- where this codebase uses em dashes (src/shared-ui/style.css on main: 26 against 2 --; src/bins/template.html: 50 against 0). Cosmetic, but the prose voice here is clearly deliberate.

Merge order

Issue #6 suggested landing this after #4 so the single-bin page's controls get designed once. Worth knowing that is no longer forced: I merged all four PRs together and they auto-merge with node build.js --check clean on the result, so the generated pages stay in sync either way. Order is now a UI-design question rather than a mechanical one — with both landed, the page gains a header button and a layer picker plus "Add a layer on top" in the focus bar, which is worth one look together before shipping.


Reviewed independently; I am not the approver.

Comment thread src/bins/template.html
like a fourth page. Plenty of people arrive wanting one bin that fits one thing,
and the way in was the bottom of a panel about laying out a whole drawer. -->
<div class="quickstart" id="quickstart">
<button type="button" class="act" id="scratchBinTop">Design one bin on its own</button>

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This label is verbatim identical to #scratchBin at line 245. With both entry points surviving, a screen reader's button list shows two entries reading "Design one bin on its own" with nothing to distinguish them.

If all three ways in stay (your call to leave that to Oliver is right), giving the in-panel one different copy — "…or design one bin on its own" — costs nothing and removes the ambiguity.

Comment thread src/shared-ui/style.css
it wrapped to three lines of 11.5px text, which failed the 12px floor this block
exists to enforce AND pushed the drawer map below the fold -- the exact regression
on-screen.spec.js was written to catch. The way in stays; only the gloss goes. */
header .quickstart span{display:none}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regression this fixes was at 375–390px, but @media(max-width:980px) also swallows tablets and half-screen desktop windows, where the sentence still fits comfortably.

Following the stylesheet's existing breakpoint rather than inventing one is a reasonable trade and I would not block on it — but a narrower query, or letting max-width: 52ch shrink instead of hiding outright, would keep the gloss where there is room for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make "Design one bin" discoverable, instead of buried under the drawer-layout panel

1 participant