Skip to content

Cardback reminder gate + apply-all/set-default prompts + PDF-wait experience - #431

Merged
WilfordGrimley merged 2 commits into
masterfrom
feat/cardback-pdfwait-flow
Jul 24, 2026
Merged

Cardback reminder gate + apply-all/set-default prompts + PDF-wait experience#431
WilfordGrimley merged 2 commits into
masterfrom
feat/cardback-pdfwait-flow

Conversation

@WilfordGrimley

Copy link
Copy Markdown

Summary

Implements SPEC-cardback-pdfwait.md (both packages, including the 2026-07-24 owner amendments) end to end.

PKG1 — cardback flow

  • 1a No-cardback reminder gate (useCardbackReminderGate), composed into usePrePrintSaveGate.startPrintFlow and independently into PDFGenerator.tsx's classic direct Generate/Save-to-Drive buttons (spec's own coverage note — a user can reach /print without ever going through the editor's Finish footer). Amendment 1: dismiss (✕/Esc/backdrop) = "use current & continue", not cancel — implemented via Modal onHide. Fires once per print attempt; a per-project sessionStorage suppression (cardbackReminderSuppression.ts) makes a second attempt in the same session silent (CB1), shared by both call sites.
  • 1b Apply-all + set-default prompt (CardbackApplyPrompt.tsx), one shared component for both entries: toolbar (project-wide, inline in the same GridSelectorModal via new additive closeOnSelect/footerContent props — never a stacked modal) and rail (new per-slot SlotCardbackControl.tsx, reusing GridSelectorResults's "embedded" variant — no modal at all). Amendment 2/OQ-B: override-with-count, plus front+current-custom-back thumbnails of every affected slot rendered above the count line, never pre-checked. New applyCardbackToAllSlots reducer overrides every slot unconditionally (including custom ones); a new cardbackExplicitlySet flag on Project (set only by real user picks — the explicit: true payload flag — never by listenerMiddleware.ts's own auto-seed effect) drives the gate's fire condition.
  • 1c Seams only, per spec — no backend built. cardbackDefaultPreference.ts's "Set as my default" write is an explicit, documented no-op seam (Annex A-2): the spec's own suggested anonymous-localStorage approach conflicts with this repo's standing "no localStorage for state that should survive clear-site-data" rule without a real backend contract to write the authenticated half against, so the UI/done-state is real but the persistence layer is deferred, not silently implemented against that rule.
  • Amendment 3 (new): the sheet's flip icon (PagePreview.tsx) gains a small warning-token indicator dot whenever that slot's back differs from the deck default — same gating as the flip icon itself, aria-label updated, no new color role.

PKG2 — PDF-generation wait experience

  • 2a Real Bootstrap ProgressBar (PDFWaitPanel.tsx's PDFProgressBox) replacing the old bare "Fetching images: N/M" text — determinate while fetching (capped 99%, never a false 100%), a hand-built indeterminate track for assembling (not <ProgressBar> — react-bootstrap always emits a real aria-valuenow from now with no way to suppress it, which would have announced a false "100%" to a screen reader mid-assembly; caught by this round's own accessibility read of §G), green on done.
  • 2b PDFWaitGameEmbed renders <QuestionFeed> verbatim (no forked component, no new voting mechanic) via next/dynamic({ssr:false}), lazy-loaded only once generation starts, torn down the instant it finishes. Amendment 4/OQ-C: teardown-to-outro — the existing PostExportContributionPrompt becomes the embed's outro; the standalone bottom-of-settings mount is suppressed whenever the embed is already showing it (one nudge, not two).
  • A real bug caught by this round's own Playwright coverage: the derived waitPhase state machine initially misclassified the brief pre-first-callback window (imageFetchProgress == null) as "assembling" instead of "fetching" — fixed.

Deviations from spec

  1. Annex A-2 persistence — "Set as my default cardback" is UI-complete but its actual write is a documented no-op seam, per the localStorage conflict above. Flagged in the module comment; a real backend contract is a follow-up.
  2. §H mockup chrome (bottom-sheet phone modal, custom scaled demo frame) — not reproduced pixel-for-pixel; real react-bootstrap Modal/Offcanvas primitives are used throughout instead, per the repo's existing "shared components gain only additive props" discipline. Token values (color/border/spacing) are binding and verified (see below); the phone modal is a centered dialog, not a bottom sheet.
  3. Full-suite Playwright verification used an isolated port (3931) per docs/lessons.md's concurrent-worktree-port guidance — not part of this diff (temp config, deleted before commit).

