add link picker and validation to navigation editor
All checks were successful
deploy / deploy (push) Successful in 1m26s

- replace freeform inputs with grouped dropdown (pages, custom pages,
  collections, external URL)
- add inline URL validation for external links
- add inline feedback component instead of flash messages
- add dismiss-on-interaction pattern (feedback clears on changes)
- add no-JS fallback via NavigationController
- add DirtyGuard hook to warn before navigating away with unsaved changes
- add no-JS fallbacks for settings forms (from address, signing secret)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-03-08 02:10:06 +00:00
parent 42542ac177
commit 3e29a89fff
10 changed files with 551 additions and 204 deletions

View File

@@ -113,12 +113,15 @@ defmodule BerrypodWeb.Admin.Settings do
# -- Events: from address --
def handle_event("change_from_address", _params, socket) do
{:noreply, assign(socket, :from_address_status, :idle)}
end
def handle_event("save_from_address", %{"from_address" => address}, socket) do
address = String.trim(address)
if address != "" do
Settings.put_setting("email_from_address", address)
Process.send_after(self(), :clear_from_address_status, 3000)
{:noreply,
socket
@@ -179,12 +182,15 @@ defmodule BerrypodWeb.Admin.Settings do
{:noreply, socket}
end
def handle_event("change_signing_secret", _params, socket) do
{:noreply, assign(socket, :signing_secret_status, :idle)}
end
def handle_event("save_signing_secret", %{"webhook" => %{"signing_secret" => secret}}, socket) do
if secret == "" do
{:noreply, put_flash(socket, :error, "Please enter a signing secret")}
else
StripeSetup.save_signing_secret(secret)
Process.send_after(self(), :clear_signing_secret_status, 3000)
socket =
socket
@@ -293,17 +299,6 @@ defmodule BerrypodWeb.Admin.Settings do
end
end
# -- Clear status messages --
@impl true
def handle_info(:clear_from_address_status, socket) do
{:noreply, assign(socket, :from_address_status, :idle)}
end
def handle_info(:clear_signing_secret_status, socket) do
{:noreply, assign(socket, :signing_secret_status, :idle)}
end
# -- Render --
@impl true
@@ -456,7 +451,14 @@ defmodule BerrypodWeb.Admin.Settings do
The sender address on all emails from your shop.
</p>
<div class="admin-section-body">
<form phx-submit="save_from_address" class="admin-row admin-row-lg">
<form
action={~p"/admin/settings/from-address"}
method="post"
phx-change="change_from_address"
phx-submit="save_from_address"
class="admin-row admin-row-lg"
>
<input type="hidden" name="_csrf_token" value={Phoenix.Controller.get_csrf_token()} />
<.input
name="from_address"
value={@from_address}
@@ -711,7 +713,13 @@ defmodule BerrypodWeb.Admin.Settings do
</p>
</div>
<.form for={@secret_form} phx-submit="save_signing_secret">
<.form
for={@secret_form}
action={~p"/admin/settings/stripe/signing-secret"}
method="post"
phx-change="change_signing_secret"
phx-submit="save_signing_secret"
>
<.input
field={@secret_form[:signing_secret]}
type="password"
@@ -741,7 +749,13 @@ defmodule BerrypodWeb.Admin.Settings do
<p class="admin-text-tertiary">
Override the webhook signing secret if you need to use a custom endpoint or the Stripe CLI.
</p>
<.form for={@secret_form} phx-submit="save_signing_secret">
<.form
for={@secret_form}
action={~p"/admin/settings/stripe/signing-secret"}
method="post"
phx-change="change_signing_secret"
phx-submit="save_signing_secret"
>
<.input
field={@secret_form[:signing_secret]}
type="password"