fix(web): make the welcome notice scan-first

This commit is contained in:
NI0317
2026-07-30 22:58:52 +08:00
parent 564ba0df72
commit 04f8b30db1
10 changed files with 150 additions and 62 deletions

View File

@@ -24,7 +24,7 @@
.dialog {
position: relative;
z-index: 1;
width: min(640px, calc(100vw - 48px));
width: min(600px, calc(100vw - 48px));
max-height: calc(100vh - 128px);
padding: 32px;
box-sizing: border-box;
@@ -40,21 +40,65 @@
font-size: 20px;
line-height: 30px;
font-weight: 600;
letter-spacing: -0.01em;
}
.copy {
display: flex;
flex-direction: column;
gap: 14px;
margin-top: 18px;
font-size: 14px;
line-height: 24px;
.lead,
.closing,
.quote,
.feedback p,
.error {
margin: 0;
}
.lead {
margin-top: 12px;
font-size: 16px;
line-height: 25px;
color: var(--dsw-alias-label-secondary);
}
.copy p,
.error {
margin: 0;
.feedback {
margin-top: 20px;
padding: 16px 18px;
border-radius: 14px;
border: 1px solid var(--dsw-alias-border-l1);
background: var(--dsw-alias-bg-module-platform);
font-size: 15px;
line-height: 24px;
}
.feedback strong {
display: block;
margin-bottom: 4px;
font-weight: 600;
}
.feedback p,
.closing {
color: var(--dsw-alias-label-secondary);
}
.closing {
margin-top: 16px;
font-size: 15px;
line-height: 24px;
}
.quote {
font-size: 14px;
line-height: 22px;
color: var(--dsw-alias-label-secondary);
}
.footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 24px;
margin-top: 24px;
padding-top: 20px;
border-top: 1px solid var(--dsw-alias-border-l1);
}
.error {
@@ -65,6 +109,32 @@
}
.primary {
width: 100%;
margin-top: 24px;
min-width: 104px;
transition: transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
}
.primary:active:not(:disabled) {
transform: scale(0.97);
}
@media (prefers-reduced-motion: reduce) {
.primary {
transition: none;
}
}
@media (max-width: 560px) {
.dialog {
padding: 24px;
}
.footer {
align-items: stretch;
flex-direction: column;
gap: 14px;
}
.primary {
width: 100%;
}
}

View File

@@ -47,22 +47,26 @@ export function WelcomeNotice(props: WelcomeNoticeProps): ReactNode {
<div className={css.overlay} role="presentation">
<div className={css.mask} aria-hidden="true" />
<section className={css.dialog} role="dialog" aria-modal="true" aria-labelledby="welcome-notice-title">
<h2 id="welcome-notice-title" className={css.title}>{t('welcome.paragraph.0')}</h2>
<div className={css.copy}>
<p>{t('welcome.paragraph.1')}</p>
<p>{t('welcome.paragraph.2')}</p>
<p>{t('welcome.paragraph.3')}</p>
<h2 id="welcome-notice-title" className={css.title}>{t('welcome.title')}</h2>
<p className={css.lead}>{t('welcome.lead')}</p>
<div className={css.feedback}>
<strong>{t('welcome.feedbackTitle')}</strong>
<p>{t('welcome.feedbackBody')}</p>
</div>
<p className={css.closing}>{t('welcome.closing')}</p>
{state.error === null ? null : <p className={css.error} role="alert">{t('welcome.error')}</p>}
<Button
variant="primary"
className={css.primary}
autoFocus
disabled={state.status === 'saving'}
onClick={() => { void acknowledge() }}
>
{t('welcome.continue')}
</Button>
<div className={css.footer}>
<p className={css.quote}>{t('welcome.quote')}</p>
<Button
variant="primary"
className={css.primary}
autoFocus
disabled={state.status === 'saving'}
onClick={() => { void acknowledge() }}
>
{t('welcome.continue')}
</Button>
</div>
</section>
</div>
)

View File

@@ -26,10 +26,12 @@ export const zh: LocaleDict = {
'permission.title': '权限',
'permission.desc': '选择默认权限模式',
'toolcall.title': '工具调用',
'welcome.paragraph.0': WELCOME_NOTICE_COPY.zh.paragraphs[0],
'welcome.paragraph.1': WELCOME_NOTICE_COPY.zh.paragraphs[1],
'welcome.paragraph.2': WELCOME_NOTICE_COPY.zh.paragraphs[2],
'welcome.paragraph.3': WELCOME_NOTICE_COPY.zh.paragraphs[3],
'welcome.title': WELCOME_NOTICE_COPY.zh.title,
'welcome.lead': WELCOME_NOTICE_COPY.zh.lead,
'welcome.feedbackTitle': WELCOME_NOTICE_COPY.zh.feedbackTitle,
'welcome.feedbackBody': WELCOME_NOTICE_COPY.zh.feedbackBody,
'welcome.closing': WELCOME_NOTICE_COPY.zh.closing,
'welcome.quote': WELCOME_NOTICE_COPY.zh.quote,
'welcome.continue': WELCOME_NOTICE_COPY.zh.continueLabel,
'welcome.error': '暂时无法保存确认状态,请重试。',
}
@@ -44,10 +46,12 @@ export const en: LocaleDict = {
'permission.title': 'Permission',
'permission.desc': 'Choose default permission mode',
'toolcall.title': 'Tool Call',
'welcome.paragraph.0': WELCOME_NOTICE_COPY.en.paragraphs[0],
'welcome.paragraph.1': WELCOME_NOTICE_COPY.en.paragraphs[1],
'welcome.paragraph.2': WELCOME_NOTICE_COPY.en.paragraphs[2],
'welcome.paragraph.3': WELCOME_NOTICE_COPY.en.paragraphs[3],
'welcome.title': WELCOME_NOTICE_COPY.en.title,
'welcome.lead': WELCOME_NOTICE_COPY.en.lead,
'welcome.feedbackTitle': WELCOME_NOTICE_COPY.en.feedbackTitle,
'welcome.feedbackBody': WELCOME_NOTICE_COPY.en.feedbackBody,
'welcome.closing': WELCOME_NOTICE_COPY.en.closing,
'welcome.quote': WELCOME_NOTICE_COPY.en.quote,
'welcome.continue': WELCOME_NOTICE_COPY.en.continueLabel,
'welcome.error': 'The acknowledgement could not be saved. Please try again.',
}

View File

@@ -8,26 +8,26 @@ export const WELCOME_NOTICE_ACK_FIELD = 'welcomeNoticeVersion'
* Bump only when the notice changes materially and every user should see it
* again. The acknowledgement is compared for exact equality.
*/
export const WELCOME_NOTICE_VERSION = '2026-07-30.1'
export const WELCOME_NOTICE_VERSION = '2026-07-30.2'
/** The complete editable welcome notice in both supported GUI locales. */
export const WELCOME_NOTICE_COPY = {
zh: {
paragraphs: [
'感谢您愿意拨冗试用 DeepSeek Harness。',
'目前的版本仍处于内部测试阶段,有些功能仍待完善,有些体验难免粗粝。',
'“如切如磋,如琢如磨。” 产品的成长,离不开一次次真实的碰撞与坦诚的反馈。您在真实使用中暴露的问题,也可能促使我们重新审视,甚至推翻已有的设计。',
'我们尤其希望听见那些失败、困惑与不顺手的时刻——如果它未能帮到您,甚至反而为工作平添了麻烦,请在企业微信群中留言,将使用感受告诉我们。每一条反馈,都会帮助我们把它打磨得更好。',
],
title: '内测声明',
lead: '感谢您试用 DeepSeek Harness。目前仍处于内部测试阶段,部分功能与体验还在持续打磨。',
feedbackTitle: '我们最想听见:失败、困惑和不顺手',
feedbackBody: '如果它没帮到您,甚至给工作添了麻烦,请在企业微信群告诉我们。',
closing: '真实使用中的每一个问题,都可能促使我们重新审视,甚至推翻已有设计。',
quote: '“如切如磋,如琢如磨。”',
continueLabel: '继续',
},
en: {
paragraphs: [
'Thank you for taking the time to try DeepSeek Harness.',
'This version is still in internal testing. Some features remain unfinished, and parts of the experience may feel rough.',
'“As one cuts and files, as one chisels and polishes.” A product grows through real encounters and candid feedback. Problems you uncover in real use may prompt us to reconsider—or even overturn—our existing designs.',
'We especially want to hear about failures, confusion, and friction. If it did not help you, or even made your work harder, please leave a message in the company WeChat group and tell us about your experience. Every piece of feedback helps us refine it.',
],
title: 'Internal Testing Notice',
lead: 'Thank you for trying DeepSeek Harness. This version is still in internal testing, and some features and experiences remain under refinement.',
feedbackTitle: 'What we most want to hear: failures, confusion, and friction',
feedbackBody: 'If it did not help—or even made your work harder—please tell us in the company WeChat group.',
closing: 'Every problem found in real use may prompt us to reconsider, or even overturn, an existing design.',
quote: '“As one cuts and files, as one chisels and polishes.”',
continueLabel: 'Continue',
},
} as const

View File

@@ -54,10 +54,18 @@ function mount(version?: string, mutateImpl: () => Promise<unknown> = () => Prom
describe('WelcomeNotice', () => {
it('renders the owner copy with one primary action and no dismissal control', async () => {
const h = mount()
const dialog = await screen.findByRole('dialog', { name: WELCOME_NOTICE_COPY.zh.paragraphs[0] })
for (const paragraph of WELCOME_NOTICE_COPY.zh.paragraphs) {
expect(screen.getByText(paragraph)).toBeTruthy()
const dialog = await screen.findByRole('dialog', { name: WELCOME_NOTICE_COPY.zh.title })
for (const text of [
WELCOME_NOTICE_COPY.zh.title,
WELCOME_NOTICE_COPY.zh.lead,
WELCOME_NOTICE_COPY.zh.feedbackTitle,
WELCOME_NOTICE_COPY.zh.feedbackBody,
WELCOME_NOTICE_COPY.zh.closing,
WELCOME_NOTICE_COPY.zh.quote,
]) {
expect(screen.getByText(text)).toBeTruthy()
}
expect(dialog.textContent?.match(/感谢您试用 DeepSeek Harness/g) ?? []).toHaveLength(1)
const buttons = dialog.querySelectorAll('button')
expect(buttons).toHaveLength(1)
expect(screen.getByRole('button', { name: WELCOME_NOTICE_COPY.zh.continueLabel })).toBeTruthy()