Enable Discovery debug logging for production troubleshooting

- Add DISCOVERY_LOG_LEVEL=debug
- Add DISCOVERY_SHOW_PROGRESS=true
- Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
2025-08-11 20:13:26 +02:00
parent 59fd3dd3b1
commit 55a330b223
3683 changed files with 2956207 additions and 16948 deletions

View File

@@ -0,0 +1,610 @@
# Admin Design System
> Comprehensive design system for administrative interfaces with modern UI patterns, accessibility standards, and developer efficiency.
## 🎯 Design Principles
### User Experience
- **Clarity First** - Information hierarchy and visual clarity over decoration
- **Efficiency** - Minimize cognitive load and interaction friction
- **Consistency** - Predictable patterns and behaviors across all interfaces
- **Accessibility** - WCAG 2.1 AA compliance and inclusive design
### Technical Excellence
- **Performance** - Fast load times and smooth interactions
- **Maintainability** - Modular, reusable components
- **Scalability** - Adaptable to growing feature requirements
- **Developer Experience** - Clear documentation and easy implementation
## 🎨 Visual Language
### Color System
```css
/* Primary Admin Palette */
--admin-primary: #6366f1; /* Indigo - Primary actions */
--admin-primary-hover: #5855eb; /* Hover states */
--admin-primary-active: #4f46e5; /* Active states */
--admin-primary-light: #a5b4fc; /* Backgrounds */
/* Semantic Colors */
--admin-success: #10b981; /* Success states */
--admin-warning: #f59e0b; /* Warning states */
--admin-error: #ef4444; /* Error states */
--admin-info: #3b82f6; /* Information */
/* Neutral System */
--admin-gray-50: #f8fafc; /* Lightest backgrounds */
--admin-gray-100: #f1f5f9; /* Light backgrounds */
--admin-gray-200: #e2e8f0; /* Borders */
--admin-gray-300: #cbd5e1; /* Disabled states */
--admin-gray-400: #94a3b8; /* Placeholders */
--admin-gray-500: #64748b; /* Secondary text */
--admin-gray-600: #475569; /* Primary text */
--admin-gray-700: #334155; /* Headings */
--admin-gray-800: #1e293b; /* Dark text */
--admin-gray-900: #0f172a; /* Darkest elements */
/* Dark Theme */
--admin-dark-bg: #0f172a;
--admin-dark-surface: #1e293b;
--admin-dark-border: #334155;
--admin-dark-text: #f1f5f9;
```
### Typography
```css
/* Font Stacks */
--admin-font-sans: 'Inter', system-ui, -apple-system, sans-serif;
--admin-font-mono: 'SF Mono', 'Monaco', 'Cascadia Code', monospace;
/* Type Scale */
--admin-text-xs: 0.75rem; /* 12px - Small labels */
--admin-text-sm: 0.875rem; /* 14px - Body text */
--admin-text-base: 1rem; /* 16px - Default */
--admin-text-lg: 1.125rem; /* 18px - Large body */
--admin-text-xl: 1.25rem; /* 20px - Small headings */
--admin-text-2xl: 1.5rem; /* 24px - Section headings */
--admin-text-3xl: 1.875rem; /* 30px - Page titles */
--admin-text-4xl: 2.25rem; /* 36px - Large titles */
/* Font Weights */
--admin-font-light: 300;
--admin-font-normal: 400;
--admin-font-medium: 500;
--admin-font-semibold: 600;
--admin-font-bold: 700;
```
### Spacing System
```css
/* 4px base unit scaling */
--admin-space-0: 0;
--admin-space-1: 0.25rem; /* 4px */
--admin-space-2: 0.5rem; /* 8px */
--admin-space-3: 0.75rem; /* 12px */
--admin-space-4: 1rem; /* 16px */
--admin-space-5: 1.25rem; /* 20px */
--admin-space-6: 1.5rem; /* 24px */
--admin-space-8: 2rem; /* 32px */
--admin-space-10: 2.5rem; /* 40px */
--admin-space-12: 3rem; /* 48px */
--admin-space-16: 4rem; /* 64px */
--admin-space-20: 5rem; /* 80px */
--admin-space-24: 6rem; /* 96px */
```
### Elevation & Shadows
```css
/* Shadow System */
--admin-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
--admin-shadow-base: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
--admin-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--admin-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
--admin-shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
/* Border Radius */
--admin-radius-none: 0;
--admin-radius-sm: 0.125rem; /* 2px */
--admin-radius-base: 0.25rem; /* 4px */
--admin-radius-md: 0.375rem; /* 6px */
--admin-radius-lg: 0.5rem; /* 8px */
--admin-radius-xl: 0.75rem; /* 12px */
--admin-radius-2xl: 1rem; /* 16px */
--admin-radius-full: 9999px; /* Pill shape */
```
## 🏗 Layout System
### Grid Foundation
```css
/* Admin Layout Grid */
.admin-layout {
display: grid;
grid-template-areas:
"header header"
"nav main"
"nav footer";
grid-template-columns: 250px 1fr;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
.admin-header { grid-area: header; }
.admin-nav { grid-area: nav; }
.admin-main { grid-area: main; }
.admin-footer { grid-area: footer; }
/* Responsive Adaptations */
@media (max-width: 768px) {
.admin-layout {
grid-template-areas:
"header"
"main"
"footer";
grid-template-columns: 1fr;
}
.admin-nav {
transform: translateX(-100%);
transition: transform 0.3s ease;
}
.admin-nav.is-open {
transform: translateX(0);
}
}
```
### Content Layout
```css
/* Page Structure */
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--admin-space-6) 0;
border-bottom: 1px solid var(--admin-gray-200);
margin-bottom: var(--admin-space-6);
}
.page-content {
max-width: none;
padding: 0;
}
/* Content Sections */
.admin-section {
background: var(--admin-surface);
border: 1px solid var(--admin-border);
border-radius: var(--admin-radius-lg);
padding: var(--admin-space-6);
margin-bottom: var(--admin-space-6);
}
.admin-section + .admin-section {
margin-top: var(--admin-space-8);
}
```
## 🧩 Component Architecture
### Base Component Classes
```css
/* Button System */
.admin-button {
display: inline-flex;
align-items: center;
gap: var(--admin-space-2);
padding: var(--admin-space-2) var(--admin-space-4);
border: 1px solid transparent;
border-radius: var(--admin-radius-md);
font-family: var(--admin-font-sans);
font-size: var(--admin-text-sm);
font-weight: var(--admin-font-medium);
line-height: 1.5;
text-decoration: none;
cursor: pointer;
transition: all 0.15s ease;
&:focus {
outline: 2px solid var(--admin-primary);
outline-offset: 2px;
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
}
/* Button Variants */
.admin-button--primary {
background: var(--admin-primary);
color: white;
&:hover:not(:disabled) {
background: var(--admin-primary-hover);
}
}
.admin-button--secondary {
background: var(--admin-gray-100);
color: var(--admin-gray-700);
border-color: var(--admin-gray-200);
&:hover:not(:disabled) {
background: var(--admin-gray-200);
}
}
.admin-button--ghost {
background: transparent;
color: var(--admin-gray-600);
&:hover:not(:disabled) {
background: var(--admin-gray-100);
}
}
```
### Form Components
```css
/* Input System */
.admin-input {
display: block;
width: 100%;
padding: var(--admin-space-3);
border: 1px solid var(--admin-gray-300);
border-radius: var(--admin-radius-md);
font-family: var(--admin-font-sans);
font-size: var(--admin-text-sm);
line-height: 1.5;
background: white;
transition: all 0.15s ease;
&:focus {
outline: none;
border-color: var(--admin-primary);
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
}
&:disabled {
background: var(--admin-gray-50);
color: var(--admin-gray-400);
cursor: not-allowed;
}
&.is-error {
border-color: var(--admin-error);
&:focus {
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
}
}
}
/* Form Groups */
.admin-form-group {
margin-bottom: var(--admin-space-4);
}
.admin-label {
display: block;
margin-bottom: var(--admin-space-2);
font-size: var(--admin-text-sm);
font-weight: var(--admin-font-medium);
color: var(--admin-gray-700);
}
.admin-help-text {
margin-top: var(--admin-space-1);
font-size: var(--admin-text-xs);
color: var(--admin-gray-500);
}
.admin-error-text {
margin-top: var(--admin-space-1);
font-size: var(--admin-text-xs);
color: var(--admin-error);
}
```
### Data Display Components
```css
/* Stats Cards */
.admin-stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: var(--admin-space-6);
margin-bottom: var(--admin-space-8);
}
.admin-stat-card {
background: var(--admin-surface);
border: 1px solid var(--admin-border);
border-radius: var(--admin-radius-lg);
padding: var(--admin-space-6);
&:hover {
border-color: var(--admin-primary-light);
transform: translateY(-1px);
box-shadow: var(--admin-shadow-md);
}
}
.admin-stat-label {
display: block;
font-size: var(--admin-text-sm);
font-weight: var(--admin-font-medium);
color: var(--admin-gray-600);
margin-bottom: var(--admin-space-2);
}
.admin-stat-value {
font-size: var(--admin-text-3xl);
font-weight: var(--admin-font-bold);
color: var(--admin-gray-900);
line-height: 1;
}
.admin-stat-trend {
margin-top: var(--admin-space-2);
font-size: var(--admin-text-xs);
&.is-positive { color: var(--admin-success); }
&.is-negative { color: var(--admin-error); }
&.is-neutral { color: var(--admin-gray-500); }
}
```
### Tables
```css
/* Admin Tables */
.admin-table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
background: var(--admin-surface);
border: 1px solid var(--admin-border);
border-radius: var(--admin-radius-lg);
overflow: hidden;
}
.admin-table th {
background: var(--admin-gray-50);
padding: var(--admin-space-4);
text-align: left;
font-size: var(--admin-text-xs);
font-weight: var(--admin-font-semibold);
color: var(--admin-gray-600);
text-transform: uppercase;
letter-spacing: 0.05em;
border-bottom: 1px solid var(--admin-border);
&[data-sort] {
cursor: pointer;
user-select: none;
&:hover {
background: var(--admin-gray-100);
}
&.is-sorted-asc::after {
content: " ↑";
color: var(--admin-primary);
}
&.is-sorted-desc::after {
content: " ↓";
color: var(--admin-primary);
}
}
}
.admin-table td {
padding: var(--admin-space-4);
border-bottom: 1px solid var(--admin-gray-100);
font-size: var(--admin-text-sm);
color: var(--admin-gray-700);
}
.admin-table tbody tr:hover {
background: var(--admin-gray-50);
}
.admin-table tbody tr:last-child td {
border-bottom: none;
}
```
## 🌓 Dark Mode Support
```css
/* Dark Theme Variables */
[data-theme="dark"] {
--admin-surface: var(--admin-dark-surface);
--admin-border: var(--admin-dark-border);
--admin-text: var(--admin-dark-text);
--admin-bg: var(--admin-dark-bg);
/* Component Adaptations */
--admin-gray-50: #334155;
--admin-gray-100: #475569;
--admin-gray-200: #64748b;
--admin-gray-600: #cbd5e1;
--admin-gray-700: #e2e8f0;
--admin-gray-900: var(--admin-dark-text);
}
/* Theme Toggle Component */
.admin-theme-toggle {
position: relative;
width: 48px;
height: 24px;
background: var(--admin-gray-200);
border: none;
border-radius: var(--admin-radius-full);
cursor: pointer;
transition: background 0.2s ease;
&::after {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 20px;
height: 20px;
background: white;
border-radius: 50%;
transition: transform 0.2s ease;
}
&.is-dark {
background: var(--admin-primary);
&::after {
transform: translateX(24px);
}
}
}
```
## ♿ Accessibility Standards
### Focus Management
```css
/* Focus Styles */
.admin-focus-visible {
outline: 2px solid var(--admin-primary);
outline-offset: 2px;
border-radius: var(--admin-radius-sm);
}
/* Skip Links */
.admin-skip-link {
position: absolute;
top: -40px;
left: 6px;
background: var(--admin-primary);
color: white;
padding: 8px;
text-decoration: none;
border-radius: var(--admin-radius-md);
z-index: 1000;
&:focus {
top: 6px;
}
}
```
### ARIA Support
```html
<!-- Navigation with proper ARIA -->
<nav class="admin-nav" role="navigation" aria-label="Main navigation">
<ul role="menubar">
<li role="none">
<a href="/admin" role="menuitem" aria-current="page">Dashboard</a>
</li>
</ul>
</nav>
<!-- Data tables with proper headers -->
<table class="admin-table" role="table" aria-label="User data">
<thead>
<tr role="row">
<th role="columnheader" aria-sort="ascending">Name</th>
<th role="columnheader">Email</th>
</tr>
</thead>
<tbody role="rowgroup">
<tr role="row">
<td role="gridcell">John Doe</td>
<td role="gridcell">john@example.com</td>
</tr>
</tbody>
</table>
```
## 📱 Responsive Behavior
### Breakpoint System
```css
/* Mobile First Breakpoints */
.admin-responsive {
/* Mobile (default) */
padding: var(--admin-space-4);
/* Tablet */
@media (min-width: 768px) {
padding: var(--admin-space-6);
}
/* Desktop */
@media (min-width: 1024px) {
padding: var(--admin-space-8);
}
/* Large Desktop */
@media (min-width: 1280px) {
padding: var(--admin-space-12);
}
}
/* Navigation Adaptations */
@media (max-width: 767px) {
.admin-nav {
position: fixed;
top: 0;
left: 0;
width: 280px;
height: 100vh;
background: var(--admin-surface);
border-right: 1px solid var(--admin-border);
transform: translateX(-100%);
transition: transform 0.3s ease;
z-index: 1000;
&.is-open {
transform: translateX(0);
}
}
.admin-nav-overlay {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5);
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
z-index: 999;
&.is-active {
opacity: 1;
visibility: visible;
}
}
}
```
---
*For implementation examples, see [Admin Components](components.md)*
*For JavaScript integration, see [JavaScript Modules](../javascript.md)*
*For performance guidelines, see [CSS Architecture](../css-architecture.md)*

