From 456a8bada316f43183516347694162e28c238770 Mon Sep 17 00:00:00 2001 From: Adithya Krishna Date: Fri, 27 Mar 2026 01:22:10 +0530 Subject: [PATCH 1/2] feat: add new variants and create docs for tokens --- .claude/rules/semantic-tokens.md | 867 ++++++++++++++++++ apps/sim/app/playground/page.tsx | 168 +++- .../emcn/components/banner/banner.tsx | 14 + .../emcn/components/combobox/combobox.tsx | 2 +- apps/sim/components/emcn/components/index.ts | 8 +- .../emcn/components/input/input.tsx | 39 +- .../emcn/components/label/label.tsx | 59 +- .../emcn/components/skeleton/skeleton.tsx | 57 +- .../emcn/components/slider/slider.tsx | 72 +- .../emcn/components/switch/switch.tsx | 91 +- .../emcn/components/textarea/textarea.tsx | 28 +- 11 files changed, 1325 insertions(+), 80 deletions(-) create mode 100644 .claude/rules/semantic-tokens.md diff --git a/.claude/rules/semantic-tokens.md b/.claude/rules/semantic-tokens.md new file mode 100644 index 00000000000..09163c95345 --- /dev/null +++ b/.claude/rules/semantic-tokens.md @@ -0,0 +1,867 @@ +# EMCN Design System Reference + +Complete reference for the EMCN component library, semantic design tokens, and Tailwind configuration. Use `@/components/emcn` as the single import path for all components. + +--- + +## Table of Contents + +1. [Semantic Tokens](#semantic-tokens) +2. [Tailwind Configuration](#tailwind-configuration) +3. [Component Reference](#component-reference) +4. [Icons](#icons) + +--- + +## Semantic Tokens + +All color values are CSS custom properties defined in `app/_styles/globals.css` under `:root` (light) and `.dark` selectors. Reference them with `var(--token-name)` in CSS or `[var(--token-name)]` in Tailwind arbitrary values. + +### Surface / Background + +| Token | Light | Dark | Usage | +|---|---|---|---| +| `--bg` | `#fefefe` | `#1b1b1b` | Main canvas background | +| `--surface-1` | `#f9f9f9` | `#1e1e1e` | Sidebar, panels | +| `--surface-2` | `#ffffff` | `#232323` | Blocks, cards, modals | +| `--surface-3` | `#f7f7f7` | `#242424` | Popovers, headers | +| `--surface-4` | `#f5f5f5` | `#292929` | Button base, badge backgrounds | +| `--surface-5` | `#f3f3f3` | `#363636` | Inputs, form elements | +| `--surface-6` | `#e5e5e5` | `#454545` | Elevated surfaces, hover states | +| `--surface-7` | `#d9d9d9` | `#505050` | Strong hover states | +| `--surface-active` | `#ececec` | `#2c2c2c` | Active/pressed state, skeleton bg | + +### Text + +| Token | Light | Dark | Usage | +|---|---|---|---| +| `--text-primary` | `#1a1a1a` | `#e6e6e6` | Headings, primary content | +| `--text-secondary` | `#525252` | `#cccccc` | Secondary content, descriptions | +| `--text-tertiary` | `#5c5c5c` | `#b3b3b3` | Tertiary labels, breadcrumbs | +| `--text-muted` | `#707070` | `#787878` | Muted text, placeholders in components | +| `--text-subtle` | `#8c8c8c` | `#7d7d7d` | Very low-emphasis text | +| `--text-body` | `#3b3b3b` | `#cdcdcd` | Body text, popover items | +| `--text-icon` | `#5e5e5e` | `#939393` | Icon default color | +| `--text-inverse` | `#ffffff` | `#1b1b1b` | Text on dark/light inverted backgrounds | +| `--text-muted-inverse` | `#a0a0a0` | `#b3b3b3` | Muted text on inverted backgrounds | +| `--text-error` | `#ef4444` | `#ef4444` | Error messages, required indicators | +| `--text-placeholder` | `#8d8d8d` | `#8d8d8d` | Input placeholder text | +| `--text-success` | `#22c55e` | `#22c55e` | Success text | + +### Border / Divider + +| Token | Light | Dark | Usage | +|---|---|---|---| +| `--border` | `#dedede` | `#333333` | Primary border (default for all `*` elements) | +| `--border-1` | `#e0e0e0` | `#3d3d3d` | Stronger border, input borders, active states | +| `--border-muted` | `#e4e4e4` | `#424242` | Subtle borders | +| `--border-success` | `#e0e0e0` | `#575757` | Success state borders | +| `--divider` | `#ededed` | `#393939` | Section dividers | + +### Brand / State + +| Token | Light | Dark | Usage | +|---|---|---|---| +| `--brand-secondary` | `#33b4ff` | `#33b4ff` | Selection highlights, secondary brand | +| `--brand-accent` | `#33c482` | `#33c482` | Tertiary button, accent green | +| `--selection` | `#1a5cf6` | `#4b83f7` | Text selection | +| `--warning` | `#ea580c` | `#ff6600` | Warning state | + +### Semantic Status + +| Token | Light | Dark | Usage | +|---|---|---|---| +| `--error` | `#dc2626` | `#f87171` | Error indicators | +| `--error-muted` | `#fecaca` | `#f6d2d2` | Muted error backgrounds | +| `--error-emphasis` | `#b91c1c` | `#b91c1c` | Strong error emphasis | +| `--caution` | `#f59e0b` | `#f59e0b` | Warning/caution indicators | +| `--success` | `#22c55e` | `#22c55e` | Success indicators | + +### Badge Colors + +Each badge color has `-bg` and `-text` variants. Used by the Badge component's color variants. + +| Base | Light BG | Light Text | Dark BG | Dark Text | +|---|---|---|---|---| +| `success` | `#bbf7d0` | `#15803d` | `rgba(34,197,94,0.2)` | `#86efac` | +| `error` | `#fecaca` | `#dc2626` | `#551a1a` | `#fca5a5` | +| `gray` | `#e7e5e4` | `#57534e` | `#3a3a3a` | `#a8a8a8` | +| `blue` | `#bfdbfe` | `#1d4ed8` | `rgba(59,130,246,0.2)` | `#93c5fd` | +| `blue-secondary` | `#bae6fd` | `#0369a1` | `rgba(51,180,255,0.2)` | `#7dd3fc` | +| `purple` | `#e9d5ff` | `#7c3aed` | `rgba(168,85,247,0.2)` | `#d8b4fe` | +| `orange` | `#fed7aa` | `#c2410c` | `rgba(249,115,22,0.2)` | `#fdba74` | +| `amber` | `#fde68a` | `#a16207` | `rgba(245,158,11,0.2)` | `#fcd34d` | +| `teal` | `#99f6e4` | `#0f766e` | `rgba(20,184,166,0.2)` | `#5eead4` | +| `cyan` | `#cffafe` | `#0891b2` | `rgba(14,165,233,0.2)` | `#7dd3fc` | +| `pink` | `#fbcfe8` | `#be185d` | `rgba(236,72,153,0.2)` | `#f9a8d4` | + +### Font Weights + +Weights are theme-aware to compensate for light-on-dark rendering differences. + +| Token | Light | Dark | Tailwind Class | +|---|---|---|---| +| `--font-weight-base` | `420` | `420` | `font-base` | +| `--font-weight-medium` | `440` | `480` | `font-medium` | +| `--font-weight-semibold` | `500` | `550` | `font-semibold` | + +### Shadows + +Defined in `:root` and overridden for `.dark` where applicable. + +| Token | Value | Tailwind Class | +|---|---|---| +| `--shadow-subtle` | `0 2px 4px 0 rgba(0,0,0,0.08)` | `shadow-subtle` | +| `--shadow-medium` | `0 4px 12px rgba(0,0,0,0.1)` | `shadow-medium` | +| `--shadow-overlay` | `0 16px 48px rgba(0,0,0,0.15)` | `shadow-overlay` | +| `--shadow-kbd` | `0 4px 0 0 rgba(48,48,48,1)` | `shadow-kbd` | +| `--shadow-kbd-sm` | `0 2px 0 0 rgba(48,48,48,1)` | `shadow-kbd-sm` | +| `--shadow-brand-inset` | `inset 0 1.25px 2.5px 0 #9b77ff` | `shadow-brand-inset` | +| `--shadow-card` | `0 1px 3px rgba(0,0,0,0.04)` | `shadow-card` | + +### Z-Index Scale + +| Token | Value | Usage | +|---|---|---| +| `--z-dropdown` | `100` | Dropdown menus | +| `--z-modal` | `200` | Modal overlays | +| `--z-popover` | `300` | Popovers (above modals for nested use) | +| `--z-tooltip` | `400` | Tooltips | +| `--z-toast` | `500` | Toast notifications | + +### Indicators + +| Token | Value | Usage | +|---|---|---| +| `--indicator-online` | `#33c482` | Online status dot | +| `--indicator-active` | `#4ade80` | Active state | +| `--indicator-inactive` | `#b7b7b7` | Inactive/offline | +| `--indicator-seat-filled` | `#34b5ff` | Occupied seat indicator | + +### Code Editor + +| Token | Light | Dark | +|---|---|---| +| `--code-bg` | `#f5f5f5` | `#1f1f1f` | +| `--code-foreground` | `#1a1a1a` | `#eeeeee` | +| `--code-line-number` | `#737373` | `#a8a8a8` | + +--- + +## Tailwind Configuration + +Defined in `tailwind.config.ts`. Key extensions to the default theme: + +### Dark Mode + +```ts +darkMode: ['class'] // Toggle via .dark class on +``` + +### Font Families + +| Class | Stack | +|---|---| +| `font-season` | Custom variable font (`var(--font-season)`) | +| `font-body` | System sans-serif stack | +| `font-mono` | Martian Mono + system monospace fallbacks | + +### Font Sizes + +| Class | Size | Usage | +|---|---|---| +| `text-micro` | `10px` | Micro labels | +| `text-xs` | `11px` | Small labels, button text `sm` | +| `text-caption` | `12px` | Captions, button group text, badge `md`/`lg` | +| `text-small` | `13px` | Labels, tag text | +| `text-base` | `15px` | Body text, branded buttons | +| `text-md` | `16px` | Larger body text | + +### Border Radius + +| Class | Value | +|---|---| +| `rounded-xs` | `2px` | +| `rounded-sm` | `calc(var(--radius) - 4px)` = `4px` | +| `rounded-md` | `calc(var(--radius) - 2px)` = `6px` | +| `rounded-lg` | `var(--radius)` = `8px` | + +### Custom Variant: `hover-hover` + +Applies hover styles only on devices with fine pointers and hover capability. Prevents sticky hover on touch devices. + +```tsx +// Usage +
+``` + +### Animations + +| Class | Duration | Usage | +|---|---|---| +| `animate-caret-blink` | `1.25s` | OTP input caret | +| `animate-slide-left` | `80s` | Infinite slide left (landing) | +| `animate-slide-right` | `80s` | Infinite slide right (landing) | +| `animate-placeholder-pulse` | `1.5s` | Loading placeholder opacity | +| `animate-ring-pulse` | `1.5s` | Border success pulse | +| `animate-stream-fade-in` | `300ms` | Streaming content fade-in | +| `animate-thinking-block` | `1.6s` | AI thinking indicator | +| `animate-slide-in-right` | `350ms` | Panel slide-in | +| `animate-slide-in-bottom` | `400ms` | Content slide-in from bottom | +| `animate-tour-tooltip-in` | `200ms` | Tour tooltip entrance | +| `animate-collapsible-down` | `300ms` | Expandable open | +| `animate-collapsible-up` | `300ms` | Expandable close | + +--- + +## Component Reference + +All components are imported from `@/components/emcn`. Never import from subpaths (except CSS files). + +```tsx +import { Button, Input, Badge, Tooltip } from '@/components/emcn' +``` + +### Button + +Versatile button with 12 visual variants and 3 sizes. + +**Variants:** `default` | `active` | `3d` | `outline` | `primary` | `destructive` | `secondary` | `tertiary` | `ghost` | `subtle` | `ghost-secondary` | `branded` + +**Sizes:** `sm` (11px) | `md` (12px, default) | `branded` (login form) + +```tsx + + + + + +``` + +| Variant | Background | Text | Border | Notes | +|---|---|---|---|---| +| `default` | `--surface-4` | `--text-secondary` | `--border` | Neutral, most common | +| `active` | `--surface-5` | `--text-primary` | `--border-1` | Selected/active state | +| `3d` | transparent | `--text-tertiary` | `--border-1` | Raised shadow effect | +| `outline` | transparent | `--text-secondary` | `--text-muted` | Bordered, no fill | +| `primary` | `--text-primary` | `--text-inverse` | none | High emphasis CTA | +| `destructive` | `--text-error` | white | none | Danger actions | +| `secondary` | `--brand-secondary` | `--text-primary` | none | Brand blue | +| `tertiary` | `--brand-accent` | `--text-inverse` | none | Brand green | +| `ghost` | transparent | `--text-secondary` | none | Minimal, text only | +| `subtle` | transparent | `--text-body` | none | Subtle hover background | +| `ghost-secondary` | transparent | `--text-muted` | none | Extra-low emphasis | +| `branded` | via CSS class | white | theme | Requires `branded-button-gradient` or `branded-button-custom` class | + +**Exports:** `Button`, `ButtonProps`, `buttonVariants` + +--- + +### ButtonGroup + +Connected toggle group where one item is selected at a time. + +**Gap:** `none` | `sm` (default) + +```tsx + + cURL + Python + +``` + +**Exports:** `ButtonGroup`, `ButtonGroupItem`, `ButtonGroupProps`, `ButtonGroupItemProps`, `buttonGroupVariants`, `buttonGroupItemVariants` + +--- + +### Input + +Text input with variant and size support. + +**Variants:** `default` | `error` | `ghost` + +**Sizes:** `sm` (12px) | `md` (14px, default) + +```tsx + + + + +``` + +| Variant | Background | Border | Focus | +|---|---|---|---| +| `default` | `--surface-5` | `--border-1` | border -> `--text-muted` | +| `error` | `--surface-5` | `--text-error` | stays `--text-error` | +| `ghost` | transparent | transparent | border -> `--border-1`, bg -> `--surface-5` | + +**Exports:** `Input`, `InputProps`, `inputVariants` + +--- + +### Textarea + +Multi-line text input with variant support. + +**Variants:** `default` | `error` | `ghost` + +```tsx +