mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
fix(cli): handle reverse-order CSS in applyResolutionPreset and document scope
This commit is contained in:
@@ -253,4 +253,61 @@ describe("applyResolutionPreset", () => {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("rewrites height-before-width inline CSS", () => {
|
||||
withFixture((dir) => {
|
||||
const file = join(dir, "index.html");
|
||||
// Reversed property order — same as the parser's stageMatchReverse path.
|
||||
const reversedOrderHtml = sampleHtml.replace(
|
||||
"html, body { margin: 0; width: 1920px; height: 1080px; overflow: hidden; }",
|
||||
"html, body { margin: 0; height: 1080px; width: 1920px; overflow: hidden; }",
|
||||
);
|
||||
writeFileSync(file, reversedOrderHtml, "utf-8");
|
||||
|
||||
applyResolutionPreset(dir, "landscape-4k");
|
||||
const out = readFileSync(file, "utf-8");
|
||||
|
||||
expect(out).toContain("height: 2160px");
|
||||
expect(out).toContain("width: 3840px");
|
||||
expect(out).not.toContain("1080px");
|
||||
expect(out).not.toContain("1920px");
|
||||
});
|
||||
});
|
||||
|
||||
it("is a no-op on a file with no dimension fingerprint (does not error)", () => {
|
||||
withFixture((dir) => {
|
||||
const file = join(dir, "fragment.html");
|
||||
// No data-width/height, no html/body block, no viewport — just markup.
|
||||
const minimal = "<!doctype html><html><head></head><body><p>hi</p></body></html>";
|
||||
writeFileSync(file, minimal, "utf-8");
|
||||
|
||||
expect(() => applyResolutionPreset(dir, "landscape-4k")).not.toThrow();
|
||||
const out = readFileSync(file, "utf-8");
|
||||
// The htmlOpenRe path adds `data-resolution="landscape-4k"` because
|
||||
// the <html> tag is present. That's correct: an explicit signal of
|
||||
// intended resolution survives even when no dim fields exist.
|
||||
expect(out).toContain('data-resolution="landscape-4k"');
|
||||
});
|
||||
});
|
||||
|
||||
it("accepts uppercase --resolution value (4K)", () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "hf-init-test-"));
|
||||
const target = join(dir, "proj");
|
||||
try {
|
||||
const res = runInit([
|
||||
target,
|
||||
"--example",
|
||||
"blank",
|
||||
"--resolution",
|
||||
"4K",
|
||||
"--non-interactive",
|
||||
"--skip-skills",
|
||||
]);
|
||||
expect(res.status).toBe(0);
|
||||
const html = readFileSync(join(target, "index.html"), "utf-8");
|
||||
expect(html).toContain('data-width="3840"');
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -451,15 +451,16 @@ async function handleVideoFile(
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Templates ship with 1920×1080 dimensions baked into multiple places.
|
||||
* When the user picks a non-default resolution we walk every HTML file in
|
||||
* the scaffold and rewrite the dimension fingerprint:
|
||||
* - `data-width` / `data-height` on the root composition
|
||||
* - `data-resolution` on the <html> element (added when missing)
|
||||
* - the `width`/`height` declared in the inline `html, body { ... }` CSS
|
||||
* - the `<meta name="viewport">` tag's `width=`/`height=` parts
|
||||
* We rewrite by regex rather than DOM-parsing because templates have
|
||||
* decorative comments and indentation we want to preserve byte-for-byte.
|
||||
* Rewrite the canvas dimensions in every scaffolded HTML file to match a
|
||||
* preset. We rewrite by regex rather than DOM-parsing so template comments
|
||||
* and indentation survive byte-for-byte — these are review-target files,
|
||||
* not transient build artifacts.
|
||||
*
|
||||
* Scope: HTML files only. Templates whose `#stage` dimensions live in an
|
||||
* external `.css` stylesheet are not patched — the bundled `blank` template
|
||||
* inlines its CSS, and that's the convention for new templates. If you
|
||||
* author a template with external CSS, replicate the dimension swap there
|
||||
* by hand or move the dimensions inline.
|
||||
*/
|
||||
export function applyResolutionPreset(destDir: string, resolution: CanvasResolution): void {
|
||||
const { width, height } = CANVAS_DIMENSIONS[resolution];
|
||||
@@ -494,11 +495,18 @@ export function applyResolutionPreset(destDir: string, resolution: CanvasResolut
|
||||
}
|
||||
}
|
||||
|
||||
// Inline `html, body { ... }` CSS: handle width-before-height and
|
||||
// height-before-width orderings. Hand-authored templates can use either.
|
||||
const bodyCssRe = /(html\s*,\s*body\s*\{[^}]*?width:\s*)\d+px([^}]*?height:\s*)\d+px/i;
|
||||
if (bodyCssRe.test(html)) {
|
||||
html = html.replace(bodyCssRe, `$1${width}px$2${height}px`);
|
||||
changed = true;
|
||||
}
|
||||
const bodyCssReverseRe = /(html\s*,\s*body\s*\{[^}]*?height:\s*)\d+px([^}]*?width:\s*)\d+px/i;
|
||||
if (bodyCssReverseRe.test(html)) {
|
||||
html = html.replace(bodyCssReverseRe, `$1${height}px$2${width}px`);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
const viewportRe = /(<meta[^>]*name=["']viewport["'][^>]*content=["'])width=\d+,\s*height=\d+/i;
|
||||
if (viewportRe.test(html)) {
|
||||
|
||||
Reference in New Issue
Block a user