YotoShelf
Design

Integration

How to consume design tokens and shared components in any YotoShelf Astro + Svelte project.

Source yotoshelf.dev/packages Current as of

The design system (tokens, Svelte components, and brand assets) lives in this repository at packages/. The YotoShelf frontend consumes these via a git submodule at frontend/design, which pins a commit of this repo.

Consuming as a submodule

The YotoShelf frontend already has this configured. For a new project:

# Add the submodule pointing at this repo
git submodule add https://gitlab.com/yotoshelf/yotoshelf.dev.git design
git submodule update --init

This creates a design/ directory. Your project then imports from design/packages/.

Importing design tokens

Install the font package this repo bundles, so nothing is fetched from a CDN: npm install @fontsource-variable/nunito. IBM Plex Mono (code/mono) has no bundled fallback — it renders from whatever the visitor's system provides, or the --font-mono stack's next fallback.

In your project's global CSS file (e.g., src/styles/global.css):

/* Nunito Variable — bundled locally via @fontsource-variable/nunito (no CDN) */
@import '@fontsource-variable/nunito';

/* Import the Tailwind theme (which imports tokens.css internally) */
@import '../design/packages/tokens/tailwind-theme.css';

/* Import Tailwind */
@import 'tailwindcss';

The Tailwind theme file imports tokens.css automatically, giving you both CSS custom properties and Tailwind utility classes from a single import.

Using design tokens directly

All tokens are available as CSS custom properties:

.my-element {
  color: var(--color-foreground);
  font-family: var(--font-body);
  padding: var(--spacing-4);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  transition: all var(--transition-base);
}

Using Tailwind utilities

The theme maps tokens to Tailwind classes:

<div class="bg-background text-foreground p-4 rounded-lg shadow-md">
  <h2 class="font-display text-2xl font-semibold">Heading</h2>
  <p class="font-body text-sm text-muted-foreground">Body text</p>
</div>

Importing shared Svelte components

<script>
  import { Button, Card, Badge, Input, Dialog, Callout, Carousel }
    from '../design/packages/components/index.js';
</script>

<Button variant="primary">Save Card</Button>
<Button variant="secondary">Cancel</Button>

<!-- Compact only where 52px genuinely breaks a dense layout -->
<Button variant="primary" size="compact">Add</Button>

<Card>
  <h3>My Collection</h3>
  <p>12 cards</p>
  <p class="card-meta">12 tracks · 48:20 · updated 3d ago</p>
</Card>

<!-- Status badges — pill shaped -->
<Badge variant="default">New</Badge>
<Badge variant="success">Ready</Badge>
<Badge variant="warning">Draft</Badge>

<!-- Callout variants -->
<Callout variant="note" title="Tip">
  Tap a card to preview before syncing.
</Callout>
<Callout variant="warning">
  Refresh tokens are single-use.
</Callout>
<Callout variant="quirk">
  Yoto cards are identified by NFC UID — duplicates share a slot.
</Callout>

Using the accent correctly

The accent ships as two tokens and they are not interchangeable. --color-primary #E8654A is for shapes: button fills, borders, focus rings. --color-primary-deep #B84A33 is for text: inline links, active labels, anything a reader parses as a sentence. Setting inline text in the raw accent on a light background computes 3.13:1 and fails AA. The full contrast table is on the colors page.

Button sizes

The default button is 52px tall with 30px horizontal padding, a pill radius, and a 16px/22px label at weight 600. There is one alternative, size="compact" at 38px, for dense application chrome — toolbars, table rows — where 52px genuinely breaks the layout. Reach for it when the layout forces you to, not to add variety; a third size is a drift, not a feature.

Card meta lines

Durations, hashes, counts, and timestamps inside a card use the .card-meta class from global.css: IBM Plex Mono at 11px in --card-meta-color. This is the only place a card uses the mono face.

Component props reference

ComponentKey Props
Button variant (primary/secondary/destructive/ghost/outline), size (default/compact), disabled, href
Card href (makes clickable), padding (boolean)
Badge variant (default/success/warning/destructive/outline), pill shape
Input label, placeholder, value (bindable), type, disabled, error
Dialog open (bindable), title, slots: default + footer
Callout variant (note/warning/quirk), title (optional); left rule, tinted background
Carousel slides ({ src, alt, caption? }[]); picture-book plate layout, omit for placeholder state

Updating the submodule pointer

# Pull latest from this repo's main branch
git submodule update --remote design

# Commit the pointer update
git add design
git commit -m "update: design system to latest"

Themes

The system is light-only today. There is no dark palette in packages/tokens/tokens.css and no data-theme hook — adding one means defining a full second set of colour tokens and re-deriving every contrast ratio, so it is a deliberate piece of work rather than a flag to flip.

Project structure

your-project/
├── design/                  ← git submodule → yotoshelf.dev
│   ├── packages/
│   │   ├── tokens/
│   │   │   ├── tokens.css          ← CSS custom properties
│   │   │   └── tailwind-theme.css  ← Tailwind v4 @theme
│   │   └── components/
│   │       ├── Button.svelte
│   │       ├── Card.svelte
│   │       ├── Badge.svelte
│   │       ├── Input.svelte
│   │       ├── Dialog.svelte
│   │       ├── Callout.svelte
│   │       ├── Carousel.svelte
│   │       └── index.js            ← barrel export
│   └── public/
│       └── logo/                   ← hero.svg, mark.svg
├── src/
│   └── styles/
│       └── global.css              ← imports from design/packages/
└── ...