add page builder polish: utility blocks, templates, duplicate
All checks were successful
deploy / deploy (push) Successful in 1m24s
All checks were successful
deploy / deploy (push) Successful in 1m24s
New block types: spacer, divider, button/CTA, video embed (YouTube, Vimeo with privacy-enhanced embeds, fallback for unknown URLs). Page templates (blank, content, landing) shown when creating custom pages. Duplicate page action on admin index with slug deduplication. Fix block picker on shop edit sidebar being cut off on mobile by accounting for bottom nav and making the grid scrollable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@ defmodule BerrypodWeb.Admin.Pages.CustomForm do
|
||||
use BerrypodWeb, :live_view
|
||||
|
||||
alias Berrypod.Pages
|
||||
alias Berrypod.Pages.Page
|
||||
alias Berrypod.Pages.{Defaults, Page}
|
||||
|
||||
@impl true
|
||||
def mount(params, _session, socket) do
|
||||
@@ -16,6 +16,7 @@ defmodule BerrypodWeb.Admin.Pages.CustomForm do
|
||||
|> assign(:page_title, "New page")
|
||||
|> assign(:page_struct, %Page{})
|
||||
|> assign(:slug_touched, false)
|
||||
|> assign(:selected_template, "blank")
|
||||
|> assign(:form, to_form(changeset))
|
||||
end
|
||||
|
||||
@@ -53,12 +54,20 @@ defmodule BerrypodWeb.Admin.Pages.CustomForm do
|
||||
{:noreply, assign(socket, form: form, slug_touched: slug_touched)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("select_template", %{"key" => key}, socket) do
|
||||
{:noreply, assign(socket, :selected_template, key)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("save", %{"page" => params}, socket) do
|
||||
save_page(socket, socket.assigns.live_action, params)
|
||||
end
|
||||
|
||||
defp save_page(socket, :new, params) do
|
||||
template_blocks = Defaults.template_blocks(socket.assigns.selected_template)
|
||||
params = Map.put(params, "blocks", template_blocks)
|
||||
|
||||
case Pages.create_custom_page(params) do
|
||||
{:ok, page} ->
|
||||
{:noreply,
|
||||
@@ -120,6 +129,25 @@ defmodule BerrypodWeb.Admin.Pages.CustomForm do
|
||||
{if @live_action == :new, do: "New page", else: "Page settings"}
|
||||
</.header>
|
||||
|
||||
<div :if={@live_action == :new} class="template-picker">
|
||||
<p class="template-picker-label">Start from a template</p>
|
||||
<div class="template-picker-cards">
|
||||
<button
|
||||
:for={tmpl <- Defaults.templates()}
|
||||
type="button"
|
||||
phx-click="select_template"
|
||||
phx-value-key={tmpl.key}
|
||||
class={[
|
||||
"template-card",
|
||||
assigns[:selected_template] == tmpl.key && "template-card-selected"
|
||||
]}
|
||||
>
|
||||
<span class="template-card-name">{tmpl.label}</span>
|
||||
<span class="template-card-desc">{tmpl.description}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<.form
|
||||
for={@form}
|
||||
id="custom-page-form"
|
||||
|
||||
@@ -40,6 +40,26 @@ defmodule BerrypodWeb.Admin.Pages.Index do
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("duplicate_custom_page", %{"slug" => slug}, socket) do
|
||||
case Pages.get_page_struct(slug) do
|
||||
%{type: "custom"} = page ->
|
||||
case Pages.duplicate_custom_page(page) do
|
||||
{:ok, copy} ->
|
||||
{:noreply,
|
||||
socket
|
||||
|> assign(:custom_pages, Pages.list_custom_pages())
|
||||
|> put_flash(:info, "\"#{copy.title}\" created as draft")}
|
||||
|
||||
{:error, _} ->
|
||||
{:noreply, put_flash(socket, :error, "Failed to duplicate page")}
|
||||
end
|
||||
|
||||
_ ->
|
||||
{:noreply, put_flash(socket, :error, "Page not found")}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
@@ -101,6 +121,14 @@ defmodule BerrypodWeb.Admin.Pages.Index do
|
||||
</span>
|
||||
<.icon name="hero-chevron-right-mini" class="size-4 page-card-arrow" />
|
||||
</.link>
|
||||
<button
|
||||
phx-click="duplicate_custom_page"
|
||||
phx-value-slug={page.slug}
|
||||
class="page-card-action"
|
||||
aria-label={"Duplicate #{page.title}"}
|
||||
>
|
||||
<.icon name="hero-document-duplicate" class="size-4" />
|
||||
</button>
|
||||
<button
|
||||
phx-click="delete_custom_page"
|
||||
phx-value-slug={page.slug}
|
||||
|
||||
Reference in New Issue
Block a user