refactor: extract hero_section to shared ShopComponents module

Create a centered hero section component with:
- Title (h1) and description (p)
- Optional CTA button with preview/live mode support
- Configurable background (:base or :sunken)

Used in: home page (with CTA), about page (without CTA)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jamey Greenwood 2026-01-17 14:54:11 +00:00
parent b2869514cb
commit f5b7693b96
3 changed files with 87 additions and 24 deletions

View File

@ -859,4 +859,79 @@ defmodule SimpleshopThemeWeb.ShopComponents do
|> Enum.reject(&(&1 == "")) |> Enum.reject(&(&1 == ""))
|> Enum.join(" ") |> Enum.join(" ")
end end
@doc """
Renders a centered hero section with title, description, and optional CTA.
## Attributes
* `title` - Required. The main heading text.
* `description` - Required. The description paragraph text.
* `background` - Background style. Either `:base` (default) or `:sunken`.
* `cta_text` - Optional. Text for the CTA button.
* `cta_page` - Optional. Page to navigate to on click (for preview mode).
* `mode` - Either `:live` (default) or `:preview`.
## Examples
<.hero_section
title="Original designs, printed on demand"
description="From art prints to apparel unique products created by independent artists."
cta_text="Shop the collection"
cta_page="collection"
mode={:preview}
/>
<.hero_section
title="About the studio"
description="Nature photography, printed with care"
background={:sunken}
/>
"""
attr :title, :string, required: true
attr :description, :string, required: true
attr :background, :atom, default: :base
attr :cta_text, :string, default: nil
attr :cta_page, :string, default: nil
attr :cta_href, :string, default: nil
attr :mode, :atom, default: :live
def hero_section(assigns) do
~H"""
<section
class="text-center"
style={"padding: var(--space-2xl) var(--space-lg); background-color: var(--t-surface-#{@background});"}
>
<h1
class="text-3xl md:text-4xl mb-4"
style="font-family: var(--t-font-heading); font-weight: var(--t-heading-weight); letter-spacing: var(--t-heading-tracking); color: var(--t-text-primary);"
>
<%= @title %>
</h1>
<p class="text-lg max-w-lg mx-auto mb-8" style="color: var(--t-text-secondary); line-height: 1.6;">
<%= @description %>
</p>
<%= if @cta_text do %>
<%= if @mode == :preview do %>
<button
phx-click="change_preview_page"
phx-value-page={@cta_page}
class="px-6 py-3 font-medium transition-all"
style="background-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l)); color: var(--t-text-inverse); border-radius: var(--t-radius-button); cursor: pointer; border: none;"
>
<%= @cta_text %>
</button>
<% else %>
<a
href={@cta_href || "/products"}
class="inline-block px-6 py-3 font-medium transition-all"
style="background-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l)); color: var(--t-text-inverse); border-radius: var(--t-radius-button); text-decoration: none;"
>
<%= @cta_text %>
</a>
<% end %>
<% end %>
</section>
"""
end
end end

View File

@ -13,14 +13,11 @@
<!-- Content Page --> <!-- Content Page -->
<main id="main-content" class="content-page" style="background-color: var(--t-surface-base);"> <main id="main-content" class="content-page" style="background-color: var(--t-surface-base);">
<!-- Hero Section --> <!-- Hero Section -->
<div class="content-hero text-center" style="padding: var(--space-2xl) var(--space-lg); background-color: var(--t-surface-sunken);"> <.hero_section
<h1 class="text-3xl md:text-4xl mb-3" style="font-family: var(--t-font-heading); font-weight: var(--t-heading-weight); letter-spacing: var(--t-heading-tracking); color: var(--t-text-primary);"> title="About the studio"
About the studio description="Nature photography, printed with care"
</h1> background={:sunken}
<p class="text-lg" style="color: var(--t-text-secondary);"> />
Nature photography, printed with care
</p>
</div>
<!-- Content Body --> <!-- Content Body -->
<div class="content-body" style="padding: var(--space-xl) var(--space-lg); max-width: 800px; margin: 0 auto;"> <div class="content-body" style="padding: var(--space-xl) var(--space-lg); max-width: 800px; margin: 0 auto;">

View File

@ -12,22 +12,13 @@
<!-- Hero Section --> <!-- Hero Section -->
<main id="main-content"> <main id="main-content">
<section class="text-center" style="padding: var(--space-2xl) var(--space-lg); background-color: var(--t-surface-base);"> <.hero_section
<h1 class="text-3xl md:text-4xl mb-4" style="font-family: var(--t-font-heading); font-weight: var(--t-heading-weight); letter-spacing: var(--t-heading-tracking); color: var(--t-text-primary);"> title="Original designs, printed on demand"
Original designs, printed on demand description="From art prints to apparel unique products created by independent artists and delivered straight to your door."
</h1> cta_text="Shop the collection"
<p class="text-lg max-w-lg mx-auto mb-8" style="color: var(--t-text-secondary); line-height: 1.6;"> cta_page="collection"
From art prints to apparel unique products created by independent artists and delivered straight to your door. mode={:preview}
</p> />
<button
phx-click="change_preview_page"
phx-value-page="collection"
class="px-6 py-3 font-medium transition-all"
style="background-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l)); color: var(--t-text-inverse); border-radius: var(--t-radius-button); cursor: pointer; border: none;"
>
Shop the collection
</button>
</section>
<!-- Categories --> <!-- Categories -->
<section style="padding: var(--space-xl) var(--space-lg); background-color: var(--t-surface-base);"> <section style="padding: var(--space-xl) var(--space-lg); background-color: var(--t-surface-base);">