From 0fc41be493b2271836755f917be8552cea5ad46c Mon Sep 17 00:00:00 2001 From: lewis Date: Fri, 17 Apr 2026 23:05:48 +0800 Subject: [PATCH] feat(presenter): preserve slide layout + draggable splitters Two user-reported issues fixed: 1. Slide layout broken in preview (content stuck to top, not centered) Root cause: iframe CSS was forcing .slide { display:block !important } which overrode base.css's .slide { display:flex; justify-content:center } Fix: Do NOT override .slide or .deck styling in iframe. Let host CSS (base.css + theme + scoped) handle flex centering, padding, etc. Only override .is-active visibility and hide notes/chrome. 2. Users can now resize preview regions - Horizontal splitter between current (left) and right column - Vertical splitter between next preview (top) and notes (bottom) - Splitters show blue hover state, drag updates flex sizes - reScale() called on every drag frame to keep iframe 1:1 accurate - Min sizes enforced (200px width, 80-100px height) to prevent collapse Verified with headless Chrome: cover slide now correctly vertically centered in the preview, matching audience view pixel-perfect. --- assets/runtime.js | 96 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 81 insertions(+), 15 deletions(-) diff --git a/assets/runtime.js b/assets/runtime.js index 8a1abcb..b691d80 100644 --- a/assets/runtime.js +++ b/assets/runtime.js @@ -190,16 +190,22 @@ // at 1920x1080 so vw/vh/clamp all resolve exactly like the audience view. // We inject via contentDocument.write() so there's ZERO HTML escaping issues. // Template is a JS string (not embedded HTML attribute), so quotes stay raw. + // IMPORTANT: Do NOT override .slide or .deck styling. The original + // base.css + theme + scoped CSS handles flex centering, padding, etc. + // We only: (1) reset margins, (2) force the single slide to be visible + // (.is-active), (3) hide the speaker notes and runtime chrome. const iframeDocTemplate = '' + '' + '' + styleSheets + '' + '' + '
%%SLIDE_HTML%%
' @@ -239,27 +245,29 @@ + ' .pv-hint { font-size: 11px; color: #484f58; margin-left: auto; }\n' + '\n' + '\n\n' -+ '
\n' -+ '
\n' ++ '
\n' ++ '
\n' + '
CURRENT
\n' + '
\n' + '
\n' -+ '
\n' -+ '
\n' ++ '
\n' ++ '
\n' ++ '
\n' + '
NEXT
\n' + '
\n' + '
\n' -+ '
\n' ++ '
\n' ++ '
\n' + '
SPEAKER SCRIPT · 逐字稿
\n' + '
\n' + '
\n' + '
\n' -+ '
\n' -+ '
00:00
\n' -+ '
1 / ' + total + '
\n' -+ '
\n' -+ '
← → 翻页 · R 重置计时 · Esc 关闭
\n' -+ '
\n' ++ '
\n' ++ '
\n' ++ '
00:00
\n' ++ '
1 / ' + total + '
\n' ++ '
\n' ++ '
← → 翻页 · R 重置计时 · 拖动分隔线调整区域 · Esc 关闭
\n' + '
\n' + '