Verification

  • tsc --noEmit: clean.
  • jest: 69 suites / 603 tests pass (14 new: cardbackApply.test.ts, cardbackReminderSuppression.test.ts, CardbackApplyPrompt.test.tsx, useCardbackReminderGate.test.tsx, plus PagePreview.test.tsx/projectSlice.test.ts additions).
  • prettier/eslint on every changed/new file: clean (pre-commit hook also ran clean).
  • Playwright: new specs CardbackFlow.spec.ts (reminder gate incl. dismiss-continues + session suppression; rail per-slot entry with trapnote; toolbar entry with thumbnails+count; both apply-all and set-default flows), PDFWaitExperience.spec.ts (fetch→assemble→done phases; game embed lazy-mount/teardown/outro-suppression; classic-direct-path guard), CardbackPdfWaitFidelity.spec.ts (computed-style self-verification against the binding token table). Full suite run twice at 4 workers, isolated port: 294 passed both times; the only non-green items were (a) 3 pre-existing tests unrelated to this change that failed only under full-suite parallel contention and passed clean in isolation (AddCardToProjectForm.spec.ts, GeneralUIAccessibility.spec.ts, DisplayLeftRailFidelity.spec.ts, HomepagePanel.spec.ts, ImportCSV.spec.ts, QuestionFeed.spec.ts — confirmed flaky-under-load, not regressions) and (b) DynamicLogo.visual.spec.ts, which hardcodes localhost:3000 for a favicon fetch and only fails because of the isolated port choice (confirmed by code inspection — untouched by this PR).
  • Computed-style fidelity delta vs SPEC-cardback-pdfwait.md §E: measured via CardbackPdfWaitFidelity.spec.ts at 1400px and 390px against a representative binding sample covering every distinct colour token the round introduces (.mdialog/.mfoot primary button, .cbprompt/.applybtn/.defbtn at rest + done state, .progressbox, .gameembed, .geband, ThumbButton's 44px floor) — 0 mismatches at both viewports.
  • Existing suites: full green after fixing 3 real ripple effects the closeOnSelect change caused (GridSelectorModal.spec.ts/GridSelectorModalVariants.spec.ts — 3 test titles renamed to describe the new stays-open behavior, acked in .github/coverage-acks.txt; DisplayPage.spec.ts's own cardback test updated the same way) and 2 existing spec files (DisplayFinishFooter.spec.ts, UnsavedWorkGuard.spec.ts) updated to click through the new reminder gate.
  • Manual UI walkthrough not run in a headed browser session — verified entirely through the above automated coverage (Playwright screenshots at 1400/390 inspected directly: reminder gate, apply-all prompt with thumbnails, PDF-wait state with game+progress, flip-icon indicator all match the mockup's visual language).

Open items

  1. Annex A-2 ("Set as my default cardback" real persistence) needs a backend/account-preference contract before it can do more than the current UI-only no-op — flagged, not blocking.
  2. Bug-A/foreign-order-resilience — no interaction found (orphan badge and the flip-icon indicator both claim the same top-right corner, pre-existing, unworsened by this change) — noted, not fixed, out of scope.
  3. Bottom-sheet phone modal presentation from the mockup's own §H demo — not built; current phone experience uses the standard centered Modal, fully reachable and legible (see 390px screenshots) but not the exact chrome shape shown.

Wiki checklist

docs/user-guide.md (the wiki's User-Guide source doc) updated in place with the new reminder-gate/apply-all/set-default/PDF-wait-game copy — wiki page itself needs the same update mirrored (cloud-session checklist item, no direct wiki push from this worktree).

🤖 Generated with Claude Code

…t experience (progress bar + What's That Card? embed)

Implements SPEC-cardback-pdfwait.md PKG1 (no-cardback reminder gate,
toolbar/rail apply-all + set-default prompts with affected-slot
thumbnails, custom-cardback flip-icon indicator) and PKG2 (determinate/
indeterminate PDF generation progress bar, embedded What's That Card?
game during PDF wait with teardown-to-outro).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gress-bar text assertion, .modal-content bg after #425's theme-defaults pass

PR #427 (landed after this branch's original base) un-skipped
PDFGenerator.spec.ts/PagePreview.spec.ts/PostExportContributionPrompt.spec.ts
onto the shared navigateToPrintPDFTab helper, which the new cardback
reminder gate now intercepts; PR #425's theme-defaults pass separately
re-routed every Modal's content background to $theme-raised-bg.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@WilfordGrimley
WilfordGrimley force-pushed the feat/cardback-pdfwait-flow branch from 46c8c68 to 6164559 Compare July 24, 2026 16:52
@WilfordGrimley
WilfordGrimley merged commit fa273a4 into master Jul 24, 2026
13 checks passed
WilfordGrimley added a commit that referenced this pull request Jul 24, 2026
…ty (#441)

rail-delegacy, editor-polish, cardback-pdfwait, wtc-rebuild — each cited
by filename in committed code comments (the first three now on master
via PR #431) but previously living only in a session tmp dir that dies
with the session. Verbatim copies + companion mockup HTML, same
durability convention as reference/funnel-spec.md.
WilfordGrimley added a commit that referenced this pull request Jul 24, 2026
…I onto Tokyo-11

PR #431 landed after the original sweep with its own hardcoded #302-derived
literals (CardbackApplyPrompt.tsx, useCardbackReminderGate.tsx,
PDFWaitPanel.tsx, SlotCardbackControl.tsx, plus a new DisplayPage.tsx line) -
migrated onto var(--bs-*)/var(--theme-*) tokens the same way the rest of the
sweep was, including simplifying the primary/info/success at-rest button
text to use the token directly (Tokyo-11's action colours are light enough,
unlike #302's, so the separate hand-picked tint literals aren't needed any
more). CardbackPdfWaitFidelity.spec.ts's own literal assertions updated to
match, comment-linked per row.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
WilfordGrimley added a commit that referenced this pull request Jul 24, 2026
Post-merge re-scan (coordinator's ask) caught one more #302-derived
literal (#431's own PagePreview.tsx diff) - the flip-button custom-cardback
indicator dot's warning colour wasn't yet routed to var(--bs-warning).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
WilfordGrimley added a commit that referenced this pull request Jul 24, 2026
… Semi radius) (#438)

* Re-theme site to Tokyo-11 (Tokyo Night base, orange action, purple accent, Semi radius)

Owner-ruled palette swap (theme-options study, palette 11) on top of #425's
token-layer pass: new colour/radius tokens in _theme-tokens.scss, Bootstrap
variable + runtime var(--bs-*)/var(--theme-*) wiring in styles.scss (incl.
the AAA button-ink flip and a WCAG/APCA audit fold-in: opaque accent focus
ring, .btn-close/.fbtoggle target-size fixes, a lightened muted token),
accent wiring across D14/chips/toggles/selection outlines, a sitewide sweep
of hardcoded old-palette literals onto token references, and matching
DisplayLeftRailFidelity.spec.ts updates.

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

* Merge master (#427/#405/#440), re-theme PR #431's cardback+PDF-wait UI onto Tokyo-11

PR #431 landed after the original sweep with its own hardcoded #302-derived
literals (CardbackApplyPrompt.tsx, useCardbackReminderGate.tsx,
PDFWaitPanel.tsx, SlotCardbackControl.tsx, plus a new DisplayPage.tsx line) -
migrated onto var(--bs-*)/var(--theme-*) tokens the same way the rest of the
sweep was, including simplifying the primary/info/success at-rest button
text to use the token directly (Tokyo-11's action colours are light enough,
unlike #302's, so the separate hand-picked tint literals aren't needed any
more). CardbackPdfWaitFidelity.spec.ts's own literal assertions updated to
match, comment-linked per row.

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

* Fix PagePreview.tsx CustomCardbackDot missed by #431 merge sweep

Post-merge re-scan (coordinator's ask) caught one more #302-derived
literal (#431's own PagePreview.tsx diff) - the flip-button custom-cardback
indicator dot's warning colour wasn't yet routed to var(--bs-warning).

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

---------

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