diff --git a/macos/CHANGELOG.md b/macos/CHANGELOG.md index 349b5101..64f36775 100644 --- a/macos/CHANGELOG.md +++ b/macos/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.5.6 — 2026-07-26 + +### 修复 + +- 移除覆盖原生标题栏与首页输入区域的绝对定位主题标语,让窗口、导航、分享与设置控件继续使用原生布局和点击区域。 +- 宽幅任务背景继续只绘制在底层画布,主阅读平面改用 240–320px 连续羽化遮罩,不再用硬编码 64% 分段形成左右拼接感。 +- 输入框恢复完整的一像素边界和独立 surface,并清除会截断其表面的容器裁切、mask 与宽幅模式 `border: 0` 覆盖。 + ## 1.5.5 — 2026-07-25 ### 修复 diff --git a/macos/VERSION b/macos/VERSION index 9075be49..eac1e0ad 100644 --- a/macos/VERSION +++ b/macos/VERSION @@ -1 +1 @@ -1.5.5 +1.5.6 diff --git a/macos/assets/dream-skin.css b/macos/assets/dream-skin.css index bd112ec0..96985bc9 100644 --- a/macos/assets/dream-skin.css +++ b/macos/assets/dream-skin.css @@ -59,6 +59,16 @@ --ds-task-immersive-edge: rgb(var(--ds-bg-rgb) / .82); --ds-task-immersive-mid: rgb(var(--ds-bg-rgb) / .74); --ds-task-immersive-far: rgb(var(--ds-bg-rgb) / .60); + /* Wide task routes remain one continuous canvas: artwork stays on the body, + while this veil feathers the reading plane into the atmospheric edge. */ + --ambient-start: 52%; + --ambient-feather: clamp(240px, 24vw, 320px); + --composer-surface: rgb(var(--ds-panel-rgb) / .94); + --reading-veil: linear-gradient(90deg, + rgb(var(--ds-panel-rgb) / .96) 0%, + rgb(var(--ds-panel-rgb) / .96) var(--ambient-start), + rgb(var(--ds-panel-rgb) / .12) calc(var(--ambient-start) + var(--ambient-feather)), + rgb(var(--ds-panel-rgb) / .06) 100%); } html[data-dream-skin="active"][data-dream-shell="light"] { @@ -411,10 +421,11 @@ html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream- html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(main.main-surface):not(:has(main.main-surface [role="main"])) main.main-surface:not(:has([role="main"])) { - background: linear-gradient(90deg, - var(--ds-task-immersive-edge), - var(--ds-task-immersive-mid) 64%, - var(--ds-task-immersive-far)) !important; + overflow: visible !important; + clip-path: none !important; + -webkit-mask-image: none !important; + mask-image: none !important; + background: var(--reading-veil) !important; border: 0 !important; border-radius: 0 !important; box-shadow: none !important; @@ -427,13 +438,12 @@ html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream- html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(main.main-surface):not(:has(main.main-surface [role="main"])) .composer-surface-chrome { - background: var(--ds-immersive-composer-solid) !important; - border: 0 !important; + background: var(--composer-surface) !important; + border: 1px solid var(--ds-line) !important; box-shadow: 0 10px 30px rgb(var(--ds-bg-rgb) / .20), - inset 0 0 0 1px var(--ds-immersive-line), inset 0 1px rgb(var(--ds-text-rgb) / .12) !important; - backdrop-filter: none !important; + backdrop-filter: blur(18px) saturate(108%) !important; } html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(main.main-surface):not(:has(main.main-surface [role="main"])) @@ -532,70 +542,24 @@ html[data-dream-skin="active"][data-dream-shell="light"] [role="main"]:has([data } html[data-dream-skin="active"] main.main-surface > header.app-header-tint { - /* Preserve Codex's native fixed header geometry and side-panel controls. */ - background: rgb(var(--ds-panel-rgb) / .90) !important; - border-bottom: 1px solid var(--ds-line) !important; - backdrop-filter: blur(14px) saturate(108%) !important; + /* Preserve the native flex layout, baselines and hit targets without + drawing a theme divider across the titlebar. */ + background: var(--composer-surface) !important; + border: 0 !important; + box-shadow: none !important; + backdrop-filter: none !important; } -/* Decorative chrome lives on the native shell; no injected positioning host is needed. */ +/* Native titlebar controls own the complete toolbar grid and hit targets. + Theme identity stays in the artwork and palette, never positioned labels. */ html[data-dream-skin="active"] - main.main-surface:not(:has([role="main"])) > header.app-header-tint::before { - content: var(--dream-skin-name, "Codex Dream Skin") " · " - var(--dream-skin-brand-subtitle, "CODEX DREAM SKIN"); - position: absolute; - left: 22px; - top: 4px; - z-index: 2; - max-width: min(42%, 360px); - overflow: hidden; - color: var(--ds-accent); - font: 800 11px/1.3 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; - letter-spacing: .03em; - text-overflow: ellipsis; - text-shadow: 0 1px 12px rgb(var(--ds-bg-rgb) / .32); - white-space: nowrap; - pointer-events: none; -} - + main.main-surface:not(:has([role="main"])) > header.app-header-tint::before, html[data-dream-skin="active"] - main.main-surface:not(:has([role="main"])) > header.app-header-tint::after { - content: var(--dream-skin-status, "DREAM SKIN ONLINE"); - position: absolute; - right: 84px; - top: 13px; - z-index: 2; - max-width: 28%; - overflow: hidden; - color: var(--ds-muted); - font: 700 9px/1.2 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; - letter-spacing: .08em; - text-overflow: ellipsis; - text-shadow: 0 1px 10px rgb(var(--ds-bg-rgb) / .32); - white-space: nowrap; - pointer-events: none; -} - + main.main-surface:not(:has([role="main"])) > header.app-header-tint::after, html[data-dream-skin="active"] main.main-surface:has([role="main"])::after { - content: var(--dream-skin-quote, "MAKE SOMETHING WONDERFUL"); - position: absolute; - right: 28px; - bottom: 72px; - z-index: 2; - pointer-events: none; - color: rgb(var(--ds-accent-rgb) / .74); - font: italic 14px/1.2 "Segoe Print", "Comic Sans MS", cursive; - letter-spacing: 0; - text-shadow: 0 0 13px rgb(var(--ds-accent-rgb) / .30); - transform: rotate(-3deg); -} - -html[data-dream-skin="active"][data-dream-shell="light"] - main.main-surface:not(:has([role="main"])) > header.app-header-tint::before, -html[data-dream-skin="active"][data-dream-shell="light"] - main.main-surface:not(:has([role="main"])) > header.app-header-tint::after { - text-shadow: none; + content: none !important; + display: none !important; } /* Windows keeps this native bar outside main; macOS simply has no match. */ @@ -889,15 +853,32 @@ html[data-dream-skin="active"] [role="main"]:has([data-testid="home-icon"]) .gro html[data-dream-skin="active"] [role="main"]:has([data-testid="home-icon"]) .group\/home-suggestions button > span:last-child { align-items: center !important; text-align: center !important; } html[data-dream-skin="active"] .composer-surface-chrome { + position: relative !important; + isolation: isolate !important; + z-index: 4 !important; overflow: visible !important; - border: 1px solid rgb(var(--ds-muted-rgb) / .18) !important; + clip-path: none !important; + -webkit-mask-image: none !important; + mask-image: none !important; + background-clip: padding-box !important; + border: 1px solid var(--ds-line) !important; border-radius: 22px !important; - background: rgb(var(--ds-panel-rgb) / .94) !important; + background: var(--composer-surface) !important; box-shadow: 0 10px 28px rgb(var(--ds-bg-rgb) / .24) !important; - backdrop-filter: blur(16px) saturate(108%) !important; + backdrop-filter: blur(18px) saturate(108%) !important; } -html[data-dream-skin="active"] .composer-surface-chrome::before { content: none !important; } +/* Keep a complete one-pixel boundary even when the native cascade zeroes the + composer's own border width. This layer never participates in input. */ +html[data-dream-skin="active"] .composer-surface-chrome::before { + content: "" !important; + position: absolute !important; + inset: 0 !important; + z-index: 2 !important; + border: 1px solid var(--ds-line) !important; + border-radius: inherit !important; + pointer-events: none !important; +} /* A wide image can carry the home screen too. The native hero remains live, but the artwork is painted once on the window instead of repeated in a card. */ @@ -980,13 +961,12 @@ html[data-dream-skin="active"][data-dream-art-wide="true"] main.main-surface:has } html[data-dream-skin="active"][data-dream-art-wide="true"] .composer-surface-chrome { - background: var(--ds-immersive-composer-solid) !important; - border: 0 !important; + background: var(--composer-surface) !important; + border: 1px solid var(--ds-line) !important; box-shadow: 0 10px 30px rgb(var(--ds-bg-rgb) / .20), - inset 0 0 0 1px var(--ds-immersive-line), inset 0 1px rgb(var(--ds-text-rgb) / .12) !important; - backdrop-filter: none !important; + backdrop-filter: blur(18px) saturate(108%) !important; } html[data-dream-skin="active"][data-dream-shell="light"][data-dream-art-wide="true"] diff --git a/macos/assets/renderer-inject.js b/macos/assets/renderer-inject.js index be799888..7bb91013 100644 --- a/macos/assets/renderer-inject.js +++ b/macos/assets/renderer-inject.js @@ -311,11 +311,9 @@ } setStyleProperty(root, "--dream-skin-name", cssString(THEME.name || "Codex Dream Skin")); setStyleProperty(root, "--dream-skin-tagline", cssString(THEME.tagline || "Make something wonderful.")); - setStyleProperty(root, "--dream-skin-quote", cssString(THEME.quote || "MAKE SOMETHING WONDERFUL")); - setStyleProperty(root, "--dream-skin-brand-subtitle", cssString( - THEME.brandSubtitle || "CODEX DREAM SKIN", - )); - setStyleProperty(root, "--dream-skin-status", cssString(THEME.statusText || "DREAM SKIN ONLINE")); + // Header and lower-chrome slogans were retired because they compete with + // native toolbar controls and the composer. Their old variable names stay + // in THEME_VARIABLES so reinjection removes values from earlier versions. setStyleProperty(root, "--dream-skin-project-prefix", cssString(THEME.projectPrefix || "选择项目 · ")); setStyleProperty(root, "--dream-skin-project-label", cssString(THEME.projectLabel || "◉ 选择项目")); }; diff --git a/macos/package.json b/macos/package.json index f8ebed43..b992b814 100644 --- a/macos/package.json +++ b/macos/package.json @@ -1,6 +1,6 @@ { "name": "codex-dream-skin-studio", - "version": "1.5.5", + "version": "1.5.6", "private": true, "type": "module", "scripts": { diff --git a/macos/scripts/common-macos.sh b/macos/scripts/common-macos.sh index 32a58da2..921ae633 100755 --- a/macos/scripts/common-macos.sh +++ b/macos/scripts/common-macos.sh @@ -29,7 +29,7 @@ CODEX_APP_JOB_LABEL="com.openai.codex-dream-skin-studio.app" INJECTOR_JOB_LABEL="com.openai.codex-dream-skin-studio.injector" EXPECTED_CODEX_TEAM_ID="2DC432GLL2" EXPECTED_CODEX_REQUIREMENT="anchor apple generic and certificate leaf[subject.OU] = \"$EXPECTED_CODEX_TEAM_ID\"" -SKIN_VERSION="1.5.5" +SKIN_VERSION="1.5.6" DREAM_SKIN_VALIDATED_RUNTIME_PID="" DREAM_SKIN_VALIDATED_RUNTIME_BUNDLE="" DREAM_SKIN_VALIDATED_RUNTIME_EXE="" diff --git a/macos/scripts/injector.mjs b/macos/scripts/injector.mjs index 924fe814..cbbbf764 100644 --- a/macos/scripts/injector.mjs +++ b/macos/scripts/injector.mjs @@ -42,7 +42,7 @@ const stableTestidLiteral = (testid) => { } return JSON.stringify(`[data-testid="${testid}"]`); }; -const SKIN_VERSION = "1.5.5"; +const SKIN_VERSION = "1.5.6"; const LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "[::1]"]); const CDP_ID_PATTERN = /^[A-Za-z0-9._-]{1,200}$/; const MAX_ART_BYTES = 10 * 1024 * 1024; diff --git a/macos/tests/run-tests.sh b/macos/tests/run-tests.sh index ca068e6d..bfee73ff 100755 --- a/macos/tests/run-tests.sh +++ b/macos/tests/run-tests.sh @@ -82,7 +82,7 @@ UPDATE_JSON="$({ })" "$NODE" -e ' const value = JSON.parse(process.argv[1]); - if (value.currentVersion !== "v1.5.5" || value.latestVersion !== "v9.8.7") process.exit(1); + if (value.currentVersion !== "v1.5.6" || value.latestVersion !== "v9.8.7") process.exit(1); if (!value.updateAvailable) process.exit(1); if (value.releaseUrl !== "https://github.com/Fei-Away/Codex-Dream-Skin/releases/latest") process.exit(1); ' "$UPDATE_JSON" @@ -1063,7 +1063,7 @@ CRLF_BACKUP="$TMP/config-crlf-backup.json" "$NODE" "$ROOT/scripts/theme-config.mjs" restore "$CRLF_CONFIG" "$CRLF_BACKUP" >/dev/null /usr/bin/cmp -s "$CRLF_CONFIG" "$TMP/original-crlf.toml" -/usr/bin/env -u HOME /bin/bash -c '. "$1/scripts/common-macos.sh"; [ -n "$HOME" ] && [ "$SKIN_VERSION" = "1.5.5" ]' _ "$ROOT" +/usr/bin/env -u HOME /bin/bash -c '. "$1/scripts/common-macos.sh"; [ -n "$HOME" ] && [ "$SKIN_VERSION" = "1.5.6" ]' _ "$ROOT" if [ "${CODEX_DREAM_SKIN_SKIP_DOCTOR:-0}" = "1" ]; then printf 'SKIP: Doctor requires an installed, signed Codex app.\n' DOCTOR_RESULT="skipped" diff --git a/runtime/dream-skin.css b/runtime/dream-skin.css index b2559ffc..4a243094 100644 --- a/runtime/dream-skin.css +++ b/runtime/dream-skin.css @@ -59,6 +59,16 @@ --ds-task-immersive-edge: rgb(var(--ds-bg-rgb) / .82); --ds-task-immersive-mid: rgb(var(--ds-bg-rgb) / .74); --ds-task-immersive-far: rgb(var(--ds-bg-rgb) / .60); + /* Wide task routes remain one continuous canvas: artwork stays on the body, + while this veil feathers the reading plane into the atmospheric edge. */ + --ambient-start: 52%; + --ambient-feather: clamp(240px, 24vw, 320px); + --composer-surface: rgb(var(--ds-panel-rgb) / .94); + --reading-veil: linear-gradient(90deg, + rgb(var(--ds-panel-rgb) / .96) 0%, + rgb(var(--ds-panel-rgb) / .96) var(--ambient-start), + rgb(var(--ds-panel-rgb) / .12) calc(var(--ambient-start) + var(--ambient-feather)), + rgb(var(--ds-panel-rgb) / .06) 100%); } html[data-dream-skin="active"][data-dream-shell="light"] { @@ -411,10 +421,11 @@ html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream- html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(__DREAM_SELECTOR_SHELL_MAIN__):not(:has(__DREAM_SELECTOR_SHELL_MAIN__ __DREAM_SELECTOR_HOME_ROUTE_CSS__)) __DREAM_SELECTOR_SHELL_MAIN__:not(:has(__DREAM_SELECTOR_HOME_ROUTE_CSS__)) { - background: linear-gradient(90deg, - var(--ds-task-immersive-edge), - var(--ds-task-immersive-mid) 64%, - var(--ds-task-immersive-far)) !important; + overflow: visible !important; + clip-path: none !important; + -webkit-mask-image: none !important; + mask-image: none !important; + background: var(--reading-veil) !important; border: 0 !important; border-radius: 0 !important; box-shadow: none !important; @@ -427,13 +438,12 @@ html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream- html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(__DREAM_SELECTOR_SHELL_MAIN__):not(:has(__DREAM_SELECTOR_SHELL_MAIN__ __DREAM_SELECTOR_HOME_ROUTE_CSS__)) __DREAM_SELECTOR_COMPOSER_CHROME__ { - background: var(--ds-immersive-composer-solid) !important; - border: 0 !important; + background: var(--composer-surface) !important; + border: 1px solid var(--ds-line) !important; box-shadow: 0 10px 30px rgb(var(--ds-bg-rgb) / .20), - inset 0 0 0 1px var(--ds-immersive-line), inset 0 1px rgb(var(--ds-text-rgb) / .12) !important; - backdrop-filter: none !important; + backdrop-filter: blur(18px) saturate(108%) !important; } html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(__DREAM_SELECTOR_SHELL_MAIN__):not(:has(__DREAM_SELECTOR_SHELL_MAIN__ __DREAM_SELECTOR_HOME_ROUTE_CSS__)) @@ -532,70 +542,24 @@ html[data-dream-skin="active"][data-dream-shell="light"] __DREAM_SELECTOR_HOME_R } html[data-dream-skin="active"] __DREAM_SELECTOR_SHELL_MAIN__ > __DREAM_SELECTOR_HEADER_TINT__ { - /* Preserve Codex's native fixed header geometry and side-panel controls. */ - background: rgb(var(--ds-panel-rgb) / .90) !important; - border-bottom: 1px solid var(--ds-line) !important; - backdrop-filter: blur(14px) saturate(108%) !important; + /* Preserve the native flex layout, baselines and hit targets without + drawing a theme divider across the titlebar. */ + background: var(--composer-surface) !important; + border: 0 !important; + box-shadow: none !important; + backdrop-filter: none !important; } -/* Decorative chrome lives on the native shell; no injected positioning host is needed. */ +/* Native titlebar controls own the complete toolbar grid and hit targets. + Theme identity stays in the artwork and palette, never positioned labels. */ html[data-dream-skin="active"] - __DREAM_SELECTOR_SHELL_MAIN__:not(:has(__DREAM_SELECTOR_HOME_ROUTE_CSS__)) > __DREAM_SELECTOR_HEADER_TINT__::before { - content: var(--dream-skin-name, "Codex Dream Skin") " · " - var(--dream-skin-brand-subtitle, "CODEX DREAM SKIN"); - position: absolute; - left: 22px; - top: 4px; - z-index: 2; - max-width: min(42%, 360px); - overflow: hidden; - color: var(--ds-accent); - font: 800 11px/1.3 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; - letter-spacing: .03em; - text-overflow: ellipsis; - text-shadow: 0 1px 12px rgb(var(--ds-bg-rgb) / .32); - white-space: nowrap; - pointer-events: none; -} - + __DREAM_SELECTOR_SHELL_MAIN__:not(:has(__DREAM_SELECTOR_HOME_ROUTE_CSS__)) > __DREAM_SELECTOR_HEADER_TINT__::before, html[data-dream-skin="active"] - __DREAM_SELECTOR_SHELL_MAIN__:not(:has(__DREAM_SELECTOR_HOME_ROUTE_CSS__)) > __DREAM_SELECTOR_HEADER_TINT__::after { - content: var(--dream-skin-status, "DREAM SKIN ONLINE"); - position: absolute; - right: 84px; - top: 13px; - z-index: 2; - max-width: 28%; - overflow: hidden; - color: var(--ds-muted); - font: 700 9px/1.2 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; - letter-spacing: .08em; - text-overflow: ellipsis; - text-shadow: 0 1px 10px rgb(var(--ds-bg-rgb) / .32); - white-space: nowrap; - pointer-events: none; -} - + __DREAM_SELECTOR_SHELL_MAIN__:not(:has(__DREAM_SELECTOR_HOME_ROUTE_CSS__)) > __DREAM_SELECTOR_HEADER_TINT__::after, html[data-dream-skin="active"] __DREAM_SELECTOR_SHELL_MAIN__:has(__DREAM_SELECTOR_HOME_ROUTE_CSS__)::after { - content: var(--dream-skin-quote, "MAKE SOMETHING WONDERFUL"); - position: absolute; - right: 28px; - bottom: 72px; - z-index: 2; - pointer-events: none; - color: rgb(var(--ds-accent-rgb) / .74); - font: italic 14px/1.2 "Segoe Print", "Comic Sans MS", cursive; - letter-spacing: 0; - text-shadow: 0 0 13px rgb(var(--ds-accent-rgb) / .30); - transform: rotate(-3deg); -} - -html[data-dream-skin="active"][data-dream-shell="light"] - __DREAM_SELECTOR_SHELL_MAIN__:not(:has(__DREAM_SELECTOR_HOME_ROUTE_CSS__)) > __DREAM_SELECTOR_HEADER_TINT__::before, -html[data-dream-skin="active"][data-dream-shell="light"] - __DREAM_SELECTOR_SHELL_MAIN__:not(:has(__DREAM_SELECTOR_HOME_ROUTE_CSS__)) > __DREAM_SELECTOR_HEADER_TINT__::after { - text-shadow: none; + content: none !important; + display: none !important; } /* Windows keeps this native bar outside main; macOS simply has no match. */ @@ -889,15 +853,32 @@ html[data-dream-skin="active"] __DREAM_SELECTOR_HOME_ROUTE__ __DREAM_SELECTOR_HO html[data-dream-skin="active"] __DREAM_SELECTOR_HOME_ROUTE__ __DREAM_SELECTOR_HOME_SUGGESTIONS__ button > span:last-child { align-items: center !important; text-align: center !important; } html[data-dream-skin="active"] __DREAM_SELECTOR_COMPOSER_CHROME__ { + position: relative !important; + isolation: isolate !important; + z-index: 4 !important; overflow: visible !important; - border: 1px solid rgb(var(--ds-muted-rgb) / .18) !important; + clip-path: none !important; + -webkit-mask-image: none !important; + mask-image: none !important; + background-clip: padding-box !important; + border: 1px solid var(--ds-line) !important; border-radius: 22px !important; - background: rgb(var(--ds-panel-rgb) / .94) !important; + background: var(--composer-surface) !important; box-shadow: 0 10px 28px rgb(var(--ds-bg-rgb) / .24) !important; - backdrop-filter: blur(16px) saturate(108%) !important; + backdrop-filter: blur(18px) saturate(108%) !important; } -html[data-dream-skin="active"] __DREAM_SELECTOR_COMPOSER_CHROME__::before { content: none !important; } +/* Keep a complete one-pixel boundary even when the native cascade zeroes the + composer's own border width. This layer never participates in input. */ +html[data-dream-skin="active"] __DREAM_SELECTOR_COMPOSER_CHROME__::before { + content: "" !important; + position: absolute !important; + inset: 0 !important; + z-index: 2 !important; + border: 1px solid var(--ds-line) !important; + border-radius: inherit !important; + pointer-events: none !important; +} /* A wide image can carry the home screen too. The native hero remains live, but the artwork is painted once on the window instead of repeated in a card. */ @@ -980,13 +961,12 @@ html[data-dream-skin="active"][data-dream-art-wide="true"] __DREAM_SELECTOR_SHEL } html[data-dream-skin="active"][data-dream-art-wide="true"] __DREAM_SELECTOR_COMPOSER_CHROME__ { - background: var(--ds-immersive-composer-solid) !important; - border: 0 !important; + background: var(--composer-surface) !important; + border: 1px solid var(--ds-line) !important; box-shadow: 0 10px 30px rgb(var(--ds-bg-rgb) / .20), - inset 0 0 0 1px var(--ds-immersive-line), inset 0 1px rgb(var(--ds-text-rgb) / .12) !important; - backdrop-filter: none !important; + backdrop-filter: blur(18px) saturate(108%) !important; } html[data-dream-skin="active"][data-dream-shell="light"][data-dream-art-wide="true"] diff --git a/runtime/renderer-inject.js b/runtime/renderer-inject.js index 4066c711..0ec08e42 100644 --- a/runtime/renderer-inject.js +++ b/runtime/renderer-inject.js @@ -311,11 +311,9 @@ } setStyleProperty(root, "--dream-skin-name", cssString(THEME.name || "Codex Dream Skin")); setStyleProperty(root, "--dream-skin-tagline", cssString(THEME.tagline || "Make something wonderful.")); - setStyleProperty(root, "--dream-skin-quote", cssString(THEME.quote || "MAKE SOMETHING WONDERFUL")); - setStyleProperty(root, "--dream-skin-brand-subtitle", cssString( - THEME.brandSubtitle || "CODEX DREAM SKIN", - )); - setStyleProperty(root, "--dream-skin-status", cssString(THEME.statusText || "DREAM SKIN ONLINE")); + // Header and lower-chrome slogans were retired because they compete with + // native toolbar controls and the composer. Their old variable names stay + // in THEME_VARIABLES so reinjection removes values from earlier versions. setStyleProperty(root, "--dream-skin-project-prefix", cssString(THEME.projectPrefix || "选择项目 · ")); setStyleProperty(root, "--dream-skin-project-label", cssString(THEME.projectLabel || "◉ 选择项目")); }; diff --git a/tools/renderer-runtime.test.mjs b/tools/renderer-runtime.test.mjs index c0492567..6e762ff9 100644 --- a/tools/renderer-runtime.test.mjs +++ b/tools/renderer-runtime.test.mjs @@ -258,9 +258,36 @@ export async function runRendererRuntimeTest(assetRoot) { assert.match(css, /main\.main-surface:has\(\[role="main"\]\)/); assert.match(css, /main\.main-surface:not\(:has\(\[role="main"\]\)\)/); assert.doesNotMatch(css, /:has\([^()]*:has\(/); - assert.match(css, /content:\s*var\(--dream-skin-name[\s\S]{0,180}var\(--dream-skin-brand-subtitle/); - assert.match(css, /content:\s*var\(--dream-skin-status/); - assert.match(css, /content:\s*var\(--dream-skin-quote/); + assert.doesNotMatch(css, + /content:\s*var\(--dream-skin-(?:chrome-mark|brand-subtitle|status|quote)/, + "Theme slogans must not be painted over native chrome."); + assert.doesNotMatch(template, + /setStyleProperty\(root,\s*"--dream-skin-(?:brand-subtitle|status|quote)"/, + "Retired chrome slogans must not be populated by the renderer."); + assert.match(css, + /--ambient-start:\s*52%[\s\S]*?--ambient-feather:\s*clamp\(240px,\s*24vw,\s*320px\)[\s\S]*?--composer-surface:[\s\S]*?--reading-veil:\s*linear-gradient/); + assert.match(css, + /data-dream-task-mode="ambient"[\s\S]*?main\.main-surface:not\(:has\(\[role="main"\]\)\)\s*\{[\s\S]*?overflow:\s*visible\s*!important[\s\S]*?clip-path:\s*none\s*!important[\s\S]*?mask-image:\s*none\s*!important[\s\S]*?background:\s*var\(--reading-veil\)\s*!important/, + "Wide ambient tasks must feather one body artwork layer through a continuous main canvas."); + assert.match(css, + /header\.app-header-tint\s*\{[\s\S]*?background:\s*var\(--composer-surface\)\s*!important[\s\S]*?border:\s*0\s*!important[\s\S]*?box-shadow:\s*none\s*!important/, + "The theme must not draw a divider across the native toolbar."); + assert.match(css, + /composer-surface-chrome\s*\{[\s\S]{0,260}?isolation:\s*isolate\s*!important[\s\S]{0,180}?overflow:\s*visible\s*!important[\s\S]{0,220}?clip-path:\s*none\s*!important[\s\S]{0,220}?mask-image:\s*none\s*!important[\s\S]{0,220}?background:\s*var\(--composer-surface\)\s*!important/, + "The composer must stay one complete surface above atmospheric layers."); + assert.match(css, + /composer-surface-chrome::before\s*\{[\s\S]*?border:\s*1px solid var\(--ds-line\)[\s\S]*?pointer-events:\s*none\s*!important/, + "The composer boundary must remain complete without intercepting input."); + const threadSurfaceBlocks = [...css.matchAll( + /([^{}]*\.thread-scroll-container[^{}]*)\{([^{}]*)\}/g, + )]; + for (const [, selector, declarations] of threadSurfaceBlocks) { + assert.doesNotMatch( + declarations, + /(?:^|\n)\s*(?:overflow(?:-[xy])?|clip-path|(?:-webkit-)?mask(?:-image)?)\s*:/, + `The skin must not override native scrolling or clipping on ${selector.trim()}.`, + ); + } assert.match(css, /--ds-task-full-veil/); assert.match(css, /data-dream-task-mode="full"/); assert.match(css, /background-image:\s*var\(--ds-task-full-veil\),\s*var\(--dream-skin-art\)/); @@ -281,8 +308,9 @@ export async function runRendererRuntimeTest(assetRoot) { assert.equal(home.document.adoptedStyleSheets.length, 1); assert.equal(state.scope.baseState, "home"); assert.equal(state.scope.level, "L1"); - assert.equal(home.rootStyle.values.get("--dream-skin-brand-subtitle"), '"CODEX DREAM SKIN"'); - assert.equal(home.rootStyle.values.get("--dream-skin-status"), '"DREAM SKIN ONLINE"'); + assert.equal(home.rootStyle.values.has("--dream-skin-brand-subtitle"), false); + assert.equal(home.rootStyle.values.has("--dream-skin-status"), false); + assert.equal(home.rootStyle.values.has("--dream-skin-quote"), false); assert.equal(home.rootStyle.values.get("--ds-theme-surface-radius"), "12px"); assert.equal(home.rootStyle.values.get("--ds-theme-surface-opacity"), "1"); assert.equal(home.rootStyle.values.get("--ds-theme-surface-blur"), "0px"); diff --git a/windows/VERSION b/windows/VERSION index 9075be49..eac1e0ad 100644 --- a/windows/VERSION +++ b/windows/VERSION @@ -1 +1 @@ -1.5.5 +1.5.6 diff --git a/windows/assets/dream-skin.css b/windows/assets/dream-skin.css index bd112ec0..96985bc9 100644 --- a/windows/assets/dream-skin.css +++ b/windows/assets/dream-skin.css @@ -59,6 +59,16 @@ --ds-task-immersive-edge: rgb(var(--ds-bg-rgb) / .82); --ds-task-immersive-mid: rgb(var(--ds-bg-rgb) / .74); --ds-task-immersive-far: rgb(var(--ds-bg-rgb) / .60); + /* Wide task routes remain one continuous canvas: artwork stays on the body, + while this veil feathers the reading plane into the atmospheric edge. */ + --ambient-start: 52%; + --ambient-feather: clamp(240px, 24vw, 320px); + --composer-surface: rgb(var(--ds-panel-rgb) / .94); + --reading-veil: linear-gradient(90deg, + rgb(var(--ds-panel-rgb) / .96) 0%, + rgb(var(--ds-panel-rgb) / .96) var(--ambient-start), + rgb(var(--ds-panel-rgb) / .12) calc(var(--ambient-start) + var(--ambient-feather)), + rgb(var(--ds-panel-rgb) / .06) 100%); } html[data-dream-skin="active"][data-dream-shell="light"] { @@ -411,10 +421,11 @@ html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream- html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(main.main-surface):not(:has(main.main-surface [role="main"])) main.main-surface:not(:has([role="main"])) { - background: linear-gradient(90deg, - var(--ds-task-immersive-edge), - var(--ds-task-immersive-mid) 64%, - var(--ds-task-immersive-far)) !important; + overflow: visible !important; + clip-path: none !important; + -webkit-mask-image: none !important; + mask-image: none !important; + background: var(--reading-veil) !important; border: 0 !important; border-radius: 0 !important; box-shadow: none !important; @@ -427,13 +438,12 @@ html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream- html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(main.main-surface):not(:has(main.main-surface [role="main"])) .composer-surface-chrome { - background: var(--ds-immersive-composer-solid) !important; - border: 0 !important; + background: var(--composer-surface) !important; + border: 1px solid var(--ds-line) !important; box-shadow: 0 10px 30px rgb(var(--ds-bg-rgb) / .20), - inset 0 0 0 1px var(--ds-immersive-line), inset 0 1px rgb(var(--ds-text-rgb) / .12) !important; - backdrop-filter: none !important; + backdrop-filter: blur(18px) saturate(108%) !important; } html[data-dream-skin="active"]:is([data-dream-task-mode="ambient"], [data-dream-art-task-mode="ambient"], [data-dream-task-mode="banner"], [data-dream-art-task-mode="banner"])[data-dream-art-wide="true"]:has(main.main-surface):not(:has(main.main-surface [role="main"])) @@ -532,70 +542,24 @@ html[data-dream-skin="active"][data-dream-shell="light"] [role="main"]:has([data } html[data-dream-skin="active"] main.main-surface > header.app-header-tint { - /* Preserve Codex's native fixed header geometry and side-panel controls. */ - background: rgb(var(--ds-panel-rgb) / .90) !important; - border-bottom: 1px solid var(--ds-line) !important; - backdrop-filter: blur(14px) saturate(108%) !important; + /* Preserve the native flex layout, baselines and hit targets without + drawing a theme divider across the titlebar. */ + background: var(--composer-surface) !important; + border: 0 !important; + box-shadow: none !important; + backdrop-filter: none !important; } -/* Decorative chrome lives on the native shell; no injected positioning host is needed. */ +/* Native titlebar controls own the complete toolbar grid and hit targets. + Theme identity stays in the artwork and palette, never positioned labels. */ html[data-dream-skin="active"] - main.main-surface:not(:has([role="main"])) > header.app-header-tint::before { - content: var(--dream-skin-name, "Codex Dream Skin") " · " - var(--dream-skin-brand-subtitle, "CODEX DREAM SKIN"); - position: absolute; - left: 22px; - top: 4px; - z-index: 2; - max-width: min(42%, 360px); - overflow: hidden; - color: var(--ds-accent); - font: 800 11px/1.3 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; - letter-spacing: .03em; - text-overflow: ellipsis; - text-shadow: 0 1px 12px rgb(var(--ds-bg-rgb) / .32); - white-space: nowrap; - pointer-events: none; -} - + main.main-surface:not(:has([role="main"])) > header.app-header-tint::before, html[data-dream-skin="active"] - main.main-surface:not(:has([role="main"])) > header.app-header-tint::after { - content: var(--dream-skin-status, "DREAM SKIN ONLINE"); - position: absolute; - right: 84px; - top: 13px; - z-index: 2; - max-width: 28%; - overflow: hidden; - color: var(--ds-muted); - font: 700 9px/1.2 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; - letter-spacing: .08em; - text-overflow: ellipsis; - text-shadow: 0 1px 10px rgb(var(--ds-bg-rgb) / .32); - white-space: nowrap; - pointer-events: none; -} - + main.main-surface:not(:has([role="main"])) > header.app-header-tint::after, html[data-dream-skin="active"] main.main-surface:has([role="main"])::after { - content: var(--dream-skin-quote, "MAKE SOMETHING WONDERFUL"); - position: absolute; - right: 28px; - bottom: 72px; - z-index: 2; - pointer-events: none; - color: rgb(var(--ds-accent-rgb) / .74); - font: italic 14px/1.2 "Segoe Print", "Comic Sans MS", cursive; - letter-spacing: 0; - text-shadow: 0 0 13px rgb(var(--ds-accent-rgb) / .30); - transform: rotate(-3deg); -} - -html[data-dream-skin="active"][data-dream-shell="light"] - main.main-surface:not(:has([role="main"])) > header.app-header-tint::before, -html[data-dream-skin="active"][data-dream-shell="light"] - main.main-surface:not(:has([role="main"])) > header.app-header-tint::after { - text-shadow: none; + content: none !important; + display: none !important; } /* Windows keeps this native bar outside main; macOS simply has no match. */ @@ -889,15 +853,32 @@ html[data-dream-skin="active"] [role="main"]:has([data-testid="home-icon"]) .gro html[data-dream-skin="active"] [role="main"]:has([data-testid="home-icon"]) .group\/home-suggestions button > span:last-child { align-items: center !important; text-align: center !important; } html[data-dream-skin="active"] .composer-surface-chrome { + position: relative !important; + isolation: isolate !important; + z-index: 4 !important; overflow: visible !important; - border: 1px solid rgb(var(--ds-muted-rgb) / .18) !important; + clip-path: none !important; + -webkit-mask-image: none !important; + mask-image: none !important; + background-clip: padding-box !important; + border: 1px solid var(--ds-line) !important; border-radius: 22px !important; - background: rgb(var(--ds-panel-rgb) / .94) !important; + background: var(--composer-surface) !important; box-shadow: 0 10px 28px rgb(var(--ds-bg-rgb) / .24) !important; - backdrop-filter: blur(16px) saturate(108%) !important; + backdrop-filter: blur(18px) saturate(108%) !important; } -html[data-dream-skin="active"] .composer-surface-chrome::before { content: none !important; } +/* Keep a complete one-pixel boundary even when the native cascade zeroes the + composer's own border width. This layer never participates in input. */ +html[data-dream-skin="active"] .composer-surface-chrome::before { + content: "" !important; + position: absolute !important; + inset: 0 !important; + z-index: 2 !important; + border: 1px solid var(--ds-line) !important; + border-radius: inherit !important; + pointer-events: none !important; +} /* A wide image can carry the home screen too. The native hero remains live, but the artwork is painted once on the window instead of repeated in a card. */ @@ -980,13 +961,12 @@ html[data-dream-skin="active"][data-dream-art-wide="true"] main.main-surface:has } html[data-dream-skin="active"][data-dream-art-wide="true"] .composer-surface-chrome { - background: var(--ds-immersive-composer-solid) !important; - border: 0 !important; + background: var(--composer-surface) !important; + border: 1px solid var(--ds-line) !important; box-shadow: 0 10px 30px rgb(var(--ds-bg-rgb) / .20), - inset 0 0 0 1px var(--ds-immersive-line), inset 0 1px rgb(var(--ds-text-rgb) / .12) !important; - backdrop-filter: none !important; + backdrop-filter: blur(18px) saturate(108%) !important; } html[data-dream-skin="active"][data-dream-shell="light"][data-dream-art-wide="true"] diff --git a/windows/assets/renderer-inject.js b/windows/assets/renderer-inject.js index be799888..7bb91013 100644 --- a/windows/assets/renderer-inject.js +++ b/windows/assets/renderer-inject.js @@ -311,11 +311,9 @@ } setStyleProperty(root, "--dream-skin-name", cssString(THEME.name || "Codex Dream Skin")); setStyleProperty(root, "--dream-skin-tagline", cssString(THEME.tagline || "Make something wonderful.")); - setStyleProperty(root, "--dream-skin-quote", cssString(THEME.quote || "MAKE SOMETHING WONDERFUL")); - setStyleProperty(root, "--dream-skin-brand-subtitle", cssString( - THEME.brandSubtitle || "CODEX DREAM SKIN", - )); - setStyleProperty(root, "--dream-skin-status", cssString(THEME.statusText || "DREAM SKIN ONLINE")); + // Header and lower-chrome slogans were retired because they compete with + // native toolbar controls and the composer. Their old variable names stay + // in THEME_VARIABLES so reinjection removes values from earlier versions. setStyleProperty(root, "--dream-skin-project-prefix", cssString(THEME.projectPrefix || "选择项目 · ")); setStyleProperty(root, "--dream-skin-project-label", cssString(THEME.projectLabel || "◉ 选择项目")); }; diff --git a/windows/scripts/injector.mjs b/windows/scripts/injector.mjs index ebedabf7..bf04480f 100644 --- a/windows/scripts/injector.mjs +++ b/windows/scripts/injector.mjs @@ -39,7 +39,7 @@ const stableTestidLiteral = (testid) => { } return JSON.stringify(`[data-testid="${testid}"]`); }; -const SKIN_VERSION = "1.5.5"; +const SKIN_VERSION = "1.5.6"; const MAX_ART_BYTES = 10 * 1024 * 1024; const MAX_SAFE_CSS_BYTES = 256 * 1024; const STRONG_THEME_AUDIT_MS = 30000; diff --git a/windows/tests/injector-window-readiness.test.mjs b/windows/tests/injector-window-readiness.test.mjs index 4a691b11..39cd8914 100644 --- a/windows/tests/injector-window-readiness.test.mjs +++ b/windows/tests/injector-window-readiness.test.mjs @@ -83,7 +83,7 @@ function makeDomFixture({ }; const window = { __CODEX_DREAM_SKIN_STATE__: { - version: "1.5.5", + version: "1.5.6", themeId: "fixture-theme", revision: "fixture-revision", styleMode: "style",