mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 08:31:08 -05:00
Update activeContext.md and productContext.md with new project information and context
This commit is contained in:
995
memory-bank/design-system/component-library.md
Normal file
995
memory-bank/design-system/component-library.md
Normal file
@@ -0,0 +1,995 @@
|
||||
|
||||
# ThrillWiki Design System - Component Library
|
||||
|
||||
## Overview
|
||||
Comprehensive component library for ThrillWiki's frontend redesign, providing reusable UI patterns that implement the design token system consistently across all templates.
|
||||
|
||||
## Component Categories
|
||||
|
||||
### 1. Layout Components
|
||||
|
||||
#### Container
|
||||
```html
|
||||
<!-- Base container with responsive padding -->
|
||||
<div class="container">
|
||||
<!-- Content -->
|
||||
</div>
|
||||
|
||||
<!-- Fluid container (full width) -->
|
||||
<div class="container-fluid">
|
||||
<!-- Content -->
|
||||
</div>
|
||||
|
||||
<!-- Constrained container (max-width) -->
|
||||
<div class="container-constrained">
|
||||
<!-- Content -->
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.container {
|
||||
width: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-left: var(--spacing-container-sm);
|
||||
padding-right: var(--spacing-container-sm);
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.container {
|
||||
padding-left: var(--spacing-container-md);
|
||||
padding-right: var(--spacing-container-md);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.container {
|
||||
padding-left: var(--spacing-container-lg);
|
||||
padding-right: var(--spacing-container-lg);
|
||||
}
|
||||
}
|
||||
|
||||
.container-constrained {
|
||||
max-width: 1280px;
|
||||
}
|
||||
|
||||
.container-fluid {
|
||||
width: 100%;
|
||||
padding-left: var(--spacing-container-xs);
|
||||
padding-right: var(--spacing-container-xs);
|
||||
}
|
||||
```
|
||||
|
||||
#### Grid System
|
||||
```html
|
||||
<!-- Responsive grid -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div class="grid-item">Item 1</div>
|
||||
<div class="grid-item">Item 2</div>
|
||||
<div class="grid-item">Item 3</div>
|
||||
</div>
|
||||
|
||||
<!-- Auto-fit grid -->
|
||||
<div class="grid-auto-fit">
|
||||
<div class="grid-item">Item 1</div>
|
||||
<div class="grid-item">Item 2</div>
|
||||
<div class="grid-item">Item 3</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.grid-auto-fit {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: var(--spacing-layout-md);
|
||||
}
|
||||
|
||||
.grid-item {
|
||||
min-width: 0; /* Prevent grid blowout */
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Navigation Components
|
||||
|
||||
#### Primary Navigation
|
||||
```html
|
||||
<nav class="nav-primary" x-data="{ mobileOpen: false }">
|
||||
<div class="nav-container">
|
||||
<!-- Logo -->
|
||||
<div class="nav-brand">
|
||||
<a href="/" class="nav-logo">
|
||||
<img src="/static/images/logo.svg" alt="ThrillWiki" class="nav-logo-img">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Desktop Navigation -->
|
||||
<div class="nav-links hidden lg:flex">
|
||||
<a href="/parks/" class="nav-link">Parks</a>
|
||||
<a href="/rides/" class="nav-link">Rides</a>
|
||||
<a href="/search/" class="nav-link">Search</a>
|
||||
</div>
|
||||
|
||||
<!-- User Actions -->
|
||||
<div class="nav-actions">
|
||||
<!-- Theme Toggle -->
|
||||
<button class="btn-icon" x-data="themeToggle()" @click="toggle()">
|
||||
<svg x-show="!isDark" class="icon-sm" fill="currentColor" viewBox="0 0 20 20">
|
||||
<!-- Sun icon -->
|
||||
</svg>
|
||||
<svg x-show="isDark" class="icon-sm" fill="currentColor" viewBox="0 0 20 20">
|
||||
<!-- Moon icon -->
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!-- User Menu -->
|
||||
<div class="dropdown" x-data="{ open: false }">
|
||||
<button @click="open = !open" class="btn-icon">
|
||||
<img src="{{ user.avatar.url }}" alt="{{ user.username }}" class="avatar-sm">
|
||||
</button>
|
||||
<div x-show="open" @click.away="open = false" class="dropdown-menu">
|
||||
<a href="/profile/" class="dropdown-item">Profile</a>
|
||||
<a href="/settings/" class="dropdown-item">Settings</a>
|
||||
<hr class="dropdown-divider">
|
||||
<a href="/logout/" class="dropdown-item">Logout</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mobile Menu Toggle -->
|
||||
<button @click="mobileOpen = !mobileOpen" class="btn-icon lg:hidden">
|
||||
<svg class="icon-sm" fill="currentColor" viewBox="0 0 20 20">
|
||||
<!-- Hamburger icon -->
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mobile Navigation -->
|
||||
<div x-show="mobileOpen" x-transition class="nav-mobile lg:hidden">
|
||||
<div class="nav-mobile-links">
|
||||
<a href="/parks/" class="nav-mobile-link">Parks</a>
|
||||
<a href="/rides/" class="nav-mobile-link">Rides</a>
|
||||
<a href="/search/" class="nav-mobile-link">Search</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
```
|
||||
|
||||
```css
|
||||
.nav-primary {
|
||||
background: var(--bg-elevated);
|
||||
border-bottom: 1px solid var(--border-primary);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: var(--z-sticky);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
.nav-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: var(--spacing-component-md) var(--spacing-container-md);
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.nav-brand {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.nav-logo-img {
|
||||
height: 2rem;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-component-lg);
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
color: var(--text-secondary);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
padding: var(--spacing-component-sm) var(--spacing-component-md);
|
||||
border-radius: var(--radius-md);
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.nav-link:hover {
|
||||
color: var(--text-primary);
|
||||
background: var(--interactive-secondary);
|
||||
}
|
||||
|
||||
.nav-link.active {
|
||||
color: var(--text-brand);
|
||||
background: var(--color-primary-50);
|
||||
}
|
||||
|
||||
.dark .nav-link.active {
|
||||
background: var(--color-primary-900);
|
||||
}
|
||||
|
||||
.nav-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-component-sm);
|
||||
}
|
||||
|
||||
.nav-mobile {
|
||||
border-top: 1px solid var(--border-primary);
|
||||
background: var(--bg-elevated);
|
||||
}
|
||||
|
||||
.nav-mobile-links {
|
||||
padding: var(--spacing-component-md);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-component-xs);
|
||||
}
|
||||
|
||||
.nav-mobile-link {
|
||||
color: var(--text-secondary);
|
||||
text-decoration: none;
|
||||
padding: var(--spacing-component-md);
|
||||
border-radius: var(--radius-md);
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.nav-mobile-link:hover {
|
||||
color: var(--text-primary);
|
||||
background: var(--interactive-secondary);
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Button Components
|
||||
|
||||
#### Button Variants
|
||||
```html
|
||||
<!-- Primary Button -->
|
||||
<button class="btn btn-primary">Primary Action</button>
|
||||
|
||||
<!-- Secondary Button -->
|
||||
<button class="btn btn-secondary">Secondary Action</button>
|
||||
|
||||
<!-- Outline Button -->
|
||||
<button class="btn btn-outline">Outline Button</button>
|
||||
|
||||
<!-- Ghost Button -->
|
||||
<button class="btn btn-ghost">Ghost Button</button>
|
||||
|
||||
<!-- Icon Button -->
|
||||
<button class="btn-icon">
|
||||
<svg class="icon-sm" fill="currentColor" viewBox="0 0 20 20">
|
||||
<!-- Icon -->
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!-- Button with Icon -->
|
||||
<button class="btn btn-primary">
|
||||
<svg class="icon-sm" fill="currentColor" viewBox="0 0 20 20">
|
||||
<!-- Icon -->
|
||||
</svg>
|
||||
Button Text
|
||||
</button>
|
||||
|
||||
<!-- Loading Button -->
|
||||
<button class="btn btn-primary" :disabled="loading">
|
||||
<svg x-show="loading" class="icon-sm animate-spin" fill="currentColor" viewBox="0 0 20 20">
|
||||
<!-- Spinner icon -->
|
||||
</svg>
|
||||
<span x-show="!loading">Submit</span>
|
||||
<span x-show="loading">Loading...</span>
|
||||
</button>
|
||||
```
|
||||
|
||||
```css
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--spacing-component-xs);
|
||||
padding: var(--spacing-component-sm) var(--spacing-component-md);
|
||||
border: 1px solid transparent;
|
||||
border-radius: var(--radius-button);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 500;
|
||||
line-height: 1.5;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-fast);
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.btn:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--interactive-primary);
|
||||
color: var(--text-inverse);
|
||||
box-shadow: var(--shadow-button);
|
||||
}
|
||||
|
||||
.btn-primary:hover:not(:disabled) {
|
||||
background: var(--interactive-primary-hover);
|
||||
box-shadow: var(--shadow-button-hover);
|
||||
}
|
||||
|
||||
.btn-primary:active {
|
||||
background: var(--interactive-primary-active);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: var(--interactive-secondary);
|
||||
color: var(--text-primary);
|
||||
border-color: var(--border-primary);
|
||||
}
|
||||
|
||||
.btn-secondary:hover:not(:disabled) {
|
||||
background: var(--interactive-secondary-hover);
|
||||
border-color: var(--border-secondary);
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
background: transparent;
|
||||
color: var(--interactive-primary);
|
||||
border-color: var(--interactive-primary);
|
||||
}
|
||||
|
||||
.btn-outline:hover:not(:disabled) {
|
||||
background: var(--interactive-primary);
|
||||
color: var(--text-inverse);
|
||||
}
|
||||
|
||||
.btn-ghost {
|
||||
background: transparent;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.btn-ghost:hover:not(:disabled) {
|
||||
background: var(--interactive-secondary);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
padding: 0;
|
||||
border: none;
|
||||
border-radius: var(--radius-button);
|
||||
background: transparent;
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.btn-icon:hover {
|
||||
background: var(--interactive-secondary);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* Button Sizes */
|
||||
.btn-sm {
|
||||
padding: var(--spacing-component-xs) var(--spacing-component-sm);
|
||||
font-size: var(--text-xs);
|
||||
}
|
||||
|
||||
.btn-lg {
|
||||
padding: var(--spacing-component-md) var(--spacing-component-lg);
|
||||
font-size: var(--text-base);
|
||||
}
|
||||
|
||||
.btn-xl {
|
||||
padding: var(--spacing-component-lg) var(--spacing-component-xl);
|
||||
font-size: var(--text-lg);
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Form Components
|
||||
|
||||
#### Input Fields
|
||||
```html
|
||||
<!-- Text Input -->
|
||||
<div class="form-group">
|
||||
<label for="park-name" class="form-label">Park Name</label>
|
||||
<input type="text" id="park-name" name="name" class="form-input" placeholder="Enter park name">
|
||||
<div class="form-error" x-show="errors.name" x-text="errors.name"></div>
|
||||
</div>
|
||||
|
||||
<!-- Textarea -->
|
||||
<div class="form-group">
|
||||
<label for="description" class="form-label">Description</label>
|
||||
<textarea id="description" name="description" class="form-textarea" rows="4" placeholder="Enter description"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Select -->
|
||||
<div class="form-group">
|
||||
<label for="status" class="form-label">Status</label>
|
||||
<select id="status" name="status" class="form-select">
|
||||
<option value="">Select status</option>
|
||||
<option value="operating">Operating</option>
|
||||
<option value="closed">Closed</option>
|
||||
<option value="seasonal">Seasonal</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Checkbox -->
|
||||
<div class="form-group">
|
||||
<label class="form-checkbox">
|
||||
<input type="checkbox" name="featured" class="form-checkbox-input">
|
||||
<span class="form-checkbox-label">Featured Park</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Radio Group -->
|
||||
<div class="form-group">
|
||||
<fieldset class="form-fieldset">
|
||||
<legend class="form-legend">Park Type</legend>
|
||||
<div class="form-radio-group">
|
||||
<label class="form-radio">
|
||||
<input type="radio" name="park_type" value="theme" class="form-radio-input">
|
||||
<span class="form-radio-label">Theme Park</span>
|
||||
</label>
|
||||
<label class="form-radio">
|
||||
<input type="radio" name="park_type" value="water" class="form-radio-input">
|
||||
<span class="form-radio-label">Water Park</span>
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.form-group {
|
||||
margin-bottom: var(--spacing-component-lg);
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: block;
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-component-xs);
|
||||
}
|
||||
|
||||
.form-input,
|
||||
.form-textarea,
|
||||
.form-select {
|
||||
width: 100%;
|
||||
padding: var(--spacing-component-sm) var(--spacing-component-md);
|
||||
border: 1px solid var(--border-primary);
|
||||
border-radius: var(--radius-input);
|
||||
background: var(--bg-elevated);
|
||||
color: var(--text-primary);
|
||||
font-size: var(--text-sm);
|
||||
line-height: 1.5;
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.form-input:focus,
|
||||
.form-textarea:focus,
|
||||
.form-select:focus {
|
||||
outline: none;
|
||||
border-color: var(--border-focus);
|
||||
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
.form-input.error,
|
||||
.form-textarea.error,
|
||||
.form-select.error {
|
||||
border-color: var(--border-error);
|
||||
}
|
||||
|
||||
.form-error {
|
||||
margin-top: var(--spacing-component-xs);
|
||||
font-size: var(--text-xs);
|
||||
color: var(--color-error-600);
|
||||
}
|
||||
|
||||
.form-textarea {
|
||||
resize: vertical;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.form-checkbox,
|
||||
.form-radio {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: var(--spacing-component-sm);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.form-checkbox-input,
|
||||
.form-radio-input {
|
||||
margin: 0;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.form-checkbox-label,
|
||||
.form-radio-label {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-primary);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.form-fieldset {
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.form-legend {
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-component-sm);
|
||||
}
|
||||
|
||||
.form-radio-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-component-sm);
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.form-radio-group {
|
||||
flex-direction: row;
|
||||
gap: var(--spacing-component-lg);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Card Components
|
||||
|
||||
#### Basic Card
|
||||
```html
|
||||
<!-- Basic Card -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Card Title</h3>
|
||||
<p class="card-subtitle">Card subtitle</p>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>Card content goes here.</p>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button class="btn btn-primary">Action</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Park Card -->
|
||||
<div class="card card-hover">
|
||||
<div class="card-image">
|
||||
<img src="{{ park.image.url }}" alt="{{ park.name }}" class="card-image-img">
|
||||
<div class="card-image-overlay">
|
||||
<span class="badge badge-{{ park.status }}">{{ park.get_status_display }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">
|
||||
<a href="{{ park.get_absolute_url }}" class="card-title-link">{{ park.name }}</a>
|
||||
</h3>
|
||||
<p class="card-text">{{ park.description|truncatewords:20 }}</p>
|
||||
<div class="card-meta">
|
||||
<span class="card-meta-item">
|
||||
<svg class="icon-xs" fill="currentColor" viewBox="0 0 20 20">
|
||||
<!-- Location icon -->
|
||||
</svg>
|
||||
{{ park.location }}
|
||||
</span>
|
||||
<span class="card-meta-item">
|
||||
<svg class="icon-xs" fill="currentColor" viewBox="0 0 20 20">
|
||||
<!-- Rides icon -->
|
||||
</svg>
|
||||
{{ park.rides.count }} rides
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.card {
|
||||
background: var(--bg-elevated);
|
||||
border: 1px solid var(--border-primary);
|
||||
border-radius: var(--radius-card);
|
||||
box-shadow: var(--shadow-card);
|
||||
overflow: hidden;
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.card-hover:hover {
|
||||
box-shadow: var(--shadow-card-hover);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
padding: var(--spacing-component-lg);
|
||||
border-bottom: 1px solid var(--border-primary);
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: var(--text-lg);
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin: 0 0 var(--spacing-component-xs) 0;
|
||||
}
|
||||
|
||||
.card-subtitle {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-secondary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.card-title-link {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
transition: color var(--transition-fast);
|
||||
}
|
||||
|
||||
.card-title-link:hover {
|
||||
color: var(--text-brand);
|
||||
}
|
||||
|
||||
.card-body {
|
||||
padding: var(--spacing-component-lg);
|
||||
}
|
||||
|
||||
.card-text {
|
||||
color: var(--text-secondary);
|
||||
line-height: var(--leading-relaxed);
|
||||
margin: 0 0 var(--spacing-component-md) 0;
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
padding: var(--spacing-component-lg);
|
||||
border-top: 1px solid var(--border-primary);
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
|
||||
.card-image {
|
||||
position: relative;
|
||||
aspect-ratio: 16 / 9;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-image-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform var(--transition-slow);
|
||||
}
|
||||
|
||||
.card-hover:hover .card-image-img {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.card-image-overlay {
|
||||
position: absolute;
|
||||
top: var(--spacing-component-sm);
|
||||
right: var(--spacing-component-sm);
|
||||
}
|
||||
|
||||
.card-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--spacing-component-md);
|
||||
margin-top: var(--spacing-component-md);
|
||||
}
|
||||
|
||||
.card-meta-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-component-xs);
|
||||
font-size: var(--text-xs);
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Modal Components
|
||||
|
||||
#### Modal Structure
|
||||
```html
|
||||
<!-- Modal Trigger -->
|
||||
<button class="btn btn-primary" @click="$dispatch('modal-open', { id: 'park-modal' })">
|
||||
Open Modal
|
||||
</button>
|
||||
|
||||
<!-- Modal -->
|
||||
<div x-data="modal()"
|
||||
x-show="isOpen"
|
||||
x-on:modal-open.window="handleOpen($event.detail)"
|
||||
x-on:modal-close.window="handleClose($event.detail)"
|
||||
class="modal-overlay"
|
||||
x-transition:enter="transition ease-out duration-300"
|
||||
x-transition:enter-start="opacity-0"
|
||||
x-transition:enter-end="opacity-100"
|
||||
x-transition:leave="transition ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0">
|
||||
|
||||
<div class="modal-container" @click.away="close()">
|
||||
<div class="modal-content"
|
||||
x-transition:enter="transition ease-out duration-300"
|
||||
x-transition:enter-start="opacity-0 transform scale-95"
|
||||
x-transition:enter-end="opacity-100 transform scale-100"
|
||||
x-transition:leave="transition ease-in duration-200"
|
||||
x-transition:leave-start="opacity-100 transform scale-100"
|
||||
x-transition:leave-end="opacity-0 transform scale-95">
|
||||
|
||||
<!-- Modal Header -->
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title">Modal Title</h2>
|
||||
<button @click="close()" class="btn-icon">
|
||||
<svg class="icon-sm" fill="currentColor" viewBox="0 0 20 20">
|
||||
<!-- Close icon -->
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Modal Body -->
|
||||
<div class="modal-body">
|
||||
<p>Modal content goes here.</p>
|
||||
</div>
|
||||
|
||||
<!-- Modal Footer -->
|
||||
<div class="modal-footer">
|
||||
<button @click="close()" class="btn btn-secondary">Cancel</button>
|
||||
<button class="btn btn-primary">Confirm</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: var(--bg-overlay);
|
||||
z-index: var(--z-modal);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: var(--spacing-component-md);
|
||||
}
|
||||
|
||||
.modal-container {
|
||||
width: 100%;
|
||||
max-width: 32rem;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background: var(--bg-elevated);
|
||||
border-radius: var(--radius-modal);
|
||||
box-shadow: var(--shadow-modal);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: var(--spacing-component-lg);
|
||||
border-bottom: 1px solid var(--border-primary);
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: var(--text-xl);
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: var(--spacing-component-lg);
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: var(--spacing-component-sm);
|
||||
padding: var(--spacing-component-lg);
|
||||
border-top: 1px solid var(--border-primary);
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
```
|
||||
|
||||
### 7. Utility Components
|
||||
|
||||
#### Icons
|
||||
```html
|
||||
<!-- Icon Sizes -->
|
||||
<svg class="icon-xs" fill="currentColor" viewBox="0 0 20 20"><!-- Icon --></svg>
|
||||
<svg class="icon-sm" fill="currentColor" viewBox="0 0 20 20"><!-- Icon --></svg>
|
||||
<svg class="icon-md" fill="currentColor" viewBox="0 0 20 20"><!-- Icon --></svg>
|
||||
<svg class="icon-lg" fill="currentColor" viewBox="0 0 20 20"><!-- Icon --></svg>
|
||||
<svg class="icon-xl" fill="currentColor" viewBox="0 0 20 20"><!-- Icon --></svg>
|
||||
```
|
||||
|
||||
```css
|
||||
.icon-xs { width: 0.75rem; height: 0.75rem; }
|
||||
.icon-sm { width: 1rem; height: 1rem; }
|
||||
.icon-md { width: 1.25rem; height: 1.25rem; }
|
||||
.icon-lg { width: 1.5rem; height: 1.5rem; }
|
||||
.icon-xl { width: 2rem; height: 2rem; }
|
||||
```
|
||||
|
||||
#### Badges
|
||||
```html
|
||||
<!-- Status Badges -->
|
||||
<span class="badge badge-success">Operating</span>
|
||||
<span class="badge badge-warning">Seasonal</span>
|
||||
<span class="badge badge-error">Closed</span>
|
||||
<span class="badge badge-info">Under Construction</span>
|
||||
|
||||
<!-- Size Variants -->
|
||||
<span class="badge badge-sm badge-primary">Small</span>
|
||||
<span class="badge badge-primary">Default</span>
|
||||
<span class="badge badge-lg badge-primary">Large</span>
|
||||
```
|
||||
|
||||
```css
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: var(--spacing-component-xs) var(--spacing-component-sm);
|
||||
font-size: var(--text-xs);
|
||||
font-weight: 500;
|
||||
border-radius: var(--radius-badge);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: var(--tracking-wide);
|
||||
}
|
||||
|
||||
.badge-sm {
|
||||
padding: 0.125rem var(--spacing-component-xs);
|
||||
font-size: 0.625rem;
|
||||
}
|
||||
|
||||
.badge-lg {
|
||||
padding: var(--spacing-component-sm) var(--spacing-component-md);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
.badge-primary {
|
||||
background: var(--color-primary-100);
|
||||
color: var(--color-primary-800);
|
||||
}
|
||||
|
||||
.badge-success {
|
||||
background: var(--color-success-100);
|
||||
color: var(--color-success-800);
|
||||
}
|
||||
|
||||
.badge-warning {
|
||||
background: var(--color-warning-100);
|
||||
color: var(--color-warning-800);
|
||||
}
|
||||
|
||||
.badge-error {
|
||||
background: var(--color-error-100);
|
||||
color: var(--color-error-800);
|
||||
}
|
||||
|
||||
.badge-info {
|
||||
background: var(--color-info-100);
|
||||
color: var(--color-info-800);
|
||||
}
|
||||
|
||||
.dark .badge-primary {
|
||||
background: var(--color-primary-900);
|
||||
color: var(--color-primary-200);
|
||||
}
|
||||
|
||||
.dark .badge-success {
|
||||
background: var(--color-success-900);
|
||||
color: var(--color-success-200);
|
||||
}
|
||||
|
||||
.dark .badge-warning {
|
||||
background: var(--color-warning-900);
|
||||
color: var(--color-warning-200);
|
||||
}
|
||||
|
||||
.dark .badge-error {
|
||||
background: var(--color-error-900);
|
||||
color: var(--color-error-200);
|
||||
}
|
||||
|
||||
.dark .badge-info {
|
||||
background: var(--color-info-900);
|
||||
color: var(--color-info-200);
|
||||
}
|
||||
```
|
||||
|
||||
#### Avatars
|
||||
```html
|
||||
<!-- Avatar Sizes -->
|
||||
<img src="/path/to/avatar.jpg" alt="User" class="avatar-xs">
|
||||
<img src="/path/to/avatar.jpg" alt="User" class="avatar-sm">
|
||||
<img src="/path/to/avatar.jpg" alt="User" class="avatar-md">
|
||||
<img src="/path/to/avatar.jpg" alt="User" class="avatar-lg">
|
||||
<img src="/path/to/avatar.jpg" alt="User" class="avatar-xl">
|
||||
|
||||
<!-- Avatar with Fallback -->
|
||||
<div class="avatar-md avatar-fallback">
|
||||
<span>JD</span>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.avatar-xs,
|
||||
.avatar-sm,
|
||||
.avatar-md,
|
||||
.avatar-lg,
|
||||
.avatar-xl {
|
||||
border-radius: var(--radius-full);
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.avatar-xs { width: 1.5rem; height: 1.5rem; }
|
||||
.avatar-sm { width: 2rem; height: 2rem; }
|
||||
.avatar-md { width: 2.5rem; height: 2.5rem; }
|
||||
.avatar-lg { width: 3rem; height: 3rem; }
|
||||
.avatar-xl { width: 4rem; height: 4rem; }
|
||||
|
||||
.avatar-fallback {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--color-primary-100);
|
||||
color: var(--color-primary-700);
|
||||
font-weight: 500;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.dark .avatar-fallback {
|
||||
background: var(--color-primary-800);
|
||||
color: var(--color-primary-200);
|
||||
}
|
||||
```
|
||||
|
||||
## Alpine.js Component Patterns
|
||||
|
||||
### Theme Toggle Component
|
||||
```javascript
|
||||
Alpine.data('themeToggle', () => ({
|
||||
isDark: localStorage.getItem('theme') === 'dark' ||
|
||||
(!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches),
|
||||
|
||||
init() {
|
||||
this.updateTheme();
|
||||
},
|
||||
|
||||
toggle() {
|
||||
this.isDark = !this.isDark;
|
||||
this.updateTheme();
|
||||
},
|
||||
|
||||
updateTheme() {
|
||||
if (this.isDark) {
|
||||
document.documentElement.classList.add('dark');
|
||||
localStorage.setItem('theme', 'dark');
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark');
|
||||
localStorage.setItem('theme', 'light');
|
||||
}
|
||||
}
|
||||
}));
|
||||
```
|
||||
|
||||
### Modal Component
|
||||
```javascript
|
||||
Alpine.data
|
||||
508
memory-bank/design-system/design-tokens.md
Normal file
508
memory-bank/design-system/design-tokens.md
Normal file
@@ -0,0 +1,508 @@
|
||||
# ThrillWiki Design System - Design Tokens
|
||||
|
||||
## Overview
|
||||
Comprehensive design token system for ThrillWiki's frontend redesign, establishing consistent visual language across all components and templates.
|
||||
|
||||
## Color System
|
||||
|
||||
### Brand Colors
|
||||
```css
|
||||
:root {
|
||||
/* Primary Brand Colors */
|
||||
--color-primary-50: #eff6ff;
|
||||
--color-primary-100: #dbeafe;
|
||||
--color-primary-200: #bfdbfe;
|
||||
--color-primary-300: #93c5fd;
|
||||
--color-primary-400: #60a5fa;
|
||||
--color-primary-500: #3b82f6; /* Main brand blue */
|
||||
--color-primary-600: #2563eb;
|
||||
--color-primary-700: #1d4ed8;
|
||||
--color-primary-800: #1e40af;
|
||||
--color-primary-900: #1e3a8a;
|
||||
--color-primary-950: #172554;
|
||||
|
||||
/* Secondary Colors - Complementary Orange */
|
||||
--color-secondary-50: #fff7ed;
|
||||
--color-secondary-100: #ffedd5;
|
||||
--color-secondary-200: #fed7aa;
|
||||
--color-secondary-300: #fdba74;
|
||||
--color-secondary-400: #fb923c;
|
||||
--color-secondary-500: #f97316; /* Main accent orange */
|
||||
--color-secondary-600: #ea580c;
|
||||
--color-secondary-700: #c2410c;
|
||||
--color-secondary-800: #9a3412;
|
||||
--color-secondary-900: #7c2d12;
|
||||
--color-secondary-950: #431407;
|
||||
}
|
||||
```
|
||||
|
||||
### Semantic Colors
|
||||
```css
|
||||
:root {
|
||||
/* Success Colors */
|
||||
--color-success-50: #f0fdf4;
|
||||
--color-success-100: #dcfce7;
|
||||
--color-success-200: #bbf7d0;
|
||||
--color-success-300: #86efac;
|
||||
--color-success-400: #4ade80;
|
||||
--color-success-500: #22c55e;
|
||||
--color-success-600: #16a34a;
|
||||
--color-success-700: #15803d;
|
||||
--color-success-800: #166534;
|
||||
--color-success-900: #14532d;
|
||||
|
||||
/* Warning Colors */
|
||||
--color-warning-50: #fffbeb;
|
||||
--color-warning-100: #fef3c7;
|
||||
--color-warning-200: #fde68a;
|
||||
--color-warning-300: #fcd34d;
|
||||
--color-warning-400: #fbbf24;
|
||||
--color-warning-500: #f59e0b;
|
||||
--color-warning-600: #d97706;
|
||||
--color-warning-700: #b45309;
|
||||
--color-warning-800: #92400e;
|
||||
--color-warning-900: #78350f;
|
||||
|
||||
/* Error Colors */
|
||||
--color-error-50: #fef2f2;
|
||||
--color-error-100: #fee2e2;
|
||||
--color-error-200: #fecaca;
|
||||
--color-error-300: #fca5a5;
|
||||
--color-error-400: #f87171;
|
||||
--color-error-500: #ef4444;
|
||||
--color-error-600: #dc2626;
|
||||
--color-error-700: #b91c1c;
|
||||
--color-error-800: #991b1b;
|
||||
--color-error-900: #7f1d1d;
|
||||
|
||||
/* Info Colors */
|
||||
--color-info-50: #f0f9ff;
|
||||
--color-info-100: #e0f2fe;
|
||||
--color-info-200: #bae6fd;
|
||||
--color-info-300: #7dd3fc;
|
||||
--color-info-400: #38bdf8;
|
||||
--color-info-500: #0ea5e9;
|
||||
--color-info-600: #0284c7;
|
||||
--color-info-700: #0369a1;
|
||||
--color-info-800: #075985;
|
||||
--color-info-900: #0c4a6e;
|
||||
}
|
||||
```
|
||||
|
||||
### Neutral Colors (Light/Dark Mode)
|
||||
```css
|
||||
:root {
|
||||
/* Light Mode Neutrals */
|
||||
--color-neutral-50: #f8fafc;
|
||||
--color-neutral-100: #f1f5f9;
|
||||
--color-neutral-200: #e2e8f0;
|
||||
--color-neutral-300: #cbd5e1;
|
||||
--color-neutral-400: #94a3b8;
|
||||
--color-neutral-500: #64748b;
|
||||
--color-neutral-600: #475569;
|
||||
--color-neutral-700: #334155;
|
||||
--color-neutral-800: #1e293b;
|
||||
--color-neutral-900: #0f172a;
|
||||
--color-neutral-950: #020617;
|
||||
}
|
||||
|
||||
/* Dark Mode Color Overrides */
|
||||
.dark {
|
||||
--color-neutral-50: #020617;
|
||||
--color-neutral-100: #0f172a;
|
||||
--color-neutral-200: #1e293b;
|
||||
--color-neutral-300: #334155;
|
||||
--color-neutral-400: #475569;
|
||||
--color-neutral-500: #64748b;
|
||||
--color-neutral-600: #94a3b8;
|
||||
--color-neutral-700: #cbd5e1;
|
||||
--color-neutral-800: #e2e8f0;
|
||||
--color-neutral-900: #f1f5f9;
|
||||
--color-neutral-950: #f8fafc;
|
||||
}
|
||||
```
|
||||
|
||||
### Theme-Aware Semantic Tokens
|
||||
```css
|
||||
:root {
|
||||
/* Background Colors */
|
||||
--bg-primary: var(--color-neutral-50);
|
||||
--bg-secondary: var(--color-neutral-100);
|
||||
--bg-tertiary: var(--color-neutral-200);
|
||||
--bg-elevated: #ffffff;
|
||||
--bg-overlay: rgba(0, 0, 0, 0.5);
|
||||
|
||||
/* Text Colors */
|
||||
--text-primary: var(--color-neutral-900);
|
||||
--text-secondary: var(--color-neutral-700);
|
||||
--text-tertiary: var(--color-neutral-500);
|
||||
--text-inverse: #ffffff;
|
||||
--text-brand: var(--color-primary-600);
|
||||
|
||||
/* Border Colors */
|
||||
--border-primary: var(--color-neutral-200);
|
||||
--border-secondary: var(--color-neutral-300);
|
||||
--border-focus: var(--color-primary-500);
|
||||
--border-error: var(--color-error-500);
|
||||
|
||||
/* Interactive Colors */
|
||||
--interactive-primary: var(--color-primary-500);
|
||||
--interactive-primary-hover: var(--color-primary-600);
|
||||
--interactive-primary-active: var(--color-primary-700);
|
||||
--interactive-secondary: var(--color-neutral-200);
|
||||
--interactive-secondary-hover: var(--color-neutral-300);
|
||||
}
|
||||
|
||||
.dark {
|
||||
/* Dark Mode Background Colors */
|
||||
--bg-primary: var(--color-neutral-900);
|
||||
--bg-secondary: var(--color-neutral-800);
|
||||
--bg-tertiary: var(--color-neutral-700);
|
||||
--bg-elevated: var(--color-neutral-800);
|
||||
--bg-overlay: rgba(0, 0, 0, 0.7);
|
||||
|
||||
/* Dark Mode Text Colors */
|
||||
--text-primary: var(--color-neutral-100);
|
||||
--text-secondary: var(--color-neutral-300);
|
||||
--text-tertiary: var(--color-neutral-500);
|
||||
--text-inverse: var(--color-neutral-900);
|
||||
--text-brand: var(--color-primary-400);
|
||||
|
||||
/* Dark Mode Border Colors */
|
||||
--border-primary: var(--color-neutral-700);
|
||||
--border-secondary: var(--color-neutral-600);
|
||||
--border-focus: var(--color-primary-400);
|
||||
|
||||
/* Dark Mode Interactive Colors */
|
||||
--interactive-primary: var(--color-primary-500);
|
||||
--interactive-primary-hover: var(--color-primary-400);
|
||||
--interactive-primary-active: var(--color-primary-300);
|
||||
--interactive-secondary: var(--color-neutral-700);
|
||||
--interactive-secondary-hover: var(--color-neutral-600);
|
||||
}
|
||||
```
|
||||
|
||||
## Typography System
|
||||
|
||||
### Font Families
|
||||
```css
|
||||
:root {
|
||||
/* Primary Font - Poppins (existing) */
|
||||
--font-primary: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
|
||||
/* Monospace Font */
|
||||
--font-mono: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
|
||||
|
||||
/* System Font Stack (fallback) */
|
||||
--font-system: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
}
|
||||
```
|
||||
|
||||
### Font Sizes & Line Heights
|
||||
```css
|
||||
:root {
|
||||
/* Font Sizes */
|
||||
--text-xs: 0.75rem; /* 12px */
|
||||
--text-sm: 0.875rem; /* 14px */
|
||||
--text-base: 1rem; /* 16px */
|
||||
--text-lg: 1.125rem; /* 18px */
|
||||
--text-xl: 1.25rem; /* 20px */
|
||||
--text-2xl: 1.5rem; /* 24px */
|
||||
--text-3xl: 1.875rem; /* 30px */
|
||||
--text-4xl: 2.25rem; /* 36px */
|
||||
--text-5xl: 3rem; /* 48px */
|
||||
--text-6xl: 3.75rem; /* 60px */
|
||||
--text-7xl: 4.5rem; /* 72px */
|
||||
|
||||
/* Line Heights */
|
||||
--leading-none: 1;
|
||||
--leading-tight: 1.25;
|
||||
--leading-snug: 1.375;
|
||||
--leading-normal: 1.5;
|
||||
--leading-relaxed: 1.625;
|
||||
--leading-loose: 2;
|
||||
|
||||
/* Letter Spacing */
|
||||
--tracking-tighter: -0.05em;
|
||||
--tracking-tight: -0.025em;
|
||||
--tracking-normal: 0em;
|
||||
--tracking-wide: 0.025em;
|
||||
--tracking-wider: 0.05em;
|
||||
--tracking-widest: 0.1em;
|
||||
}
|
||||
```
|
||||
|
||||
### Typography Scale
|
||||
```css
|
||||
:root {
|
||||
/* Heading Styles */
|
||||
--heading-1: var(--text-4xl);
|
||||
--heading-1-line-height: var(--leading-tight);
|
||||
--heading-1-weight: 700;
|
||||
--heading-1-tracking: var(--tracking-tight);
|
||||
|
||||
--heading-2: var(--text-3xl);
|
||||
--heading-2-line-height: var(--leading-tight);
|
||||
--heading-2-weight: 600;
|
||||
--heading-2-tracking: var(--tracking-tight);
|
||||
|
||||
--heading-3: var(--text-2xl);
|
||||
--heading-3-line-height: var(--leading-snug);
|
||||
--heading-3-weight: 600;
|
||||
--heading-3-tracking: var(--tracking-normal);
|
||||
|
||||
--heading-4: var(--text-xl);
|
||||
--heading-4-line-height: var(--leading-snug);
|
||||
--heading-4-weight: 600;
|
||||
--heading-4-tracking: var(--tracking-normal);
|
||||
|
||||
--heading-5: var(--text-lg);
|
||||
--heading-5-line-height: var(--leading-normal);
|
||||
--heading-5-weight: 500;
|
||||
--heading-5-tracking: var(--tracking-normal);
|
||||
|
||||
--heading-6: var(--text-base);
|
||||
--heading-6-line-height: var(--leading-normal);
|
||||
--heading-6-weight: 500;
|
||||
--heading-6-tracking: var(--tracking-wide);
|
||||
|
||||
/* Body Text Styles */
|
||||
--body-large: var(--text-lg);
|
||||
--body-large-line-height: var(--leading-relaxed);
|
||||
--body-large-weight: 400;
|
||||
|
||||
--body-base: var(--text-base);
|
||||
--body-base-line-height: var(--leading-normal);
|
||||
--body-base-weight: 400;
|
||||
|
||||
--body-small: var(--text-sm);
|
||||
--body-small-line-height: var(--leading-normal);
|
||||
--body-small-weight: 400;
|
||||
|
||||
--body-xs: var(--text-xs);
|
||||
--body-xs-line-height: var(--leading-normal);
|
||||
--body-xs-weight: 400;
|
||||
}
|
||||
```
|
||||
|
||||
## Spacing System
|
||||
|
||||
### Base Spacing Scale
|
||||
```css
|
||||
:root {
|
||||
/* Spacing Scale (based on 4px grid) */
|
||||
--space-0: 0;
|
||||
--space-px: 1px;
|
||||
--space-0-5: 0.125rem; /* 2px */
|
||||
--space-1: 0.25rem; /* 4px */
|
||||
--space-1-5: 0.375rem; /* 6px */
|
||||
--space-2: 0.5rem; /* 8px */
|
||||
--space-2-5: 0.625rem; /* 10px */
|
||||
--space-3: 0.75rem; /* 12px */
|
||||
--space-3-5: 0.875rem; /* 14px */
|
||||
--space-4: 1rem; /* 16px */
|
||||
--space-5: 1.25rem; /* 20px */
|
||||
--space-6: 1.5rem; /* 24px */
|
||||
--space-7: 1.75rem; /* 28px */
|
||||
--space-8: 2rem; /* 32px */
|
||||
--space-9: 2.25rem; /* 36px */
|
||||
--space-10: 2.5rem; /* 40px */
|
||||
--space-11: 2.75rem; /* 44px */
|
||||
--space-12: 3rem; /* 48px */
|
||||
--space-14: 3.5rem; /* 56px */
|
||||
--space-16: 4rem; /* 64px */
|
||||
--space-20: 5rem; /* 80px */
|
||||
--space-24: 6rem; /* 96px */
|
||||
--space-28: 7rem; /* 112px */
|
||||
--space-32: 8rem; /* 128px */
|
||||
--space-36: 9rem; /* 144px */
|
||||
--space-40: 10rem; /* 160px */
|
||||
--space-44: 11rem; /* 176px */
|
||||
--space-48: 12rem; /* 192px */
|
||||
--space-52: 13rem; /* 208px */
|
||||
--space-56: 14rem; /* 224px */
|
||||
--space-60: 15rem; /* 240px */
|
||||
--space-64: 16rem; /* 256px */
|
||||
--space-72: 18rem; /* 288px */
|
||||
--space-80: 20rem; /* 320px */
|
||||
--space-96: 24rem; /* 384px */
|
||||
}
|
||||
```
|
||||
|
||||
### Semantic Spacing
|
||||
```css
|
||||
:root {
|
||||
/* Component Spacing */
|
||||
--spacing-component-xs: var(--space-2);
|
||||
--spacing-component-sm: var(--space-3);
|
||||
--spacing-component-md: var(--space-4);
|
||||
--spacing-component-lg: var(--space-6);
|
||||
--spacing-component-xl: var(--space-8);
|
||||
|
||||
/* Layout Spacing */
|
||||
--spacing-layout-xs: var(--space-4);
|
||||
--spacing-layout-sm: var(--space-6);
|
||||
--spacing-layout-md: var(--space-8);
|
||||
--spacing-layout-lg: var(--space-12);
|
||||
--spacing-layout-xl: var(--space-16);
|
||||
--spacing-layout-2xl: var(--space-24);
|
||||
|
||||
/* Container Spacing */
|
||||
--spacing-container-xs: var(--space-4);
|
||||
--spacing-container-sm: var(--space-6);
|
||||
--spacing-container-md: var(--space-8);
|
||||
--spacing-container-lg: var(--space-12);
|
||||
--spacing-container-xl: var(--space-16);
|
||||
}
|
||||
```
|
||||
|
||||
## Border Radius System
|
||||
|
||||
```css
|
||||
:root {
|
||||
/* Border Radius Scale */
|
||||
--radius-none: 0;
|
||||
--radius-sm: 0.125rem; /* 2px */
|
||||
--radius-base: 0.25rem; /* 4px */
|
||||
--radius-md: 0.375rem; /* 6px */
|
||||
--radius-lg: 0.5rem; /* 8px */
|
||||
--radius-xl: 0.75rem; /* 12px */
|
||||
--radius-2xl: 1rem; /* 16px */
|
||||
--radius-3xl: 1.5rem; /* 24px */
|
||||
--radius-full: 9999px;
|
||||
|
||||
/* Semantic Border Radius */
|
||||
--radius-button: var(--radius-md);
|
||||
--radius-card: var(--radius-lg);
|
||||
--radius-modal: var(--radius-xl);
|
||||
--radius-input: var(--radius-md);
|
||||
--radius-badge: var(--radius-full);
|
||||
}
|
||||
```
|
||||
|
||||
## Shadow System
|
||||
|
||||
```css
|
||||
:root {
|
||||
/* Shadow Scale */
|
||||
--shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||
--shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
|
||||
--shadow-base: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
|
||||
--shadow-md: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
|
||||
--shadow-lg: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
|
||||
--shadow-xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
||||
--shadow-2xl: 0 50px 100px -20px rgba(0, 0, 0, 0.25);
|
||||
--shadow-inner: inset 0 2px 4px 0 rgba(0, 0, 0, 0.05);
|
||||
|
||||
/* Semantic Shadows */
|
||||
--shadow-card: var(--shadow-sm);
|
||||
--shadow-card-hover: var(--shadow-md);
|
||||
--shadow-modal: var(--shadow-xl);
|
||||
--shadow-dropdown: var(--shadow-lg);
|
||||
--shadow-button: var(--shadow-xs);
|
||||
--shadow-button-hover: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.dark {
|
||||
/* Dark Mode Shadow Adjustments */
|
||||
--shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
|
||||
--shadow-sm: 0 1px 3px 0 rgba(0, 0, 0, 0.4), 0 1px 2px -1px rgba(0, 0, 0, 0.4);
|
||||
--shadow-base: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -2px rgba(0, 0, 0, 0.4);
|
||||
--shadow-md: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -4px rgba(0, 0, 0, 0.4);
|
||||
--shadow-lg: 0 20px 25px -5px rgba(0, 0, 0, 0.4), 0 8px 10px -6px rgba(0, 0, 0, 0.4);
|
||||
--shadow-xl: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
||||
--shadow-2xl: 0 50px 100px -20px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
```
|
||||
|
||||
## Z-Index System
|
||||
|
||||
```css
|
||||
:root {
|
||||
/* Z-Index Scale */
|
||||
--z-0: 0;
|
||||
--z-10: 10;
|
||||
--z-20: 20;
|
||||
--z-30: 30;
|
||||
--z-40: 40;
|
||||
--z-50: 50;
|
||||
|
||||
/* Semantic Z-Index */
|
||||
--z-dropdown: var(--z-10);
|
||||
--z-sticky: var(--z-20);
|
||||
--z-fixed: var(--z-30);
|
||||
--z-modal-backdrop: var(--z-40);
|
||||
--z-modal: var(--z-50);
|
||||
--z-popover: var(--z-50);
|
||||
--z-tooltip: var(--z-50);
|
||||
}
|
||||
```
|
||||
|
||||
## Breakpoint System
|
||||
|
||||
```css
|
||||
:root {
|
||||
/* Breakpoint Values */
|
||||
--breakpoint-xs: 475px;
|
||||
--breakpoint-sm: 640px;
|
||||
--breakpoint-md: 768px;
|
||||
--breakpoint-lg: 1024px;
|
||||
--breakpoint-xl: 1280px;
|
||||
--breakpoint-2xl: 1536px;
|
||||
}
|
||||
```
|
||||
|
||||
## Animation & Transition System
|
||||
|
||||
```css
|
||||
:root {
|
||||
/* Timing Functions */
|
||||
--ease-linear: linear;
|
||||
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
||||
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
||||
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
--ease-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
||||
|
||||
/* Duration Scale */
|
||||
--duration-75: 75ms;
|
||||
--duration-100: 100ms;
|
||||
--duration-150: 150ms;
|
||||
--duration-200: 200ms;
|
||||
--duration-300: 300ms;
|
||||
--duration-500: 500ms;
|
||||
--duration-700: 700ms;
|
||||
--duration-1000: 1000ms;
|
||||
|
||||
/* Semantic Transitions */
|
||||
--transition-fast: var(--duration-150) var(--ease-out);
|
||||
--transition-base: var(--duration-200) var(--ease-out);
|
||||
--transition-slow: var(--duration-300) var(--ease-out);
|
||||
--transition-bounce: var(--duration-300) var(--ease-bounce);
|
||||
}
|
||||
```
|
||||
|
||||
## Usage Guidelines
|
||||
|
||||
### Color Usage
|
||||
- Use semantic color tokens (`--text-primary`, `--bg-elevated`) instead of direct color values
|
||||
- Ensure sufficient contrast ratios (4.5:1 for normal text, 3:1 for large text)
|
||||
- Test all color combinations in both light and dark modes
|
||||
- Use brand colors sparingly for emphasis and calls-to-action
|
||||
|
||||
### Typography Usage
|
||||
- Use the typography scale consistently across all components
|
||||
- Maintain proper hierarchy with heading levels
|
||||
- Ensure line heights provide comfortable reading experience
|
||||
- Use font weights purposefully to create visual hierarchy
|
||||
|
||||
### Spacing Usage
|
||||
- Follow the 4px grid system for all spacing decisions
|
||||
- Use semantic spacing tokens for consistent component spacing
|
||||
- Maintain consistent spacing patterns within component families
|
||||
- Consider touch targets (minimum 44px) for interactive elements
|
||||
|
||||
### Implementation Notes
|
||||
- All design tokens should be implemented as CSS custom properties
|
||||
- Tokens should be imported into the main Tailwind CSS configuration
|
||||
- Components should reference tokens rather than hardcoded values
|
||||
- Dark mode variants should be automatically applied via CSS custom properties
|
||||
Reference in New Issue
Block a user