an Alignment control beside Width

Left, Centred, Right on the selected block. Left writes nothing, so a block that
has never been touched inherits the page.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-05 14:53:44 +01:00
co-authored by Claude Opus 5
parent 55be0a1860
commit 76a749d8f9
2 changed files with 34 additions and 2 deletions
+32 -2
View File
@@ -33,6 +33,7 @@ export const BlockSettings = ({
title?: string | null;
title_size?: string | null;
width?: string | null;
align?: string | null;
padding?: Record<string, { x?: number; y?: number }>;
};
/** 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 = ({
</select>
</div>
{/*
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.
*/}
<div className="mt-3 flex flex-col gap-1">
<label className="text-xs">Alignment</label>
<select
value={draft.align}
onChange={(event) => {
const value = event.currentTarget.value;
setDraft((was) => ({ ...was, align: value }));
}}
className="h-8 rounded-md border border-input bg-transparent px-2 text-xs"
>
<option value="">Left</option>
<option value="center">Centred</option>
<option value="right">Right</option>
</select>
</div>
{/*
The block's own spacing, at the width the toggle above is showing.