defmodule PhoenixKit.Modules.Shared.Components.Image do
@moduledoc """
Image component with lazy loading and responsive sizing.
Supports both direct URLs and PhoenixKit Storage file UUIDs with automatic variant selection.
## Usage
### With direct URL:
### With PhoenixKit Storage file UUID:
## Attributes
- `src` - Direct image URL (takes precedence over file_uuid)
- `file_uuid` - PhoenixKit Storage file UUID
- `file_variant` - Storage variant to use (default: "original")
- Images: "original", "thumbnail", "small", "medium", "large"
- `alt` - Alt text for accessibility (required)
- `class` - Additional CSS classes (optional)
"""
use Phoenix.Component
alias PhoenixKit.Modules.Storage
attr :attributes, :map, default: %{}
attr :variant, :string, default: "default"
attr :content, :string, default: nil
def render(assigns) do
# Extract attributes
src = Map.get(assigns.attributes, "src")
file_uuid = Map.get(assigns.attributes, "file_uuid")
file_variant = Map.get(assigns.attributes, "file_variant", "original")
alt = Map.get(assigns.attributes, "alt", "")
custom_class = Map.get(assigns.attributes, "class", "")
# Determine image source
image_src =
cond do
# Direct src takes precedence
src && src != "" ->
src
# Use file_uuid from PhoenixKit Storage
file_uuid && file_uuid != "" ->
get_file_url(file_uuid, file_variant)
# No source provided
true ->
nil
end
assigns =
assigns
|> assign(:src, image_src)
|> assign(:alt, alt)
|> assign(:custom_class, custom_class)
~H"""
<%= if @src do %>
<% else %>
<%!-- Fallback for missing image --%>
Image not available
<% end %>
"""
end
# Helper function to get file URL from Storage
defp get_file_url(file_uuid, variant) do
case Storage.get_public_url_by_uuid(file_uuid, variant) do
nil ->
# Try without variant (fallback to original)
Storage.get_public_url_by_uuid(file_uuid)
url ->
url
end
rescue
_ ->
# Gracefully handle missing repo or file
nil
end
end