@trading-game/design-intelligence-layer
v0.15.0
Published
Trading Game Design System — shadcn/ui components with Tailwind CSS v4
Downloads
4,511
Readme
Trading Game Design System
A component library and design token system for the Trading Game product. Built on shadcn/ui with a custom Figma-driven token architecture, Tailwind CSS v4, and React 19.
Published as @trading-game/design-intelligence-layer on npm.
Quick Start
Installation
npm install @trading-game/design-intelligence-layer@latest --safe-chain-skip-minimum-package-ageNote: The
--safe-chain-skip-minimum-package-ageflag bypasses npm's 72-hour safe-chain hold on newly published packages. Required when the latest version was published less than 72 hours ago (common for AI agents and CI pipelines).
1. Add the CSS imports
In your main CSS file (e.g. globals.css), add these three lines in this order:
@import "@trading-game/design-intelligence-layer/styles";
@import "tailwindcss";
@source "../node_modules/@trading-game/design-intelligence-layer/dist";Why
@source? Tailwind v4 skipsnode_modulesby default. Without this line, Tailwind won't generate CSS for the component classes. Adjust the path if your CSS file is not one level belownode_modules(e.g. in a monorepo use../../node_modules/...).
1b. Vite projects — add the Tailwind plugin
If your project uses Vite (e.g. Vite + React), you must add the Tailwind CSS plugin to your Vite config:
npm install @tailwindcss/vite// vite.config.js
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'
export default {
plugins: [react(), tailwindcss()],
}Next.js projects do not need this — Next.js uses PostCSS for Tailwind automatically.
2. Fonts (handled automatically)
The styles import loads Plus Jakarta Sans from Google Fonts automatically. No additional font setup is needed.
Use font-body, font-display, or font-sans in your Tailwind classes — all resolve to Plus Jakarta Sans.
3. Use components
import { Button, Card, Badge } from "@trading-game/design-intelligence-layer"
export default function App() {
return (
<Card>
<Button variant="primary">Trade Now</Button>
<Badge>Live</Badge>
</Card>
)
}Peer dependencies
Make sure these are installed in your project:
npm install react react-dom tailwindcssRequires React 18+ and Tailwind CSS v4+.
What's inside
- 56 UI components — buttons, forms, dialogs, charts, sidebars, and more
- Design tokens — CSS custom properties for color, radius, typography, and transitions synced from Figma
- Transition tokens — semantic duration and easing tokens (
duration-base,ease-standard, etc.) — no hardcodedduration-200anywhere - Light-only theme — white backgrounds, black text, primary blue accents — no dark mode
- Typography classes — heading scale (h1–xs) and body scale (lg–xs) ready to use
- TypeScript — full type definitions included
- ESM + CJS — works with any bundler
Available components
| Component | Import |
|---|---|
| Accordion | Accordion, AccordionItem, AccordionTrigger, AccordionContent |
| Alert | Alert, AlertTitle, AlertDescription |
| Alert Dialog | AlertDialog, AlertDialogTrigger, AlertDialogContent, ... |
| Avatar | Avatar, AvatarImage, AvatarFallback, AvatarBadge, AvatarGroup |
| Badge | Badge, badgeVariants |
| Breadcrumb | Breadcrumb, BreadcrumbList, BreadcrumbItem, ... |
| Button | Button, buttonVariants |
| Calendar | Calendar, CalendarDayButton |
| Card | Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter |
| Carousel | Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext |
| Chart | ChartContainer, ChartTooltip, ChartLegend, ChartStyle |
| Checkbox | Checkbox |
| Collapsible | Collapsible, CollapsibleTrigger, CollapsibleContent |
| Combobox | Combobox, ComboboxInput, ComboboxContent, ComboboxItem, ... |
| Command | Command, CommandDialog, CommandInput, CommandList, ... |
| Context Menu | ContextMenu, ContextMenuTrigger, ContextMenuContent, ... |
| Dialog | Dialog, DialogTrigger, DialogContent, DialogHeader, ... |
| Drawer | Drawer, DrawerTrigger, DrawerContent, DrawerHeader, ... |
| Dropdown Menu | DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, ... |
| Empty State | Empty, EmptyHeader, EmptyTitle, EmptyDescription, EmptyContent |
| Field | Field, FieldLabel, FieldDescription, FieldError, FieldGroup |
| Form | Form, FormItem, FormLabel, FormControl, FormField, FormMessage |
| Hover Card | HoverCard, HoverCardTrigger, HoverCardContent |
| Input | Input |
| Input Group | InputGroup, InputGroupAddon, InputGroupButton, InputGroupText |
| Input OTP | InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator — Variants: OTP 4 digits, OTP 6 digits, OTP 6 split, OTP 8 digits, OTP 6 separated |
| Item | Item, ItemMedia, ItemContent, ItemTitle, ItemDescription |
| Kbd | Kbd, KbdGroup |
| Label | Label |
| Link | Link |
| Menubar | Menubar, MenubarMenu, MenubarTrigger, MenubarContent, ... |
| Native Select | NativeSelect, NativeSelectOptGroup, NativeSelectOption |
| Navigation Button | NavigationButton, navigationButtonVariants |
| Navigation Menu | NavigationMenu, NavigationMenuList, NavigationMenuTrigger, ... |
| Pagination | Pagination, PaginationContent, PaginationLink, ... |
| Popover | Popover, PopoverTrigger, PopoverContent, PopoverAnchor |
| Progress | Progress |
| Radio Group | RadioGroup, RadioGroupItem |
| Resizable | ResizableHandle, ResizablePanel, ResizablePanelGroup |
| Scroll Area | ScrollArea, ScrollBar |
| Select | Select, SelectTrigger, SelectContent, SelectItem, ... |
| Separator | Separator |
| Sheet | Sheet, SheetTrigger, SheetContent, SheetHeader, ... |
| Sidebar | Sidebar, SidebarProvider, SidebarMenu, SidebarMenuItem, ... |
| Skeleton | Skeleton |
| Slider | Slider |
| Spinner | Spinner |
| Stepper | Stepper |
| Switch | Switch |
| Table | Table, TableHeader, TableBody, TableRow, TableHead, TableCell |
| Tabs | Tabs, TabsList, TabsTrigger, TabsContent |
| Textarea | Textarea |
| Ticket Card | TicketCard, BoostTicketCard |
| Toast | Toaster |
| Toggle | Toggle, toggleVariants |
| Toggle Group | ToggleGroup, ToggleGroupItem |
| Tooltip | Tooltip, TooltipTrigger, TooltipContent, TooltipProvider |
Blocks
Blocks are opinionated, composed UI patterns built from design system primitives — exported from the package the same as primitives. Import them by name and pass data via props. Variants (layout / mode / status) live on a single block, not separate components.
import { HeroBlock, ResultBlock, OpenPositionsBlock } from "@trading-game/design-intelligence-layer"| Block | Variants | Description |
|---|---|---|
| HeroBlock | layout: "centered" \| "split" | Marketing hero section. Centred = single-column, no image; split = two-column with image. Tagline pill, heading, body, primary + optional secondary CTA. |
| AuthBlock | mode: "sign-in" \| "sign-up" | Auth form — logo lockup, OAuth provider buttons (Google, Telegram, X), divider, email input, terms, primary CTA, footer cross-link. |
| FAQBlock | layout: "desktop" \| "mobile" | Eyebrow + heading + intro + accordion + optional "Need more help" card. Items passed as { value, question, answer }[]. |
| NavBarBlock | — (internal mobile-menu state) | Responsive marketing nav — brand logos, link buttons, Sign in / Sign up CTAs, hamburger drawer on mobile. |
| HeaderNavigationBlock | — | In-app trading header. Back · badge · balance · optional history button with history.count numeric badge (bg-primary; ≥99 → 99+) · actions slot. |
| OpenPositionsBlock | Position discriminated union (rise-fall / swipe / box-o / digits) | Responsive Sheet (desktop) / Drawer (mobile) listing open positions. Consumer-provided trigger; default empty state. |
| ResultBlock | status: "win" \| "loss", ctaMode: "next-round" \| "go-again" \| "conversion" | Win/loss result card. Animated halo + thumb illustration (bundled inline) + contract badge + duration badge + CTA. |
| ResultDialog | — | Fixed-width system dialog (title + body + two CTAs). For messages like "out of balance" or "on a roll". |
See AGENTS.md for full usage examples per block.
Button variants and sizes
<Button variant="primary" /> // Blue filled — main CTA (light surfaces)
<Button variant="primary-inverse" /> // White filled + blue text — main CTA on dark/coloured surfaces
<Button variant="secondary" /> // Black outline — secondary actions (light surfaces)
<Button variant="secondary-inverse" /> // White outline + white text — secondary actions on dark/coloured surfaces
<Button variant="tertiary" /> // Text only — minimal (light surfaces)
// Sizes
<Button size="lg" /> // 48px height (default)
<Button size="md" /> // 40px height
<Button size="sm" /> // 32px height
<Button size="xs" /> // 24px height
<Button size="icon-lg" /> // 48px square
<Button size="icon-md" /> // 40px square
<Button size="icon-sm" /> // 28px square
<Button size="icon-xs" /> // 24px squareNavigation Button
An icon-only tertiary button for navigation actions. Transparent background, black icon color (text-on-prominent), grey hover (bg-secondary-hover). All sizes follow the 8-point grid.
<NavigationButton size="lg" aria-label="Home"><HomeIcon /></NavigationButton>| Size | Button | Icon |
|------|--------|------|
| lg | 48px | 24px |
| md | 40px | 20px |
| sm | 32px | 20px |
| xs | 24px | 16px |
States: hover (bg-secondary-hover), focus (3px ring-ring/50), active (opacity-60), disabled (opacity-24). Supports asChild for custom elements.
Badge variants
// Default (solid)
<Badge variant="default" /> // Blue (#2323FF)
<Badge variant="default-success" /> // Green
<Badge variant="default-fail" /> // Red
// Standard (neutral grey chip) — for non-status meta like contract type, duration
<Badge variant="standard" />
// Fill (tint background)
<Badge variant="fill" /> // Blue tint
<Badge variant="fill-success" /> // Green tint
<Badge variant="fill-fail" /> // Red tint
<Badge variant="fill-warning" /> // Orange tint
<Badge variant="fill-boost" /> // Amber-orange tint — boost/bonus labels (pair with a Rocket icon)
// Outline (black border, secondary-hover on hover)
<Badge variant="outline" />
// Ghost (transparent)
<Badge variant="ghost" />
<Badge variant="ghost-success" />
<Badge variant="ghost-fail" />
// Sizes
<Badge size="sm" /> // 24px height
<Badge size="md" /> // 32px height (default)
<Badge size="lg" /> // 40px heightAlert variants
<Alert variant="info" /> // blue — informational (default)
<Alert variant="error" /> // red — error stateComponent behaviour notes
AlertDialog — button fill
AlertDialogAction and AlertDialogCancel fill the full container width only when size="sm". On size="default" (the default), buttons are natural width and right-aligned.
<AlertDialogContent size="sm"> // buttons fill width (50/50 grid)
<AlertDialogContent size="default"> // buttons natural width, right-alignedDrawer — footer buttons
DrawerFooter makes all direct child buttons fill the full width automatically via [&>*]:w-full. Stack your buttons inside DrawerFooter and they will always be full-width.
Link — size lg
The lg variant of Link uses text-base (16px). The md and sm variants use text-sm (14px) and text-xs (12px) respectively.
<Link size="lg" /> // 16px — font-base
<Link size="md" /> // 14px — font-sm
<Link size="sm" /> // 12px — font-xsSelect — sizes
SelectTrigger accepts a size prop with three values matching the Input height scale:
<SelectTrigger size="sm" /> // h-8 (32px) — text-xs
<SelectTrigger size="md" /> // h-10 (40px) — text-sm (default)
<SelectTrigger size="lg" /> // h-12 (48px) — text-baseTabs — line variant hover
On the line variant, hover state shows text-primary (blue) with no background fill. On the default (pill) variant, hover shows a grey background with text-on-prominent.
Design tokens
All tokens are CSS custom properties, loaded automatically via @trading-game/design-intelligence-layer/styles.
Background tokens
| Tailwind class | CSS variable | Value | Usage |
|---|---|---|---|
| bg-prominent | --prominent | #FFFFFF | Page background |
| bg-prominent-inverse | --prominent-inverse | #000000 | Dark surface for use on light pages (e.g. toasts) |
| bg-card | --card | #FFFFFF | Card/panel surface |
| bg-popover | --popover | #FFFFFF | Popover/dropdown surface |
| bg-subtle | --subtle | #F5F5F5 | Subtle tinted surface |
| bg-overlay | --overlay | black 50% | Modal/dialog backdrop only |
| bg-tabs | --tabs | black 4% alpha | Tab container background (variant="default") |
| bg-tabs-active | --tabs-active | #FFFFFF | Active / selected tab pill |
| bg-primary | --primary | #2323FF | Brand blue — CTAs |
| bg-primary-hover | --primary-hover | #0B0BD2 | Primary button hover (darker blue) |
| bg-primary-inverse | --primary-inverse | #FFFFFF | Inverted primary surface — white bg for use on dark/coloured areas |
| bg-secondary-hover | --secondary-hover | #EEEEEE | Outline/secondary hover (light grey) |
| bg-semantic-win | --semantic-win | green | Profit / positive state |
| bg-semantic-loss | --semantic-loss | red | Loss / negative state |
| bg-semantic-boost | --semantic-boost | #F9840F amber-orange | Boost / bonus badge background |
Text tokens
Naming convention: every surface (bg) token has a paired
text-on-<surface>foreground (text/icon) token. Always use the pair together —bg-primary+text-on-primary,bg-semantic-win+text-on-semantic-win, etc. — for guaranteed legibility regardless of theme.
| Tailwind class | Value | Usage |
|---|---|---|
| text-on-prominent | #000000 | Text on bg-prominent (default body text on light surfaces) |
| text-on-prominent-inverse | #FFFFFF | Text on bg-prominent-inverse (e.g. toast title/description) |
| text-on-subtle | mid grey | Text on bg-subtle (secondary / supporting text) |
| text-on-disabled | #BBBBBB | Disabled / inactive text |
| text-on-primary | #FFFFFF | Text on bg-primary (e.g. primary button label, tooltip text) |
| text-on-primary-inverse | #2323FF | Text on bg-primary-inverse (e.g. primary-inverse button label) |
| text-on-semantic-win | #FFFFFF | Text on bg-semantic-win (e.g. success badge label) |
| text-on-semantic-loss | #FFFFFF | Text on bg-semantic-loss (e.g. fail badge label) |
| text-on-semantic-warning | #FFFFFF | Text on bg-semantic-warning (e.g. warning badge label) |
| text-on-semantic-boost | #713813 dark amber | Text on bg-semantic-boost (e.g. boost badge label) |
| text-primary | #2323FF | Brand blue inline text (use as a foreground over neutral surfaces) |
| text-semantic-win | green | Profit / positive inline text |
| text-semantic-loss | red | Loss / negative inline text |
Deprecated:
text-on-prominent-static-inverseand the matching--on-prominent-static-inverseCSS variable are still defined for backwards-compat with external code that references them via rawvar(). Internal components no longer use them. For new code, pick the explicittext-on-<surface>paired with the actual background.
Border & focus tokens
| Tailwind class | CSS variable | Value | Usage |
|---|---|---|---|
| border-border-subtle | --border-subtle | #EEEEEE | Default — cards, dividers, form borders |
| border-border-prominent | --border-prominent | #000000 | Outline variant components (button, badge, toggle) |
| border-border | --border | #EEEEEE | @deprecated alias — prefer border-border-subtle |
| border-input | --input | #EEEEEE | Input field borders |
| ring-ring | --ring | #2323FF | Focus rings |
⚠️
border-bordervsborder-border-subtle: Both resolve to the same light grey#EEEEEE.border-borderis kept for backward compatibility. Preferborder-border-subtlein all new code.
Transition tokens
Duration — primitive scale:
| Tailwind class | CSS variable | Value | Used for |
|---|---|---|---|
| duration-instant | --primitive-duration-instant | 50ms | Focus rings, hover tints |
| duration-fast | --primitive-duration-fast | 100ms | Buttons, inputs, badges |
| duration-base | --primitive-duration-base | 200ms | Dropdowns, popovers, accordions |
| duration-slow | --primitive-duration-slow | 300ms | Dialogs, sheets, drawers closing |
| duration-open | --primitive-duration-open | 500ms | Sheets, drawers entering |
Easing — primitive scale:
| Tailwind class | CSS variable | Value | Used for |
|---|---|---|---|
| ease-standard | --primitive-ease-standard | cubic-bezier(0.2, 0, 0, 1) | General UI — bidirectional state changes |
| ease-enter | --primitive-ease-enter | cubic-bezier(0, 0, 0.2, 1) | Overlays / surfaces entering |
| ease-exit | --primitive-ease-exit | cubic-bezier(0.4, 0, 1, 1) | Overlays / surfaces leaving |
| ease-linear | --primitive-ease-linear | linear | Sidebar width, progress bar |
Always use token utilities — never raw
duration-200orease-in-outdirectly.
Other tokens
| Tailwind class | Value | Usage |
|---|---|---|
| bg-slider-range | blue 40% | Slider filled range |
| rounded-lg | 0.625rem | Base border radius |
Using opacity with tokens
Opacity on tokens is allowed and encouraged:
✅ bg-primary/20 → blue at 20% opacity
✅ border-border-subtle/50 → light grey border at 50% opacity
✅ ring-ring/10 → ring at 10% opacity
❌ bg-black/50 → NOT a token, use bg-overlay instead
❌ bg-white → NOT a token, use bg-prominent or bg-cardPrimitive alpha scales
For structured alpha surfaces, the design system ships two internal alpha primitive scales. These are CSS variables only — not exposed as Tailwind utility classes. Always reference them via a semantic token, never directly in components.
--primitive-mono-alpha-4 through --primitive-mono-alpha-80 (black at N%)
--primitive-blue-alpha-4 through --primitive-blue-alpha-80 (brand blue at N%)
Stops: 4 · 8 · 16 · 24 · 32 · 40 · 50 · 64 · 80Example — how --tabs uses the alpha scale:
--tabs: var(--primitive-mono-alpha-4); /* black at 4% — tab container background */
--primitive-black-50is deprecated. It now aliases--primitive-mono-alpha-50. The--overlaysemantic token is unaffected.
Typography
The styles export includes pre-built typography classes using Plus Jakarta Sans.
Heading scale (Semibold 600 · tracking 1.5px · uppercase)
| Class | Size / Line height |
|---|---|
| heading-h1 | 72px / 72px |
| heading-h2 | 64px / 64px |
| heading-h3 | 48px / 48px |
| heading-h4 | 40px / 40px |
| heading-xs | 24px / 24px |
Body scale (Semibold 600)
| Class | Size / Line height |
|---|---|
| body-lg | 18px / 28px |
| body-md | 16px / 24px |
| body-sm | 12px / 16px |
| body-xs | 8px / 12px |
Font utilities
| Tailwind class | Font |
|---|---|
| font-display | Plus Jakarta Sans — headings, display text |
| font-body or font-sans | Plus Jakarta Sans — body text |
Upgrading the design system
When you bump @trading-game/design-intelligence-layer and run npm install (or npm ci):
| How you use the package | What happens |
|-------------------------|----------------|
| You import components only from @trading-game/design-intelligence-layer | After install and a rebuild, your app uses the new implementations in node_modules/.../dist — buttons, cards, etc. reflect the version you installed. |
| You copied components/ui/* (or similar) into your repo | Those files do not auto-update. You must delete them and switch to package imports, or manually merge changes from the new package. |
Overrides: Passing large className strings onto DS components can mask new defaults (e.g. old radius after a “pill button” update). After upgrading, review those callsites.
Cursor / AI agents: The package ships agent rules at node_modules/@trading-game/design-intelligence-layer/guides/rules/design-system-consuming-project.mdc. Cursor does not load rules from node_modules by default — re-copy that file into .cursor/rules/ after each upgrade so instructions match the release (same command as in AI Agent Setup below). The rules include Rule 7 — Package version upgrades: agents should search for duplicated components, align with the package, and tell you explicitly if local component code was replaced.
AI Agent Setup
All AI tools (Cursor, Windsurf, Claude Code, Copilot, and others)
The package ships an AGENTS.md file that most AI tools read automatically. After installing the package, copy it to your project root:
cp node_modules/@trading-game/design-intelligence-layer/AGENTS.md ./AGENTS.mdThis tells any AI agent to:
- Read the design principles before building any screen
- Follow the component and token rules
- Run the 7-point checklist before completing any view
Design principles file (bundled in the package):
node_modules/@trading-game/design-intelligence-layer/guides/design-principles/trading-game-design-principles.mdAccessibility standards file (bundled in the package):
node_modules/@trading-game/design-intelligence-layer/guides/accessibility-standards/trading-game-accessibility-standards.mdPersonas file (bundled in the package):
node_modules/@trading-game/design-intelligence-layer/guides/personas/trading-game-player-field-guide.mdBrand voice (bundled in the package):
node_modules/@trading-game/design-intelligence-layer/guides/brand-voice/trading-game-brand-voice.mdAll four files apply to all projects built with this package — landing pages, product screens, and games. Every AI agent must read all of them before starting any build. Run the design principles and accessibility checklists before completing any screen. Use the personas and brand voice to guide all player-facing copy.
Cursor
Copy the included rule file into your project:
mkdir -p .cursor/rules
cp node_modules/@trading-game/design-intelligence-layer/guides/rules/design-system-consuming-project.mdc .cursor/rules/Re-run this cp after every design-system version bump so your workspace rules stay in sync with the installed package.
Claude Code
Add the following to your project's CLAUDE.md:
## Design System
This project uses @trading-game/design-intelligence-layer. Before writing any UI:
1. Read node_modules/@trading-game/design-intelligence-layer/guides/design-principles/trading-game-design-principles.md — apply the 8 principles and run the 7-point checklist on every screen
2. Read node_modules/@trading-game/design-intelligence-layer/guides/accessibility-standards/trading-game-accessibility-standards.md — apply WCAG 2.1 AA standards and run the 9-point accessibility checklist on every screen
3. Read node_modules/@trading-game/design-intelligence-layer/guides/personas/trading-game-player-field-guide.md — understand the 3 player modes (Edge Seeker, System Runner, Public Predictor) that shape all copy and UX
4. Read node_modules/@trading-game/design-intelligence-layer/guides/brand-voice/trading-game-brand-voice.md — apply the brand voice: channel-specific voice, banned phrases, vocabulary, and formatting rules for all player-facing copy
5. Check if the component exists in the package — import it, don't re-implement
6. Use only design token classes (bg-prominent, text-on-prominent, border-border-subtle, etc.) — no hardcoded hex or raw Tailwind palette colors
7. Do not install lucide-react, tailwindcss, or other bundled dependencies separately
8. If no token exists for a value, ask before using a hardcoded value
9. After upgrading the package: prefer package imports over local copies of components; if replacing local UI code with the package version, tell the user what was overwritten; re-copy guides/rules/design-system-consuming-project.mdc into .cursor/rules if using Cursor
See node_modules/@trading-game/design-intelligence-layer/guides/rules/design-system-consuming-project.mdc for full rules.
See node_modules/@trading-game/design-intelligence-layer/README.md for complete token and component reference.Common mistakes
| Wrong | Right | Why |
|---|---|---|
| bg-gray-100 | bg-subtle | Raw Tailwind palette — use tokens |
| bg-white | bg-prominent or bg-card | Not a semantic token |
| text-white | text-on-<surface> (e.g. text-on-primary, text-on-prominent-inverse, text-on-semantic-win) | Pick the paired foreground for the actual background |
| text-black | text-on-prominent | Not a semantic token |
| text-gray-400 | text-on-disabled | Use the disabled text token |
| bg-black/50 | bg-overlay | Overlay has its own token |
| bg-[#2323FF] | bg-primary | Hardcoded hex — use token |
| border-border | border-border-subtle | Old name — prefer the new explicit name |
| bg-[var(--primary)] | bg-primary | Raw CSS var — Tailwind v4 maps tokens directly |
| hsl(var(--primary)) | bg-primary | Tailwind v3 syntax — not needed in v4 |
| Installing lucide-react | Already bundled | Icons are included in the package |
Do NOT install separately
These are bundled with the package. Installing them separately can cause version conflicts:
lucide-react— icon libraryradix-ui— headless primitivesclass-variance-authority— variant APIcmdk— command palettevaul— drawersonner— toastrecharts— chartsreact-day-picker— calendarembla-carousel-react— carouselreact-resizable-panels— resizable panels
Development (contributors only)
# Clone
git clone https://github.com/trading-game/TG-design-system.git
cd TG-design-system
# Install dependencies
npm install
# Start dev server (Next.js component playground)
npm run dev
# Build the library (ESM + CJS + types)
npm run build
# Build the Next.js showcase app
npm run build:nextUpdating design tokens
Design tokens are managed in Figma and exported as CSS variables. To update:
- Update the CSS custom properties in
app/globals.css(playground) andsrc/styles.css(published package) - Update
guides/rules/design-system-consuming-project.mdcto reflect any token renames - Update this README's token tables
Tech stack
- React 19 + TypeScript
- Tailwind CSS v4 — CSS-first configuration
- shadcn/ui (New York style) — base component primitives
- Radix UI — accessible headless primitives
- Figma — source of truth for design tokens
Changelog
v0.14.0
- New Result block: Fixed-width (320 px) end-of-round result card with 5 variants — Win/continuing, Loss/continuing, End of demo, Out of balance, On a roll. Thumb-up/down SVG with subtle radial halo + idle motion (float for win, head-shake for loss). Title (
You won!/You lost!), amount headline in semantic colour, contract + durationstandardBadge pills, and CTA(s). Digit contracts render the picked digit inside the contract pill with a thin vertical divider. Out-of-balance and on-a-roll variants are dialog-only (no thumb / no amount) — title + body + 2 CTAs. Lives under Blocks → Result in the playground. - Sheet Open Positions redesign: Each row now uses a 2-col layout — bet name + stake (left) / PnL + market·duration (right). Dropped per-row asset (
V100), round number, and digit/multiplier suffix labels (the game is already implied by the sheet/tab title). Abbreviated durations (sec / min / hr / day) and dropped theStakeprefix on amounts. Added an "Edge cases" row demonstrating drawer behavior with 1 item and 30 items. - Section nav sheet — desktop-safe: The mobile section picker
Sheetis now conditionally mounted ({isMobile && …}) so it can't be triggered at desktop widths where the permanent sidebar is already visible, avoiding redundant overlay layers. - Badge — new
standardvariant: Neutral grey chip (bg-subtle/text-on-prominent) for non-status meta like contract type and duration. Existingdefault(solid blue) and all other variants are unchanged. - TicketCard / BoostTicketCard:
- Left content restructured as a 2-column grid so the icon circle scales to match the label + value height (was a fixed
size-10centered against the entire column). - Boost badge now sits in row 2 of column 2 — aligned under the value, not pinned to the card's left edge.
- 2-decimal balance formatting: the
valueprop is now normalised byformatBalanceValuebefore render, so values always display with exactly two decimal places regardless of input (e.g.$12,450→$12,450.00,$12,450.5→$12,450.50,1234→1,234.00). Currency prefix/suffix is preserved.
- Left content restructured as a 2-column grid so the icon circle scales to match the label + value height (was a fixed
- Token convention —
on-<surface>foreground pairs: Added a Material-style paired foreground for every semantic surface so colour roles are self-documenting and resolve robustly across consumer setups (incl. Module Federation, where rawvar()fallbacks were previously needed). New CSS variables and Tailwind utilities:--on-primary(white) /text-on-primary— paired withbg-primary--primary-inverse(white) /bg-primary-inverse— inverted primary surface for use on dark/coloured areas--on-primary-inverse(blue) /text-on-primary-inverse— paired withbg-primary-inverse--prominent-inverse(black) /bg-prominent-inverse— dark surface for use on light pages (e.g. toasts)--on-prominent-inverse(white) /text-on-prominent-inverse— paired withbg-prominent-inverse--on-semantic-win/--on-semantic-loss/--on-semantic-warning(all white) and--on-semantic-boost(dark amber) — paired with the matchingbg-semantic-*surfaces.
- Internal sweep: all internal components (Button, Badge, Tooltip, Toast, Checkbox, Avatar, Input, NativeSelect, TicketCard, BoostTicketCard, sidebar mini-avatar) now use the explicit
on-<surface>foregrounds — no more catch-alltext-on-prominent-static-inverse. - Backwards-compat aliases preserved:
--on-prominent-static-inverse(→var(--on-prominent-inverse)) and--surface-inverse-static(→var(--primary-inverse)) remain defined in CSS so existing consumer code referencing them via rawvar()(e.g.var(--on-prominent-static-inverse, #fff)) keeps working. The Tailwind utilitytext-on-prominent-static-inverseis also still emitted, but new code should pick the explicit paired token. - Sonner → Toast rename: The toast wrapper file moved from
components/ui/sonner.tsxtocomponents/ui/toast.tsx. The wrapper component is stillToaster, andtoastis now re-exported from this module so consumers no longer needimport { toast } from "sonner"directly. Import path:@trading-game/design-intelligence-layer(was... from "sonner"). fill-credit→fill-boostBadge variant rename: The amber-orange badge variant for bonus labels is nowfill-boost(usesbg-semantic-boost/16+text-on-semantic-boost). The CSS tokens were correspondingly renamed:--semantic-credit→--semantic-boost,--semantic-credit-text→--on-semantic-boost. Breaking change for consumers that referenced these by name.CreditTicketCard→BoostTicketCardrename: Component, props (creditAmount→boostAmount,creditCurrency→boostCurrency), and badge text ("Credit: …"→"Boost: …") all renamed for consistency. The boost badge now uses a leadingRocketicon and a trailingInfoicon (replacing the priorTicketPlus). Breaking change.- Button
primary-inverse/secondary-inverse: Now built from the newbg-primary-inverse/text-on-primary-inverse/border-primary-inverse/text-on-prominent-inversetokens. Visually identical to before, but the underlying class names are different. - Toast — action button visual fix: The toast action button (the inverse-coloured "Undo" pill) now uses
primary-inversecolouring (white bg + blue text) to match the dark toast surface, instead of the previousbg-primary(blue on dark — low hierarchy / wrong surface-context).
v0.12.0
- New semantic tokens — credit: (superseded — see Unreleased above for the
boostrename)--semantic-credit(#F9840Famber-orange) and--semantic-credit-text(#713813dark amber) added to bothsrc/styles.cssandapp/globals.css. Tailwind utilities:bg-semantic-credit,text-semantic-credit-text. - Badge —
fill-creditvariant: (superseded — nowfill-boost) Variant for credit/bonus labels —bg-semantic-credit/16background withtext-semantic-credit-textforeground. Pair with aTicketPlusicon. Badge base class no longer appliestracking-wide; letter spacing is default on all badge variants. - New
CreditTicketCardcomponent: (superseded — nowBoostTicketCard) Exported alongsideTicketCard. Renders the same ticket shell (notches, tear-line, shimmer stub) but with a variable-height card body and an inline<Badge variant="fill-credit">below the value for credit/bonus display. Props:icon,label,value,currency,stubLabel,onStubClick,stubDisabled,creditAmount(default"0.00"),creditCurrency(default"USDT"),compact. TicketCard—compactprop: New boolean prop (defaultfalse). Whentrue, reduces left-content padding frompx-4 gap-4topx-2 gap-2for mobile layouts.TicketCard— welcome-credit props removed:welcomeCredit,freeCredit(deprecated alias),creditUsed,creditTotal,creditCurrency,creditLabel,creditFullWidth, and theProgress-based credit bar have been removed. UseCreditTicketCardfor the credit use case.tracking-wide/tracking-widestremoved from several components: Badge base class,Linkbase class,PaginationLink,CommandShortcut,ContextMenuShortcut,DropdownMenuShortcut, andMenubarShortcutno longer apply letter-spacing overrides. All render with default tracking.
v0.10.1
- TicketCard — Wallet icon: Default icon in the circular badge is now a
Walleticon (replacesCircleDollarSign). - TicketCard — sentence case labels: The label above the value (e.g. "Total balance") and the stub label (e.g. "Deposit") no longer apply
uppercaseortracking-widest. Both render in sentence case with default letter spacing. - Select — sm / md / lg sizes:
SelectTriggernow acceptssize="sm"(h-8, text-xs) |"md"(h-10, text-sm, default) |"lg"(h-12, text-base), matching theInputandInputGroupheight scale. The previous"default"size alias is replaced by"md".
v0.10.0
- Demo app — responsive mobile layout: The component playground is now fully mobile-friendly. Foundations / Components / Blocks navigation moves to a fixed bottom tab bar on mobile. A hamburger menu opens a slide-in Sheet to pick any component within the active tab. The desktop sidebar and inline tab switcher are unchanged.
- Sonner toast — mobile-aware behaviour: Toasts now appear at
top-centeron mobile (single visible toast) andbottom-righton desktop (up to 3). Added custom token-based styling (--on-prominentbackground, inverse text,font-displaytitle). - Toaster registered in root layout:
<Toaster />is now mounted inapp/layout.tsxso toast notifications work globally. - InputOTP docs: README and design-system guide updated with full variant listing — OTP 4 digits, OTP 6 digits, OTP 6 split, OTP 8 digits, OTP 6 separated.
