Skip to content

Commit a2964e2

Browse files
committed
fix(desktop): paint an opaque window on every platform
The macOS window used vibrancy over a transparent background, so the dark palette rendered on a translucent light surface its secondary colours were never designed for. Drop vibrancy and transparency and paint the palette's own background colour, keeping the per-platform window chrome.
1 parent 3cdf7b3 commit a2964e2

2 files changed

Lines changed: 44 additions & 43 deletions

File tree

apps/desktop/src/main.ts

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -195,28 +195,17 @@ async function createMainWindow(): Promise<BrowserWindow> {
195195
autoHideMenuBar: true,
196196
frame: process.platform === 'win32',
197197
titleBarStyle: process.platform === 'darwin' ? 'hiddenInset' : 'hidden',
198-
...(process.platform === 'darwin' ? {} : {
199-
titleBarOverlay: {
200-
color: '#00000000',
201-
symbolColor: '#7f858f',
202-
height: 44,
203-
},
204-
}),
205-
...(process.platform === 'darwin' ? {
206-
trafficLightPosition: { x: 16, y: 18 },
207-
vibrancy: 'sidebar' as const,
208-
visualEffectState: 'followWindow' as const,
209-
} : {}),
210-
// Windows uses an opaque window so theme colors do not blend with desktop wallpaper.
211-
...(process.platform === 'win32' ? {
212-
backgroundColor: '#0d1117',
213-
hasShadow: true,
214-
roundedCorners: true,
215-
thickFrame: true,
216-
} : {
217-
transparent: true,
218-
backgroundColor: '#00000000',
219-
}),
198+
titleBarOverlay: process.platform === 'darwin' ? undefined : {
199+
color: '#00000000',
200+
symbolColor: '#7f858f',
201+
height: 44,
202+
},
203+
trafficLightPosition: process.platform === 'darwin' ? { x: 16, y: 18 } : undefined,
204+
// Use an opaque window so theme colors do not blend with desktop wallpaper.
205+
backgroundColor: '#0d1117',
206+
hasShadow: process.platform === 'win32' ? true : undefined,
207+
roundedCorners: process.platform === 'win32' ? true : undefined,
208+
thickFrame: process.platform === 'win32' ? true : undefined,
220209
title: APP_NAME,
221210
webPreferences: {
222211
contextIsolation: true,

apps/desktop/tests/window-appearance.spec.ts

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,36 +8,48 @@ const desktopRoot = resolve(import.meta.dirname, '..')
88
const mainSource = readFileSync(resolve(desktopRoot, 'src', 'main.ts'), 'utf8')
99

1010
describe('desktop window appearance configuration', () => {
11-
it('keeps Windows opaque and non-Windows windows transparent', () => {
11+
it('keeps the main window opaque on every platform', () => {
1212
const backgroundMaterialMatches = [...mainSource.matchAll(/backgroundMaterial/gu)]
13-
const win32BranchMatches = [...mainSource.matchAll(
14-
/\.\.\.\(process\.platform === 'win32' \? \{([\s\S]*?)\} : \{\s*transparent: true,/gu,
15-
)]
16-
const nonWin32BranchMatches = [...mainSource.matchAll(
17-
/\} : \{\s*transparent: true,[\s\S]*?\}\),\s*title:/gu,
13+
const mainWindowOptionMatches = [...mainSource.matchAll(
14+
/const window = new BrowserWindow\(\{([\s\S]*?)\n \}\)/gu,
1815
)]
1916

2017
expect(backgroundMaterialMatches).toHaveLength(0)
21-
expect(win32BranchMatches).toHaveLength(1)
22-
expect(nonWin32BranchMatches).toHaveLength(1)
18+
expect(mainWindowOptionMatches).toHaveLength(1)
2319

24-
const win32Branch = win32BranchMatches[0]![1]!
25-
const opaqueColorMatches = [...win32Branch.matchAll(/backgroundColor:\s*'#[0-9a-fA-F]{6}'/gu)]
26-
const alphaColorMatches = [...win32Branch.matchAll(/#[0-9a-fA-F]{8}/gu)]
27-
const hasShadowMatches = [...win32Branch.matchAll(/hasShadow:\s*true/gu)]
28-
const roundedCornersMatches = [...win32Branch.matchAll(/roundedCorners:\s*true/gu)]
29-
const thickFrameMatches = [...win32Branch.matchAll(/thickFrame:\s*true/gu)]
20+
const mainWindowOptions = mainWindowOptionMatches[0]![1]!
21+
const vibrancyMatches = [...mainWindowOptions.matchAll(/vibrancy\s*:/gu)]
22+
const visualEffectStateMatches = [...mainWindowOptions.matchAll(/visualEffectState\s*:/gu)]
23+
const transparentMatches = [...mainWindowOptions.matchAll(/transparent:\s*true/gu)]
24+
const backgroundColorMatches = [...mainWindowOptions.matchAll(
25+
/backgroundColor:\s*'(#[0-9a-fA-F]{6}(?:[0-9a-fA-F]{2})?)'/gu,
26+
)]
27+
const transparentBackgroundMatches = backgroundColorMatches.filter(
28+
(match) => match[1]!.length === 9 && match[1]!.endsWith('00'),
29+
)
30+
const hasShadowMatches = [...mainWindowOptions.matchAll(
31+
/hasShadow:\s*process\.platform === 'win32' \? true : undefined/gu,
32+
)]
33+
const roundedCornersMatches = [...mainWindowOptions.matchAll(
34+
/roundedCorners:\s*process\.platform === 'win32' \? true : undefined/gu,
35+
)]
36+
const thickFrameMatches = [...mainWindowOptions.matchAll(
37+
/thickFrame:\s*process\.platform === 'win32' \? true : undefined/gu,
38+
)]
3039

31-
expect(opaqueColorMatches).toHaveLength(1)
32-
expect(alphaColorMatches).toHaveLength(0)
40+
expect(vibrancyMatches).toHaveLength(0)
41+
expect(visualEffectStateMatches).toHaveLength(0)
42+
expect(transparentMatches).toHaveLength(0)
43+
expect(backgroundColorMatches).toHaveLength(1)
44+
expect(backgroundColorMatches[0]![1]).not.toBe('#00000000')
45+
expect(transparentBackgroundMatches).toHaveLength(0)
3346
expect(hasShadowMatches).toHaveLength(1)
3447
expect(roundedCornersMatches).toHaveLength(1)
3548
expect(thickFrameMatches).toHaveLength(1)
3649

37-
expect(win32Branch).toContain('backgroundColor')
38-
expect(nonWin32BranchMatches[0]![0]).toContain('transparent: true')
39-
expect(win32Branch).toContain('hasShadow')
40-
expect(win32Branch).toContain('roundedCorners')
41-
expect(win32Branch).toContain('thickFrame')
50+
expect(mainWindowOptions).toContain('backgroundColor')
51+
expect(mainWindowOptions).toContain('hasShadow')
52+
expect(mainWindowOptions).toContain('roundedCorners')
53+
expect(mainWindowOptions).toContain('thickFrame')
4254
})
4355
})

0 commit comments

Comments
 (0)