fix(web): make the welcome notice scan-first
This commit is contained in:
@@ -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%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
|
||||
@@ -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.',
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user