berrypod/lib/simpleshop_theme_web/components/shop_components.ex
Jamey Greenwood 14b1af5314 refactor: extract search_modal to shared ShopComponents module
Move the search modal from ThemeLive.PreviewPages to the shared
ShopComponents module. Add optional hint_text attribute - preview
pages pass demo hint text while real stores can omit it.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 14:05:00 +00:00

126 lines
4.3 KiB
Elixir

defmodule SimpleshopThemeWeb.ShopComponents do
@moduledoc """
Provides shop/storefront UI components.
These components are shared between the theme preview system and
the public storefront pages. They render using CSS custom properties
defined by the theme settings.
"""
use Phoenix.Component
@doc """
Renders the announcement bar.
The bar displays promotional messaging at the top of the page.
It uses CSS custom properties for theming.
## Attributes
* `theme_settings` - Required. The theme settings map.
* `message` - Optional. The announcement message to display.
Defaults to "Free delivery on orders over £40".
## Examples
<.announcement_bar theme_settings={@theme_settings} />
<.announcement_bar theme_settings={@theme_settings} message="20% off this weekend!" />
"""
attr :theme_settings, :map, required: true
attr :message, :string, default: "Free delivery on orders over £40"
def announcement_bar(assigns) do
~H"""
<div
class="announcement-bar"
style="background-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l)); color: var(--t-text-inverse); text-align: center; padding: 0.5rem 1rem; font-size: var(--t-text-small);"
>
<p style="margin: 0;">{@message}</p>
</div>
"""
end
@doc """
Renders the skip link for keyboard navigation accessibility.
This is a standard accessibility pattern that allows keyboard users
to skip directly to the main content.
"""
def skip_link(assigns) do
~H"""
<a href="#main-content" class="skip-link">
Skip to main content
</a>
"""
end
@doc """
Renders the search modal overlay.
This is a modal dialog for searching products. Currently provides
the UI shell; search functionality will be added later.
## Attributes
* `hint_text` - Optional. Hint text shown below the search input.
Defaults to nil (no hint shown).
## Examples
<.search_modal />
<.search_modal hint_text="Try searching for \"mountain\" or \"forest\"" />
"""
attr :hint_text, :string, default: nil
def search_modal(assigns) do
~H"""
<div
id="search-modal"
class="search-modal"
style="position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 1001; display: none; align-items: flex-start; justify-content: center; padding-top: 10vh;"
phx-click={Phoenix.LiveView.JS.hide(to: "#search-modal")}
>
<div
class="search-modal-content w-full max-w-xl mx-4"
style="background: var(--t-surface-raised); border-radius: var(--t-radius-card); overflow: hidden; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);"
phx-click-away={Phoenix.LiveView.JS.hide(to: "#search-modal")}
>
<div
class="flex items-center gap-3 p-4"
style="border-bottom: 1px solid var(--t-border-default);"
>
<svg class="w-5 h-5 flex-shrink-0" style="color: var(--t-text-tertiary);" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8"></circle>
<path d="M21 21l-4.35-4.35"></path>
</svg>
<input
type="text"
id="search-input"
class="flex-1 text-lg bg-transparent border-none outline-none"
style="font-family: var(--t-font-body); color: var(--t-text-primary);"
placeholder="Search products..."
phx-click={Phoenix.LiveView.JS.dispatch("stop-propagation")}
/>
<button
type="button"
class="w-8 h-8 flex items-center justify-center transition-all"
style="color: var(--t-text-tertiary); background: none; border: none; cursor: pointer; border-radius: var(--t-radius-button);"
phx-click={Phoenix.LiveView.JS.hide(to: "#search-modal")}
aria-label="Close search"
>
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
<%= if @hint_text do %>
<div class="p-6" style="color: var(--t-text-tertiary);">
<p class="text-sm">{@hint_text}</p>
</div>
<% end %>
</div>
</div>
"""
end
end