fix(desktop): preserve artifact dark theme in iframe#77
Conversation
There was a problem hiding this comment.
Findings
-
[Major] Baseline style injection misses valid
<body>documents without<html>/<head>— after switching iframe background to transparent, these artifacts will not receive the fallback background, causing inconsistent preview surfaces. Evidence:packages/runtime/src/index.ts:31
Suggested fix:const withBaseline = /<head[^>]*>/i.test(stripped) ? stripped.replace(/<head[^>]*>/i, (match) => `${match}${BASELINE_STYLE}`) : /<html[^>]*>/i.test(stripped) ? stripped.replace(/<html[^>]*>/i, (match) => `${match}<head>${BASELINE_STYLE}</head>`) : stripped.replace(/<body[^>]*>/i, (match) => `<head>${BASELINE_STYLE}</head>${match}`);
-
[Minor] Hardcoded color violates the UI token constraint —
#ffffffis newly introduced in runtime preview styling, which conflicts with the “UI values viapackages/uitokens” rule. Evidence:packages/runtime/src/index.ts:15
Suggested fix:const BASELINE_STYLE = '<style>html,body{margin:0;padding:0;background:var(--color-artifact-bg);min-height:100%;}</style>';
Summary
- Review mode: initial
- 2 issues found in changed lines: one preview correctness regression path and one hard-constraint violation.
docs/VISION.mdanddocs/PRINCIPLES.md: Not found in repo/docs.
Testing
- Not run (automation):
pnpmis unavailable in this runner, so Vitest/Playwright could not be executed here.
open-codesign Bot
| return stripped.replace( | ||
| const withBaseline = /<head[^>]*>/i.test(stripped) | ||
| ? stripped.replace(/<head[^>]*>/i, (match) => `${match}${BASELINE_STYLE}`) | ||
| : stripped.replace(/<html[^>]*>/i, (match) => `${match}<head>${BASELINE_STYLE}</head>`); |
There was a problem hiding this comment.
</body>-based input can still be missing both <head> and <html>. In that case this branch currently injects nothing, so the new baseline is skipped. Consider adding a <body> fallback branch so transparent iframe mode stays deterministic.
| * artifact wins via cascade order. | ||
| */ | ||
| const BASELINE_STYLE = | ||
| '<style>html,body{margin:0;padding:0;background:#ffffff;min-height:100%;}</style>'; |
There was a problem hiding this comment.
This introduces a hardcoded color (#ffffff). Project constraints require UI values to come from tokens; please switch to a tokenized CSS variable here.
There was a problem hiding this comment.
Findings
-
[Major] Hardcoded color token bypass in runtime baseline style — this introduces a new raw
#ffffff, violating the project constraint that UI values must come from shared tokens and risking token drift across themes. Evidence:packages/runtime/src/index.ts:15
Suggested fix:const BASELINE_STYLE = '<style>html,body{margin:0;padding:0;background:var(--color-artifact-bg, #ffffff);min-height:100%;}</style>';
-
[Blocker] Missing DCO sign-off in new commits — repository policy requires
Signed-off-byon commits, and the current PR commits do not include it (checked commit messages at head).
Suggested fix:git commit --amend -s # repeat for each unsigned commit (or rebase -i with reword) git push --force-with-lease
Summary
- Review mode: follow-up after new commits
- 2 issues remain: 1 code-level hard-constraint violation in changed lines and 1 PR-level policy blocker (DCO).
docs/VISION.mdanddocs/PRINCIPLES.md: Not found in repo/docs.
Testing
- Not run (automation)
open-codesign Bot
| * artifact wins via cascade order. | ||
| */ | ||
| const BASELINE_STYLE = | ||
| '<style>html,body{margin:0;padding:0;background:#ffffff;min-height:100%;}</style>'; |
There was a problem hiding this comment.
Hardcoded #ffffff violates the project token constraint and can drift from themed surfaces. Please use a tokenized value (for example var(--color-artifact-bg, #ffffff)) in BASELINE_STYLE.
The BASELINE_STYLE injected into the preview iframe used a hardcoded #ffffff, which violates the project rule that UI values must come from shared design tokens. Switch to var(--color-artifact-bg, #ffffff) so the canonical token in packages/ui is the source of truth, with #ffffff retained as a safe fallback for sandboxed iframes that don't inherit the parent's CSS vars. Codex review feedback on PR #77.
91c7f78 to
81177fa
Compare
|
Addressed Codex [Major] finding on |
There was a problem hiding this comment.
Findings
-
[Major] Malformed
bodyreconstruction when input has</body>but no<body>opener — this branch wraps the original HTML inside a new<body>...</body>without removing the existing closing tag, yielding invalid structure and potentially placing the overlay script outside the intended body parsing flow. Evidence:packages/runtime/src/index.ts:47,packages/runtime/src/index.ts:49
Suggested fix:} else { const bodyContent = stripped.replace(/<\/body\s*>/gi, ''); withBaseline = `<!doctype html><html><head>${BASELINE_STYLE}</head><body>${bodyContent}</body></html>`; }
-
[Blocker] Missing DCO sign-off in new commits — hard constraint requires
Signed-off-byon each commit, and the new commits at1bd8c6197d87ebe40a0cefabb039d0854899e195,433521938d2a61dd7971ae8b82d101bb4c4a5b6f, and81177faa8ce82e7f9afb65eee98f3c16fdde97d6do not include it.
Suggested fix:git rebase -i --signoff 91c7f78cb5adf13c1f5abab982d5820f4115b1a8 git push --force-with-lease
Summary
- Review mode: follow-up after new commits
- 2 issues found: 1 code-level correctness risk in new
buildSrcdocbranch and 1 PR policy blocker (DCO). docs/VISION.mdanddocs/PRINCIPLES.md: Not found in repo/docs.
Testing
- Not run (automation)
open-codesign Bot
| (match) => `<html><head>${BASELINE_STYLE}</head>${match}`, | ||
| )}</html>`; | ||
| } else { | ||
| withBaseline = `<!doctype html><html><head>${BASELINE_STYLE}</head><body>${stripped}</body></html>`; |
There was a problem hiding this comment.
Wrapping the entire stripped payload here can produce </body></body> when input has an orphan closing body tag. That creates malformed structure and can move the injected overlay script outside the intended body context. Consider stripping orphan </body> tags before wrapping.
The BASELINE_STYLE injected into the preview iframe used a hardcoded #ffffff, which violates the project rule that UI values must come from shared design tokens. Switch to var(--color-artifact-bg, #ffffff) so the canonical token in packages/ui is the source of truth, with #ffffff retained as a safe fallback for sandboxed iframes that don't inherit the parent's CSS vars. Codex review feedback on PR #77.
81177fa to
f7035f6
Compare
|
Addressed Codex [Major] on malformed body reconstruction. Refactored
Added 5 new unit tests under Commit: f7035f6 |
There was a problem hiding this comment.
Findings
-
[Blocker] Missing DCO
Signed-off-byin new commits — repository hard constraints require DCO sign-off, but the commits in this PR head (b23c9a756501f6dd07fb5041120fb6e34bd1a431,7f28ffb088d80b4a69f9af87f4f42c06abbd1632,52f346a0ae8435679a564fdc37928b1e0aeb2cbb,f7035f651d2ef5656b130e36df77fd54413e42ea) do not includeSigned-off-bytrailers.
Suggested fix:git rebase -i --signoff <base-before-these-commits> git push --force-with-lease
-
[Major]
normalizeBodyTagsappends</body>after</html>for several malformed shapes, producing crossed tags and risking overlay/script injection outside the intended body context, evidencepackages/runtime/src/index.ts:37,packages/runtime/src/index.ts:52,packages/runtime/src/index.ts:55.
Suggested fix:function closeBody(html: string): string { return /<\/html\s*>/i.test(html) ? html.replace(/<\/html\s*>/i, '</body></html>') : `${html}</body>`; } if (hasOpen && !hasClose) return closeBody(html); if (!hasOpen && !hasClose) { if (HEAD_CLOSE_RE.test(html)) return closeBody(html.replace(HEAD_CLOSE_RE, (m) => `${m}<body>`)); if (HTML_RE.test(html)) return closeBody(html.replace(HTML_RE, (m) => `${m}<body>`)); return `<body>${html}</body>`; }
Summary
- Review mode: follow-up after new commits
- 2 issues found (1 blocker policy issue, 1 major correctness issue).
docs/VISION.mdanddocs/PRINCIPLES.md: Not found in repo/docs.
Testing
- Not run (automation):
pnpmis unavailable in this runner environment.
open-codesign Bot
| if (hasOpen && hasClose) return html; | ||
|
|
||
| if (hasOpen && !hasClose) { | ||
| return `${html}</body>`; |
There was a problem hiding this comment.
When <body> is opened but missing its closer, this branch appends </body> at EOF. If input already ends with </html>, output becomes ...</html></body> (crossed tags). Please insert the closer before </html> when present, otherwise append at EOF.
When a model produced a dark-theme artifact, the iframe's outer white
artifact-bg token bled through any artifact whose body background was
unset, making dark dashboards look washed out. Make the iframe element
transparent and inject a low-specificity baseline white html/body
background inside the srcdoc so artifacts that explicitly set a dark
body { background } now win via cascade order.
…docs buildSrcdoc previously only synthesised a <head> when the artifact had an <html> wrapper. A valid document containing only <body>...</body> (or a fragment with </body> but no <html>) silently skipped baseline injection, because the regex replace on <html> matched nothing. Handle four document shapes explicitly: - has <head>: inject inside head (unchanged) - has <html> but no <head>: synth <head> after <html> (unchanged) - has <body> but no <html>: wrap with <html><head>...</head> + close </html> - has </body> but no <body> opener: rebuild as full doctype document Add vitest cases for body-only docs, plain fragments, and full docs with <head> to lock the four branches in.
The BASELINE_STYLE injected into the preview iframe used a hardcoded #ffffff, which violates the project rule that UI values must come from shared design tokens. Switch to var(--color-artifact-bg, #ffffff) so the canonical token in packages/ui is the source of truth, with #ffffff retained as a safe fallback for sandboxed iframes that don't inherit the parent's CSS vars. Codex review feedback on PR #77.
Codex flagged a malformed reconstruction when input had </body> but no <body>: the prior cascade fell through to the bare-fragment branch, wrapping content that already ended with </body> inside another <body>...</body>, producing nested/crossed tags. Refactor into a single normalizeBodyTags step that explicitly handles all four shapes (both, opener-only, closer-only, neither), then runs baseline + overlay injection on the normalized document. Adds unit tests for each shape.
f7035f6 to
3f48024
Compare
|
Addressed Codex [Major] on New tests cover:
Commit: 3f48024. All 17 runtime tests pass. Also rebased onto latest origin/main. |
There was a problem hiding this comment.
Findings
- [Blocker] Missing DCO
Signed-off-bytrailer on the new follow-up commit — CI/policy requires DCO for every commit, and the latest head commit3f48024ef0f9d57a7b1fbacad16de18c78e84f11does not include aSigned-off-by:trailer in its commit message metadata.
Suggested fix:git commit --amend --signoff git push --force-with-lease
Summary
- Review mode: follow-up after new commits
- 1 issue found (policy blocker).
docs/VISION.mdanddocs/PRINCIPLES.md: Not found in repo/docs.
Testing
- Not run (automation)
open-codesign Bot
Summary
bg-transparent+buildSrcdoc注入 low-specificity baseline whitehtml, body { background },artifact 自己的 body bg 通过 cascade order 胜出。Root cause
PreviewPane给 iframe 元素设了bg-[var(--color-artifact-bg)](白)。当 artifact body 没有显式 background 时,iframe body 透明 → iframe 元素 bg 显示。Dark artifacts 通常只把 bg 设在内层容器(如bg-gray-900),body 仍透明,于是看起来浅。Fix
packages/runtime/src/index.ts— 在 srcdoc head 最前面注入 baseline<style>html,body{background:#ffffff;...}</style>,artifact 自己的 body bg 依然是 last-wins。apps/desktop/src/renderer/src/components/PreviewPane.tsx— iframe className 由bg-[var(--color-artifact-bg)]改为bg-transparent,让内部 body bg 决定可见颜色。Compat / upgradeability / no bloat / elegance
buildSrcdoc仍是唯一 srcdoc 装配处。Test plan
pnpm --filter @open-codesign/runtime exec vitest run(6 passed)pnpm typecheck(clean)