From 10e5a625ffa30e66d435931072dbf03a26c4a8b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Mon, 31 Aug 2026 15:38:20 +0100 Subject: [PATCH] Media replaces Video, and the greyed-out Image MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two rows, one of them marked `soon`, for a distinction that was never the editor's to make. The path names a real file and what that file IS is a fact about it — the site reads it off the extension the way a gallery item always has. So the picker asks for a file and stops asking what kind. `video` is gone from what an editor can create and still legal in the database. Every row was migrated; one written by something older should still be editable rather than open nothing, which is why the edit path answers to both. Co-Authored-By: Claude Opus 5 (1M context) --- web/sections/AddComponentDialog.tsx | 15 +++++++++++---- web/sections/PageBuilderPanel.tsx | 17 +++++++++++------ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/web/sections/AddComponentDialog.tsx b/web/sections/AddComponentDialog.tsx index 2fa4615..58dfac6 100644 --- a/web/sections/AddComponentDialog.tsx +++ b/web/sections/AddComponentDialog.tsx @@ -1,4 +1,4 @@ -import { Handshake, Images, Mail, Type, Video, type LucideIcon } from 'lucide-react'; +import { Handshake, Image, Images, Mail, Type, type LucideIcon } from 'lucide-react'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; /** @@ -23,7 +23,7 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/u * A kind the server would accept and this has never heard of is not creatable anyway. */ -export type ComponentKind = 'free-text' | 'video' | 'gallery' | 'contact-form' | 'partners'; +export type ComponentKind = 'free-text' | 'media' | 'gallery' | 'contact-form' | 'partners'; type Choice = { kind: ComponentKind | null; @@ -42,8 +42,15 @@ type Choice = { */ const CHOICES: Choice[] = [ { kind: 'free-text', label: 'Text', hint: 'Words, headings and links', Icon: Type }, - { kind: null, label: 'Image', hint: 'One picture from the media store', Icon: Images }, - { kind: 'video', label: 'Video', hint: 'No controls, a poster, autoplay and loop', Icon: Video }, + /* + One entry, either kind, because the block does not store which. + + Image and Video were two rows — one of them greyed out as `soon` — and the distinction was never + the editor's to make: the path names a real file and what that file IS is a fact about it. So the + picker asks for a file and the site works out the rest, which is also what a gallery item has + always done. + */ + { kind: 'media', label: 'Media', hint: 'A photograph or a video, from the media store', Icon: Image }, { kind: 'gallery', label: 'Gallery', hint: 'A named set of media', Icon: Images }, /* Two that place something the site already draws. diff --git a/web/sections/PageBuilderPanel.tsx b/web/sections/PageBuilderPanel.tsx index 4ab0537..76408ab 100644 --- a/web/sections/PageBuilderPanel.tsx +++ b/web/sections/PageBuilderPanel.tsx @@ -15,7 +15,7 @@ import { paintCanvas, type CanvasComponent, type CanvasSection } from '../canvas */ const LABELS: Record = { 'free-text': 'Text', - video: 'Video', + media: 'Media', gallery: 'Gallery', 'contact-form': 'Contact form', partners: 'Partners', @@ -294,16 +294,19 @@ export const PageBuilderPanel = () => { setChoosing(null); // Each kind opens its own editor. A kind with no case here cannot be created, which is the point. if (kind === 'free-text') setEditing({ id: null, ...at, html: '' }); - if (kind === 'video') setPicking({ id: null, ...at }); + if (kind === 'media') setPicking({ id: null, ...at }); if (kind === 'gallery') setChoosingGallery({ id: null, ...at, galleryId: null }); if (PLACES_ONLY.includes(kind)) void createEmpty(kind, at); }; /* - A video is a PATH, saved as soon as it is chosen. + A media block is a PATH, saved as soon as it is chosen. Free text needs a dialog because writing is a thing people do halfway; picking a file is one act with one outcome, so there is nothing to draft and nothing to cancel out of afterwards. + + Photograph or video is not asked. The file already knows, and the site reads it off the extension + the way a gallery item always has — a kind stored here would be a second answer able to disagree. */ const saveVideo = async (url: string) => { if (!page || !picking) return; @@ -312,7 +315,7 @@ export const PageBuilderPanel = () => { setError(null); try { if (picking.id === null) { - await clientRef.current.post(base, { kind: 'video', column: picking.column, content: { url } }); + await clientRef.current.post(base, { kind: 'media', column: picking.column, content: { url } }); } else { await clientRef.current.patch(`${base}/${picking.id}`, { content: { url } }); } @@ -353,7 +356,9 @@ export const PageBuilderPanel = () => { // Edit means whatever editing THIS kind means. The canvas draws one button; which door it opens is // decided here, where the kinds are known. - if (component.kind === 'video') { + // `video` too — no row holds it since the rename, but one written by something older should + // still be editable rather than open nothing. + if (component.kind === 'media' || component.kind === 'video') { setPicking({ id: component.id, sectionId: owner.id, column: component.column }); return; } @@ -518,7 +523,7 @@ export const PageBuilderPanel = () => { open={picking !== null} onClose={() => setPicking(null)} onPick={(path) => void saveVideo(path)} - title="Choose a video" + title="Choose a photograph or a video" />