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>
This commit is contained in:
2026-09-04 18:01:15 +01:00
co-authored by Claude Opus 5
parent 5e5c06e76e
commit 15042ccc76
19 changed files with 148 additions and 148 deletions
+12 -12
View File
@@ -4,7 +4,7 @@ import { Images, Loader2, Plus, Trash2 } from 'lucide-react';
import { useClient } from 'hooks/useClient';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { GalleryPicker } from '../GalleryPicker';
import { CarouselPicker } from '../CarouselPicker';
import { readableError } from '../errors';
import { useEditorSlot } from '../useEditorSlot';
import { thumbUrl } from '../thumbnail';
@@ -27,7 +27,7 @@ import type { SubjectPhoto, SubjectRecord, SubjectSection } from './subjects';
*
* The photographs belong to the gallery, and so does their order — including which one leads, which
* is simply the first. Making them look pressable here would promise a control that lives in
* Galleries.
* Carousels.
*/
export const SubjectPanel = <T extends SubjectRecord>({ section }: { section: SubjectSection<T> }) => {
const client = useClient();
@@ -167,11 +167,11 @@ export const SubjectPanel = <T extends SubjectRecord>({ section }: { section: Su
);
});
const chooseGallery = (galleryId: number) =>
const chooseCarousel = (carouselId: number) =>
send(async () => {
if (!selected) return;
setPicking(false);
await clientRef.current.patch(`${section.endpoint}/${selected.id}`, { gallery_id: galleryId });
await clientRef.current.patch(`${section.endpoint}/${selected.id}`, { carousel_id: carouselId });
});
return (
@@ -230,11 +230,11 @@ export const SubjectPanel = <T extends SubjectRecord>({ section }: { section: Su
<div className="mb-4 flex flex-wrap items-center gap-2 border-b border-border pb-3">
<Button size="sm" variant="outline" className="h-8 gap-1.5 text-xs" onClick={() => setPicking(true)}>
<Images className="size-3.5" />
{selected.gallery_id ? 'Change gallery' : 'Choose a gallery'}
{selected.carousel_id ? 'Change gallery' : 'Choose a gallery'}
</Button>
<span className="min-w-0 flex-1" />
{/* Deleting removes the ROW, never the photographs — they belong to a gallery, which
belongs to Galleries. Said on the button so nobody has to find out. */}
belongs to Carousels. Said on the button so nobody has to find out. */}
<Button
size="sm"
variant="outline"
@@ -251,7 +251,7 @@ export const SubjectPanel = <T extends SubjectRecord>({ section }: { section: Su
{!selected ? (
<p className="text-xs text-muted-foreground">Choose a {section.noun}, or make one.</p>
) : !selected.gallery_id ? (
) : !selected.carousel_id ? (
<p className="text-xs text-muted-foreground">
No gallery yet. Choose one and its photographs appear here.
</p>
@@ -261,13 +261,13 @@ export const SubjectPanel = <T extends SubjectRecord>({ section }: { section: Su
</p>
) : photos.length === 0 ? (
<p className="text-xs text-muted-foreground">
That gallery is empty. Add photographs to it in Galleries.
That gallery is empty. Add photographs to it in Carousels.
</p>
) : (
<>
<p className="mb-3 text-xs text-muted-foreground">
{photos.length} photographs, in the gallery&rsquo;s order &mdash; the first one leads.
Reorder them in Galleries.
Reorder them in Carousels.
</p>
<ul className="grid grid-cols-[repeat(auto-fill,minmax(9rem,1fr))] gap-3">
{photos.map((photo) => (
@@ -286,11 +286,11 @@ export const SubjectPanel = <T extends SubjectRecord>({ section }: { section: Su
{/* `selected` guarded: the picker writes to whatever is open, and there is nothing to write to
when nothing is. */}
{selected && (
<GalleryPicker
<CarouselPicker
open={picking}
onClose={() => setPicking(false)}
onPick={(galleryId) => void chooseGallery(galleryId)}
selected={selected.gallery_id}
onPick={(carouselId) => void chooseCarousel(carouselId)}
selected={selected.carousel_id}
/>
)}
</div>