add settings editor component for unified on-site editing
All checks were successful
deploy / deploy (push) Successful in 4m13s

Phase 3b of unified editing mode. The Settings tab now shows
context-specific forms: custom pages get editable title, slug,
meta, visibility and nav options; system pages get read-only info
with links to admin; product/collection pages show provider info.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-03-09 15:38:06 +00:00
parent bb5d220079
commit f7891188e0
6 changed files with 553 additions and 34 deletions

View File

@@ -61,6 +61,9 @@ defmodule BerrypodWeb.PageEditorHook do
|> assign(:theme_editor_contrast_warning, :ok)
|> assign(:theme_editor_customise_open, false)
|> assign(:theme_editor_presets, Presets.all_with_descriptions())
# Settings editing state
|> assign(:settings_dirty, false)
|> assign(:settings_save_status, :idle)
|> attach_hook(:editor_params, :handle_params, &handle_editor_params/3)
|> attach_hook(:editor_events, :handle_event, &handle_editor_event/3)
|> attach_hook(:editor_info, :handle_info, &handle_editor_info/2)
@@ -212,6 +215,16 @@ defmodule BerrypodWeb.PageEditorHook do
load_theme_state(socket)
end
# Initialize settings form from current page if not already set
# Only custom pages have editable settings (meta_description, published, etc.)
socket =
if is_nil(socket.assigns[:settings_form]) && socket.assigns[:page] &&
socket.assigns.page[:type] == "custom" do
init_settings_form(socket)
else
socket
end
assign(socket, :editor_active_tab, :settings)
end
@@ -251,6 +264,15 @@ defmodule BerrypodWeb.PageEditorHook do
end
end
# Settings editing events (custom page settings)
defp handle_editor_event("settings_" <> action, params, socket) do
if socket.assigns.is_admin do
handle_settings_action(action, params, socket)
else
{:cont, socket}
end
end
defp handle_editor_event(_event, _params, socket), do: {:cont, socket}
# ── Block manipulation actions ───────────────────────────────────
@@ -721,6 +743,106 @@ defmodule BerrypodWeb.PageEditorHook do
# Catch-all for unknown theme actions
defp handle_theme_action(_action, _params, socket), do: {:halt, socket}
# ── Settings editing actions (custom page settings) ────────────────
# Validate page settings form (live as-you-type)
defp handle_settings_action("validate_page", %{"page" => params}, socket) do
page = socket.assigns.page
# Only allow editing custom pages
if page && page.type == "custom" do
socket =
socket
|> assign(:settings_form, params)
|> assign(:settings_dirty, has_settings_changed?(page, params))
|> assign(:settings_save_status, :idle)
{:halt, socket}
else
{:halt, socket}
end
end
# Save page settings
defp handle_settings_action("save_page", %{"page" => params}, socket) do
page = socket.assigns.page
# Only allow editing custom pages
if page && page.type == "custom" do
# Normalize checkbox fields (unchecked checkboxes aren't sent)
params =
params
|> Map.put_new("published", "false")
|> Map.put_new("show_in_nav", "false")
old_slug = page.slug
# Fetch the Page struct from DB (assigns.page may be a map from cache)
page_struct = Pages.get_page_struct(page.slug)
case Pages.update_custom_page(page_struct, params) do
{:ok, updated_page} ->
# Reinitialize form from saved page
socket =
socket
|> assign(:page, updated_page)
|> assign(:settings_form, nil)
|> assign(:settings_dirty, false)
|> assign(:settings_save_status, :saved)
# Reinit form with new page values
socket = init_settings_form(socket)
# If slug changed, redirect to new URL
socket =
if updated_page.slug != old_slug do
push_navigate(socket, to: "/#{updated_page.slug}")
else
socket
end
{:halt, socket}
{:error, _changeset} ->
socket = assign(socket, :settings_save_status, :error)
{:halt, socket}
end
else
{:halt, socket}
end
end
# Catch-all for unknown settings actions
defp handle_settings_action(_action, _params, socket), do: {:halt, socket}
# Check if settings have changed from current page values
defp has_settings_changed?(page, params) do
page.title != (params["title"] || "") or
page.slug != (params["slug"] || "") or
(page.meta_description || "") != (params["meta_description"] || "") or
to_string(page.published) != (params["published"] || "false") or
to_string(page.show_in_nav) != (params["show_in_nav"] || "false") or
(page.nav_label || "") != (params["nav_label"] || "") or
to_string(page.nav_position || 0) != (params["nav_position"] || "0")
end
# Initialize settings form from page values
defp init_settings_form(socket) do
page = socket.assigns.page
form = %{
"title" => page.title || "",
"slug" => page.slug || "",
"meta_description" => page.meta_description || "",
"published" => to_string(page.published),
"show_in_nav" => to_string(page.show_in_nav),
"nav_label" => page.nav_label || "",
"nav_position" => to_string(page.nav_position || 0)
}
assign(socket, :settings_form, form)
end
# Helper to update a theme setting and regenerate CSS
defp update_theme_setting(socket, attrs, field) do
case Settings.update_theme_settings(attrs) do