refactor: extract product_grid to shared ShopComponents module
Create a reusable product grid component that handles responsive
column layouts. Supports two modes:
- Theme-based columns: Uses theme_settings.grid_columns for lg breakpoint
- Fixed columns: Use columns={:fixed_4} for 2/4 column layouts
Used in: home (featured), collection, pdp (related), error (suggestions)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
9746bf183c
commit
b2869514cb
@ -781,4 +781,82 @@ defmodule SimpleshopThemeWeb.ShopComponents do
|
|||||||
defp title_style(:featured), do: "color: var(--t-text-primary);"
|
defp title_style(:featured), do: "color: var(--t-text-primary);"
|
||||||
defp title_style(:compact), do: "font-family: var(--t-font-heading); color: var(--t-text-primary);"
|
defp title_style(:compact), do: "font-family: var(--t-font-heading); color: var(--t-text-primary);"
|
||||||
defp title_style(:minimal), do: "color: var(--t-text-primary);"
|
defp title_style(:minimal), do: "color: var(--t-text-primary);"
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Renders a responsive product grid container.
|
||||||
|
|
||||||
|
This component wraps product cards in a responsive grid layout. It supports
|
||||||
|
theme-based column settings or fixed column layouts for specific use cases.
|
||||||
|
|
||||||
|
## Attributes
|
||||||
|
|
||||||
|
* `theme_settings` - Optional. When provided, uses `grid_columns` setting for lg breakpoint.
|
||||||
|
* `columns` - Optional. Fixed column count for lg breakpoint (overrides theme_settings).
|
||||||
|
Use `:fixed_4` for a fixed 2/4 column layout (error page, related products).
|
||||||
|
* `gap` - Optional. Gap size. Defaults to standard gap.
|
||||||
|
* `class` - Optional. Additional CSS classes to add.
|
||||||
|
|
||||||
|
## Slots
|
||||||
|
|
||||||
|
* `inner_block` - Required. The product cards to render inside the grid.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
<.product_grid theme_settings={@theme_settings}>
|
||||||
|
<%= for product <- @products do %>
|
||||||
|
<.product_card product={product} theme_settings={@theme_settings} />
|
||||||
|
<% end %>
|
||||||
|
</.product_grid>
|
||||||
|
|
||||||
|
<.product_grid columns={:fixed_4} gap="gap-6">
|
||||||
|
...
|
||||||
|
</.product_grid>
|
||||||
|
"""
|
||||||
|
attr :theme_settings, :map, default: nil
|
||||||
|
attr :columns, :atom, default: nil
|
||||||
|
attr :gap, :string, default: nil
|
||||||
|
attr :class, :string, default: nil
|
||||||
|
|
||||||
|
slot :inner_block, required: true
|
||||||
|
|
||||||
|
def product_grid(assigns) do
|
||||||
|
~H"""
|
||||||
|
<div class={grid_classes(@theme_settings, @columns, @gap, @class)}>
|
||||||
|
<%= render_slot(@inner_block) %>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
defp grid_classes(theme_settings, columns, gap, extra_class) do
|
||||||
|
base = "product-grid grid"
|
||||||
|
|
||||||
|
cols =
|
||||||
|
cond do
|
||||||
|
columns == :fixed_4 ->
|
||||||
|
"grid-cols-2 md:grid-cols-4"
|
||||||
|
|
||||||
|
theme_settings != nil ->
|
||||||
|
responsive_cols = "grid-cols-1 sm:grid-cols-2"
|
||||||
|
|
||||||
|
lg_cols =
|
||||||
|
case theme_settings.grid_columns do
|
||||||
|
"2" -> "lg:grid-cols-2"
|
||||||
|
"3" -> "lg:grid-cols-3"
|
||||||
|
"4" -> "lg:grid-cols-4"
|
||||||
|
_ -> "lg:grid-cols-3"
|
||||||
|
end
|
||||||
|
|
||||||
|
"#{responsive_cols} #{lg_cols}"
|
||||||
|
|
||||||
|
true ->
|
||||||
|
"grid-cols-1 sm:grid-cols-2 lg:grid-cols-3"
|
||||||
|
end
|
||||||
|
|
||||||
|
gap_class = gap || ""
|
||||||
|
|
||||||
|
[base, cols, gap_class, extra_class]
|
||||||
|
|> Enum.reject(&is_nil/1)
|
||||||
|
|> Enum.reject(&(&1 == ""))
|
||||||
|
|> Enum.join(" ")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -52,25 +52,17 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Product Grid -->
|
<!-- Product Grid -->
|
||||||
<div class={[
|
<.product_grid theme_settings={@theme_settings}>
|
||||||
"product-grid grid grid-cols-1 sm:grid-cols-2",
|
<%= for product <- @preview_data.products do %>
|
||||||
case @theme_settings.grid_columns do
|
<.product_card
|
||||||
"2" -> "lg:grid-cols-2"
|
product={product}
|
||||||
"3" -> "lg:grid-cols-3"
|
theme_settings={@theme_settings}
|
||||||
"4" -> "lg:grid-cols-4"
|
mode={:preview}
|
||||||
_ -> "lg:grid-cols-3"
|
variant={:default}
|
||||||
end
|
show_category={true}
|
||||||
]}>
|
/>
|
||||||
<%= for product <- @preview_data.products do %>
|
<% end %>
|
||||||
<.product_card
|
</.product_grid>
|
||||||
product={product}
|
|
||||||
theme_settings={@theme_settings}
|
|
||||||
mode={:preview}
|
|
||||||
variant={:default}
|
|
||||||
show_category={true}
|
|
||||||
/>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|||||||
@ -40,7 +40,7 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="product-grid mt-12 grid gap-4 grid-cols-2 md:grid-cols-4 max-w-xl mx-auto">
|
<.product_grid columns={:fixed_4} gap="gap-4" class="mt-12 max-w-xl mx-auto">
|
||||||
<%= for product <- Enum.take(@preview_data.products, 4) do %>
|
<%= for product <- Enum.take(@preview_data.products, 4) do %>
|
||||||
<.product_card
|
<.product_card
|
||||||
product={product}
|
product={product}
|
||||||
@ -49,7 +49,7 @@
|
|||||||
variant={:minimal}
|
variant={:minimal}
|
||||||
/>
|
/>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</.product_grid>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|||||||
@ -52,15 +52,7 @@
|
|||||||
Featured products
|
Featured products
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div class={[
|
<.product_grid theme_settings={@theme_settings}>
|
||||||
"product-grid grid grid-cols-1 sm:grid-cols-2",
|
|
||||||
case @theme_settings.grid_columns do
|
|
||||||
"2" -> "lg:grid-cols-2"
|
|
||||||
"3" -> "lg:grid-cols-3"
|
|
||||||
"4" -> "lg:grid-cols-4"
|
|
||||||
_ -> "lg:grid-cols-3"
|
|
||||||
end
|
|
||||||
]}>
|
|
||||||
<%= for product <- Enum.take(@preview_data.products, 4) do %>
|
<%= for product <- Enum.take(@preview_data.products, 4) do %>
|
||||||
<.product_card
|
<.product_card
|
||||||
product={product}
|
product={product}
|
||||||
@ -69,7 +61,7 @@
|
|||||||
variant={:featured}
|
variant={:featured}
|
||||||
/>
|
/>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</.product_grid>
|
||||||
|
|
||||||
<div class="text-center mt-8">
|
<div class="text-center mt-8">
|
||||||
<button
|
<button
|
||||||
|
|||||||
@ -402,7 +402,7 @@
|
|||||||
You might also like
|
You might also like
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div class="product-grid grid gap-6 grid-cols-2 md:grid-cols-4">
|
<.product_grid columns={:fixed_4} gap="gap-6">
|
||||||
<%= for related_product <- Enum.slice(@preview_data.products, 1, 4) do %>
|
<%= for related_product <- Enum.slice(@preview_data.products, 1, 4) do %>
|
||||||
<.product_card
|
<.product_card
|
||||||
product={related_product}
|
product={related_product}
|
||||||
@ -411,7 +411,7 @@
|
|||||||
variant={:compact}
|
variant={:compact}
|
||||||
/>
|
/>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</.product_grid>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user