feat: add default content pages for delivery, privacy and terms

Replace one-off ShopLive.About with generic ShopLive.Content that
handles all static content pages via live_action. Add delivery &
returns, privacy policy, and terms of service pages with sample
content. Update footer help links and theme editor preview.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-02-08 10:47:54 +00:00
parent 0af8997623
commit 5a43cfc761
10 changed files with 523 additions and 115 deletions

View File

@@ -1,51 +0,0 @@
<div
id="shop-container"
phx-hook="CartPersist"
class="shop-container min-h-screen pb-20 md:pb-0"
style="background-color: var(--t-surface-base); font-family: var(--t-font-body); color: var(--t-text-primary);"
>
<.skip_link />
<%= if @theme_settings.announcement_bar do %>
<.announcement_bar theme_settings={@theme_settings} />
<% end %>
<.shop_header
theme_settings={@theme_settings}
logo_image={@logo_image}
header_image={@header_image}
active_page="about"
mode={@mode}
cart_count={@cart_count}
/>
<main id="main-content" class="content-page" style="background-color: var(--t-surface-base);">
<.hero_section
title="About the studio"
description="Your story goes here this is sample content for the demo shop"
background={:sunken}
/>
<.content_body
image_src="/mockups/night-sky-blanket-3"
image_alt="Night sky blanket draped over a chair"
>
<.rich_text blocks={SimpleshopTheme.Theme.PreviewData.about_content()} />
</.content_body>
</main>
<.shop_footer theme_settings={@theme_settings} mode={@mode} />
<.cart_drawer
cart_items={@cart_items}
subtotal={@cart_subtotal}
cart_count={@cart_count}
mode={@mode}
open={assigns[:cart_drawer_open] || false}
cart_status={assigns[:cart_status]}
/>
<.search_modal hint_text={~s(Try a search e.g. "mountain" or "notebook")} />
<.mobile_bottom_nav active_page="about" mode={@mode} />
</div>

View File

@@ -0,0 +1,71 @@
<div
id="shop-container"
phx-hook="CartPersist"
class="shop-container min-h-screen pb-20 md:pb-0"
style="background-color: var(--t-surface-base); font-family: var(--t-font-body); color: var(--t-text-primary);"
>
<.skip_link />
<%= if @theme_settings.announcement_bar do %>
<.announcement_bar theme_settings={@theme_settings} />
<% end %>
<.shop_header
theme_settings={@theme_settings}
logo_image={@logo_image}
header_image={@header_image}
active_page={@active_page}
mode={@mode}
cart_count={@cart_count}
/>
<main id="main-content" class="content-page" style="background-color: var(--t-surface-base);">
<%= if assigns[:hero_background] do %>
<.hero_section
title={@hero_title}
description={@hero_description}
background={@hero_background}
/>
<% else %>
<.hero_section
variant={:page}
title={@hero_title}
description={@hero_description}
/>
<% end %>
<div style="padding: var(--space-xl) var(--space-lg); max-width: 800px; margin: 0 auto;">
<%= if assigns[:image_src] do %>
<div
class="content-image"
style="margin-bottom: var(--space-lg); border-radius: var(--t-radius-image); overflow: hidden;"
>
<.responsive_image
src={@image_src}
source_width={1200}
alt={@image_alt}
sizes="(max-width: 800px) 100vw, 800px"
class="w-full h-[300px] object-cover"
/>
</div>
<% end %>
<.rich_text blocks={@content_blocks} />
</div>
</main>
<.shop_footer theme_settings={@theme_settings} mode={@mode} />
<.cart_drawer
cart_items={@cart_items}
subtotal={@cart_subtotal}
cart_count={@cart_count}
mode={@mode}
open={assigns[:cart_drawer_open] || false}
cart_status={assigns[:cart_status]}
/>
<.search_modal hint_text={~s(Try a search e.g. "mountain" or "notebook")} />
<.mobile_bottom_nav active_page={@active_page} mode={@mode} />
</div>

View File

