refactor: extract search_modal to shared ShopComponents module
Move the search modal from ThemeLive.PreviewPages to the shared ShopComponents module. Add optional hint_text attribute - preview pages pass demo hint text while real stores can omit it. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
0e998fdac9
commit
14b1af5314
@ -52,4 +52,74 @@ defmodule SimpleshopThemeWeb.ShopComponents do
|
|||||||
</a>
|
</a>
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Renders the search modal overlay.
|
||||||
|
|
||||||
|
This is a modal dialog for searching products. Currently provides
|
||||||
|
the UI shell; search functionality will be added later.
|
||||||
|
|
||||||
|
## Attributes
|
||||||
|
|
||||||
|
* `hint_text` - Optional. Hint text shown below the search input.
|
||||||
|
Defaults to nil (no hint shown).
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
<.search_modal />
|
||||||
|
<.search_modal hint_text="Try searching for \"mountain\" or \"forest\"" />
|
||||||
|
"""
|
||||||
|
attr :hint_text, :string, default: nil
|
||||||
|
|
||||||
|
def search_modal(assigns) do
|
||||||
|
~H"""
|
||||||
|
<div
|
||||||
|
id="search-modal"
|
||||||
|
class="search-modal"
|
||||||
|
style="position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 1001; display: none; align-items: flex-start; justify-content: center; padding-top: 10vh;"
|
||||||
|
phx-click={Phoenix.LiveView.JS.hide(to: "#search-modal")}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="search-modal-content w-full max-w-xl mx-4"
|
||||||
|
style="background: var(--t-surface-raised); border-radius: var(--t-radius-card); overflow: hidden; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);"
|
||||||
|
phx-click-away={Phoenix.LiveView.JS.hide(to: "#search-modal")}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center gap-3 p-4"
|
||||||
|
style="border-bottom: 1px solid var(--t-border-default);"
|
||||||
|
>
|
||||||
|
<svg class="w-5 h-5 flex-shrink-0" style="color: var(--t-text-tertiary);" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<circle cx="11" cy="11" r="8"></circle>
|
||||||
|
<path d="M21 21l-4.35-4.35"></path>
|
||||||
|
</svg>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id="search-input"
|
||||||
|
class="flex-1 text-lg bg-transparent border-none outline-none"
|
||||||
|
style="font-family: var(--t-font-body); color: var(--t-text-primary);"
|
||||||
|
placeholder="Search products..."
|
||||||
|
phx-click={Phoenix.LiveView.JS.dispatch("stop-propagation")}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="w-8 h-8 flex items-center justify-center transition-all"
|
||||||
|
style="color: var(--t-text-tertiary); background: none; border: none; cursor: pointer; border-radius: var(--t-radius-button);"
|
||||||
|
phx-click={Phoenix.LiveView.JS.hide(to: "#search-modal")}
|
||||||
|
aria-label="Close search"
|
||||||
|
>
|
||||||
|
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||||
|
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||||
|
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<%= if @hint_text do %>
|
||||||
|
<div class="p-6" style="color: var(--t-text-tertiary);">
|
||||||
|
<p class="text-sm">{@hint_text}</p>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -313,57 +313,4 @@ defmodule SimpleshopThemeWeb.ThemeLive.PreviewPages do
|
|||||||
</style>
|
</style>
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
|
||||||
Renders the search modal overlay.
|
|
||||||
"""
|
|
||||||
def search_modal(assigns) do
|
|
||||||
~H"""
|
|
||||||
<div
|
|
||||||
id="search-modal"
|
|
||||||
class="search-modal"
|
|
||||||
style="position: fixed; inset: 0; background: rgba(0,0,0,0.5); z-index: 1001; display: none; align-items: flex-start; justify-content: center; padding-top: 10vh;"
|
|
||||||
phx-click={Phoenix.LiveView.JS.hide(to: "#search-modal")}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="search-modal-content w-full max-w-xl mx-4"
|
|
||||||
style="background: var(--t-surface-raised); border-radius: var(--t-radius-card); overflow: hidden; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);"
|
|
||||||
phx-click-away={Phoenix.LiveView.JS.hide(to: "#search-modal")}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="flex items-center gap-3 p-4"
|
|
||||||
style="border-bottom: 1px solid var(--t-border-default);"
|
|
||||||
>
|
|
||||||
<svg class="w-5 h-5 flex-shrink-0" style="color: var(--t-text-tertiary);" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
||||||
<circle cx="11" cy="11" r="8"></circle>
|
|
||||||
<path d="M21 21l-4.35-4.35"></path>
|
|
||||||
</svg>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="search-input"
|
|
||||||
class="flex-1 text-lg bg-transparent border-none outline-none"
|
|
||||||
style="font-family: var(--t-font-body); color: var(--t-text-primary);"
|
|
||||||
placeholder="Search products..."
|
|
||||||
phx-click={Phoenix.LiveView.JS.dispatch("stop-propagation")}
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="w-8 h-8 flex items-center justify-center transition-all"
|
|
||||||
style="color: var(--t-text-tertiary); background: none; border: none; cursor: pointer; border-radius: var(--t-radius-button);"
|
|
||||||
phx-click={Phoenix.LiveView.JS.hide(to: "#search-modal")}
|
|
||||||
aria-label="Close search"
|
|
||||||
>
|
|
||||||
<svg class="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
||||||
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
||||||
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="p-6" style="color: var(--t-text-tertiary);">
|
|
||||||
<p class="text-sm">Try searching for "mountain", "forest", or "ocean"</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@ -72,5 +72,5 @@
|
|||||||
<!-- Cart Drawer -->
|
<!-- Cart Drawer -->
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.cart_drawer cart_items={SimpleshopTheme.Theme.PreviewData.cart_drawer_items()} />
|
<SimpleshopThemeWeb.ThemeLive.PreviewPages.cart_drawer cart_items={SimpleshopTheme.Theme.PreviewData.cart_drawer_items()} />
|
||||||
|
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.search_modal />
|
<.search_modal hint_text={~s(Try searching for "mountain", "forest", or "ocean")} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -125,5 +125,5 @@
|
|||||||
<!-- Cart Drawer -->
|
<!-- Cart Drawer -->
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.cart_drawer cart_items={SimpleshopTheme.Theme.PreviewData.cart_drawer_items()} />
|
<SimpleshopThemeWeb.ThemeLive.PreviewPages.cart_drawer cart_items={SimpleshopTheme.Theme.PreviewData.cart_drawer_items()} />
|
||||||
|
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.search_modal />
|
<.search_modal hint_text={~s(Try searching for "mountain", "forest", or "ocean")} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -136,5 +136,5 @@
|
|||||||
<!-- Cart Drawer -->
|
<!-- Cart Drawer -->
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.cart_drawer cart_items={SimpleshopTheme.Theme.PreviewData.cart_drawer_items()} />
|
<SimpleshopThemeWeb.ThemeLive.PreviewPages.cart_drawer cart_items={SimpleshopTheme.Theme.PreviewData.cart_drawer_items()} />
|
||||||
|
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.search_modal />
|
<.search_modal hint_text={~s(Try searching for "mountain", "forest", or "ocean")} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -192,5 +192,5 @@
|
|||||||
<!-- Cart Drawer -->
|
<!-- Cart Drawer -->
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.cart_drawer cart_items={SimpleshopTheme.Theme.PreviewData.cart_drawer_items()} />
|
<SimpleshopThemeWeb.ThemeLive.PreviewPages.cart_drawer cart_items={SimpleshopTheme.Theme.PreviewData.cart_drawer_items()} />
|
||||||
|
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.search_modal />
|
<.search_modal hint_text={~s(Try searching for "mountain", "forest", or "ocean")} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -83,5 +83,5 @@
|
|||||||
<!-- Cart Drawer -->
|
<!-- Cart Drawer -->
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.cart_drawer cart_items={SimpleshopTheme.Theme.PreviewData.cart_drawer_items()} />
|
<SimpleshopThemeWeb.ThemeLive.PreviewPages.cart_drawer cart_items={SimpleshopTheme.Theme.PreviewData.cart_drawer_items()} />
|
||||||
|
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.search_modal />
|
<.search_modal hint_text={~s(Try searching for "mountain", "forest", or "ocean")} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -157,5 +157,5 @@
|
|||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.cart_drawer cart_items={SimpleshopTheme.Theme.PreviewData.cart_drawer_items()} />
|
<SimpleshopThemeWeb.ThemeLive.PreviewPages.cart_drawer cart_items={SimpleshopTheme.Theme.PreviewData.cart_drawer_items()} />
|
||||||
|
|
||||||
<!-- Search Modal -->
|
<!-- Search Modal -->
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.search_modal />
|
<.search_modal hint_text={~s(Try searching for "mountain", "forest", or "ocean")} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -453,5 +453,5 @@
|
|||||||
<!-- Cart Drawer -->
|
<!-- Cart Drawer -->
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.cart_drawer cart_items={SimpleshopTheme.Theme.PreviewData.cart_drawer_items()} />
|
<SimpleshopThemeWeb.ThemeLive.PreviewPages.cart_drawer cart_items={SimpleshopTheme.Theme.PreviewData.cart_drawer_items()} />
|
||||||
|
|
||||||
<SimpleshopThemeWeb.ThemeLive.PreviewPages.search_modal />
|
<.search_modal hint_text={~s(Try searching for "mountain", "forest", or "ocean")} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user