the chrome stays inside the measure, and the view stays centred
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) <noreply@anthropic.com>
This commit is contained in:
@@ -235,10 +235,29 @@ export const SitePreview = ({
|
|||||||
*/
|
*/
|
||||||
const shownHeight = Math.max(0, available.height);
|
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<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const element = scroller.current;
|
||||||
|
if (!element) return;
|
||||||
|
element.scrollLeft = Math.max(0, (width - element.clientWidth) / 2);
|
||||||
|
}, [width, available.width, loaded]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="flex min-h-0 flex-1 flex-col gap-2">
|
<section className="flex min-h-0 flex-1 flex-col gap-2">
|
||||||
<div ref={box} className="min-h-0 flex-1">
|
<div ref={box} className="min-h-0 flex-1">
|
||||||
<div
|
<div
|
||||||
|
ref={scroller}
|
||||||
// `overflow-auto`, not hidden: at Desktop in a narrow panel the frame is wider than the room,
|
// `overflow-auto`, not hidden: at Desktop in a narrow panel the frame is wider than the room,
|
||||||
// and scrolling to the rest of it is the honest answer where scaling was not.
|
// and scrolling to the rest of it is the honest answer where scaling was not.
|
||||||
className="mx-auto overflow-auto rounded-lg border border-border bg-white"
|
className="mx-auto overflow-auto rounded-lg border border-border bg-white"
|
||||||
|
|||||||
+18
-3
@@ -114,7 +114,10 @@ export function paintCanvas(document: Document, canvas: Canvas): () => void {
|
|||||||
// `relative` so the label and the controls can be placed against this band rather than the page.
|
// `relative` so the label and the controls can be placed against this band rather than the page.
|
||||||
element.style.position = 'relative';
|
element.style.position = 'relative';
|
||||||
element.style.outline = `1px solid ${ACCENT}`;
|
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.
|
// Room for the outline and the label above it, so two bands in a row do not touch.
|
||||||
element.style.margin = '2.5rem 0';
|
element.style.margin = '2.5rem 0';
|
||||||
|
|
||||||
@@ -182,7 +185,7 @@ export function paintCanvas(document: Document, canvas: Canvas): () => void {
|
|||||||
const was = column.style.outline;
|
const was = column.style.outline;
|
||||||
const wasOffset = column.style.outlineOffset;
|
const wasOffset = column.style.outlineOffset;
|
||||||
column.style.outline = `1px dashed color-mix(in srgb, ${ACCENT} 45%, transparent)`;
|
column.style.outline = `1px dashed color-mix(in srgb, ${ACCENT} 45%, transparent)`;
|
||||||
column.style.outlineOffset = '-4px';
|
column.style.outlineOffset = '-5px';
|
||||||
undo.push(() => {
|
undo.push(() => {
|
||||||
column.style.outline = was;
|
column.style.outline = was;
|
||||||
column.style.outlineOffset = wasOffset;
|
column.style.outlineOffset = wasOffset;
|
||||||
@@ -264,6 +267,18 @@ export function paintCanvas(document: Document, canvas: Canvas): () => void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── Add section, always last ─────────────────────────────────────────────────────────────────
|
// ── 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<HTMLElement>('[data-content-column]') ?? root;
|
||||||
|
|
||||||
const zone = document.createElement('div');
|
const zone = document.createElement('div');
|
||||||
zone.setAttribute(MARK, 'add-section');
|
zone.setAttribute(MARK, 'add-section');
|
||||||
style(zone, [
|
style(zone, [
|
||||||
@@ -295,7 +310,7 @@ export function paintCanvas(document: Document, canvas: Canvas): () => void {
|
|||||||
button.addEventListener('click', canvas.onAddSection);
|
button.addEventListener('click', canvas.onAddSection);
|
||||||
|
|
||||||
zone.append(button);
|
zone.append(button);
|
||||||
root.append(zone);
|
zoneParent.append(zone);
|
||||||
undo.push(() => {
|
undo.push(() => {
|
||||||
button.removeEventListener('click', canvas.onAddSection);
|
button.removeEventListener('click', canvas.onAddSection);
|
||||||
zone.remove();
|
zone.remove();
|
||||||
|
|||||||
Reference in New Issue
Block a user