add admin media library with image management and block picker integration
- Schema: alt, caption, tags fields on images table with metadata changeset - Context: list_images with filters, find_usages, used_image_ids, delete_with_cleanup - Admin UI: /admin/media with grid view, upload, filters, detail panel, metadata editing - Block editor: :image field type for image_text and content_body blocks - Page renderer: image_id resolution with legacy URL fallback - Mobile: bottom sheet detail panel with slide-up animation - CSS: uses correct --t-* admin theme tokens, admin-badge colour variants Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -249,12 +249,13 @@ defmodule BerrypodWeb.PageRenderer do
|
||||
|
||||
defp render_block(%{block: %{"type" => "image_text"}} = assigns) do
|
||||
settings = assigns.block["settings"] || %{}
|
||||
image_url = resolve_block_image_url(settings["image_id"], settings["image_url"])
|
||||
|
||||
assigns =
|
||||
assigns
|
||||
|> assign(:section_title, settings["title"] || "")
|
||||
|> assign(:section_description, settings["description"] || "")
|
||||
|> assign(:image_url, settings["image_url"] || "")
|
||||
|> assign(:image_url, image_url)
|
||||
|> assign(:link_text, settings["link_text"])
|
||||
|> assign(:link_href, settings["link_href"])
|
||||
|
||||
@@ -560,11 +561,12 @@ defmodule BerrypodWeb.PageRenderer do
|
||||
defp render_block(%{block: %{"type" => "content_body"}} = assigns) do
|
||||
settings = assigns.block["settings"] || %{}
|
||||
content = settings["content"] || ""
|
||||
{image_src, image_alt} = resolve_content_image(settings)
|
||||
|
||||
assigns =
|
||||
assigns
|
||||
|> assign(:image_src, settings["image_src"])
|
||||
|> assign(:image_alt, settings["image_alt"] || "")
|
||||
|> assign(:image_src, image_src)
|
||||
|> assign(:image_alt, image_alt)
|
||||
|> assign(:content, content)
|
||||
|
||||
~H"""
|
||||
@@ -998,6 +1000,42 @@ defmodule BerrypodWeb.PageRenderer do
|
||||
defp collection_path(slug, "featured"), do: ~p"/collections/#{slug}"
|
||||
defp collection_path(slug, sort), do: ~p"/collections/#{slug}?sort=#{sort}"
|
||||
|
||||
# Resolves an image_id to a URL, falling back to a legacy URL string
|
||||
defp resolve_block_image_url(image_id, fallback_url) do
|
||||
case resolve_image(image_id) do
|
||||
{url, _alt} -> url
|
||||
nil -> fallback_url || ""
|
||||
end
|
||||
end
|
||||
|
||||
# Resolves image_id for content_body blocks, returning {src, alt}
|
||||
defp resolve_content_image(settings) do
|
||||
case resolve_image(settings["image_id"]) do
|
||||
{src, alt} -> {src, alt}
|
||||
nil -> {settings["image_src"], settings["image_alt"] || ""}
|
||||
end
|
||||
end
|
||||
|
||||
defp resolve_image(nil), do: nil
|
||||
defp resolve_image(""), do: nil
|
||||
|
||||
defp resolve_image(image_id) do
|
||||
case Berrypod.Media.get_image(image_id) do
|
||||
nil ->
|
||||
nil
|
||||
|
||||
image ->
|
||||
url =
|
||||
if image.is_svg do
|
||||
"/image_cache/#{image.id}.webp"
|
||||
else
|
||||
"/image_cache/#{image.id}-800.webp"
|
||||
end
|
||||
|
||||
{url, image.alt || image.filename}
|
||||
end
|
||||
end
|
||||
|
||||
def format_order_status("unfulfilled"), do: "Being prepared"
|
||||
def format_order_status("submitted"), do: "Sent to printer"
|
||||
def format_order_status("processing"), do: "In production"
|
||||
|
||||
Reference in New Issue
Block a user