Add comprehensive layout and styling controls including header layout options (standard, centered, left), content width settings (contained, wide, full), and card shadow levels. Update all theme presets with these new settings. Replace placeholder images with real Unsplash product and category images for more realistic previews. Add announcement bar and sticky header toggle options for enhanced header customization. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
227 lines
5.0 KiB
Elixir
227 lines
5.0 KiB
Elixir
defmodule SimpleshopTheme.Theme.Presets do
|
|
@moduledoc """
|
|
Defines the 8 curated theme presets for SimpleShop.
|
|
"""
|
|
|
|
@presets %{
|
|
gallery: %{
|
|
mood: "warm",
|
|
typography: "editorial",
|
|
shape: "soft",
|
|
density: "spacious",
|
|
grid_columns: "3",
|
|
header_layout: "centered",
|
|
accent_color: "#e85d04",
|
|
layout_width: "wide",
|
|
card_shadow: "sm",
|
|
announcement_bar: true
|
|
},
|
|
studio: %{
|
|
mood: "neutral",
|
|
typography: "clean",
|
|
shape: "soft",
|
|
density: "balanced",
|
|
grid_columns: "4",
|
|
header_layout: "standard",
|
|
accent_color: "#3b82f6",
|
|
layout_width: "wide",
|
|
card_shadow: "sm",
|
|
announcement_bar: true
|
|
},
|
|
boutique: %{
|
|
mood: "warm",
|
|
typography: "classic",
|
|
shape: "soft",
|
|
density: "balanced",
|
|
grid_columns: "3",
|
|
header_layout: "left",
|
|
accent_color: "#b45309",
|
|
layout_width: "contained",
|
|
card_shadow: "md",
|
|
announcement_bar: true
|
|
},
|
|
bold: %{
|
|
mood: "neutral",
|
|
typography: "modern",
|
|
shape: "sharp",
|
|
density: "compact",
|
|
grid_columns: "4",
|
|
header_layout: "standard",
|
|
accent_color: "#dc2626",
|
|
layout_width: "full",
|
|
card_shadow: "none",
|
|
announcement_bar: true
|
|
},
|
|
playful: %{
|
|
mood: "neutral",
|
|
typography: "friendly",
|
|
shape: "pill",
|
|
density: "balanced",
|
|
grid_columns: "4",
|
|
header_layout: "standard",
|
|
accent_color: "#8b5cf6",
|
|
layout_width: "wide",
|
|
card_shadow: "md",
|
|
announcement_bar: true
|
|
},
|
|
minimal: %{
|
|
mood: "neutral",
|
|
typography: "impulse",
|
|
shape: "sharp",
|
|
density: "spacious",
|
|
grid_columns: "2",
|
|
header_layout: "standard",
|
|
accent_color: "#171717",
|
|
layout_width: "full",
|
|
card_shadow: "none",
|
|
announcement_bar: false
|
|
},
|
|
night: %{
|
|
mood: "dark",
|
|
typography: "modern",
|
|
shape: "soft",
|
|
density: "balanced",
|
|
grid_columns: "4",
|
|
header_layout: "standard",
|
|
accent_color: "#f97316",
|
|
layout_width: "wide",
|
|
card_shadow: "lg",
|
|
announcement_bar: true
|
|
},
|
|
classic: %{
|
|
mood: "warm",
|
|
typography: "classic",
|
|
shape: "soft",
|
|
density: "spacious",
|
|
grid_columns: "3",
|
|
header_layout: "standard",
|
|
accent_color: "#166534",
|
|
layout_width: "contained",
|
|
card_shadow: "sm",
|
|
announcement_bar: true
|
|
}
|
|
}
|
|
|
|
@descriptions %{
|
|
gallery: "Elegant & editorial",
|
|
studio: "Clean & professional",
|
|
boutique: "Warm & sophisticated",
|
|
bold: "High contrast, strong",
|
|
playful: "Fun & approachable",
|
|
minimal: "Light & airy",
|
|
night: "Dark & dramatic",
|
|
classic: "Traditional & refined"
|
|
}
|
|
|
|
# Core keys used to match presets (excludes branding-specific settings)
|
|
@core_keys ~w(mood typography shape density grid_columns header_layout accent_color layout_width card_shadow announcement_bar)a
|
|
|
|
@doc """
|
|
Returns all available presets.
|
|
|
|
## Examples
|
|
|
|
iex> all()
|
|
%{gallery: %{...}, studio: %{...}, ...}
|
|
|
|
"""
|
|
def all, do: @presets
|
|
|
|
@doc """
|
|
Gets a preset by name.
|
|
|
|
## Examples
|
|
|
|
iex> get(:gallery)
|
|
%{mood: "warm", typography: "editorial", ...}
|
|
|
|
iex> get(:nonexistent)
|
|
nil
|
|
|
|
"""
|
|
def get(preset_name) when is_atom(preset_name) do
|
|
Map.get(@presets, preset_name)
|
|
end
|
|
|
|
@doc """
|
|
Lists all preset names.
|
|
|
|
## Examples
|
|
|
|
iex> list_names()
|
|
[:gallery, :studio, :boutique, :bold, :playful, :minimal, :night, :classic]
|
|
|
|
"""
|
|
def list_names do
|
|
Map.keys(@presets)
|
|
end
|
|
|
|
@doc """
|
|
Gets the description for a preset.
|
|
|
|
## Examples
|
|
|
|
iex> get_description(:gallery)
|
|
"Elegant & editorial"
|
|
|
|
"""
|
|
def get_description(preset_name) when is_atom(preset_name) do
|
|
Map.get(@descriptions, preset_name, "")
|
|
end
|
|
|
|
@doc """
|
|
Returns all presets with their descriptions.
|
|
|
|
## Examples
|
|
|
|
iex> all_with_descriptions()
|
|
[{:bold, "High contrast, strong"}, ...]
|
|
|
|
"""
|
|
def all_with_descriptions do
|
|
@presets
|
|
|> Map.keys()
|
|
|> Enum.sort()
|
|
|> Enum.map(fn name -> {name, Map.get(@descriptions, name, "")} end)
|
|
end
|
|
|
|
@doc """
|
|
Detects which preset matches the current theme settings, if any.
|
|
Only compares core theme keys, ignoring branding-specific settings.
|
|
|
|
## Examples
|
|
|
|
iex> detect_preset(%ThemeSettings{mood: "warm", typography: "editorial", ...})
|
|
:gallery
|
|
|
|
iex> detect_preset(%ThemeSettings{...customized...})
|
|
nil
|
|
|
|
"""
|
|
def detect_preset(theme_settings) do
|
|
current_core = extract_core_values(theme_settings)
|
|
|
|
Enum.find_value(@presets, fn {name, preset} ->
|
|
preset_core = Map.take(preset, @core_keys)
|
|
|
|
if maps_match?(current_core, preset_core) do
|
|
name
|
|
else
|
|
nil
|
|
end
|
|
end)
|
|
end
|
|
|
|
defp extract_core_values(theme_settings) do
|
|
theme_settings
|
|
|> Map.from_struct()
|
|
|> Map.take(@core_keys)
|
|
end
|
|
|
|
defp maps_match?(map1, map2) do
|
|
Enum.all?(@core_keys, fn key ->
|
|
Map.get(map1, key) == Map.get(map2, key)
|
|
end)
|
|
end
|
|
end
|