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>
|
</div>
|
||||||
"""
|
"""
|
||||||
end
|
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
|
end
|
||||||
|
|||||||
@ -116,102 +116,6 @@ defmodule SimpleshopThemeWeb.ThemeLive.PreviewPages do
|
|||||||
"background-repeat: no-repeat; z-index: 0;"
|
"background-repeat: no-repeat; z-index: 0;"
|
||||||
end
|
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 """
|
@doc """
|
||||||
Renders the cart drawer (floating sidebar).
|
Renders the cart drawer (floating sidebar).
|
||||||
|
|||||||
@ -66,7 +66,7 @@
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.shop_footer theme_settings={@theme_settings} />
|
<.shop_footer theme_settings={@theme_settings} mode={:preview} />
|
||||||
|
|
||||||
<!-- Search Modal -->
|
<!-- Search Modal -->
|
||||||
<!-- Cart Drawer -->
|
<!-- Cart Drawer -->
|
||||||
|
|||||||
@ -119,7 +119,7 @@
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.shop_footer theme_settings={@theme_settings} />
|
<.shop_footer theme_settings={@theme_settings} mode={:preview} />
|
||||||
|
|
||||||
<!-- Search Modal -->
|
<!-- Search Modal -->
|
||||||
<!-- Cart Drawer -->
|
<!-- Cart Drawer -->
|
||||||
|
|||||||
@ -130,7 +130,7 @@
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.shop_footer theme_settings={@theme_settings} />
|
<.shop_footer theme_settings={@theme_settings} mode={:preview} />
|
||||||
|
|
||||||
<!-- Search Modal -->
|
<!-- Search Modal -->
|
||||||
<!-- Cart Drawer -->
|
<!-- Cart Drawer -->
|
||||||
|
|||||||
@ -186,7 +186,7 @@
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.shop_footer theme_settings={@theme_settings} />
|
<.shop_footer theme_settings={@theme_settings} mode={:preview} />
|
||||||
|
|
||||||
<!-- Search Modal -->
|
<!-- Search Modal -->
|
||||||
<!-- Cart Drawer -->
|
<!-- Cart Drawer -->
|
||||||
|
|||||||
@ -77,7 +77,7 @@
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.shop_footer theme_settings={@theme_settings} />
|
<.shop_footer theme_settings={@theme_settings} mode={:preview} />
|
||||||
|
|
||||||
<!-- Search Modal -->
|
<!-- Search Modal -->
|
||||||
<!-- Cart Drawer -->
|
<!-- Cart Drawer -->
|
||||||
|
|||||||
@ -151,7 +151,7 @@
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.shop_footer theme_settings={@theme_settings} />
|
<.shop_footer theme_settings={@theme_settings} mode={:preview} />
|
||||||
|
|
||||||
<!-- Cart Drawer -->
|
<!-- Cart Drawer -->
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.cart_drawer cart_items={SimpleshopTheme.Theme.PreviewData.cart_drawer_items()} />
|
<SimpleshopThemeWeb.ThemeLive.PreviewPages.cart_drawer cart_items={SimpleshopTheme.Theme.PreviewData.cart_drawer_items()} />
|
||||||
|
|||||||
@ -447,7 +447,7 @@
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.shop_footer theme_settings={@theme_settings} />
|
<.shop_footer theme_settings={@theme_settings} mode={:preview} />
|
||||||
|
|
||||||
<!-- Search Modal -->
|
<!-- Search Modal -->
|
||||||
<!-- Cart Drawer -->
|
<!-- Cart Drawer -->
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user