Skip to main content

Design System

HyperStudy uses a design system based on CSS custom properties (design tokens) and reusable Svelte components. This ensures visual consistency across the application.

Design Tokens

Design tokens are CSS custom properties that define our visual language. They're located in frontend/src/lib/styles/design-tokens.css.

Token Categories

Colors

/* Primary colors */
--color-primary: #2196f3;
--color-primary-dark: #1976d2;
--color-primary-light: #64b5f6;

/* Status colors */
--color-success: #4caf50;
--color-warning: #ff9800;
--color-error: #f44336;

/* Neutral colors */
--color-background: #121212;
--color-surface: #1e1e1e;
--color-text: #ffffff;
--color-text-secondary: #b0b0b0;

Spacing

--spacing-xs: 4px;
--spacing-sm: 8px;
--spacing-md: 16px;
--spacing-lg: 24px;
--spacing-xl: 32px;
--spacing-xxl: 48px;

Typography

--font-family: 'Inter', system-ui, sans-serif;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
--font-size-xl: 1.25rem;
--font-size-2xl: 1.5rem;
--font-weight-normal: 400;
--font-weight-medium: 500;
--font-weight-bold: 700;

Borders & Radius

--border-radius-sm: 4px;
--border-radius-md: 8px;
--border-radius-lg: 12px;
--border-radius-full: 9999px;
--border-width: 1px;
--border-color: #333333;

Shadows

--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.3);
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.3);

Using Tokens

Always use tokens instead of hardcoded values:

/* Good */
.button {
background-color: var(--color-primary);
padding: var(--spacing-sm) var(--spacing-md);
border-radius: var(--border-radius-md);
}

/* Avoid */
.button {
background-color: #2196f3;
padding: 8px 16px;
border-radius: 8px;
}

Z-Index Management

Z-index values are defined in frontend/src/lib/styles/z-index.css:

--z-dropdown: 100;
--z-sticky: 200;
--z-modal-backdrop: 300;
--z-modal: 400;
--z-popover: 500;
--z-tooltip: 600;
--z-toast: 700;

Use these to ensure consistent layering:

.modal {
z-index: var(--z-modal);
}

.tooltip {
z-index: var(--z-tooltip);
}

Shared Components

Reusable UI components are in frontend/src/components/shared/.

Button

<script>
import Button from '$lib/components/shared/Button.svelte';
</script>

<Button variant="primary" onclick={handleClick}>
Click Me
</Button>

<Button variant="secondary" disabled>
Disabled
</Button>

<Button variant="danger" size="small">
Delete
</Button>

Props:

  • variant: primary | secondary | danger | ghost
  • size: small | medium | large
  • disabled: boolean
  • type: button | submit | reset
<script>
import Modal from '$lib/components/shared/Modal.svelte';
let showModal = $state(false);
</script>

<Modal
bind:open={showModal}
title="Confirm Action"
onclose={() => showModal = false}
>
<p>Are you sure you want to proceed?</p>

<svelte:fragment slot="footer">
<Button variant="secondary" onclick={() => showModal = false}>
Cancel
</Button>
<Button variant="primary" onclick={handleConfirm}>
Confirm
</Button>
</svelte:fragment>
</Modal>

Input

<script>
import Input from '$lib/components/shared/Input.svelte';
let value = $state('');
</script>

<Input
bind:value
label="Email"
type="email"
placeholder="Enter your email"
error={!isValid ? 'Invalid email' : ''}
/>

Props:

  • value: string
  • label: string
  • type: text | email | password | number
  • placeholder: string
  • error: string (displays error message)
  • disabled: boolean

SimpleTable

<script>
import SimpleTable from '$lib/components/shared/SimpleTable.svelte';

const columns = [
{ key: 'name', label: 'Name' },
{ key: 'email', label: 'Email' },
{ key: 'role', label: 'Role' }
];

const data = [
{ name: 'Alice', email: 'alice@example.com', role: 'Admin' },
{ name: 'Bob', email: 'bob@example.com', role: 'Member' }
];
</script>

<SimpleTable {columns} {data} />

Icon

<script>
import Icon from '$lib/components/shared/Icon.svelte';
</script>

<Icon name="check" size={24} color="var(--color-success)" />
<Icon name="warning" size={16} />
<Icon name="close" />

Available Icons:

  • Navigation: arrow-left, arrow-right, chevron-down, chevron-up
  • Actions: check, close, edit, delete, add, search
  • Status: warning, error, info, success
  • UI: menu, settings, user, help

Creating New Components

Component Template

<script>
/**
* ComponentName - Brief description
* @component
*/

/** @type {string} */
export let variant = 'default';

/** @type {boolean} */
export let disabled = false;
</script>

<div
class="component"
class:component--disabled={disabled}
class:component--{variant}
>
<slot />
</div>

<style>
.component {
/* Use design tokens */
padding: var(--spacing-md);
background: var(--color-surface);
border-radius: var(--border-radius-md);
}

.component--disabled {
opacity: 0.5;
pointer-events: none;
}

.component--primary {
background: var(--color-primary);
}
</style>

Guidelines

  1. Use design tokens - Never hardcode colors, spacing, or typography
  2. Support variants - Provide props for common variations
  3. Accessibility - Include ARIA attributes and keyboard support
  4. Documentation - Add JSDoc comments for props
  5. Slots - Use slots for flexible content
  6. BEM naming - Use Block__Element--Modifier pattern for classes

Storybook Integration

Design tokens are automatically documented in Storybook:

  1. Design Tokens addon displays all tokens in a panel
  2. Stories showcase component variants
  3. Controls let users experiment with props

See Storybook documentation for details.

Migration Guide

When updating existing components to use the design system:

Before

<style>
.card {
background: #1e1e1e;
padding: 16px;
border-radius: 8px;
color: white;
}
</style>

After

<style>
.card {
background: var(--color-surface);
padding: var(--spacing-md);
border-radius: var(--border-radius-md);
color: var(--color-text);
}
</style>

Best Practices

  1. Consistent spacing - Use spacing tokens for all margins and padding
  2. Color semantics - Use semantic color names (success, error) not literal (green, red)
  3. Responsive tokens - Consider breakpoint-specific token values
  4. Dark mode ready - Tokens make theme switching straightforward
  5. Component composition - Build complex UIs from simple shared components