View File

@@ -0,0 +1,471 @@
# UI Components
> Component library documentation and usage examples for the design system.
## 🧩 Component Architecture
All components follow a consistent structure with design tokens, accessibility standards, and responsive behavior.
### Base Component Pattern
```html
<div class="component-name" data-component="name" role="[role]" aria-label="[description]">
<div class="component-name__element">
<!-- Component content -->
</div>
</div>
```
### Component CSS Structure
```css
/* Block */
.component-name {
/* Base styles using design tokens */
}
/* Element */
.component-name__element {
/* Element styles */
}
/* Modifier */
.component-name--variant {
/* Variant styles */
}
/* State */
.component-name.is-active {
/* State styles */
}
```
## 📋 Form Components
### Buttons
Basic button implementation with variants:
```html
<!-- Primary Button -->
<button class="btn btn--primary" type="button">
Primary Action
</button>
<!-- Secondary Button -->
<button class="btn btn--secondary" type="button">
Secondary Action
</button>
<!-- Ghost Button -->
<button class="btn btn--ghost" type="button">
Ghost Action
</button>
```
**CSS Implementation:**
```css
.btn {
display: inline-flex;
align-items: center;
gap: var(--space-2);
padding: var(--space-3) var(--space-4);
border: 1px solid transparent;
border-radius: var(--radius-md);
font-family: var(--font-family-sans);
font-size: var(--text-sm);
font-weight: var(--font-medium);
text-decoration: none;
cursor: pointer;
transition: all var(--duration-150) var(--ease-out);
&:focus-visible {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
}
.btn--primary {
background: var(--color-primary);
color: white;
&:hover:not(:disabled) {
background: var(--color-primary-600);
}
}
.btn--secondary {
background: var(--color-gray-100);
color: var(--color-gray-700);
border-color: var(--color-gray-200);
&:hover:not(:disabled) {
background: var(--color-gray-200);
}
}
.btn--ghost {
background: transparent;
color: var(--color-gray-600);
&:hover:not(:disabled) {
background: var(--color-gray-100);
}
}
```
### Input Fields
Form input components with validation states:
```html
<div class="form-group">
<label class="form-label" for="example-input">
Field Label
</label>
<input
class="form-input"
type="text"
id="example-input"
placeholder="Enter text..."
aria-describedby="example-help"
/>
<div class="form-help" id="example-help">
Optional help text for this field
</div>
</div>
<!-- Error State -->
<div class="form-group">
<label class="form-label" for="error-input">
Field with Error
</label>
<input
class="form-input form-input--error"
type="text"
id="error-input"
aria-invalid="true"
aria-describedby="error-message"
/>
<div class="form-error" id="error-message">
This field is required
</div>
</div>
```
## 🎭 Layout Components
### Cards
Content containers with consistent styling:
```html
<div class="card">
<div class="card__header">
<h3 class="card__title">Card Title</h3>
<div class="card__actions">
<button class="btn btn--ghost">Action</button>
</div>
</div>
<div class="card__body">
<p>Card content goes here...</p>
</div>
<div class="card__footer">
<small class="text-muted">Footer information</small>
</div>
</div>
```
### Modals
Accessible modal dialogs:
```html
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="modal-title">
<div class="modal__overlay" data-modal-close></div>
<div class="modal__content">
<div class="modal__header">
<h2 class="modal__title" id="modal-title">Modal Title</h2>
<button class="modal__close" data-modal-close aria-label="Close modal">
×
</button>
</div>
<div class="modal__body">
<p>Modal content...</p>
</div>
<div class="modal__footer">
<button class="btn btn--primary">Confirm</button>
<button class="btn btn--secondary" data-modal-close>Cancel</button>
</div>
</div>
</div>
```
## 📊 Data Display
### Tables
Data tables with sorting and filtering:
```html
<div class="table-container">
<table class="table">
<thead>
<tr>
<th data-sort="name" class="table__header--sortable">
Name
<span class="table__sort-indicator"></span>
</th>
<th data-sort="email" class="table__header--sortable">
Email
<span class="table__sort-indicator"></span>
</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>John Doe</td>
<td>john@example.com</td>
<td>
<div class="table__actions">
<button class="btn btn--ghost btn--sm">Edit</button>
<button class="btn btn--ghost btn--sm">Delete</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
```
### Stats Cards
Dashboard statistics display:
```html
<div class="stats-grid">
<div class="stat-card">
<div class="stat-card__icon">
📊
</div>
<div class="stat-card__content">
<div class="stat-card__label">Total Users</div>
<div class="stat-card__value">1,234</div>
<div class="stat-card__trend stat-card__trend--positive">
↗ +12% from last month
</div>
</div>
</div>
</div>
```
## 🔔 Feedback Components
### Alerts
Status and notification messages:
```html
<!-- Success Alert -->
<div class="alert alert--success" role="alert">
<div class="alert__icon"></div>
<div class="alert__content">
<div class="alert__title">Success</div>
<div class="alert__message">Operation completed successfully!</div>
</div>
<button class="alert__close" aria-label="Close alert">×</button>
</div>
<!-- Error Alert -->
<div class="alert alert--error" role="alert">
<div class="alert__icon"></div>
<div class="alert__content">
<div class="alert__title">Error</div>
<div class="alert__message">Something went wrong. Please try again.</div>
</div>
<button class="alert__close" aria-label="Close alert">×</button>
</div>
```
### Loading States
Progress indicators and skeleton screens:
```html
<!-- Spinner -->
<div class="spinner" role="status" aria-label="Loading">
<div class="spinner__circle"></div>
</div>
<!-- Progress Bar -->
<div class="progress" role="progressbar" aria-valuenow="65" aria-valuemin="0" aria-valuemax="100">
<div class="progress__bar" style="width: 65%"></div>
<div class="progress__label">65% Complete</div>
</div>
<!-- Skeleton Screen -->
<div class="skeleton">
<div class="skeleton__line skeleton__line--title"></div>
<div class="skeleton__line skeleton__line--text"></div>
<div class="skeleton__line skeleton__line--text skeleton__line--short"></div>
</div>
```
## 🎯 Interactive Components
### Tabs
Content organization with tabbed interface:
```html
<div class="tabs" role="tablist">
<button class="tabs__tab tabs__tab--active" role="tab" aria-selected="true" aria-controls="panel-1">
Tab 1
</button>
<button class="tabs__tab" role="tab" aria-selected="false" aria-controls="panel-2">
Tab 2
</button>
<button class="tabs__tab" role="tab" aria-selected="false" aria-controls="panel-3">
Tab 3
</button>
</div>
<div class="tabs__panels">
<div class="tabs__panel tabs__panel--active" role="tabpanel" id="panel-1">
Content for tab 1
</div>
<div class="tabs__panel" role="tabpanel" id="panel-2" hidden>
Content for tab 2
</div>
<div class="tabs__panel" role="tabpanel" id="panel-3" hidden>
Content for tab 3
</div>
</div>
```
### Dropdowns
Menu and selection dropdowns:
```html
<div class="dropdown">
<button class="dropdown__trigger" aria-haspopup="true" aria-expanded="false">
Menu
<span class="dropdown__arrow"></span>
</button>
<ul class="dropdown__menu" role="menu">
<li role="none">
<a class="dropdown__item" role="menuitem" href="#action1">Action 1</a>
</li>
<li role="none">
<a class="dropdown__item" role="menuitem" href="#action2">Action 2</a>
</li>
<li class="dropdown__divider" role="separator"></li>
<li role="none">
<a class="dropdown__item dropdown__item--danger" role="menuitem" href="#delete">
Delete Item
</a>
</li>
</ul>
</div>
```
## ♿ Accessibility Guidelines
### ARIA Implementation
All components include proper ARIA attributes:
- `role` attributes for semantic meaning
- `aria-label` for accessible names
- `aria-describedby` for help text associations
- `aria-expanded` for collapsible content
- `aria-selected` for selectable items
### Keyboard Navigation
Components support keyboard interaction:
- **Tab**: Navigate between focusable elements
- **Enter/Space**: Activate buttons and links
- **Escape**: Close modals and dropdowns
- **Arrow Keys**: Navigate within component groups
### Focus Management
Proper focus indicators and management:
```css
.component:focus-visible {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
}
/* Skip focus ring on mouse interaction */
.component:focus:not(:focus-visible) {
outline: none;
}
```
## 🎨 Theming
All components automatically adapt to theme changes through CSS custom properties:
```css
.component {
background: var(--surface);
color: var(--text-primary);
border: 1px solid var(--border);
}
/* Dark theme automatically applied */
[data-theme="dark"] .component {
/* Inherits dark theme tokens */
}
```
## 📚 Usage Examples
### JavaScript Integration
Components work with the framework's JavaScript module system:
```javascript
// Auto-initialize components
document.querySelectorAll('[data-component="modal"]').forEach(element => {
new Modal(element);
});
// Event-driven interactions
events.delegate('click', '[data-action="show-alert"]', (event, element) => {
const message = element.dataset.message;
showAlert('success', message);
});
```
### PHP Template Integration
Components integrate with the View system:
```php
<div class="card">
<div class="card__header">
<h3 class="card__title"><?= $title ?></h3>
</div>
<div class="card__body">
<?= $content ?>
</div>
</div>
```
---
*For design tokens and foundations, see [Design Foundations](foundations.md)*
*For CSS architecture details, see [CSS Architecture](css-architecture.md)*
*For JavaScript integration, see [JavaScript Modules](javascript.md)*

