feat: add /collections/:slug routes with category filtering

- Add ShopLive.Collection LiveView for collection pages
- Add products_by_category/1 and category_by_slug/1 to PreviewData
- Support /collections/all for all products view
- Remove /products route and ShopLive.Products (replaced by collections)
- Update all links to use /collections/all instead of /products
- Update category nav to link to /collections/:slug
- Update PDP breadcrumb to link to specific collection

URL structure now follows Shopify convention:
- /collections/all - All products
- /collections/art-prints - Art Prints collection
- /collections/apparel - Apparel collection
- etc.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-19 23:26:41 +00:00
parent 848c4ea146
commit 9fb836ca0d
6 changed files with 208 additions and 71 deletions

View File

@@ -10,7 +10,7 @@
<main id="main-content" class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<.breadcrumb items={[
%{label: "Home", page: "home", href: "/"},
%{label: @product.category, page: "collection", href: "/products"},
%{label: @product.category, page: "collection", href: "/collections/#{@product.category |> String.downcase() |> String.replace(" ", "-")}"},
%{label: @product.name, current: true}
]} mode={@mode} />

View File

@@ -184,9 +184,9 @@ defmodule SimpleshopThemeWeb.ShopComponents 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;">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>
<li><a href="/collections/all" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary);">All products</a></li>
<li><a href="/collections/all" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary);">New arrivals</a></li>
<li><a href="/collections/all" class="transition-colors hover:opacity-80" style="color: var(--t-text-secondary);">Best sellers</a></li>
<% end %>
</ul>
</div>
@@ -327,7 +327,7 @@ defmodule SimpleshopThemeWeb.ShopComponents do
<a href="#" phx-click="change_preview_page" phx-value-page="contact" aria-current={if @active_page == "contact", do: "page"} style="color: var(--t-text-secondary); text-decoration: none; cursor: pointer;">Contact</a>
<% else %>
<a href="/" aria-current={if @active_page == "home", do: "page"} style="color: var(--t-text-secondary); text-decoration: none;">Home</a>
<a href="/products" aria-current={if @active_page in ["collection", "pdp"], do: "page"} style="color: var(--t-text-secondary); text-decoration: none;">Shop</a>
<a href="/collections/all" aria-current={if @active_page in ["collection", "pdp"], do: "page"} style="color: var(--t-text-secondary); text-decoration: none;">Shop</a>
<a href="/about" aria-current={if @active_page == "about", do: "page"} style="color: var(--t-text-secondary); text-decoration: none;">About</a>
<a href="/contact" aria-current={if @active_page == "contact", do: "page"} style="color: var(--t-text-secondary); text-decoration: none;">Contact</a>
<% end %>
@@ -1078,7 +1078,7 @@ defmodule SimpleshopThemeWeb.ShopComponents do
</span>
</a>
<% else %>
<a href={"/products?category=#{category[:slug] || category.name}"} class="flex flex-col items-center gap-3 p-4 rounded-lg transition-colors hover:bg-black/5" style="text-decoration: none;">
<a href={"/collections/#{category.slug}"} class="flex flex-col items-center gap-3 p-4 rounded-lg transition-colors hover:bg-black/5" style="text-decoration: none;">
<div
class="w-24 h-24 rounded-full bg-gray-200 bg-cover bg-center transition-transform hover:scale-105"
style={"background-image: url('#{category.image_url}');"}
@@ -1106,7 +1106,7 @@ defmodule SimpleshopThemeWeb.ShopComponents do
* `mode` - Either `:live` (default) or `:preview`.
* `cta_text` - Optional. Text for the "view all" button. Defaults to "View all products".
* `cta_page` - Optional. Page to navigate to (preview mode). Defaults to "collection".
* `cta_href` - Optional. URL for live mode. Defaults to "/products".
* `cta_href` - Optional. URL for live mode. Defaults to "/collections/all".
## Examples
@@ -1124,7 +1124,7 @@ defmodule SimpleshopThemeWeb.ShopComponents do
attr :mode, :atom, default: :live
attr :cta_text, :string, default: "View all products"
attr :cta_page, :string, default: "collection"
attr :cta_href, :string, default: "/products"
attr :cta_href, :string, default: "/collections/all"
def featured_products_section(assigns) do
~H"""
@@ -1785,7 +1785,7 @@ defmodule SimpleshopThemeWeb.ShopComponents do
</button>
<% else %>
<a
href="/products"
href="/collections/all"
class="block w-full px-6 py-3 font-semibold transition-all text-center"
style="border: 2px solid var(--t-border-default); color: var(--t-text-primary); border-radius: var(--t-radius-button); text-decoration: none;"
>
@@ -1812,7 +1812,7 @@ defmodule SimpleshopThemeWeb.ShopComponents do
<.breadcrumb items={[
%{label: "Home", page: "home", href: "/"},
%{label: "Art Prints", page: "collection", href: "/products?category=art-prints"},
%{label: "Art Prints", page: "collection", href: "/collections/art-prints"},
%{label: "Mountain Sunrise", current: true}
]} mode={:preview} />
"""