mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-10-22 18:13:27 +00:00
🩹 fix: PPTX preview fills panel height (no white gap below slides)
Manual e2e on PR #12934: PPTX preview filled the panel width but left empty space below the last slide. DOCX didn't have this issue because its content (mammoth-rendered HTML) flows naturally and either fits exactly or overflows; PPTX slides are fixed-aspect 16:9 and don't grow with the panel. Two changes: 1. **Body fills the iframe viewport** — `html, body { min-height: 100vh }` plus `body { display: flex; flex-direction: column }` and `#lc-render { flex: 1 0 auto }`. The dark theme bg now fills the iframe even when total slide content is shorter than the panel, so a single-slide deck never reveals a "white below" gap. 2. **Per-slide scale honors viewport height** — `scaleFor(nativeW, nativeH)` now returns `min(width-fit, height-fit)` (largest factor that fits without overflowing either dimension). On a tall artifact panel with a short deck, slides grow up to the full panel height instead of staying at the width-bound size. Existing height-fit was always considered correct conceptually but the previous implementation only used width-fit, leaving half the viewport unused per slide. Tests: regression now also asserts `availableHeight()`, the `Math.min(sw, sh)` formula, and `min-height: 100vh` are in the bootstrap. Negative assertion for the old `Math.min(1, ...)` upscale cap remains.
This commit is contained in:
parent
4e2d538b03
commit
355dce7820
2 changed files with 47 additions and 19 deletions
|
|
@ -478,22 +478,27 @@ describe('Office HTML producers', () => {
|
|||
/* The wrapper class used by the CSS rules. */
|
||||
expect(html).toContain('lc-slide-wrap');
|
||||
/* The wrap function + the per-slide scale function. The scale
|
||||
* uses each slide's actual rendered native width (not a
|
||||
* constant) so panels wider than 960px still fill — no
|
||||
* upscale cap means we never leave whitespace on the sides
|
||||
* of the panel. */
|
||||
* uses each slide's actual rendered native width AND height
|
||||
* so panels of any aspect fill correctly — no upscale cap
|
||||
* means we never leave whitespace on either axis. */
|
||||
expect(html).toContain('wrapSlides');
|
||||
expect(html).toContain('scaleFor');
|
||||
expect(html).toContain('availableWidth');
|
||||
/* The scale formula divides available width by the slides
|
||||
* rendered native width — this is the line that ensures full
|
||||
* panel coverage. */
|
||||
expect(html).toContain('availableWidth() / (nativeW || SLIDE_W)');
|
||||
expect(html).toContain('availableHeight');
|
||||
/* The scale is `min(width-fit, height-fit)` so each slide is
|
||||
* the largest it can be in the iframe viewport without
|
||||
* overflowing either dimension — manual e2e feedback on
|
||||
* PR #12934. */
|
||||
expect(html).toContain('Math.min(sw, sh)');
|
||||
/* Negative assertion: the previous version capped the scale
|
||||
* at 1.0 with `Math.min(1, ...)`, which left whitespace on
|
||||
* panels wider than 960px. The new code must not reintroduce
|
||||
* that cap. */
|
||||
expect(html).not.toContain('Math.min(1');
|
||||
expect(html).not.toMatch(/Math\.min\(\s*1\s*,/);
|
||||
/* Body fills the iframe viewport vertically and inherits the
|
||||
* dark bg so a short deck (single slide) never reveals a
|
||||
* "white below" gap below the slides. */
|
||||
expect(html).toContain('min-height: 100vh');
|
||||
/* Container is hidden during render and revealed by the
|
||||
* `finalize` step so the unscaled flash never reaches the
|
||||
* user. */
|
||||
|
|
|
|||
|
|
@ -1073,7 +1073,14 @@ function buildPptxCdnDocument(base64: string): string {
|
|||
:root { color-scheme: light dark; --bg: #ffffff; --fg: #1f2937; --muted: #6b7280; }
|
||||
@media (prefers-color-scheme: dark) { :root { --bg: #1a1a2e; --fg: #e5e7eb; --muted: #9ca3af; } }
|
||||
html, body { margin: 0; padding: 0; background: var(--bg); color: var(--fg); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
|
||||
#lc-render { padding: 16px; box-sizing: border-box; display: flex; flex-direction: column; align-items: center; gap: 16px; }
|
||||
/* Body fills the iframe viewport vertically and inherits the dark bg
|
||||
* so even when total slide content is shorter than the panel (e.g. a
|
||||
* single-slide deck) the artifact card has no visible "white below"
|
||||
* gap — DOCX flows naturally and never has this issue, but PPTX
|
||||
* slides are fixed-aspect and don't grow with the panel. */
|
||||
html, body { min-height: 100vh; }
|
||||
body { display: flex; flex-direction: column; }
|
||||
#lc-render { padding: 16px; box-sizing: border-box; display: flex; flex-direction: column; align-items: center; gap: 16px; flex: 1 0 auto; }
|
||||
/* Each rendered slide is wrapped post-hoc by the bootstrap script in
|
||||
* an .lc-slide-wrap div with explicit width/height set inline. The
|
||||
* inner slide keeps its native pixel size and gets transformed via
|
||||
|
|
@ -1168,14 +1175,30 @@ html, body { margin: 0; padding: 0; background: var(--bg); color: var(--fg); fon
|
|||
var w = (container.clientWidth || window.innerWidth) - 32;
|
||||
return w > 0 ? w : 600;
|
||||
}
|
||||
function availableHeight() {
|
||||
/* Viewport height inside the iframe minus the same 16px top+
|
||||
* bottom padding so a single-slide deck can grow up to the full
|
||||
* panel height without spilling. */
|
||||
var h = (window.innerHeight || document.documentElement.clientHeight || 0) - 32;
|
||||
return h > 0 ? h : 400;
|
||||
}
|
||||
|
||||
/* Per-slide scale: divides each slides actual rendered native
|
||||
* width into the panel width, so we always fill the panel. No
|
||||
* upscale cap — pptx-preview always rasterizes against the init
|
||||
* canvas (960×540 here), so text/charts inside the slide are
|
||||
* vector or canvas-rendered and stay legible when scaled up. */
|
||||
function scaleFor(nativeW) {
|
||||
return availableWidth() / (nativeW || SLIDE_W);
|
||||
/* Per-slide scale: the largest factor that lets the slide fit in
|
||||
* the iframe viewport without overflowing either dimension. No
|
||||
* upscale cap — pptx-preview rasterizes against the init canvas
|
||||
* (960×540), text/charts are vector or canvas-rendered, so they
|
||||
* stay legible when scaled up.
|
||||
*
|
||||
* Why the height-aware version (vs. width-only): a tall artifact
|
||||
* panel with a short deck would otherwise leave the slide at
|
||||
* panel_w × (panel_w·9/16) and waste the rest of the viewport
|
||||
* vertically. Min-of-fits makes the slide grow until ONE
|
||||
* dimension is the constraint, exactly the contain-fit pattern
|
||||
* the rest of the iframe expects. */
|
||||
function scaleFor(nativeW, nativeH) {
|
||||
var sw = availableWidth() / (nativeW || SLIDE_W);
|
||||
var sh = availableHeight() / (nativeH || SLIDE_H);
|
||||
return Math.min(sw, sh);
|
||||
}
|
||||
|
||||
/* Wrap each rendered slide and apply the scale. Called ONCE,
|
||||
|
|
@ -1199,7 +1222,7 @@ html, body { margin: 0; padding: 0; background: var(--bg); color: var(--fg); fon
|
|||
slide.dataset.lcNativeW = String(nativeW);
|
||||
slide.dataset.lcNativeH = String(nativeH);
|
||||
}
|
||||
var scale = scaleFor(nativeW);
|
||||
var scale = scaleFor(nativeW, nativeH);
|
||||
var wrap = document.createElement('div');
|
||||
wrap.className = 'lc-slide-wrap';
|
||||
wrap.style.width = (nativeW * scale) + 'px';
|
||||
|
|
@ -1222,7 +1245,7 @@ html, body { margin: 0; padding: 0; background: var(--bg); color: var(--fg); fon
|
|||
if (!inner || !inner.dataset) { continue; }
|
||||
var nativeW = parseFloat(inner.dataset.lcNativeW) || SLIDE_W;
|
||||
var nativeH = parseFloat(inner.dataset.lcNativeH) || SLIDE_H;
|
||||
var scale = scaleFor(nativeW);
|
||||
var scale = scaleFor(nativeW, nativeH);
|
||||
wrap.style.width = (nativeW * scale) + 'px';
|
||||
wrap.style.height = (nativeH * scale) + 'px';
|
||||
inner.style.transform = 'scale(' + scale + ')';
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue