feat: Add complete Docker deployment with web-based setup wizard
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>
This commit is contained in:
739
INTEGRATION_SNIPPETS.md
Normal file
739
INTEGRATION_SNIPPETS.md
Normal file
@@ -0,0 +1,739 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user