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: "#2563eb", 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: "Editorial serif headlines", studio: "Clean modern sans-serif", boutique: "Elegant classic serif", bold: "Tech-forward geometric", playful: "Quirky variable font", minimal: "Light refined pairing", night: "Dark tech aesthetic", classic: "Traditional luxury serif" } # 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