diff --git a/web/canvas.ts b/web/canvas.ts index 0854180..0d2095a 100644 --- a/web/canvas.ts +++ b/web/canvas.ts @@ -57,6 +57,8 @@ export type CanvasComponent = { title?: string | null; /** `main`, `page` or null — how wide it is allowed to be. See the site's schema. */ width?: string | null; + /** `center`, `right` or null — how the block's own content sits. See the site's schema. */ + align?: string | null; /* One optional field per kind that the panel reads back. Not `Record`: every reader would then need a cast, and the point of naming them is that the compiler knows `free-text` holds diff --git a/web/sections/BlockSettings.tsx b/web/sections/BlockSettings.tsx index 52e9f27..66378e1 100644 --- a/web/sections/BlockSettings.tsx +++ b/web/sections/BlockSettings.tsx @@ -33,6 +33,7 @@ export const BlockSettings = ({ title?: string | null; title_size?: string | null; width?: string | null; + align?: string | null; padding?: Record; }; /** The padding scale, sent by the API so this file holds no copy of it. */ @@ -49,6 +50,7 @@ export const BlockSettings = ({ const [draft, setDraft] = useState({ title: block.title ?? '', width: block.width ?? '', + align: block.align ?? '', padding: block.padding ?? {}, }); const [busy, setBusy] = useState(false); @@ -57,7 +59,7 @@ export const BlockSettings = ({ // Keyed on the id, so re-reading the same block after a save does not throw away what is being typed. useEffect( - () => setDraft({ title: block.title ?? '', width: block.width ?? '', padding: block.padding ?? {} }), + () => setDraft({ title: block.title ?? '', width: block.width ?? '', align: block.align ?? '', padding: block.padding ?? {} }), [block.id], ); @@ -100,7 +102,7 @@ export const BlockSettings = ({ // Empty is sent as an empty string, which the API reads as "take the heading off". await clientRef.current.patch( `/fofos-admin/pages/${pageId}/sections/${sectionId}/components/${block.id}`, - { title: draft.title, width: draft.width || null, padding: draft.padding, ...extra }, + { title: draft.title, width: draft.width || null, align: draft.align || null, padding: draft.padding, ...extra }, ); flashSaved(); onSaved(); @@ -114,6 +116,7 @@ export const BlockSettings = ({ const stored = JSON.stringify({ title: block.title ?? '', width: block.width ?? '', + align: block.align ?? '', padding: block.padding ?? {}, }); const pending = JSON.stringify(draft); @@ -166,6 +169,33 @@ export const BlockSettings = ({ + {/* + How the block's own content sits. + + A property of the BLOCK, not of the words in it: it applies to a title drawn from the subject, + a spec table and a photograph, none of which have text you could select and centre. The rich + text editor still has its own alignment for a paragraph inside a free-text block, and the two + are different questions. + + Left is the absence of a value rather than a value, so a block that has never been touched + inherits the page and nothing is written for it. + */} +
+ + +
+ {/* The block's own spacing, at the width the toggle above is showing.