finish the carousel rename in the panels

Two of these were live: PageBuilderPanel still compared kind === 'gallery' in
two places, so a carousel block's editor and its Choose button were both dead
branches. The type checker could not see them — both compare against string.

The rest is copy somebody reads: "Change gallery", "Name a new gallery",
"Reading the gallery", "Add to this gallery", Home's Gallery heading, and the
"Create Gallery" file action, now "Carousel from folder".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-04 18:06:06 +01:00
co-authored by Claude Opus 5
parent 15042ccc76
commit 6e33e89e2c
15 changed files with 104 additions and 104 deletions
+15 -15
View File
@@ -8,15 +8,15 @@ import { readableError } from '../errors';
import { thumbUrl } from '../thumbnail';
/**
* One gallery's contents: what is in it, in what order, and what each picture is called.
* One carousel's contents: what is in it, in what order, and what each picture is called.
*
* ── Why it is here and not a link to Carousels ──
*
* A gallery block on a page IS a gallery, and being sent to another section to reorder it means
* A carousel block on a page IS a carousel, and being sent to another section to reorder it means
* losing the page you were arranging it for. The set is a thing of its own — that is why it has its
* own section — but editing it is something you do while looking at where it appears.
*
* ── It reads the gallery itself ──
* ── It reads the carousel itself ──
*
* `GET /carousels/:id`, rather than being handed one. The block knows an id and nothing else, and a
* component that fetches what it needs can be dropped anywhere something knows an id.
@@ -29,21 +29,21 @@ import { thumbUrl } from '../thumbnail';
*/
type Item = { id: number; url: string; alt: string | null };
type Gallery = { id: number; name: string; slug: string; items: Item[] };
type Carousel = { id: number; name: string; slug: string; items: Item[] };
export const CarouselItems = ({ carouselId, onChanged }: { carouselId: number; onChanged?: () => void }) => {
const client = useClient();
const clientRef = useRef(client);
clientRef.current = client;
const [gallery, setCarousel] = useState<Gallery | null>(null);
const [carousel, setCarousel] = useState<Carousel | null>(null);
const [busy, setBusy] = useState(false);
const [error, setError] = useState<string | null>(null);
const [picking, setPicking] = useState(false);
const load = useCallback(async () => {
try {
setCarousel((await clientRef.current.get<{ data: Gallery }>(`/fofos-admin/carousels/${carouselId}`)).data);
setCarousel((await clientRef.current.get<{ data: Carousel }>(`/fofos-admin/carousels/${carouselId}`)).data);
} catch (failure) {
setError(readableError(failure));
}
@@ -60,7 +60,7 @@ export const CarouselItems = ({ carouselId, onChanged }: { carouselId: number; o
try {
await call();
await load();
// The page draws this gallery, so it is now showing the old one.
// The page draws this carousel, so it is now showing the old one.
onChanged?.();
} catch (failure) {
setError(readableError(failure));
@@ -83,19 +83,19 @@ export const CarouselItems = ({ carouselId, onChanged }: { carouselId: number; o
const orderedRef = useRef<Item[] | null>(null);
const moveOver = (event: React.DragEvent, overId: number) => {
if (dragged === null || !gallery) return;
if (dragged === null || !carousel) return;
// Without this the drop is refused and the browser animates the row back to where it started.
event.preventDefault();
if (dragged === overId) return;
const next = [...gallery.items];
const next = [...carousel.items];
const from = next.findIndex((one) => one.id === dragged);
const to = next.findIndex((one) => one.id === overId);
if (from < 0 || to < 0) return;
next.splice(to, 0, next.splice(from, 1)[0]!);
orderedRef.current = next;
setCarousel({ ...gallery, items: next });
setCarousel({ ...carousel, items: next });
};
const commitOrder = () => {
@@ -110,19 +110,19 @@ export const CarouselItems = ({ carouselId, onChanged }: { carouselId: number; o
);
};
if (!gallery) return <p className="text-xs text-muted-foreground">{error ?? 'Loading…'}</p>;
if (!carousel) return <p className="text-xs text-muted-foreground">{error ?? 'Loading…'}</p>;
return (
<div className="flex flex-col gap-2">
<div className="flex items-baseline gap-2">
<span className="min-w-0 flex-1 truncate text-xs font-medium">{gallery.name}</span>
<span className="min-w-0 flex-1 truncate text-xs font-medium">{carousel.name}</span>
<span className="shrink-0 text-[10px] text-muted-foreground">
{gallery.items.length} item{gallery.items.length === 1 ? '' : 's'}
{carousel.items.length} item{carousel.items.length === 1 ? '' : 's'}
</span>
</div>
<ul className="flex flex-col gap-1">
{gallery.items.map((item) => (
{carousel.items.map((item) => (
<li
key={item.id}
/* The row is the drop target; the grip is what drags. See the note on the handler. */
@@ -213,7 +213,7 @@ export const CarouselItems = ({ carouselId, onChanged }: { carouselId: number; o
setPicking(false);
void send(() => clientRef.current.post(`/fofos-admin/carousels/${carouselId}/items`, { urls: [url] }));
}}
title="Add to this gallery"
title="Add to this carousel"
/>
</div>
);