View File

@@ -0,0 +1,252 @@
# CSS Architecture
> ITCSS-based modular CSS architecture with component-driven development and utility-first approach.
## 📁 File Structure
```
resources/css/
├── styles.css # Main import file
├── settings/
│ ├── colors.css # Color definitions
│ ├── typography.css # Font sizes, fonts
│ ├── spacing.css # Spacing (margin, padding)
│ └── variables.css # Duration, easing, radius, z-index etc.
├── base/
│ ├── reset.css # Reset/Normalize
│ ├── global.css # Global styles for html, body, etc.
│ ├── typography.css # h1, p, etc.
│ ├── focus.css # Focus states
│ ├── media.css # Media queries
│ └── index.css # Base layer imports
├── layout/
│ ├── container.css # .page-container, max-widths, etc.
│ └── grid.css # Custom grid system
├── components/
│ ├── header.css
│ ├── nav.css
│ ├── footer.css
│ ├── buttons.css
│ ├── card.css
│ └── sidebar.css
├── forms/
│ └── inputs.css
├── utilities/
│ ├── animations.css # .fade-in, .shake, etc.
│ ├── helpers.css # .skip-link, .hidden, .visually-hidden
│ ├── scroll.css # scroll-behavior, scrollbar-style
│ ├── transitions.css
│ └── noise.css
└── themes/
└── dark.css # Dark mode color adjustments
```
## 🏗 ITCSS Layer Hierarchy
1. **Settings** - Variables, colors, typography scales
2. **Base** - Reset, normalize, global element styles
3. **Layout** - Grid systems, containers, structural components
4. **Components** - UI components and modules
5. **Utilities** - Helper classes and overrides
6. **Themes** - Color scheme variations
## 🎨 Design Tokens
### Colors
```css
/* Primary Palette */
--color-primary: #007bff;
--color-primary-dark: #0056b3;
--color-primary-light: #66b3ff;
/* Semantic Colors */
--color-success: #28a745;
--color-warning: #ffc107;
--color-error: #dc3545;
--color-info: #17a2b8;
/* Neutral Palette */
--color-gray-50: #f8f9fa;
--color-gray-100: #e9ecef;
--color-gray-900: #212529;
```
### Typography
```css
/* Font Stacks */
--font-family-sans: system-ui, -apple-system, sans-serif;
--font-family-mono: 'SF Mono', Monaco, 'Cascadia Code', monospace;
/* Type Scale */
--font-size-xs: 0.75rem; /* 12px */
--font-size-sm: 0.875rem; /* 14px */
--font-size-base: 1rem; /* 16px */
--font-size-lg: 1.125rem; /* 18px */
--font-size-xl: 1.25rem; /* 20px */
--font-size-2xl: 1.5rem; /* 24px */
--font-size-3xl: 1.875rem; /* 30px */
--font-size-4xl: 2.25rem; /* 36px */
```
### Spacing System
```css
/* 8pt Grid System */
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-5: 1.25rem; /* 20px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
--space-10: 2.5rem; /* 40px */
--space-12: 3rem; /* 48px */
--space-16: 4rem; /* 64px */
--space-20: 5rem; /* 80px */
```
## 🧩 Component Patterns
### BEM Methodology
```css
/* Block */
.card { }
/* Element */
.card__header { }
.card__body { }
.card__footer { }
/* Modifier */
.card--large { }
.card--featured { }
.card__header--centered { }
```
### Component States
```css
.button {
/* Base styles */
&:hover { }
&:focus { }
&:active { }
&:disabled { }
&[aria-pressed="true"] { }
&[aria-expanded="true"] { }
}
```
## 📱 Responsive Design
### Breakpoints
```css
/* Mobile First Approach */
--breakpoint-sm: 640px;
--breakpoint-md: 768px;
--breakpoint-lg: 1024px;
--breakpoint-xl: 1280px;
--breakpoint-2xl: 1536px;
```
### Media Query Mixins
```css
@media (min-width: 768px) {
/* Tablet and up */
}
@media (min-width: 1024px) {
/* Desktop and up */
}
@media (prefers-reduced-motion: reduce) {
/* Reduced motion accessibility */
}
@media (prefers-color-scheme: dark) {
/* Dark mode preferences */
}
```
## 🎯 Admin-Specific Extensions
### Admin Color Palette
```css
/* Admin Theme Colors */
--admin-primary: #6366f1;
--admin-secondary: #8b5cf6;
--admin-success: #10b981;
--admin-warning: #f59e0b;
--admin-error: #ef4444;
/* Admin Neutral Palette */
--admin-bg: #f8fafc;
--admin-surface: #ffffff;
--admin-border: #e2e8f0;
--admin-text: #1e293b;
--admin-text-muted: #64748b;
```
### Admin Components
```css
/* Admin Layout */
.admin-layout { }
.admin-header { }
.admin-nav { }
.admin-main { }
.admin-sidebar { }
/* Admin UI Components */
.admin-card { }
.admin-table { }
.admin-button { }
.admin-form { }
.admin-stats { }
```
## 🔧 Build Process
### CSS Processing
1. **PostCSS** for modern CSS features
2. **Autoprefixer** for browser compatibility
3. **CSS Nano** for minification
4. **PurgeCSS** for unused style removal
### Development Workflow
```bash
# Development with hot reload
npm run dev
# Production build
npm run build
# Watch for changes
npm run watch
```
## 📋 Best Practices
### Performance
- Use CSS custom properties for theme values
- Minimize selector specificity
- Leverage cascade and inheritance
- Use `contain` property for layout optimization
- Implement critical CSS loading
### Maintainability
- Follow BEM naming conventions
- Keep components isolated and reusable
- Use meaningful class names
- Document complex selectors
- Regular architecture reviews
### Accessibility
- Ensure sufficient color contrast ratios
- Support reduced motion preferences
- Use semantic markup structure
- Implement focus management
- Test with assistive technologies
---
*For component examples and live demos, visit [Admin Style Guide](/admin/docs)*

