feat: add CSS generation system with custom properties and ETS cache
- Create theme-primitives.css with spacing, fonts, radius scales - Create theme-semantic.css with semantic CSS variable aliases - Update app.css to import theme CSS files - Add CSSGenerator module for dynamic CSS token generation - Generates mood variables (neutral, warm, cool, dark) - Generates typography variables (7 font combinations) - Generates shape variables (sharp, soft, round, pill) - Generates density variables (spacious, balanced, compact) - Converts hex colors to HSL for flexible manipulation - Add CSSCache GenServer with ETS table for performance - Caches generated CSS to avoid regeneration - Warms cache on application startup - Provides invalidation for theme updates - Add CSSCache to application supervision tree - Add comprehensive tests for CSS generation (29 tests) - Add comprehensive tests for preset validation (14 tests) - All tests passing (58 total tests, 0 failures) - Verified CSS generation and caching work correctly in IEx
This commit is contained in:
58
priv/static/css/theme-primitives.css
Normal file
58
priv/static/css/theme-primitives.css
Normal file
@@ -0,0 +1,58 @@
|
||||
/* ========================================
|
||||
THEME PRIMITIVES - Layer 1
|
||||
Fixed CSS custom properties
|
||||
======================================== */
|
||||
|
||||
:root {
|
||||
/* Spacing scale */
|
||||
--p-space-1: 0.25rem;
|
||||
--p-space-2: 0.5rem;
|
||||
--p-space-3: 0.75rem;
|
||||
--p-space-4: 1rem;
|
||||
--p-space-6: 1.5rem;
|
||||
--p-space-8: 2rem;
|
||||
--p-space-12: 3rem;
|
||||
--p-space-16: 4rem;
|
||||
--p-space-24: 6rem;
|
||||
|
||||
/* Border radius scale */
|
||||
--p-radius-none: 0;
|
||||
--p-radius-sm: 0.25rem;
|
||||
--p-radius-md: 0.5rem;
|
||||
--p-radius-lg: 0.75rem;
|
||||
--p-radius-xl: 1rem;
|
||||
--p-radius-full: 9999px;
|
||||
|
||||
/* Font families */
|
||||
--p-font-inter: 'Inter', system-ui, sans-serif;
|
||||
--p-font-fraunces: 'Fraunces', serif;
|
||||
--p-font-source: 'Source Sans 3', system-ui, sans-serif;
|
||||
--p-font-space: 'Space Grotesk', system-ui, sans-serif;
|
||||
--p-font-baskerville: 'Libre Baskerville', Georgia, serif;
|
||||
--p-font-nunito: 'Nunito', system-ui, sans-serif;
|
||||
--p-font-outfit: 'Outfit', system-ui, sans-serif;
|
||||
--p-font-avenir: 'Nunito Sans', 'Avenir Next', 'Avenir', system-ui, sans-serif;
|
||||
|
||||
/* Font size scale */
|
||||
--p-text-xs: 0.75rem;
|
||||
--p-text-sm: 0.875rem;
|
||||
--p-text-base: 1rem;
|
||||
--p-text-lg: 1.125rem;
|
||||
--p-text-xl: 1.25rem;
|
||||
--p-text-2xl: 1.5rem;
|
||||
--p-text-3xl: 1.875rem;
|
||||
--p-text-4xl: 2.25rem;
|
||||
|
||||
/* Animation durations */
|
||||
--p-duration-fast: 0.1s;
|
||||
--p-duration-normal: 0.2s;
|
||||
--p-duration-slow: 0.35s;
|
||||
|
||||
/* Easing functions */
|
||||
--p-ease-out: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
--p-ease-out-back: cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
|
||||
/* Shadow base */
|
||||
--p-shadow-color: 0 0% 0%;
|
||||
--p-shadow-strength: 0.06;
|
||||
}
|
||||
80
priv/static/css/theme-semantic.css
Normal file
80
priv/static/css/theme-semantic.css
Normal file
@@ -0,0 +1,80 @@
|
||||
/* ========================================
|
||||
THEME SEMANTIC - Layer 3
|
||||
Semantic aliases for easy usage
|
||||
======================================== */
|
||||
|
||||
:root {
|
||||
/* Accent color (dynamic, set by theme) */
|
||||
--t-accent-h: 24;
|
||||
--t-accent-s: 95%;
|
||||
--t-accent-l: 53%;
|
||||
--t-accent: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
|
||||
--t-accent-hover: hsl(var(--t-accent-h) var(--t-accent-s) calc(var(--t-accent-l) - 8%));
|
||||
--t-accent-subtle: hsl(var(--t-accent-h) 40% 95%);
|
||||
--t-accent-ring: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l) / 0.4);
|
||||
|
||||
/* Secondary colors */
|
||||
--t-secondary-accent: #ea580c;
|
||||
--t-sale-color: #dc2626;
|
||||
|
||||
/* Density multiplier */
|
||||
--t-density: 1;
|
||||
|
||||
/* Layout */
|
||||
--t-layout-max-width: 1400px;
|
||||
--t-button-style: filled;
|
||||
--t-card-shadow: none;
|
||||
--t-product-text-align: left;
|
||||
|
||||
/* Page colors */
|
||||
--color-page: var(--t-surface-base);
|
||||
--color-card: var(--t-surface-raised);
|
||||
--color-input: var(--t-surface-raised);
|
||||
|
||||
/* Text colors */
|
||||
--color-heading: var(--t-text-primary);
|
||||
--color-body: var(--t-text-secondary);
|
||||
--color-caption: var(--t-text-tertiary);
|
||||
|
||||
/* Button colors */
|
||||
--color-button-primary: var(--t-accent);
|
||||
--color-button-primary-hover: var(--t-secondary-accent);
|
||||
--color-button-primary-text: var(--t-text-inverse);
|
||||
|
||||
/* Border colors */
|
||||
--color-border: var(--t-border-default);
|
||||
|
||||
/* Typography */
|
||||
--font-heading: var(--t-font-heading);
|
||||
--font-body: var(--t-font-body);
|
||||
--weight-heading: var(--t-heading-weight);
|
||||
--tracking-heading: var(--t-heading-tracking);
|
||||
|
||||
/* Responsive spacing (density-aware) */
|
||||
--space-xs: calc(var(--p-space-2) * var(--t-density));
|
||||
--space-sm: calc(var(--p-space-3) * var(--t-density));
|
||||
--space-md: calc(var(--p-space-4) * var(--t-density));
|
||||
--space-lg: calc(var(--p-space-6) * var(--t-density));
|
||||
--space-xl: calc(var(--p-space-8) * var(--t-density));
|
||||
--space-2xl: calc(var(--p-space-12) * var(--t-density));
|
||||
|
||||
/* Border radius */
|
||||
--radius-button: var(--t-radius-button);
|
||||
--radius-card: var(--t-radius-card);
|
||||
--radius-input: var(--t-radius-input);
|
||||
--radius-image: var(--t-radius-image);
|
||||
|
||||
/* Shadows */
|
||||
--shadow-sm:
|
||||
0 1px 2px hsl(var(--p-shadow-color) / calc(var(--p-shadow-strength) * 0.5)),
|
||||
0 1px 3px hsl(var(--p-shadow-color) / var(--p-shadow-strength));
|
||||
--shadow-md:
|
||||
0 2px 4px hsl(var(--p-shadow-color) / calc(--p-shadow-strength) * 0.5)),
|
||||
0 4px 8px hsl(var(--p-shadow-color) / var(--p-shadow-strength)),
|
||||
0 8px 16px hsl(var(--p-shadow-color) / calc(var(--p-shadow-strength) * 0.5));
|
||||
|
||||
/* Transitions */
|
||||
--transition-fast: var(--p-duration-fast) var(--p-ease-out);
|
||||
--transition-normal: var(--p-duration-normal) var(--p-ease-out);
|
||||
--transition-bounce: var(--p-duration-normal) var(--p-ease-out-back);
|
||||
}
|
||||
Reference in New Issue
Block a user