fix(home,chart,ephemeris): drop the unfinished-rectification hint, full chart-type captions, orbit instead of 还没拿到, constellation icon (BUG-1111..1114)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
82db6373d6
commit
921992a492
@@ -14942,3 +14942,44 @@
|
||||
- 防复发:真机复测后更新本条状态;若仍复现需真机录屏与 Safari 版本。
|
||||
- 相关记录:TASK-report-english-edition-20260929
|
||||
- 修复版本:分支 `codex/surface-feedback-20260929`
|
||||
|
||||
## BUG-1111 | 首页常驻「上次那次校正还没完成,可以在历史对话里接着做。」
|
||||
|
||||
- 状态:resolved(代码 + 回归测试)
|
||||
- 首次发现 / 最近更新:2026-09-30 / 2026-09-30
|
||||
- 影响面:`components/starter-home.tsx::rectificationEntryHint`。
|
||||
- 现象:有未完成的校正时首页入口下方一直挂着这句提示;产品要求去掉。
|
||||
- 修复:`rectificationEntryHint(rectificationForSelf)` 只保留「生时校正暂时只支持本人。」一句;未完成的校正仍在历史列表里。
|
||||
- 验证:`starter-home-polish-20260926.test.tsx`、`rectification-agentic-entry.test.ts`(断言三栏更新)、`surface-feedback-20260929.test.tsx`。
|
||||
- 相关记录:BUG-1041、TASK-starter-home-polish-20260926 D2
|
||||
- 修复版本:分支 `codex/surface-feedback-20260929`
|
||||
|
||||
## BUG-1112 | 星盘类型面板里每格的说明文字被截掉下半截 / 显示不全
|
||||
|
||||
- 状态:resolved(代码 + 回归测试;iPhone 真机欠)
|
||||
- 首次发现 / 最近更新:2026-09-30 / 2026-09-30
|
||||
- 影响面:`globals.css .chart-page-type-cell small`。
|
||||
- 根因:说明行 `white-space: nowrap; overflow: hidden`,行高沿用按钮的紧行高,iPhone 上中文字形下半被裁;「以月亮为第 1 宫」这类长说明只能省略。
|
||||
- 修复:说明行行高 1.4、最多两行(line-clamp),格子最小高 56 → 64px。
|
||||
- 验证:`chart-type-picker.test.tsx`(三栏)、`surface-feedback-20260929.test.tsx`。
|
||||
- 修复版本:分支 `codex/surface-feedback-20260929`
|
||||
|
||||
## BUG-1113 | 星盘、星历加载时写「这一张盘还没拿到。」「这一天的星历还没拿到。」
|
||||
|
||||
- 状态:resolved(代码 + 回归测试 + 本机手机视口截图)
|
||||
- 首次发现 / 最近更新:2026-09-30 / 2026-09-30
|
||||
- 影响面:新增 `components/orbit-waiting.tsx`;`secondary-page-shell.tsx`、`chart-page-skeleton.tsx`、`chart-dasha-tab.tsx`。
|
||||
- 现象:几秒内就会加载好的内容,先用一句「还没拿到」占位,读起来像出错。
|
||||
- 修复:统一用首页加载屏的轨道环(40px)作为次级页短等待动画:星盘空盘中央、星历 / 报告列表首屏、Chara 大运栏;原句只留给读屏器(`sr-only` + `role="status"`)。
|
||||
- 产品决定:此前 AGENTS §6「揭幕后不得再出现加载动画」只对首页;星盘页 Chara 栏等待改为轨道环属产品本次明确要求,记录在此。
|
||||
- 验证:`surface-feedback-20260929.test.tsx`;既有「还没拿到」断言因文本仍在读屏节点里而不变。
|
||||
- 修复版本:分支 `codex/surface-feedback-20260929`
|
||||
|
||||
## BUG-1114 | 「那一刻的天空」按钮用的是各平台常见的星芒(AI)图标
|
||||
|
||||
- 状态:resolved(代码 + 回归测试)
|
||||
- 首次发现 / 最近更新:2026-09-30 / 2026-09-30
|
||||
- 修复:改为自绘「小星座」图标(四颗星以细线相连),与点开后的群星汇聚一致;产品在三个方案中选定。
|
||||
- 验证:`surface-feedback-20260929.test.tsx`。
|
||||
- 相关记录:BUG-1102
|
||||
- 修复版本:分支 `codex/surface-feedback-20260929`
|
||||
|
||||
+5
-1
@@ -563,6 +563,10 @@ one skeleton, none of them carrying the sidebar.
|
||||
more. A page's own reassurance copy (the chart page's cost-and-speed eyebrow,
|
||||
for one) stays in the body; it is content, not chrome.
|
||||
|
||||
### Short waits on secondary pages (2026-09-30, BUG-1113)
|
||||
|
||||
The chart page, the ephemeris and the report list wait with one motion: the home loading screen's orbit ring at 40px (`OrbitWaiting`), centred in the empty chart grid or in the page. No sentence is shown; the old 「……还没拿到。」 copy is kept only as the screen-reader status. The chart's breathing empty grid stays (BUG-1016 exception).
|
||||
|
||||
### Personal report centre
|
||||
|
||||
- **Structure:** inside the app shell, not a page of its own. The name 「我的报告」 sits alone in the 46px header. The body opens with the **generate card** (`.report-center-create`, 2026-09-29, product sketch): a centred `--color-canvas` sheet, `--space-6` below the header (BUG-1103: it used to sit flush under it), with a file icon, the title 「完整本命报告」 (what you get), one line 「星盘、力量、大运、年运、瑜伽共 6 章,中英两版;生成后可离开,完成时下方自动出现。」 and the filled 「生成报告」 button (what it does) — title and button no longer say the same thing — the page's only generate entry; the header button was deleted rather than kept as a second one. Below it, 「过往的报告」 heads the **row list** of reports; with none yet, a single quiet line 「还没有个人报告。」 replaces the old second big empty card. The supporting paragraph (「有填报到分钟的出生时间即可生成……」) and the 「共 N 份 · 已完成 N 份」 overview line above it were removed on 2026-09-28 (TASK-self-edit-avatar-menu-20260928 S3, product: 「这里的提示去掉」); the minute requirement still lives in the 生成 button's hover title.
|
||||
@@ -1183,7 +1187,7 @@ D40 / D45 / D60 的表格上方,出生时间不是「已校正」时多一句
|
||||
|
||||
### 位置一:星盘页顶栏按钮
|
||||
|
||||
- 星盘页 `ok` 后立即预取 `/api/birth-sky?subject=<当前人物>` 并在屏外画好 PNG;**画好之后**顶栏右侧才出现一枚描边按钮「那一刻的天空」(`<Button variant="outline" size="sm">`,顶栏里按 `.chat-header-actions button` 收成 32px + 命中区外扩)。2026-09-29 晚改(BUG-1102,产品「按钮不明显、慢一秒才出现」):星盘 `ok` 即显示按钮,不等 PNG;封面还在画时点击被记下,画好立即开播重放,中间不插转圈(重放的汇聚本身就是等待);样式改为 `.birth-sky-entry`:星芒图标 + `--color-action` 12% 浅底 + accent 字色 600 字重(不用 `--color-action-soft` 实块,BUG-1078)。预取失败时按钮消失,资料不全、切人物时都不显示按钮,不报错。切换人物或改出生资料(指纹变)就按新人物重新预取。家人的盘也能生成。
|
||||
- 星盘页 `ok` 后立即预取 `/api/birth-sky?subject=<当前人物>` 并在屏外画好 PNG;**画好之后**顶栏右侧才出现一枚描边按钮「那一刻的天空」(`<Button variant="outline" size="sm">`,顶栏里按 `.chat-header-actions button` 收成 32px + 命中区外扩)。2026-09-29 晚改(BUG-1102,产品「按钮不明显、慢一秒才出现」):星盘 `ok` 即显示按钮,不等 PNG;封面还在画时点击被记下,画好立即开播重放,中间不插转圈(重放的汇聚本身就是等待);样式改为 `.birth-sky-entry`:自绘小星座图标(四颗星细线相连,2026-09-30 替换星芒,BUG-1114)+ `--color-action` 12% 浅底 + accent 字色 600 字重(不用 `--color-action-soft` 实块,BUG-1078)。预取失败时按钮消失,资料不全、切人物时都不显示按钮,不报错。切换人物或改出生资料(指纹变)就按新人物重新预取。家人的盘也能生成。
|
||||
- 点按钮**重放群星汇聚并定格**(2026-09-29,TASK-mobile-chart-and-confirmed-edit-20260929 M4,替换第三轮 P1 的静态海报弹层):与首次建盘过场同一个组件 `BirthSkyConverge`、同一条时间轴,`mode="hold"`——汇聚约 3 秒、文字 600ms 淡入,然后**停在定格帧不动**,不淡出、不自动关闭。每次打开都从头重放。定格帧就是导出的海报(画布调用序列逐条相同,且用生成 PNG 时同一个宋体判定 `cover.serif`)。全屏原生 `<dialog>` portal 到 `document.body`,底色 `night` 页底色,画布取视口内最大 3:4、乘 DPR。
|
||||
- 控件浮在画面上方一行:**左上 ×**(只有图标,读屏名「关闭」)、**右上「分享」**(分享图标 + 字,night 墨色细描边)。播放中也在,都 ≥ 44px,顶部留安全区。点画面(不在控件上)直接跳到定格帧、**不关闭**;按 Esc 或点 × 关闭,焦点回到按钮。`prefers-reduced-motion` 时不汇聚,600ms 淡入到定格帧。
|
||||
- 「分享」:浏览器能分享文件时(iOS Safari)调 `navigator.share({ files })`,系统面板里有「存储图像」;否则 Blob + `a.download`。分享的就是屏幕上定格的那张 PNG(按钮出现前已画好,分享从不等待)。用户取消不算错误、不提示;其他失败在右上方小字「没能分享,再试一次。」。
|
||||
|
||||
@@ -149,6 +149,10 @@ Jyotisha 的可见文案是产品的一部分。正确性红线(真实性、
|
||||
|
||||
- 英文版正文的口径:用 BPHS / PL9 通行的英文术语(Exalted、Own Sign、Mooltrikona、Sub lord……),不音译中文、不中英混写;限制说明用固定英文四句(见 `report-public-projection.ts` 的 `ENGLISH_LIMITATION_COPY`)。应用外壳(侧栏、标题、按钮、到底部)始终是中文。
|
||||
|
||||
## 等待时不写「还没拿到」(2026-09-30)
|
||||
|
||||
星盘、星历、报告列表几秒内就会出现,等待时只放轨道环动画,不在屏幕上写「这一张盘还没拿到。」一类句子;这些句子只给读屏器。首页不再写「上次那次校正还没完成,可以在历史对话里接着做。」。
|
||||
|
||||
## 报告里的限制说明
|
||||
|
||||
普通报告只留下人能读的正文、结论、行动建议和必要限制。不写字段名、状态码、评分、权重或执行账本。说不到日期就写「这次说不到具体哪一天。」依据没补上就写「有些依据还没补上,相关说法不能当成确定预测。」判断没闭合就写「有些判断还没闭合,不能写成确定结论。」不出现 `technique_truth`、`workflow_route` 这类键。
|
||||
|
||||
@@ -2231,6 +2231,11 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
|
||||
line-height: 1.6;
|
||||
text-align: center;
|
||||
}
|
||||
/* The home screen's orbit ring at 40px: the shared short-wait motion for the
|
||||
chart, ephemeris and report pages (2026-09-30). */
|
||||
.orbit-waiting { display: grid; place-items: center; min-height: 64px; }
|
||||
.orbit-waiting .app-loading-symbol { width: 40px; height: 40px; }
|
||||
.orbit-waiting .app-loading-mark { width: 22px; height: 22px; }
|
||||
.chart-page-body,
|
||||
.ephemeris-body,
|
||||
.report-center-body,
|
||||
@@ -5175,7 +5180,7 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
|
||||
.chart-page-type-cell {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
min-height: 56px;
|
||||
min-height: 64px;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -5187,14 +5192,21 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
|
||||
color: var(--color-ink);
|
||||
cursor: pointer;
|
||||
}
|
||||
.chart-page-type-cell strong { font-size: var(--type-body-md); font-weight: 500; font-variant-numeric: tabular-nums; }
|
||||
.chart-page-type-cell strong { font-size: var(--type-body-md); font-weight: 500; line-height: 1.3; font-variant-numeric: tabular-nums; }
|
||||
/* The meaning line wraps to at most two lines (2026-09-30): it used to be one
|
||||
clipped line whose glyph bottoms were cut off on iPhone (the button's inherited
|
||||
line-height was tighter than CJK glyphs), and 「以月亮为第 1 宫」 ran out of room. */
|
||||
.chart-page-type-cell small {
|
||||
display: -webkit-box;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
color: var(--color-ink-tertiary);
|
||||
font-size: var(--type-caption);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
line-height: 1.4;
|
||||
text-align: center;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
}
|
||||
.chart-page-type-cell:hover { background: var(--color-canvas-muted); }
|
||||
.chart-page-type-cell.is-current { border-color: var(--color-ink); background: var(--color-selected); }
|
||||
@@ -5285,12 +5297,10 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class
|
||||
/* Waiting copy sits over the breathing empty chart, centred, so the waiting
|
||||
stage and the finished one are the same height. */
|
||||
.chart-page-waiting-plot { position: relative; }
|
||||
.chart-page-note.chart-page-skeleton-copy {
|
||||
.chart-page-skeleton-copy {
|
||||
position: absolute;
|
||||
inset: 50% var(--space-4) auto;
|
||||
margin: 0;
|
||||
transform: translateY(-50%);
|
||||
text-align: center;
|
||||
}
|
||||
.chart-page-symbol-hit { fill: transparent; stroke: none; }
|
||||
.chart-page-symbol-target { cursor: help; }
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import dynamic from "next/dynamic";
|
||||
import { Sparkles } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
@@ -28,10 +27,28 @@ export function BirthSkyEntry({ cover }: { cover: BirthSkyCover | null }) {
|
||||
return (
|
||||
<>
|
||||
<Button type="button" variant="secondary" size="sm" className="birth-sky-entry" onClick={() => setWanted(true)}>
|
||||
<Sparkles aria-hidden="true" />
|
||||
<ConstellationIcon />
|
||||
{BIRTH_SKY_ENTRY_LABEL}
|
||||
</Button>
|
||||
{open ? <BirthSkyReplay cover={cover} onClose={() => setWanted(false)} /> : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A small constellation: four stars joined by thin lines (2026-09-30, product:
|
||||
* the sparkle icon is on every AI product). It says what the button opens —
|
||||
* the stars of that moment drawing together — and is drawn here, not taken
|
||||
* from an icon set.
|
||||
*/
|
||||
function ConstellationIcon() {
|
||||
return (
|
||||
<svg viewBox="0 0 16 16" width="16" height="16" aria-hidden="true">
|
||||
<path d="M2.5 11.5 L6 5 L10.5 7.5 L13.5 2.5" fill="none" stroke="currentColor" strokeWidth="1" strokeLinecap="round" strokeLinejoin="round" opacity=".55" />
|
||||
<circle cx="2.5" cy="11.5" r="1.3" fill="currentColor" />
|
||||
<circle cx="6" cy="5" r="1.6" fill="currentColor" />
|
||||
<circle cx="10.5" cy="7.5" r="1.2" fill="currentColor" />
|
||||
<circle cx="13.5" cy="2.5" r="1.4" fill="currentColor" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { chartLayerFailureCopy } from "@/lib/chart-view-failure";
|
||||
import { OrbitWaiting } from "@/components/orbit-waiting";
|
||||
import type { ChartViewFailureStatus, ChartViewOk } from "@/lib/chart-view-contract";
|
||||
import { CHARA_ZERO_YEAR_LABEL, CHARA_ZERO_YEAR_NOTE, CHART_VIEW_COPY } from "@/lib/chart-view-labels";
|
||||
|
||||
@@ -154,7 +155,9 @@ export function ChartDashaTab({
|
||||
<Track {...view.dasha.vimshottari} asOf={asOf} />
|
||||
{charaPending || charaFailure ? (
|
||||
<section className="chart-page-dasha-track">
|
||||
<p className="chart-page-note">{charaPending ? CHART_VIEW_COPY.waitingLayer : chartLayerFailureCopy(charaFailure!)}</p>
|
||||
{charaPending
|
||||
? <OrbitWaiting label={CHART_VIEW_COPY.waitingLayer} />
|
||||
: <p className="chart-page-note">{chartLayerFailureCopy(charaFailure!)}</p>}
|
||||
</section>
|
||||
) : (
|
||||
<Track {...view.dasha.chara} asOf={asOf} />
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { EMPTY_NORTH_INDIAN_CHART, VedicChartSvg } from "@/components/personal-report/vedic-chart-svg";
|
||||
import { EMPTY_WESTERN_WHEEL, WesternWheelSvg } from "./western-wheel-svg";
|
||||
import { OrbitWaiting } from "@/components/orbit-waiting";
|
||||
|
||||
/** Only chart positions opt in; the shared page shell remains static. */
|
||||
export function ChartPageSkeleton({ copy, western = false }: { copy: string; western?: boolean }) {
|
||||
@@ -10,9 +11,10 @@ export function ChartPageSkeleton({ copy, western = false }: { copy: string; wes
|
||||
{western ? <WesternWheelSvg western={EMPTY_WESTERN_WHEEL} skeleton />
|
||||
: <VedicChartSvg chart={EMPTY_NORTH_INDIAN_CHART} ariaLabel={copy} skeleton />}
|
||||
</div>
|
||||
{/* Over the empty drawing, not under it: the finished chart has no line
|
||||
below it any more (BUG-1101), so a line here would make it jump. */}
|
||||
<p className="chart-page-note chart-page-skeleton-copy">{copy}</p>
|
||||
{/* Over the empty drawing, not under it, so the waiting stage and the
|
||||
finished one are the same height (BUG-1101). An orbit, not a sentence
|
||||
(2026-09-30); the sentence is for screen readers. */}
|
||||
<OrbitWaiting className="chart-page-skeleton-copy" label={copy} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* The one short-wait animation for secondary pages (2026-09-30, product: while
|
||||
* a chart or a day's ephemeris loads, show motion instead of 「……还没拿到。」).
|
||||
* It is the home loading screen's orbit ring at a smaller size, so the app has
|
||||
* one waiting motif. The sentence stays for screen readers only.
|
||||
*/
|
||||
export function OrbitWaiting({ label, className = "" }: Readonly<{ label: string; className?: string }>) {
|
||||
return (
|
||||
<div className={`orbit-waiting${className ? ` ${className}` : ""}`} role="status">
|
||||
<span className="app-loading-symbol" aria-hidden="true">
|
||||
<span className="app-loading-orbit" />
|
||||
<span className="app-loading-mark" />
|
||||
</span>
|
||||
<span className="sr-only">{label}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
import { CurrentSubjectSwitcher } from "@/components/current-subject-switcher";
|
||||
import { OrbitWaiting } from "@/components/orbit-waiting";
|
||||
import { SecondaryHeader } from "@/components/secondary-header";
|
||||
|
||||
export type SecondaryPageShellProps = {
|
||||
@@ -40,7 +41,7 @@ export function SecondaryPageShell({
|
||||
actions={actions}
|
||||
/>
|
||||
<div className="secondary-page">
|
||||
{waiting ? <p className="secondary-page-waiting">{waiting}</p> : children}
|
||||
{waiting ? <OrbitWaiting className="secondary-page-waiting" label={waiting} /> : children}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -45,16 +45,11 @@ export function StarterGreeting({ starterGreeting, dailyTrend = null, dailyTrend
|
||||
}
|
||||
|
||||
/* The line under the pills only appears when there is something to do about
|
||||
it. First runs and finished cases say nothing: the pill already names the
|
||||
action. The branch reads the entry summary itself, not the derived
|
||||
start/restart label, and a non-self subject wins because the case summary
|
||||
belongs to the account owner. */
|
||||
export function rectificationEntryHint(
|
||||
rectificationForSelf: boolean,
|
||||
summary: RectificationEntrySummary | null,
|
||||
): string | null {
|
||||
it: a non-self subject cannot start a rectification. A resumable case says
|
||||
nothing here any more (2026-09-30, product: 「这个提示可以去掉」); the case
|
||||
is still in the history list. */
|
||||
export function rectificationEntryHint(rectificationForSelf: boolean): string | null {
|
||||
if (!rectificationForSelf) return "生时校正暂时只支持本人。";
|
||||
if (summary?.hasResumableCase) return "上次那次校正还没完成,可以在历史对话里接着做。";
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -67,6 +62,7 @@ export type StarterEntriesProps = {
|
||||
readonly rectificationLoading: boolean;
|
||||
readonly rectificationMutationPending: boolean;
|
||||
readonly openRectificationFromHomepage: () => void;
|
||||
/** Still passed by the page; the hint no longer reads it (2026-09-30). */
|
||||
readonly rectificationEntrySummary: RectificationEntrySummary | null;
|
||||
readonly rectificationError: string;
|
||||
readonly rectificationSurfaceOpen: boolean;
|
||||
@@ -82,7 +78,6 @@ export function StarterEntries({
|
||||
rectificationLoading,
|
||||
rectificationMutationPending,
|
||||
openRectificationFromHomepage,
|
||||
rectificationEntrySummary,
|
||||
rectificationError,
|
||||
rectificationSurfaceOpen,
|
||||
rectificationErrorMessage,
|
||||
@@ -90,7 +85,7 @@ export function StarterEntries({
|
||||
const subjectId = useCurrentSubject();
|
||||
const rectificationForSelf = subjectId === "self";
|
||||
const dailyLabel = natalMinuteAvailable ? "今日星语" : "每日运势";
|
||||
const rectificationHint = rectificationEntryHint(rectificationForSelf, rectificationEntrySummary);
|
||||
const rectificationHint = rectificationEntryHint(rectificationForSelf);
|
||||
|
||||
return (
|
||||
<div className="starter-entries">
|
||||
|
||||
@@ -69,7 +69,9 @@ test("the strip is one sideways-scrolling line and the sheet is a three-column g
|
||||
assert.match(strip, /min-width:\s*0/);
|
||||
assert.match(cssDeclarations(".chart-page-type-grid", globalStyles), /grid-template-columns:\s*repeat\(3, minmax\(0, 1fr\)\)/);
|
||||
assert.match(cssDeclarations(".chart-page-type-menu", globalStyles), /width:\s*44px/);
|
||||
assert.match(cssDeclarations(".chart-page-type-cell", globalStyles), /min-height:\s*56px/);
|
||||
// 原值:min-height 56px;新值:64px;原因:2026-09-30 真机截图说明文字被截底,说明行改为最多两行、行高 1.4,格子加高以容纳
|
||||
assert.match(cssDeclarations(".chart-page-type-cell", globalStyles), /min-height:\s*64px/);
|
||||
assert.match(cssDeclarations(".chart-page-type-cell small", globalStyles), /line-clamp:\s*2/);
|
||||
assert.doesNotMatch(globalStyles, /\.chart-page-varga-chips/);
|
||||
});
|
||||
|
||||
|
||||
@@ -986,8 +986,11 @@ test("homepage CTA is server-driven from the entry summary, not the session list
|
||||
// 「restart」分支对应的那句已删除,改锁 hint 读的是 summary 本身、不读会话列表
|
||||
// 原因:TASK-starter-home-polish-20260926 D2 删掉「上次已经校正完…」一句;BUG-1041 查明
|
||||
// `=== "restart"` 从未命中(解析器读错键名)。「CTA 与提示由服务端 entry summary 驱动」这条意图不变。
|
||||
assert.match(page, /rectificationEntryHint\(rectificationForSelf, rectificationEntrySummary\)/);
|
||||
assert.match(page, /summary\?\.hasResumableCase/);
|
||||
// 原值:首页小字 rectificationEntryHint(rectificationForSelf, rectificationEntrySummary) 读 summary?.hasResumableCase
|
||||
// 新值:rectificationEntryHint(rectificationForSelf),不再读 summary(未完成校正的提示句已删)
|
||||
// 原因:2026-09-30 产品「首页的这个提示可以去掉」;CTA 仍由 entry summary 驱动(下方 resolveRectificationEntryAction 断言不变)
|
||||
assert.match(page, /rectificationEntryHint\(rectificationForSelf\)/);
|
||||
assert.doesNotMatch(page, /上次那次校正还没完成/);
|
||||
assert.doesNotMatch(page, /rectificationCardAction === "restart"/);
|
||||
assert.match(entryLib, /开始新的生时校正/);
|
||||
assert.match(entryLib, /再次校正/);
|
||||
|
||||
@@ -73,19 +73,21 @@ test("D2: the line under the pills only appears when the user has something to d
|
||||
assert.doesNotMatch(markup, REMOVED_HINTS);
|
||||
}
|
||||
|
||||
// An unfinished case: one sentence, the resumable one.
|
||||
// 原值:未完成的校正显示一句「上次那次校正还没完成,可以在历史对话里接着做。」
|
||||
// 新值:未完成的校正也不显示任何提示
|
||||
// 原因:2026-09-30 产品「首页的这个提示可以去掉」;校正会话仍在历史列表里
|
||||
const resumable = renderToStaticMarkup(<StarterEntries {...entriesProps({ rectificationEntrySummary: summaries.resumable })} />);
|
||||
assert.equal(hintOf(resumable), RESUMABLE_HINT);
|
||||
assert.equal(hintOf(resumable), null);
|
||||
assert.doesNotMatch(resumable, new RegExp(RESUMABLE_HINT));
|
||||
assert.doesNotMatch(resumable, REMOVED_HINTS);
|
||||
});
|
||||
|
||||
test("D2: a non-self subject gets the self-only sentence, even with an unfinished case on record", async () => {
|
||||
assert.equal(rectificationEntryHint(false, null), NON_SELF_HINT);
|
||||
assert.equal(rectificationEntryHint(false, summaries.resumable), NON_SELF_HINT);
|
||||
assert.equal(rectificationEntryHint(true, summaries.resumable), RESUMABLE_HINT);
|
||||
assert.equal(rectificationEntryHint(true, summaries.rectified), null);
|
||||
assert.equal(rectificationEntryHint(true, summaries.firstRun), null);
|
||||
assert.equal(rectificationEntryHint(true, null), null);
|
||||
// 原值:rectificationEntryHint(rectificationForSelf, summary),本人 + 未完成时返回 RESUMABLE_HINT
|
||||
// 新值:rectificationEntryHint(rectificationForSelf),本人一律无提示;非本人仍是「生时校正暂时只支持本人。」
|
||||
// 原因:2026-09-30 产品删除未完成校正提示,入参 summary 不再使用
|
||||
assert.equal(rectificationEntryHint(false), NON_SELF_HINT);
|
||||
assert.equal(rectificationEntryHint(true), null);
|
||||
|
||||
// Rendered through the real subject store, not just the helper.
|
||||
const harness = createClientLifecycleHarness();
|
||||
@@ -194,5 +196,6 @@ test("BUG-1041: the homepage parser reads what the entry-summary route actually
|
||||
const resumable = entrySummaryFromResponse(resumableWire);
|
||||
assert.equal(resumable.hasResumableCase, true);
|
||||
assert.equal(resumable.latestResumable?.lastActivityAt, "2026-09-26T00:00:00.000Z");
|
||||
assert.equal(rectificationEntryHint(true, resumable), RESUMABLE_HINT);
|
||||
// 原值:rectificationEntryHint(true, resumable) === RESUMABLE_HINT;新值:解析仍读出 hasResumableCase,但首页不再据此出提示;原因同上
|
||||
assert.equal(rectificationEntryHint(true), null);
|
||||
});
|
||||
|
||||
@@ -130,3 +130,34 @@ test("switching editions keeps the reader on the same chapter (BUG-1108)", () =>
|
||||
assert.match(view, /drawn=\{drawnThrough !== null && chapter <= drawnThrough\}/);
|
||||
assert.match(view, /useState\(section\.eager \|\| drawn\)/);
|
||||
});
|
||||
|
||||
// Product feedback 2026-09-30 01:00.
|
||||
test("the home no longer says an unfinished rectification is waiting in history", async () => {
|
||||
const { rectificationEntryHint } = await import("../src/components/starter-home");
|
||||
assert.equal(rectificationEntryHint(true), null);
|
||||
assert.doesNotMatch(read("../src/components/starter-home.tsx"), /上次那次校正还没完成/);
|
||||
});
|
||||
|
||||
test("chart-type cells show the whole meaning line (two lines, CJK-safe line height)", () => {
|
||||
const css = read("../src/app/globals.css");
|
||||
const small = css.slice(css.indexOf(".chart-page-type-cell small {"), css.indexOf("}", css.indexOf(".chart-page-type-cell small {")));
|
||||
assert.match(small, /line-height: 1\.4/);
|
||||
assert.match(small, /-webkit-line-clamp: 2/);
|
||||
assert.doesNotMatch(small, /white-space: nowrap/);
|
||||
});
|
||||
|
||||
test("chart, ephemeris and report waits show the orbit, the sentence only for screen readers", () => {
|
||||
const orbit = read("../src/components/orbit-waiting.tsx");
|
||||
assert.match(orbit, /<span className="sr-only">\{label\}<\/span>/);
|
||||
assert.match(orbit, /app-loading-orbit/);
|
||||
assert.match(read("../src/components/secondary-page-shell.tsx"), /<OrbitWaiting className="secondary-page-waiting" label=\{waiting\} \/>/);
|
||||
assert.match(read("../src/components/chart-page/chart-page-skeleton.tsx"), /<OrbitWaiting className="chart-page-skeleton-copy" label=\{copy\} \/>/);
|
||||
assert.doesNotMatch(read("../src/components/chart-page/chart-page-skeleton.tsx"), /<p className="chart-page-note/);
|
||||
});
|
||||
|
||||
test("the sky button carries a drawn constellation, not the sparkle", () => {
|
||||
const entry = read("../src/components/birth-sky/birth-sky-entry.tsx");
|
||||
assert.doesNotMatch(entry, /Sparkles/);
|
||||
assert.match(entry, /<ConstellationIcon \/>/);
|
||||
assert.equal((entry.match(/<circle /g) ?? []).length, 4);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user