fix content image double-suffix, clean up page defaults and editor UX
All checks were successful
deploy / deploy (push) Successful in 1m22s

- Fix resolve_content_image returning base path (not full URL) so
  responsive_image doesn't double-append width/extension
- Remove legacy image fields (image_src, image_alt, image_url) from
  block settings schemas
- Remove demo/mockup fallbacks from renderer and defaults — blank
  fields stay blank instead of showing preview content
- Replace demo text in defaults with instructional placeholders that
  guide new shop owners
- Remove redundant X button from editor sidebar, add unsaved-changes
  confirmation to Done button
- Fix block card name overflow on mobile (display: block, flex-wrap)
- Add onboarding UX improvement plan (10 tasks)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-03-03 00:56:01 +00:00
parent 61772c26ae
commit 8ea77e5992
11 changed files with 189 additions and 80 deletions

View File

@@ -112,15 +112,12 @@ defmodule BerrypodWeb.PageRenderer do
>
Reset
</button>
<button phx-click="editor_done" class="admin-btn admin-btn-sm admin-btn-ghost">
Done
</button>
<button
phx-click="editor_toggle_sidebar"
phx-click="editor_done"
class="admin-btn admin-btn-sm admin-btn-ghost"
aria-label="Close sidebar"
data-confirm={@editor_dirty && "You have unsaved changes. Leave without saving?"}
>
<.icon name="hero-x-mark" class="size-5" />
Done
</button>
</div>
</div>
@@ -280,7 +277,7 @@ 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"])
image_url = resolve_block_image_url(settings["image_id"])
assigns =
assigns
@@ -634,11 +631,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)
{image_src, source_width, image_alt} = resolve_content_image(settings)
assigns =
assigns
|> assign(:image_src, image_src)
|> assign(:image_source_width, source_width || 1200)
|> assign(:image_alt, image_alt)
|> assign(:content, content)
@@ -648,7 +646,7 @@ defmodule BerrypodWeb.PageRenderer do
<div class="content-image">
<.responsive_image
src={@image_src}
source_width={1200}
source_width={@image_source_width}
alt={@image_alt}
sizes="(max-width: 800px) 100vw, 800px"
class="content-hero-image"
@@ -1154,47 +1152,41 @@ 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
# Resolves an image_id to a full URL for blocks that need a single URL (e.g. background-image).
defp resolve_block_image_url(image_id) do
case resolve_image(image_id) do
{url, _alt} -> url
nil -> fallback_url || ""
nil ->
""
image ->
if image.is_svg do
"/image_cache/#{image.id}.webp"
else
width =
image.source_width
|> Berrypod.Images.Optimizer.applicable_widths()
|> List.last()
"/image_cache/#{image.id}-#{width || 400}.webp"
end
end
end
# Resolves image_id for content_body blocks, returning {src, alt}
# Resolves image_id for content_body blocks, returning {base_path, source_width, alt}.
# base_path has no width/extension suffix — responsive_image adds those.
defp resolve_content_image(settings) do
case resolve_image(settings["image_id"]) do
{src, alt} -> {src, alt}
nil -> {settings["image_src"], settings["image_alt"] || ""}
nil ->
{nil, nil, ""}
image ->
{"/image_cache/#{image.id}", image.source_width, image.alt || image.filename}
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
# Pick the largest variant that was actually generated
width =
image.source_width
|> Berrypod.Images.Optimizer.applicable_widths()
|> List.last()
"/image_cache/#{image.id}-#{width || 400}.webp"
end
{url, image.alt || image.filename}
end
end
defp resolve_image(image_id), do: Berrypod.Media.get_image(image_id)
@youtube_re ~r/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})/
@vimeo_re ~r/vimeo\.com\/(?:video\/)?(\d+)/