Skip to content

Restyle the decision card - #231

Open
MaggieAppleton wants to merge 5 commits into
mainfrom
design/decision-card-restyle
Open

MaggieAppleton wants to merge 5 commits into
mainfrom
design/decision-card-restyle

Conversation

@MaggieAppleton

@MaggieAppleton MaggieAppleton commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

PR 1 of the decision card redesign: restyles QuestionView to the approved jig. Resolved/Decided rendering is unchanged.

  • Header: no "Decision" label row; 24px success mark (new DecisionIcon in @chopin/icons) leads the question title. Presence badges unchanged (PR 2).
  • Options: lettered tiles, label/description, brand-wash selection with a fading check; native radio/checkbox kept (visually hidden, row focus ring). Multi-select adds a "Choose any" hint.
  • Custom answer is now the last "Add an option" row; one click turns it into a focused inline field (next letter) bound to the same custom draft and 4000-char limit.
  • Footer: Discard (outline) / Save (primary, "Saving…", "Try again"); Discard swaps the footer in place to "Discard this decision?" with Keep it / Discard (destructive), same underlying cancel action.
  • Several questions: tablist removed; footer stepper ‹ header n/m ›, primary reads "Next" until the last question, then "Save". Per-question drafts preserved.
  • Save failed: callout reusing .plan-research-callout / .plan-research-badge with a "Couldn't save" lead line.
  • Tests and e2e selectors/copy updated.

Decisions made

  • Save and Next are disabled until the current question has an answer (per the approved design; reviewer change). A blank custom answer does not count. Read-only views keep free Next navigation. The validation alert remains only for a skipped earlier question in a multi-question save and for server rejections.
  • Add an option field is a single-row auto-growing textarea (Enter blurs, Shift+Enter newline, Escape closes the field and returns to the choices) rather than the jig's <input>, so long existing custom answers keep wrapping and the 4000-char limit is unchanged. An empty field is left open (not auto-closed on blur) so Save still reports "requires an answer".
  • Inactive add row keeps a native radio/checkbox named "Add an option" for keyboard/AT semantics and e2e roles; the active field is a textbox with the same name.
  • The native inputs are 1px, opacity 0 inside their label row (not covering it), so label clicks, Playwright check() on options and the row focus ring all behave. Focus ring is drawn on the row via :has(:focus-visible).
  • "Couldn't save" heads every error callout, including cancel and sync errors, since error is one string.
  • Stepper focus: when a caret reaches an end it disables, so focus is moved to the opposite caret after render. Arrow-key tab navigation is gone with the tablist.
  • Design-contract bookkeeping: ChevronIcon size=16 allowed in the question view (icon test), btn-outline added as a recognised tier in the token test, native-control registrations for the old question inputs removed (the inputs are now intentionally bespoke), and dynamic-packages.json cases/hashes renewed for question-view.tsx and icons/line.tsx.
  • Reduced motion: the footer fade only runs under prefers-reduced-motion: no-preference (keeps the existing theme test's first reduced-motion block intact).
  • The "Decision" mark keeps a native title="Decision" tooltip as in the jig.

Before / after (2x)

State Before After
Open card
Option chosen
Add an option (field)
Discard confirm
Save failed
Several questions, first
Several questions, second

Note: the multi-question fixture is the read-only stored questionnaire (no live record), so selection states are not shown for it.

Checks

  • bun run fix, bun run ci, bun run types: pass
  • bun test: 1736 pass, 0 fail
  • e2e (--project=fixtures), full project: 88 passed

🤖 Generated with Claude Code

Drop the Decision label row for a mark beside the question, lettered option rows
with a trailing check, an always-last Add an option row, Discard/Save footer
with in-place confirm, a stepper in place of question tabs, and a shared
callout for a failed save. Adds DecisionIcon.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@coolify-githubnext-app

coolify-githubnext-app Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

The preview deployment for chopin is ready. 🟢

Open app | Open Build Logs | Open Application Logs

Last updated at: 2026-09-30 20:52:52 CET

The approved design greys the primary action until an option is chosen.
Next keeps free navigation in read-only views. Focus follows the primary
button when Next lands on the last question. The alert-motion e2e now
triggers a rejected save instead of an empty submit.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
MaggieAppleton and others added 3 commits September 30, 2026 21:48
The decision cards at the foot of the scroller wrap to more lines at 320px
than the old card did, so the bottom distance settles at 40px (was exactly
24px). Bound it at 64px; a moved document is hundreds of pixels.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@MaggieAppleton

Copy link
Copy Markdown
Collaborator Author

Independent review (automated, designer asleep)

Fixed and pushed

  • Save and Next were enabled with nothing chosen; the approved design disables them. Now disabled until the current question is answered (a blank custom answer does not count). Next keeps free navigation in read-only views. Unit tests added; the e2e now checks the disabled state.
  • The alert-motion e2e relied on an empty submit, which is no longer reachable. It now covers a server-rejected save (WebSocket question:submit refusal) and asserts "Couldn't save", the message, "Try again" and the alert transition.
  • CI failure responsive-content "a selected tab follows strip layout changes": not flaky. The seeded decision cards sit at the foot of the scroller and wrap to more lines at 320px, so the bottom distance settles at 40px. On main it was exactly 24px, the old limit, so it passed only by luck. Bound raised to 64px with a comment; a moved document would be hundreds of pixels. Full fixtures project now passes.
  • Escape in the Add an option field dropped focus to the body. Focus now returns to the row; e2e covers it.
  • After Next lands on the last question, focus moves to the new primary button (Save) rather than the Previous caret.
  • .question-callout now out-specifies .plan-research-callout so the padding does not depend on stylesheet load order.
  • Design-contract sourceHash renewed for question-view.tsx after these edits.
  • Refreshed after-1-open.png (Save greyed) and after-5-save-failed.png (now a real rejected save with a selected option).

Checked, no change needed: draft/multi-question state, multiple-select and custom-answer mode switching, discard confirm, aria-busy/disabled fieldset, keyboard-only focus ring, tokens/btn utilities, fidelity to the jig CSS (sizes, spacing, colours, copy).

Left as is

  • Saving from the last step with an earlier question unanswered still shows " requires an answer" (the view has no per-question focus from the controller); same as before this PR.
  • Enter in the field blurs it (as in the jig); focus is not moved elsewhere.

Checks: bun run fix, bun test (1736 pass), bun run types, bun run ci pass; e2e --project=fixtures 88 passed.

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