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
2025-12-30 21:41:25 +00:00
|
|
|
defmodule SimpleshopTheme.Theme.CSSGenerator do
|
|
|
|
|
@moduledoc """
|
|
|
|
|
Generates CSS custom properties (Layer 2: Theme Tokens) from theme settings.
|
|
|
|
|
|
|
|
|
|
This module converts ThemeSettings into CSS variables that bridge the gap
|
|
|
|
|
between fixed primitives (Layer 1) and semantic aliases (Layer 3).
|
2026-01-17 21:43:26 +00:00
|
|
|
|
|
|
|
|
For the shop (public pages), this generates ALL theme tokens inline, so the
|
|
|
|
|
shop doesn't need the attribute-based selectors in theme-layer2-attributes.css.
|
|
|
|
|
The theme editor still uses those selectors for live preview switching.
|
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
2025-12-30 21:41:25 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
alias SimpleshopTheme.Settings.ThemeSettings
|
2026-01-25 00:33:24 +00:00
|
|
|
alias SimpleshopTheme.Theme.Fonts
|
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
2025-12-30 21:41:25 +00:00
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
|
Generates CSS for theme settings.
|
|
|
|
|
|
|
|
|
|
Returns a string of CSS custom properties that can be injected into a <style> tag.
|
2026-01-17 21:43:26 +00:00
|
|
|
This includes ALL theme tokens (mood, typography, shape, density) so the shop
|
|
|
|
|
pages don't need the attribute-based CSS selectors.
|
2026-01-25 00:33:24 +00:00
|
|
|
|
|
|
|
|
Also includes @font-face declarations for the fonts used by the typography preset.
|
2026-01-25 09:32:06 +00:00
|
|
|
|
|
|
|
|
Accepts an optional path_resolver function for digested font paths.
|
|
|
|
|
In production, pass `&SimpleshopThemeWeb.Endpoint.static_path/1`.
|
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
2025-12-30 21:41:25 +00:00
|
|
|
"""
|
2026-01-25 09:32:06 +00:00
|
|
|
def generate(%ThemeSettings{} = settings, path_resolver \\ fn path -> path end) do
|
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
2025-12-30 21:41:25 +00:00
|
|
|
"""
|
2026-01-25 00:33:24 +00:00
|
|
|
/* Font faces for #{settings.typography} typography */
|
2026-01-25 09:32:06 +00:00
|
|
|
#{Fonts.generate_font_faces(settings.typography, path_resolver)}
|
2026-01-25 00:33:24 +00:00
|
|
|
|
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
2025-12-30 21:41:25 +00:00
|
|
|
/* Theme Tokens - Layer 2 (dynamically generated) */
|
2026-01-17 21:43:26 +00:00
|
|
|
.themed {
|
|
|
|
|
/* Mood colors */
|
|
|
|
|
#{generate_mood(settings.mood)}
|
|
|
|
|
|
|
|
|
|
/* Typography */
|
|
|
|
|
#{generate_typography(settings.typography)}
|
|
|
|
|
|
|
|
|
|
/* Shape (border radii) */
|
|
|
|
|
#{generate_shape(settings.shape)}
|
|
|
|
|
|
|
|
|
|
/* Density */
|
|
|
|
|
#{generate_density(settings.density)}
|
|
|
|
|
|
|
|
|
|
/* Slider-controlled values */
|
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
2025-12-30 21:41:25 +00:00
|
|
|
#{generate_accent(settings.accent_color)}
|
|
|
|
|
#{generate_secondary_colors(settings)}
|
2026-01-02 13:48:03 +00:00
|
|
|
#{generate_font_size(settings.font_size)}
|
|
|
|
|
#{generate_heading_weight(settings.heading_weight)}
|
|
|
|
|
#{generate_layout_width(settings.layout_width)}
|
|
|
|
|
#{generate_button_style(settings.button_style)}
|
|
|
|
|
#{generate_product_text_align(settings.product_text_align)}
|
|
|
|
|
#{generate_image_aspect_ratio(settings.image_aspect_ratio)}
|
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
2025-12-30 21:41:25 +00:00
|
|
|
}
|
|
|
|
|
"""
|
|
|
|
|
|> String.trim()
|
|
|
|
|
end
|
|
|
|
|
|
2026-01-17 21:43:26 +00:00
|
|
|
# Mood colors - surface, text, and border colors
|
|
|
|
|
defp generate_mood("neutral") do
|
|
|
|
|
"""
|
|
|
|
|
--t-surface-base: #ffffff;
|
|
|
|
|
--t-surface-raised: #ffffff;
|
|
|
|
|
--t-surface-sunken: #f5f5f5;
|
|
|
|
|
--t-surface-overlay: rgba(255, 255, 255, 0.95);
|
|
|
|
|
--t-text-primary: #171717;
|
|
|
|
|
--t-text-secondary: #525252;
|
2026-01-21 21:55:55 +00:00
|
|
|
--t-text-tertiary: #737373;
|
2026-01-17 21:43:26 +00:00
|
|
|
--t-text-inverse: #ffffff;
|
|
|
|
|
--t-border-default: #e5e5e5;
|
|
|
|
|
--t-border-subtle: #f0f0f0;
|
|
|
|
|
"""
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_mood("warm") do
|
|
|
|
|
"""
|
|
|
|
|
--t-surface-base: #fdf8f3;
|
|
|
|
|
--t-surface-raised: #fffcf8;
|
|
|
|
|
--t-surface-sunken: #f5ebe0;
|
|
|
|
|
--t-surface-overlay: rgba(253, 248, 243, 0.95);
|
|
|
|
|
--t-text-primary: #1c1917;
|
|
|
|
|
--t-text-secondary: #57534e;
|
2026-01-21 21:55:55 +00:00
|
|
|
--t-text-tertiary: #78716c;
|
2026-01-17 21:43:26 +00:00
|
|
|
--t-text-inverse: #ffffff;
|
|
|
|
|
--t-border-default: #e7e0d8;
|
|
|
|
|
--t-border-subtle: #f0ebe4;
|
|
|
|
|
"""
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_mood("cool") do
|
|
|
|
|
"""
|
|
|
|
|
--t-surface-base: #f4f7fb;
|
|
|
|
|
--t-surface-raised: #f8fafc;
|
|
|
|
|
--t-surface-sunken: #e8eff7;
|
|
|
|
|
--t-surface-overlay: rgba(244, 247, 251, 0.95);
|
|
|
|
|
--t-text-primary: #0f172a;
|
|
|
|
|
--t-text-secondary: #475569;
|
2026-01-21 21:55:55 +00:00
|
|
|
--t-text-tertiary: #64748b;
|
2026-01-17 21:43:26 +00:00
|
|
|
--t-text-inverse: #ffffff;
|
|
|
|
|
--t-border-default: #d4dce8;
|
|
|
|
|
--t-border-subtle: #e8eff5;
|
|
|
|
|
"""
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_mood("dark") do
|
|
|
|
|
"""
|
|
|
|
|
--t-surface-base: #0a0a0a;
|
|
|
|
|
--t-surface-raised: #171717;
|
|
|
|
|
--t-surface-sunken: #000000;
|
|
|
|
|
--t-surface-overlay: rgba(23, 23, 23, 0.95);
|
|
|
|
|
--t-text-primary: #fafafa;
|
|
|
|
|
--t-text-secondary: #a3a3a3;
|
|
|
|
|
--t-text-tertiary: #737373;
|
|
|
|
|
--t-text-inverse: #171717;
|
|
|
|
|
--t-border-default: #262626;
|
|
|
|
|
--t-border-subtle: #1c1c1c;
|
|
|
|
|
"""
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# Fallback for any other mood value
|
|
|
|
|
defp generate_mood(_), do: generate_mood("neutral")
|
|
|
|
|
|
2026-01-25 00:33:24 +00:00
|
|
|
# Typography style settings (weight and tracking per preset)
|
|
|
|
|
@typography_styles %{
|
|
|
|
|
"clean" => %{weight: 600, tracking: "-0.02em"},
|
|
|
|
|
"editorial" => %{weight: 500, tracking: "-0.01em"},
|
|
|
|
|
"modern" => %{weight: 500, tracking: "-0.03em"},
|
|
|
|
|
"classic" => %{weight: 500, tracking: "0"},
|
|
|
|
|
"friendly" => %{weight: 600, tracking: "-0.01em"},
|
|
|
|
|
"minimal" => %{weight: 500, tracking: "0"},
|
|
|
|
|
"impulse" => %{weight: 300, tracking: "0.02em"}
|
|
|
|
|
}
|
2026-01-17 21:43:26 +00:00
|
|
|
|
2026-01-25 00:33:24 +00:00
|
|
|
# Typography - font families, weights, and tracking
|
|
|
|
|
# Uses Fonts module for DRY font-family declarations
|
|
|
|
|
defp generate_typography(typography) do
|
|
|
|
|
%{heading: heading_key, body: body_key} = Fonts.fonts_for_typography(typography)
|
|
|
|
|
style = Map.get(@typography_styles, typography, @typography_styles["clean"])
|
2026-01-17 21:43:26 +00:00
|
|
|
|
|
|
|
|
"""
|
2026-01-25 00:33:24 +00:00
|
|
|
--t-font-heading: #{Fonts.font_family(heading_key)};
|
|
|
|
|
--t-font-body: #{Fonts.font_family(body_key)};
|
|
|
|
|
--t-heading-weight: #{style.weight};
|
|
|
|
|
--t-heading-tracking: #{style.tracking};
|
2026-01-17 21:43:26 +00:00
|
|
|
"""
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# Shape - border radii
|
|
|
|
|
defp generate_shape("soft") do
|
|
|
|
|
"""
|
|
|
|
|
--t-radius-sm: 0.25rem;
|
|
|
|
|
--t-radius-md: 0.5rem;
|
|
|
|
|
--t-radius-lg: 0.75rem;
|
|
|
|
|
--t-radius-button: 0.5rem;
|
|
|
|
|
--t-radius-card: 0.75rem;
|
|
|
|
|
--t-radius-input: 0.5rem;
|
|
|
|
|
--t-radius-image: 0.5rem;
|
|
|
|
|
"""
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_shape("sharp") do
|
|
|
|
|
"""
|
|
|
|
|
--t-radius-sm: 0;
|
|
|
|
|
--t-radius-md: 0;
|
|
|
|
|
--t-radius-lg: 0;
|
|
|
|
|
--t-radius-button: 0;
|
|
|
|
|
--t-radius-card: 0;
|
|
|
|
|
--t-radius-input: 0;
|
|
|
|
|
--t-radius-image: 0;
|
|
|
|
|
"""
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_shape("round") do
|
|
|
|
|
"""
|
|
|
|
|
--t-radius-sm: 0.5rem;
|
|
|
|
|
--t-radius-md: 0.75rem;
|
|
|
|
|
--t-radius-lg: 1rem;
|
|
|
|
|
--t-radius-button: 0.75rem;
|
|
|
|
|
--t-radius-card: 1rem;
|
|
|
|
|
--t-radius-input: 0.75rem;
|
|
|
|
|
--t-radius-image: 0.75rem;
|
|
|
|
|
"""
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_shape("pill") do
|
|
|
|
|
"""
|
|
|
|
|
--t-radius-sm: 9999px;
|
|
|
|
|
--t-radius-md: 9999px;
|
|
|
|
|
--t-radius-lg: 1rem;
|
|
|
|
|
--t-radius-button: 9999px;
|
|
|
|
|
--t-radius-card: 1rem;
|
|
|
|
|
--t-radius-input: 9999px;
|
|
|
|
|
--t-radius-image: 0.75rem;
|
|
|
|
|
"""
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# Fallback for any other shape value
|
|
|
|
|
defp generate_shape(_), do: generate_shape("soft")
|
|
|
|
|
|
|
|
|
|
# Density - spacing multiplier
|
|
|
|
|
defp generate_density("balanced") do
|
|
|
|
|
"""
|
|
|
|
|
--t-density: 1;
|
|
|
|
|
--space-xs: 0.5rem;
|
|
|
|
|
--space-sm: 0.75rem;
|
|
|
|
|
--space-md: 1rem;
|
|
|
|
|
--space-lg: 1.5rem;
|
|
|
|
|
--space-xl: 2rem;
|
|
|
|
|
--space-2xl: 3rem;
|
|
|
|
|
"""
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_density("spacious") do
|
|
|
|
|
"""
|
|
|
|
|
--t-density: 1.25;
|
|
|
|
|
--space-xs: 0.625rem;
|
|
|
|
|
--space-sm: 0.9375rem;
|
|
|
|
|
--space-md: 1.25rem;
|
|
|
|
|
--space-lg: 1.875rem;
|
|
|
|
|
--space-xl: 2.5rem;
|
|
|
|
|
--space-2xl: 3.75rem;
|
|
|
|
|
"""
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_density("compact") do
|
|
|
|
|
"""
|
|
|
|
|
--t-density: 0.85;
|
|
|
|
|
--space-xs: 0.425rem;
|
|
|
|
|
--space-sm: 0.6375rem;
|
|
|
|
|
--space-md: 0.85rem;
|
|
|
|
|
--space-lg: 1.275rem;
|
|
|
|
|
--space-xl: 1.7rem;
|
|
|
|
|
--space-2xl: 2.55rem;
|
|
|
|
|
"""
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# Fallback for any other density value
|
|
|
|
|
defp generate_density(_), do: generate_density("balanced")
|
|
|
|
|
|
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
2025-12-30 21:41:25 +00:00
|
|
|
# Accent color with HSL breakdown
|
|
|
|
|
defp generate_accent(hex_color) do
|
|
|
|
|
{h, s, l} = hex_to_hsl(hex_color)
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
--t-accent-h: #{h};
|
|
|
|
|
--t-accent-s: #{s}%;
|
|
|
|
|
--t-accent-l: #{l}%;
|
|
|
|
|
"""
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# Secondary colors
|
|
|
|
|
defp generate_secondary_colors(settings) do
|
|
|
|
|
"""
|
|
|
|
|
--t-secondary-accent: #{settings.secondary_accent_color};
|
|
|
|
|
--t-sale-color: #{settings.sale_color};
|
|
|
|
|
"""
|
|
|
|
|
end
|
|
|
|
|
|
2026-01-02 13:48:03 +00:00
|
|
|
# Font size variations
|
|
|
|
|
# Using 18px as base for better accessibility (WCAG recommends 18px+)
|
|
|
|
|
# Small: 18px, Medium: 19px, Large: 20px
|
|
|
|
|
defp generate_font_size("small") do
|
|
|
|
|
"--t-font-size-scale: 1.125;"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_font_size("medium") do
|
|
|
|
|
"--t-font-size-scale: 1.1875;"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_font_size("large") do
|
|
|
|
|
"--t-font-size-scale: 1.25;"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# Heading weight (override typography default)
|
|
|
|
|
defp generate_heading_weight("regular") do
|
|
|
|
|
"--t-heading-weight-override: 400;"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_heading_weight("medium") do
|
|
|
|
|
"--t-heading-weight-override: 500;"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_heading_weight("bold") do
|
|
|
|
|
"--t-heading-weight-override: 700;"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# Layout width
|
|
|
|
|
defp generate_layout_width("contained") do
|
|
|
|
|
"--t-layout-max-width: 1100px;"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_layout_width("wide") do
|
|
|
|
|
"--t-layout-max-width: 1400px;"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_layout_width("full") do
|
|
|
|
|
"--t-layout-max-width: 100%;"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# Button style
|
|
|
|
|
defp generate_button_style("filled") do
|
|
|
|
|
"--t-button-style: filled;"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_button_style("outline") do
|
|
|
|
|
"--t-button-style: outline;"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_button_style("soft") do
|
|
|
|
|
"--t-button-style: soft;"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# Product text alignment
|
|
|
|
|
defp generate_product_text_align("left") do
|
|
|
|
|
"--t-product-text-align: left;"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_product_text_align("center") do
|
|
|
|
|
"--t-product-text-align: center;"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# Image aspect ratio
|
|
|
|
|
defp generate_image_aspect_ratio("square") do
|
|
|
|
|
"--t-image-aspect-ratio: 1 / 1;"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_image_aspect_ratio("portrait") do
|
|
|
|
|
"--t-image-aspect-ratio: 3 / 4;"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp generate_image_aspect_ratio("landscape") do
|
|
|
|
|
"--t-image-aspect-ratio: 4 / 3;"
|
|
|
|
|
end
|
|
|
|
|
|
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
2025-12-30 21:41:25 +00:00
|
|
|
# Convert hex color to HSL
|
|
|
|
|
defp hex_to_hsl("#" <> hex), do: hex_to_hsl(hex)
|
|
|
|
|
|
|
|
|
|
defp hex_to_hsl(hex) when byte_size(hex) == 6 do
|
|
|
|
|
{r, ""} = Integer.parse(String.slice(hex, 0..1), 16)
|
|
|
|
|
{g, ""} = Integer.parse(String.slice(hex, 2..3), 16)
|
|
|
|
|
{b, ""} = Integer.parse(String.slice(hex, 4..5), 16)
|
|
|
|
|
|
|
|
|
|
# Normalize RGB values to 0-1
|
|
|
|
|
r = r / 255
|
|
|
|
|
g = g / 255
|
|
|
|
|
b = b / 255
|
|
|
|
|
|
|
|
|
|
max = Enum.max([r, g, b])
|
|
|
|
|
min = Enum.min([r, g, b])
|
|
|
|
|
delta = max - min
|
|
|
|
|
|
|
|
|
|
# Calculate lightness
|
|
|
|
|
l = (max + min) / 2
|
|
|
|
|
|
|
|
|
|
# Calculate saturation and hue
|
|
|
|
|
{h, s} =
|
|
|
|
|
if delta == 0 do
|
|
|
|
|
{0, 0}
|
|
|
|
|
else
|
|
|
|
|
s = if l > 0.5, do: delta / (2 - max - min), else: delta / (max + min)
|
|
|
|
|
|
|
|
|
|
h =
|
|
|
|
|
cond do
|
|
|
|
|
max == r -> (g - b) / delta + if(g < b, do: 6, else: 0)
|
|
|
|
|
max == g -> (b - r) / delta + 2
|
|
|
|
|
max == b -> (r - g) / delta + 4
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
{h * 60, s}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
{round(h), round(s * 100), round(l * 100)}
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# Handle invalid hex values
|
|
|
|
|
defp hex_to_hsl(_), do: {0, 0, 50}
|
|
|
|
|
end
|