Major improvements to WooNooW Page Editor system: Schema & Architecture: - Canonical section schema with unified sectionSchema.ts - Normalized feature-grid to use items (not features) - Standardized default values across all section types - Schema versioning with automatic migration on read Backend (PHP): - Enhanced PlaceholderRenderer with typed output contracts - Added fallback behavior for empty/invalid dynamic sources - Added caching support for post data resolution - New SchemaMigration class for backward compatibility - New Features class for feature flags - Enhanced PageSSR with full style support - Removed controller-level special-casing for related_posts Frontend (Admin SPA): - Updated CanvasRenderer with schema-aware transformation - Enhanced InspectorPanel with canonical schema metadata - Added new section renderers Frontend (Customer SPA): - New section components: BentoCategoryGrid, MarqueeBanner, ProductCarousel, ShoppableImage - Updated FeatureGridSection for items prop contract Testing: - Add PHP tests: SchemaMigrationTest, PlaceholderRendererTest, PageSSRTest - Add TypeScript tests: schema-integration, feature-grid-regression - Add parity tests for React vs SSR content matching - Add CI script: check-schema-drift.mjs - Add VERIFICATION_CHECKLIST.md Documentation: - RELEASE_NOTES-v1.0.md with full release notes - docs/PAGE_EDITOR_SECTION_SCHEMA_V1.md - docs/PAGE_EDITOR_SSR_COVERAGE_AUDIT.md
349 lines
7.3 KiB
CSS
349 lines
7.3 KiB
CSS
/**
|
|
* WooNooW Customer SPA - Design Tokens
|
|
*
|
|
* All styling is controlled via CSS custom properties (design tokens).
|
|
* These values are injected from PHP settings via ThemeProvider.
|
|
*/
|
|
|
|
:root {
|
|
/* ========================================
|
|
* COLORS
|
|
* ======================================== */
|
|
|
|
/* Brand Colors (injected from settings) */
|
|
--color-primary: #3B82F6;
|
|
--color-secondary: #8B5CF6;
|
|
--color-accent: #10B981;
|
|
--color-background: #FFFFFF;
|
|
--color-text: #1F2937;
|
|
|
|
/* Color Shades (auto-generated) */
|
|
--color-primary-50: #EFF6FF;
|
|
--color-primary-100: #DBEAFE;
|
|
--color-primary-200: #BFDBFE;
|
|
--color-primary-300: #93C5FD;
|
|
--color-primary-400: #60A5FA;
|
|
--color-primary-500: var(--color-primary);
|
|
--color-primary-600: #2563EB;
|
|
--color-primary-700: #1D4ED8;
|
|
--color-primary-800: #1E40AF;
|
|
--color-primary-900: #1E3A8A;
|
|
|
|
/* Semantic Colors */
|
|
--color-success: #10B981;
|
|
--color-warning: #F59E0B;
|
|
--color-error: #EF4444;
|
|
--color-info: #3B82F6;
|
|
|
|
/* Neutral Colors */
|
|
--color-gray-50: #F9FAFB;
|
|
--color-gray-100: #F3F4F6;
|
|
--color-gray-200: #E5E7EB;
|
|
--color-gray-300: #D1D5DB;
|
|
--color-gray-400: #9CA3AF;
|
|
--color-gray-500: #6B7280;
|
|
--color-gray-600: #4B5563;
|
|
--color-gray-700: #374151;
|
|
--color-gray-800: #1F2937;
|
|
--color-gray-900: #111827;
|
|
|
|
/* ========================================
|
|
* TYPOGRAPHY
|
|
* ======================================== */
|
|
|
|
/* Font Families (injected from settings) */
|
|
--font-heading: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
--font-body: 'Lora', Georgia, serif;
|
|
--font-mono: 'IBM Plex Mono', 'Courier New', monospace;
|
|
|
|
/* Font Weights */
|
|
--font-weight-heading: 700;
|
|
--font-weight-body: 400;
|
|
--font-weight-light: 300;
|
|
--font-weight-normal: 400;
|
|
--font-weight-medium: 500;
|
|
--font-weight-semibold: 600;
|
|
--font-weight-bold: 700;
|
|
|
|
/* Font Sizes (8px base scale) */
|
|
--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 */
|
|
|
|
/* Line Heights */
|
|
--line-height-none: 1;
|
|
--line-height-tight: 1.25;
|
|
--line-height-snug: 1.375;
|
|
--line-height-normal: 1.5;
|
|
--line-height-relaxed: 1.625;
|
|
--line-height-loose: 2;
|
|
|
|
/* ========================================
|
|
* SPACING (8px grid system)
|
|
* ======================================== */
|
|
|
|
--space-0: 0;
|
|
--space-1: 0.5rem;
|
|
/* 8px */
|
|
--space-2: 1rem;
|
|
/* 16px */
|
|
--space-3: 1.5rem;
|
|
/* 24px */
|
|
--space-4: 2rem;
|
|
/* 32px */
|
|
--space-5: 2.5rem;
|
|
/* 40px */
|
|
--space-6: 3rem;
|
|
/* 48px */
|
|
--space-8: 4rem;
|
|
/* 64px */
|
|
--space-10: 5rem;
|
|
/* 80px */
|
|
--space-12: 6rem;
|
|
/* 96px */
|
|
--space-16: 8rem;
|
|
/* 128px */
|
|
--space-20: 10rem;
|
|
/* 160px */
|
|
--space-24: 12rem;
|
|
/* 192px */
|
|
|
|
/* ========================================
|
|
* BORDER RADIUS
|
|
* ======================================== */
|
|
|
|
--radius-none: 0;
|
|
--radius-sm: 0.25rem;
|
|
/* 4px */
|
|
--radius-md: 0.5rem;
|
|
/* 8px */
|
|
--radius-lg: 1rem;
|
|
/* 16px */
|
|
--radius-xl: 1.5rem;
|
|
/* 24px */
|
|
--radius-2xl: 2rem;
|
|
/* 32px */
|
|
--radius-full: 9999px;
|
|
|
|
/* ========================================
|
|
* SHADOWS
|
|
* ======================================== */
|
|
|
|
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
|
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
|
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
|
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
|
--shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
|
--shadow-inner: inset 0 2px 4px 0 rgb(0 0 0 / 0.05);
|
|
|
|
/* ========================================
|
|
* TRANSITIONS
|
|
* ======================================== */
|
|
|
|
--transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
--transition-base: 250ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
--transition-slow: 350ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
|
|
/* ========================================
|
|
* BREAKPOINTS (for reference in JS)
|
|
* ======================================== */
|
|
|
|
--breakpoint-sm: 640px;
|
|
--breakpoint-md: 768px;
|
|
--breakpoint-lg: 1024px;
|
|
--breakpoint-xl: 1280px;
|
|
--breakpoint-2xl: 1536px;
|
|
|
|
/* ========================================
|
|
* Z-INDEX SCALE
|
|
* ======================================== */
|
|
|
|
--z-base: 0;
|
|
--z-dropdown: 1000;
|
|
--z-sticky: 1020;
|
|
--z-fixed: 1030;
|
|
--z-modal-backdrop: 1040;
|
|
--z-modal: 1050;
|
|
--z-popover: 1060;
|
|
--z-tooltip: 1070;
|
|
}
|
|
|
|
/* ========================================
|
|
* DARK MODE
|
|
* ======================================== */
|
|
|
|
:root.dark {
|
|
--color-background: #1F2937;
|
|
--color-text: #F9FAFB;
|
|
|
|
/* Invert gray scale for dark mode */
|
|
--color-gray-50: #111827;
|
|
--color-gray-100: #1F2937;
|
|
--color-gray-200: #374151;
|
|
--color-gray-300: #4B5563;
|
|
--color-gray-400: #6B7280;
|
|
--color-gray-500: #9CA3AF;
|
|
--color-gray-600: #D1D5DB;
|
|
--color-gray-700: #E5E7EB;
|
|
--color-gray-800: #F3F4F6;
|
|
--color-gray-900: #F9FAFB;
|
|
}
|
|
|
|
@media (prefers-color-scheme: dark) {
|
|
:root:not(.light):not(.dark) {
|
|
--color-background: #1F2937;
|
|
--color-text: #F9FAFB;
|
|
|
|
/* Invert gray scale for dark mode */
|
|
--color-gray-50: #111827;
|
|
--color-gray-100: #1F2937;
|
|
--color-gray-200: #374151;
|
|
--color-gray-300: #4B5563;
|
|
--color-gray-400: #6B7280;
|
|
--color-gray-500: #9CA3AF;
|
|
--color-gray-600: #D1D5DB;
|
|
--color-gray-700: #E5E7EB;
|
|
--color-gray-800: #F3F4F6;
|
|
--color-gray-900: #F9FAFB;
|
|
}
|
|
}
|
|
|
|
/* ========================================
|
|
* BASE STYLES
|
|
* ======================================== */
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
html {
|
|
font-size: 16px;
|
|
-webkit-font-smoothing: antialiased;
|
|
-moz-osx-font-smoothing: grayscale;
|
|
}
|
|
|
|
body {
|
|
font-family: var(--font-body);
|
|
font-size: var(--text-base);
|
|
line-height: var(--line-height-normal);
|
|
color: var(--color-text);
|
|
background-color: var(--color-background);
|
|
}
|
|
|
|
h1,
|
|
h2,
|
|
h3,
|
|
h4,
|
|
h5,
|
|
h6 {
|
|
font-family: var(--font-heading);
|
|
font-weight: var(--font-weight-heading);
|
|
line-height: var(--line-height-tight);
|
|
color: var(--color-text);
|
|
}
|
|
|
|
h1 {
|
|
font-size: var(--text-5xl);
|
|
}
|
|
|
|
h2 {
|
|
font-size: var(--text-4xl);
|
|
}
|
|
|
|
h3 {
|
|
font-size: var(--text-3xl);
|
|
}
|
|
|
|
h4 {
|
|
font-size: var(--text-2xl);
|
|
}
|
|
|
|
h5 {
|
|
font-size: var(--text-xl);
|
|
}
|
|
|
|
h6 {
|
|
font-size: var(--text-lg);
|
|
}
|
|
|
|
a {
|
|
color: var(--color-primary);
|
|
text-decoration: none;
|
|
transition: color var(--transition-fast);
|
|
}
|
|
|
|
a:hover {
|
|
color: var(--color-primary-600);
|
|
}
|
|
|
|
button {
|
|
font-family: var(--font-body);
|
|
cursor: pointer;
|
|
}
|
|
|
|
img {
|
|
max-width: 100%;
|
|
height: auto;
|
|
}
|
|
|
|
/* ========================================
|
|
* UTILITY CLASSES
|
|
* ======================================== */
|
|
|
|
.container {
|
|
width: 100%;
|
|
margin-left: auto;
|
|
margin-right: auto;
|
|
padding-left: var(--space-4);
|
|
padding-right: var(--space-4);
|
|
}
|
|
|
|
@media (min-width: 640px) {
|
|
.container {
|
|
max-width: 640px;
|
|
}
|
|
}
|
|
|
|
@media (min-width: 768px) {
|
|
.container {
|
|
max-width: 768px;
|
|
}
|
|
}
|
|
|
|
@media (min-width: 1024px) {
|
|
.container {
|
|
max-width: 1024px;
|
|
}
|
|
}
|
|
|
|
@media (min-width: 1280px) {
|
|
.container {
|
|
max-width: 1280px;
|
|
}
|
|
}
|
|
|
|
@media (min-width: 1536px) {
|
|
.container {
|
|
max-width: 1536px;
|
|
}
|
|
}
|