此前空态是 hero 卡(h1 clamp 到 52px)加两张 min-height 228px 的产品卡, 输入框被压在约 800px 内容之下,主动作不是视觉焦点。 改法:问候拆成 StarterGreeting 留在对话区并底对齐,两个产品入口降级成 StarterEntries 渲染在 composer 之后。composer 本身一行未动——它在空态与 会话态是同一个 DOM 位置,首条消息落地时不重挂载,草稿/焦点/排队卡都不受影响。 顺带修掉:空态 composer 1040px、会话态 760px,发首条消息时输入框会当场 变窄一截。两态统一到 --session-column-width,并新增断言锁住。 校正入口保留三个服务端驱动的文案分支(我第一版收成了两个,是 rectification-agentic-entry 打红才发现)。 DESIGN.md:Product entrypoint card 整节重写为 Starter home;删掉 Suggestion card 死文档(它描述的主题卡样式正是本轮删除的 CSS)。 测试 3350 不变,fail 仍 31 且与基线双向零差异;/ 仍 Static; CSS gzip 41,096→41,044(−0.13%)。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
82 lines
4.0 KiB
TypeScript
82 lines
4.0 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import test from "node:test";
|
|
|
|
import { bootstrapPrepareSettled } from "../src/lib/home-bootstrap.ts";
|
|
|
|
const page = readFileSync(new URL("../src/app/page.tsx", import.meta.url), "utf8");
|
|
const starterHome = readFileSync(new URL("../src/components/starter-home.tsx", import.meta.url), "utf8");
|
|
const bootstrap = readFileSync(new URL("../src/lib/home-bootstrap.ts", import.meta.url), "utf8");
|
|
const entrypoint = readFileSync(new URL("../src/lib/consultation-entrypoint.ts", import.meta.url), "utf8");
|
|
const srcFiles = [
|
|
page,
|
|
starterHome,
|
|
readFileSync(new URL("../src/hooks/use-profile-onboarding.ts", import.meta.url), "utf8"),
|
|
readFileSync(new URL("../src/mastra/index.ts", import.meta.url), "utf8"),
|
|
];
|
|
|
|
test("the homepage no longer renders theme cards", () => {
|
|
assert.doesNotMatch(starterHome, /starter-themes|starter-theme-card|starter-theme-accordion|starter-themes-heading/);
|
|
assert.doesNotMatch(starterHome, /从一个主题开始/);
|
|
assert.doesNotMatch(starterHome, /starterThemes|starterSuggestions|onboardingError/);
|
|
// 原值:`starter-hero` 卡 + `product-entrypoints` 两张 132px 大卡
|
|
// 新值:`starter-greeting-block` 一行问候 + `starter-entry` 两枚 pill
|
|
// 原因:输入框此前被压在约 800px 内容之下,主动作不是视觉焦点。
|
|
assert.match(starterHome, /className="starter-greeting-block"/);
|
|
assert.match(starterHome, /className="starter-entry"/);
|
|
assert.doesNotMatch(starterHome, /starter-hero|product-entrypoint/);
|
|
});
|
|
|
|
test("the homepage no longer requests /api/onboarding", () => {
|
|
for (const source of srcFiles) {
|
|
assert.doesNotMatch(source, /\/api\/onboarding/);
|
|
assert.doesNotMatch(source, /requestOnboardingWithRecovery/);
|
|
assert.doesNotMatch(source, /getOnboardingAgent/);
|
|
}
|
|
assert.doesNotMatch(page, /fetch\("\/api\/onboarding"/);
|
|
});
|
|
|
|
test("bootstrap prepare no longer waits on onboarding suggestions", () => {
|
|
assert.doesNotMatch(bootstrap, /onboardingSettled|profileComplete/);
|
|
assert.doesNotMatch(page, /onboardingSettled/);
|
|
assert.equal(bootstrapPrepareSettled({
|
|
dailyStarlanguageApplicable: true,
|
|
dailyStarlanguageSettled: true,
|
|
entrySummarySettled: true,
|
|
}), true);
|
|
assert.equal(bootstrapPrepareSettled({
|
|
dailyStarlanguageApplicable: true,
|
|
dailyStarlanguageSettled: false,
|
|
entrySummarySettled: true,
|
|
}), false);
|
|
});
|
|
|
|
test("StarterHome no longer receives suggestion props", () => {
|
|
assert.doesNotMatch(starterHome, /starterThemes|starterSuggestions|startSuggestedConsultation|onboardingError/);
|
|
assert.doesNotMatch(page, /starterThemes=\{|starterSuggestions=\{|onboardingError=\{/);
|
|
assert.match(page, /startSuggestedConsultation\(/);
|
|
assert.match(page, /startDailyStarlanguageConsultation/);
|
|
});
|
|
|
|
test("guided_topic remains readable for history but has no homepage emit point", () => {
|
|
assert.match(entrypoint, /入口已于 2026-09-15 下线,枚举值保留用于读回历史会话/);
|
|
assert.match(entrypoint, /"guided_topic"/);
|
|
assert.doesNotMatch(starterHome, /guided_topic/);
|
|
assert.doesNotMatch(page, /"guided_topic"/);
|
|
});
|
|
|
|
// 原值:空态 = 问候卡 + 两张产品卡,输入框在它们下面
|
|
// 新值:空态 = 一行问候(在对话区,底对齐)+ 输入框 + 两枚入口 pill(在输入框下)
|
|
// 原因:把主动作放回视觉焦点;输入框仍是同一个 DOM 位置,首条消息落地时不重挂载。
|
|
test("the empty home is a greeting, the composer, then two entry pills", () => {
|
|
assert.match(starterHome, /starter-greeting-block/);
|
|
assert.match(starterHome, /starter-entry-row/);
|
|
assert.doesNotMatch(starterHome, /starter-theme|daily-starlanguage-card|birth-rectification-card/);
|
|
assert.match(page, /composer-wrap-starter/);
|
|
// 入口 pill 必须渲染在 composer 之后,否则又回到「输入框被压在下面」。
|
|
assert.ok(
|
|
page.indexOf("<StarterEntries") > page.indexOf("<ChatComposer"),
|
|
"StarterEntries must render after the composer inside .composer-wrap",
|
|
);
|
|
});
|