View File

@@ -0,0 +1,365 @@
# Design System Foundations
> Core design principles, tokens, and guidelines for consistent visual language.
## 🎨 Color System
### Primary Palette
```css
--color-primary: #6366f1; /* Indigo - Main brand color */
--color-primary-50: #eef2ff; /* Lightest tint */
--color-primary-100: #e0e7ff;
--color-primary-200: #c7d2fe;
--color-primary-300: #a5b4fc;
--color-primary-400: #818cf8;
--color-primary-500: #6366f1; /* Base */
--color-primary-600: #4f46e5;
--color-primary-700: #4338ca;
--color-primary-800: #3730a3;
--color-primary-900: #312e81; /* Darkest shade */
```
### Semantic Colors
```css
/* Success - Green */
--color-success: #10b981;
--color-success-light: #d1fae5;
--color-success-dark: #047857;
/* Warning - Amber */
--color-warning: #f59e0b;
--color-warning-light: #fef3c7;
--color-warning-dark: #d97706;
/* Error - Red */
--color-error: #ef4444;
--color-error-light: #fee2e2;
--color-error-dark: #dc2626;
/* Info - Blue */
--color-info: #3b82f6;
--color-info-light: #dbeafe;
--color-info-dark: #1d4ed8;
```
### Neutral Palette
```css
--color-gray-50: #f8fafc;
--color-gray-100: #f1f5f9;
--color-gray-200: #e2e8f0;
--color-gray-300: #cbd5e1;
--color-gray-400: #94a3b8;
--color-gray-500: #64748b;
--color-gray-600: #475569;
--color-gray-700: #334155;
--color-gray-800: #1e293b;
--color-gray-900: #0f172a;
```
## 📝 Typography
### Font Stacks
```css
/* Sans Serif - Primary */
--font-family-sans: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
/* Monospace - Code */
--font-family-mono: 'SF Mono', 'Monaco', 'Cascadia Code', 'Fira Code', monospace;
/* Serif - Optional */
--font-family-serif: 'Charter', 'Georgia', 'Times New Roman', serif;
```
### Type Scale
```css
/* Font Sizes (16px base) */
--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 */
--text-8xl: 6rem; /* 96px */
--text-9xl: 8rem; /* 128px */
```
### Font Weights
```css
--font-thin: 100;
--font-extralight: 200;
--font-light: 300;
--font-normal: 400;
--font-medium: 500;
--font-semibold: 600;
--font-bold: 700;
--font-extrabold: 800;
--font-black: 900;
```
### Line Heights
```css
--leading-none: 1;
--leading-tight: 1.25;
--leading-snug: 1.375;
--leading-normal: 1.5;
--leading-relaxed: 1.625;
--leading-loose: 2;
```
## 📏 Spacing System
### Base Unit: 4px
```css
--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 */
```
## 🔲 Border Radius
```css
--radius-none: 0;
--radius-sm: 0.125rem; /* 2px */
--radius: 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; /* Pill shape */
```
## 🌫 Shadows & Elevation
```css
/* Box Shadows */
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
--shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
--shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
--shadow-inner: inset 0 2px 4px 0 rgba(0, 0, 0, 0.06);
/* Colored Shadows */
--shadow-primary: 0 4px 14px 0 rgba(99, 102, 241, 0.15);
--shadow-success: 0 4px 14px 0 rgba(16, 185, 129, 0.15);
--shadow-warning: 0 4px 14px 0 rgba(245, 158, 11, 0.15);
--shadow-error: 0 4px 14px 0 rgba(239, 68, 68, 0.15);
```
## 📐 Layout & Grid
### Breakpoints
```css
--breakpoint-sm: 640px; /* Small tablets */
--breakpoint-md: 768px; /* Large tablets */
--breakpoint-lg: 1024px; /* Laptops */
--breakpoint-xl: 1280px; /* Desktops */
--breakpoint-2xl: 1536px; /* Large desktops */
```
### Container Sizes
```css
--container-sm: 640px;
--container-md: 768px;
--container-lg: 1024px;
--container-xl: 1280px;
--container-2xl: 1536px;
```
### Z-Index Scale
```css
--z-auto: auto;
--z-0: 0;
--z-10: 10;
--z-20: 20;
--z-30: 30;
--z-40: 40;
--z-50: 50;
/* Named layers */
--z-dropdown: 1000;
--z-sticky: 1020;
--z-fixed: 1030;
--z-modal-backdrop: 1040;
--z-modal: 1050;
--z-popover: 1060;
--z-tooltip: 1070;
--z-toast: 1080;
```
## ⏱ Motion & Animation
### Duration
```css
--duration-75: 75ms;
--duration-100: 100ms;
--duration-150: 150ms;
--duration-200: 200ms;
--duration-300: 300ms;
--duration-500: 500ms;
--duration-700: 700ms;
--duration-1000: 1000ms;
```
### Easing Functions
```css
--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);
/* Custom easing */
--ease-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
--ease-smooth: cubic-bezier(0.25, 0.46, 0.45, 0.94);
```
## 🎭 Theme System
### Light Theme (Default)
```css
:root {
--background: var(--color-gray-50);
--surface: #ffffff;
--surface-variant: var(--color-gray-100);
--border: var(--color-gray-200);
--text-primary: var(--color-gray-900);
--text-secondary: var(--color-gray-600);
--text-muted: var(--color-gray-500);
--text-disabled: var(--color-gray-400);
}
```
### Dark Theme
```css
[data-theme="dark"] {
--background: var(--color-gray-900);
--surface: var(--color-gray-800);
--surface-variant: var(--color-gray-700);
--border: var(--color-gray-600);
--text-primary: var(--color-gray-50);
--text-secondary: var(--color-gray-300);
--text-muted: var(--color-gray-400);
--text-disabled: var(--color-gray-500);
/* Adjust shadows for dark mode */
--shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3), 0 1px 2px 0 rgba(0, 0, 0, 0.2);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -1px rgba(0, 0, 0, 0.2);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.3), 0 4px 6px -2px rgba(0, 0, 0, 0.2);
}
```
## 📊 Usage Guidelines
### Semantic Token Usage
```css
/* Use semantic tokens for meaning */
.success-message {
color: var(--color-success);
background: var(--color-success-light);
border-color: var(--color-success);
}
/* Use scale tokens for consistency */
.card {
padding: var(--space-6);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-md);
}
/* Use theme tokens for adaptability */
.content {
background: var(--surface);
color: var(--text-primary);
border: 1px solid var(--border);
}
```
### Responsive Design
```css
/* Mobile first approach */
.component {
padding: var(--space-4);
font-size: var(--text-sm);
@media (min-width: 768px) {
padding: var(--space-6);
font-size: var(--text-base);
}
@media (min-width: 1024px) {
padding: var(--space-8);
font-size: var(--text-lg);
}
}
```
### Accessibility Considerations
```css
/* Ensure sufficient contrast */
.text-on-primary {
color: white; /* Passes WCAG AA on primary blue */
}
/* Respect motion preferences */
.animated-element {
transition: transform var(--duration-300) var(--ease-out);
@media (prefers-reduced-motion: reduce) {
transition: none;
}
}
/* Focus indicators */
.interactive-element:focus-visible {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
}
```
---
*For implementation examples, see [CSS Architecture](css-architecture.md)*
*For component usage, see [UI Components](components.md)*
*For admin-specific patterns, see [Admin Interface](admin/overview.md)*

