From d2ac0aca1bdfcbc2a9a3bb8c8dcd7e140717b85f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Tue, 1 Sep 2026 09:05:32 +0100 Subject: [PATCH] Home stays first, and a reorder shows in the preview MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Home has no grip, and dropping onto it is refused — hiding the handle alone would still let something be dragged above the site's front door. Every preview now reloads on the change channel, not just the page builder's own writes. The Layout preview draws the top menu and had no reload token at all, so the one screen where a reorder is visible was the one that never showed it. Co-Authored-By: Claude Opus 5 (1M context) --- web/NavPanel.tsx | 18 ++++++++++++++++++ web/SitePreview.tsx | 17 +++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/web/NavPanel.tsx b/web/NavPanel.tsx index 2babaa2..528a0c7 100644 --- a/web/NavPanel.tsx +++ b/web/NavPanel.tsx @@ -6,6 +6,7 @@ import { SECTIONS, sectionOpen } from './sections'; import { href, useNav } from './routes'; import { useReady } from './useReady'; import { pageParam, usePages, type Page } from './usePages'; +import { useFofosChanged } from './channel'; /** * The left column: which part of the fofos site the detail panel is showing. @@ -91,11 +92,15 @@ export const NavPanel = () => { The write happens once, at the end: `PUT /pages/order` takes the whole set, because an order is a property of the SET and sending one row's new index leaves the server guessing about everyone else. */ + const [, bump] = useFofosChanged(); const [dragged, setDragged] = useState(null); const orderedRef = useRef(null); const moveOver = (event: React.DragEvent, overId: number) => { if (dragged === null || !pages) return; + // Home is first and stays first — see the note on its missing grip. Refusing the drop here is what + // stops anything being dragged ABOVE it, which no amount of hiding the handle would prevent. + if (pages.find((page) => page.id === overId)?.is_home) return; // Without this the drop is refused and the browser animates the row back to where it started. event.preventDefault(); if (dragged === overId) return; @@ -119,6 +124,8 @@ export const NavPanel = () => { void clientRef.current .put('/fofos-admin/pages/order', { ids: ordered.map((page) => page.id) }) + // The menu is the site's, so every preview on the screen is now showing the old one. + .then(() => bump()) // The list is already showing the new order; a failure has to put the old one back, and the // server is the only thing that knows what that was. .catch(() => void clientRef.current.get<{ data: Page[] }>('/fofos-admin/pages').then((body) => announce(body.data))); @@ -210,6 +217,16 @@ export const NavPanel = () => { current ? 'bg-muted' : 'hover:bg-muted/50' } ${dragged === page.id ? 'opacity-40' : ''}`} > + {/* + Home has no grip. + + It is the site's front door and its address is `/`; a menu that opens somewhere else + is not a menu with a different order, it is a different site. The space is kept so the + titles still line up — an unindented Home would read as a heading rather than a row. + */} + {page.is_home ? ( + + ) : ( { @@ -224,6 +241,7 @@ export const NavPanel = () => { > + )} { setLoaded(0); - }, [reloadToken]); + }, [reloadToken, changed]); useEffect(() => { if (!loaded) return; @@ -334,7 +347,7 @@ export const SitePreview = ({