|
1 | 1 | --- |
2 | 2 | name: emcn-design-review |
3 | | -description: Review UI code for alignment with the emcn design system — components, tokens, patterns, and conventions |
| 3 | +description: Review product UI changes for design drift using the local conformance check, EMCN components, and global styles. |
4 | 4 | argument-hint: "[scope] [fix=true|false]" |
5 | 5 | --- |
6 | 6 |
|
7 | | -# EMCN Design Review |
8 | | - |
9 | | -Arguments: |
10 | | -- scope: what to review (default: your current changes). Examples: "diff to main", "PR #123", "src/components/", "whole codebase" |
11 | | -- fix: whether to apply fixes (default: true). Set to false to only propose changes. |
| 7 | +# EMCN design review |
12 | 8 |
|
13 | 9 | User arguments: $ARGUMENTS |
14 | 10 |
|
15 | | -## Context |
16 | | - |
17 | | -This codebase uses **emcn**, a custom component library built on Radix UI primitives with CVA variants and CSS variable design tokens. All UI must use emcn components and tokens. |
18 | | - |
19 | | -## Steps |
20 | | - |
21 | | -1. Read the emcn public barrel at `packages/emcn/src/index.ts` (re-exports components, Calendar, Table*, and icons) to know what's available; for the full icon set read `packages/emcn/src/icons/index.ts` |
22 | | -2. Read `apps/sim/app/_styles/globals.css` for CSS variable tokens |
23 | | -3. Analyze the specified scope against every rule below |
24 | | -4. If fix=true, apply the fixes. If fix=false, propose the fixes without applying. |
25 | | - |
26 | | ---- |
27 | | - |
28 | | -## Imports |
29 | | - |
30 | | -- Components, `cn`, and tokens from the `@sim/emcn` barrel, never component subpaths |
31 | | -- Icons from `@sim/emcn/icons` |
32 | | - |
33 | | -## Design Tokens |
34 | | - |
35 | | -Use CSS variable pattern (`text-[var(--text-primary)]`), never Tailwind semantics (`text-muted-foreground`) or hardcoded colors (`text-gray-500`, `#333`). |
36 | | - |
37 | | -**Text**: `--text-primary`, `--text-secondary`, `--text-tertiary`, `--text-muted`, `--text-body` (canonical value text), `--text-icon`, `--text-placeholder`, `--text-subtle`, `--text-inverse`, `--text-error` |
38 | | -**Surfaces**: `--bg`, `--surface-1` through `--surface-7`, `--surface-hover`, `--surface-active` |
39 | | -**Borders**: `--border` (`--border-1`/`--border-muted` are legacy aliases resolving to it — flag new uses) |
40 | | -**Brand/accent**: `--brand-secondary`, `--brand-accent` |
41 | | -**Z-Index**: `--z-dropdown` (100), `--z-toast` (150), `--z-modal` (200), `--z-popover` (300), `--z-tooltip` (400), `--z-takeover` (500), `--z-shell-gate` (600) |
42 | | -**Shadows**: `shadow-subtle`, `shadow-medium`, `shadow-overlay`, `shadow-card` |
43 | | -**Badges**: `--badge-*` semantic families (success/error/gray/blue/purple/orange/amber/teal/cyan/pink, each with `-bg`/`-text`) |
44 | | - |
45 | | -## Buttons |
46 | | - |
47 | | -Intent-to-variant mapping (read the actual `buttonVariants` in `packages/emcn/src/components/button/button.tsx` for the full variant set — it exposes more than listed here): |
48 | | - |
49 | | -| Action | Variant | |
50 | | -|--------|---------| |
51 | | -| Toolbar, icon-only | `ghost` | |
52 | | -| Create, save, submit | `primary` | |
53 | | -| Cancel, close | `default` | |
54 | | -| Delete, remove | `destructive` | |
55 | | -| Selected state | `active` | |
56 | | -| Toggle | `outline` | |
57 | | - |
58 | | -## Delete/Remove Confirmations |
59 | | - |
60 | | -`ChipModal` `size='sm'`, title "Delete/Remove {ItemType}", destructive confirm button, plain Cancel (follow the chip footer layout in `.claude/rules/emcn-components.md`). Use `text-[var(--text-error)]` for irreversible warnings. |
61 | | - |
62 | | -## Toast |
63 | | - |
64 | | -`toast.success()`, `toast.error()`, `toast()` from `@sim/emcn`. Never custom notification UI. |
65 | | - |
66 | | -## Badges |
67 | | - |
68 | | -`red`=error/failed, `gray-secondary`=metadata/roles, `type`=type annotations, `green`=success/active, `gray`=neutral, `amber`=processing, `orange`=paused, `blue`=info. Use `dot` prop for status indicators. |
69 | | - |
70 | | -## Icons |
71 | | - |
72 | | -Default: `size-[14px]`. Color: `text-[var(--text-icon)]`. Scale: 14px > 16px > 12px > 20px. Use the `size-*` shorthand — flag `h-[Npx] w-[Npx]` and `h-N w-N` pairs as refactor targets. |
| 11 | +Interpret the arguments as the product UI scope (default: current changes) and an optional `fix=true|false` mode (default: `false`). When `fix=false`, explain proposed changes without applying them. |
73 | 12 |
|
74 | | -## Anti-patterns to flag |
| 13 | +1. When EMCN, global styles, recipes or design ownership metadata change, run the diff check in step 2. It derives facts from each source revision, so the originating design-system change remains visible without a committed metadata file. |
| 14 | +2. During UI work, run `bun run check:design --base origin/staging --working-tree` from the repo root, substituting the actual PR target for `origin/staging`. After committing, use `--head HEAD` for the immutable PR comparison. Exit 1 means findings to review; exit 2 means the check failed and must be repaired or reported. CI is warning-only for findings and fails on incomplete analysis. |
| 15 | +3. For each new finding, inspect the cited source, the applicable public EMCN export in `packages/emcn/src/index.ts`, and tokens and recipes in `apps/sim/app/_styles/globals.css`. Reuse a suitable component, prop, variant, or global token when it expresses the design intent. Avoid near-duplicate local colours or overriding EMCN chrome merely for convenience. |
| 16 | +4. A genuinely new product treatment may remain an Extra. Explain its visual intent and why existing EMCN or global styling does not fit in the PR. The check does not decide design approval and must not be silenced by adding an arbitrary token, broad exclusion, or fake component wrapper. Ask the designer or engineer when changing a shared recipe would have broad or ambiguous effects. |
| 17 | +5. Keep unresolved `unchecked` inputs and inspection failures separate from findings. A quiet diff means no *new detected* debt, not proof of complete visual conformance. Existing debt stays quiet; a new copy can warn. Landing and docs are out of product scope; Monaco presentation, provider branding, and block identity palettes have deliberate exclusions. See `scripts/design-conformance/README.md` for exact rule boundaries. |
75 | 18 |
|
76 | | -- Raw `<button>`/`<input>`, or legacy `Input`/`Textarea`/`Modal`, instead of the canonical chip components (`ChipInput`/`ChipTextarea`/`ChipModal`) |
77 | | -- Hand-rolled field rows inside a `ChipModalBody` instead of `ChipModalField` |
78 | | -- Hardcoded colors (`text-gray-*`, `#hex`, `rgb()`) |
79 | | -- Tailwind semantics (`text-muted-foreground`) instead of CSS variables |
80 | | -- Template literal className instead of `cn()` |
81 | | -- Inline styles for colors/static values (dynamic values OK) |
82 | | -- Importing from emcn subpaths instead of barrel |
83 | | -- Arbitrary z-index instead of tokens |
84 | | -- Wrong button variant for action type |
| 19 | +Do not turn this review into an unrelated whole-codebase cleanup. Preserve intended appearance when migrating product UI and use before/after screenshots when a treatment changes. |
0 commit comments