From 4fcade7238f553f94c588a0c068147edc77b869d Mon Sep 17 00:00:00 2001 From: jesse-ux Date: Tue, 27 Oct 2026 02:33:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=AF=E7=A8=8B=E6=B8=85=E5=8D=95=E3=80=81?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E5=92=8C=E5=8A=A8=E6=95=88=E6=94=B9=E5=88=B0?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E5=87=BA=E6=9D=A5=E5=90=8E=E5=86=8D=E8=BD=BD?= =?UTF-8?q?=E5=85=A5=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 首屏 gzip-9 从比基线多 11.05% 降到多 7.54%。首页仍是静态页。加载时不转圈。 Co-Authored-By: Grok (agent loop) --- CHANGELOG.md | 6 ++++++ .../PROGRESS-ui-kit-onboarding-fix-20261026.md | 16 +++++++--------- frontend/DESIGN.md | 2 +- frontend/src/app/(app)/layout.tsx | 13 +++++++++++-- frontend/src/app/(app)/page.tsx | 7 ++++++- .../tests/onboarding-checklist-20261022.test.ts | 9 +++++++++ 6 files changed, 40 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61f9177f..2113b995 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # 印度占星 Skill 更新日志 +## 2026-10-27 — 启程清单、提示和动效不进首屏 + +- 首页先出来。启程清单、一次性提示和启程动效随后再载入,中间不转圈、不写「正在加载」。 +- 动效还没到手时,内容保持可见。 +- Skill 版本不变。 + ## 2026-10-25 — 组件库收尾:去掉没人用的旧样式 - 删掉样式表里已经没有页面使用的旧类。还在用的类和动画都留着。 diff --git a/docs/tasks/PROGRESS-ui-kit-onboarding-fix-20261026.md b/docs/tasks/PROGRESS-ui-kit-onboarding-fix-20261026.md index b8c4d0e3..901fd553 100644 --- a/docs/tasks/PROGRESS-ui-kit-onboarding-fix-20261026.md +++ b/docs/tasks/PROGRESS-ui-kit-onboarding-fix-20261026.md @@ -154,14 +154,12 @@ ## 首屏体积(U8) -这次构建是在 `521e902f3` 上跑的。`npm run build` 打完路由表,`/` 是 `○ Static`。口径:`.next/server/app/index.html` 引用的 `/_next/static/*.js` 和 `*.css`,去重后每个用 gzip -9,字节相加。 +口径:`npm run build` 之后,`.next/server/app/index.html` 引用的 `/_next/static/*.js` 和 `*.css`,去重后每个用 gzip -9,字节相加。基线是 `0f66d92d4`,在另一棵工作树里用当时的锁文件 `npm ci` 再构建。两次构建的 `/` 都是 `○ Static`。`skill-package-registry.ts` 的 5 条追踪警告两边都有,这次没改那份文件,也没改 next 配置。 -| 项 | 字节 | -| --- | --- | -| 文件数 | 39,缺失 0 | -| gzip-9 合计 | 717631 | -| 其中 js | 636112 | -| 其中 css | 81519 | -| 未压缩合计 | 2460717 | +| 版本 | 文件 | gzip-9 | js | css | 相对基线 | +| --- | --- | --- | --- | --- | --- | +| 基线 `0f66d92d4` | 36,缺失 0 | 646201 | 575350 | 70851 | — | +| 延后加载之前 | 39,缺失 0 | 717631 | 636112 | 81519 | +71430,+11.05% | +| 延后加载之后 | 38,缺失 0 | 694941 | 613422 | 81519 | +48740,+7.54% | -基线 `0f66d92d4` 用同一口径另开工作树再量。超过 ±2% 才把启程清单、提示层、动效改成用到时再加载。构建日志里 `skill-package-registry.ts` 的追踪警告这次没改那份文件,也没改 next 配置。 +延后加载之前那次构建在 `521e902f3`。超过 2% 之后,启程清单、一次性提示和启程动效宿主改成页面出来后再载入,不占位、不转圈。这一步少了 22690 字节。相对基线仍是 +7.54%,还在 2% 外面。多出来的是组件库外壳和整站样式,不是这三块还留在首屏里。 diff --git a/frontend/DESIGN.md b/frontend/DESIGN.md index d805dffb..2057be2a 100644 --- a/frontend/DESIGN.md +++ b/frontend/DESIGN.md @@ -1283,7 +1283,7 @@ Yogini 还在取时,右栏用和 Chara 相同的轨道等待(`OrbitWaiting` 一次性提示用现有弹出层,宽 `min(18rem, calc(100vw - 2rem))`,不抢焦点。侧栏两项从锚点右侧伸出,其余从上方伸出,间距 8px。按钮是「知道了」。同一时刻最多一条。天空过场、兑换窗、任何弹窗或抽屉、启程清单正打开、回答还在生成时,提示不出;挡着的那一条等条件过去再出。侧栏「星盘」、手机菜单和星盘四个页签上的小圆点是 8px,贴在右上角 4px,不是字符。 -启程专用动效只在启程里播放:清单还开着且有未完成项,或账户还没完成第一问。清单已经关掉的账户不播追问进场、档案卡进场、星盘和大运画出、合盘头像靠拢。动效代码还没到手、或 300ms 内没到手时,内容保持可见,不先藏起来。只在元素第一次出现时播放。重绘、来回切换不重播。除回答流式中的呼吸点外,没有无限循环。只动 `opacity`、`transform`、颜色、`clip-path`,不触发布局。Motion 用到才加载,不进首屏。系统开启「减少动态效果」时,星点和圆点闪烁去掉,其余只淡入,没有位移、缩放和擦除。 +启程专用动效只在启程里播放:清单还开着且有未完成项,或账户还没完成第一问。清单已经关掉的账户不播追问进场、档案卡进场、星盘和大运画出、合盘头像靠拢。动效代码还没到手、或 300ms 内没到手时,内容保持可见,不先藏起来。只在元素第一次出现时播放。重绘、来回切换不重播。除回答流式中的呼吸点外,没有无限循环。只动 `opacity`、`transform`、颜色、`clip-path`,不触发布局。Motion 用到才加载,不进首屏。启程清单、一次性提示和启程动效宿主也在页面出来后再载入,不进首屏。没载入之前不占位、不转圈;内容保持可见。系统开启「减少动态效果」时,星点和圆点闪烁去掉,其余只淡入,没有位移、缩放和擦除。 | 类别 | 用在哪 | 时长 | 曲线 | | --- | --- | --- | --- | diff --git a/frontend/src/app/(app)/layout.tsx b/frontend/src/app/(app)/layout.tsx index 20f67d0e..f7b4fdb8 100644 --- a/frontend/src/app/(app)/layout.tsx +++ b/frontend/src/app/(app)/layout.tsx @@ -1,11 +1,10 @@ "use client"; import type { ReactNode } from "react"; +import dynamic from "next/dynamic"; import { AccountDeletionGate } from "@/components/account-deletion-gate"; import { AppSidebar } from "@/components/app-sidebar"; -import { OnboardingHintLayer } from "@/components/onboarding-hint-layer"; -import { OnboardingMotionHost } from "@/components/onboarding-motion-host"; import { LegalConsentGate } from "@/components/legal/legal-consent-gate"; import { PageSwitch } from "@/components/shell-motion"; import { ShellFrame } from "@/components/shell-frame"; @@ -14,6 +13,16 @@ import { OnboardingJourneyProvider } from "@/lib/onboarding-journey"; import { SessionListProvider, sessionListSidebarModel, useSessionList, useShellRegistration } from "@/hooks/use-session-list"; import "../site-styles"; +// After the page is up. No placeholder: a spinner is not allowed once the home screen is revealed. +const OnboardingHintLayer = dynamic( + () => import("@/components/onboarding-hint-layer").then((module) => module.OnboardingHintLayer), + { ssr: false }, +); +const OnboardingMotionHost = dynamic( + () => import("@/components/onboarding-motion-host").then((module) => module.OnboardingMotionHost), + { ssr: false }, +); + function AppShell({ children }: { children: ReactNode }) { const list = useSessionList(); const registration = useShellRegistration(); diff --git a/frontend/src/app/(app)/page.tsx b/frontend/src/app/(app)/page.tsx index 4938b319..8ff42192 100644 --- a/frontend/src/app/(app)/page.tsx +++ b/frontend/src/app/(app)/page.tsx @@ -51,7 +51,6 @@ import { notifyOnboardingDailyOpened } from "@/lib/onboarding-signals"; import { personRelationLabel } from "@/lib/person-relation"; import { readStarterSignMap, readStarterSigns, subscribeStarterSigns } from "@/lib/starter-questions"; import { DailyStarlanguageBinder } from "@/components/daily-starlanguage-binder"; -import { OnboardingChecklistEntry } from "@/components/onboarding-checklist"; import { OnboardingChartDot } from "@/components/onboarding-dot"; import { OnboardingHomeBridge } from "@/components/onboarding-home-bridge"; import { AccountDialogDeepLink, SynastryDeepLink } from "@/components/people-home-links"; @@ -201,6 +200,12 @@ const BillingPanel = dynamic(loadBillingPanel, { loading: () =>

