Major additions: - Web-based setup wizard (setup.php, setup_wizard.php, setup-wizard.js) - Production Docker configuration (docker-compose.prod.yml, .env.production) - Database initialization SQL files (deploy/init_settings.sql) - Template builder system with drag-and-drop UI - Advanced features (OAuth, CDN, enhanced analytics, monetization) - Comprehensive documentation (deployment guides, quick start, feature docs) - Design system with accessibility and responsive layout - Deployment automation scripts (deploy.ps1, generate-secrets.ps1) Setup wizard allows customization of: - Platform name and branding - Domain configuration - Membership tiers and pricing - Admin credentials - Feature toggles Database includes 270+ tables for complete video streaming platform with advanced features for analytics, moderation, template building, and monetization. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
740 lines
18 KiB
Markdown
740 lines
18 KiB
Markdown
# EasyStream Design System - Integration Snippets
|
|
|
|
Quick copy-paste snippets to integrate the new design system into EasyStream templates.
|
|
|
|
## Table of Contents
|
|
1. [HTML Head Updates](#html-head-updates)
|
|
2. [Skip Links](#skip-links)
|
|
3. [Theme Switcher UI](#theme-switcher-ui)
|
|
4. [Accessibility Improvements](#accessibility-improvements)
|
|
5. [Responsive Components](#responsive-components)
|
|
|
|
---
|
|
|
|
## HTML Head Updates
|
|
|
|
### Add to Smarty Template Headers
|
|
|
|
**For frontend templates** ([f_templates/tpl_frontend/tpl_head_min.tpl](f_templates/tpl_frontend/tpl_head_min.tpl)):
|
|
|
|
```smarty
|
|
{* Add after existing CSS includes *}
|
|
|
|
<!-- Design System v2.0 -->
|
|
<link rel="stylesheet" href="{$main_url}/f_scripts/shared/design-system.css">
|
|
<link rel="stylesheet" href="{$main_url}/f_scripts/shared/accessibility.css">
|
|
<link rel="stylesheet" href="{$main_url}/f_scripts/shared/responsive.css">
|
|
|
|
<!-- Meta tags for PWA -->
|
|
<meta name="theme-color" content="#06a2cb">
|
|
<meta name="mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
<meta name="apple-mobile-web-app-title" content="EasyStream">
|
|
|
|
<!-- Manifest -->
|
|
<link rel="manifest" href="{$main_url}/manifest.json">
|
|
|
|
<!-- Preload critical fonts -->
|
|
<link rel="preload" as="font" type="font/woff2" crossorigin>
|
|
```
|
|
|
|
### Add to Footer Scripts
|
|
|
|
**For frontend templates** ([f_templates/tpl_frontend/tpl_footerjs_min.tpl](f_templates/tpl_frontend/tpl_footerjs_min.tpl)):
|
|
|
|
```smarty
|
|
{* Add before closing body tag *}
|
|
|
|
<!-- Theme Switcher -->
|
|
<script src="{$main_url}/f_scripts/shared/theme-switcher.js"></script>
|
|
|
|
<!-- Service Worker Registration (already in index.js but ensure it's loaded) -->
|
|
<script>
|
|
if ('serviceWorker' in navigator) {
|
|
navigator.serviceWorker.register('/sw.js?v=2')
|
|
.then(reg => console.log('[SW] Registered'))
|
|
.catch(err => console.error('[SW] Registration failed:', err));
|
|
}
|
|
</script>
|
|
```
|
|
|
|
---
|
|
|
|
## Skip Links
|
|
|
|
### Add to Body Start
|
|
|
|
**Add to** ([f_templates/tpl_frontend/tpl_body.tpl](f_templates/tpl_frontend/tpl_body.tpl:1)) at the very beginning:
|
|
|
|
```smarty
|
|
<body class="fe media-width-768 is-fw{if $is_mobile eq 1} is-mobile{/if}" data-theme="{$theme_name|default:'blue'}">
|
|
|
|
{* Skip links for accessibility *}
|
|
<div class="skip-links" role="navigation" aria-label="Skip links">
|
|
<a href="#main-content" class="skip-to-content">Skip to main content</a>
|
|
<a href="#navigation" class="skip-to-content">Skip to navigation</a>
|
|
<a href="#search" class="skip-to-content">Skip to search</a>
|
|
</div>
|
|
|
|
{* Rest of body content *}
|
|
```
|
|
|
|
### Add Main Content ID
|
|
|
|
**Update main wrapper** in [f_templates/tpl_frontend/tpl_body_main.tpl](f_templates/tpl_frontend/tpl_body_main.tpl):
|
|
|
|
```smarty
|
|
<main id="main-content" role="main" class="container">
|
|
{* Your main content *}
|
|
</main>
|
|
```
|
|
|
|
---
|
|
|
|
## Theme Switcher UI
|
|
|
|
### Option 1: Add to Header Navigation
|
|
|
|
**Add to** [f_templates/tpl_frontend/tpl_header/tpl_headernav_yt.tpl](f_templates/tpl_frontend/tpl_header/tpl_headernav_yt.tpl):
|
|
|
|
```smarty
|
|
{* Add to header navigation area *}
|
|
<div class="header-controls">
|
|
{* Theme toggle button *}
|
|
<button
|
|
id="theme-toggle"
|
|
class="btn btn-secondary touch-target"
|
|
aria-label="Toggle dark mode"
|
|
title="Toggle dark mode">
|
|
<i class="icon-moon"></i>
|
|
<span class="sr-only">Toggle theme</span>
|
|
</button>
|
|
|
|
{* Existing notification bell, user menu, etc. *}
|
|
</div>
|
|
```
|
|
|
|
### Option 2: Full Theme Picker Modal
|
|
|
|
Create new template: `f_templates/tpl_frontend/tpl_theme_picker.tpl`
|
|
|
|
```smarty
|
|
{* Theme Picker Modal *}
|
|
<div id="theme-picker-modal" class="modal" role="dialog" aria-labelledby="theme-modal-title" aria-hidden="true">
|
|
<div class="modal-backdrop" data-dismiss="modal"></div>
|
|
<div class="modal-content card">
|
|
<div class="modal-header">
|
|
<h2 id="theme-modal-title" class="text-xl font-semibold">Appearance Settings</h2>
|
|
<button class="modal-close" data-dismiss="modal" aria-label="Close">
|
|
<i class="icon-close"></i>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="modal-body p-lg">
|
|
{* Theme mode toggle *}
|
|
<div class="theme-setting">
|
|
<label class="theme-label flex justify-between items-center">
|
|
<span class="font-medium">Theme Mode</span>
|
|
<button id="theme-toggle" class="btn btn-secondary touch-target" aria-label="Toggle theme mode">
|
|
<i class="icon-moon"></i>
|
|
</button>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="hr m-y-md"></div>
|
|
|
|
{* Color picker *}
|
|
<div class="theme-setting">
|
|
<span class="theme-label font-medium block m-b-sm">Color Theme</span>
|
|
<div class="color-options flex gap-sm flex-wrap" role="group" aria-label="Color themes">
|
|
<button class="color-btn color-blue touch-target" data-color-theme="blue" aria-label="Blue theme" title="Blue">
|
|
<span class="sr-only">Blue</span>
|
|
</button>
|
|
<button class="color-btn color-red touch-target" data-color-theme="red" aria-label="Red theme" title="Red">
|
|
<span class="sr-only">Red</span>
|
|
</button>
|
|
<button class="color-btn color-cyan touch-target" data-color-theme="cyan" aria-label="Cyan theme" title="Cyan">
|
|
<span class="sr-only">Cyan</span>
|
|
</button>
|
|
<button class="color-btn color-green touch-target" data-color-theme="green" aria-label="Green theme" title="Green">
|
|
<span class="sr-only">Green</span>
|
|
</button>
|
|
<button class="color-btn color-orange touch-target" data-color-theme="orange" aria-label="Orange theme" title="Orange">
|
|
<span class="sr-only">Orange</span>
|
|
</button>
|
|
<button class="color-btn color-pink touch-target" data-color-theme="pink" aria-label="Pink theme" title="Pink">
|
|
<span class="sr-only">Pink</span>
|
|
</button>
|
|
<button class="color-btn color-purple touch-target" data-color-theme="purple" aria-label="Purple theme" title="Purple">
|
|
<span class="sr-only">Purple</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.color-btn {
|
|
width: 44px;
|
|
height: 44px;
|
|
border-radius: var(--border-radius-full);
|
|
border: 3px solid transparent;
|
|
cursor: pointer;
|
|
transition: all var(--transition-base);
|
|
position: relative;
|
|
}
|
|
|
|
.color-btn:hover {
|
|
transform: scale(1.1);
|
|
box-shadow: var(--shadow-md);
|
|
}
|
|
|
|
.color-btn.active {
|
|
border-color: var(--color-text-primary);
|
|
box-shadow: var(--shadow-lg);
|
|
}
|
|
|
|
.color-btn.active::after {
|
|
content: '✓';
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
color: white;
|
|
font-weight: bold;
|
|
font-size: 1.25rem;
|
|
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
|
|
}
|
|
|
|
.color-blue { background: #06a2cb; }
|
|
.color-red { background: #dd1e2f; }
|
|
.color-cyan { background: #00997a; }
|
|
.color-green { background: #199900; }
|
|
.color-orange { background: #f28410; }
|
|
.color-pink { background: #ec7ab9; }
|
|
.color-purple { background: #b25c8b; }
|
|
</style>
|
|
```
|
|
|
|
---
|
|
|
|
## Accessibility Improvements
|
|
|
|
### Form Labels
|
|
|
|
**Before:**
|
|
```html
|
|
<input type="text" name="username" placeholder="Username">
|
|
```
|
|
|
|
**After:**
|
|
```html
|
|
<label for="username" class="font-medium m-b-xs">
|
|
Username
|
|
<span class="required" aria-label="required">*</span>
|
|
</label>
|
|
<input
|
|
type="text"
|
|
id="username"
|
|
name="username"
|
|
class="input"
|
|
aria-required="true"
|
|
aria-describedby="username-error">
|
|
<div id="username-error" class="error-message" role="alert" style="display: none;">
|
|
Please enter a username
|
|
</div>
|
|
```
|
|
|
|
### Image Alt Text
|
|
|
|
**Before:**
|
|
```smarty
|
|
<img src="{$video.thumbnail}">
|
|
```
|
|
|
|
**After:**
|
|
```smarty
|
|
<img
|
|
src="{$video.thumbnail}"
|
|
alt="{$video.title|escape} - Thumbnail"
|
|
loading="lazy"
|
|
width="320"
|
|
height="180">
|
|
```
|
|
|
|
### Button Accessibility
|
|
|
|
**Before:**
|
|
```html
|
|
<button onclick="likeVideo()">
|
|
<i class="icon-like"></i>
|
|
</button>
|
|
```
|
|
|
|
**After:**
|
|
```html
|
|
<button
|
|
onclick="likeVideo()"
|
|
class="btn btn-secondary touch-target"
|
|
aria-label="Like this video"
|
|
aria-pressed="false">
|
|
<i class="icon-like" aria-hidden="true"></i>
|
|
<span class="sr-only">Like</span>
|
|
</button>
|
|
```
|
|
|
|
### Heading Hierarchy
|
|
|
|
**Before:**
|
|
```html
|
|
<div class="title">Featured Videos</div>
|
|
<div class="video-title">My Video</div>
|
|
```
|
|
|
|
**After:**
|
|
```html
|
|
<h2 class="content-title text-2xl font-semibold">Featured Videos</h2>
|
|
<h3 class="video-title text-lg">My Video</h3>
|
|
```
|
|
|
|
### ARIA Landmarks
|
|
|
|
**Add to templates:**
|
|
|
|
```smarty
|
|
<header role="banner">
|
|
{* Header content *}
|
|
</header>
|
|
|
|
<nav role="navigation" aria-label="Main navigation">
|
|
{* Navigation menu *}
|
|
</nav>
|
|
|
|
<main role="main" id="main-content">
|
|
{* Main content *}
|
|
</main>
|
|
|
|
<aside role="complementary" aria-label="Sidebar">
|
|
{* Sidebar content *}
|
|
</aside>
|
|
|
|
<footer role="contentinfo">
|
|
{* Footer content *}
|
|
</footer>
|
|
```
|
|
|
|
---
|
|
|
|
## Responsive Components
|
|
|
|
### Video Grid
|
|
|
|
**Before:**
|
|
```smarty
|
|
<div class="thumbs-wrapper">
|
|
{foreach from=$videos item=video}
|
|
<div class="vs-column">
|
|
{* Video thumbnail *}
|
|
</div>
|
|
{/foreach}
|
|
</div>
|
|
```
|
|
|
|
**After:**
|
|
```smarty
|
|
<div class="video-grid">
|
|
{foreach from=$videos item=video}
|
|
<article class="video-card">
|
|
<a href="{$video.url}" class="video-link">
|
|
<div class="aspect-video">
|
|
<img
|
|
src="{$video.thumbnail}"
|
|
alt="{$video.title|escape} - Thumbnail"
|
|
loading="lazy"
|
|
class="video-thumbnail">
|
|
</div>
|
|
<div class="video-info p-sm">
|
|
<h3 class="video-title text-md font-medium">{$video.title}</h3>
|
|
<p class="video-meta text-sm text-secondary">
|
|
<span>{$video.views} views</span>
|
|
<span aria-hidden="true">•</span>
|
|
<span>{$video.date}</span>
|
|
</p>
|
|
</div>
|
|
</a>
|
|
</article>
|
|
{/foreach}
|
|
</div>
|
|
```
|
|
|
|
### Responsive Container
|
|
|
|
**Before:**
|
|
```html
|
|
<div class="inner-block">
|
|
{* Content *}
|
|
</div>
|
|
```
|
|
|
|
**After:**
|
|
```html
|
|
<div class="container">
|
|
{* Content auto-sizes with padding *}
|
|
</div>
|
|
```
|
|
|
|
### Flex Layout
|
|
|
|
**Before:**
|
|
```html
|
|
<div style="display: flex; justify-content: space-between; align-items: center;">
|
|
<div>{$title}</div>
|
|
<div>{$actions}</div>
|
|
</div>
|
|
```
|
|
|
|
**After:**
|
|
```html
|
|
<div class="flex justify-between items-center gap-md">
|
|
<div>{$title}</div>
|
|
<div>{$actions}</div>
|
|
</div>
|
|
```
|
|
|
|
### Responsive Text
|
|
|
|
**Before:**
|
|
```html
|
|
<h1 style="font-size: 36px;">{$title}</h1>
|
|
```
|
|
|
|
**After:**
|
|
```html
|
|
<h1 class="text-responsive-xl font-bold">{$title}</h1>
|
|
```
|
|
|
|
### Responsive Spacing
|
|
|
|
**Before:**
|
|
```html
|
|
<div style="padding: 16px; margin-bottom: 24px;">
|
|
{* Content *}
|
|
</div>
|
|
```
|
|
|
|
**After:**
|
|
```html
|
|
<div class="p-responsive m-b-lg">
|
|
{* Content *}
|
|
</div>
|
|
```
|
|
|
|
### Card Component
|
|
|
|
**New pattern:**
|
|
```html
|
|
<div class="card shadow-md">
|
|
<div class="card-header p-md">
|
|
<h2 class="text-lg font-semibold">Card Title</h2>
|
|
</div>
|
|
<div class="card-body p-lg">
|
|
{* Card content *}
|
|
</div>
|
|
<div class="card-footer p-md">
|
|
<button class="btn btn-primary">Action</button>
|
|
</div>
|
|
</div>
|
|
```
|
|
|
|
### Alert Messages
|
|
|
|
**Before:**
|
|
```smarty
|
|
{if $error_message}
|
|
<div class="error-message-text">{$error_message}</div>
|
|
{/if}
|
|
```
|
|
|
|
**After:**
|
|
```smarty
|
|
{if $error_message}
|
|
<div class="alert alert-error" role="alert">
|
|
<i class="icon-warning" aria-hidden="true"></i>
|
|
<span>{$error_message}</span>
|
|
</div>
|
|
{/if}
|
|
|
|
{if $success_message}
|
|
<div class="alert alert-success" role="alert">
|
|
<i class="icon-check" aria-hidden="true"></i>
|
|
<span>{$success_message}</span>
|
|
</div>
|
|
{/if}
|
|
```
|
|
|
|
---
|
|
|
|
## JavaScript Enhancements
|
|
|
|
### Theme Switcher Events
|
|
|
|
```javascript
|
|
// Listen for theme changes
|
|
document.addEventListener('easystream:theme-change', (e) => {
|
|
console.log('Theme changed:', e.detail);
|
|
// Update other components if needed
|
|
});
|
|
|
|
// Programmatically change theme
|
|
window.themeSwitcher.toggleMode(); // Toggle light/dark
|
|
window.themeSwitcher.setColor('red'); // Change color
|
|
|
|
// Get current theme
|
|
const theme = window.themeSwitcher.getCurrentTheme();
|
|
console.log(theme); // { mode: 'dark', color: 'blue', ... }
|
|
```
|
|
|
|
### Service Worker Updates
|
|
|
|
```javascript
|
|
// Update service worker
|
|
if ('serviceWorker' in navigator) {
|
|
navigator.serviceWorker.register('/sw.js?v=2')
|
|
.then(reg => {
|
|
// Check for updates
|
|
reg.update();
|
|
|
|
// Listen for updates
|
|
reg.addEventListener('updatefound', () => {
|
|
const newWorker = reg.installing;
|
|
newWorker.addEventListener('statechange', () => {
|
|
if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
|
|
// New version available
|
|
if (confirm('New version available! Reload to update?')) {
|
|
window.location.reload();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
});
|
|
}
|
|
```
|
|
|
|
### Offline Detection
|
|
|
|
```javascript
|
|
// Detect online/offline
|
|
window.addEventListener('online', () => {
|
|
console.log('Back online!');
|
|
// Show success message
|
|
showNotification('You are back online', 'success');
|
|
});
|
|
|
|
window.addEventListener('offline', () => {
|
|
console.log('Gone offline');
|
|
// Show warning message
|
|
showNotification('You are offline. Some features may be unavailable.', 'warning');
|
|
});
|
|
|
|
function showNotification(message, type) {
|
|
const alert = document.createElement('div');
|
|
alert.className = `alert alert-${type}`;
|
|
alert.textContent = message;
|
|
alert.role = 'alert';
|
|
document.body.appendChild(alert);
|
|
|
|
setTimeout(() => alert.remove(), 5000);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Testing Snippets
|
|
|
|
### Check Accessibility
|
|
|
|
```javascript
|
|
// Check for images without alt text
|
|
const imagesWithoutAlt = document.querySelectorAll('img:not([alt])');
|
|
console.log('Images missing alt text:', imagesWithoutAlt.length);
|
|
|
|
// Check for buttons without labels
|
|
const buttonsWithoutLabel = document.querySelectorAll('button:not([aria-label]):not(:has(.sr-only))');
|
|
console.log('Buttons missing labels:', buttonsWithoutLabel.length);
|
|
|
|
// Check heading hierarchy
|
|
const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
|
|
headings.forEach(h => console.log(h.tagName, h.textContent.substring(0, 50)));
|
|
```
|
|
|
|
### Check Contrast Ratios
|
|
|
|
```javascript
|
|
// Check text contrast (simplified)
|
|
function checkContrast(element) {
|
|
const style = getComputedStyle(element);
|
|
const color = style.color;
|
|
const bgColor = style.backgroundColor;
|
|
console.log(`Element: ${element.tagName}`, { color, bgColor });
|
|
}
|
|
|
|
// Check all text elements
|
|
document.querySelectorAll('p, h1, h2, h3, h4, h5, h6, a, button, span').forEach(checkContrast);
|
|
```
|
|
|
|
### Test Keyboard Navigation
|
|
|
|
```javascript
|
|
// Highlight focusable elements
|
|
document.querySelectorAll('a, button, input, select, textarea, [tabindex]').forEach(el => {
|
|
el.style.outline = '2px solid red';
|
|
});
|
|
|
|
// Tab order test
|
|
let tabIndex = 0;
|
|
document.addEventListener('focus', (e) => {
|
|
console.log(`Tab ${++tabIndex}:`, e.target);
|
|
}, true);
|
|
```
|
|
|
|
---
|
|
|
|
## Common Patterns
|
|
|
|
### Modal Dialog
|
|
|
|
```html
|
|
<div id="my-modal" class="modal" role="dialog" aria-labelledby="modal-title" aria-hidden="true">
|
|
<div class="modal-backdrop" data-dismiss="modal"></div>
|
|
<div class="modal-content card shadow-xl">
|
|
<div class="modal-header p-md flex justify-between items-center">
|
|
<h2 id="modal-title" class="text-xl font-semibold">Modal Title</h2>
|
|
<button class="modal-close btn btn-secondary" data-dismiss="modal" aria-label="Close">
|
|
<i class="icon-close"></i>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body p-lg">
|
|
{* Modal content *}
|
|
</div>
|
|
<div class="modal-footer p-md flex justify-end gap-sm">
|
|
<button class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
|
<button class="btn btn-primary">Confirm</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
```
|
|
|
|
### Dropdown Menu
|
|
|
|
```html
|
|
<div class="dropdown">
|
|
<button
|
|
class="btn btn-secondary dropdown-toggle touch-target"
|
|
aria-haspopup="true"
|
|
aria-expanded="false"
|
|
id="dropdown-menu-btn">
|
|
Menu <i class="icon-chevron-down"></i>
|
|
</button>
|
|
<ul
|
|
class="dropdown-menu"
|
|
role="menu"
|
|
aria-labelledby="dropdown-menu-btn"
|
|
hidden>
|
|
<li role="none">
|
|
<a href="#" role="menuitem" class="dropdown-item">Option 1</a>
|
|
</li>
|
|
<li role="none">
|
|
<a href="#" role="menuitem" class="dropdown-item">Option 2</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
```
|
|
|
|
### Loading Spinner
|
|
|
|
```html
|
|
<div class="loading-spinner" role="status" aria-live="polite">
|
|
<i class="icon-spinner spinner"></i>
|
|
<span class="sr-only">Loading...</span>
|
|
</div>
|
|
```
|
|
|
|
### Breadcrumbs
|
|
|
|
```html
|
|
<nav aria-label="Breadcrumb">
|
|
<ol class="breadcrumb flex gap-xs items-center">
|
|
<li><a href="/">Home</a></li>
|
|
<li aria-hidden="true">/</li>
|
|
<li><a href="/videos">Videos</a></li>
|
|
<li aria-hidden="true">/</li>
|
|
<li aria-current="page">Current Page</li>
|
|
</ol>
|
|
</nav>
|
|
```
|
|
|
|
---
|
|
|
|
## Quick Reference
|
|
|
|
### Class Names Cheat Sheet
|
|
|
|
**Spacing:**
|
|
- `m-xs`, `m-sm`, `m-md`, `m-lg` - Margins
|
|
- `p-xs`, `p-sm`, `p-md`, `p-lg` - Padding
|
|
|
|
**Typography:**
|
|
- `text-xs`, `text-sm`, `text-md`, `text-lg`, `text-xl` - Font sizes
|
|
- `font-light`, `font-normal`, `font-medium`, `font-bold` - Font weights
|
|
|
|
**Layout:**
|
|
- `flex`, `flex-col`, `flex-wrap` - Flexbox
|
|
- `grid`, `grid-cols-{n}` - Grid
|
|
- `container` - Responsive container
|
|
|
|
**Display:**
|
|
- `hidden`, `block`, `flex` - Display
|
|
- `xs:hidden`, `md:block` - Responsive display
|
|
|
|
**Colors:**
|
|
- `text-primary`, `text-secondary` - Text colors
|
|
- `bg-primary`, `bg-secondary` - Background colors
|
|
|
|
**Borders:**
|
|
- `rounded-sm`, `rounded-md`, `rounded-lg`, `rounded-full` - Border radius
|
|
|
|
**Shadows:**
|
|
- `shadow-sm`, `shadow-md`, `shadow-lg` - Box shadows
|
|
|
|
**Accessibility:**
|
|
- `sr-only` - Screen reader only
|
|
- `touch-target` - Minimum touch size
|
|
- `focus-visible` - Focus indicator
|
|
|
|
---
|
|
|
|
## Migration Checklist
|
|
|
|
- [ ] Include new CSS files in templates
|
|
- [ ] Include theme-switcher.js
|
|
- [ ] Add skip links to body
|
|
- [ ] Add main content ID
|
|
- [ ] Update navigation with theme toggle
|
|
- [ ] Replace inline styles with utility classes
|
|
- [ ] Add alt text to all images
|
|
- [ ] Add ARIA labels to buttons
|
|
- [ ] Add labels to form inputs
|
|
- [ ] Fix heading hierarchy
|
|
- [ ] Add ARIA landmarks
|
|
- [ ] Test keyboard navigation
|
|
- [ ] Test with screen reader
|
|
- [ ] Test on mobile devices
|
|
- [ ] Test all theme combinations
|
|
- [ ] Run Lighthouse audit
|
|
|
|
---
|
|
|
|
**Next Steps:** See [DESIGN_SYSTEM_GUIDE.md](DESIGN_SYSTEM_GUIDE.md) for complete documentation.
|