View File

@@ -0,0 +1,642 @@
# JavaScript Module System
> Modern ES6+ modular JavaScript architecture with performance monitoring, state management, and component-based UI interactions.
## 📁 Module Structure
```
resources/js/
├── main.js # Entry point
├── core/ # Core framework modules
│ ├── index.js # Core exports
│ ├── init.js # Initialization
│ ├── router.js # SPA routing
│ ├── state.js # State management
│ ├── EventManager.js # Event system
│ ├── PerformanceMonitor.js # Performance tracking
│ └── logger.js # Logging utilities
├── modules/ # Feature modules
│ ├── index.js # Module registry
│ ├── ui/ # UI components
│ │ ├── UIManager.js # UI coordinator
│ │ └── components/ # Individual components
│ ├── scroll-fx/ # Scroll animations
│ ├── lightbox/ # Image lightbox
│ └── parallax/ # Parallax effects
├── utils/ # Utility functions
└── docs/ # Module documentation
```
## 🚀 Core System
### Application Initialization
```javascript
// main.js - Application entry point
import { init } from './core/init.js';
import { ModuleRegistry } from './modules/index.js';
// Initialize core systems
await init({
performance: true,
router: true,
state: true,
logging: 'development'
});
// Register and load modules
ModuleRegistry.register('ui', () => import('./modules/ui/index.js'));
ModuleRegistry.register('scrollfx', () => import('./modules/scrollfx/index.js'));
// Auto-load modules based on DOM attributes
ModuleRegistry.autoLoad();
```
### Router System
```javascript
// SPA routing with layout animations
import { Router } from './core/router.js';
const router = new Router({
mode: 'history',
base: '/',
transitions: true,
prefetch: true
});
// Route definitions
router.addRoute('/admin/:page?', async (ctx) => {
const { page = 'dashboard' } = ctx.params;
// Layout animation
if (ctx.isLayoutChange) {
await animateLayoutSwitch('admin');
}
// Load page content
return await loadAdminPage(page);
});
// Meta data extraction from HTML
router.onNavigate((ctx) => {
// Extract and apply meta data
const metaTitle = ctx.dom.querySelector('[data-meta-title]');
if (metaTitle) {
document.title = metaTitle.dataset.metaTitle;
}
const metaTheme = ctx.dom.querySelector('[data-meta-theme]');
if (metaTheme) {
document.documentElement.style.setProperty('--theme-color', metaTheme.dataset.metaTheme);
}
});
```
### State Management
```javascript
// Reactive state system
import { State } from './core/state.js';
// Global state
const appState = new State({
user: null,
theme: 'light',
admin: {
currentPage: 'dashboard',
notifications: []
}
});
// Reactive updates
appState.watch('theme', (newTheme, oldTheme) => {
document.documentElement.dataset.theme = newTheme;
localStorage.setItem('preferred-theme', newTheme);
});
// Component state binding
appState.bind('[data-user-name]', 'user.name');
appState.bind('[data-notification-count]', 'admin.notifications.length');
```
### Event System
```javascript
// Centralized event management
import { EventManager } from './core/EventManager.js';
const events = new EventManager();
// Global event delegation
events.delegate('click', '[data-action]', (event, element) => {
const action = element.dataset.action;
const target = element.dataset.target;
switch (action) {
case 'toggle-theme':
appState.set('theme', appState.get('theme') === 'light' ? 'dark' : 'light');
break;
case 'show-modal':
UIManager.showModal(target);
break;
}
});
// Custom events
events.on('admin:page-change', (data) => {
appState.set('admin.currentPage', data.page);
PerformanceMonitor.mark(`admin-${data.page}-loaded`);
});
```
## 🧩 UI Component System
### Component Architecture
```javascript
// Base component class
class BaseComponent {
constructor(element, options = {}) {
this.element = element;
this.options = { ...this.defaults, ...options };
this.state = new State(this.initialState);
this.init();
this.bindEvents();
}
init() {
// Override in subclasses
}
bindEvents() {
// Override in subclasses
}
destroy() {
this.state.destroy();
this.element.removeEventListener();
}
}
```
### Modal Component
```javascript
// UI Modal component
class Modal extends BaseComponent {
defaults = {
closeOnOverlay: true,
closeOnEscape: true,
animation: 'fade'
};
initialState = {
isOpen: false,
content: null
};
init() {
this.overlay = this.element.querySelector('.modal-overlay');
this.content = this.element.querySelector('.modal-content');
this.closeBtn = this.element.querySelector('[data-modal-close]');
// State reactivity
this.state.watch('isOpen', (isOpen) => {
this.element.classList.toggle('is-open', isOpen);
this.element.setAttribute('aria-hidden', !isOpen);
if (isOpen) {
this.trapFocus();
} else {
this.releaseFocus();
}
});
}
bindEvents() {
if (this.closeBtn) {
this.closeBtn.addEventListener('click', () => this.close());
}
if (this.options.closeOnOverlay) {
this.overlay.addEventListener('click', () => this.close());
}
if (this.options.closeOnEscape) {
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && this.state.get('isOpen')) {
this.close();
}
});
}
}
open(content = null) {
if (content) {
this.setContent(content);
}
this.state.set('isOpen', true);
events.emit('modal:opened', { modal: this });
}
close() {
this.state.set('isOpen', false);
events.emit('modal:closed', { modal: this });
}
setContent(content) {
if (typeof content === 'string') {
this.content.innerHTML = content;
} else if (content instanceof HTMLElement) {
this.content.innerHTML = '';
this.content.appendChild(content);
}
this.state.set('content', content);
}
}
// Auto-initialization
document.querySelectorAll('[data-modal]').forEach(element => {
new Modal(element);
});
```
### Admin-specific Components
```javascript
// Admin Stats Card
class AdminStatsCard extends BaseComponent {
defaults = {
updateInterval: 30000,
animateChanges: true
};
init() {
this.valueElement = this.element.querySelector('.stat-value');
this.labelElement = this.element.querySelector('.stat-label');
this.trendElement = this.element.querySelector('.stat-trend');
if (this.options.updateInterval) {
this.startPolling();
}
}
startPolling() {
this.pollInterval = setInterval(() => {
this.updateValue();
}, this.options.updateInterval);
}
async updateValue() {
const endpoint = this.element.dataset.endpoint;
if (!endpoint) return;
try {
const response = await fetch(endpoint);
const data = await response.json();
if (this.options.animateChanges) {
this.animateValueChange(data.value);
} else {
this.setValue(data.value);
}
if (data.trend) {
this.setTrend(data.trend);
}
} catch (error) {
console.error('Failed to update stat:', error);
}
}
animateValueChange(newValue) {
const currentValue = parseInt(this.valueElement.textContent) || 0;
const duration = 1000;
const steps = 60;
const increment = (newValue - currentValue) / steps;
let step = 0;
const timer = setInterval(() => {
step++;
const value = Math.round(currentValue + (increment * step));
this.valueElement.textContent = value.toLocaleString();
if (step >= steps) {
clearInterval(timer);
this.valueElement.textContent = newValue.toLocaleString();
}
}, duration / steps);
}
}
```
## 📊 Performance Monitoring
```javascript
// Performance tracking
import { PerformanceMonitor } from './core/PerformanceMonitor.js';
// Page load metrics
PerformanceMonitor.mark('page-start');
PerformanceMonitor.measure('page-load', 'page-start', 'page-end');
// Component performance
class ComponentWithMetrics extends BaseComponent {
init() {
PerformanceMonitor.mark(`${this.constructor.name}-init-start`);
// Component initialization
super.init();
PerformanceMonitor.mark(`${this.constructor.name}-init-end`);
PerformanceMonitor.measure(
`${this.constructor.name}-init`,
`${this.constructor.name}-init-start`,
`${this.constructor.name}-init-end`
);
}
}
// Performance reporting
PerformanceMonitor.report((metrics) => {
// Send to analytics
if (window.gtag) {
gtag('event', 'performance_metric', {
custom_map: { metric_name: 'custom_metric_name' },
metric_name: metrics.name,
value: metrics.duration
});
}
});
```
## 🎨 Admin Interface Integration
### Theme System
```javascript
// Admin theme management
class AdminThemeManager {
constructor() {
this.themes = ['light', 'dark', 'auto'];
this.currentTheme = localStorage.getItem('admin-theme') || 'auto';
this.mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
this.init();
}
init() {
this.applyTheme(this.currentTheme);
this.bindEvents();
}
bindEvents() {
// Theme toggle button
document.addEventListener('click', (e) => {
if (e.target.matches('[data-theme-toggle]')) {
this.toggleTheme();
}
});
// System theme changes
this.mediaQuery.addEventListener('change', () => {
if (this.currentTheme === 'auto') {
this.applyTheme('auto');
}
});
}
applyTheme(theme) {
let resolvedTheme = theme;
if (theme === 'auto') {
resolvedTheme = this.mediaQuery.matches ? 'dark' : 'light';
}
document.documentElement.dataset.theme = resolvedTheme;
document.documentElement.style.setProperty('--theme-preference', theme);
// Update theme color meta tag
const metaThemeColor = document.querySelector('meta[name="theme-color"]');
if (metaThemeColor) {
const color = resolvedTheme === 'dark' ? '#1e293b' : '#ffffff';
metaThemeColor.setAttribute('content', color);
}
}
toggleTheme() {
const currentIndex = this.themes.indexOf(this.currentTheme);
const nextIndex = (currentIndex + 1) % this.themes.length;
const nextTheme = this.themes[nextIndex];
this.setTheme(nextTheme);
}
setTheme(theme) {
this.currentTheme = theme;
localStorage.setItem('admin-theme', theme);
this.applyTheme(theme);
events.emit('theme:changed', { theme, resolvedTheme: this.getResolvedTheme() });
}
getResolvedTheme() {
if (this.currentTheme === 'auto') {
return this.mediaQuery.matches ? 'dark' : 'light';
}
return this.currentTheme;
}
}
// Initialize admin theme
new AdminThemeManager();
```
### Data Tables
```javascript
// Admin data table component
class AdminDataTable extends BaseComponent {
defaults = {
sortable: true,
filterable: true,
paginated: true,
pageSize: 25
};
init() {
this.table = this.element.querySelector('table');
this.tbody = this.table.querySelector('tbody');
this.headers = [...this.table.querySelectorAll('th[data-sort]')];
this.filterInput = this.element.querySelector('[data-table-filter]');
this.data = this.extractData();
this.filteredData = [...this.data];
this.currentSort = { column: null, direction: 'asc' };
this.currentPage = 1;
this.bindEvents();
this.render();
}
bindEvents() {
// Column sorting
this.headers.forEach(header => {
header.addEventListener('click', () => {
const column = header.dataset.sort;
this.sort(column);
});
});
// Filtering
if (this.filterInput) {
this.filterInput.addEventListener('input', debounce(() => {
this.filter(this.filterInput.value);
}, 300));
}
}
sort(column) {
if (this.currentSort.column === column) {
this.currentSort.direction = this.currentSort.direction === 'asc' ? 'desc' : 'asc';
} else {
this.currentSort.column = column;
this.currentSort.direction = 'asc';
}
this.filteredData.sort((a, b) => {
const aVal = a[column];
const bVal = b[column];
const modifier = this.currentSort.direction === 'asc' ? 1 : -1;
if (aVal < bVal) return -1 * modifier;
if (aVal > bVal) return 1 * modifier;
return 0;
});
this.currentPage = 1;
this.render();
}
filter(query) {
if (!query) {
this.filteredData = [...this.data];
} else {
const searchTerm = query.toLowerCase();
this.filteredData = this.data.filter(row => {
return Object.values(row).some(value =>
String(value).toLowerCase().includes(searchTerm)
);
});
}
this.currentPage = 1;
this.render();
}
render() {
// Update table body
this.renderTableBody();
// Update sort indicators
this.updateSortIndicators();
// Update pagination
if (this.options.paginated) {
this.renderPagination();
}
}
}
```
## 🔧 Utility Functions
```javascript
// Common utility functions
export const utils = {
// Debounce function calls
debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
},
// Throttle function calls
throttle(func, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
},
// DOM manipulation helpers
dom: {
ready(fn) {
if (document.readyState !== 'loading') {
fn();
} else {
document.addEventListener('DOMContentLoaded', fn);
}
},
create(tag, attributes = {}, children = []) {
const element = document.createElement(tag);
Object.entries(attributes).forEach(([key, value]) => {
if (key === 'className') {
element.className = value;
} else if (key.startsWith('data-')) {
element.dataset[key.slice(5)] = value;
} else {
element.setAttribute(key, value);
}
});
children.forEach(child => {
if (typeof child === 'string') {
element.appendChild(document.createTextNode(child));
} else {
element.appendChild(child);
}
});
return element;
}
},
// Format utilities
format: {
bytes(bytes, decimals = 2) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i];
},
duration(ms) {
if (ms < 1000) return `${ms}ms`;
if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;
return `${(ms / 60000).toFixed(1)}m`;
}
}
};
```
---
*For specific module documentation, see individual files in `/resources/js/docs/`*
*For performance optimization, see [Performance Guidelines](../development/performance.md)*
*For component integration, see [UI Components](components.md)*