<.skip_link />
<%= if @theme_settings.announcement_bar do %>
@@ -40,4 +40,6 @@
<.cart_drawer cart_items={@cart_items} subtotal={@cart_subtotal} mode={@mode} />
<.search_modal hint_text={~s(Try searching for "mountain", "forest", or "ocean")} />
+
+ <.mobile_bottom_nav active_page="home" mode={@mode} />
diff --git a/lib/simpleshop_theme_web/components/page_templates/pdp.html.heex b/lib/simpleshop_theme_web/components/page_templates/pdp.html.heex
index 7d0d0ce..6034ed2 100644
--- a/lib/simpleshop_theme_web/components/page_templates/pdp.html.heex
+++ b/lib/simpleshop_theme_web/components/page_templates/pdp.html.heex
@@ -1,4 +1,4 @@
-
+
<.skip_link />
<%= if @theme_settings.announcement_bar do %>
@@ -41,4 +41,6 @@
<.cart_drawer cart_items={@cart_items} subtotal={@cart_subtotal} mode={@mode} />
<.search_modal hint_text={~s(Try searching for "mountain", "forest", or "ocean")} />
+
+ <.mobile_bottom_nav active_page="pdp" mode={@mode} />
diff --git a/lib/simpleshop_theme_web/components/shop_components.ex b/lib/simpleshop_theme_web/components/shop_components.ex
index 62dc797..bf4ad66 100644
--- a/lib/simpleshop_theme_web/components/shop_components.ex
+++ b/lib/simpleshop_theme_web/components/shop_components.ex
@@ -53,6 +53,164 @@ defmodule SimpleshopThemeWeb.ShopComponents do
"""
end
+ @doc """
+ Renders a mobile bottom navigation bar.
+
+ This component provides thumb-friendly navigation for mobile devices,
+ following modern UX best practices. It's hidden on larger screens where
+ the standard header navigation is used.
+
+ ## Attributes
+
+ * `active_page` - Required. The current page identifier (e.g., "home", "collection", "about", "contact").
+ * `mode` - Optional. Either `:live` (default) for real navigation or
+ `:preview` for theme preview mode with phx-click handlers.
+ * `cart_count` - Optional. Number of items in cart for badge display. Default: 0.
+
+ ## Examples
+
+ <.mobile_bottom_nav active_page="home" />
+ <.mobile_bottom_nav active_page="collection" mode={:preview} />
+ """
+ attr :active_page, :string, required: true
+ attr :mode, :atom, default: :live
+ attr :cart_count, :integer, default: 0
+
+ def mobile_bottom_nav(assigns) do
+ ~H"""
+
+ """
+ end
+
+ attr :icon, :atom, required: true
+ attr :label, :string, required: true
+ attr :page, :string, required: true
+ attr :href, :string, required: true
+ attr :active_page, :string, required: true
+ attr :active_pages, :list, default: nil
+ attr :mode, :atom, default: :live
+
+ defp mobile_nav_item(assigns) do
+ active_pages = assigns.active_pages || [assigns.page]
+ is_current = assigns.active_page in active_pages
+ assigns = assign(assigns, :is_current, is_current)
+
+ ~H"""
+
+ <%= if @mode == :preview do %>
+
+ <.nav_icon icon={@icon} size={if @is_current, do: "w-6 h-6", else: "w-5 h-5"} />
+ {@label}
+
+ <% else %>
+
+ <.nav_icon icon={@icon} size={if @is_current, do: "w-6 h-6", else: "w-5 h-5"} />
+ {@label}
+
+ <% end %>
+
+ """
+ end
+
+ defp nav_icon(%{icon: :home} = assigns) do
+ assigns = assign_new(assigns, :size, fn -> "w-5 h-5" end)
+
+ ~H"""
+
+ """
+ end
+
+ defp nav_icon(%{icon: :shop} = assigns) do
+ assigns = assign_new(assigns, :size, fn -> "w-5 h-5" end)
+
+ ~H"""
+
+ """
+ end
+
+ defp nav_icon(%{icon: :about} = assigns) do
+ assigns = assign_new(assigns, :size, fn -> "w-5 h-5" end)
+
+ ~H"""
+
+ """
+ end
+
+ defp nav_icon(%{icon: :contact} = assigns) do
+ assigns = assign_new(assigns, :size, fn -> "w-5 h-5" end)
+
+ ~H"""
+
+ """
+ end
+
@doc """
Renders the search modal overlay.
@@ -250,8 +408,8 @@ defmodule SimpleshopThemeWeb.ShopComponents do
def shop_header(assigns) do
~H"""