mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-23 10:31:08 -05:00
Add standardized HTMX conventions, interaction patterns, and migration guide for ThrillWiki UX
This commit is contained in:
336
docs/design-system/MIGRATION.md
Normal file
336
docs/design-system/MIGRATION.md
Normal file
@@ -0,0 +1,336 @@
|
||||
# Design System Migration Guide
|
||||
|
||||
This guide helps migrate from the legacy frontend system to the unified design system.
|
||||
|
||||
## Overview
|
||||
|
||||
The ThrillWiki frontend was consolidated from two parallel systems:
|
||||
- **Legacy System** (`/backend/templates/`, `/backend/static/css/`) - HSL-based variables, Font Awesome icons
|
||||
- **Modern System** (`/templates/`, `/static/css/`) - RGB hex-based design tokens, SVG icons
|
||||
|
||||
The unified system uses `design-tokens.css` as the single source of truth.
|
||||
|
||||
## CSS Migration
|
||||
|
||||
### Color Variables
|
||||
|
||||
Replace HSL-based variables with design tokens:
|
||||
|
||||
```css
|
||||
/* Before (legacy) */
|
||||
background-color: hsl(var(--primary));
|
||||
color: hsl(var(--primary-foreground));
|
||||
|
||||
/* After (design tokens) */
|
||||
background-color: var(--color-primary);
|
||||
color: var(--color-primary-foreground);
|
||||
```
|
||||
|
||||
### Common Replacements
|
||||
|
||||
| Legacy | Design Token |
|
||||
|--------|--------------|
|
||||
| `hsl(var(--primary))` | `var(--color-primary)` |
|
||||
| `hsl(var(--secondary))` | `var(--color-secondary)` |
|
||||
| `hsl(var(--background))` | `var(--color-background)` |
|
||||
| `hsl(var(--foreground))` | `var(--color-foreground)` |
|
||||
| `hsl(var(--muted))` | `var(--color-muted)` |
|
||||
| `hsl(var(--accent))` | `var(--color-accent)` |
|
||||
| `hsl(var(--destructive))` | `var(--color-destructive)` |
|
||||
| `hsl(var(--border))` | `var(--color-border)` |
|
||||
| `hsl(var(--card))` | `var(--color-card)` |
|
||||
|
||||
### Font Variables
|
||||
|
||||
```css
|
||||
/* Before */
|
||||
font-family: var(--font-sans);
|
||||
|
||||
/* After */
|
||||
font-family: var(--font-family-sans);
|
||||
```
|
||||
|
||||
### Shadow Variables
|
||||
|
||||
```css
|
||||
/* Before */
|
||||
box-shadow: var(--shadow);
|
||||
|
||||
/* After */
|
||||
box-shadow: var(--shadow-base);
|
||||
```
|
||||
|
||||
## Icon Migration
|
||||
|
||||
Replace Font Awesome icons with the SVG icon component:
|
||||
|
||||
```html
|
||||
<!-- Before (Font Awesome) -->
|
||||
<i class="fa fa-search"></i>
|
||||
<i class="fas fa-user"></i>
|
||||
<i class="far fa-heart"></i>
|
||||
|
||||
<!-- After (SVG Icon Component) -->
|
||||
{% include "components/ui/icon.html" with name="search" %}
|
||||
{% include "components/ui/icon.html" with name="user" %}
|
||||
{% include "components/ui/icon.html" with name="heart" %}
|
||||
```
|
||||
|
||||
### Icon Name Mapping
|
||||
|
||||
| Font Awesome | SVG Icon |
|
||||
|--------------|----------|
|
||||
| `fa-search` | `search` |
|
||||
| `fa-user` | `user` |
|
||||
| `fa-users` | `users` |
|
||||
| `fa-cog` | `settings` |
|
||||
| `fa-heart` | `heart` |
|
||||
| `fa-star` | `star` |
|
||||
| `fa-home` | `home` |
|
||||
| `fa-edit` | `edit` |
|
||||
| `fa-trash` | `trash` |
|
||||
| `fa-copy` | `copy` |
|
||||
| `fa-external-link` | `external-link` |
|
||||
| `fa-chevron-down` | `chevron-down` |
|
||||
| `fa-chevron-up` | `chevron-up` |
|
||||
| `fa-chevron-left` | `chevron-left` |
|
||||
| `fa-chevron-right` | `chevron-right` |
|
||||
| `fa-check` | `check` |
|
||||
| `fa-times` | `close` |
|
||||
| `fa-plus` | `plus` |
|
||||
| `fa-minus` | `minus` |
|
||||
| `fa-bars` | `menu` |
|
||||
|
||||
### Icon Sizes
|
||||
|
||||
```html
|
||||
<!-- Before -->
|
||||
<i class="fa fa-search fa-sm"></i>
|
||||
<i class="fa fa-search fa-lg"></i>
|
||||
<i class="fa fa-search fa-2x"></i>
|
||||
|
||||
<!-- After -->
|
||||
{% include "components/ui/icon.html" with name="search" size="sm" %}
|
||||
{% include "components/ui/icon.html" with name="search" size="lg" %}
|
||||
{% include "components/ui/icon.html" with name="search" size="xl" %}
|
||||
```
|
||||
|
||||
## Button Migration
|
||||
|
||||
### Basic Buttons
|
||||
|
||||
```html
|
||||
<!-- Before -->
|
||||
<button class="btn btn-primary">Click Me</button>
|
||||
<button class="btn btn-secondary">Click Me</button>
|
||||
<button class="btn btn-danger">Delete</button>
|
||||
<button class="btn btn-outline">Outline</button>
|
||||
|
||||
<!-- After -->
|
||||
{% include "components/ui/button.html" with text="Click Me" variant="default" %}
|
||||
{% include "components/ui/button.html" with text="Click Me" variant="secondary" %}
|
||||
{% include "components/ui/button.html" with text="Delete" variant="destructive" %}
|
||||
{% include "components/ui/button.html" with text="Outline" variant="outline" %}
|
||||
```
|
||||
|
||||
### Buttons with Icons
|
||||
|
||||
```html
|
||||
<!-- Before -->
|
||||
<button class="btn btn-primary">
|
||||
<i class="fa fa-search mr-2"></i>
|
||||
Search
|
||||
</button>
|
||||
|
||||
<!-- After -->
|
||||
{% include "components/ui/button.html" with text="Search" icon="search" %}
|
||||
```
|
||||
|
||||
### Link Buttons
|
||||
|
||||
```html
|
||||
<!-- Before -->
|
||||
<a href="/url" class="btn btn-primary">Go</a>
|
||||
|
||||
<!-- After -->
|
||||
{% include "components/ui/button.html" with text="Go" href="/url" %}
|
||||
```
|
||||
|
||||
## Form Input Migration
|
||||
|
||||
```html
|
||||
<!-- Before -->
|
||||
<div class="form-group">
|
||||
<label for="email">Email</label>
|
||||
<input type="email" id="email" name="email" class="form-control" placeholder="Enter email">
|
||||
<small class="form-text text-muted">We'll never share your email.</small>
|
||||
</div>
|
||||
|
||||
<!-- After -->
|
||||
{% include "components/ui/input.html" with
|
||||
name="email"
|
||||
label="Email"
|
||||
type="email"
|
||||
placeholder="Enter email"
|
||||
hint="We'll never share your email."
|
||||
%}
|
||||
```
|
||||
|
||||
## Card Migration
|
||||
|
||||
```html
|
||||
<!-- Before -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Title</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>Content here</p>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button class="btn">Action</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- After -->
|
||||
{% include "components/ui/card.html" with
|
||||
title="Title"
|
||||
body_content="<p>Content here</p>"
|
||||
footer_content="<button class='btn'>Action</button>"
|
||||
%}
|
||||
```
|
||||
|
||||
## Modal Migration
|
||||
|
||||
```html
|
||||
<!-- Before -->
|
||||
<div class="modal" id="myModal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Title</h5>
|
||||
<button class="close">×</button>
|
||||
</div>
|
||||
<div class="modal-body">Content</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- After -->
|
||||
{% include "components/ui/dialog.html" with
|
||||
id="myModal"
|
||||
title="Title"
|
||||
content="Content"
|
||||
footer="<button class='btn'>Close</button>"
|
||||
%}
|
||||
```
|
||||
|
||||
## Alpine.js Migration
|
||||
|
||||
### Store Definitions
|
||||
|
||||
Move inline store definitions to `stores/index.js`:
|
||||
|
||||
```javascript
|
||||
// Before (inline in template)
|
||||
<script>
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.store('theme', {
|
||||
isDark: false,
|
||||
toggle() { this.isDark = !this.isDark; }
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
// After (use centralized store)
|
||||
// Store is already defined in stores/index.js
|
||||
// Access via $store.theme.toggle()
|
||||
```
|
||||
|
||||
### Component Definitions
|
||||
|
||||
Move inline component definitions to `alpine-components.js`:
|
||||
|
||||
```javascript
|
||||
// Before (inline in template)
|
||||
<div x-data="{ open: false }">
|
||||
<button @click="open = !open">Toggle</button>
|
||||
<div x-show="open">Content</div>
|
||||
</div>
|
||||
|
||||
// After (use registered component)
|
||||
<div x-data="dropdown()">
|
||||
<button @click="toggle()">Toggle</button>
|
||||
<div x-show="open">Content</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Alert/Toast Migration
|
||||
|
||||
```html
|
||||
<!-- Before -->
|
||||
<div class="alert alert-success">
|
||||
<strong>Success!</strong> Your action was completed.
|
||||
</div>
|
||||
|
||||
<!-- After -->
|
||||
<div class="alert alert-success" role="alert">
|
||||
<div class="alert-title">Success!</div>
|
||||
<div class="alert-description">Your action was completed.</div>
|
||||
</div>
|
||||
|
||||
<!-- Or use toast store for dynamic notifications -->
|
||||
<script>
|
||||
Alpine.store('toast').success('Your action was completed.');
|
||||
</script>
|
||||
```
|
||||
|
||||
## Responsive Classes Migration
|
||||
|
||||
```html
|
||||
<!-- Before -->
|
||||
<div class="d-none d-md-block">Hidden on mobile</div>
|
||||
<div class="d-md-none">Only on mobile</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6">...</div>
|
||||
</div>
|
||||
|
||||
<!-- After -->
|
||||
<div class="hidden-mobile">Hidden on mobile</div>
|
||||
<div class="show-mobile">Only on mobile</div>
|
||||
<div class="grid-responsive-2">
|
||||
<div>...</div>
|
||||
<div>...</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Checklist
|
||||
|
||||
Use this checklist when migrating a template:
|
||||
|
||||
- [ ] Replace HSL color variables with design tokens
|
||||
- [ ] Replace Font Awesome icons with SVG icon component
|
||||
- [ ] Update button markup to use button component
|
||||
- [ ] Update form inputs to use input component
|
||||
- [ ] Update cards to use card component
|
||||
- [ ] Update modals to use dialog component
|
||||
- [ ] Remove inline Alpine.js store definitions
|
||||
- [ ] Update responsive classes
|
||||
- [ ] Test dark mode appearance
|
||||
- [ ] Test focus states for accessibility
|
||||
- [ ] Test on mobile viewport
|
||||
|
||||
## Testing Migration
|
||||
|
||||
After migrating, visit `/design-system-test/` to compare your migrated components against the reference implementation.
|
||||
|
||||
## Getting Help
|
||||
|
||||
If you encounter issues during migration:
|
||||
|
||||
1. Check the design system README for component documentation
|
||||
2. Review `design-tokens.css` for available tokens
|
||||
3. Inspect the design system test page for examples
|
||||
405
docs/design-system/README.md
Normal file
405
docs/design-system/README.md
Normal file
@@ -0,0 +1,405 @@
|
||||
# ThrillWiki Design System
|
||||
|
||||
A unified design system for the ThrillWiki application, providing consistent styling, components, and utilities across the entire frontend.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Directory Structure
|
||||
|
||||
```
|
||||
backend/
|
||||
├── static/
|
||||
│ ├── css/
|
||||
│ │ └── design-tokens.css # Primary design tokens (colors, typography, spacing)
|
||||
│ └── js/
|
||||
│ ├── alpine-components.js # Alpine.js components
|
||||
│ └── stores/index.js # Alpine.js stores
|
||||
└── templates/
|
||||
├── base/
|
||||
│ └── base.html # Base template (extend this)
|
||||
└── components/
|
||||
└── ui/
|
||||
├── button.html # Button component
|
||||
├── card.html # Card component
|
||||
├── dialog.html # Modal/dialog component
|
||||
├── icon.html # SVG icon component
|
||||
└── input.html # Form input component
|
||||
```
|
||||
|
||||
### CSS Loading Order
|
||||
|
||||
CSS files must be loaded in this specific order:
|
||||
|
||||
```html
|
||||
<link href="{% static 'css/design-tokens.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'css/tailwind.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'css/components.css' %}" rel="stylesheet">
|
||||
```
|
||||
|
||||
### JavaScript Loading Order
|
||||
|
||||
```html
|
||||
<!-- Alpine.js stores (loaded before Alpine) -->
|
||||
<script src="{% static 'js/stores/index.js' %}"></script>
|
||||
|
||||
<!-- Alpine.js plugins -->
|
||||
<script defer src="https://unpkg.com/@alpinejs/intersect@3.x.x/dist/cdn.min.js"></script>
|
||||
<script defer src="https://unpkg.com/@alpinejs/persist@3.x.x/dist/cdn.min.js"></script>
|
||||
|
||||
<!-- Alpine.js core -->
|
||||
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||
|
||||
<!-- Alpine.js components (after Alpine loads) -->
|
||||
<script src="{% static 'js/alpine-components.js' %}"></script>
|
||||
```
|
||||
|
||||
## Design Tokens
|
||||
|
||||
Design tokens are CSS custom properties that define the visual language of the application.
|
||||
|
||||
### Color System
|
||||
|
||||
#### Color Scales
|
||||
|
||||
Each color has a scale from 50-950:
|
||||
|
||||
```css
|
||||
--color-primary-50 /* Lightest */
|
||||
--color-primary-100
|
||||
--color-primary-200
|
||||
--color-primary-300
|
||||
--color-primary-400
|
||||
--color-primary-500 /* Base */
|
||||
--color-primary-600
|
||||
--color-primary-700
|
||||
--color-primary-800
|
||||
--color-primary-900
|
||||
--color-primary-950 /* Darkest */
|
||||
```
|
||||
|
||||
Available color scales:
|
||||
- `primary` - Blue (brand color)
|
||||
- `secondary` - Slate (neutral)
|
||||
- `accent` - Red (highlights)
|
||||
- `success` - Green
|
||||
- `warning` - Amber
|
||||
- `error` - Red
|
||||
- `info` - Sky blue
|
||||
|
||||
#### Semantic Colors
|
||||
|
||||
These adapt automatically for dark mode:
|
||||
|
||||
```css
|
||||
--color-background /* Page background */
|
||||
--color-foreground /* Primary text */
|
||||
--color-muted /* Muted backgrounds */
|
||||
--color-muted-foreground /* Secondary text */
|
||||
--color-border /* Border color */
|
||||
--color-card /* Card background */
|
||||
--color-card-foreground /* Card text */
|
||||
--color-primary /* Primary action color */
|
||||
--color-primary-foreground /* Text on primary */
|
||||
--color-destructive /* Destructive actions */
|
||||
```
|
||||
|
||||
### Typography
|
||||
|
||||
```css
|
||||
/* Font Families */
|
||||
--font-family-sans /* Inter - body text */
|
||||
--font-family-serif /* Playfair Display - headings */
|
||||
--font-family-mono /* JetBrains Mono - code */
|
||||
|
||||
/* Font Sizes */
|
||||
--font-size-xs /* 12px */
|
||||
--font-size-sm /* 14px */
|
||||
--font-size-base /* 16px */
|
||||
--font-size-lg /* 18px */
|
||||
--font-size-xl /* 20px */
|
||||
--font-size-2xl /* 24px */
|
||||
--font-size-3xl /* 30px */
|
||||
--font-size-4xl /* 36px */
|
||||
```
|
||||
|
||||
### Spacing Scale
|
||||
|
||||
```css
|
||||
--spacing-1 /* 4px */
|
||||
--spacing-2 /* 8px */
|
||||
--spacing-3 /* 12px */
|
||||
--spacing-4 /* 16px */
|
||||
--spacing-6 /* 24px */
|
||||
--spacing-8 /* 32px */
|
||||
--spacing-12 /* 48px */
|
||||
--spacing-16 /* 64px */
|
||||
```
|
||||
|
||||
### Shadows
|
||||
|
||||
```css
|
||||
--shadow-sm /* Subtle shadow */
|
||||
--shadow-base /* Default shadow */
|
||||
--shadow-md /* Medium shadow */
|
||||
--shadow-lg /* Large shadow */
|
||||
--shadow-xl /* Extra large shadow */
|
||||
--shadow-2xl /* Maximum shadow */
|
||||
```
|
||||
|
||||
### Border Radius
|
||||
|
||||
```css
|
||||
--radius-sm /* 2px */
|
||||
--radius-base /* 4px */
|
||||
--radius-md /* 6px */
|
||||
--radius-lg /* 8px */
|
||||
--radius-xl /* 12px */
|
||||
--radius-full /* 9999px (pill) */
|
||||
```
|
||||
|
||||
### Breakpoints
|
||||
|
||||
```css
|
||||
--breakpoint-sm /* 640px - Mobile landscape */
|
||||
--breakpoint-md /* 768px - Tablets */
|
||||
--breakpoint-lg /* 1024px - Desktops */
|
||||
--breakpoint-xl /* 1280px - Large screens */
|
||||
--breakpoint-2xl /* 1536px - Extra large */
|
||||
```
|
||||
|
||||
## Components
|
||||
|
||||
### Button Component
|
||||
|
||||
```django
|
||||
{% include "components/ui/button.html" with
|
||||
text="Button Text"
|
||||
variant="default" {# default|secondary|destructive|outline|ghost|link #}
|
||||
size="default" {# default|sm|lg|icon #}
|
||||
icon="search" {# Optional: icon name #}
|
||||
disabled=False
|
||||
type="button" {# button|submit|reset #}
|
||||
href="" {# If provided, renders as <a> #}
|
||||
hx_get="/url" {# HTMX attributes #}
|
||||
hx_post="/url"
|
||||
hx_target="#element"
|
||||
hx_swap="innerHTML"
|
||||
x_on_click="handler" {# Alpine.js attributes #}
|
||||
%}
|
||||
```
|
||||
|
||||
### Card Component
|
||||
|
||||
```django
|
||||
{% include "components/ui/card.html" with
|
||||
title="Card Title"
|
||||
description="Optional description"
|
||||
body_content="<p>Card content here</p>"
|
||||
footer_content="<button>Action</button>"
|
||||
class="additional-classes"
|
||||
%}
|
||||
```
|
||||
|
||||
### Input Component
|
||||
|
||||
```django
|
||||
{% include "components/ui/input.html" with
|
||||
name="field_name"
|
||||
label="Field Label"
|
||||
type="text" {# text|email|password|number|textarea #}
|
||||
placeholder="Placeholder text"
|
||||
value=""
|
||||
required=False
|
||||
disabled=False
|
||||
error="Error message"
|
||||
hint="Helper text"
|
||||
%}
|
||||
```
|
||||
|
||||
### Dialog/Modal Component
|
||||
|
||||
```django
|
||||
{% include "components/ui/dialog.html" with
|
||||
id="modal-id"
|
||||
title="Dialog Title"
|
||||
description="Optional description"
|
||||
content="<p>Dialog content</p>"
|
||||
footer="<button>Action</button>"
|
||||
size="default" {# sm|default|lg|xl|full #}
|
||||
closable=True
|
||||
open=True
|
||||
%}
|
||||
```
|
||||
|
||||
### Icon Component
|
||||
|
||||
```django
|
||||
{% include "components/ui/icon.html" with
|
||||
name="search" {# Icon name from library #}
|
||||
size="md" {# xs|sm|md|lg|xl #}
|
||||
class="text-primary" {# Additional classes #}
|
||||
%}
|
||||
```
|
||||
|
||||
Available icons: search, menu, close, chevron-up, chevron-down, chevron-left, chevron-right, arrow-up, arrow-down, arrow-left, arrow-right, user, users, settings, cog, heart, heart-filled, star, star-filled, home, edit, trash, copy, external-link, download, upload, check, check-circle, x-circle, info, warning, error, plus, minus, filter, sort, calendar, clock, map-pin, phone, mail, globe, link, image, camera, play, pause, volume, bell, bookmark, share, refresh, eye, eye-off, lock, unlock, sun, moon, loader
|
||||
|
||||
## Utility Classes
|
||||
|
||||
### Responsive Utilities
|
||||
|
||||
```css
|
||||
/* Visibility */
|
||||
.hidden-mobile /* Hidden on mobile */
|
||||
.hidden-sm /* Hidden on sm breakpoint */
|
||||
.show-mobile /* Only visible on mobile */
|
||||
.show-lg /* Only visible on lg breakpoint */
|
||||
|
||||
/* Grid */
|
||||
.grid-responsive-2 /* 1 col mobile, 2 cols sm+ */
|
||||
.grid-responsive-3 /* 1 col mobile, 2 cols sm+, 3 cols lg+ */
|
||||
.grid-responsive-4 /* 1 col mobile, 2 cols sm+, 4 cols lg+ */
|
||||
.grid-auto-fit /* Auto-fit grid with 300px min */
|
||||
|
||||
/* Flex */
|
||||
.stack-to-row /* Column on mobile, row on sm+ */
|
||||
.stack-to-row-lg /* Column on mobile/tablet, row on lg+ */
|
||||
|
||||
/* Spacing */
|
||||
.py-responsive /* 16px mobile, 24px sm, 32px lg */
|
||||
.px-responsive /* Same for horizontal */
|
||||
.gap-responsive /* Responsive gap */
|
||||
```
|
||||
|
||||
### Container Classes
|
||||
|
||||
```css
|
||||
.container /* max-width: 1280px */
|
||||
.container-sm /* max-width: 640px */
|
||||
.container-md /* max-width: 768px */
|
||||
.container-lg /* max-width: 1024px */
|
||||
.container-xl /* max-width: 1280px */
|
||||
.container-2xl /* max-width: 1536px */
|
||||
```
|
||||
|
||||
### Accessibility Utilities
|
||||
|
||||
```css
|
||||
.sr-only /* Visually hidden, screen reader accessible */
|
||||
.sr-only-focusable /* sr-only that becomes visible on focus */
|
||||
.focus-ring /* Focus ring on :focus-visible */
|
||||
.touch-target /* Minimum 44x44px touch target */
|
||||
.skip-link /* Skip to content link */
|
||||
```
|
||||
|
||||
## Alpine.js Stores
|
||||
|
||||
### Theme Store
|
||||
|
||||
```javascript
|
||||
// Access
|
||||
Alpine.store('theme')
|
||||
|
||||
// Properties
|
||||
$store.theme.isDark // Current theme state
|
||||
$store.theme.systemTheme // System preference
|
||||
|
||||
// Methods
|
||||
$store.theme.toggle() // Toggle theme
|
||||
$store.theme.set('dark') // Set specific theme
|
||||
```
|
||||
|
||||
### Toast Store
|
||||
|
||||
```javascript
|
||||
// Show notifications
|
||||
Alpine.store('toast').show('Message', 'success')
|
||||
Alpine.store('toast').success('Success message')
|
||||
Alpine.store('toast').error('Error message')
|
||||
Alpine.store('toast').warning('Warning message')
|
||||
Alpine.store('toast').info('Info message')
|
||||
```
|
||||
|
||||
### Auth Store
|
||||
|
||||
```javascript
|
||||
// Access current user
|
||||
$store.auth.user // User object or null
|
||||
$store.auth.isLoggedIn // Boolean
|
||||
$store.auth.hasPermission('permission_name')
|
||||
```
|
||||
|
||||
### UI Store
|
||||
|
||||
```javascript
|
||||
// Modal management
|
||||
Alpine.store('ui').openModal('modal-id')
|
||||
Alpine.store('ui').closeModal('modal-id')
|
||||
Alpine.store('ui').isModalOpen('modal-id')
|
||||
|
||||
// Sidebar
|
||||
Alpine.store('ui').toggleSidebar()
|
||||
$store.ui.isSidebarOpen
|
||||
```
|
||||
|
||||
## Dark Mode
|
||||
|
||||
Dark mode is automatically supported through CSS custom properties. Toggle with:
|
||||
|
||||
```html
|
||||
<button @click="$store.theme.toggle()">
|
||||
Toggle Theme
|
||||
</button>
|
||||
```
|
||||
|
||||
Or use the theme toggle component in the navbar.
|
||||
|
||||
## Accessibility
|
||||
|
||||
### Focus Management
|
||||
|
||||
All interactive elements have visible focus indicators using `:focus-visible`. Custom focus rings can be added with `.focus-ring`.
|
||||
|
||||
### Reduced Motion
|
||||
|
||||
Animations are automatically disabled for users who prefer reduced motion:
|
||||
|
||||
```css
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
* { animation-duration: 0.01ms !important; }
|
||||
}
|
||||
```
|
||||
|
||||
### Screen Reader Support
|
||||
|
||||
Use `.sr-only` for screen reader text:
|
||||
|
||||
```html
|
||||
<button>
|
||||
<svg>...</svg>
|
||||
<span class="sr-only">Close menu</span>
|
||||
</button>
|
||||
```
|
||||
|
||||
### Touch Targets
|
||||
|
||||
Ensure interactive elements meet minimum touch target size (44x44px):
|
||||
|
||||
```html
|
||||
<button class="touch-target">...</button>
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
Visit `/design-system-test/` (development only) to see all components rendered with their various states and options.
|
||||
|
||||
## Migration from Legacy System
|
||||
|
||||
If migrating from the legacy system:
|
||||
|
||||
1. Replace HSL color variables with design token references
|
||||
2. Replace Font Awesome icons with `{% include "components/ui/icon.html" %}`
|
||||
3. Update button classes from `.btn-primary` to the button component
|
||||
4. Replace inline Alpine.js stores with centralized stores from `stores/index.js`
|
||||
5. Update responsive classes to use new utility classes
|
||||
|
||||
See `MIGRATION.md` for detailed migration steps.
|
||||
Reference in New Issue
Block a user