Web app vs Figma "Final Design": differences
Figma: file xjx0pz8JSVeCqP1kYg3elT, page “Final Design” (77:4027). Code: worktree
.worktrees/plan-11-project-approval/web/src (paths below are relative to that). App values
were measured in the running app (localhost:5173, 1920×1080, light theme, getComputedStyle)
unless marked “code”. Figma values come from get_design_context / get_metadata / pixel
samples of exported frames. Screenshots are in scratchpad/figma/.
Legend: (a) layout/visual, (b) missing element/section, (c) behaviour/structure.
Size: S under an hour, M half a day to a day, L more than a day or needs backend.
[PD] = needs a product decision or backend data; it is not a style fix.
[P10-Fx] = the Plan 10 spec (docs/superpowers/specs/2026-09-23-plan-10-frontend-design.md)
already chose this deviation on purpose (ruling Fx or the section cited). Listed so you can
re-decide, not because it is an accident.
Data differences (names, amounts, “CLM-” vs “EC-” references) are ignored.
0. Shared tokens (these affect every screen)
Section titled “0. Shared tokens (these affect every screen)”| # | Type | Element | Figma | App | Size |
|---|---|---|---|---|---|
| 0.1 | a | Card radius (KPI cards, list container, panels) | 20px (card I129:2811;129:2692, panels 407:17002) |
--radius-card: 12px (styles/tokens.css:177) |
S (token change; check every rounded-card user) |
| 0.2 | a | Status/tone text colours | amber #ffa30e, green #00b884 (paid label #1a932e), red #ea3434, blue #57f (= #5577ff), purple #9747ff, all used as text on white or soft tints |
Darkened for WCAG AA: amber-fg #9a5b00, green-fg #0f7a45, red-fg #b4232a, blue-fg #1d5fc9 (tokens.css:37-61). Accent (border/icon) colours also differ: amber #f5a623, green #1aa260, red #e0242a, blue #3b82f6 |
S to change, [PD]: Figma’s #ffa30e on #fef6df is about 2:1 contrast, below AA. Decide: exact Figma, or keep AA |
| 0.3 | a | Soft tints | pending card #fef6df, approved/paid #e9f8ef, total #edf5fa, rejected #ffe3e3 (pixel), category pills #fff1db/#e2f4ff/#f1dbff/#edfff0 |
amber-soft #fff5dc, green-soft #e6f7ee, blue-soft #eaf2fd, red-soft #fdecec (tokens.css:38-59) |
S |
| 0.4 | a | Table header / top bar background | #faf5f9 (pixel sample and Header Light 77:4061) |
--bg-subtle: #f8f6fa (tokens.css:15) |
S |
| 0.5 | a | Paid status chip | Green outline chip, same as 已批准 (I126:1618;63:3042) |
payout → green-solid, a filled green chip with white text (components/workflow/semanticTone.ts:10) |
S ([P10-§3.4] table says “green (solid)”) |
| 0.6 | a | Row hover | Light blue #ecf5ff (pixel, row 3 of 430:26056) |
hover:bg-bg-subtle #f8f6fa (components/ui/DataTable.tsx:111) |
S |
1. Shell: sidebar (instance 126:1565; illustration I126:1565;63:2568)
Section titled “1. Shell: sidebar (instance 126:1565; illustration I126:1565;63:2568)”| # | Type | Element | Figma | App | Size |
|---|---|---|---|---|---|
| 1.1 | c | Scrollbar | No scroll. 9 items fit in 1080px | overflow-y-auto (app/shell/Sidebar.tsx:121). Measured: nav ends at y=820 and the collapse button at 1068, so natural height is about 888px. At 1080px there is no overflow (scrollHeight = clientHeight = 1080), but any window shorter than about 890px shows a scrollbar (a 1366×768 or 1440×900 laptop with browser chrome). The cause is the 16 nav items, not the CSS alone |
S to hide the scrollbar (scrollbar-width:none) or tighten spacing; M to shrink the nav ([PD]: 16 items vs Figma’s 9, see 1.12) |
| 1.2 | b | Astronaut illustration | Bottom-right, opacity: 30%, mirrored (-scale-x-100), left: 37.55%, right: -1.27%, aspect 206/219, so about 151×161px on a 237px sidebar. Sits behind the nav |
Missing | S. Asset downloaded: figma/astronaut-object1.png (540×568 PNG, the fill used in the frame); figma/sidebar-raw-2.png is the same image at 270×284 (sidebar-raw-1.png duplicates the 540 one) |
| 1.3 | b | Section dividers | border-top: 1px rgba(255,255,255,0.2) above 申请 and 管理 (I126:1565;63:2423, ;63:2428) |
None; groups are separated only by gap-4 (Sidebar.tsx:94) |
S |
| 1.4 | a | Background | Solid #876b9f (pixel-sampled top to bottom: constant 135,107,159) |
Gradient #8a6aaa → #6a4b8d (tokens.css:26-27, Sidebar.tsx:121) |
S |
| 1.5 | a | Width | 237px | 240px (xl:w-60, Sidebar.tsx:123) |
S |
| 1.6 | a | Group heading | 14px/16 bold white, not uppercase, 46px-tall row (I126:1565;63:2418) |
12px/14 bold, uppercase, rgba(255,255,255,.72) (Sidebar.tsx:100); renders “WORKSPACE / REQUESTS / APPROVALS / MANAGE” in English |
S |
| 1.7 | a | Nav item | 20px icon, gap 8, padding 8/16, 14px regular white, radius 10, row about 36px | 16px icon (size-4), gap 12, padding 0/12, h-36 (Sidebar.tsx:60,66) |
S |
| 1.8 | a | Active item | Solid #6a4b8d fill (I126:1565;63:2426), text weight regular |
rgba(255,255,255,.18) overlay, font-medium (Sidebar.tsx:62, tokens.css:30) |
S |
| 1.9 | a | Icons | Iconly-style set: 4-squares (首页), folder (项目), pulse (Activity), $-document (费用报销), wallet (备用金), cube (资产预订), people (团队), calculator (会计), megaphone (公告) | lucide ReceiptText, WalletCards, HandCoins, ListChecks, etc. (app/shell/nav.ts:1-21) |
S–M (choose lucide equivalents, or export the Figma SVGs) |
| 1.10 | a | Org switcher | Pill rgba(106,75,141,.4), h38, radius 10, 26px company logo image, 12px text “Company name”, chevron at right (I126:1565;426:21487). Employee frame 135:12106: no chevron, a flat header with a bottom divider |
bg-sidebar-active (white 18%), h40, lucide Building2 icon, 14px text (app/shell/OrgSwitcher.tsx:23-26) |
S for style. The logo needs an org logo field [PD]. figma/company-logo.png is a third-party brand mark used as a placeholder; do not ship it |
| 1.11 | a | Container padding | Header row padding 16, nav column 184px wide, centred | p-3 (12px) everywhere (Sidebar.tsx:121) |
S |
| 1.12 | b | Figma nav items the app lacks | 首页 Home, 项目 Projects, 资产预订 Asset booking, 会计 Accounting, 公告 Announcements | Not rendered | [PD] L. No backend for these ([P10-F4], spec §1 “Out of scope”) |
2. Shell: header (Top, 201:12152 → 83:6578)
Section titled “2. Shell: header (Top, 201:12152 → 83:6578)”| # | Type | Element | Figma | App | Size |
|---|---|---|---|---|---|
| 2.1 | a | Height / border | 55px, #faf5f9, no bottom border |
56px (h-14), #f8f6fa, border-b #efeef2 (app/shell/TopBar.tsx:29) |
S |
| 2.2 | b | Global search pill | Centred, white, radius 50, h34, 20px search icon, 12px placeholder “Search for anything” (77:4078), group width 524 | Missing | [PD] L. No search backend ([P10-F4]) |
| 2.3 | b | “Ai Chats” pill | White pill 119×34, #9747ff 14px text, robot image (77:4085; figma/ai-chats-robot.png) |
Missing | [PD] L ([P10-F4]) |
| 2.4 | b | Notification bell | 20px bell-03 left of the user chip (77:4062) |
Missing | [PD] L ([P10-F4]) |
| 2.5 | a | User chip | White pill h34 radius 50, 28px photo avatar, name 14px #292d32, second line = job title (“Finance Manager”) 12px rgba(41,45,50,.44), chevron (77:4065) |
bg-primary-soft #f1e9f1, 32px initials disc, second line = organization name (app/shell/UserMenu.tsx:31-41) |
S for colour/size. Photo and job title need data [PD] (M) |
| 2.6 | a | Breadcrumb | 12px; group #8e8e93 uppercase, item black (77:4064) |
Matches (components/ui/Breadcrumb.tsx:21); on petty cash Figma shows “申请 / 备用金”, the app follows the locale | none |
3. My claims (123:7183)
Section titled “3. My claims (123:7183)”| # | Type | Element | Figma | App | Size |
|---|---|---|---|---|---|
| 3.1 | a | Vertical rhythm | Top → title 8px, title row → KPIs 8px, KPIs → tabs 8px, tabs sit directly on the list container (0 gap) | Title 16px below the header (main py-4), PageHeader mb-4 plus gap-4, so 32px title → KPIs, 16px KPIs → tabs, 16px tabs → container (components/ui/PageHeader.tsx:14, features/claims/ClaimsListPage.tsx:119) |
S |
| 3.2 | a | Page subtitle | 12/14 black (126:1573) | 12/14 text-fg-muted grey (PageHeader.tsx:17) |
S |
| 3.3 | a | “提交报销” button | h36, padding 4/8, gap 4, 20px plus icon, 14px regular (126:1575) | h40, padding 0/16, gap 8, 16px icon, font-medium (measured; components/ui/Button.tsx) | S |
| 3.4 | a | KPI cards | Radius 20, border 1px white, gap between cards 16, internal gap 16, count 20px bold (line-height 16), amount 16/20, icon 30px, height 116 | Radius 12, border = accent at 40% alpha, gap 12 (gap-3), count 18px, icon 28px (size-7), height 114 (components/ui/StatCard.tsx:86,91,95; ClaimsListPage.tsx:136) |
S |
| 3.5 | a | KPI label colours | 待审核 #ffa30e, 已批准 #00b884, 已付款 #1a932e, 总提交 #57f |
amber-fg #9a5b00; approved and paid both tone-green-fg; blue-fg (StatCard.tsx:15-50) |
S (see 0.2) |
| 3.6 | a | KPI icons | Clock; circle-check; square $ (banknote in a rounded square); document with an up arrow | Clock, CircleCheck, BadgeDollarSign, FileText (ClaimsListPage.tsx:139-160). Closest lucide: SquareDollarSign, FileUp |
S |
| 3.7 | a+c | Tab group (我的报销/我的审批/所有报销) | Fixed 124×30 items, gap 0, 20px icons, active text #6a4b8d, underline 62×2px rounded, under the label only, no full-width rule under the tabs (126:1585-1587) |
Items auto-width with gap-6, 16px icons, active text black medium, border-b-2 across the whole trigger, plus a full-width border-b on the list (components/ui/Tabs.tsx:30,37-38,42) |
S |
| 3.8 | c | Tab row scrolls vertically | No scroll | Confirmed: tablist scrollHeight 30 > clientHeight 29. Cause: overflow-x-auto on the list (Tabs.tsx:30) forces overflow-y to compute to auto too, and each trigger’s -mb-px (Tabs.tsx:37) pushes 1px past the list’s bottom border, so a vertical scrollbar appears. The same component is used on petty cash (Requests/Cash movements), where it was also measured 30 > 29 |
S (drop -mb-px, or use overflow-y-hidden, or change the underline technique) |
| 3.9 | a | List container | One border #efeef2, radius 20 on top corners only, padding-top 16; the table is flush inside it (126:1588) |
Outer section radius 12 with border plus DataTable’s own rounded-card border wrapper inside it, so two borders and two radii, 1px inset (ClaimsListPage.tsx:173; components/ui/DataTable.tsx:71; measured outer 1632px, inner 1630px) |
S (let DataTable drop its frame when nested) |
| 3.10 | a | Status label + chips | “主状态” label followed by a vertical divider (border-right #d3d2dc, h24). Chips h38, p8, radius 10; active bg #f1e9f1 with text #846a9a medium; inactive white with #8e8e93 medium; count badge 20px radius 5 (active: #6a4b8d bg with #f1e9f1 text; inactive: #f1e9f1 bg with #6a4b8d text) |
No divider after “Status”. Chips h32; active text black; inactive text weight 400 (components/workflow/StateFilterChips.tsx:25-27,58) | S |
| 3.11 | b | 筛选 Filter / 导出 Export | Right end of the chip row, 20px icon plus 14px text (129:2619, 129:2620) | Missing. The Plan 10 spec §5.2 lists “export” for this screen, so this is also a gap against our own spec | Export M (CSV of the current query, backend or client); Filter [PD] (what does it open?) |
| 3.12 | a | Search | 342×34, radius 10, 20px icon, 12px placeholder “搜索报销单号/供应商…” (126:1608) | 256×36 (md:w-64), 16px icon, 14px text, placeholder “Search claim ID or title…” (ClaimsListPage.tsx:184-195) |
S. Searching by supplier needs the API to support it [PD] |
| 3.13 | a | Project / month selects | 230px and 180px wide, h36, 20px chevron (123:7159, 126:1616) | 160px each (measured) | S |
| 3.14 | a | Table header | 44px, #faf5f9, 14px black regular (I126:1618;63:2979) |
44px, #f8f6fa, 14px #8e8e93 (DataTable.tsx:75,82) |
S |
| 3.15 | a | Row height | 54px | 57px (h-13.5 plus py-2 with 24px chips; measured) |
S |
| 3.16 | b | Title cell subline | Title 14px plus merchant 12px (“Zus咖啡”, “Grab”) | Title only, font-medium (features/claims/ClaimsTable.tsx:30). Plan 10 spec §5.2 promised “the first line’s supplier as the subline”, but ExpenseClaim in api/openapi.yaml has no supplier field |
M. Needs an additive list field [PD] |
| 3.17 | a | Category pill | Soft pill, radius 10, padding 6/16, a different colour per category (orange, blue, purple, green) | Always purple soft, radius 6 (rounded-chip), padding 0/12, h24 (features/claims/CategoryPills.tsx:11; components/ui/Tag.tsx:49) |
S for shape. Per-category colour [PD]: categories carry no colour; hashing the id to a palette is S, a colour column is M |
| 3.18 | a | Status chip | Radius 50, padding 6/16 (about h26), white bg; draft text #8e8e93 with a #d3d2dc border |
Padding 0/12, h24; draft text #3c3c43 (Tag.tsx:49; tone-neutral-fg) |
S |
| 3.19 | b | Foreign-currency amount | Two lines: “CNY 333.00” over “RM 210.55” | Base amount only | [PD] M. The list item carries only total in base currency |
| 3.20 | a | Submitted cell | Two lines: “11 Aug 2026” (14px) over “10:10 AM” (12px) | One line “24 Sept 2026, 23:41” (ClaimsTable.tsx:64 uses whitespace-pre-line, but formatDateTime returns no newline) |
S |
| 3.21 | a | Claim ID | Roboto regular | font-mono (ClaimsTable.tsx:74) |
S |
| 3.22 | a | Actions column | Header “操作” and 24px kebab both centred (I126:1618;63:3083-3085) |
Left-aligned header, 40px IconButton | S |
| 3.23 | a | “Showing 6 of 6 claims” | 14/16 black | 12/14 muted (ClaimsListPage.tsx:237) | S |
| 3.24 | c | Pagination | Numbered pager ‹ 1 2 3 … 10 › when more than 10 rows (note 426:21251; shown on 135:11106) |
“Load more” | [P10-F10]: cursor API. Numbered pages would need a total count [PD] |
4. My approvals (123:7184)
Section titled “4. My approvals (123:7184)”Everything in §3 applies too. Additional:
| # | Type | Element | Figma | App | Size |
|---|---|---|---|---|---|
| 4.1 | c | Page title follows the tab | Title “我的审批” (note 171:12705 says the name differs per tab) | Always “My claims” (t('title'), ClaimsListPage.tsx:121) |
S |
| 4.2 | c | “提交报销” button | Not shown on this tab | Shown on every tab | S |
| 4.3 | b | 5 KPI cards | Adds 已拒绝 (bg #ffe3e3, label #ea3434, square-X icon); last card is “审批总数” |
4 cards; no rejected KPI (ClaimsListPage.tsx:136-165) | M. Needs a rejected bucket in the summary (S4) [PD] |
| 4.4 | b | Second filter row | “审批状态” for main states, then “审批阶段” for detail stages (类别已核对, 已结算, 退款处理中, 退款已确认, 争议中) | One row with every definition state (Draft … Disputed) | M. Which states are “main” vs “detail” is not in the definition [PD] |
| 4.5 | b | Group select | Adds “全部报销组” (claim group) as well as “所有项目” (project) | One select, “All projects”, which is actually the claim group | [PD] M. Figma separates group from project; Plan 11’s charge-to may be the project axis |
| 4.6 | b | Department + Projects columns | “Department”, “Projects” between category and status | Missing | M. Needs claimant unit and charge-to project on the list item [PD] |
5. All claims (135:11106)
Section titled “5. All claims (135:11106)”| # | Type | Element | Figma | App | Size |
|---|---|---|---|---|---|
| 5.1 | c | Title/subline | “所有报销”, “本月共 30笔报销 · 16 笔待审核” | “My claims”; subline counts my own claims only (thisMonth uses scope mine, ClaimsListPage.tsx:74) |
S |
| 5.2 | b | 5 KPI cards incl. 已拒绝; last one “报销总数” | 4 cards | see 4.3 | |
| 5.3 | b | Employee + Projects columns (note 171:12715 “可查看员工,Projects”) | Missing. Employee names are available (member directory S2); project is not | Employee S–M; project [PD] | |
| 5.4 | c | No actions column | Actions kebab shown | S | |
| 5.5 | b | Two filter rows, group + project selects, numbered pagination | see 4.4, 4.5, 3.24 |
6. Employee view (135:12106)
Section titled “6. Employee view (135:12106)”| # | Type | Element | Figma | App | Size |
|---|---|---|---|---|---|
| 6.1 | c | Only the 我的报销 tab | “My claims” and “My approvals” always show; “All claims” is permission-gated (ClaimsListPage.tsx:104-108) | S. Gate to_act on a transition permission, or on the approvals count |
|
| 6.2 | a | Sidebar for an employee | Org header without chevron and with a bottom divider; nav 工作区 (首页, 项目, Activity), 申请 (费用报销, 资产预订), 管理 (公告) | Permission-filtered items; the org switcher already hides the chevron for one org | see §1 |
7. Submit wizard (popup 233:13631; steps 151:9387, 157:10693, 157:11554, 166:12080, 157:12018, 166:11486)
Section titled “7. Submit wizard (popup 233:13631; steps 151:9387, 157:10693, 157:11554, 166:12080, 157:12018, 166:11486)”| # | Type | Element | Figma | App | Size |
|---|---|---|---|---|---|
| 7.1 | a | Dialog width / radius | 700px, radius 20, content padding 32 | md:max-w-3xl (768px), radius 24, padding 24 (components/ui/Dialog.tsx:7,39-41; ClaimWizard.tsx:274) |
S |
| 7.2 | a | Header band | Title 20px medium on a #faf9fb band (padding 16/32/8), 12px grey subtitle; the stepper sits in the same band with a bottom border #efeef2 (151:4385, 151:4489) |
White header, 16px bold title (Dialog.tsx:46); the stepper is inside the scrolling body | S–M |
| 7.3 | a | Stepper | Badge 24px; current = #6a4b8d fill with bold 14px white number; future = #f3f4f6 fill with #d3d2dc border and #4b5563 number; fixed 100px connector lines; steps spread across the width |
Reached = primary fill, 12px number; unreached = border only; connectors flex-1 (features/claims/wizard/Stepper.tsx:9-32) |
S |
| 7.4 | b/c | Extra step heading | None | An h3 repeating the step name (ClaimWizard.tsx:309) |
S (remove) |
| 7.5 | a | Field style | Label 14px bold; input border #efeef2 (light outline), h36, radius 10, padding 9/8; hints are inline grey after the label, e.g. “标题 (这笔报销在列表中显示的名称)” |
Field component: border #d3d2dc, hint rendered separately (components/ui/Field.tsx, Input.tsx) |
S |
| 7.6 | b | 报销类型 has two options | “费用报销: I already paid” and “采购申请: I need approval before buying”, with descriptions in the dropdown (157:10616) | One option, “receipt” (StepInfo.tsx:52-59) | [PD] L. Purchase requests are a new record type |
| 7.7 | a | Step 1 layout | 项目 half-width alone; 报销类型 + 费用类别 side by side; title; purpose | Same grid, plus ChargeTo (Plan 11) and a record-language hint | keep (see §12) |
| 7.8 | a | Step 2 upload | Dashed dropzone #faf9fb-ish, 16px upload icon, “点击上传或拖拽文件到此处”; file rows on a tinted bg with PDF icon, size, status “已上传 ✓” / “上传中” spinner, trash icon |
Dashed box with a 24px icon; file rows with a FileText icon and a border (components/upload/DocumentUploader.tsx:113-186) |
S–M |
| 7.9 | a | Date field | Calendar icon inside the input | DatePicker (check the icon) | S |
| 7.10 | a/b | Amount + currency | “RM” prefix box plus a currency select (MYR ▾) | MoneyInput plus a free-text 3-letter currency input (StepAmount.tsx:120-125) | S (select from a currency list) |
| 7.11 | b | “备注 (选填)” remark on step 2 | Present | Not on step 2 (description is on step 1) | S (if the line or claim has a note field; check the API) |
| 7.12 | a | Step 3 payout cards | 3 cards in a row, radio at left, title plus masked detail; selected border #6a4b8d |
RadioCards auto-fit grid (components/ui/RadioCards.tsx:36-58); close | S |
| 7.13 | b | “设为默认收款方式” checkbox | Below the payout cards | Missing | S–M (does the API store a default channel? [PD]) |
| 7.14 | a | Footer buttons | 保存草稿 outline 126×40 with #846a9a text; 上一步 outline about 200px; 下一步 primary 172px with chevron |
Default Button widths (ClaimWizard.tsx:277-306) | S |
8. Claim detail drawer (Approve 278:24022, 278:24420, 286:9929, 297:15763, 278:25302, 286:15830…)
Section titled “8. Claim detail drawer (Approve 278:24022, 278:24420, 286:9929, 297:15763, 278:25302, 286:15830…)”| # | Type | Element | Figma | App | Size |
|---|---|---|---|---|---|
| 8.1 | a | Drawer width | About 470px (390px in a 1600px render of a 1925px frame) | 520px (components/ui/Drawer.tsx:35) | S |
| 8.2 | b | State-specific footer | Claimant pending: 取消申请 + 编辑报销; rejected: 取消申请 + 重新提交; closed: 下载收据 + 关闭 | Always one full-width “Close” (features/claims/detail/ClaimDrawer.tsx:121-123); transitions are in a TransitionBar in the body | M. Edit/resubmit/cancel map to existing transitions and the wizard |
| 8.3 | a | Amount banner by state | pending: amber soft; closed: green soft “8月9日已付款 · 9月1日已结案”; rejected: red soft with the rejection reason in red | green when settled, otherwise bg-subtle grey; no rejected variant (ClaimDrawer.tsx:195-207) |
S |
| 8.4 | a | Approver actions | 驳回 (red outline) and 通过审批 (primary), equal width, directly under the banner | TransitionBar layout="bar" (close; check widths) |
S |
| 8.5 | b | Receipts “下载” (download all) | Beside the thumbnails | Check ClaimReceipts (features/claims/detail/ClaimReceipts.tsx) | S |
| 8.6 | c | 基本信息 collapsible | Collapsed shows 4 rows; expanded shows 11 (297:15763) | Always expanded (ClaimFacts) | S |
| 8.7 | a | Timeline rows | Future steps show the expected approver (e.g. “Jessica Wong”, “Finance Team”); after a rejection the remaining steps read “已取消 — 申请未继续” | Pending steps without names unless the view carries eligible approvers ([P10 §4]) | M [PD] |
| 8.8 | b | Comments (评论) | Input, 发布, empty state, threaded replies with like/edit/delete (286:9929, 297:15763) | Missing | [P10-F3] [PD] L. No comment model |
9. Petty cash (407:17221; small screen 426:24658/426:24659)
Section titled “9. Petty cash (407:17221; small screen 426:24658/426:24659)”| # | Type | Element | Figma | App | Size |
|---|---|---|---|---|---|
| 9.1 | a | Header buttons | 归还备用金 (outline 112×36) and 申请备用金 (primary with plus) | Return float, Record spend, Request float; disabled with a tooltip when you are not the holder (features/pettycash/PettyCashPage.tsx:119-131) | keep Record spend (§12); S for style |
| 9.2 | a | KPI cards | 3 cards of fixed width 396 / 464 / 464 (the row does not fill the width), radius 20. Card 1 amber “待审核 3 笔” plus amount RM 31.00. Card 2 #eeecff “授权项目备用金总额度 RM 28,000.00” (24px bold), “共3个授权项目” 12px #746596, coins icon. Card 3 #e2f4ff “可用余额 RM 15,800.00”, “可用 56.4%” and a 6px progress bar (track #d6deff, value #39baff), wallet icon. Variant 446:21158: card 2 “备用金额度 RM 10000.00, 已使用20% (RM2000.00 / RM10000.00)” with a bar |
Grid of 3 equal columns; “In progress” count with the hint “requests not yet finished” (no amount); “Cash balance” (purple tone) + committed; “Available” (blue) + float code; no progress bars; 18px figures (features/pettycash/FloatKpis.tsx:9-47) | S for style and bar (a percentage only needs a ratio from server strings, no client sum). Card 2 total across projects [P10-§5.4] [PD] |
| 9.3 | b/c | 待审批 panel | Always a half-width panel (left), heading 14px bold #24212b plus 12px subtitle, header row #fef6df, columns 日期 / 申请金额 / 用途说明 / 操作, 批准 (green #00b884 outline 80×30) and 驳回 (red #ea3434 outline 80×30) |
Exists as ToApproveTable, but renders nothing when the queue is empty (features/pettycash/ToApproveTable.tsx:19); full width; header bg-subtle grey; columns reference / requested by / amount / description / status / actions; TransitionBar buttons |
S–M. Also decide whether to show an empty state instead of hiding it |
| 9.4 | b | 按项目查看备用金使用 panel | Right half: 项目名称 + code, 已使用/额度, 使用率 % with a 7px bar (track #cbebff, value #8564d3), 可用余额; header row #eeecff |
Missing. The app shows a Floats table instead (custodian only) (PettyCashPage.tsx:152-158) | [P10-§5.4] [PD] L. Floats are per holder, not per project; the per-project quota does not exist |
| 9.5 | a | Panel layout | 待审批 and per-project side by side (two 809px columns, gap 16); stacked at 1280px (426:24659) | Stacked full width | S once 9.3/9.4 are decided |
| 9.6 | b | Records toolbar | Heading “备用金流水记录”; status-count chips (全部 6, 待审核 3, 已审核, 已批准, 已出款, 已拒绝, 归还); search “搜索申请编号,说明…” 342px; month select 180px; 筛选; 导出 | Heading plus Requests / Cash movements tabs only (PettyCashPage.tsx:159-175); no chips, search, month, filter or export | M (chips need a count summary, as claims have in S4; [PD] for search and export) |
| 9.7 | c | Records tab row scrolls vertically | n/a | Measured 30 > 29, same cause as 3.8 (shared Tabs) | fixed by 3.8 |
| 9.8 | a/b | Records table columns | 日期 (date over time) / 类型 / 说明 / 金额 / 状态 / 申请编号 / 操作 (kebab); amounts signed and coloured (+ RM 68.40 green, - RM 650.00 red); the 归还 view adds 归还方式 |
Requests: type / reference / description (+date subline) / amount / status, no date column, no actions; ledger is a separate tab (features/pettycash/RequestsTable.tsx, MovementLedger.tsx) | M |
| 9.9 | a | Type pills | 申请备用金 purple, 归还备用金 blue, 已支出 red; radius 10, h28 | Spend red, top-up purple, outline chips h24 (RequestsTable.tsx:36-38) | S |
| 9.10 | a | Row hover | #ecf5ff |
#f8f6fa |
S (0.6) |
| 9.11 | b | Toasts | Green-check toast with title, body and a “查看记录” link (430:25922) | Toaster (components/ui/Toaster.tsx); a link action is probably missing | S |
10. Request float (426:18791; 430:25361, 430:26056)
Section titled “10. Request float (426:18791; 430:25361, 430:26056)”| # | Type | Element | Figma | App | Size |
|---|---|---|---|---|---|
| 10.1 | a | Dialog | 700px, radius 20, tinted header band (same as 7.1/7.2) | Default md (512px) (features/pettycash/RequestFloatDialog.tsx:38) |
S |
| 10.2 | b | Fields | 申请金额 (RM prefix), 项目, 预计使用日期, 代申请员工 (on behalf of), 用途说明, 补充资料 upload | Amount and purpose only, plus “into float X” text (RequestFloatDialog.tsx:54-73) | [PD] M–L. Project and on-behalf-of fields don’t exist in POST /pettycash/topups. On-behalf-of also bears on “a claimant never picks their own approver” and “nobody files for anybody else” (Ruling R20) |
| 10.3 | a | Footer | 保存草稿 (outline) + 提交申请 | Cancel + Submit request | S if drafts exist for top-ups [PD] |
11. Return float (446:20155; 446:21158)
Section titled “11. Return float (446:20155; 446:21158)”| # | Type | Element | Figma | App | Size |
|---|---|---|---|---|---|
| 11.1 | a | Dialog | 700px, radius 20, tinted header | Default 512px (features/pettycash/ReturnFloatDialog.tsx:33) | S |
| 11.2 | b/c | Partial return | 关联备用金申请 (linked request select), 项目, 退还金额 with a “全部退还” link, 退还日期, 退还方式 cards (bank / cash / Touch ’n Go) + “设为默认退还方式” + 管理收款资料, 上传凭证, 备注 | Returns the whole cash balance and closes the float; shows float code + amount; proof upload only (ReturnFloatDialog.tsx:52-71) | [PD] L. The app’s return is a close-out; a partial return linked to a request is a different model |
| 11.3 | a | Footer | 保存草稿 + 提交申请 | Cancel + Submit return | S |
12. App has, Figma doesn’t — keep
Section titled “12. App has, Figma doesn’t — keep”- Extra nav items: Activity is in both; the app adds Advances, Approvals (with a count badge), Float register, Team, Org structure, Chart of accounts, Payout channels, Reports, Fiscal periods, Journal entries, Settings, Workflows, Project approvers (app/shell/nav.ts:39-156).
- Sidebar collapse toggle and icon-only mode between 768 and 1280px; mobile drawer (Sidebar.tsx:115-141, AppShell.tsx).
- en / ms / zh i18n (English by default); Figma is Chinese-only.
- Record-language hints (claims wizard, petty cash dialogs).
- Wizard: Plan 11 ChargeTo picker, receipt-evidence basis, supplier, e-Invoice UUID, relaxation reason, “Add another line”, other-lines list (StepAmount.tsx, StepInfo.tsx).
- Claim detail: lines table (P10-F11), sign-off panel, settlements, duplicate flags, keyboard ←/→ pager.
- Petty cash: Record spend, float selector and Floats table for custodians, Cash movements ledger, disabled-button reasons.
- Row menu (open, copy reference, edit draft) on claims.
- Dark theme.
13. Needs a product decision (not a style fix)
Section titled “13. Needs a product decision (not a style fix)”- Global search, Ai Chats, notification bell (2.2-2.4). No backend. Show inert controls, or keep them hidden? (P10-F4)
- Nav items 首页, 项目, 资产预订, 会计, 公告 (1.12). No modules.
- 16 nav items vs Figma’s 9. This drives the sidebar scrollbar (1.1). Collapse groups, move admin items under Settings, or accept the scroll with a hidden scrollbar?
- Exact Figma status colours vs WCAG AA contrast (0.2).
- User chip photo and job title (2.5); org logo (1.10).
- Claim list data: merchant subline (3.16), original-currency amount (3.19), department / project / employee columns (4.6, 5.3), rejected KPI bucket (4.3), main vs detail state split (4.4), claim group vs project filters (4.5), per-category colours (3.17), numbered pagination with totals (3.24), filter panel and export (3.11).
- Purchase request (采购申请) as a second claim type (7.6); default payout method checkbox (7.13).
- Claim comments (8.8, P10-F3); expected approvers on future timeline steps (8.7).
- Petty cash by project: authorised project total, per-project quota and usage (9.2, 9.4), project and on-behalf-of on requests (10.2), partial returns linked to a request with a return method (11.2). The app’s float is per holder (P10 §5.4), so this is a model change, not a screen change.
Assets downloaded (scratchpad/figma/)
Section titled “Assets downloaded (scratchpad/figma/)”astronaut-object1.png: 540×568, sidebar illustration (render mirrored, 30% opacity, about 151×161px at bottom-right).sidebar-raw-2.png: the same illustration at 270×284.sidebar-raw-1.pngduplicates the 540 version.sidebar-export.png: 240×1080 render of the whole Figma sidebar, for visual reference.company-logo.png/sidebar-raw-3.png: 400×425 placeholder company logo (a third-party brand mark; do not ship).ai-chats-robot.png: 752×690 robot image from the Ai Chats pill.- Frame renders:
my-claims.png,my-approvals.png,all-claims.png,employee-view.png,wizard-1-info.png…wizard-6-confirm-active.png,detail-closed.png,detail-pending.png,detail-pending-approver.png,detail-expanded.png,petty-cash.png,request-float.png,request-float-2.png,request-float-3.png,return-float.png,return-float-2.png,small-screen-a.png,small-screen-b.png,toast.png.
Not verified
Section titled “Not verified”- The app’s wizard, detail drawer and petty-cash dialogs were compared from code, not opened in the browser. The logged-in user (a custodian) does not hold the float shown, so the petty-cash buttons were disabled.
- Mobile (<768px) layouts were not compared; the new Figma file has no mobile frames in scope.
- Dark mode was not compared.