Files
pastilhasandClaude Opus 5 15042ccc76 a gallery is a carousel
It always rendered as one — data-carousel, a snap track, two arrows, driven by
carousel.client.js. The entity was the last thing still calling it something
else, and that collided with the site's own Gallery section: two nav rows
reading Gallery and Galleries, meaning a list of objects and a list of
photograph sets.

GalleriesPanel, GalleryPicker and GalleryItems become Carousels*, the endpoint
becomes /fofos-admin/carousels, the block kind becomes carousel and
subject-gallery becomes subject-carousel. The publish allowlist follows the
renamed tables.

What did NOT move: GALLERY_CONFIG at /fofos-admin/gallery, subjects.ts's
base '/gallery', and home_gallery_media. Those are the Gallery section and the
legacy rows, and both are correct.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 18:01:15 +01:00

76 lines
3.3 KiB
TypeScript

import { useLocation } from 'react-router';
import { DEFAULT_SECTION, isSectionKey, type SectionKey } from './sections';
/**
* Where this admin is in the URL, read from the PATH.
*
* ── The path, not the query string ──
*
* It was `?section=layout&band=header`. Everything about where you were lived in the query, which made
* every link a fresh `URLSearchParams` and every navigation a decision about what to carry — see the
* note NavPanel used to hold about parameters leaking between sections. A path has no such question:
* `/fofos-admin/layout/header` says where you are and nothing else, and what remains in the query is
* genuinely about how you are looking rather than at what.
*
* The routes themselves are declared in the manifest, so the platform knows they exist — which is what
* lets a route carry its own arrangement of panels rather than sharing one with the whole screen.
*
* ── Why the pathname and not `useParams` ──
*
* Which parameters exist depends on which route matched: `/fofos-admin/layout/header` has a `band` and
* `/fofos-admin/carousels` has nothing. A panel would then have to know its own route to read its own
* position, and every panel is rendered on all of them.
*
* Two segments after the mount, always in the same places. One reader, every route.
*/
export const MOUNT = '/fofos-admin';
/**
* The section and its sub-item, from the two segments after the mount.
*
* `atIndex` is the bare `/fofos-admin`, which is a real state and not the same as Layout: the panel
* redirects, so the address bar ends up saying where you are. `section` is still defaulted, so
* everything that only wants to draw a highlight has one answer rather than a branch.
*/
export const useNav = (): {
section: SectionKey;
item: string | null;
part: string | null;
piece: string | null;
atIndex: boolean;
} => {
const { pathname } = useLocation();
const rest = pathname.startsWith(MOUNT) ? pathname.slice(MOUNT.length) : '';
const [first = '', second = '', third = '', fourth = ''] = rest.replace(/^\//, '').split('/');
return {
// An unknown segment falls back rather than 404s: the URL is a thing people type and edit.
section: isSectionKey(first) ? first : DEFAULT_SECTION,
item: second ? decodeURIComponent(second) : null,
/** Something inside the item — a band of the open page. */
part: third ? decodeURIComponent(third) : null,
/** Something inside THAT — a block in the band. This is what selection writes. */
piece: fourth ? decodeURIComponent(fourth) : null,
atIndex: first === '',
};
};
/**
* A link to a section, or to something inside one.
*
* The query string is dropped, and that is the point rather than an omission. `?device=tablet` is how
* you are looking at the Layout preview; carrying it into Carousels would be state from one screen
* deciding something on another. A panel that wants a parameter to survive says so at its own link.
*/
export const href = (
section: SectionKey,
item?: string | null,
part?: string | null,
piece?: string | null,
): string => {
if (!item) return `${MOUNT}/${section}`;
let path = `${MOUNT}/${section}/${encodeURIComponent(item)}`;
if (!part) return path;
path += `/${encodeURIComponent(part)}`;
return piece ? `${path}/${encodeURIComponent(piece)}` : path;
};