fix(desktop): refine DMG installer layout

Use a compact 640x420 branded background and reposition the Finder icons so the installer opens without excess canvas or scrollbars. Keep key content clear when hidden DMG resources are visible.

Checks: node --test test/packaging/package-security.test.cjs; npm run dist; npx electron-builder --mac dmg; hdiutil verify; codesign --verify --deep --strict; git diff --check
This commit is contained in:
Ryder Sun committed 2026-09-10 13:11:58 +08:00
1 parent 717d21373d
commit 38c480575d
5 files changed
+70 -15

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 KiB

+55
View File
@@ -0,0 +1,55 @@
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="420" viewBox="0 0 640 420">
<defs>
<linearGradient id="surface" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#17191c"/>
<stop offset="1" stop-color="#0d0f11"/>
</linearGradient>
<radialGradient id="leftGlow" cx="0" cy="0.5" r="1">
<stop offset="0" stop-color="#ff725f" stop-opacity="0.14"/>
<stop offset="1" stop-color="#ff725f" stop-opacity="0"/>
</radialGradient>
<radialGradient id="rightGlow" cx="1" cy="0.5" r="1">
<stop offset="0" stop-color="#67d5de" stop-opacity="0.12"/>
<stop offset="1" stop-color="#67d5de" stop-opacity="0"/>
</radialGradient>
<filter id="softShadow" x="-40%" y="-40%" width="180%" height="180%">
<feGaussianBlur stdDeviation="12"/>
</filter>
</defs>
<rect width="640" height="420" fill="url(#surface)"/>
<rect width="320" height="420" fill="url(#leftGlow)"/>
<rect x="320" width="320" height="420" fill="url(#rightGlow)"/>
<g fill="none" stroke="#ffffff" stroke-opacity="0.055">
<path d="M0 74H112L126 88H244L258 74H640"/>
<path d="M0 82H104L122 100H250L268 82H640"/>
</g>
<g font-family="-apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif">
<g transform="translate(438 24)">
<rect width="34" height="34" rx="8" fill="#f5f6f7"/>
<path d="M7 24V13.5C7 9.8 12.2 8.6 13.9 12V24M13.9 16.2C13.9 12.1 19.6 10.8 21.3 14.6V24" fill="none" stroke="#121417" stroke-width="3.7" stroke-linecap="round"/>
<circle cx="27.2" cy="24" r="2.3" fill="#ff705d"/>
<text x="46" y="25" fill="#f7f7f8" font-size="22" font-weight="650">Meldwork</text>
</g>
<text x="465" y="145" fill="#c8ccd0" font-size="14" font-weight="600" text-anchor="middle">Drag to Applications</text>
</g>
<ellipse cx="175" cy="253" rx="64" ry="64" fill="#000000" fill-opacity="0.34" filter="url(#softShadow)"/>
<ellipse cx="465" cy="253" rx="64" ry="64" fill="#000000" fill-opacity="0.34" filter="url(#softShadow)"/>
<circle cx="175" cy="245" r="58" fill="#0b0d0f" fill-opacity="0.3" stroke="#ffffff" stroke-opacity="0.08"/>
<circle cx="465" cy="245" r="58" fill="#0b0d0f" fill-opacity="0.3" stroke="#ffffff" stroke-opacity="0.08"/>
<g transform="translate(275 245)" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path d="M0 0H82" stroke="#ffffff" stroke-opacity="0.16" stroke-width="2"/>
<path d="M70 -8L82 0L70 8" stroke="#ff705d" stroke-width="2.5"/>
<circle cx="10" r="2" fill="#ff705d" stroke="none"/>
<circle cx="26" r="2" fill="#f3c07b" stroke="none"/>
<circle cx="42" r="2" fill="#d9e5df" stroke="none"/>
<circle cx="58" r="2" fill="#67d5de" stroke="none"/>
</g>
<rect x="24" y="396" width="592" height="1" fill="#ffffff" fill-opacity="0.05"/>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 968 KiB

+8 -8
View File
@@ -70,21 +70,21 @@
]
},
"dmg": {
"background": "build/dmg-background-ai-v2.png",
"background": "build/dmg-background-ai-v3.png",
"window": {
"width": 540,
"height": 380
"width": 640,
"height": 420
},
"iconSize": 128,
"iconSize": 112,
"contents": [
{
"x": 145,
"y": 210,
"x": 175,
"y": 245,
"type": "file"
},
{
"x": 395,
"y": 210,
"x": 465,
"y": 245,
"type": "link",
"path": "/Applications"
}
@@ -36,15 +36,15 @@ test('packaged application carries the open-source and commercial licensing noti
test('DMG uses the branded background and fixed drag layout', () => {
const dmg = desktopPackage.build.dmg
assert.equal(dmg.background, 'build/dmg-background-ai-v2.png')
assert.deepEqual(dmg.window, { width: 540, height: 380 })
assert.equal(dmg.iconSize, 128)
assert.equal(dmg.background, 'build/dmg-background-ai-v3.png')
assert.deepEqual(dmg.window, { width: 640, height: 420 })
assert.equal(dmg.iconSize, 112)
assert.deepEqual(dmg.contents, [
{ x: 145, y: 210, type: 'file' },
{ x: 395, y: 210, type: 'link', path: '/Applications' },
{ x: 175, y: 245, type: 'file' },
{ x: 465, y: 245, type: 'link', path: '/Applications' },
])
const background = fs.readFileSync(path.join(__dirname, '..', '..', dmg.background))
assert.equal(background.readUInt32BE(16), 540)
assert.equal(background.readUInt32BE(20), 380)
assert.equal(background.readUInt32BE(16), 640)
assert.equal(background.readUInt32BE(20), 420)
})