feat(elixir): proper dark/light mode support

This commit is contained in:
Schuwi
2025-09-14 22:50:44 +02:00
parent 280caad641
commit ae861f32a1
6 changed files with 237 additions and 202 deletions

View File

@@ -319,16 +319,16 @@ defmodule ComponentsElixirWeb.ComponentsLive do
@impl true
def render(assigns) do
~H"""
<div class="min-h-screen bg-gray-50">
<div class="min-h-screen bg-base-200">
<!-- Header -->
<div class="bg-white shadow">
<div class="bg-base-100 shadow">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between items-center py-6">
<div class="flex items-center">
<h1 class="text-3xl font-bold text-gray-900">
<h1 class="text-3xl font-bold text-base-content">
Components Inventory
</h1>
<div class="ml-8 text-sm text-gray-500">
<div class="ml-8 text-sm text-base-content/60">
{@stats.total_components} components • {@stats.total_stock} items in stock
</div>
</div>
@@ -341,20 +341,20 @@ defmodule ComponentsElixirWeb.ComponentsLive do
</button>
<.link
navigate={~p"/categories"}
class="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
class="inline-flex items-center px-4 py-2 border border-base-300 text-sm font-medium rounded-md text-base-content bg-base-100 hover:bg-base-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary"
>
<.icon name="hero-folder" class="w-4 h-4 mr-2" /> Categories
</.link>
<.link
navigate={~p"/storage_locations"}
class="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
class="inline-flex items-center px-4 py-2 border border-base-300 text-sm font-medium rounded-md text-base-content bg-base-100 hover:bg-base-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary"
>
<.icon name="hero-archive-box" class="w-4 h-4 mr-2" /> Storage
</.link>
<.link
href="/logout"
method="post"
class="inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
class="inline-flex items-center px-4 py-2 border border-base-300 text-sm font-medium rounded-md text-base-content bg-base-100 hover:bg-base-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary"
>
<.icon name="hero-arrow-right-on-rectangle" class="w-4 h-4 mr-2" /> Logout
</.link>
@@ -373,7 +373,7 @@ defmodule ComponentsElixirWeb.ComponentsLive do
name="search"
value={@search}
placeholder="Search components..."
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
class="block w-full px-3 py-2 border border-base-300 rounded-md shadow-sm bg-base-100 text-base-content focus:outline-none focus:ring-primary focus:border-primary sm:text-sm"
/>
</form>
</div>
@@ -381,7 +381,7 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<form phx-change="category_filter">
<select
name="category_id"
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
class="block w-full px-3 py-2 border border-base-300 rounded-md shadow-sm bg-base-100 text-base-content focus:outline-none focus:ring-primary focus:border-primary sm:text-sm"
>
<option value="" selected={is_nil(@selected_category)}>All Categories</option>
<%= for category <- @categories do %>
@@ -400,7 +400,7 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<form phx-change="sort_change">
<select
name="sort_criteria"
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
class="block w-full px-3 py-2 border border-base-300 rounded-md shadow-sm bg-base-100 text-base-content focus:outline-none focus:ring-primary focus:border-primary sm:text-sm"
>
<option value="all_not_id" selected={@sort_criteria == "all_not_id"}>
All (without IDs)
@@ -422,14 +422,14 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<!-- Add Component Modal -->
<%= if @show_add_form do %>
<div class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
<div class="relative top-20 mx-auto p-5 border w-11/12 md:w-1/2 shadow-lg rounded-md bg-white">
<div class="fixed inset-0 bg-base-content/50 overflow-y-auto h-full w-full z-50">
<div class="relative top-20 mx-auto p-5 border border-base-300 w-11/12 md:w-1/2 shadow-lg rounded-md bg-base-100">
<div class="mt-3">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-medium text-gray-900">Add New Component</h3>
<h3 class="text-lg font-medium text-base-content">Add New Component</h3>
<button
phx-click="hide_add_form"
class="text-gray-400 hover:text-gray-600"
class="text-base-content/60 hover:text-base-content"
>
<.icon name="hero-x-mark" class="w-6 h-6" />
</button>
@@ -437,12 +437,12 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<.form for={@form} phx-submit="save_component" phx-change="validate" multipart={true} class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700">Name</label>
<label class="block text-sm font-medium text-base-content">Name</label>
<.input field={@form[:name]} type="text" required />
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Category</label>
<label class="block text-sm font-medium text-base-content">Category</label>
<.input
field={@form[:category_id]}
type="select"
@@ -452,17 +452,17 @@ defmodule ComponentsElixirWeb.ComponentsLive do
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Description</label>
<label class="block text-sm font-medium text-base-content">Description</label>
<.input field={@form[:description]} type="textarea" />
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700">Keywords</label>
<label class="block text-sm font-medium text-base-content">Keywords</label>
<.input field={@form[:keywords]} type="text" />
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Storage Location</label>
<label class="block text-sm font-medium text-base-content">Storage Location</label>
<.input
field={@form[:storage_location_id]}
type="select"
@@ -473,26 +473,26 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700">Count</label>
<label class="block text-sm font-medium text-base-content">Count</label>
<.input field={@form[:count]} type="number" min="0" />
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Datasheet URL</label>
<label class="block text-sm font-medium text-base-content">Datasheet URL</label>
<.input field={@form[:datasheet_url]} type="url" />
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Component Image</label>
<label class="block text-sm font-medium text-base-content">Component Image</label>
<div class="mt-1">
<.live_file_input upload={@uploads.image} class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100" />
<.live_file_input upload={@uploads.image} class="block w-full text-sm text-base-content file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-primary/10 file:text-primary hover:file:bg-primary/20" />
</div>
<p class="mt-1 text-xs text-gray-500">
<p class="mt-1 text-xs text-base-content/60">
JPG, PNG, GIF up to 5MB
</p>
<%= for err <- upload_errors(@uploads.image) do %>
<p class="text-red-600 text-sm mt-1"><%= Phoenix.Naming.humanize(err) %></p>
<p class="text-error text-sm mt-1"><%= Phoenix.Naming.humanize(err) %></p>
<% end %>
<%= for entry <- @uploads.image.entries do %>
@@ -502,17 +502,17 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<.live_img_preview entry={entry} class="h-10 w-10 rounded-lg object-cover" />
</div>
<div class="ml-3">
<p class="text-sm font-medium text-gray-900"><%= entry.client_name %></p>
<p class="text-sm text-gray-500"><%= entry.progress %>%</p>
<p class="text-sm font-medium text-base-content"><%= entry.client_name %></p>
<p class="text-sm text-base-content/60"><%= entry.progress %>%</p>
</div>
</div>
<button type="button" phx-click="cancel-upload" phx-value-ref={entry.ref} aria-label="cancel" class="text-red-600 hover:text-red-900">
<button type="button" phx-click="cancel-upload" phx-value-ref={entry.ref} aria-label="cancel" class="text-error hover:text-error/80">
<.icon name="hero-x-mark" class="w-5 h-5" />
</button>
</div>
<% end %>
<%= for err <- upload_errors(@uploads.image) do %>
<p class="mt-1 text-sm text-red-600"><%= upload_error_to_string(err) %></p>
<p class="mt-1 text-sm text-error"><%= upload_error_to_string(err) %></p>
<% end %>
</div>
@@ -520,13 +520,13 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<button
type="button"
phx-click="hide_add_form"
class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50"
class="px-4 py-2 border border-base-300 rounded-md text-sm font-medium text-base-content hover:bg-base-200"
>
Cancel
</button>
<button
type="submit"
class="px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700"
class="px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-primary-content bg-primary hover:bg-primary/90"
>
Save Component
</button>
@@ -539,14 +539,14 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<!-- Edit Component Modal -->
<%= if @show_edit_form do %>
<div class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50">
<div class="relative top-20 mx-auto p-5 border w-11/12 md:w-1/2 shadow-lg rounded-md bg-white">
<div class="fixed inset-0 bg-base-content/50 overflow-y-auto h-full w-full z-50">
<div class="relative top-20 mx-auto p-5 border border-base-300 w-11/12 md:w-1/2 shadow-lg rounded-md bg-base-100">
<div class="mt-3">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-medium text-gray-900">Edit Component</h3>
<h3 class="text-lg font-medium text-base-content">Edit Component</h3>
<button
phx-click="hide_edit_form"
class="text-gray-400 hover:text-gray-600"
class="text-base-content/60 hover:text-base-content"
>
<.icon name="hero-x-mark" class="w-6 h-6" />
</button>
@@ -554,12 +554,12 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<.form for={@form} phx-submit="save_edit" phx-change="validate" multipart={true} class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700">Name</label>
<label class="block text-sm font-medium text-base-content">Name</label>
<.input field={@form[:name]} type="text" required />
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Category</label>
<label class="block text-sm font-medium text-base-content">Category</label>
<.input
field={@form[:category_id]}
type="select"
@@ -569,17 +569,17 @@ defmodule ComponentsElixirWeb.ComponentsLive do
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Description</label>
<label class="block text-sm font-medium text-base-content">Description</label>
<.input field={@form[:description]} type="textarea" />
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700">Keywords</label>
<label class="block text-sm font-medium text-base-content">Keywords</label>
<.input field={@form[:keywords]} type="text" />
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Storage Location</label>
<label class="block text-sm font-medium text-base-content">Storage Location</label>
<.input
field={@form[:storage_location_id]}
type="select"
@@ -590,32 +590,32 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700">Count</label>
<label class="block text-sm font-medium text-base-content">Count</label>
<.input field={@form[:count]} type="number" min="0" />
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Datasheet URL</label>
<label class="block text-sm font-medium text-base-content">Datasheet URL</label>
<.input field={@form[:datasheet_url]} type="url" />
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Component Image</label>
<label class="block text-sm font-medium text-base-content">Component Image</label>
<%= if @editing_component && @editing_component.image_filename do %>
<div class="mt-1 mb-2">
<p class="text-sm text-gray-600">Current image:</p>
<p class="text-sm text-base-content/70">Current image:</p>
<img src={"/user_generated/uploads/images/#{@editing_component.image_filename}"} alt="Current component" class="h-20 w-20 object-cover rounded-lg" />
</div>
<% end %>
<div class="mt-1">
<.live_file_input upload={@uploads.image} class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-indigo-50 file:text-indigo-700 hover:file:bg-indigo-100" />
<.live_file_input upload={@uploads.image} class="block w-full text-sm text-base-content file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-primary/10 file:text-primary hover:file:bg-primary/20" />
</div>
<p class="mt-1 text-xs text-gray-500">
<p class="mt-1 text-xs text-base-content/60">
JPG, PNG, GIF up to 5MB (leave empty to keep current image)
</p>
<%= for err <- upload_errors(@uploads.image) do %>
<p class="text-red-600 text-sm mt-1"><%= Phoenix.Naming.humanize(err) %></p>
<p class="text-error text-sm mt-1"><%= Phoenix.Naming.humanize(err) %></p>
<% end %>
<%= for entry <- @uploads.image.entries do %>
@@ -625,17 +625,17 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<.live_img_preview entry={entry} class="h-10 w-10 rounded-lg object-cover" />
</div>
<div class="ml-3">
<p class="text-sm font-medium text-gray-900"><%= entry.client_name %></p>
<p class="text-sm text-gray-500"><%= entry.progress %>%</p>
<p class="text-sm font-medium text-base-content"><%= entry.client_name %></p>
<p class="text-sm text-base-content/60"><%= entry.progress %>%</p>
</div>
</div>
<button type="button" phx-click="cancel-upload" phx-value-ref={entry.ref} aria-label="cancel" class="text-red-600 hover:text-red-900">
<button type="button" phx-click="cancel-upload" phx-value-ref={entry.ref} aria-label="cancel" class="text-error hover:text-error/80">
<.icon name="hero-x-mark" class="w-5 h-5" />
</button>
</div>
<% end %>
<%= for err <- upload_errors(@uploads.image) do %>
<p class="mt-1 text-sm text-red-600"><%= upload_error_to_string(err) %></p>
<p class="mt-1 text-sm text-error"><%= upload_error_to_string(err) %></p>
<% end %>
</div>
@@ -643,13 +643,13 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<button
type="button"
phx-click="hide_edit_form"
class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50"
class="px-4 py-2 border border-base-300 rounded-md text-sm font-medium text-base-content hover:bg-base-200"
>
Cancel
</button>
<button
type="submit"
class="px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700"
class="px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-primary-content bg-primary hover:bg-primary/90"
>
Update Component
</button>
@@ -662,10 +662,10 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<!-- Components List -->
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pb-6">
<div class="bg-white shadow overflow-hidden sm:rounded-md">
<ul class="divide-y divide-gray-200" id="components-list" phx-update="replace">
<div class="bg-base-100 shadow overflow-hidden sm:rounded-md">
<ul class="divide-y divide-base-300" id="components-list" phx-update="replace">
<%= for component <- @components do %>
<li id={"component-#{component.id}"} class="px-6 py-4 hover:bg-gray-50">
<li id={"component-#{component.id}"} class="px-6 py-4 hover:bg-base-200">
<div class="flex items-center justify-between">
<!-- Component Image -->
<div class="flex-shrink-0 mr-4">
@@ -674,8 +674,8 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<img src={"/user_generated/uploads/images/#{component.image_filename}"} alt={component.name} class="h-12 w-12 rounded-lg object-cover cursor-pointer" />
</button>
<% else %>
<div class="h-12 w-12 rounded-lg bg-gray-200 flex items-center justify-center">
<.icon name="hero-cube-transparent" class="h-6 w-6 text-gray-400" />
<div class="h-12 w-12 rounded-lg bg-base-200 flex items-center justify-center">
<.icon name="hero-cube-transparent" class="h-6 w-6 text-base-content/50" />
</div>
<% end %>
</div>
@@ -684,12 +684,12 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<!-- Top row: Name and Category -->
<div class="flex items-start justify-between">
<div class="flex items-center min-w-0 flex-1">
<p class="text-sm font-medium text-indigo-600 truncate">
<p class="text-sm font-medium text-primary truncate">
<%= if component.datasheet_url do %>
<a
href={component.datasheet_url}
target="_blank"
class="hover:text-indigo-500"
class="hover:text-primary/80"
>
{component.name}
</a>
@@ -698,7 +698,7 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<% end %>
</p>
<%= if component.datasheet_url do %>
<span class="ml-2 text-blue-500" title="Datasheet available">📄</span>
<span class="ml-2 text-primary" title="Datasheet available">📄</span>
<% end %>
</div>
<div class="ml-4 flex-shrink-0">
@@ -711,29 +711,29 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<!-- Middle row: Description -->
<%= if component.description do %>
<div class="mt-1">
<p class="text-sm text-gray-500 line-clamp-2">
<p class="text-sm text-base-content/70 line-clamp-2">
{component.description}
</p>
</div>
<% end %>
<!-- Bottom row: Metadata -->
<div class="mt-2 grid grid-cols-1 sm:grid-cols-3 gap-x-4 gap-y-1 text-sm text-gray-500">
<div class="mt-2 grid grid-cols-1 sm:grid-cols-3 gap-x-4 gap-y-1 text-sm text-base-content/60">
<%= if component.storage_location do %>
<div class="flex items-center min-w-0">
<.icon name="hero-map-pin" class="w-4 h-4 mr-1 text-gray-400 flex-shrink-0" />
<.icon name="hero-map-pin" class="w-4 h-4 mr-1 text-base-content/50 flex-shrink-0" />
<span class="font-medium">Location:</span>
<span class="ml-1 truncate">{storage_location_display_name(component.storage_location)}</span>
</div>
<% end %>
<div class="flex items-center">
<.icon name="hero-cube" class="w-4 h-4 mr-1 text-gray-400" />
<.icon name="hero-cube" class="w-4 h-4 mr-1 text-base-content/50" />
<span class="font-medium">Count:</span>
<span class="ml-1">{component.count}</span>
</div>
<%= if @sort_criteria == "all" or @sort_criteria == "id" do %>
<div class="flex items-center">
<.icon name="hero-hashtag" class="w-4 h-4 mr-1 text-gray-400" />
<.icon name="hero-hashtag" class="w-4 h-4 mr-1 text-base-content/50" />
<span class="font-medium">ID:</span>
<span class="ml-1">{component.id}</span>
</div>
@@ -743,7 +743,7 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<!-- Keywords row -->
<%= if component.keywords do %>
<div class="mt-2">
<p class="text-xs text-gray-400">
<p class="text-xs text-base-content/50">
<span class="font-medium">Keywords:</span> {component.keywords}
</p>
</div>
@@ -789,7 +789,7 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<div class="bg-white px-4 py-3 flex items-center justify-center border-t border-gray-200">
<button
phx-click="load_more"
class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"
class="relative inline-flex items-center px-4 py-2 border border-base-300 text-sm font-medium rounded-md text-base-content bg-base-100 hover:bg-base-200"
>
Load More
</button>
@@ -798,9 +798,9 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<%= if Enum.empty?(@components) do %>
<div class="text-center py-12">
<.icon name="hero-cube-transparent" class="mx-auto h-12 w-12 text-gray-400" />
<h3 class="mt-2 text-sm font-medium text-gray-900">No components found</h3>
<p class="mt-1 text-sm text-gray-500">
<.icon name="hero-cube-transparent" class="mx-auto h-12 w-12 text-base-content/50" />
<h3 class="mt-2 text-sm font-medium text-base-content">No components found</h3>
<p class="mt-1 text-sm text-base-content/60">
<%= if @search != "" do %>
Try adjusting your search terms.
<% else %>
@@ -820,13 +820,13 @@ defmodule ComponentsElixirWeb.ComponentsLive do
<div class="absolute inset-0 bg-black bg-opacity-75"></div>
<!-- Modal content -->
<div class="relative bg-white rounded-lg shadow-xl max-w-4xl w-full max-h-full overflow-auto" phx-click="prevent_close">
<div class="relative bg-base-100 rounded-lg shadow-xl max-w-4xl w-full max-h-full overflow-auto" phx-click="prevent_close">
<!-- Header -->
<div class="flex justify-between items-center p-4 border-b bg-white rounded-t-lg">
<h3 class="text-lg font-semibold text-gray-900">Component Image</h3>
<div class="flex justify-between items-center p-4 border-b border-base-300 bg-base-100 rounded-t-lg">
<h3 class="text-lg font-semibold text-base-content">Component Image</h3>
<button
type="button"
class="text-gray-400 hover:text-gray-600 text-3xl font-bold leading-none p-1"
class="text-base-content/50 hover:text-base-content text-3xl font-bold leading-none p-1"
phx-click="close_image_modal"
title="Close"
>
@@ -835,7 +835,7 @@ defmodule ComponentsElixirWeb.ComponentsLive do
</div>
<!-- Content -->
<div class="p-6 bg-white rounded-b-lg">
<div class="p-6 bg-base-100 rounded-b-lg">
<div class="text-center">
<%= if @modal_image_url do %>
<img
@@ -845,7 +845,7 @@ defmodule ComponentsElixirWeb.ComponentsLive do
style="object-fit: contain;"
/>
<% else %>
<p class="text-gray-500 py-8">No image available</p>
<p class="text-base-content/60 py-8">No image available</p>
<% end %>
</div>
</div>