From fb651f06e24a08f8fc3861eb8a03222f9e923eee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Mon, 31 Aug 2026 04:26:02 +0100 Subject: [PATCH] the chrome stays inside the measure, and the view stays centred MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two things the guides made visible the moment they existed. THE SKELETON CROSSED THE LINES. Add section was appended to `main`, which is the full width of the page — the content column is what holds it to its measure. So the drop zone ran edge to edge and straight past the guides, describing a place a section could go that no section will ever occupy. It goes in the column now, falling back to main for a page that opts out of the measure, where the column genuinely is the page. The section outline had the same fault in miniature: `outline-offset: 4px` puts it OUTSIDE the element, so a band filling the column drew its edges past the guides. Inset now. Editor chrome that overflows the thing it describes is chrome that lies about it. THE VIEW WAS LEFT-ANCHORED. Narrowing the panel showed the left margin and the start of the content — the least informative part of a centred layout and never the part anybody is looking at. The scroller now starts in the middle, because the page is centred on a real screen and the preview should be too. On the scroller, not a transform. A transform is the scaling this just stopped doing. Co-Authored-By: Claude Opus 5 (1M context) --- web/SitePreview.tsx | 19 +++++++++++++++++++ web/canvas.ts | 21 ++++++++++++++++++--- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/web/SitePreview.tsx b/web/SitePreview.tsx index 744b809..f2c4949 100644 --- a/web/SitePreview.tsx +++ b/web/SitePreview.tsx @@ -235,10 +235,29 @@ export const SitePreview = ({ */ const shownHeight = Math.max(0, available.height); + /* + When the frame is wider than the room, show its MIDDLE. + + Left-anchored, a narrow panel showed the left margin and the start of the content — the least + informative part of a centred layout, and never the part anybody is looking at. The page is centred + on a real screen, so the preview should be centred too; the scrollbar is still there for the rest. + + Set on the scroller rather than with a transform, because a transform is the scaling this just + stopped doing. + */ + const scroller = useRef(null); + + useEffect(() => { + const element = scroller.current; + if (!element) return; + element.scrollLeft = Math.max(0, (width - element.clientWidth) / 2); + }, [width, available.width, loaded]); + return (
void { // `relative` so the label and the controls can be placed against this band rather than the page. element.style.position = 'relative'; element.style.outline = `1px solid ${ACCENT}`; - element.style.outlineOffset = '4px'; + // INSET. At `4px` the outline sat outside the element, so a band that fills the content column drew + // its edges past the measure — the guides said the column ended and the skeleton crossed them. + // Editor chrome that overflows the thing it is describing is chrome that lies about it. + element.style.outlineOffset = '-1px'; // Room for the outline and the label above it, so two bands in a row do not touch. element.style.margin = '2.5rem 0'; @@ -182,7 +185,7 @@ export function paintCanvas(document: Document, canvas: Canvas): () => void { const was = column.style.outline; const wasOffset = column.style.outlineOffset; column.style.outline = `1px dashed color-mix(in srgb, ${ACCENT} 45%, transparent)`; - column.style.outlineOffset = '-4px'; + column.style.outlineOffset = '-5px'; undo.push(() => { column.style.outline = was; column.style.outlineOffset = wasOffset; @@ -264,6 +267,18 @@ export function paintCanvas(document: Document, canvas: Canvas): () => void { } // ── Add section, always last ───────────────────────────────────────────────────────────────── + /* + Add section goes inside the CONTENT COLUMN, not `main`. + + `main` is the full width of the page; the column is what holds it to its measure. Appended to main, + the drop zone ran edge to edge and straight past the guides — describing a place a section could go + that no section will ever occupy. + + Falls back to `main` for a page that opts out of the measure (`full` in Layout), where the column + genuinely is the page. + */ + const zoneParent = root.querySelector('[data-content-column]') ?? root; + const zone = document.createElement('div'); zone.setAttribute(MARK, 'add-section'); style(zone, [ @@ -295,7 +310,7 @@ export function paintCanvas(document: Document, canvas: Canvas): () => void { button.addEventListener('click', canvas.onAddSection); zone.append(button); - root.append(zone); + zoneParent.append(zone); undo.push(() => { button.removeEventListener('click', canvas.onAddSection); zone.remove();