Skip to content

Rail-delegacy: remove the nine grey /editor rail accordions - #413

Merged
WilfordGrimley merged 2 commits into
masterfrom
worktree-agent-aafdc73509db49d76
Jul 24, 2026
Merged

Rail-delegacy: remove the nine grey /editor rail accordions#413
WilfordGrimley merged 2 commits into
masterfrom
worktree-agent-aafdc73509db49d76

Conversation

@WilfordGrimley

Copy link
Copy Markdown

Description

Implements the owner-approved rail-delegacy design (SPEC-rail-delegacy.md + mockup, binding §D token table) for the /editor unified left rail: every one of the nine grey AutofillCollapse sections is removed and its contents folded into designed elements, per the spec's ruled dispositions (§E RD1-RD8).

Disposition -> implementation map

Ruling Disposition Implementation
RD1/O1 ONE chip surface - funnel Border/Frame/Treatment chips ARE the implicit-vote surface; separate .achip explicit-vote fieldset (AttributesSection.tsx) scrapped AttributesSection import/usage removed from DisplayPage.tsx's Rail; funnel chips (FunnelAxisRow/TreatmentChipRow, already implementing suggestedFilterTagNames-driven SUGGESTED state + castImplicitVote on pick) relocated into the shared Filters panel body in SelectVersionResults.tsx
RD2 Sort -> compact Form.Select of the 6 SortByOptions, inline in the SV header row New .svhead row in SelectVersionResults.tsx (funnel-sort-select), replacing NullableSortByFilter for the rail path
RD3/O4 Jump to Version fully scrapped Never wired into the new header/panel; GridSelectorFilters' own Jump section stays untouched for the sidebar/modal layout, just never reachable from the rail
RD4/O3 Filters panel tier-conditional: phone = in-rail Collapse; desktop inline rail + tablet drawer = a panel escaping the 380px column/drawer clipping SelectVersionResults.tsx: phone renders .fpanel.inline in-tree; desktop/tablet renders .fpanel.float + .fscrim via ReactDOM.createPortal(..., document.body) - see FloatFiltersPortalRoot's own comment for why a plain in-tree position:fixed node wasn't enough (LeftRailOffcanvas's position:sticky traps descendant z-index in a local stacking context; caught live via a blocked Playwright click before switching to a portal)
RD5 Print Options + Slot Actions + Report -> one .cstack; Report = small btn-outline-danger expanding to reason chips in place New ControlStack component in DisplayPage.tsx; ReportCardPanel already implements the expand-in-place behavior verbatim, no changes needed there
RD6/O2 Whole Card-Details metadata block + Download/Favourite -> "More details" disclosure only; rail-head stays lean RailHeader rewritten: .rhead-row + .detmore toggle + .detbody (CardMetaTable + CardDownloadFavorite)
RD7 Printing id appears ONCE, in D14; RequestedPrintingBadge becomes conditional-on-mismatch only; also required dropping CardMetaTable's own "Canonical Card" row in the rail context (not explicitly listed in the spec's component table but required by the "exactly once" rule - CardMetaTable gained an additive showCanonicalCard prop, default true, unaffected everywhere else) RequestedPrintingBadge gained additive showOnlyOnMismatch/resolvedPrinting props; CardMetaTable gained additive showCanonicalCard prop
RD8 66px subject-card preview + dashed empty state at the rail top .subject/.subject.empty in RailHeader, reusing the selected image's own smallThumbnailUrl
item 6 Printing Tags panel hangs off D14, opened on demand New IdentifyPanel in DisplayPage.tsx, wrapping the existing PrintingTagsBlock (PrintingTagPicker + conditional AttributeVotingPanel) verbatim - no fork
§A drawer flex-height note .lrail/.lscroll flex trap inside the Offcanvas drawer Verified NOT applicable to the real app: Bootstrap's stock .offcanvas-body{flex-grow:1;overflow-y:auto} already owns the scroll (no custom .lrail/.lscroll wrapper divs exist here) - confirmed via the new phone bottom-stack-reachability Playwright test, not just asserted

