commit 462936e5181377f3b3adc08bdc5fa10cdee0da02
parent a1c047cc6472e8d93051c8aebe6f9cc016e583f3
Author: Hunter
Date:   Mon,  2 Feb 2026 23:40:31 -0500

align zine to grid

Diffstat:
Mresources/editor.css | 14+++++++++++++-
Mresources/editor.js | 20++++++++++++++++++++
Mresources/spread-layout.js | 23+++++++++++++++++++++++
3 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/resources/editor.css b/resources/editor.css @@ -40,7 +40,19 @@ body { height: 100%; display: flex; flex-direction: column; - background: linear-gradient(to top, #252525, #3a3a3a); + --grid-width: 33px; + --grid-height: 33px; + --spread-left: 0px; + --spread-top: 0px; + background: + linear-gradient(to right, #4a7a6a 1px, transparent 1px), + linear-gradient(to bottom, #4a7a6a 1px, transparent 1px), + linear-gradient(to bottom, #1a4d3a, #184534); + background-size: var(--grid-width) var(--grid-height), var(--grid-width) var(--grid-height), 100% 100%; + background-position: + calc(var(--spread-left) + var(--grid-width) / 2) var(--spread-top), + calc(var(--spread-left) + var(--grid-width) / 2) var(--spread-top), + 0 0; } .preview-pane.fullscreen { diff --git a/resources/editor.js b/resources/editor.js @@ -31,6 +31,26 @@ window.addEventListener('message', function(event) { window.saveFile(); } else if (event.data === 'saveFileWithViewer') { window.saveFileWithViewer(); + } else if (event.data?.type === 'scaleChange') { + // Update background grid size and position to match zine preview + const previewPane = document.querySelector('.preview-pane'); + const preview = document.querySelector('#preview'); + if (previewPane && preview) { + // Get iframe position relative to preview pane + const iframeRect = preview.getBoundingClientRect(); + const paneRect = previewPane.getBoundingClientRect(); + const iframeOffsetX = iframeRect.left - paneRect.left; + const iframeOffsetY = iframeRect.top - paneRect.top; + + // Spread position in pane coordinates + const spreadLeft = iframeOffsetX + event.data.spreadLeft; + const spreadTop = iframeOffsetY + event.data.spreadTop; + + previewPane.style.setProperty('--grid-width', `${event.data.gridWidth}px`); + previewPane.style.setProperty('--grid-height', `${event.data.gridHeight}px`); + previewPane.style.setProperty('--spread-left', `${spreadLeft}px`); + previewPane.style.setProperty('--spread-top', `${spreadTop}px`); + } } }); diff --git a/resources/spread-layout.js b/resources/spread-layout.js @@ -79,4 +79,27 @@ export function scaleSpreadToFit(container, doc, bottomPadding = 0) { const translateX = translateMatch ? translateMatch[0] : ''; bookContainer.style.transform = translateX ? `scale(${scale}) ${translateX}` : `scale(${scale})`; + + // Notify parent of spread position and grid size for background grid + if (doc.defaultView?.parent && doc.defaultView.parent !== doc.defaultView) { + const rect = bookContainer.getBoundingClientRect(); + + // Derive grid from height (always 1 page tall = 11 cells) + // Cell aspect ratio: (2.75/7) / (4.25/11) = 30.25/29.75 + const gridHeight = rect.height / 11; + const gridWidth = gridHeight * (30.25 / 29.75); + + // Remove translateX shift so grid always anchors to the un-shifted book position + // The translateX is in inches and gets multiplied by scale + const translateInchMatch = translateX.match(/translateX\(([^)]+)in\)/); + const translatePx = translateInchMatch ? parseFloat(translateInchMatch[1]) * 96 * scale : 0; + + doc.defaultView.parent.postMessage({ + type: 'scaleChange', + gridWidth, + gridHeight, + spreadLeft: rect.left - translatePx, + spreadTop: rect.top + }, '*'); + } }