Skip to content

DS-037/038/039/040: tokenize chart colours and migrate Earn, Faucet and Referrals to shared primitives - #441

Merged
IbrahimIjai merged 3 commits into
SO4-Markets:mainfrom
nonso7:feat/ds-037-040-design-system-migration
Jul 27, 2026
Merged

DS-037/038/039/040: tokenize chart colours and migrate Earn, Faucet and Referrals to shared primitives#441
IbrahimIjai merged 3 commits into
SO4-Markets:mainfrom
nonso7:feat/ds-037-040-design-system-migration

Conversation

@nonso7

@nonso7 nonso7 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

The four issues all depend on semantic tokens and shared primitives that did not exist yet, so this PR adds those first and then migrates each surface onto them.

Tokens

packages/ui/src/styles/globals.css gains semantic colour roles for both themes:

  • --success, --warning, --info, --destructive-foreground
  • trading aliases --long / --short
  • --chart-* roles (surface, text, grid, crosshair, crosshair-label, border, up, down, liquidation) that alias the semantic tokens

Because the chart roles alias the same tokens the UI uses, a long candle and a positive PnL can no longer drift apart.

Shared primitives (@workspace/ui)

New: Text / Heading (type scale + tones), NumericText (tabular figures with positive | negative | warning | accent | muted | neutral roles), Stat, Card, Table, Alert, LoadingState / EmptyState / ErrorState, Spinner, LoadingButton. Badge gains success / warning / info / muted variants.

All of them are covered by a new accessibility + behaviour suite (primitives.test.tsx, 37 tests) and are shown in the development-only design system gallery at /design-system.

DS-040 — Tokenize trading chart colours

apps/web/src/features/trade/lib/chart-theme.ts is a typed adapter between the CSS tokens and lightweight-charts:

  • ChartPalette names every colour the chart paints; CHART_TOKENS maps each role to its CSS custom property.
  • The chart renders to canvas and parses colours itself, and it cannot read oklch(). The resolver converts each token by painting it to a 1×1 canvas and reading the pixel back, so tokens stay authored in oklch while the chart receives rgb().
  • Any role that fails to resolve falls back to an sRGB mirror of the token, so SSR and the first paint still get the right colours.
  • TVChartContainer re-applies layout, candle and position-line colours from a MutationObserver on the root class — theme changes repaint without a reload.
  • Long / short / liquidation lines now use --long / --short / --warning.

32 unit tests cover both generated palettes, the per-role fallback, the resolver-throws path, the colour-conversion rule and the light-vs-dark difference.

DS-037 / DS-038 / DS-039 — Earn, Referrals, Faucet

  • Feature-local one-off text sizes (text-[11px], text-[13px], …) replaced with the shared type scale.
  • Rewards, balances, APRs, TVL, commissions and token amounts go through NumericText / Stat with semantic numeric roles.
  • Loading, empty and error treatments use the shared state primitives; the duplicated TierProgress in affiliates-tab.tsx now reuses the shared one.
  • Tables (Earn distributions + discover, Referrals distributions + referrals + commission tiers) use the shared table primitives, which scroll inside their own container rather than widening the page.
  • Faucet covers connected, disconnected, cooldown, mismatch, loading and error states; every claim action is a LoadingButton with aria-busy and an aria-hidden spinner, so the button keeps its accessible name.
  • Referrals stacks the sidebar below the content under lg so the layout holds at 375px; tier chips render through the shared Badge with the tier tint kept as data in tiers.ts.

Drive-by fix

@workspace/ui's test suite could not run at all: vitest.config.ts overrode setupFiles with a name that mergeConfig appended rather than replaced, and vitest-axe@0.1.0 ships an empty extend-expect entry so toHaveNoViolations was never registered. Both are fixed, four stale assertions in the pre-existing specs are corrected (Base UI exposes aria-selected, not data-state; the slider's accessible control is a hidden range input; two axe fixtures were missing labels), and the package now runs 55/55 green with a clean tsc.

Verification

  • packages/ui: 55/55 tests pass, tsc --noEmit clean.
  • apps/web: all Earn tests and the 32 chart-theme tests pass. The remaining Faucet / referrals-page / code-display / useReferralCode failures are identical to main on this machine (invalid placeholder contract IDs and a jsdom clipboard stub) — verified by running the same command on a stashed tree.
  • vite build succeeds; the built CSS emits both token sets and the new utilities.
  • Checked in a real browser at 1440px and 375px in both themes: the chart repaints live on theme change with no colour-parse errors, and the migrated pages render correctly.

