diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fe21da2..418e269c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # 印度占星 Skill 更新日志 +## 2026-10-28 — 前端删掉 15 个没人用的文件 + +- 删掉 15 个没有任何页面用到的前端文件(约 700 行),其中包括一个会把动效库带回首屏的旧外壳和一个与「不出现骨架屏」规定冲突的组件。用户看到的内容不变。 +- Skill 版本不变(BUG-1480,issue #139)。 + ## 2026-10-28 — VedAstro 限流或不可用时,不再每轮重等 - VedAstro 被限流或暂时拿不到数据时,同一张盘当天只问一次;之后的提问直接说明「外部校验暂不可用」,不再每轮多等 0.4~1.5 秒。第二天会重新问。 diff --git a/docs/BUG_HISTORY.md b/docs/BUG_HISTORY.md index 0b9e84a0..b10ebc37 100644 --- a/docs/BUG_HISTORY.md +++ b/docs/BUG_HISTORY.md @@ -20203,3 +20203,18 @@ - 关联:BUG-734(健康探测走缓存)、BUG-727 / BUG-301(前台快照)。 - 复发自:无 - 修复版本:分支 `codex/vedastro-negative-day-20261028`。 + +## BUG-1480 | 前端留着 15 个没有任何页面用到的文件 + +- 状态:resolved(代码 + 回归测试;待部署) +- 首次发现 / 最近更新:2026-10-28 / 2026-10-28(issue #118 代码体检第 24 条 → #139) +- 影响面:`frontend/src/`;不影响任何页面(这些文件从任何入口都不可达)。 +- 现象:从所有页面、布局、接口、错误页入口和 `frontend/scripts/` 出发(计入动态 import),有 18 个文件不可达。其中 `lib/motion/provider.tsx` 静态引用 `motion/react`,将来谁一引用 Motion 就回到首屏;`ui/skeleton` 与 DESIGN「揭幕后不得出现骨架」冲突,留着容易被误用。 +- 根因:改版和组件库生成后留下的残余,只被测试引用或没人引用。 +- 修复:删除 15 个:`components/chart-page/chart-basics-tab.tsx`、`components/error-toast.tsx`、`components/ui/{avatar,empty,field,kbd,separator,skeleton,switch}.tsx`、`lib/birth-time-choice-question-model.ts`、`lib/birth-time-guided-terminal.ts`、`lib/birth-time-guided-turn-identity.ts`、`lib/motion/provider.tsx`、`stores/account-store.ts`、`stores/people-store.ts`。保留 `app/forbidden.tsx`(Next 的特殊入口文件)以及进度记录里写过理由的 `reader-appendix-language.ts`、`personal-report-longform-download.ts`。删前对每个文件用 `git grep -- tests/ frontend/` 核对,Python 源码契约测试里没有引用。 +- 测试变化(只少被删模块的用例):删除 `birth-time-guide-flow.test.ts`(1 条,只测 `guidedTurnIdentity`);`birth-time-choice-question.test.ts` 删 2 条(click intent submits primary and unknown options immediately、unmatched requests clarification without creating scoring evidence);`birth-time-guided-review-fixes.test.ts` 删 1 条(dynamic medium terminal preserves its candidate range without direct adoption),另 1 条去掉 `guidedTerminalPath` 断言;`birth-time-rectification-contract.test.ts` 1 条去掉 `guidedTerminalPath` 断言;`ui-kit-stores.test.ts` 去掉两个空骨架 store 的断言(Home 不引用它们的断言保留);`motion-presets.test.ts`「LazyMotion loads domAnimation asynchronously and honors reduced motion」改名为「the home and the layout never import motion or a motion shell statically」,只留首页与 layout 的静态引用约束。改动处都写了原值 / 新值 / 原因。 +- 验证:不可达文件 18 → 3(上面保留的 3 个)。全量前端测试与 staging 逐条比对:少的名字正好是上面 4 条删除和 1 条改名,没有新增失败。tsc 0、lint 0 error。删的都是不可达文件,打包内容不变。 +- 防复发:删除前跑可达性检查并 `git grep -- tests/ frontend/`;只被测试引用的模块连同测试一起删。 +- 关联:前端死代码清理(frontend-dead-code 进度记录)。 +- 复发自:无 +- 修复版本:分支 `codex/frontend-dead-files-20261028`。 diff --git a/frontend/src/components/chart-page/chart-basics-tab.tsx b/frontend/src/components/chart-page/chart-basics-tab.tsx deleted file mode 100644 index 847f0f7d..00000000 --- a/frontend/src/components/chart-page/chart-basics-tab.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import type { ChartViewOk } from "@/lib/chart-view-contract"; -import { formatDegree } from "./chart-format"; - -export function ChartBasicsTab({ view }: { view: ChartViewOk }) { - return ( -
-
- {view.vedic.planets.map((planet) => ( -
-

{planet.label}

-

本命 {planet.signLabel} {formatDegree(planet.degreeInSign)} · 第{planet.house}宫

-

{planet.nakshatra} 第{planet.pada}足 · 星宿主 {planet.nakshatraLord}

-

D9 {planet.d9SignLabel ?? "未返回"}

- {planet.symbol ?

{planet.symbol}

: null} -
- ))} -
-
- ); -} diff --git a/frontend/src/components/error-toast.tsx b/frontend/src/components/error-toast.tsx deleted file mode 100644 index 12374923..00000000 --- a/frontend/src/components/error-toast.tsx +++ /dev/null @@ -1,17 +0,0 @@ -"use client"; - -import { useEffect } from "react"; - -import { notifyError } from "@/lib/notify"; - -/** - * An error a flow keeps in state, said once as a toast whenever it changes to - * a new message (2026-09-30: no inline error bars). The message is the toast's - * id, so a remount repeats nothing on screen. Renders nothing. - */ -export function ErrorToast({ message }: Readonly<{ message: string | null | undefined }>) { - useEffect(() => { - if (message) notifyError(message, { id: `error:${message}` }); - }, [message]); - return null; -} diff --git a/frontend/src/components/ui/avatar.tsx b/frontend/src/components/ui/avatar.tsx deleted file mode 100644 index a20f4ebc..00000000 --- a/frontend/src/components/ui/avatar.tsx +++ /dev/null @@ -1,108 +0,0 @@ -"use client" - -import * as React from "react" -import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar" -import { cn } from "@/lib/utils" - -function Avatar({ - className, - size = "default", - ...props -}: AvatarPrimitive.Root.Props & { - size?: "default" | "sm" | "lg" -}) { - return ( - - ) -} - -function AvatarImage({ className, ...props }: AvatarPrimitive.Image.Props) { - return ( - - ) -} - -function AvatarFallback({ - className, - ...props -}: AvatarPrimitive.Fallback.Props) { - return ( - - ) -} - -function AvatarBadge({ className, ...props }: React.ComponentProps<"span">) { - return ( - svg]:hidden", - "group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2", - "group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2", - className - )} - {...props} - /> - ) -} - -function AvatarGroup({ className, ...props }: React.ComponentProps<"div">) { - return ( -
- ) -} - -function AvatarGroupCount({ - className, - ...props -}: React.ComponentProps<"div">) { - return ( -
svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3", - className - )} - {...props} - /> - ) -} - -export { - Avatar, - AvatarImage, - AvatarFallback, - AvatarGroup, - AvatarGroupCount, - AvatarBadge, -} diff --git a/frontend/src/components/ui/empty.tsx b/frontend/src/components/ui/empty.tsx deleted file mode 100644 index 78848967..00000000 --- a/frontend/src/components/ui/empty.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { cva, type VariantProps } from "class-variance-authority" -import { cn } from "@/lib/utils" - -function Empty({ className, ...props }: React.ComponentProps<"div">) { - return ( -
- ) -} - -function EmptyHeader({ className, ...props }: React.ComponentProps<"div">) { - return ( -
- ) -} - -const emptyMediaVariants = cva( - "mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0", - { - variants: { - variant: { - default: "bg-transparent", - icon: "flex size-8 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg:not([class*='size-'])]:size-4", - }, - }, - defaultVariants: { - variant: "default", - }, - } -) - -function EmptyMedia({ - className, - variant = "default", - ...props -}: React.ComponentProps<"div"> & VariantProps) { - return ( -
- ) -} - -function EmptyTitle({ className, ...props }: React.ComponentProps<"div">) { - return ( -
- ) -} - -function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) { - return ( -
a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary", - className - )} - {...props} - /> - ) -} - -function EmptyContent({ className, ...props }: React.ComponentProps<"div">) { - return ( -
- ) -} - -export { - Empty, - EmptyHeader, - EmptyTitle, - EmptyDescription, - EmptyContent, - EmptyMedia, -} diff --git a/frontend/src/components/ui/field.tsx b/frontend/src/components/ui/field.tsx deleted file mode 100644 index f66bff1d..00000000 --- a/frontend/src/components/ui/field.tsx +++ /dev/null @@ -1,238 +0,0 @@ -"use client" - -import { useMemo } from "react" -import { cva, type VariantProps } from "class-variance-authority" -import { cn } from "@/lib/utils" - -import { Label } from "@/components/ui/label" -import { Separator } from "@/components/ui/separator" - -function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) { - return ( -
[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3", - className - )} - {...props} - /> - ) -} - -function FieldLegend({ - className, - variant = "legend", - ...props -}: React.ComponentProps<"legend"> & { variant?: "legend" | "label" }) { - return ( - - ) -} - -function FieldGroup({ className, ...props }: React.ComponentProps<"div">) { - return ( -
- ) -} - -const fieldVariants = cva( - "group/field flex w-full gap-2 data-[invalid=true]:text-destructive", - { - variants: { - orientation: { - vertical: "flex-col *:w-full [&>.sr-only]:w-auto", - horizontal: - "flex-row items-center has-[>[data-slot=field-content]]:items-start *:data-[slot=field-label]:flex-auto has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px", - responsive: - "flex-col *:w-full @md/field-group:flex-row @md/field-group:items-center @md/field-group:*:w-auto @md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:*:data-[slot=field-label]:flex-auto [&>.sr-only]:w-auto @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px", - }, - }, - defaultVariants: { - orientation: "vertical", - }, - } -) - -function Field({ - className, - orientation = "vertical", - ...props -}: React.ComponentProps<"div"> & VariantProps) { - return ( -
- ) -} - -function FieldContent({ className, ...props }: React.ComponentProps<"div">) { - return ( -
- ) -} - -function FieldLabel({ - className, - ...props -}: React.ComponentProps) { - return ( -