From d4dcaf38b7bef02f4b7d60b9b355cdc6c70a9571 Mon Sep 17 00:00:00 2001 From: NimBold Date: Sun, 6 Sep 2026 07:54:22 +0330 Subject: [PATCH] fix(window): restore clear Windows frame contours - Apply stronger active and inactive renderer contours only on Windows. - Keep native shadows disabled for main and Properties windows to prevent rectangular corner bleed. - Lock platform configuration and maximized-frame invariants with regression tests. --- scripts/window-frame.node-test.js | 79 +++++++++++++++++++++++++++++++ src/index.css | 18 +++++++ 2 files changed, 97 insertions(+) create mode 100644 scripts/window-frame.node-test.js diff --git a/scripts/window-frame.node-test.js b/scripts/window-frame.node-test.js new file mode 100644 index 0000000..079a856 --- /dev/null +++ b/scripts/window-frame.node-test.js @@ -0,0 +1,79 @@ +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import test from 'node:test'; + +const windowStyles = fs.readFileSync('src/index.css', 'utf8'); +const propertiesWindowSource = fs.readFileSync('src-tauri/src/properties_window.rs', 'utf8'); +const mainWindowSource = fs.readFileSync('src-tauri/src/lib.rs', 'utf8'); +const windowsConfiguration = JSON.parse( + fs.readFileSync('src-tauri/tauri.windows.conf.json', 'utf8') +); + +const cssBlock = selector => { + const opening = `${selector} {`; + const start = windowStyles.indexOf(opening); + assert.notEqual(start, -1, `${selector} should exist`); + const end = windowStyles.indexOf('}', start + opening.length); + assert.notEqual(end, -1, `${selector} should have a closing brace`); + return windowStyles.slice(start, end + 1); +}; + +test('Windows native shadows remain disabled for the main and Properties windows', () => { + assert.deepEqual( + { + transparent: windowsConfiguration.app.windows[0].transparent, + decorations: windowsConfiguration.app.windows[0].decorations, + shadow: windowsConfiguration.app.windows[0].shadow, + }, + { transparent: true, decorations: false, shadow: false } + ); + assert.match( + mainWindowSource, + /let main_window_config = app\s*\.config\(\)\s*\.app\s*\.windows[\s\S]*?\.find\(\|window\| window\.label == "main"\)/ + ); + assert.match( + mainWindowSource, + /WebviewWindowBuilder::from_config\(\s*app\.handle\(\),\s*&main_window_config,\s*\)/ + ); + assert.match( + propertiesWindowSource, + /#\[cfg\(target_os = "windows"\)\]\s*let builder = builder\.transparent\(true\)\.shadow\(false\);/ + ); +}); + +test('Windows selects stronger renderer-owned contours for every theme', () => { + const expectedTokens = [ + [':root', '220 12% 30% / 0.60', '220 10% 30% / 0.18'], + ['.theme-light', '220 12% 30% / 0.60', '220 10% 30% / 0.18'], + ['.theme-dark', '0 0% 100% / 0.35', '0 0% 100% / 0.14'], + ['.theme-dracula', '228 14% 84% / 0.45', '228 14% 84% / 0.18'], + ['.theme-nord', '218 27% 88% / 0.45', '218 27% 88% / 0.18'], + ]; + + for (const [selector, active, inactive] of expectedTokens) { + const block = cssBlock(selector); + assert.match(block, new RegExp(`--window-frame-windows-active: ${active.replace('.', '\\.')}\\s*;`)); + assert.match(block, new RegExp(`--window-frame-windows-inactive: ${inactive.replace('.', '\\.')}\\s*;`)); + } + + const windowsBlock = cssBlock('html[data-platform="windows"]'); + assert.match( + windowsBlock, + /--window-frame-active:\s*var\(--window-frame-windows-active\);/ + ); + assert.match( + windowsBlock, + /--window-frame-inactive:\s*var\(--window-frame-windows-inactive\);/ + ); +}); + +test('maximized Windows shells remain square and borderless', () => { + assert.match( + windowStyles, + /html\[data-platform="windows"\] :is\(\.app-shell, \.properties-window-shell\)\[data-window-maximized="true"\] \{\s*border-color:\s*transparent;/ + ); + assert.match( + windowStyles, + /html\[data-platform="linux"\] :is\(\.app-shell, \.properties-window-shell\),\s*html\[data-platform="windows"\] :is\(\.app-shell, \.properties-window-shell\)\[data-window-maximized="true"\] \{\s*border-radius:\s*0;/ + ); +}); diff --git a/src/index.css b/src/index.css index 85a5ec5..13d5370 100644 --- a/src/index.css +++ b/src/index.css @@ -29,6 +29,8 @@ --shadow-color: 220 10% 20% / 0.1; --window-frame-active: 220 12% 30% / 0.22; --window-frame-inactive: 220 10% 30% / 0.08; + --window-frame-windows-active: 220 12% 30% / 0.60; + --window-frame-windows-inactive: 220 10% 30% / 0.18; --sidebar-shell-bg: 0 0% 92%; --sidebar-panel-bg: 0 0% 96%; --workspace-bg: 0 0% 98%; @@ -77,6 +79,8 @@ --shadow-color: 220 10% 20% / 0.1; --window-frame-active: 220 12% 30% / 0.22; --window-frame-inactive: 220 10% 30% / 0.08; + --window-frame-windows-active: 220 12% 30% / 0.60; + --window-frame-windows-inactive: 220 10% 30% / 0.18; --sidebar-shell-bg: 0 0% 92%; --sidebar-panel-bg: 0 0% 96%; --workspace-bg: 0 0% 98%; @@ -109,6 +113,8 @@ --shadow-color: 0 0% 0% / 0.30; --window-frame-active: 0 0% 100% / 0.14; --window-frame-inactive: 0 0% 100% / 0.06; + --window-frame-windows-active: 0 0% 100% / 0.35; + --window-frame-windows-inactive: 0 0% 100% / 0.14; --status-completed: 136 62% 48%; --status-paused: 0 0% 56%; --status-downloading: 211 100% 56%; @@ -158,6 +164,8 @@ --shadow-color: 231 20% 8% / 0.35; --window-frame-active: 228 14% 84% / 0.18; --window-frame-inactive: 228 14% 84% / 0.08; + --window-frame-windows-active: 228 14% 84% / 0.45; + --window-frame-windows-inactive: 228 14% 84% / 0.18; --status-completed: 135 94% 65%; --status-paused: 65 92% 76%; --status-downloading: 191 97% 77%; @@ -207,6 +215,8 @@ --shadow-color: 220 25% 10% / 0.34; --window-frame-active: 218 27% 88% / 0.18; --window-frame-inactive: 218 27% 88% / 0.08; + --window-frame-windows-active: 218 27% 88% / 0.45; + --window-frame-windows-inactive: 218 27% 88% / 0.18; --status-completed: 92 28% 65%; --status-paused: 40 71% 73%; --status-downloading: 193 43% 67%; @@ -232,6 +242,14 @@ --add-shadow: 220 28% 10% / 0.30; } +/* Windows cannot safely combine Tao's native undecorated shadow with this + per-pixel-transparent rounded surface. Select the stronger renderer-owned + contour tokens without increasing the macOS or Linux frame contrast. */ +html[data-platform="windows"] { + --window-frame-active: var(--window-frame-windows-active); + --window-frame-inactive: var(--window-frame-windows-inactive); +} + @theme { --color-sidebar-bg: hsl(var(--sidebar-bg)); --color-sidebar-glass: hsl(var(--sidebar-glass));