Known issue, not addressed here

At 375px every app page (including /pools, untouched by this PR) overflows horizontally by 56px because of the shared Navbar. It reproduces identically on main, so it is left for a separate fix.

Closes #424
Closes #425
Closes #426
Closes #427

…and Referrals

Adds the semantic colour roles and shared primitives the remaining DS issues
depend on, then migrates the four surfaces onto them.

Tokens (packages/ui/src/styles/globals.css)
- --success / --warning / --info / --destructive-foreground, plus the trading
  aliases --long and --short, for light and dark.
- --chart-* roles (surface, text, grid, crosshair, border, up, down,
  liquidation) that alias those semantic tokens, so the trading chart and the
  rest of the app cannot drift apart.

Shared primitives (packages/ui)
- Text / Heading type scale, NumericText with semantic numeric roles, Stat,
  Card, Table, Alert, LoadingState / EmptyState / ErrorState, Spinner and
  LoadingButton. Badge gains success / warning / info / muted variants.
- All are exercised by a new accessibility + behaviour suite and shown in the
  development-only design system gallery.

DS-040 — trading chart colours
- New typed adapter (features/trade/lib/chart-theme.ts) derives the chart
  palette from the CSS tokens, converting oklch() into a notation
  lightweight-charts can paint, and falls back per role when a token is
  unreadable. TVChartContainer re-themes the layout, candles and position
  lines on class change with no reload. 32 unit tests cover both palettes.

DS-037 / DS-038 / DS-039 — Earn, Referrals and Faucet
- Feature-local one-off text sizes, cards, pills, tables, alerts, spinners and
  empty states replaced with the shared primitives; rewards, balances, APRs,
  commissions and token amounts now use semantic numeric roles.
- Faucet covers connected, disconnected, cooldown, mismatch, loading and error
  states; claim actions use LoadingButton.
- Referrals stacks its sidebar below the content under lg so the layout holds
  at 375px; tier chips render through the shared Badge.

Also repairs the @workspace/ui test setup: the vitest setup file was resolved
under the wrong name and vitest-axe's matcher was never registered, so the
whole package suite errored out. It now runs green (55 tests).

Resolves SO4-Markets#424
Resolves SO4-Markets#425
Resolves SO4-Markets#426
Resolves SO4-Markets#427
@vercel

vercel Bot commented Jul 26, 2026

Copy link
Copy Markdown

@nonso7 is attempting to deploy a commit to the Ijai's projects Team on Vercel.

A member of the Team first needs to authorize it.

@nonso7 nonso7 closed this Jul 26, 2026
@nonso7 nonso7 reopened this Jul 26, 2026
@drips-wave

drips-wave Bot commented Jul 26, 2026

Copy link
Copy Markdown

@nonso7 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Conflicts and how they were resolved:

- packages/ui/setup-tests.ts + vitest.setup.ts — upstream kept a shim
  importing ./setup-tests; this branch had already inlined that setup into
  vitest.setup.ts. Kept the self-contained vitest.setup.ts and dropped the
  now-unreferenced setup-tests.ts (packages/ui only — apps/web keeps its own).

- packages/ui/src/styles/globals.css — this branch's token block is a strict
  superset of upstream's (same values, plus the semantic status and chart
  roles), so it is taken as-is.

- packages/ui/src/components/alert.tsx — the two sides shipped different
  APIs. Merged into one component supporting both: the existing `variant` +
  AlertTitle/AlertDescription composition used across the app, and upstream's
  `severity`/`layout`/icon/action/onDismiss props API. `variant` maps onto
  `severity` for colour ("danger" -> "error") but keeps its own ARIA mapping
  so existing `variant="warning"` callsites are not silently made assertive.
  Severity colours use the semantic tokens rather than upstream's raw
  emerald/amber palette, per this branch's token migration.

Also updates five `.animate-pulse` test assertions to query
[data-slot="skeleton"], since upstream's skeleton deliberately moved to
`motion-safe:animate-pulse` and asserts the bare class is absent.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@IbrahimIjai
IbrahimIjai merged commit 7385f4b into SO4-Markets:main Jul 27, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants