berrypod/lib/simpleshop_theme/settings/theme_settings.ex
Jamey Greenwood a8c0e150c8 feat: enhance theme customization with layout controls and real product images
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>
2026-01-01 16:16:05 +00:00

110 lines
3.9 KiB
Elixir

defmodule SimpleshopTheme.Settings.ThemeSettings do
use Ecto.Schema
import Ecto.Changeset
@derive Jason.Encoder
@primary_key false
embedded_schema do
# Core theme tokens
field :mood, :string, default: "neutral"
field :typography, :string, default: "clean"
field :shape, :string, default: "soft"
field :density, :string, default: "balanced"
field :grid_columns, :string, default: "4"
field :header_layout, :string, default: "standard"
field :accent_color, :string, default: "#f97316"
# Branding
field :site_name, :string, default: "Store Name"
field :logo_mode, :string, default: "text-only"
field :logo_image_id, :binary_id
field :logo_size, :integer, default: 36
field :logo_recolor, :boolean, default: false
field :logo_color, :string, default: "#171717"
# Header Background
field :header_background_enabled, :boolean, default: false
field :header_image_id, :binary_id
field :header_zoom, :integer, default: 100
field :header_position_x, :integer, default: 50
field :header_position_y, :integer, default: 50
# Advanced customization
field :secondary_accent_color, :string, default: "#ea580c"
field :sale_color, :string, default: "#dc2626"
field :font_size, :string, default: "medium"
field :heading_weight, :string, default: "bold"
field :layout_width, :string, default: "wide"
field :button_style, :string, default: "filled"
field :card_shadow, :string, default: "none"
field :product_text_align, :string, default: "left"
field :image_aspect_ratio, :string, default: "square"
# Feature toggles
field :announcement_bar, :boolean, default: true
field :sticky_header, :boolean, default: false
field :hover_image, :boolean, default: true
field :quick_add, :boolean, default: true
field :show_prices, :boolean, default: true
field :pdp_trust_badges, :boolean, default: true
field :pdp_reviews, :boolean, default: true
field :pdp_related_products, :boolean, default: true
end
@doc false
def changeset(settings, attrs) do
settings
|> cast(attrs, [
:mood,
:typography,
:shape,
:density,
:grid_columns,
:header_layout,
:accent_color,
:site_name,
:logo_mode,
:logo_image_id,
:logo_size,
:logo_recolor,
:logo_color,
:header_background_enabled,
:header_image_id,
:header_zoom,
:header_position_x,
:header_position_y,
:secondary_accent_color,
:sale_color,
:font_size,
:heading_weight,
:layout_width,
:button_style,
:card_shadow,
:product_text_align,
:image_aspect_ratio,
:announcement_bar,
:sticky_header,
:hover_image,
:quick_add,
:show_prices,
:pdp_trust_badges,
:pdp_reviews,
:pdp_related_products
])
|> validate_required([:mood, :typography, :shape, :density])
|> validate_inclusion(:mood, ~w(neutral warm cool dark))
|> validate_inclusion(:typography, ~w(clean editorial modern classic friendly minimal impulse))
|> validate_inclusion(:shape, ~w(sharp soft round pill))
|> validate_inclusion(:density, ~w(spacious balanced compact))
|> validate_inclusion(:grid_columns, ~w(2 3 4))
|> validate_inclusion(:header_layout, ~w(standard centered left))
|> validate_inclusion(:logo_mode, ~w(text-only logo-text logo-only))
|> validate_number(:logo_size, greater_than_or_equal_to: 24, less_than_or_equal_to: 120)
|> validate_number(:header_zoom, greater_than_or_equal_to: 100, less_than_or_equal_to: 200)
|> validate_number(:header_position_x, greater_than_or_equal_to: 0, less_than_or_equal_to: 100)
|> validate_number(:header_position_y, greater_than_or_equal_to: 0, less_than_or_equal_to: 100)
|> validate_inclusion(:layout_width, ~w(contained wide full))
|> validate_inclusion(:card_shadow, ~w(none sm md lg))
end
end