refactor: extract shop_footer to shared ShopComponents module
Move the footer from ThemeLive.PreviewPages to the shared ShopComponents module. Add mode attribute (:live vs :preview) for navigation behavior. Preview mode uses phx-click handlers, live mode uses real URLs. Also makes copyright year dynamic. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
14b1af5314
commit
c72f6446a4
@ -122,4 +122,127 @@ defmodule SimpleshopThemeWeb.ShopComponents do
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders the shop footer with newsletter signup and links.
|
||||
|
||||
## Attributes
|
||||
|
||||
* `theme_settings` - Required. The theme settings map containing site_name.
|
||||
* `mode` - Optional. Either `:live` (default) for real navigation or
|
||||
`:preview` for theme preview mode with phx-click handlers.
|
||||
|
||||
## Examples
|
||||
|
||||
<.shop_footer theme_settings={@theme_settings} />
|
||||
<.shop_footer theme_settings={@theme_settings} mode={:preview} />
|
||||
"""
|
||||
attr :theme_settings, :map, required: true
|
||||
attr :mode, :atom, default: :live
|
||||
|
||||
def shop_footer(assigns) do
|
||||
assigns = assign(assigns, :current_year, Date.utc_today().year)
|
||||
|
||||
~H"""
|
||||
<footer style="background-color: var(--t-surface-raised); border-top: 1px solid var(--t-border-default);">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-12">
|
||||
<!-- Newsletter -->
|
||||
<div>
|
||||
<h3 class="text-xl font-bold mb-2" style="font-family: var(--t-font-heading); color: var(--t-text-primary); font-weight: var(--t-heading-weight);">
|
||||
Stay in touch
|
||||
</h3>
|
||||
<p class="mb-4 text-sm" style="color: var(--t-text-secondary);">
|
||||
Get 10% off your first order and be the first to know about new designs.
|
||||
</p>
|
||||
<form class="flex flex-wrap gap-2">
|
||||
<input
|
||||
type="email"
|
||||
placeholder="your@email.com"
|
||||
class="flex-1 min-w-0 px-4 py-2 text-sm"
|
||||
style="background-color: var(--t-surface-base); color: var(--t-text-primary); border: 1px solid var(--t-border-default); border-radius: var(--t-radius-input); min-width: 150px;"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
class="px-6 py-2 font-medium transition-all text-sm whitespace-nowrap"
|
||||
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);"
|
||||
>
|
||||
Subscribe
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Links -->
|
||||
<div class="grid grid-cols-2 gap-8">
|
||||
<div>
|
||||
<h4 class="font-semibold mb-4 text-sm" style="font-family: var(--t-font-heading); color: var(--t-text-primary);">
|
||||
Shop
|
||||
</h4>
|
||||
<ul class="space-y-2 text-sm">
|
||||
<%= if @mode == :preview do %>
|
||||
<li><a href="#" phx-click="change_preview_page" phx-value-page="collection" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary); cursor: pointer;">All products</a></li>
|
||||
<li><a href="#" phx-click="change_preview_page" phx-value-page="collection" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary); cursor: pointer;">New arrivals</a></li>
|
||||
<li><a href="#" phx-click="change_preview_page" phx-value-page="collection" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary); cursor: pointer;">Best sellers</a></li>
|
||||
<% else %>
|
||||
<li><a href="/products" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary);">All products</a></li>
|
||||
<li><a href="/products?sort=newest" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary);">New arrivals</a></li>
|
||||
<li><a href="/products?sort=popular" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary);">Best sellers</a></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="font-semibold mb-4 text-sm" style="font-family: var(--t-font-heading); color: var(--t-text-primary);">
|
||||
Help
|
||||
</h4>
|
||||
<ul class="space-y-2 text-sm">
|
||||
<%= if @mode == :preview do %>
|
||||
<li><a href="#" phx-click="change_preview_page" phx-value-page="about" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary); cursor: pointer;">Delivery</a></li>
|
||||
<li><a href="#" phx-click="change_preview_page" phx-value-page="about" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary); cursor: pointer;">Returns</a></li>
|
||||
<li><a href="#" phx-click="change_preview_page" phx-value-page="contact" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary); cursor: pointer;">Contact</a></li>
|
||||
<% else %>
|
||||
<li><a href="/delivery" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary);">Delivery</a></li>
|
||||
<li><a href="/returns" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary);">Returns</a></li>
|
||||
<li><a href="/contact" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary);">Contact</a></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom Bar -->
|
||||
<div class="mt-12 pt-8 flex flex-col md:flex-row justify-between items-center gap-4" style="border-top: 1px solid var(--t-border-subtle);">
|
||||
<p class="text-xs" style="color: var(--t-text-tertiary);">
|
||||
© {@current_year} {@theme_settings.site_name}
|
||||
</p>
|
||||
<div class="flex gap-2">
|
||||
<a
|
||||
href="#"
|
||||
class="social-link w-9 h-9 flex items-center justify-center transition-all"
|
||||
style="color: var(--t-text-secondary); border-radius: var(--t-radius-button);"
|
||||
aria-label="Instagram"
|
||||
>
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect>
|
||||
<path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path>
|
||||
<line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line>
|
||||
</svg>
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="social-link w-9 h-9 flex items-center justify-center transition-all"
|
||||
style="color: var(--t-text-secondary); border-radius: var(--t-radius-button);"
|
||||
aria-label="Pinterest"
|
||||
>
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
<path d="M8 12c0-2.2 1.8-4 4-4s4 1.8 4 4-1.8 4-4 4"></path>
|
||||
<line x1="12" y1="16" x2="9" y2="21"></line>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
"""
|
||||
end
|
||||
end
|
||||
|
||||
@ -116,102 +116,6 @@ defmodule SimpleshopThemeWeb.ThemeLive.PreviewPages do
|
||||
"background-repeat: no-repeat; z-index: 0;"
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders the shop footer with newsletter and links.
|
||||
"""
|
||||
attr :theme_settings, :map, required: true
|
||||
|
||||
def shop_footer(assigns) do
|
||||
~H"""
|
||||
<footer style="background-color: var(--t-surface-raised); border-top: 1px solid var(--t-border-default);">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-12">
|
||||
<!-- Newsletter -->
|
||||
<div>
|
||||
<h3 class="text-xl font-bold mb-2" style="font-family: var(--t-font-heading); color: var(--t-text-primary); font-weight: var(--t-heading-weight);">
|
||||
Stay in touch
|
||||
</h3>
|
||||
<p class="mb-4 text-sm" style="color: var(--t-text-secondary);">
|
||||
Get 10% off your first order and be the first to know about new designs.
|
||||
</p>
|
||||
<form class="flex flex-wrap gap-2">
|
||||
<input
|
||||
type="email"
|
||||
placeholder="your@email.com"
|
||||
class="flex-1 min-w-0 px-4 py-2 text-sm"
|
||||
style="background-color: var(--t-surface-base); color: var(--t-text-primary); border: 1px solid var(--t-border-default); border-radius: var(--t-radius-input); min-width: 150px;"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
class="px-6 py-2 font-medium transition-all text-sm whitespace-nowrap"
|
||||
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);"
|
||||
>
|
||||
Subscribe
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Links -->
|
||||
<div class="grid grid-cols-2 gap-8">
|
||||
<div>
|
||||
<h4 class="font-semibold mb-4 text-sm" style="font-family: var(--t-font-heading); color: var(--t-text-primary);">
|
||||
Shop
|
||||
</h4>
|
||||
<ul class="space-y-2 text-sm">
|
||||
<li><a href="#" phx-click="change_preview_page" phx-value-page="collection" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary); cursor: pointer;">All products</a></li>
|
||||
<li><a href="#" phx-click="change_preview_page" phx-value-page="collection" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary); cursor: pointer;">New arrivals</a></li>
|
||||
<li><a href="#" phx-click="change_preview_page" phx-value-page="collection" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary); cursor: pointer;">Best sellers</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="font-semibold mb-4 text-sm" style="font-family: var(--t-font-heading); color: var(--t-text-primary);">
|
||||
Help
|
||||
</h4>
|
||||
<ul class="space-y-2 text-sm">
|
||||
<li><a href="#" phx-click="change_preview_page" phx-value-page="about" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary); cursor: pointer;">Delivery</a></li>
|
||||
<li><a href="#" phx-click="change_preview_page" phx-value-page="about" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary); cursor: pointer;">Returns</a></li>
|
||||
<li><a href="#" phx-click="change_preview_page" phx-value-page="contact" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary); cursor: pointer;">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom Bar -->
|
||||
<div class="mt-12 pt-8 flex flex-col md:flex-row justify-between items-center gap-4" style="border-top: 1px solid var(--t-border-subtle);">
|
||||
<p class="text-xs" style="color: var(--t-text-tertiary);">
|
||||
© 2025 <%= @theme_settings.site_name %>
|
||||
</p>
|
||||
<div class="flex gap-2">
|
||||
<a
|
||||
href="#"
|
||||
class="social-link w-9 h-9 flex items-center justify-center transition-all"
|
||||
style="color: var(--t-text-secondary); border-radius: var(--t-radius-button);"
|
||||
aria-label="Instagram"
|
||||
>
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect>
|
||||
<path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path>
|
||||
<line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line>
|
||||
</svg>
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="social-link w-9 h-9 flex items-center justify-center transition-all"
|
||||
style="color: var(--t-text-secondary); border-radius: var(--t-radius-button);"
|
||||
aria-label="Pinterest"
|
||||
>
|
||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
<path d="M8 12c0-2.2 1.8-4 4-4s4 1.8 4 4-1.8 4-4 4"></path>
|
||||
<line x1="12" y1="16" x2="9" y2="21"></line>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders the cart drawer (floating sidebar).
|
||||
|
||||
@ -66,7 +66,7 @@
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.shop_footer theme_settings={@theme_settings} />
|
||||
<.shop_footer theme_settings={@theme_settings} mode={:preview} />
|
||||
|
||||
<!-- Search Modal -->
|
||||
<!-- Cart Drawer -->
|
||||
|
||||
@ -119,7 +119,7 @@
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.shop_footer theme_settings={@theme_settings} />
|
||||
<.shop_footer theme_settings={@theme_settings} mode={:preview} />
|
||||
|
||||
<!-- Search Modal -->
|
||||
<!-- Cart Drawer -->
|
||||
|
||||
@ -130,7 +130,7 @@
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.shop_footer theme_settings={@theme_settings} />
|
||||
<.shop_footer theme_settings={@theme_settings} mode={:preview} />
|
||||
|
||||
<!-- Search Modal -->
|
||||
<!-- Cart Drawer -->
|
||||
|
||||
@ -186,7 +186,7 @@
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.shop_footer theme_settings={@theme_settings} />
|
||||
<.shop_footer theme_settings={@theme_settings} mode={:preview} />
|
||||
|
||||
<!-- Search Modal -->
|
||||
<!-- Cart Drawer -->
|
||||
|
||||
@ -77,7 +77,7 @@
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.shop_footer theme_settings={@theme_settings} />
|
||||
<.shop_footer theme_settings={@theme_settings} mode={:preview} />
|
||||
|
||||
<!-- Search Modal -->
|
||||
<!-- Cart Drawer -->
|
||||
|
||||
@ -151,7 +151,7 @@
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.shop_footer theme_settings={@theme_settings} />
|
||||
<.shop_footer theme_settings={@theme_settings} mode={:preview} />
|
||||
|
||||
<!-- Cart Drawer -->
|
||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.cart_drawer cart_items={SimpleshopTheme.Theme.PreviewData.cart_drawer_items()} />
|
||||
|
||||
@ -447,7 +447,7 @@
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.shop_footer theme_settings={@theme_settings} />
|
||||
<.shop_footer theme_settings={@theme_settings} mode={:preview} />
|
||||
|
||||
<!-- Search Modal -->
|
||||
<!-- Cart Drawer -->
|
||||
|
||||
Loading…
Reference in New Issue
Block a user