diff --git a/assets/css/admin/components.css b/assets/css/admin/components.css index c49f8e4..76c63a9 100644 --- a/assets/css/admin/components.css +++ b/assets/css/admin/components.css @@ -94,6 +94,22 @@ /* ── Sidebar nav ── */ +.admin-nav-group { + & + & { + margin-top: 0.75rem; + } +} + +.admin-nav-heading { + display: block; + padding: 0.25rem 0.75rem; + font-size: 0.6875rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; + color: color-mix(in oklch, var(--t-text-primary) 45%, transparent); +} + .admin-nav { list-style: none; padding: 0; @@ -171,6 +187,10 @@ &:hover { background-color: var(--t-surface-sunken); opacity: 1; } } +.admin-btn-active { + background-color: var(--t-surface-sunken); +} + .admin-btn-outline { background: none; color: inherit; @@ -1282,6 +1302,39 @@ color: var(--t-text-secondary); } +/* Inline page settings panel */ + +.page-settings-panel { + margin-top: 1rem; + padding: 1rem; + border: 1px solid var(--t-border-default); + border-radius: 0.5rem; + background: var(--t-surface-sunken); +} + +.page-settings-fields { + display: grid; + gap: 0.75rem; + + @media (min-width: 40em) { + grid-template-columns: 1fr 1fr; + } +} + +.page-settings-row { + display: flex; + gap: 1.5rem; + align-items: center; +} + +.page-settings-actions { + display: flex; + gap: 0.5rem; + margin-top: 1rem; + padding-top: 0.75rem; + border-top: 1px solid var(--t-border-default); +} + /* Page editor split layout */ .page-editor-container { diff --git a/lib/berrypod_web/components/layouts/admin.html.heex b/lib/berrypod_web/components/layouts/admin.html.heex index a7a07f4..d9b967e 100644 --- a/lib/berrypod_web/components/layouts/admin.html.heex +++ b/lib/berrypod_web/components/layouts/admin.html.heex @@ -53,104 +53,119 @@ <%!-- nav links --%> <%!-- sidebar footer --%> diff --git a/lib/berrypod_web/live/admin/pages/editor.ex b/lib/berrypod_web/live/admin/pages/editor.ex index 45e2290..4e25baa 100644 --- a/lib/berrypod_web/live/admin/pages/editor.ex +++ b/lib/berrypod_web/live/admin/pages/editor.ex @@ -1,7 +1,7 @@ defmodule BerrypodWeb.Admin.Pages.Editor do use BerrypodWeb, :live_view - alias Berrypod.{LegalPages, Media, Pages} + alias Berrypod.{LegalPages, Media, Pages, Products} alias Berrypod.Pages.{BlockEditor, BlockTypes, Page} alias Berrypod.Products.ProductImage alias Berrypod.Theme.{Fonts, PreviewData} @@ -13,9 +13,12 @@ defmodule BerrypodWeb.Admin.Pages.Editor do page = Pages.get_page(slug) allowed_blocks = BlockTypes.allowed_for(slug) + real_products = Products.list_visible_products(limit: 8) + real_categories = Products.list_categories() + preview_data = %{ - products: PreviewData.products(), - categories: PreviewData.categories(), + products: if(real_products != [], do: real_products, else: PreviewData.products()), + categories: if(real_categories != [], do: real_categories, else: PreviewData.categories()), cart_items: PreviewData.cart_items() } @@ -43,6 +46,7 @@ defmodule BerrypodWeb.Admin.Pages.Editor do |> assign(:image_picker_search, "") |> assign(:is_custom_page, !Page.system_slug?(slug)) |> assign(:is_legal_page, LegalPages.legal_slug?(slug)) + |> assign_settings_form(slug) |> allow_upload(:image_picker_upload, accept: ~w(.png .jpg .jpeg .webp .svg), max_entries: 1, @@ -462,6 +466,55 @@ defmodule BerrypodWeb.Admin.Pages.Editor do end end + # ── Page settings (custom pages only) ───────────────────────────── + + def handle_event("toggle_settings", _params, socket) do + {:noreply, assign(socket, :show_settings, !socket.assigns.show_settings)} + end + + def handle_event("validate_settings", %{"page" => params}, socket) do + form = + socket.assigns.page_struct + |> Page.custom_changeset(params) + |> Map.put(:action, :validate) + |> to_form() + + {:noreply, assign(socket, :settings_form, form)} + end + + def handle_event("save_settings", %{"page" => params}, socket) do + case Pages.update_custom_page(socket.assigns.page_struct, params) do + {:ok, page} -> + {:noreply, + socket + |> assign(:page_struct, page) + |> assign(:page_data, %{socket.assigns.page_data | title: page.title}) + |> assign(:page_title, page.title) + |> assign(:settings_form, to_form(Page.custom_changeset(page, %{}))) + |> assign(:show_settings, false) + |> put_flash(:info, "Page settings saved")} + + {:error, changeset} -> + {:noreply, assign(socket, :settings_form, to_form(changeset))} + end + end + + defp assign_settings_form(socket, slug) do + if Page.system_slug?(slug) do + socket + |> assign(:show_settings, false) + |> assign(:page_struct, nil) + |> assign(:settings_form, nil) + else + page_struct = Pages.get_page_struct(slug) + + socket + |> assign(:show_settings, false) + |> assign(:page_struct, page_struct) + |> assign(:settings_form, to_form(Page.custom_changeset(page_struct, %{}))) + end + end + # ── Render ─────────────────────────────────────────────────────── @impl true @@ -487,13 +540,16 @@ defmodule BerrypodWeb.Admin.Pages.Editor do /> {if @show_preview, do: "Edit", else: "Preview"} - <.link + + + + +
<%!-- Editor pane --%>