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:
@@ -57,6 +57,8 @@ export type CanvasComponent = {
|
|||||||
title?: string | null;
|
title?: string | null;
|
||||||
/** `main`, `page` or null — how wide it is allowed to be. See the site's schema. */
|
/** `main`, `page` or null — how wide it is allowed to be. See the site's schema. */
|
||||||
width?: string | null;
|
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<string, unknown>`: every reader
|
One optional field per kind that the panel reads back. Not `Record<string, unknown>`: every reader
|
||||||
would then need a cast, and the point of naming them is that the compiler knows `free-text` holds
|
would then need a cast, and the point of naming them is that the compiler knows `free-text` holds
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ export const BlockSettings = ({
|
|||||||
title?: string | null;
|
title?: string | null;
|
||||||
title_size?: string | null;
|
title_size?: string | null;
|
||||||
width?: string | null;
|
width?: string | null;
|
||||||
|
align?: string | null;
|
||||||
padding?: Record<string, { x?: number; y?: number }>;
|
padding?: Record<string, { x?: number; y?: number }>;
|
||||||
};
|
};
|
||||||
/** The padding scale, sent by the API so this file holds no copy of it. */
|
/** 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({
|
const [draft, setDraft] = useState({
|
||||||
title: block.title ?? '',
|
title: block.title ?? '',
|
||||||
width: block.width ?? '',
|
width: block.width ?? '',
|
||||||
|
align: block.align ?? '',
|
||||||
padding: block.padding ?? {},
|
padding: block.padding ?? {},
|
||||||
});
|
});
|
||||||
const [busy, setBusy] = useState(false);
|
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.
|
// Keyed on the id, so re-reading the same block after a save does not throw away what is being typed.
|
||||||
useEffect(
|
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],
|
[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".
|
// Empty is sent as an empty string, which the API reads as "take the heading off".
|
||||||
await clientRef.current.patch(
|
await clientRef.current.patch(
|
||||||
`/fofos-admin/pages/${pageId}/sections/${sectionId}/components/${block.id}`,
|
`/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();
|
flashSaved();
|
||||||
onSaved();
|
onSaved();
|
||||||
@@ -114,6 +116,7 @@ export const BlockSettings = ({
|
|||||||
const stored = JSON.stringify({
|
const stored = JSON.stringify({
|
||||||
title: block.title ?? '',
|
title: block.title ?? '',
|
||||||
width: block.width ?? '',
|
width: block.width ?? '',
|
||||||
|
align: block.align ?? '',
|
||||||
padding: block.padding ?? {},
|
padding: block.padding ?? {},
|
||||||
});
|
});
|
||||||
const pending = JSON.stringify(draft);
|
const pending = JSON.stringify(draft);
|
||||||
@@ -166,6 +169,33 @@ export const BlockSettings = ({
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</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.
|
The block's own spacing, at the width the toggle above is showing.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user