账户信息还没拿到。

, }); +// After the page is up. No placeholder: a spinner is not allowed once the home screen is revealed. +const OnboardingChecklistEntry = dynamic( + () => import("@/components/onboarding-checklist").then((module) => module.OnboardingChecklistEntry), + { ssr: false }, +); + let nudgeComposerTimer: number | undefined; function clearNudgeComposerTimer() { diff --git a/frontend/tests/onboarding-checklist-20261022.test.ts b/frontend/tests/onboarding-checklist-20261022.test.ts index e65c3460..7d6c80c4 100644 --- a/frontend/tests/onboarding-checklist-20261022.test.ts +++ b/frontend/tests/onboarding-checklist-20261022.test.ts @@ -282,6 +282,15 @@ test("checklist and hint wiring stay inside the existing shell", () => { const home = page.slice(page.indexOf("export default function Home(")); assert.match(page, //); assert.match(page, //); + // 原值:首页静态引入启程清单。 + // 新值:清单、提示层、动效宿主都是页面出来后再载入,且不给占位。 + // 原因:首屏 gzip-9 比基线 0f66d92d4 大 11.05%,任务书要求这三块不进首屏。 + assert.match(page, /import\("@\/components\/onboarding-checklist"\)[\s\S]{0,200}ssr: false/); + assert.doesNotMatch(page, /import \{ OnboardingChecklistEntry \}/); + assert.match(layout, /import\("@\/components\/onboarding-hint-layer"\)[\s\S]{0,200}ssr: false/); + assert.match(layout, /import\("@\/components\/onboarding-motion-host"\)[\s\S]{0,200}ssr: false/); + assert.doesNotMatch(layout, /import \{ OnboardingHintLayer \}/); + assert.doesNotMatch(layout, /import \{ OnboardingMotionHost \}/); const header = page.slice(page.indexOf('
'), page.indexOf("composer-wrap")); assert.match(header, //); assert.equal(header.includes("composer-wrap"), false);