Skip to content

Repository files navigation

Northbound

A concept investing app for people in Latin America who want to invest in US stocks and ETFs. Built as a public case study: a token-driven, AI-ready design system taken from Figma primitives to a deployed product.

Concept project. No real money flows, all data is sample data, and nothing here is financial advice. Designed and built independently by Maty Sandoval alongside Memorisely's AI Design Systems and AI Coding bootcamps.

View the live Storybook →

The idea

AI design and code tools are only as good as the system they consume. This repo is the proof of that pipeline: one token source feeding both Figma and production code, with components generated and scaled using Claude Code via Figma MCP.

Token architecture

styles/tokens/
  primitives.css     Raw scales: color, type, space, radius. No theme logic.
  semantics.css      Role-based tokens (background, text, border, icon). Light values in :root, dark values under .dark.

Tokens are authored in Token Studio and exported as CSS. The CSS files are versioned in this repo as the single source of truth — semantics.css references primitives as var() chains, so the full design decision is inspectable end to end.

The naming grammar

The naming is the actual system, not the colors. Every semantic token follows one predictable pattern:

--color-{category}-{purpose}-{emphasis}-{state}
  • category (4): background, text, border, icon
  • purpose (6): neutral, brand, info, danger, warning, success
  • emphasis (3): subtlest, subtle, bold
  • state (4): default, hovered, pressed, disabled

This is what scales the system from 3 screens to a full product without renaming anything.

Traceability

Tokens keep their semantic-to-primitive references intact, so the chain is inspectable end to end. Open styles/tokens/semantics.css and you see var(--color-gold-500), not a baked hex value. The reference chain is the architecture — a var() chain from semantic intent all the way down to a primitive hex.

Accessibility

WCAG pairings are designed into the token decisions, not checked afterward. The brand anchor, gold.500 on gray.900, lands at 13:1 contrast (AAA).

Storybook's addon-a11y runs as a hard gate (test: 'error') against every story via npx vitest run. See the Accessibility doc page for the full WCAG AA pass — what was fixed, what's recorded as a known gap, and why.

Components

Components are organized into four layers. Each layer can only depend on layers below it.

Foundation

Atomic, single-responsibility primitives. No dependencies on other design system components.

  • Icon — Central barrel export for Heroicons and Lucide icons
  • Avatar — User avatar — initials or image variant, two sizes
  • Button — Primary interaction component — primary, secondary, destructive variants
  • Input — Form input — lg/md/sm sizes, prefix/suffix slots, error state
  • Divider — Horizontal or vertical separator
  • Chip — Filter/selection chip with selected and disabled states
  • Badge — Status/change indicator — pairs an icon with a numeric value and caption
  • Icon Tile — Semantic container wrapping an arbitrary icon — neutral, brand, info, warning, success, negative variants
  • Sparkline — Financial chart visualization — brand, positive, and negative variants with left/right direction

Composite

Assembled from one or more Foundation components.

  • Chip Group — Single-select group of Chip components with controlled/uncontrolled selection
  • Amount Cluster — Input with label and helper-text slot, three sizes
  • Data Row — Icon Tile + label + value with neutral, positive, and negative appearances
  • Asset Header — Avatar + title/label identity block, md and sm sizes
  • Section Header — Title row with four right-slot variants: text, button, badge, none
  • Card — Rounded surface pairing a Section Header with a flexible children slot
  • Holding Row — Asset Header + Sparkline + value/change Badge; the core row of the portfolio holdings list

Feature

Domain-specific components assembled from Composite components. Tied to the investing product screens.

  • Movement Breakdown — Card listing the full breakdown of a money movement: amount sent, exchange rate, fee, amount received, and expected arrival
  • Price Chart — Card with a Sparkline, selectable time-period ChipGroup, and a performance Badge in the header
  • Position Summary — Card showing a single position: market value, share count, today's return, total return, and average cost
  • Personal Holdings — Card listing portfolio holdings as a scrollable HoldingRow list with optional section header
  • Portfolio Balance — Standalone widget (no card) combining an AmountCluster with a performance Badge; four variants: size (md/sm) × direction (positive/negative)

Layout

Full-screen shells and section-level layout components assembled from Feature components. One component per major screen region.

  • AppBar — Top navigation bar with a leading back button, centered or left-aligned title area (plain text or AssetHeader), and a trailing action button
  • BalanceSection — Portfolio balance widget: PortfolioBalance (AmountCluster + Badge) stacked above a primary CTA button
  • HoldingsSection — Section header row (title + count) above a PersonalHoldings card
  • ScreenScaffold — Full-screen shell (430 × 932) with AppBar pinned at the top and a content area below; provides background, padding, and overflow clipping

Screens

Full products assembled from the Layout layer, each backed by a Figma frame referenced in a code comment for traceability.

  • Portfolio Dashboard — Balance, 30-day price chart, and scrollable holdings list
  • Asset Detail — Per-share price, price chart, two position summaries, and a place-order action
  • Deposit & FX Conversion — Amount entry with MXN→USD conversion badge, preset chips, and a full movement breakdown

Status

  • Primitive tokens
  • Semantic layer, light and dark
  • Tokens wired to code (CSS variables mapped to Tailwind v4 via @theme {})
  • Foundation components — Icon, Avatar, Button, Input, Divider, Chip, Badge, Icon Tile, Sparkline
  • Composite components — Chip Group, Amount Cluster, Data Row, Asset Header, Section Header, Card, Holding Row
  • Feature components — Movement Breakdown, Price Chart, Position Summary, Personal Holdings, Portfolio Balance
  • Layout components — AppBar, BalanceSection, HoldingsSection, ScreenScaffold
  • Storybook wired up with stories for all components, plus a dedicated Design Tokens doc page
  • 3 screens: Portfolio Dashboard, Asset Detail, Deposit & FX Conversion
  • CI: Storybook auto-published to Chromatic on every push to main

Getting started

Requires Node 20+.

npm install
npm run dev             # app — localhost:5173
npm run storybook       # component library — localhost:6006

Other scripts: npm run build, npm run build-storybook, npm run lint.

Or skip local setup entirely and browse the live Storybook.

Stack

Figma · Token Studio · Claude Code · Cursor · React 19 · Vite · Tailwind CSS v4 · shadcn/ui · Storybook · Chromatic · Vitest · Playwright

Author

Maty Sandoval, Product Designer matysandoval.com · Contra

About

App that allows non US investors invest in US markets starting from LATAM

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages