Просмотр исходного кода

feat(web): add preview badge to empty hero

ZiyaZhang 2 месяцев назад
Родитель
Сommit
047ea50987

+ 1 - 1
apps/web/tests/snapshots/lifecycle-chrome/hero.expected.md

@@ -20,7 +20,7 @@
 - button "Settings":
   - img
   - text: Settings
-- text: Let's start building
+- text: Let's start building Preview
 - button "Choose workspace":
   - img
   - text: workspace

+ 1 - 1
apps/web/tests/snapshots/lifecycle-chrome/plan-active.expected.md

@@ -20,7 +20,7 @@
 - button "Settings":
   - img
   - text: Settings
-- text: Let's start building
+- text: Let's start building Preview
 - button "Choose workspace":
   - img
   - text: workspace

+ 2 - 0
packages/client/ui-conversation/src/client/locales.ts

@@ -33,6 +33,7 @@ export const zh = {
   'access.confirm.cancel': '取消',
   'access.confirm.enable': '启用 Full access',
   'hero.headline': '开始构建吧',
+  'hero.preview': '预览版',
   'hero.chooseWorkspace': '选择工作区',
   'session.hierarchy': '会话层级',
   'details.title': '详情',
@@ -144,6 +145,7 @@ export const en = {
   'access.confirm.cancel': 'Cancel',
   'access.confirm.enable': 'Enable Full access',
   'hero.headline': 'Let\'s start building',
+  'hero.preview': 'Preview',
   'hero.chooseWorkspace': 'Choose workspace',
   'session.hierarchy': 'Session hierarchy',
   'details.title': 'Details',

+ 2 - 1
packages/client/ui-conversation/src/client/skeleton/EmptyHero.tsx

@@ -119,7 +119,8 @@ export function HeroShell({ t, children }: HeroShellProps) {
         <div className={css.headline}>
           {/* figma 34:10412: fish 34×25 leading the headline, gap 10. */}
           <FishLogo size={34} className={css.fish} />
-          {t('hero.headline')}
+          <span className={css.headlineText}>{t('hero.headline')}</span>
+          <span className={css.previewBadge}>{t('hero.preview')}</span>
         </div>
         <div className={css.body}>
           {/* The resident composer (ConversationRoot wrapActiveBody seat; the

+ 27 - 4
packages/client/ui-conversation/src/client/skeleton/HeroShell.module.css

@@ -23,21 +23,44 @@
   overflow: visible;
 }
 
-/* figma 34:10411: fish + title, gap 10, centered; 26/32 wt500. */
+/* Fish + title stay centered as one unit; the preview badge aligns with the
+   title's leading edge on the second row. */
 .headline {
-  display: flex;
+  display: grid;
+  grid-template-columns: 34px auto;
+  column-gap: 10px;
+  row-gap: 4px;
   align-items: center;
   justify-content: center;
-  gap: 10px;
   font-size: 26px;
   line-height: 32px;
   font-weight: 500;
   color: var(--dsw-alias-label-primary);
 }
 
+.headlineText {
+  grid-row: 1;
+  grid-column: 2;
+}
+
+.previewBadge {
+  grid-row: 2;
+  grid-column: 2;
+  justify-self: start;
+  padding: 0 4px;
+  border-radius: 4px;
+  background: var(--dsw-alias-state-business-tertiary);
+  color: var(--dsw-alias-state-business-primary);
+  font-size: 12px;
+  line-height: 18px;
+  font-weight: 500;
+  white-space: nowrap;
+}
+
 /* figma fish fill rides business blue. */
 .fish {
-  flex: none;
+  grid-row: 1;
+  grid-column: 1;
   color: var(--dsw-alias-state-business-primary);
 }
 

+ 10 - 1
packages/client/ui-conversation/tests/skeleton.spec.tsx

@@ -12,12 +12,14 @@ import type {
 import type { ConversationRootProps } from '../src/client/skeleton/ConversationRoot.tsx'
 import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'
 import { makeTranslate } from '@deepseek-ai/dsh-client-test-runtime'
+import { en as commonEn } from '@deepseek-ai/dsh-client-locale/src/locales/en.ts'
 import { zh as commonZh } from '@deepseek-ai/dsh-client-locale/src/locales/zh.ts'
 import { createChatStore } from '../src/client/stores.ts'
 import { SessionInputShell } from '../src/client/input/facade.ts'
-import { zh } from '../src/client/locales.ts'
+import { en, zh } from '../src/client/locales.ts'
 import { ConversationRoot } from '../src/client/skeleton/ConversationRoot.tsx'
 import { ConversationSession } from '../src/client/skeleton/ConversationSession.tsx'
+import { HeroShell } from '../src/client/skeleton/EmptyHero.tsx'
 import { InputBar } from '../src/client/skeleton/InputBar.tsx'
 import type { InputBarProps } from '../src/client/skeleton/InputBar.tsx'
 import type {
@@ -214,6 +216,12 @@ function mount(
 }
 
 describe('ConversationRoot resident composer', () => {
+  it('renders the English preview badge through the hero locale seat', () => {
+    const view = render(<HeroShell t={makeTranslate(en, commonEn)} />)
+    expect(view.getByText('Let\'s start building')).toBeTruthy()
+    expect(view.getByText('Preview')).toBeTruthy()
+  })
+
   it('keeps composer text in the machine, mirrors to the chat store, and submits through the sink', () => {
     const b = mount(conversationSnapshot())
     const box = b.view.getByRole('textbox')
@@ -273,6 +281,7 @@ describe('ConversationRoot resident composer', () => {
     expect(host).not.toBeNull()
     expect(header?.getAttribute('aria-hidden')).toBe('true')
     expect(b.view.getByText('开始构建吧')).toBeTruthy()
+    expect(b.view.getByText('预览版')).toBeTruthy()
     expect(b.view.queryByTestId('view-chat')).toBeNull()
     // The same machine-backed textarea is live in the hero, and the
     // persistence mirror stays bound (ConversationSession mounts chrome-hidden