Skip to content

Figma alignment, batch 1: implementation plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development to implement this plan task by task.

Goal: Bring the web app’s existing screens in line with the Figma “Final Design” page wherever that needs no new data and no product decision.

Architecture: This is styling and layout work in web/src only. Design tokens change once, in styles/tokens.css, and components consume them. No API, schema, or Go change. Every row this plan fixes is a numbered row of the audit.

Tech stack: React 19, Tailwind v4 tokens, Radix primitives, i18next (en/ms/zh), Vitest, and Playwright (existing specs only).

Spec: docs/superpowers/specs/2026-09-25-figma-alignment-audit.md. The audit is the spec: each task cites its rows by number, e.g. “3.7”. Figma file xjx0pz8JSVeCqP1kYg3elT, page “Final Design” (77:4027). The audit gives each row’s node id; read exact values with the Figma MCP tools (get_design_context on the node, after reading skill://figma/figma-design-to-code/SKILL.md), and never guess.

  • Out of scope: every row marked [PD], and everything in audit §12 (“App has, Figma doesn’t — keep”). Do not remove any feature, nav item, locale, hint, or control the app has.
  • Tokens: colours, radii and sizes go in web/src/styles/tokens.css as tokens. Components use tokens; no new hex literals in components. Dark-theme tokens must still be defined for every token you add or change.
  • Contrast: the status/tone text colours stay as they are (audit 0.2 is [PD]). Soft tints, borders, backgrounds and shapes may change.
  • Assets: raster assets ship as WebP (animation as WebM). SVG stays SVG. The sidebar astronaut is already at web/src/assets/sidebar-astronaut.webp (304×320, a 2× asset for about 151×161 display). Do not ship company-logo.png.
  • Money and i18n: a float never touches money (web/src/lib/money.ts only). Every user-facing string is an i18n key in en, ms and zh, and ms must be genuine Malay.
  • Tests: keep all existing vitest and e2e green. Update test selectors only where markup legitimately changed. Add a vitest case for any behaviour change (tabs not scrolling, title per tab, footer per state). While iterating, run pnpm -C web test -- <path>. Before committing, run pnpm -C web typecheck && pnpm -C web lint && pnpm -C web test.
  • Runtime check: each task loads its screens in the running app at 1920×1080 and 1280×800, light and dark, and compares them against the Figma frame renders in /private/tmp/claude-501/-Users-limziyang-Documents-repos-mcomtask/211212d1-b84f-40e0-bd2b-3ef9b4196ddd/scratchpad/figma/ (e.g. my-claims.png, petty-cash.png, wizard-*.png, detail-*.png).
    • The API runs on :3000.
    • Start vite from this worktree: pnpm -C web dev --port 5190 --strictPort, in the background, and stop it when done.
    • Signing in: an agent must not type passwords. Use the e2e helper pattern (web/e2e/support.ts login) from a throwaway Playwright script outside the repo, or report that the check could not be run.
  • Commits end with Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>.

Audit rows: 0.1, 0.3, 0.4, 0.5, 0.6, 3.7, 3.8, 3.9, 3.14, 3.15, 3.17 (shape only), 3.18, 3.22, 9.7, 9.10.

Files:

  • web/src/styles/tokens.css
  • web/src/components/ui/{Tabs,DataTable,Tag}.tsx
  • web/src/components/workflow/semanticTone.ts
  • web/src/features/claims/CategoryPills.tsx
  • their tests

Changes:

  • Card radius becomes 20px.
  • Soft tints and the table-header/top-bar background take the Figma values.
  • Row hover takes the Figma light blue (as a token, with a dark variant).
  • The paid (payout) chip becomes the green outline chip.
  • Tabs:
    • The tablist never scrolls vertically: fix the -mb-px / overflow-x-auto cause described in 3.8.
    • Figma tab styling (3.7): fixed-width items, 20px icons, active text primary, a rounded 2px underline under the label only, and no full-width rule.
    • Vitest: the list’s scrollHeight <= clientHeight, or assert the class change that removes the cause.
  • DataTable:
    • Draws no frame of its own when nested in a framed container. Add a prop such as framed={false}, and use it wherever a table sits inside a card section.
    • Header text is black regular.
    • Row height 54px.
    • The actions column header and cell are centred, with a 24px kebab.
  • Tags:
    • Status chips: radius 50, padding 6/16, white background; the draft chip gets a #d3d2dc-equivalent border token.
    • Category pill shape: radius 10, padding 6/16. Colour stays as is (per-category colour is [PD]).

Commit: Figma batch 1: shared tokens, tabs, table and chips.

Audit rows: 1.1 (hidden scrollbar and tighter spacing; the nav item count stays), 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 1.10 (style only, no logo), 1.11, 2.1, 2.5 (colour and size only; photo and job title are [PD]).

Files:

  • web/src/app/shell/{Sidebar,OrgSwitcher,TopBar,UserMenu}.tsx
  • web/src/app/shell/nav.ts
  • web/src/styles/tokens.css
  • tests

Changes:

  • Solid sidebar background, 237px wide.
  • Group headings keep their i18n text but lose the uppercase transform: 14px bold white.
  • A 1px 20%-white divider above every group after the first.
  • Nav items: 20px icons, gap 8, padding 8/16, radius 10, regular weight. The active item is a solid primary fill.
  • The astronaut sits at the bottom-right behind the nav: mirrored, 30% opacity, aria-hidden, alt="", not interactive. It is hidden when the sidebar is collapsed to icons and in the mobile drawer.
  • Icons: pick the closest lucide equivalents to Figma’s set for the items Figma shows (e.g. LayoutGrid, FolderOpen, Activity, ReceiptText→ a $-document, Wallet, Users, Calculator). Keep the other items’ icons consistent in weight.
  • The scrollbar is hidden (scrollbar-width: none plus the WebKit rule) while scrolling still works, so small windows can reach every item.
  • Header: 55px, no bottom border, Figma background.
  • User chip: white pill, h34.
  • Collapse mode and the mobile drawer must keep working.

Commit: Figma batch 1: sidebar and header.

Task FA3: Claims list — My claims, My approvals, All claims

Section titled “Task FA3: Claims list — My claims, My approvals, All claims”

Audit rows: 3.1, 3.2, 3.3, 3.4, 3.5 (the approved vs paid label distinction may use the existing green tokens; no new text colours), 3.6, 3.10, 3.12 (size and placeholder copy only; search semantics unchanged), 3.13, 3.20, 3.21, 3.23, 4.1, 4.2, 5.1, 5.4, 6.1.

Files:

  • web/src/features/claims/{ClaimsListPage,ClaimsTable}.tsx
  • web/src/components/ui/{PageHeader,StatCard,Button}.tsx
  • web/src/components/workflow/StateFilterChips.tsx
  • web/src/lib/format (date and time on two lines)
  • the claims locale files
  • tests

Behaviour changes, each needing a vitest:

  • The page title and subtitle follow the tab. The subtitle counts:
    • on My claims: my claims;
    • on All claims: the org’s claims, within the existing summary scopes;
    • on My approvals: those awaiting me.
  • The New claim button is shown on My claims only.
  • All claims has no actions column.
  • The My approvals tab is shown only to a member who can act on claims: gate it on the approvals count or on an existing permission the session exposes. Say which in the report.

Commit: Figma batch 1: claims list.

Audit rows: 7.1, 7.2, 7.3, 7.4, 7.5, 7.8, 7.9, 7.10 (a currency Select, only if a currency list already exists client-side or in the API; otherwise leave it and say so), 7.12, 7.14, 10.1, 10.3 (style only), 11.1, 11.3 (style only).

Files:

  • web/src/components/ui/{Dialog,Field,Input}.tsx
  • web/src/features/claims/wizard/*
  • web/src/components/upload/DocumentUploader.tsx
  • web/src/features/pettycash/{RequestFloatDialog,ReturnFloatDialog}.tsx
  • tests

Changes:

  • A dialog size of 700px with radius 20 and padding 32.
  • An optional tinted header band that can hold the stepper.
  • Field label 14px bold, input border in the light outline token, h36, radius 10.
  • The wizard’s repeated step heading is removed.
  • All existing wizard fields and Plan 11’s ChargeTo stay.

Commit: Figma batch 1: wizard and dialogs.

Audit rows: 8.1, 8.3, 8.4, 8.5 (only if receipts already support downloading), 8.6, 8.2.

Files:

  • web/src/components/ui/Drawer.tsx
  • web/src/features/claims/detail/*
  • tests

Changes:

  • Drawer 470px wide.
  • Amount banner tinted by state, including a rejected variant that shows the rejection reason, which the view already carries.
  • Approver actions sit under the banner at equal width.
  • 基本信息 is collapsible: four rows collapsed, all rows expanded.
  • 8.2, the footer by state, uses existing transitions and the existing wizard only. Map each footer button to an available transition or to “edit draft”; no new endpoint:
    • claimant pending: cancel + edit;
    • rejected: cancel + resubmit;
    • closed: download receipts + close.
    • A state with no mapped action keeps Close.
  • Vitest: one test per footer case.

Commit: Figma batch 1: claim detail.

Audit rows: 9.1 (style only; Record spend stays), 9.2 (style, fixed card widths, and a progress bar for Available as available/cash-balance computed from money strings in lib/money.ts; card 2’s project total is [PD], so keep the current card 2 content in the new style), 9.3 (always rendered, with an empty state; Figma styling; the columns keep the app’s data), 9.5 (stacked for now), 9.8 (a date column with the time on a second line; signed, coloured amounts where the direction is known; an actions kebab only if a row action already exists), 9.9, 9.11 (a “view record” link on the success toast, only if the toaster supports actions).

Files:

  • web/src/features/pettycash/*
  • web/src/components/ui/StatCard.tsx (only if shared)
  • the petty cash locale files
  • tests

Commit: Figma batch 1: petty cash.


FA1 → FA2 → FA3 → FA4 → FA5 → FA6. FA1’s tokens and primitives feed the rest.

  • Coverage: every non-[PD] audit row in sections 0–11 is assigned to a task, except:
    • 3.11 Export: a spec gap, but M, and a behaviour decision about scope.
    • 7.6, 7.11, 7.13, 8.7, 8.8, 9.4, 9.6, 10.2 and 11.2: [PD] or need data.
    • 3.16, 3.19 and 3.24: [PD].
  • Constraint check: no task removes a §12 feature, and text colours are untouched because 0.2 is [PD].