Skip to content

feat(ui): rebuild Subscription on subturtle-ui - #67

Open
SomiVista wants to merge 1 commit into
new-designfrom
claude/subscription-screen-subturtle-ui
Open

feat(ui): rebuild Subscription on subturtle-ui#67
SomiVista wants to merge 1 commit into
new-designfrom
claude/subscription-screen-subturtle-ui

Conversation

@SomiVista

Copy link
Copy Markdown
Collaborator

The next screen in the pilotUI → subturtle-ui migration, from the Subturtle Subscription.dc.html handoff.

What changed

The four standalone pricing cards become the design's tablist + detail panel: a current-plan usage strip, one tab per tier, and the selected tier's price, CTA and features in a single panel. Styled entirely with st- classes and var(--token) — no raw hex, no dark: variants — and verified under data-theme="light" and "dark".

No new ui/ components and no new icons. StSwitch, StBadge, StButton, StCard, StSkeleton, StEmptyState, StModal and solar:check-circle-bold all already ship, so ui/ gains nothing but a comment fix.

StarterUsageCard is deleted — it was used only by this page, and the strip now serves every tier. VoiceMeter stays untouched: two un-migrated screens still use its sm variant.

Departures from the prototype, and why

bg-st-sunken for the panel's left rail, not --ink-50 The ink ramp inverts in dark, where ink-50 lands within one channel step of --surface-card and the rail disappears.
Amber/red steps on the meter fill Rose at rest as drawn, but the cap warning Council 004 specced survives — the prototype's all-zero demo never shows it.
Unlimited = empty accent track A full bar reads as "you are at your cap", the opposite of unlimited.
Free tier never reads "Unlimited" FREE_CAPS fallback, carried over from the deleted card — a missing cap would otherwise promise something the tier does not give.
Reader keeps the "Upgrade to Learner" upsell A no-voice tier would otherwise render a dead 0 / 0.
Ribbon uses Stripe's badge metadata Falls back to the i18n string; the prototype hardcodes "POPULAR".
Strip names the tier ("Starter") The prototype's "Free plan" is demo text; this keeps the strip and the tabs consistent.

Manage / change plan / downgrade / checkout / Adaptive Pricing all behave as before.

Fixes found along the way

  • goToPortal recursion. It branched on trialing to open the retention off-ramp, but the off-ramp's own "continue" calls goToPortal — trialing users could never reach the portal. manageSubscription now owns that branch.
  • Misleading first paint. The strip rendered its defaults (Starter, no allowances) as a real answer before getSubscriptionDetails landed; it now waits on isSubscriptionFetching.
  • Dead isLoading state dropped rather than carried forward — it was read but never assigned.
  • Stale docs. theme-tokens.css and CLAUDE.md said the design system's subturtle-theme.css supersedes ui/'s dark layer wholesale. Per the handoff that note predates the theme PR — ui/'s is the one that ships (RGB channels for Tailwind, the .theme-switching rule, measured contrast). Corrected in both. Comments only; no palette change.

Testing

  • tests/e2e/specs/subscription-ui.spec.ts asserted against the old cards and the VoiceMeter sub-line; assertions updated to the new structure. 8/8 pass.
  • yarn test:unit 43/43, nuxi typecheck clean for the touched files (4 pre-existing errors remain in ActivityChartOverview.vue, untouched).
  • Verified in-browser against a real backend with a standard freemium user, light and dark, plus mobile at 430px.

🤖 Generated with Claude Code

Replaces the four standalone pricing cards with the design's tablist + detail
panel: a current-plan usage strip, one tab per tier, and the selected tier's
price, CTA and features in a single panel. All `st-` tokens, no raw hex and no
`dark:` variants, so the screen reads correctly under both themes.

No new components or icons were needed — StSwitch, StBadge, StButton, StCard,
StSkeleton, StEmptyState, StModal and solar:check-circle-bold all already ship.

Notable decisions, and where they depart from the prototype:

- The usage strip serves every tier, so StarterUsageCard (used only here) is
  deleted and the paid "This month" block folds into the same four meters.
- `bg-st-sunken` for the detail panel's left rail, not the design's `--ink-50`:
  the ink ramp inverts in dark, where ink-50 lands within one channel step of
  --surface-card and the rail disappears.
- Meter fill stays rose at rest as drawn, but keeps the amber/red cap warning
  Council 004 specced — the prototype's all-zero demo never shows it.
- An unlimited allowance renders an empty accent track; a full bar would read as
  "at your cap". A free tier never reads Unlimited (FREE_CAPS fallback), and a
  Reader with no voice budget keeps the "Upgrade to Learner" upsell instead of a
  dead 0 / 0.
- The ribbon uses Stripe's `badge` metadata, falling back to the i18n string.
- Manage/change/downgrade CTAs are preserved; goToPortal no longer branches on
  trialing (the off-ramp's own "continue" calls it, which would have recursed),
  manageSubscription owns that.
- The strip waits on isSubscriptionFetching so its defaults never render as a
  real answer, and dead `isLoading` state is dropped.

theme-tokens.css and CLAUDE.md carried a note saying the design system's
subturtle-theme.css supersedes ui/'s dark layer wholesale. Per the screen
handoff that note predates the theme PR; ui/'s is the one that ships (RGB
channels for Tailwind, the .theme-switching rule, measured contrast). Corrected
in both places — comments only, no palette change.

The e2e spec asserted against the old card layout and VoiceMeter sub-line; its
assertions are updated to the new structure. 8/8 pass.

Co-Authored-By: Claude Opus 5 (1M context) <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