Deviations (documented)

  1. Implicit-vote awareness line gated on >=1 active chip, not always-visible as the mockup's decorative demo copy shows - the real awarenessCopy callback names active tags, which has nothing to describe with zero active chips. Existing tested behavior preserved.
  2. Active-tag pill row dropped from the SV header (the mockup's own .svhead has no pills row) - chip active state is now shown via each chip's own data-active/data-state attribute inside the Filters panel instead.
  3. D21's tier-based axis auto-collapse/auto-open retired - the funnel chips now live inside the same one user-toggled Filters panel as DPI/size/language/tags/NSFW (RD4's unification), so a survivor-count-driven auto-open/collapse would fight the calm, closed-by-default design.
  4. DPI/Size/Language/Tags/NSFW fieldsets reuse FilterSettings.tsx unchanged (not re-skinned to the mockup's literal .frange/.ftree/.swtrack token values) - re-styling those shared components would touch the Search Settings modal and GridSelectorModal too, which is out of scope for a rail-only round and would risk drift; flagged as a residual visual-fidelity gap, not silently dropped.
  5. CanonicalCardFilter (printings/artists filter) not mounted in the rail's Filters panel - it isn't accounted for anywhere in the spec's §F disposition table (only DPI/Size/Language/Tags/NSFW/sources/attributes are listed as "remaining after Compact the shared filter-panel controls to the approved density #409"), so it's treated as intentionally out of scope for this round, not silently dropped.
  6. Subject-preview caption text (mockup's decorative "selected art" label) omitted - no real data backs it in production (the card name is already shown in .idcol).

Dropped tests (with justification)

  • DisplayPage.spec.ts: "the Attributes section casts a real tag vote when a chip is tapped" dropped outright (not replaced) - AttributesSection.tsx's useTagVoting/submitTagVote explicit-vote fieldset is scrapped per RD1/O1, not relocated. The funnel chips' own implicit-vote path already has dedicated coverage (SelectVersionSection.spec.ts, SelectVersionResults.test.tsx); explicit attribute voting now lives only in AttributeVotingPanel (inside the identify panel), which keeps its own pre-existing, unmoved coverage.

Two further tests were adapted, not dropped (kept in the report for completeness since their shape changed materially): the two requested-printing-badge tests now assert the new mismatch-only contract (one asserts absence for a matched printing, the other asserts the single .mismatch style for a genuine mismatch) instead of the old plain/degraded two-look contract; the "clicking a collapsed section expands it" / "selecting a different slot resets the accordion" pair now exercise "More details" + the identify panel instead of the retired Attributes accordion.

Measured delta (css-diff harness)

Built a computed-style extraction harness (extract-mockup.js + a throwaway Playwright spec + diff.js, pattern from the prior corrected-bundle round's own harness) comparing the built /editor rail against rail-delegacy-mockup.html's own computed styles, at both 1400px (desktop, float Filters panel) and 390px (phone, inline Filters panel), across every introduced (§D.2) element type plus a sample of inherited (§D.1) ones: rail-head, subject preview, slot/name text, "More details" toggle/body, D14, identify panel band, .svhead, Sort select, Filters toggle, the Filters panel container, the filter fieldset legend, and the control stack + its legend.

Result: 42/42 rows matched, 0 mismatches, 0 skipped (1400px: 26/26; 390px: 16/16).

Verification

  • tsc --noEmit: clean (one pre-existing, unrelated marked module error in docsSite.ts, confirmed present before this change).
  • npx prettier@2.7.1 --check on every changed file: clean.
  • npx jest: 568/568 passing (64 suites) - includes a jest.setup.ts fix (global.matchMedia polyfill gained addEventListener/removeEventListener alongside the deprecated addListener/removeListener pair it already had, since useViewportTier.ts's modern API call was previously an unhandled crash under Jest the moment any component using it mounted - a real, previously-latent test-infra gap this round exposed).
  • Playwright, --project=chromium --workers=4, isolated port (never 3000; playwright.config.ts reverted to its original :3000/npm run dev config before this commit - diff is clean): DisplayPage.spec.ts + DisplayLeftRailFidelity.spec.ts + SelectVersionSection.spec.ts = 44/44 passing. Also spot-checked GridSelectorModal.spec.ts + CardDetailedViewModal.visual.spec.ts (shared-component blast-radius check for CardMetaTable's new prop and the sidebar/modal SelectVersionResults layout) - 24/24 passing.
  • Screenshots (built app, from an untracked throwaway spec run against this branch, not committed): /home/ubuntu/.claude/jobs/e893dbef/tmp/rail-build/v-1400-rail-allopen-top.png, v-1400-rail-allopen-bottom.png, v-1400-more-details.png, v-1400-filters-float.png, v-390-top.png, v-390-bottom-stack.png.
  • Delta reports: /home/ubuntu/.claude/jobs/e893dbef/tmp/rail-build/delta-1400.md, delta-390.md.

New test coverage added

Subject preview + dashed empty state; "More details" contents (and that the printing id is NOT duplicated there); single printing-id-occurrence dedup (both the "no art" and "has art" cases); mismatch badge conditional (present-only-on-mismatch, absent-when-matched); phone in-rail vs desktop/tablet float (float node provably absent at 390px, not just hidden); bottom-control-stack reachability at 390px (the §A phone-reachability hard requirement).

Checklist

  • I have installed pre-commit and installed the hooks with pre-commit install before creating any commits.
  • I have updated any related tests for code I modified or added new tests where appropriate.
  • I have manually tested my changes as follows:
    • Ran the full display-page Playwright suite (44 tests) plus the css-diff harness screenshots/extraction above; did not additionally drive a live browser session by hand beyond what those specs + screenshots cover.
  • I have updated any relevant documentation or created new documentation where appropriate.

Open items

  1. Docs not updated this round - docs/features/printing-tags.md/grid-selector.md's "Frontend consumer (funnel round)" sections still describe the funnel chips in their pre-rail-delegacy arrangement (always-visible above the grid, not inside a Filters panel); should be updated to reflect RD1/RD4 before/at merge. No prior SPEC-display-left-rail.md-tracking doc file exists in docs/ to supersede (the spec lives only in the job tmp dir passed to this task).
  2. Wiki checklist (per CLAUDE.md's "Wiki maintenance" convention): this changes what a USER sees on /editor (rail layout) - add "wiki: /editor left-rail page needs updating for the rail-delegacy layout (accordions removed, More details/identify panel/Filters panel/control stack)" to the merge-time checklist.
  3. DPI/Size/Language/Tags/NSFW pixel-token fidelity (deviation 4 above) is a known residual gap versus the mockup's own literal .frange/.ftree/.swtrack values - flagged for a follow-up pass if the owner wants those shared components re-skinned.

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

…y elements

Rail-head gains a 66px subject preview + "More details" disclosure (RD6/RD8),
D14 stays the one canonical printing-id occurrence with a conditional mismatch
badge (RD7), Printing Tags hangs off D14 as an identify panel (item 6), the
funnel's Border/Frame/Treatment chips become the one filter/vote surface
inside a tier-conditional Filters panel (RD1/RD4), Sort becomes a plain
Form.Select (RD2), and Print Options/Slot Actions/Report collapse into one
bottom control stack (RD5). Attributes accordion is scrapped outright.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant