diff --git a/lib/simpleshop_theme_web/components/shop_components.ex b/lib/simpleshop_theme_web/components/shop_components.ex index ce3e38c..9f9d1d6 100644 --- a/lib/simpleshop_theme_web/components/shop_components.ex +++ b/lib/simpleshop_theme_web/components/shop_components.ex @@ -516,4 +516,269 @@ defmodule SimpleshopThemeWeb.ShopComponents do """ end + + @doc """ + Renders a product card with configurable variants. + + ## Attributes + + * `product` - Required. The product map with `name`, `image_url`, `price`, etc. + * `theme_settings` - Required. The theme settings map. + * `mode` - Either `:live` (default) or `:preview`. + * `variant` - The visual variant: + - `:default` - Collection page style with border, category, full details + - `:featured` - Home page style with hover lift, no border + - `:compact` - PDP related products with aspect-square, minimal info + - `:minimal` - Error 404 style, smallest, not clickable + * `show_category` - Show category label. Defaults based on variant. + * `show_badges` - Show product badges. Defaults based on variant. + * `show_delivery_text` - Show "Free delivery" text. Defaults based on variant. + * `clickable` - Whether the card navigates. Defaults based on variant. + + ## Examples + + <.product_card product={product} theme_settings={@theme_settings} /> + <.product_card product={product} theme_settings={@theme_settings} variant={:featured} mode={:preview} /> + """ + attr :product, :map, required: true + attr :theme_settings, :map, required: true + attr :mode, :atom, default: :live + attr :variant, :atom, default: :default + attr :show_category, :boolean, default: nil + attr :show_badges, :boolean, default: nil + attr :show_delivery_text, :boolean, default: nil + attr :clickable, :boolean, default: nil + + def product_card(assigns) do + # Apply variant defaults for nil values + defaults = variant_defaults(assigns.variant) + + assigns = + assigns + |> assign_new(:show_category_resolved, fn -> + if assigns.show_category == nil, do: defaults.show_category, else: assigns.show_category + end) + |> assign_new(:show_badges_resolved, fn -> + if assigns.show_badges == nil, do: defaults.show_badges, else: assigns.show_badges + end) + |> assign_new(:show_delivery_text_resolved, fn -> + if assigns.show_delivery_text == nil, + do: defaults.show_delivery_text, + else: assigns.show_delivery_text + end) + |> assign_new(:clickable_resolved, fn -> + if assigns.clickable == nil, do: defaults.clickable, else: assigns.clickable + end) + + ~H""" + <%= if @clickable_resolved do %> + <%= if @mode == :preview do %> + + <.product_card_inner + product={@product} + theme_settings={@theme_settings} + variant={@variant} + show_category={@show_category_resolved} + show_badges={@show_badges_resolved} + show_delivery_text={@show_delivery_text_resolved} + /> + + <% else %> + + <.product_card_inner + product={@product} + theme_settings={@theme_settings} + variant={@variant} + show_category={@show_category_resolved} + show_badges={@show_badges_resolved} + show_delivery_text={@show_delivery_text_resolved} + /> + + <% end %> + <% else %> +
+ <%= @product.category %> +
+ <% end %> ++ Free delivery over £40 +
+ <% end %> ++ <%= if @product.on_sale do %> + £<%= @product.compare_at_price / 100 %> + <% end %> + £<%= @product.price / 100 %> +
+ <% :compact -> %> ++ £<%= @product.price / 100 %> +
+ <% :minimal -> %> ++ £<%= @product.price / 100 %> +
+ <% end %> + """ + end + + defp variant_defaults(:default), + do: %{show_category: true, show_badges: true, show_delivery_text: true, clickable: true} + + defp variant_defaults(:featured), + do: %{show_category: false, show_badges: true, show_delivery_text: true, clickable: true} + + defp variant_defaults(:compact), + do: %{show_category: false, show_badges: false, show_delivery_text: false, clickable: true} + + defp variant_defaults(:minimal), + do: %{show_category: false, show_badges: false, show_delivery_text: false, clickable: false} + + defp card_classes(:default), do: "product-card group overflow-hidden transition-all" + defp card_classes(:featured), do: "product-card group overflow-hidden transition-all hover:-translate-y-1" + defp card_classes(:compact), do: "product-card group overflow-hidden cursor-pointer" + defp card_classes(:minimal), do: "product-card group overflow-hidden" + + defp card_style(:default), + do: "background-color: var(--t-surface-raised); border: 1px solid var(--t-border-default); border-radius: var(--t-radius-card); cursor: pointer;" + + defp card_style(:featured), + do: "background-color: var(--t-surface-raised); border-radius: var(--t-radius-card); cursor: pointer;" + + defp card_style(:compact), + do: "background-color: var(--t-surface-raised); border: 1px solid var(--t-border-default); border-radius: var(--t-radius-card);" + + defp card_style(:minimal), + do: "background-color: var(--t-surface-raised); border: 1px solid var(--t-border-subtle); border-radius: var(--t-radius-card);" + + defp image_container_classes(:compact), + do: "product-image-container aspect-square bg-gray-200 overflow-hidden relative" + + defp image_container_classes(:minimal), + do: "product-image-container aspect-square bg-gray-200 overflow-hidden relative" + + defp image_container_classes(_), + do: "product-image-container bg-gray-200 overflow-hidden relative" + + defp content_padding_class(:compact), do: "p-3" + defp content_padding_class(:minimal), do: "p-2" + defp content_padding_class(_), do: "" + + defp title_classes(:default), do: "font-semibold mb-2" + defp title_classes(:featured), do: "text-sm font-medium mb-1" + defp title_classes(:compact), do: "font-semibold text-sm mb-1" + defp title_classes(:minimal), do: "text-xs font-semibold truncate" + + defp title_style(:default), do: "font-family: var(--t-font-heading); 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(:minimal), do: "color: var(--t-text-primary);" end diff --git a/lib/simpleshop_theme_web/live/theme_live/preview_pages/collection.html.heex b/lib/simpleshop_theme_web/live/theme_live/preview_pages/collection.html.heex index 80ea4d8..dc36b33 100644 --- a/lib/simpleshop_theme_web/live/theme_live/preview_pages/collection.html.heex +++ b/lib/simpleshop_theme_web/live/theme_live/preview_pages/collection.html.heex @@ -62,68 +62,13 @@ end ]}> <%= for product <- @preview_data.products do %> -- <%= product.category %> -
-- Free delivery over £40 -
-- <%= product.name %> -
- <%= if @theme_settings.show_prices do %> -- £<%= product.price / 100 %> -
- <% end %> -- <%= if product.on_sale do %> - £<%= product.compare_at_price / 100 %> - <% end %> - £<%= product.price / 100 %> -
- <% end %> -- Free delivery over £40 -
-- £<%= related_product.price / 100 %> -
- <% end %> -