@@ -691,22 +691,33 @@ defmodule SimpleshopThemeWeb.ShopComponents do
<a
href="#"
phx-click="change_preview_page"
phx-value-page="about"
phx-value-page="delivery"
class="transition-colors hover:opacity-80"
style="color: var(--t-text-secondary); cursor: pointer;"
>
Delivery
Delivery & returns
</a>
</li>
<li>
<a
href="#"
phx-click="change_preview_page"
phx-value-page="about"
phx-value-page="privacy"
class="transition-colors hover:opacity-80"
style="color: var(--t-text-secondary); cursor: pointer;"
>
Returns
Privacy policy
</a>
</li>
<li>
<a
href="#"
phx-click="change_preview_page"
phx-value-page="terms"
class="transition-colors hover:opacity-80"
style="color: var(--t-text-secondary); cursor: pointer;"
>
Terms of service
</a>
</li>
<li>
@@ -723,20 +734,29 @@ defmodule SimpleshopThemeWeb.ShopComponents do
<% else %>
<li>
<a
href="/contact"
href="/delivery"
class="transition-colors hover:opacity-80"
style="color: var(--t-text-secondary);"
>
Delivery
Delivery & returns
</a>
</li>
<li>
<a
href="/contact"
href="/privacy"
class="transition-colors hover:opacity-80"
style="color: var(--t-text-secondary);"
>
Returns
Privacy policy
</a>
</li>
<li>
<a
href="/terms"
class="transition-colors hover:opacity-80"
style="color: var(--t-text-secondary);"
>
Terms of service
</a>
</li>
<li>
@@ -4205,6 +4225,16 @@ defmodule SimpleshopThemeWeb.ShopComponents do
"""
end
defp rich_text_block(%{block: %{type: :list}} = assigns) do
~H"""
<ul class="mb-4 ml-6 list-disc" style="color: var(--t-text-secondary);">
<%= for item <- @block.items do %>
<li class="mb-1">{item}</li>
<% end %>
</ul>
"""
end
defp rich_text_block(assigns) do
~H"""
<p class="mb-4" style="color: var(--t-text-secondary);">

View File

@@ -1,54 +0,0 @@
defmodule SimpleshopThemeWeb.ShopLive.About do
use SimpleshopThemeWeb, :live_view
alias SimpleshopTheme.Settings
alias SimpleshopTheme.Media
alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator}
@impl true
def mount(_params, _session, socket) do
theme_settings = Settings.get_theme_settings()
generated_css =
case CSSCache.get() do
{:ok, css} ->
css
:miss ->
css = CSSGenerator.generate(theme_settings)
CSSCache.put(css)
css
end
logo_image = Media.get_logo()
header_image = Media.get_header()
socket =
socket
|> assign(:page_title, "About")
|> assign(:theme_settings, theme_settings)
|> assign(:generated_css, generated_css)
|> assign(:logo_image, logo_image)
|> assign(:header_image, header_image)
|> assign(:mode, :shop)
{:ok, socket}
end
@impl true
def render(assigns) do
~H"""
<SimpleshopThemeWeb.PageTemplates.about
theme_settings={@theme_settings}
logo_image={@logo_image}
header_image={@header_image}
mode={@mode}
cart_items={@cart_items}
cart_count={@cart_count}
cart_subtotal={@cart_subtotal}
cart_drawer_open={@cart_drawer_open}
cart_status={@cart_status}
/>
"""
end
end

View File

@@ -0,0 +1,88 @@
defmodule SimpleshopThemeWeb.ShopLive.Content do
use SimpleshopThemeWeb, :live_view
alias SimpleshopTheme.{Settings, Media}
alias SimpleshopTheme.Theme.{CSSCache, CSSGenerator, PreviewData}
@impl true
def mount(_params, _session, socket) do
theme_settings = Settings.get_theme_settings()
generated_css =
case CSSCache.get() do
{:ok, css} ->
css
:miss ->
css = CSSGenerator.generate(theme_settings)
CSSCache.put(css)
css
end
socket =
socket
|> assign(:theme_settings, theme_settings)
|> assign(:generated_css, generated_css)
|> assign(:logo_image, Media.get_logo())
|> assign(:header_image, Media.get_header())
|> assign(:mode, :shop)
{:ok, socket}
end
@impl true
def handle_params(_params, _uri, socket) do
config = page_config(socket.assigns.live_action)
{:noreply, assign(socket, config)}
end
@impl true
def render(assigns) do
~H"""
<SimpleshopThemeWeb.PageTemplates.content {assigns} />
"""
end
defp page_config(:about) do
%{
page_title: "About",
active_page: "about",
hero_title: "About the studio",
hero_description: "Your story goes here this is sample content for the demo shop",
hero_background: :sunken,
image_src: "/mockups/night-sky-blanket-3",
image_alt: "Night sky blanket draped over a chair",
content_blocks: PreviewData.about_content()
}
end
defp page_config(:delivery) do
%{
page_title: "Delivery & returns",
active_page: "delivery",
hero_title: "Delivery & returns",
hero_description: "Everything you need to know about shipping and returns",
content_blocks: PreviewData.delivery_content()
}
end
defp page_config(:privacy) do
%{
page_title: "Privacy policy",
active_page: "privacy",
hero_title: "Privacy policy",
hero_description: "How we handle your personal information",
content_blocks: PreviewData.privacy_content()
}
end
defp page_config(:terms) do
%{
page_title: "Terms of service",
active_page: "terms",
hero_title: "Terms of service",
hero_description: "The legal bits",
content_blocks: PreviewData.terms_content()
}
end
end

