All checks were successful
deploy / deploy (push) Successful in 1m27s
Replace individual shop LiveViews with a single Shop.Page that dispatches to page modules based on live_action. This enables patch navigation between pages, preserving socket state (including editor state) across transitions. Changes: - Add Shop.Page unified LiveView with handle_params dispatch - Extract page logic into Shop.Pages.* modules (Home, Product, Collection, etc.) - Update router to use Shop.Page with live_action for all shop routes - Change navigate= to patch= in shop component links - Add maybe_sync_editing_blocks to reload editor state when page changes - Track editor_page_slug to detect cross-page navigation while editing - Fix picture element height when hover image disabled - Extract ThemeEditor components for shared use Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
244 lines
5.7 KiB
Elixir
244 lines
5.7 KiB
Elixir
defmodule BerrypodWeb.ShopComponents.Base do
|
|
use Phoenix.Component
|
|
|
|
@doc """
|
|
Renders a themed text input.
|
|
|
|
This component applies the `.themed-input` CSS class which inherits
|
|
colors, borders, and radii from the current theme's CSS variables.
|
|
|
|
## Attributes
|
|
|
|
* `type` - Optional. Input type. Defaults to "text".
|
|
* `class` - Optional. Additional CSS classes.
|
|
* All other attributes are passed through to the input element.
|
|
|
|
## Examples
|
|
|
|
<.shop_input type="email" placeholder="your@email.com" />
|
|
<.shop_input type="text" name="name" class="flex-1" />
|
|
"""
|
|
attr :type, :string, default: "text"
|
|
attr :class, :string, default: nil
|
|
attr :rest, :global, include: ~w(name value placeholder required disabled autocomplete readonly)
|
|
|
|
def shop_input(assigns) do
|
|
~H"""
|
|
<input type={@type} class={["themed-input", @class]} {@rest} />
|
|
"""
|
|
end
|
|
|
|
@doc """
|
|
Renders a themed textarea.
|
|
|
|
## Attributes
|
|
|
|
* `class` - Optional. Additional CSS classes.
|
|
* All other attributes are passed through to the textarea element.
|
|
|
|
## Examples
|
|
|
|
<.shop_textarea placeholder="Your message..." rows="5" />
|
|
"""
|
|
attr :class, :string, default: nil
|
|
attr :rest, :global, include: ~w(name rows placeholder required disabled readonly)
|
|
|
|
def shop_textarea(assigns) do
|
|
~H"""
|
|
<textarea class={["themed-input", @class]} {@rest}></textarea>
|
|
"""
|
|
end
|
|
|
|
@doc """
|
|
Renders a themed select dropdown.
|
|
|
|
## Attributes
|
|
|
|
* `class` - Optional. Additional CSS classes.
|
|
* `options` - Required. List of options (strings or {value, label} tuples).
|
|
* `selected` - Optional. Currently selected value.
|
|
* All other attributes are passed through to the select element.
|
|
|
|
## Examples
|
|
|
|
<.shop_select options={["Option 1", "Option 2"]} />
|
|
<.shop_select options={[{"value", "Label"}]} selected="value" />
|
|
"""
|
|
attr :class, :string, default: nil
|
|
attr :options, :list, required: true
|
|
attr :selected, :any, default: nil
|
|
attr :rest, :global, include: ~w(name required disabled aria-label)
|
|
|
|
def shop_select(assigns) do
|
|
~H"""
|
|
<select class={["themed-select", @class]} {@rest}>
|
|
<%= for option <- @options do %>
|
|
<%= case option do %>
|
|
<% {value, label} -> %>
|
|
<option value={value} selected={@selected == value}>{label}</option>
|
|
<% label -> %>
|
|
<option selected={@selected == label}>{label}</option>
|
|
<% end %>
|
|
<% end %>
|
|
</select>
|
|
"""
|
|
end
|
|
|
|
@doc """
|
|
Renders a themed primary button (accent color background).
|
|
|
|
## Attributes
|
|
|
|
* `class` - Optional. Additional CSS classes.
|
|
* `type` - Optional. Button type. Defaults to "button".
|
|
* All other attributes are passed through to the button element.
|
|
|
|
## Slots
|
|
|
|
* `inner_block` - Required. Button content.
|
|
|
|
## Examples
|
|
|
|
<.shop_button>Send Message</.shop_button>
|
|
<.shop_button type="submit" class="w-full">Subscribe</.shop_button>
|
|
"""
|
|
attr :class, :string, default: nil
|
|
attr :type, :string, default: "button"
|
|
attr :rest, :global, include: ~w(disabled name value phx-click phx-value-page)
|
|
|
|
slot :inner_block, required: true
|
|
|
|
def shop_button(assigns) do
|
|
~H"""
|
|
<button type={@type} class={["themed-button", @class]} {@rest}>
|
|
{render_slot(@inner_block)}
|
|
</button>
|
|
"""
|
|
end
|
|
|
|
@doc """
|
|
Renders a themed outline/secondary button.
|
|
|
|
## Attributes
|
|
|
|
* `class` - Optional. Additional CSS classes.
|
|
* `type` - Optional. Button type. Defaults to "button".
|
|
* All other attributes are passed through to the button element.
|
|
|
|
## Slots
|
|
|
|
* `inner_block` - Required. Button content.
|
|
|
|
## Examples
|
|
|
|
<.shop_button_outline>Continue Shopping</.shop_button_outline>
|
|
"""
|
|
attr :class, :string, default: nil
|
|
attr :type, :string, default: "button"
|
|
attr :rest, :global, include: ~w(disabled name value phx-click phx-value-page)
|
|
|
|
slot :inner_block, required: true
|
|
|
|
def shop_button_outline(assigns) do
|
|
~H"""
|
|
<button type={@type} class={["themed-button-outline", @class]} {@rest}>
|
|
{render_slot(@inner_block)}
|
|
</button>
|
|
"""
|
|
end
|
|
|
|
@doc """
|
|
Renders a themed link styled as a primary button.
|
|
|
|
## Attributes
|
|
|
|
* `href` - Required. Link destination.
|
|
* `class` - Optional. Additional CSS classes.
|
|
|
|
## Slots
|
|
|
|
* `inner_block` - Required. Link content.
|
|
|
|
## Examples
|
|
|
|
<.shop_link_button href="/checkout">Checkout</.shop_link_button>
|
|
"""
|
|
attr :href, :string, required: true
|
|
attr :class, :string, default: nil
|
|
|
|
slot :inner_block, required: true
|
|
|
|
def shop_link_button(assigns) do
|
|
~H"""
|
|
<.link
|
|
patch={@href}
|
|
class={["themed-button", @class]}
|
|
>
|
|
{render_slot(@inner_block)}
|
|
</.link>
|
|
"""
|
|
end
|
|
|
|
@doc """
|
|
Renders a themed link styled as an outline button.
|
|
|
|
## Attributes
|
|
|
|
* `href` - Required. Link destination.
|
|
* `class` - Optional. Additional CSS classes.
|
|
|
|
## Slots
|
|
|
|
* `inner_block` - Required. Link content.
|
|
|
|
## Examples
|
|
|
|
<.shop_link_outline href="/collections/all">Continue Shopping</.shop_link_outline>
|
|
"""
|
|
attr :href, :string, required: true
|
|
attr :class, :string, default: nil
|
|
|
|
slot :inner_block, required: true
|
|
|
|
def shop_link_outline(assigns) do
|
|
~H"""
|
|
<.link
|
|
patch={@href}
|
|
class={["themed-button-outline", @class]}
|
|
>
|
|
{render_slot(@inner_block)}
|
|
</.link>
|
|
"""
|
|
end
|
|
|
|
@doc """
|
|
Renders a themed card container.
|
|
|
|
## Attributes
|
|
|
|
* `class` - Optional. Additional CSS classes.
|
|
|
|
## Slots
|
|
|
|
* `inner_block` - Required. Card content.
|
|
|
|
## Examples
|
|
|
|
<.shop_card class="p-6">
|
|
<h3>Card Title</h3>
|
|
<p>Card content...</p>
|
|
</.shop_card>
|
|
"""
|
|
attr :class, :string, default: nil
|
|
|
|
slot :inner_block, required: true
|
|
|
|
def shop_card(assigns) do
|
|
~H"""
|
|
<div class={["themed-card", @class]}>
|
|
{render_slot(@inner_block)}
|
|
</div>
|
|
"""
|
|
end
|
|
end
|