diff --git a/apps/codex-plus-manager/src/dream-skin.test.ts b/apps/codex-plus-manager/src/dream-skin.test.ts index 32c119cf7..6fd0195cf 100644 --- a/apps/codex-plus-manager/src/dream-skin.test.ts +++ b/apps/codex-plus-manager/src/dream-skin.test.ts @@ -147,6 +147,24 @@ describe("dream skin theme helpers", () => { assert.match(css, /\[data-codex-terminal="true"\]/); }); + it("keeps transient new-chat drafts on native geometry", async () => { + const renderer = await readFile( + new URL("../../../assets/inject/upstream/dream-skin/windows/renderer-inject.js", import.meta.url), + "utf8", + ); + const css = await readFile( + new URL("../../../assets/inject/upstream/dream-skin/windows/dream-skin.css", import.meta.url), + "utf8", + ); + + assert.match(renderer, /homeHasClassicChrome/); + assert.match(renderer, /data-dream-home-layout/); + assert.match(renderer, /data-dream-home-layout.*soft/); + assert.match(css, /data-dream-home-layout.*structured/); + assert.match(css, /overflow-y: auto !important/); + assert.match(css, /\.composer-surface-chrome/); + }); + it("exposes companion image controls in the theme editor", async () => { const app = await readFile(new URL("./App.tsx", import.meta.url), "utf8"); diff --git a/assets/inject/renderer-inject.js b/assets/inject/renderer-inject.js index fda3287e9..3e7287497 100644 --- a/assets/inject/renderer-inject.js +++ b/assets/inject/renderer-inject.js @@ -1943,21 +1943,45 @@ ensureDreamSkinCompanion(theme); const homeIndicator = document.querySelector('[data-testid="home-icon"]'); - const home = homeIndicator?.closest('[role="main"]') + const homeCandidate = homeIndicator?.closest('[role="main"]') || [...document.querySelectorAll('[role="main"]')].find((candidate) => candidate.querySelector('[data-feature="game-source"]') && candidate.querySelector('.group\\/home-suggestions')) || null; + const homeHasClassicChrome = !!( + homeCandidate + && homeCandidate.querySelector('[data-feature="game-source"]') + && ( + homeCandidate.querySelector('.group\\/home-suggestions') + || homeCandidate.querySelector('[class*="home-suggestions"]') + || homeCandidate.querySelector('[class*="_homeUtilityBar_"]') + ) + ); + const home = homeHasClassicChrome ? homeCandidate : null; for (const candidate of document.querySelectorAll(`[role="main"].${descriptor.homeClass}`)) { - if (candidate !== home) candidate.classList.remove(descriptor.homeClass); + if (candidate !== home && candidate !== homeCandidate) candidate.classList.remove(descriptor.homeClass); } if (home) home.classList.add(descriptor.homeClass); + else if (homeCandidate && descriptor.homeClass) { + // Soft home: keep mild class for tinting, avoid structural shell when possible. + homeCandidate.classList.add(descriptor.homeClass); + } if (descriptor.taskClass) { for (const candidate of document.querySelectorAll('[role="main"]')) { - candidate.classList.toggle(descriptor.taskClass, candidate !== home); + candidate.classList.toggle(descriptor.taskClass, candidate !== home && candidate !== homeCandidate); + } + } + // Only mark structured layout for classic home trees. + for (const candidate of document.querySelectorAll('[role="main"]')) { + if (candidate === home) { + const hero = candidate.querySelector(':scope > div > div > div'); + const structured = !!(hero && hero.querySelector('[data-feature="game-source"], [data-testid="home-icon"]')); + candidate.setAttribute('data-dream-home-layout', structured ? 'structured' : 'soft'); + } else { + candidate.setAttribute('data-dream-home-layout', 'soft'); } } - shellMain.classList.toggle(descriptor.shellClass, Boolean(home)); + shellMain.classList.toggle(descriptor.shellClass, Boolean(homeCandidate)); if (descriptor.taskShellClass) shellMain.classList.toggle(descriptor.taskShellClass, !home); let chrome = document.getElementById(descriptor.chromeId); diff --git a/assets/inject/upstream/cidala-tiger/macos/dream-skin.css b/assets/inject/upstream/cidala-tiger/macos/dream-skin.css index 51eabd802..f06f3cc40 100644 --- a/assets/inject/upstream/cidala-tiger/macos/dream-skin.css +++ b/assets/inject/upstream/cidala-tiger/macos/dream-skin.css @@ -1323,3 +1323,49 @@ html.codex-dream-skin [data-message-author-role] { border-radius: 16px; } animation-iteration-count: 1 !important; } } + +/* codex-plus new-chat interaction safeguards */ +html.codex-dream-skin aside.app-shell-left-panel, +html.codex-dream-skin aside.app-shell-left-panel button, +html.codex-dream-skin aside.app-shell-left-panel a, +html.codex-dream-skin button[aria-label^="Start new chat in "], +html.codex-dream-skin [data-app-action-sidebar-project-row], +html.codex-dream-skin .composer-surface-chrome, +html.codex-dream-skin .composer-footer, +html.codex-dream-skin .ProseMirror, +html.codex-dream-skin [role="main"] { + pointer-events: auto !important; +} +html.codex-dream-skin button[aria-label^="Start new chat in "], +html.codex-dream-skin [data-app-action-sidebar-project-row] button { + position: relative !important; + z-index: 6 !important; +} +html.codex-dream-skin .composer-surface-chrome, +html.codex-dream-skin .composer-footer { + position: relative !important; + z-index: 4 !important; + opacity: 1 !important; + visibility: visible !important; +} +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) { + background: transparent !important; +} +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) { + min-height: 0 !important; + overflow-y: auto !important; +} +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child, +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child, +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child > div:first-child, +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child > div:first-child > div:first-child, +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child > div:first-child > div:first-child > div:first-child { + height: auto !important; + min-height: 0 !important; + max-height: none !important; + flex: 0 1 auto !important; + overflow: visible !important; + background: transparent !important; + border: 0 !important; + box-shadow: none !important; +} diff --git a/assets/inject/upstream/cidala-tiger/macos/renderer-inject.js b/assets/inject/upstream/cidala-tiger/macos/renderer-inject.js index 8cd8958a4..79fa33a7c 100644 --- a/assets/inject/upstream/cidala-tiger/macos/renderer-inject.js +++ b/assets/inject/upstream/cidala-tiger/macos/renderer-inject.js @@ -653,14 +653,28 @@ shell ||= root.getAttribute(SHELL_ATTR) || resolvedShell(); const shellMain = document.querySelector("main.main-surface") || document.querySelector("main"); const homeIndicator = document.querySelector('[data-testid="home-icon"]'); - const home = homeIndicator?.closest('[role="main"]') || + const homeCandidate = homeIndicator?.closest('[role="main"]') || [...document.querySelectorAll('[role="main"]')].find((candidate) => candidate.querySelector('[data-feature="game-source"]') && candidate.querySelector('.group\\\\/home-suggestions')) || null; + const homeHasClassicChrome = !!( + homeCandidate + && homeCandidate.querySelector('[data-feature="game-source"]') + && ( + homeCandidate.querySelector('.group\\\\/home-suggestions') + || homeCandidate.querySelector('[class*="_homeUtilityBar_"]') + ) + ); + const home = homeHasClassicChrome ? homeCandidate : null; for (const candidate of document.querySelectorAll('[role="main"].dream-skin-home')) { if (candidate !== home) candidate.classList.remove("dream-skin-home"); } if (home) home.classList.add("dream-skin-home"); + for (const candidate of document.querySelectorAll('[role="main"]')) { + if (candidate === home) candidate.setAttribute("data-dream-home-layout", "structured"); + else if (candidate === homeCandidate) candidate.setAttribute("data-dream-home-layout", "soft"); + else candidate.removeAttribute("data-dream-home-layout"); + } const homeUtilityBars = new Set(home ? home.querySelectorAll('[class*="_homeUtilityBar_"]') : []); diff --git a/assets/inject/upstream/cidala-tiger/windows/dream-skin.css b/assets/inject/upstream/cidala-tiger/windows/dream-skin.css index b8e094ca5..7cdfb0968 100644 --- a/assets/inject/upstream/cidala-tiger/windows/dream-skin.css +++ b/assets/inject/upstream/cidala-tiger/windows/dream-skin.css @@ -190,23 +190,24 @@ html.codex-dream-skin .dream-home { padding-top: 24px !important; } -.dream-home > div:first-child > div:first-child { +.dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"]) { flex: 0 0 clamp(390px, 42cqw, 510px) !important; min-height: 390px !important; align-items: flex-start !important; padding-bottom: 0 !important; } -.dream-home > div:first-child > div:first-child > div:first-child { +.dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"]) { position: relative !important; isolation: isolate; width: calc(100% - 56px) !important; max-width: 1180px !important; - height: clamp(230px, 27cqw, 326px) !important; - min-height: 230px !important; + height: auto !important; + min-height: clamp(180px, 22cqw, 280px) !important; + max-height: none !important; flex: 0 1 auto !important; padding: 0 !important; - overflow: hidden !important; + overflow: visible !important; border: 1px solid var(--dream-line) !important; border-radius: 20px !important; background-image: var(--dream-art) !important; @@ -216,11 +217,11 @@ html.codex-dream-skin .dream-home { box-shadow: var(--dream-shadow) !important; } -html.codex-dream-skin.dream-art-wide .dream-home > div:first-child > div:first-child > div:first-child { +html.codex-dream-skin.dream-art-wide .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"]) { background-size: cover !important; } -.dream-home > div:first-child > div:first-child > div:first-child::before { +.dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"])::before { content: ""; position: absolute; z-index: 0; @@ -229,15 +230,15 @@ html.codex-dream-skin.dream-art-wide .dream-home > div:first-child > div:first-c background: linear-gradient(90deg, var(--dream-hero-shade) 0 32%, transparent 70%); } -html.codex-dream-skin.dream-safe-right .dream-home > div:first-child > div:first-child > div:first-child::before { +html.codex-dream-skin.dream-safe-right .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"])::before { background: linear-gradient(270deg, var(--dream-hero-shade) 0 32%, transparent 70%); } -html.codex-dream-skin.dream-safe-center .dream-home > div:first-child > div:first-child > div:first-child::before { +html.codex-dream-skin.dream-safe-center .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"])::before { background: radial-gradient(ellipse at center, var(--dream-hero-shade) 0 23%, transparent 72%); } -html.codex-dream-skin.dream-safe-none .dream-home > div:first-child > div:first-child > div:first-child::before { +html.codex-dream-skin.dream-safe-none .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"])::before { background: transparent; } @@ -459,7 +460,7 @@ html.codex-dream-skin.dream-art-wide main.main-surface [role="main"] { } html.codex-dream-skin.dream-art-wide main.main-surface.dream-home-shell - .dream-home > div:first-child > div:first-child > div:first-child { + .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"]) { border: 0 !important; border-radius: 0 !important; background: transparent !important; @@ -467,7 +468,7 @@ html.codex-dream-skin.dream-art-wide main.main-surface.dream-home-shell } html.codex-dream-skin.dream-art-wide main.main-surface.dream-home-shell - .dream-home > div:first-child > div:first-child > div:first-child::before { + .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"])::before { content: none !important; } @@ -555,7 +556,7 @@ html.codex-dream-skin.dream-art-wide main.main-surface --thread-content-max-width: min(940px, calc(100cqw - 36px)) !important; } - .dream-home > div:first-child > div:first-child > div:first-child { + .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"]) { width: calc(100% - 36px) !important; } } @@ -565,12 +566,12 @@ html.codex-dream-skin.dream-art-wide main.main-surface padding-top: 16px !important; } - .dream-home > div:first-child > div:first-child { + .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"]) { flex-basis: 370px !important; min-height: 370px !important; } - .dream-home > div:first-child > div:first-child > div:first-child { + .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"]) { height: 220px !important; min-height: 220px !important; border-radius: 16px !important; @@ -598,7 +599,7 @@ html.codex-dream-skin.dream-art-wide main.main-surface @media (max-width: 680px) { .dream-home > div:first-child > div:first-child > div:first-child::before, html.codex-dream-skin.dream-safe-right .dream-home > div:first-child > div:first-child > div:first-child::before, - html.codex-dream-skin.dream-safe-center .dream-home > div:first-child > div:first-child > div:first-child::before { + html.codex-dream-skin.dream-safe-center .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"])::before { background: color-mix(in oklab, var(--dream-surface) 78%, transparent); } @@ -625,3 +626,49 @@ html.codex-dream-skin.dream-art-wide main.main-surface transition-duration: .01ms !important; } } + +/* codex-plus new-chat interaction safeguards */ +html.codex-dream-skin aside.app-shell-left-panel, +html.codex-dream-skin aside.app-shell-left-panel button, +html.codex-dream-skin aside.app-shell-left-panel a, +html.codex-dream-skin button[aria-label^="Start new chat in "], +html.codex-dream-skin [data-app-action-sidebar-project-row], +html.codex-dream-skin .composer-surface-chrome, +html.codex-dream-skin .composer-footer, +html.codex-dream-skin .ProseMirror, +html.codex-dream-skin [role="main"] { + pointer-events: auto !important; +} +html.codex-dream-skin button[aria-label^="Start new chat in "], +html.codex-dream-skin [data-app-action-sidebar-project-row] button { + position: relative !important; + z-index: 6 !important; +} +html.codex-dream-skin .composer-surface-chrome, +html.codex-dream-skin .composer-footer { + position: relative !important; + z-index: 4 !important; + opacity: 1 !important; + visibility: visible !important; +} +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) { + background: transparent !important; +} +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) { + min-height: 0 !important; + overflow-y: auto !important; +} +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child, +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child, +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child > div:first-child, +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child > div:first-child > div:first-child, +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child > div:first-child > div:first-child > div:first-child { + height: auto !important; + min-height: 0 !important; + max-height: none !important; + flex: 0 1 auto !important; + overflow: visible !important; + background: transparent !important; + border: 0 !important; + box-shadow: none !important; +} diff --git a/assets/inject/upstream/cidala-tiger/windows/renderer-inject.js b/assets/inject/upstream/cidala-tiger/windows/renderer-inject.js index f82da7752..326c32261 100644 --- a/assets/inject/upstream/cidala-tiger/windows/renderer-inject.js +++ b/assets/inject/upstream/cidala-tiger/windows/renderer-inject.js @@ -279,7 +279,7 @@ const root = document.documentElement; root?.classList.remove(...ROOT_CLASSES); for (const property of ROOT_PROPERTIES) root?.style.removeProperty(property); - document.querySelectorAll(".dream-home").forEach((node) => node.classList.remove("dream-home")); + document.querySelectorAll(".dream-home").forEach((node) => { node.classList.remove("dream-home"); node.removeAttribute("data-dream-home-layout"); }); document.querySelectorAll(".dream-task").forEach((node) => node.classList.remove("dream-task")); document.querySelectorAll(".dream-home-shell").forEach((node) => node.classList.remove("dream-home-shell")); document.querySelectorAll(`.${HOME_UTILITY_CLASS}`).forEach((node) => node.classList.remove(HOME_UTILITY_CLASS)); @@ -347,17 +347,40 @@ style.dataset.dreamVersion = "3"; } - const home = document.querySelector('[role="main"]:has([data-testid="home-icon"])'); + const homeCandidate = document.querySelector('[role="main"]:has([data-testid="home-icon"])'); + const homeHasClassicChrome = !!( + homeCandidate + && homeCandidate.querySelector('[data-feature="game-source"]') + && ( + homeCandidate.querySelector('.group\\/home-suggestions') + || homeCandidate.querySelector('[class*="home-suggestions"]') + || homeCandidate.querySelector('[class*="_homeUtilityBar_"]') + ) + ); + const home = homeHasClassicChrome ? homeCandidate : null; for (const candidate of document.querySelectorAll('[role="main"]')) { - candidate.classList.toggle("dream-home", candidate === home); - candidate.classList.toggle("dream-task", candidate !== home); + const isStructuredHome = candidate === home; + const isSoftHome = candidate === homeCandidate && !home; + candidate.classList.toggle("dream-home", isStructuredHome || isSoftHome); + candidate.classList.toggle("dream-task", !(isStructuredHome || isSoftHome)); + if (isStructuredHome) { + const hero = candidate.querySelector(":scope > div > div > div"); + const structured = !!( + hero + && candidate.querySelector('[data-feature="game-source"]') + && hero.querySelector('[data-feature="game-source"], [data-testid="home-icon"]') + ); + candidate.setAttribute("data-dream-home-layout", structured ? "structured" : "soft"); + } else { + candidate.setAttribute("data-dream-home-layout", "soft"); + } } const utilityBars = new Set(home ? home.querySelectorAll('[class*="_homeUtilityBar_"]') : []); for (const candidate of document.querySelectorAll(`.${HOME_UTILITY_CLASS}`)) { if (!utilityBars.has(candidate)) candidate.classList.remove(HOME_UTILITY_CLASS); } for (const candidate of utilityBars) candidate.classList.add(HOME_UTILITY_CLASS); - shellMain.classList.toggle("dream-home-shell", Boolean(home)); + shellMain.classList.toggle("dream-home-shell", Boolean(homeCandidate)); let chrome = document.getElementById(CHROME_ID); if (!chrome || chrome.parentElement !== document.body) { @@ -403,7 +426,7 @@ }); const timer = setInterval(ensure, 5000); window[STATE_KEY] = { - ensure, cleanup, observer, timer, scheduler, artUrl, profile, config, installToken, version: "1.2.0", + ensure, cleanup, observer, timer, scheduler, artUrl, profile, config, installToken, version: "1.2.1-newchat-fix", }; ensure(); analyzeArt().then((result) => { @@ -413,5 +436,5 @@ state.profile = result; ensure(); }); - return { installed: true, version: "1.2.0", adaptive: true }; + return { installed: true, version: "1.2.1-newchat-fix", adaptive: true }; })(__DREAM_CSS_JSON__, __DREAM_ART_JSON__, __DREAM_THEME_JSON__) diff --git a/assets/inject/upstream/dream-skin/macos/dream-skin.css b/assets/inject/upstream/dream-skin/macos/dream-skin.css index 07976b196..021811010 100644 --- a/assets/inject/upstream/dream-skin/macos/dream-skin.css +++ b/assets/inject/upstream/dream-skin/macos/dream-skin.css @@ -1080,3 +1080,49 @@ html.codex-dream-skin [data-message-author-role] { border-radius: 16px; } animation-iteration-count: 1 !important; } } + +/* codex-plus new-chat interaction safeguards */ +html.codex-dream-skin aside.app-shell-left-panel, +html.codex-dream-skin aside.app-shell-left-panel button, +html.codex-dream-skin aside.app-shell-left-panel a, +html.codex-dream-skin button[aria-label^="Start new chat in "], +html.codex-dream-skin [data-app-action-sidebar-project-row], +html.codex-dream-skin .composer-surface-chrome, +html.codex-dream-skin .composer-footer, +html.codex-dream-skin .ProseMirror, +html.codex-dream-skin [role="main"] { + pointer-events: auto !important; +} +html.codex-dream-skin button[aria-label^="Start new chat in "], +html.codex-dream-skin [data-app-action-sidebar-project-row] button { + position: relative !important; + z-index: 6 !important; +} +html.codex-dream-skin .composer-surface-chrome, +html.codex-dream-skin .composer-footer { + position: relative !important; + z-index: 4 !important; + opacity: 1 !important; + visibility: visible !important; +} +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) { + background: transparent !important; +} +html.codex-dream-skin .dream-skin-home:not([data-dream-home-layout="structured"]) { + min-height: 0 !important; + overflow-y: auto !important; +} +html.codex-dream-skin .dream-skin-home:not([data-dream-home-layout="structured"]) > div:first-child, +html.codex-dream-skin .dream-skin-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child, +html.codex-dream-skin .dream-skin-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child > div:first-child, +html.codex-dream-skin .dream-skin-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child > div:first-child > div:first-child, +html.codex-dream-skin .dream-skin-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child > div:first-child > div:first-child > div:first-child { + height: auto !important; + min-height: 0 !important; + max-height: none !important; + flex: 0 1 auto !important; + overflow: visible !important; + background: transparent !important; + border: 0 !important; + box-shadow: none !important; +} diff --git a/assets/inject/upstream/dream-skin/macos/renderer-inject.js b/assets/inject/upstream/dream-skin/macos/renderer-inject.js index 9988cf181..cd7264208 100644 --- a/assets/inject/upstream/dream-skin/macos/renderer-inject.js +++ b/assets/inject/upstream/dream-skin/macos/renderer-inject.js @@ -563,14 +563,30 @@ shell ||= root.getAttribute(SHELL_ATTR) || resolvedShell(); const shellMain = document.querySelector("main.main-surface") || document.querySelector("main"); const homeIndicator = document.querySelector('[data-testid="home-icon"]'); - const home = homeIndicator?.closest('[role="main"]') || + const homeCandidate = homeIndicator?.closest('[role="main"]') || [...document.querySelectorAll('[role="main"]')].find((candidate) => candidate.querySelector('[data-feature="game-source"]') && candidate.querySelector('.group\\\\/home-suggestions')) || null; + const homeHasClassicChrome = !!( + homeCandidate + && homeCandidate.querySelector('[data-feature="game-source"]') + && ( + homeCandidate.querySelector('.group\\\\/home-suggestions') + || homeCandidate.querySelector('[class*="home-suggestions"]') + || homeCandidate.querySelector('[class*="_homeUtilityBar_"]') + ) + ); + const home = homeHasClassicChrome ? homeCandidate : null; for (const candidate of document.querySelectorAll('[role="main"].dream-skin-home')) { - if (candidate !== home) candidate.classList.remove("dream-skin-home"); + if (candidate !== home && candidate !== homeCandidate) candidate.classList.remove("dream-skin-home"); } if (home) home.classList.add("dream-skin-home"); + else if (homeCandidate) homeCandidate.classList.add("dream-skin-home"); + for (const candidate of document.querySelectorAll('[role="main"]')) { + if (candidate === home) candidate.setAttribute("data-dream-home-layout", "structured"); + else if (candidate === homeCandidate) candidate.setAttribute("data-dream-home-layout", "soft"); + else candidate.removeAttribute("data-dream-home-layout"); + } const homeUtilityBars = new Set(home ? home.querySelectorAll('[class*="_homeUtilityBar_"]') : []); @@ -586,7 +602,7 @@ observedShellMain = shellMain; layout = true; } - shellMain.classList.toggle("dream-skin-home-shell", Boolean(home)); + shellMain.classList.toggle("dream-skin-home-shell", Boolean(homeCandidate)); let chrome = document.getElementById(CHROME_ID); let created = false; if (!chrome || chrome.parentElement !== document.body) { @@ -653,7 +669,10 @@ for (const name of ART_ATTRS) document.documentElement?.removeAttribute(name); document.documentElement?.style.removeProperty("--dream-skin-art"); for (const name of THEME_VARIABLES) document.documentElement?.style.removeProperty(name); - document.querySelectorAll(".dream-skin-home").forEach((node) => node.classList.remove("dream-skin-home")); + document.querySelectorAll(".dream-skin-home").forEach((node) => { + node.classList.remove("dream-skin-home"); + node.removeAttribute("data-dream-home-layout"); + }); document.querySelectorAll(".dream-skin-home-shell").forEach((node) => node.classList.remove("dream-skin-home-shell")); document.querySelectorAll(".dream-skin-home-utility").forEach((node) => node.classList.remove("dream-skin-home-utility")); document.getElementById(STYLE_ID)?.remove(); diff --git a/assets/inject/upstream/dream-skin/windows/dream-skin.css b/assets/inject/upstream/dream-skin/windows/dream-skin.css index 7e8d061bb..9dabd61df 100644 --- a/assets/inject/upstream/dream-skin/windows/dream-skin.css +++ b/assets/inject/upstream/dream-skin/windows/dream-skin.css @@ -205,23 +205,24 @@ html.codex-dream-skin .dream-home { padding-top: 24px !important; } -.dream-home > div:first-child > div:first-child { +.dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"]) { flex: 0 0 clamp(390px, 42cqw, 510px) !important; min-height: 390px !important; align-items: flex-start !important; padding-bottom: 0 !important; } -.dream-home > div:first-child > div:first-child > div:first-child { +.dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"]) { position: relative !important; isolation: isolate; width: calc(100% - 56px) !important; max-width: 1180px !important; - height: clamp(230px, 27cqw, 326px) !important; - min-height: 230px !important; + height: auto !important; + min-height: clamp(180px, 22cqw, 280px) !important; + max-height: none !important; flex: 0 1 auto !important; padding: 0 !important; - overflow: hidden !important; + overflow: visible !important; border: 1px solid var(--dream-line) !important; border-radius: 20px !important; background-image: var(--dream-art) !important; @@ -231,11 +232,11 @@ html.codex-dream-skin .dream-home { box-shadow: var(--dream-shadow) !important; } -html.codex-dream-skin.dream-art-wide .dream-home > div:first-child > div:first-child > div:first-child { +html.codex-dream-skin.dream-art-wide .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"]) { background-size: cover !important; } -.dream-home > div:first-child > div:first-child > div:first-child::before { +.dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"])::before { content: ""; position: absolute; z-index: 0; @@ -244,15 +245,15 @@ html.codex-dream-skin.dream-art-wide .dream-home > div:first-child > div:first-c background: linear-gradient(90deg, var(--dream-hero-shade) 0 32%, transparent 70%); } -html.codex-dream-skin.dream-safe-right .dream-home > div:first-child > div:first-child > div:first-child::before { +html.codex-dream-skin.dream-safe-right .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"])::before { background: linear-gradient(270deg, var(--dream-hero-shade) 0 32%, transparent 70%); } -html.codex-dream-skin.dream-safe-center .dream-home > div:first-child > div:first-child > div:first-child::before { +html.codex-dream-skin.dream-safe-center .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"])::before { background: radial-gradient(ellipse at center, var(--dream-hero-shade) 0 23%, transparent 72%); } -html.codex-dream-skin.dream-safe-none .dream-home > div:first-child > div:first-child > div:first-child::before { +html.codex-dream-skin.dream-safe-none .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"])::before { background: transparent; } @@ -474,7 +475,7 @@ html.codex-dream-skin.dream-art-wide main.main-surface [role="main"] { } html.codex-dream-skin.dream-art-wide main.main-surface.dream-home-shell - .dream-home > div:first-child > div:first-child > div:first-child { + .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"]) { border: 0 !important; border-radius: 0 !important; background: transparent !important; @@ -482,7 +483,7 @@ html.codex-dream-skin.dream-art-wide main.main-surface.dream-home-shell } html.codex-dream-skin.dream-art-wide main.main-surface.dream-home-shell - .dream-home > div:first-child > div:first-child > div:first-child::before { + .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"])::before { content: none !important; } @@ -590,7 +591,7 @@ html.codex-dream-skin.dream-art-wide main.main-surface --thread-content-max-width: min(940px, calc(100cqw - 36px)) !important; } - .dream-home > div:first-child > div:first-child > div:first-child { + .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"]) { width: calc(100% - 36px) !important; } } @@ -600,12 +601,12 @@ html.codex-dream-skin.dream-art-wide main.main-surface padding-top: 16px !important; } - .dream-home > div:first-child > div:first-child { + .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"]) { flex-basis: 370px !important; min-height: 370px !important; } - .dream-home > div:first-child > div:first-child > div:first-child { + .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"]) { height: 220px !important; min-height: 220px !important; border-radius: 16px !important; @@ -633,7 +634,7 @@ html.codex-dream-skin.dream-art-wide main.main-surface @media (max-width: 680px) { .dream-home > div:first-child > div:first-child > div:first-child::before, html.codex-dream-skin.dream-safe-right .dream-home > div:first-child > div:first-child > div:first-child::before, - html.codex-dream-skin.dream-safe-center .dream-home > div:first-child > div:first-child > div:first-child::before { + html.codex-dream-skin.dream-safe-center .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"])::before { background: color-mix(in oklab, var(--dream-surface) 78%, transparent); } @@ -660,3 +661,53 @@ html.codex-dream-skin.dream-art-wide main.main-surface transition-duration: .01ms !important; } } + +/* codex-plus new-chat interaction safeguards */ +html.codex-dream-skin aside.app-shell-left-panel, +html.codex-dream-skin aside.app-shell-left-panel button, +html.codex-dream-skin aside.app-shell-left-panel a, +html.codex-dream-skin button[aria-label^="Start new chat in "], +html.codex-dream-skin [data-app-action-sidebar-project-row], +html.codex-dream-skin .composer-surface-chrome, +html.codex-dream-skin .composer-footer, +html.codex-dream-skin .ProseMirror, +html.codex-dream-skin [role="main"] { + pointer-events: auto !important; +} + +html.codex-dream-skin button[aria-label^="Start new chat in "], +html.codex-dream-skin [data-app-action-sidebar-project-row] button { + position: relative !important; + z-index: 6 !important; +} + +html.codex-dream-skin .composer-surface-chrome, +html.codex-dream-skin .composer-footer { + position: relative !important; + z-index: 4 !important; + opacity: 1 !important; + visibility: visible !important; +} + +/* Unstructured home/new-chat draft: keep native geometry, only tint surfaces. */ +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) { + background: transparent !important; +} +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) { + min-height: 0 !important; + overflow-y: auto !important; +} +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child, +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child, +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child > div:first-child, +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child > div:first-child > div:first-child, +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child > div:first-child > div:first-child > div:first-child { + height: auto !important; + min-height: 0 !important; + max-height: none !important; + flex: 0 1 auto !important; + overflow: visible !important; + background: transparent !important; + border: 0 !important; + box-shadow: none !important; +} diff --git a/assets/inject/upstream/dream-skin/windows/renderer-inject.js b/assets/inject/upstream/dream-skin/windows/renderer-inject.js index e4b6812c4..2f3a29c37 100644 --- a/assets/inject/upstream/dream-skin/windows/renderer-inject.js +++ b/assets/inject/upstream/dream-skin/windows/renderer-inject.js @@ -289,7 +289,7 @@ const root = document.documentElement; root?.classList.remove(...ROOT_CLASSES); for (const property of ROOT_PROPERTIES) root?.style.removeProperty(property); - document.querySelectorAll(".dream-home").forEach((node) => node.classList.remove("dream-home")); + document.querySelectorAll(".dream-home").forEach((node) => { node.classList.remove("dream-home"); node.removeAttribute("data-dream-home-layout"); }); document.querySelectorAll(".dream-task").forEach((node) => node.classList.remove("dream-task")); document.querySelectorAll(".dream-home-shell").forEach((node) => node.classList.remove("dream-home-shell")); document.querySelectorAll(`.${HOME_UTILITY_CLASS}`).forEach((node) => node.classList.remove(HOME_UTILITY_CLASS)); @@ -388,17 +388,42 @@ style.dataset.dreamVersion = "3"; } - const home = document.querySelector('[role="main"]:has([data-testid="home-icon"])'); + const homeCandidate = document.querySelector('[role="main"]:has([data-testid="home-icon"])'); + const homeHasClassicChrome = !!( + homeCandidate + && homeCandidate.querySelector('[data-feature="game-source"]') + && ( + homeCandidate.querySelector('.group\\/home-suggestions') + || homeCandidate.querySelector('[class*="home-suggestions"]') + || homeCandidate.querySelector('[class*="_homeUtilityBar_"]') + ) + ); + // Project "Start new chat" often lands on a home-like draft without classic chrome. + // Keep soft theming, but skip structural dream-home surgery that can blank the page. + const home = homeHasClassicChrome ? homeCandidate : null; for (const candidate of document.querySelectorAll('[role="main"]')) { - candidate.classList.toggle("dream-home", candidate === home); - candidate.classList.toggle("dream-task", candidate !== home); + const isStructuredHome = candidate === home; + const isSoftHome = candidate === homeCandidate && !home; + candidate.classList.toggle("dream-home", isStructuredHome || isSoftHome); + candidate.classList.toggle("dream-task", !(isStructuredHome || isSoftHome)); + if (isStructuredHome) { + const hero = candidate.querySelector(":scope > div > div > div"); + const structured = !!( + hero + && candidate.querySelector('[data-feature="game-source"]') + && hero.querySelector('[data-feature="game-source"], [data-testid="home-icon"]') + ); + candidate.setAttribute("data-dream-home-layout", structured ? "structured" : "soft"); + } else { + candidate.setAttribute("data-dream-home-layout", "soft"); + } } const utilityBars = new Set(home ? home.querySelectorAll('[class*="_homeUtilityBar_"]') : []); for (const candidate of document.querySelectorAll(`.${HOME_UTILITY_CLASS}`)) { if (!utilityBars.has(candidate)) candidate.classList.remove(HOME_UTILITY_CLASS); } for (const candidate of utilityBars) candidate.classList.add(HOME_UTILITY_CLASS); - shellMain.classList.toggle("dream-home-shell", Boolean(home)); + shellMain.classList.toggle("dream-home-shell", Boolean(homeCandidate)); reconcileAuxiliaryPanels(shellMain); let chrome = document.getElementById(CHROME_ID); @@ -445,7 +470,7 @@ }); const timer = setInterval(ensure, 5000); window[STATE_KEY] = { - ensure, cleanup, observer, timer, scheduler, artUrl, profile, config, installToken, version: "1.2.0", + ensure, cleanup, observer, timer, scheduler, artUrl, profile, config, installToken, version: "1.2.1-newchat-fix", }; ensure(); analyzeArt().then((result) => { @@ -455,5 +480,5 @@ state.profile = result; ensure(); }); - return { installed: true, version: "1.2.0", adaptive: true }; + return { installed: true, version: "1.2.1-newchat-fix", adaptive: true }; })(__DREAM_CSS_JSON__, __DREAM_ART_JSON__, __DREAM_THEME_JSON__) diff --git a/assets/inject/upstream/snow-skin/dream-skin.css b/assets/inject/upstream/snow-skin/dream-skin.css index e0f60c99e..b06a45443 100644 --- a/assets/inject/upstream/snow-skin/dream-skin.css +++ b/assets/inject/upstream/snow-skin/dream-skin.css @@ -178,14 +178,14 @@ html.codex-dream-skin .dream-home { min-height: 100% !important; } -.dream-home > div:first-child > div:first-child { +.dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"]) { flex: 0 0 430px !important; min-height: 430px !important; align-items: flex-start !important; padding-bottom: 0 !important; } -.dream-home > div:first-child > div:first-child > div:first-child { +.dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"]) { position: relative !important; isolation: isolate; width: calc(100% - 44px) !important; @@ -206,7 +206,7 @@ html.codex-dream-skin .dream-home { box-shadow: 0 14px 34px rgba(33,93,146,.20), inset 0 0 0 4px rgba(255,255,255,.22) !important; } -.dream-home > div:first-child > div:first-child > div:first-child::before { +.dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"])::before { content: ""; position: absolute; z-index: 0; @@ -433,15 +433,15 @@ html.codex-dream-skin [data-message-author-role] { .dream-polaroid { display: none !important; } .dream-ribbon { bottom: 70px; font-size: 20px; } .dream-home { --thread-content-max-width: min(860px, calc(100cqw - 30px)) !important; } - .dream-home > div:first-child > div:first-child > div:first-child { width: calc(100% - 28px) !important; } + .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"]) { width: calc(100% - 28px) !important; } } @media (max-width: 900px) { .dream-signature { display: none !important; } .dream-brand { left: 15px; } .dream-brand b { font-size: 13px; } - .dream-home > div:first-child > div:first-child { flex-basis: 396px !important; min-height: 396px !important; } - .dream-home > div:first-child > div:first-child > div:first-child { height: 224px !important; min-height: 224px !important; background-size: 100% 100%, auto 145% !important; } + .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"]) { flex-basis: 396px !important; min-height: 396px !important; } + .dream-home[data-dream-home-layout="structured"] > div:first-child > div:first-child > div:first-child:has([data-feature="game-source"], [data-testid="home-icon"]) { height: 224px !important; min-height: 224px !important; background-size: 100% 100%, auto 145% !important; } .dream-home > div:first-child > div:first-child > div:first-child > div:first-child { padding-left: 26px; } .dream-home > div:first-child > div:first-child > div:first-child > div:first-child > div:first-child { width: 66% !important; } .dream-home [data-feature="game-source"] { font-size: 18px !important; } @@ -452,3 +452,49 @@ html.codex-dream-skin [data-message-author-role] { @media (prefers-reduced-motion: reduce) { .dream-sparkles i { animation: none !important; } } + +/* codex-plus new-chat interaction safeguards */ +html.codex-dream-skin aside.app-shell-left-panel, +html.codex-dream-skin aside.app-shell-left-panel button, +html.codex-dream-skin aside.app-shell-left-panel a, +html.codex-dream-skin button[aria-label^="Start new chat in "], +html.codex-dream-skin [data-app-action-sidebar-project-row], +html.codex-dream-skin .composer-surface-chrome, +html.codex-dream-skin .composer-footer, +html.codex-dream-skin .ProseMirror, +html.codex-dream-skin [role="main"] { + pointer-events: auto !important; +} +html.codex-dream-skin button[aria-label^="Start new chat in "], +html.codex-dream-skin [data-app-action-sidebar-project-row] button { + position: relative !important; + z-index: 6 !important; +} +html.codex-dream-skin .composer-surface-chrome, +html.codex-dream-skin .composer-footer { + position: relative !important; + z-index: 4 !important; + opacity: 1 !important; + visibility: visible !important; +} +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) { + background: transparent !important; +} +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) { + min-height: 0 !important; + overflow-y: auto !important; +} +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child, +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child, +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child > div:first-child, +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child > div:first-child > div:first-child, +html.codex-dream-skin .dream-home:not([data-dream-home-layout="structured"]) > div:first-child > div:first-child > div:first-child > div:first-child > div:first-child { + height: auto !important; + min-height: 0 !important; + max-height: none !important; + flex: 0 1 auto !important; + overflow: visible !important; + background: transparent !important; + border: 0 !important; + box-shadow: none !important; +} diff --git a/assets/inject/upstream/snow-skin/renderer-inject.js b/assets/inject/upstream/snow-skin/renderer-inject.js index 783c41db5..b70fa26ff 100644 --- a/assets/inject/upstream/snow-skin/renderer-inject.js +++ b/assets/inject/upstream/snow-skin/renderer-inject.js @@ -41,14 +41,40 @@ } const shellMain = document.querySelector("main.main-surface") || document.querySelector("main"); - const home = document.querySelector('[role="main"]:has([data-testid="home-icon"])'); - for (const candidate of document.querySelectorAll('[role="main"].dream-home')) { - if (candidate !== home) candidate.classList.remove("dream-home"); + const homeCandidate = document.querySelector('[role="main"]:has([data-testid="home-icon"])'); + const homeHasClassicChrome = !!( + homeCandidate + && homeCandidate.querySelector('[data-feature="game-source"]') + && ( + homeCandidate.querySelector('.group\\/home-suggestions') + || homeCandidate.querySelector('[class*="home-suggestions"]') + || homeCandidate.querySelector('[class*="_homeUtilityBar_"]') + ) + ); + const home = homeHasClassicChrome ? homeCandidate : null; + for (const candidate of document.querySelectorAll('[role="main"]')) { + const isStructuredHome = candidate === home; + const isSoftHome = candidate === homeCandidate && !home; + candidate.classList.toggle("dream-home", isStructuredHome || isSoftHome); + candidate.classList.toggle("dream-task", !(isStructuredHome || isSoftHome)); + if (isStructuredHome) { + const hero = candidate.querySelector(":scope > div > div > div"); + const structured = !!( + hero + && candidate.querySelector('[data-feature="game-source"]') + && hero.querySelector('[data-feature="game-source"], [data-testid="home-icon"]') + ); + candidate.setAttribute("data-dream-home-layout", structured ? "structured" : "soft"); + } else { + candidate.setAttribute("data-dream-home-layout", "soft"); + } } - if (home) home.classList.add("dream-home"); - - if (!shellMain || !document.body) return; - shellMain.classList.toggle("dream-home-shell", Boolean(home)); + const utilityBars = new Set(home ? home.querySelectorAll('[class*="_homeUtilityBar_"]') : []); + for (const candidate of document.querySelectorAll(`.${HOME_UTILITY_CLASS}`)) { + if (!utilityBars.has(candidate)) candidate.classList.remove(HOME_UTILITY_CLASS); + } + for (const candidate of utilityBars) candidate.classList.add(HOME_UTILITY_CLASS); + shellMain.classList.toggle("dream-home-shell", Boolean(homeCandidate)); let chrome = document.getElementById(CHROME_ID); if (!chrome || chrome.parentElement !== document.body) { chrome?.remove(); @@ -75,7 +101,7 @@ window.__CODEX_DREAM_SKIN_DISABLED__ = true; document.documentElement?.classList.remove("codex-dream-skin"); document.documentElement?.style.removeProperty("--dream-art"); - document.querySelectorAll(".dream-home").forEach((node) => node.classList.remove("dream-home")); + document.querySelectorAll(".dream-home").forEach((node) => { node.classList.remove("dream-home"); node.removeAttribute("data-dream-home-layout"); }); document.querySelectorAll(".dream-home-shell").forEach((node) => node.classList.remove("dream-home-shell")); document.getElementById(STYLE_ID)?.remove(); document.getElementById(CHROME_ID)?.remove(); diff --git a/crates/codex-plus-core/src/assets.rs b/crates/codex-plus-core/src/assets.rs index daa739724..3755654ec 100644 --- a/crates/codex-plus-core/src/assets.rs +++ b/crates/codex-plus-core/src/assets.rs @@ -49,7 +49,7 @@ const STEPWISE_SCRIPT: &str = include_str!("../../../assets/inject/stepwise-inje const SPONSOR_ALIPAY: &[u8] = include_bytes!("../../../assets/images/sponsor-alipay.jpg"); const SPONSOR_WECHAT: &[u8] = include_bytes!("../../../assets/images/sponsor-wechat.jpg"); pub const DIAGNOSTIC_BUILD_ID: &str = "diag-20260518-1"; -const DREAM_SKIN_RENDERER_REVISION: &str = "17"; +const DREAM_SKIN_RENDERER_REVISION: &str = "18-newchat-fix"; pub fn renderer_script() -> &'static str { RENDERER_SCRIPT diff --git a/crates/codex-plus-core/tests/dream_skin_runtime.rs b/crates/codex-plus-core/tests/dream_skin_runtime.rs index 3e871e187..29add2c16 100644 --- a/crates/codex-plus-core/tests/dream_skin_runtime.rs +++ b/crates/codex-plus-core/tests/dream_skin_runtime.rs @@ -2,6 +2,7 @@ use codex_plus_core::dream_skin_runtime::{ DreamSkinRuntimeStatus, DreamSkinState, apply_dream_skin_live, macos_arch_name, parse_renderer_verification, windows_app_path_matches_registered_root, }; +use std::path::Path; #[test] fn maps_rust_apple_silicon_arch_to_lipo_name() { @@ -118,6 +119,49 @@ fn verification_accepts_target_project_live_contract() { assert!(result.pass); } +#[test] +fn bundled_skin_runtimes_gate_structural_home_layout_on_classic_chrome() { + for relative_path in [ + "assets/inject/upstream/dream-skin/windows/renderer-inject.js", + "assets/inject/upstream/dream-skin/macos/renderer-inject.js", + "assets/inject/upstream/cidala-tiger/windows/renderer-inject.js", + "assets/inject/upstream/cidala-tiger/macos/renderer-inject.js", + "assets/inject/upstream/snow-skin/renderer-inject.js", + ] { + let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("../..").join(relative_path); + let source = std::fs::read_to_string(&path) + .unwrap_or_else(|error| panic!("failed to read {relative_path}: {error}")); + assert!( + source.contains("homeHasClassicChrome"), + "missing home gate in {relative_path}" + ); + assert!( + source.contains("data-dream-home-layout"), + "missing layout marker in {relative_path}" + ); + } + for relative_path in [ + "assets/inject/upstream/dream-skin/windows/dream-skin.css", + "assets/inject/upstream/dream-skin/macos/dream-skin.css", + "assets/inject/upstream/cidala-tiger/windows/dream-skin.css", + "assets/inject/upstream/cidala-tiger/macos/dream-skin.css", + "assets/inject/upstream/snow-skin/dream-skin.css", + ] { + let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("../..").join(relative_path); + let source = std::fs::read_to_string(&path) + .unwrap_or_else(|error| panic!("failed to read {relative_path}: {error}")); + assert!( + source.contains("data-dream-home-layout=\"soft\"") + || (source.contains("data-dream-home-layout=\"structured\"") + && source.contains(":not([data-dream-home-layout=\"structured\"])") + ) + || source.contains("data-dream-home-layout=\\\"soft\\\"") + || source.contains("data-dream-home-layout=\\\"structured\\\""), + "missing soft layout CSS in {relative_path}" + ); + } +} + #[test] fn windows_identity_requires_a_path_inside_the_registered_package_root() { let root = std::path::Path::new( diff --git a/crates/codex-plus-core/tests/upstream_theme_assets.rs b/crates/codex-plus-core/tests/upstream_theme_assets.rs index 4ffa044e2..2ea73d3a8 100644 --- a/crates/codex-plus-core/tests/upstream_theme_assets.rs +++ b/crates/codex-plus-core/tests/upstream_theme_assets.rs @@ -10,7 +10,19 @@ fn assert_sha256(relative_path: &str, expected: &str) { path.display() ) }); - let actual = format!("{:X}", Sha256::digest(bytes)); + // Git may materialize these text assets with CRLF on Windows. Hash the + // repository's canonical LF representation so the guard is platform + // independent while still detecting substantive asset changes. + let mut normalized = Vec::with_capacity(bytes.len()); + let mut index = 0; + while index < bytes.len() { + if bytes[index] == b'\r' && bytes.get(index + 1) == Some(&b'\n') { + index += 1; + } + normalized.push(bytes[index]); + index += 1; + } + let actual = format!("{:X}", Sha256::digest(normalized)); assert_eq!(actual, expected, "upstream asset changed: {relative_path}"); } @@ -19,43 +31,43 @@ fn bundled_target_renderers_and_styles_remain_byte_exact() { for (path, hash) in [ ( "assets/inject/upstream/dream-skin/windows/renderer-inject.js", - "74D3BFB0F0F55C138EE3B0933F7B55BC11F71D09F1B07794BCA51B6598DE203D", + "6CC916DFD987BF672D6C99CC68C059E28747500E4CD25F0DF1706603FE3DABC6", ), ( "assets/inject/upstream/dream-skin/windows/dream-skin.css", - "12848DA7DDAACF1B0F18CD419B2B27A6355DCBCE01AF650F1BCE14D99FEBD532", + "049695F3F8FD66826F7DD0EF9363D21A5AA491C627DD9602CEAEA7383CFDD49C", ), ( "assets/inject/upstream/dream-skin/macos/renderer-inject.js", - "2704C39506C66554C3529BF0D15B876B4AEC2DD9A36B1796AB43E19C33A046FC", + "73DA118C964E768676C44C9ABAC910114547DDA44B6190CC3D8A6220059ABB0B", ), ( "assets/inject/upstream/dream-skin/macos/dream-skin.css", - "EC3C3BC5F6E10E20A3F2307796BD1E1350E80E5D23D37318EE5468833C95A6DF", + "CDA12A5E08815533919A6005A803C2269637CDCAAC4D121D170230163DC9CF09", ), ( "assets/inject/upstream/cidala-tiger/windows/renderer-inject.js", - "0BFB5F66A0323BF1392B42033E66904DE3EC4BFC8A5BA297F2BB92A4A6740A34", + "98B9F323A9711FFB3E8307C9ACA3F4FBDA71896A047F334AB38AF43FDB2D53E6", ), ( "assets/inject/upstream/cidala-tiger/windows/dream-skin.css", - "482A60AF98DD6B460BF624C56918C5B57F9CCD5B55E52FA46D486F7D65259D9A", + "0C371B7D794C4783648D1733661E8FA8674C872296CE5CF9898B28EB1765425C", ), ( "assets/inject/upstream/cidala-tiger/macos/renderer-inject.js", - "21FAF1DC0A3EBE78D8D972182CACE62BD93D5D0E5841725398A4A524EF2BC20B", + "19202C8A37C7512E65F950A5516A314867FDF305B74B313F0ABCEA8CF7347F59", ), ( "assets/inject/upstream/cidala-tiger/macos/dream-skin.css", - "5E149E9A13985961C5F3125296178ACB2ABF0B528974F1E616AA625970430562", + "45506CA7C71D4E9867287AE2358C4380C0993F0D04039C29FEE6DBEE20495148", ), ( "assets/inject/upstream/snow-skin/renderer-inject.js", - "0FCDFF4AECD03EAB2CA4EE923CCD20CB97EB5460F7C9F07351A2003FFA76E6FA", + "9AE8123B51917975B5D4B91995173A6A4DD3C27C6BD5B465B5670C2C1330955A", ), ( "assets/inject/upstream/snow-skin/dream-skin.css", - "0AF2D20FBE3E3DD13F0BE7F1E5A90366E1501084827B22C1D4815A421BFCE823", + "97807DE20E40680471D211466B657867CB46280F393EF9D7FBBA5CE829AE5599", ), ( "assets/inject/upstream/glass-vision/renderer-inject.js",