View File

@@ -431,11 +431,75 @@ defmodule SimpleshopThemeWeb.ThemeLive.Index do
defp preview_page(%{page: :about} = assigns) do
~H"""
<SimpleshopThemeWeb.PageTemplates.about
<SimpleshopThemeWeb.PageTemplates.content
theme_settings={@theme_settings}
logo_image={@logo_image}
header_image={@header_image}
mode={:preview}
active_page="about"
hero_title="About the studio"
hero_description="Your story goes here this is sample content for the demo shop"
hero_background={:sunken}
image_src="/mockups/night-sky-blanket-3"
image_alt="Night sky blanket draped over a chair"
content_blocks={PreviewData.about_content()}
cart_items={PreviewData.cart_drawer_items()}
cart_count={2}
cart_subtotal="£72.00"
cart_drawer_open={@cart_drawer_open}
/>
"""
end
defp preview_page(%{page: :delivery} = assigns) do
~H"""
<SimpleshopThemeWeb.PageTemplates.content
theme_settings={@theme_settings}
logo_image={@logo_image}
header_image={@header_image}
mode={:preview}
active_page="delivery"
hero_title="Delivery & returns"
hero_description="Everything you need to know about shipping and returns"
content_blocks={PreviewData.delivery_content()}
cart_items={PreviewData.cart_drawer_items()}
cart_count={2}
cart_subtotal="£72.00"
cart_drawer_open={@cart_drawer_open}
/>
"""
end
defp preview_page(%{page: :privacy} = assigns) do
~H"""
<SimpleshopThemeWeb.PageTemplates.content
theme_settings={@theme_settings}
logo_image={@logo_image}
header_image={@header_image}
mode={:preview}
active_page="privacy"
hero_title="Privacy policy"
hero_description="How we handle your personal information"
content_blocks={PreviewData.privacy_content()}
cart_items={PreviewData.cart_drawer_items()}
cart_count={2}
cart_subtotal="£72.00"
cart_drawer_open={@cart_drawer_open}
/>
"""
end
defp preview_page(%{page: :terms} = assigns) do
~H"""
<SimpleshopThemeWeb.PageTemplates.content
theme_settings={@theme_settings}
logo_image={@logo_image}
header_image={@header_image}
mode={:preview}
active_page="terms"
hero_title="Terms of service"
hero_description="The legal bits"
content_blocks={PreviewData.terms_content()}
cart_items={PreviewData.cart_drawer_items()}
cart_count={2}
cart_subtotal="£72.00"

View File

@@ -1091,6 +1091,9 @@
{:pdp, "Product"},
{:cart, "Cart"},
{:about, "About"},
{:delivery, "Delivery"},
{:privacy, "Privacy"},
{:terms, "Terms"},
{:contact, "Contact"},
{:error, "404"}
] do %>

View File

@@ -34,7 +34,10 @@ defmodule SimpleshopThemeWeb.Router do
layout: {SimpleshopThemeWeb.Layouts, :shop},
on_mount: [{SimpleshopThemeWeb.CartHook, :mount_cart}] do
live "/", ShopLive.Home, :index
live "/about", ShopLive.About, :index
live "/about", ShopLive.Content, :about
live "/delivery", ShopLive.Content, :delivery
live "/privacy", ShopLive.Content, :privacy
live "/terms", ShopLive.Content, :terms
live "/contact", ShopLive.Contact, :index
live "/collections/:slug", ShopLive.Collection, :show
live "/products/:id", ShopLive.ProductShow, :show