feat: complete WorkBuddy parity and Windows release workflow

This commit is contained in:
xiaohan.yuan committed 2026-10-18 12:45:21 +08:00
1 parent 143516b3a8
commit d5512df549
434 files changed
+54977 -1854

No files matched your search

+43 -11
View File
@@ -9,6 +9,8 @@ const fs = require('node:fs/promises')
const path = require('node:path')
const assert = require('node:assert/strict')
const EXTERNAL_ARROW_PATH = 'M9.8242 6.6001L9.8242 5.109Q9.8243 3.305 9.7462 2.7323Q9.7081 2.4537 9.6375 2.2354L0.8485 11.0243L0 10.1758L8.789 1.3868Q8.5706 1.3162 8.292 1.2782Q7.7193 1.2 5.9153 1.2001L4.4243 1.2001L4.4243 0L5.9152 0Q7.8008 -0 8.4543 0.0892Q9.5761 0.2423 10.179 0.8453Q10.782 1.4482 10.9351 2.57Q11.0243 3.2235 11.0243 5.1091L11.0243 6.6001L9.8242 6.6001Z'
if (!process.versions.electron) {
;(async () => {
const directory = await fs.mkdtemp(path.resolve('.tmp/about-help-settings-'))
@@ -85,13 +87,18 @@ if (!process.versions.electron) {
section: panel?.dataset.aboutHelpPanel,
card: rect(document.querySelector('.help-feedback-panel__card')),
rows: [...document.querySelectorAll('.help-feedback-panel__card-row')].map(row => ({
rect: rect(row),
id: row.id, rect: rect(row),
labelTag: row.querySelector('.help-feedback-panel__card-label')?.tagName,
label: row.querySelector('.help-feedback-panel__card-label')?.childNodes[0]?.textContent?.trim(),
value: row.querySelector('.help-feedback-panel__card-value')?.textContent?.trim()
})),
buttons: buttons.map(button => ({ text: button.textContent.trim(), rect: rect(button), disabled: button.disabled,
ariaDisabled: button.getAttribute('aria-disabled'),
title: button.getAttribute('title'), arrow: !!button.querySelector('.wb-button__icon svg') })),
title: button.getAttribute('title'), arrow: !!button.querySelector('.wb-button__icon svg'),
iconWrapperClass: button.querySelector('.wb-button__icon')?.className ?? null,
iconFill: button.querySelector('.wb-button__icon svg')?.getAttribute('fill') ?? null,
path: button.querySelector('.wb-button__icon path')?.getAttribute('d') ?? null,
transform: button.querySelector('.wb-button__icon path')?.getAttribute('transform') ?? null })),
follow: rect(document.querySelector('.help-feedback-panel__follow-card')),
followTitle: (() => { const node = document.querySelector('.help-feedback-panel__follow-title'); return node ? { ...rect(node), text: node.textContent.trim() } : null })(),
qrList: rect(document.querySelector('.help-feedback-panel__qr-list')),
@@ -101,8 +108,13 @@ if (!process.versions.electron) {
placeholder: item.querySelector('.help-feedback-panel__qr--placeholder')?.textContent?.trim()
})),
footer: rect(document.querySelector('.help-feedback-panel__footer')),
footerDivider: (() => { const node = document.querySelector('.help-feedback-panel__footer-divider')
return node ? { rect: rect(node), className: node.className, fontSize: getComputedStyle(node).fontSize,
lineHeight: getComputedStyle(node).lineHeight } : null })(),
footerLinks: [...document.querySelectorAll('.help-feedback-panel__footer-link')].map(link => ({
text: link.textContent.trim(), rect: rect(link), disabled: link.disabled, color: getComputedStyle(link).color })),
text: link.textContent.trim(), rect: rect(link), disabled: link.disabled, className: link.className,
color: getComputedStyle(link).color, fontSize: getComputedStyle(link).fontSize,
lineHeight: getComputedStyle(link).lineHeight })),
anchors: [...document.querySelectorAll('a')].map(anchor => anchor.getAttribute('href')).filter(Boolean),
cardBackground: panel ? getComputedStyle(document.querySelector('.help-feedback-panel__card')).backgroundColor : null,
labelColor: (() => { const node = document.querySelector('.help-feedback-panel__card-label'); return node ? getComputedStyle(node).color : null })(),
@@ -133,31 +145,47 @@ if (!process.versions.electron) {
const light = await read(layoutSource, settings)
snapshots.aboutLight = light
await fs.writeFile(path.join(directory, 'about-light.png'), (await settings.webContents.capturePage()).toPNG())
check('关于 panel keeps the recovered 638x620 box at 232,40',
[near(light.panel.x, 232), near(light.panel.y, 40), near(light.panel.width, 638), near(light.panel.height, 620)], [true, true, true, true])
check('关于 top card keeps 638x108 with two 606x32 rows',
[near(light.card.width, 638), near(light.card.height, 108),
check('关于 adds the requested metadata row while keeping 606x32 row geometry',
[near(light.card.width, 638), near(light.card.height, 160),
near(light.rows[0].rect.y, 52), near(light.rows[0].rect.width, 606), near(light.rows[0].rect.height, 32),
near(light.rows[1].rect.y, 104)], [true, true, true, true, true, true])
check('关于 rows keep the recovered ids and span labels',
light.rows.map(row => [row.id, row.labelTag]),
[['settings-about-version', 'SPAN'], ['settings-about-product', 'SPAN'], ['settings-about-model-metadata', 'SPAN']])
check('关于 rows show the real YCode version and the recovered labels',
[light.rows[0].label, light.rows[0].value, light.rows[1].label],
['当前版本', `v${appInfo.version}`, '关于 YCode'])
check('关于 action buttons keep 82x32 / 102x32 and stay explicitly disabled',
[light.buttons.map(button => button.text), near(light.buttons[0].rect.x, 772), near(light.buttons[0].rect.width, 82),
[light.buttons.slice(0, 2).map(button => button.text), near(light.buttons[0].rect.x, 772), near(light.buttons[0].rect.width, 82),
near(light.buttons[1].rect.x, 752), near(light.buttons[1].rect.width, 102),
light.buttons.every(button => button.ariaDisabled === 'true' && near(button.rect.height, 32)),
light.buttons.slice(0, 2).every(button => button.ariaDisabled === 'true' && near(button.rect.height, 32)),
light.buttons[0].title, light.buttons[1].title, light.buttons[1].arrow],
[['检查更新', '前往官网'], true, true, true, true, true, '暂未接入', '尚未配置', true])
check('关于 metadata update is enabled in its own row', [light.buttons[2].text, light.buttons[2].ariaDisabled !== 'true', near(light.rows[2].rect.y, 156), near(light.rows[2].rect.height, 32)], ['更新元数据', true, true, true])
check('关于 external arrow keeps the exact REA wrapper, path and transform',
[light.buttons[1].iconWrapperClass, light.buttons[1].iconFill, light.buttons[1].path, light.buttons[1].transform],
['wb-button__icon wb-button__icon--right', 'currentColor', EXTERNAL_ARROW_PATH, 'matrix(1 0 0 1 2.57586 2.39996)'])
check('关注卡片 keeps 638x226 with the recovered title and three 120x120 placeholder QRs',
[near(light.follow.y, 164), near(light.follow.width, 638), near(light.follow.height, 226),
[near(light.follow.y, 216), near(light.follow.width, 638), near(light.follow.height, 226),
light.followTitle.text, light.qrList.width, light.qrItems.map(item => item.label),
light.qrItems.every(item => near(item.rect.width, 120) && near(item.rect.height, 120) && item.placeholder === '尚未配置')],
[true, true, true, '关注我们,获取实用技巧与产品最新动态', 408, ['公众号', '视频号', '腾讯频道'], true])
check('关于 footer keeps the recovered 44px row with two 12px disabled links',
[near(light.footer.y, 616), near(light.footer.width, 638), near(light.footer.height, 44),
light.footerLinks.map(link => link.text), light.footerLinks.every(link => link.disabled && near(link.rect.height, 20)),
light.footerLinks.every(link => link.className.includes('wb-button--link') && link.className.includes('wb-button--small')),
light.footerLinks[0].color, near(light.footerLinks[0].rect.x, 489.438, 0.5), near(light.footerLinks[1].rect.x, 564.563, 0.5)],
[true, true, true, ['隐私政策', '服务协议'], true, 'rgba(0, 0, 0, 0.3)', true, true])
[true, true, true, ['隐私政策', '服务协议'], true, true, 'rgba(0, 0, 0, 0.3)', true, true])
check('关于 footer divider keeps the recovered class and 3.125x17 glyph box',
[light.footerDivider?.className, near(light.footerDivider?.rect.width, 3.125, 0.25),
near(light.footerDivider?.rect.height, 17, 0.75), near(light.footerDivider?.rect.x, 549.438, 0.5)],
['help-feedback-panel__footer-divider', true, true, true])
check('关于 footer keeps the recovered 12/20 link labels and 13/normal divider glyph',
[light.footerLinks.map(link => [link.fontSize, link.lineHeight]), light.footerDivider?.fontSize, light.footerDivider?.lineHeight],
[[['12px', '20px'], ['12px', '20px']], '13px', 'normal'])
check('关于 page contains no anchor links (no WorkBuddy jumps)', light.anchors, [])
await step('help-settings')
@@ -176,6 +204,9 @@ if (!process.versions.electron) {
near(help.buttons[1].rect.x, 752), near(help.buttons[1].rect.width, 102),
help.buttons.every(button => button.ariaDisabled === 'true' && button.title === '尚未配置'), help.buttons[1].arrow],
[['意见反馈', '帮助文档'], ['填写反馈', '查看文档'], true, true, true, true, true, true])
check('获取帮助 rows keep the recovered ids and span labels',
help.rows.map(row => [row.id, row.labelTag]),
[['settings-get-help-feedback', 'SPAN'], ['settings-get-help-docs', 'SPAN']])
check('获取帮助 has no QR block, footer or anchor links',
[help.follow, help.footer, help.anchors], [null, null, []])
@@ -188,11 +219,12 @@ if (!process.versions.electron) {
await wait(`document.documentElement.dataset.theme==='dark'&&!!document.querySelector('.help-feedback-panel')`, 'dark about panel', settings)
const dark = await read(layoutSource, settings)
snapshots.aboutDark = dark
await fs.writeFile(path.join(directory, 'about-dark.png'), (await settings.webContents.capturePage()).toPNG())
check('dark theme keeps the recovered card, text, button and QR surfaces',
[dark.cardBackground, dark.labelColor, dark.buttonBackground, dark.buttonBorder, dark.qrBackground],
['rgb(31, 31, 31)', 'rgb(242, 243, 245)', 'rgb(38, 38, 38)', 'rgb(61, 61, 61)', 'rgb(41, 41, 41)'])
check('dark theme keeps every recovered geometry',
[near(dark.panel.width, 638), near(dark.panel.height, 620), near(dark.card.height, 108),
check('dark theme keeps the row geometry and requested metadata extension',
[near(dark.panel.width, 638), near(dark.panel.height, 620), near(dark.card.height, 160),
near(dark.follow.height, 226), dark.qrItems.every(item => near(item.rect.width, 120))], [true, true, true, true, true])
await openSettings('appearance')
await wait('!!document.querySelector(".appearance-card")', 'appearance panel again', settings)