From 90b1b6fba9d0628c20039be117ef948c92c84c2a Mon Sep 17 00:00:00 2001 From: Jesse_Chen Date: Wed, 30 Sep 2026 11:19:38 +0800 Subject: [PATCH] fix(chart): symbol bubble no longer flickers (global tooltip rule switched the stage's pointer events off); rounded chart tables (BUG-1120) Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE --- CHANGELOG.md | 5 ++++ docs/BUG_HISTORY.md | 15 ++++++++++ frontend/DESIGN.md | 2 ++ frontend/src/app/globals.css | 35 +++++++++++++++++++---- frontend/tests/chart-symbol-help.test.tsx | 13 +++++++++ 5 files changed, 64 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95a4385a..89502910 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # 印度占星 Skill 更新日志 +## 2026-09-30 — 星盘符号气泡不再闪;星盘表格恢复圆角 + +- 鼠标停在星盘里的行星、上升或星座编号上,说明气泡会稳定显示;之前鼠标每动一下气泡就消失再出现。 +- 星盘页下方的行星表、分盘表、Bhava 表和西洋表加上圆角边框,与上方盘面外框一致。Skill 版本不 bump。 + ## 2026-09-30 — 性别只在星盘档案里设置 - 设置 →「个人资料」里的性别选项删除;本人和其他人的性别都在「星盘档案」→「编辑」里改,详情卡照常显示。已保存的性别不受影响。Skill 版本不 bump。 diff --git a/docs/BUG_HISTORY.md b/docs/BUG_HISTORY.md index 83e08bc2..5360568b 100644 --- a/docs/BUG_HISTORY.md +++ b/docs/BUG_HISTORY.md @@ -14948,3 +14948,18 @@ - 防复发:同一字段新增编辑入口时,同一轮撤掉旧入口并在 DESIGN 标明唯一入口。 - 相关记录:BUG-1081、TASK-consult-gender-optional-20260927 - 修复版本:分支 `codex/gender-archive-only-20260930` + +## BUG-1120 | 星盘符号说明气泡在鼠标悬停时频闪 + +- 状态:resolved(代码 + 回归测试 + 本机 Chromium 复现 / 复验;待部署) +- 首次发现 / 最近更新:2026-09-30 / 2026-09-30 +- 影响面:`frontend/src/app/globals.css` 的全局 `:has(> [role="tooltip"])` 规则;`frontend/src/components/chart-page/chart-symbol-help.tsx`(印度盘与西洋盘共用)。 +- 现象:产品反馈「鼠标浮动到图标上方会频闪」。本机 Chromium 用真实 golden 盘复现:在任一符号上移动 1px,气泡被移除再插入,22 个标记全部如此。 +- 触发条件:桌面鼠标悬停星盘内任一可说明的标记(行星、上升、星座编号)。 +- 根因:侧栏悬停提示的全局规则 `:has(> [role="tooltip"]) { pointer-events: none }` 本为弹出层定位器写的;气泡(`role="tooltip"`)是 `.chart-page-symbol-help` 的直接子元素,于是整个星盘舞台在气泡出现时失去指针事件 → 标记收到 pointerout(relatedTarget 为外框)→ 气泡关闭 → 舞台恢复命中 → pointerover → 气泡再开,循环即频闪。BUG-1100 引入气泡时单测只在无样式的 DOM 里跑,看不到这条全局 CSS。 +- 修复:全局规则改为 `:has(> [role="tooltip"]):not(.chart-page-symbol-help)`;气泡保留 `role="tooltip"`。 +- 验证:`chart-symbol-help.test.tsx` 新增 CSS 合同(带 pointer-events:none 的 tooltip 规则必须排除星盘舞台);本机 Chromium 复验:同样的移动序列下气泡不再移除 / 插入,只在盘心相邻星座编号间切换文字;chart 相关 158 条测试通过。 +- 防复发:新增内联 `role="tooltip"` 时检查全局 `:has(> [role="tooltip"])` 规则的作用范围;悬停类交互需在真实浏览器(带全站 CSS)里至少走一次。 +- 相关记录:BUG-1100(气泡引入) +- 修复版本:分支 `codex/notice-loading-polish-20260930` + diff --git a/frontend/DESIGN.md b/frontend/DESIGN.md index 5ed77638..a166c96f 100644 --- a/frontend/DESIGN.md +++ b/frontend/DESIGN.md @@ -1094,6 +1094,8 @@ D40 / D45 / D60 的表格上方,出生时间不是「已校正」时多一句 每一张 `.chart-page-planet-table`(本命、分盘、月亮盘、Bhava 两张、行运、西洋相位)都包在 `.chart-page-planet-table-wrap` 里:`min-width: 0` + `overflow-x: auto`。375px 下表格在自己的盒子里横滚,页面不横滚。`min-width: 0` 和 overflow 一样是必需的——grid item 默认按内容定宽,少了它表格会把页面撑宽而不是滚动。外层 `.secondary-page` 的单列同理是 `minmax(0, 1fr)`(BUG-1083),否则撑宽发生在更外面一层。印度盘那张从四列扩到八列后 `min-width` 由 `26rem` 提到 `34rem`。 +**圆角(2026-09-30)。** 行星表和西洋表与上方盘面外框同一语言:表格 1px `--color-border` 边框 + `--radius-lg` 圆角,`border-collapse: separate`(collapse 下圆角不生效),四个角单元格各自圆角;换宫 / 选中 / 悬停的底色落在单元格上而不是行上,这样角上的格子也能跟着圆。表题(caption)在边框外。 + **印度盘行星表的八列(2026-09-18)。** 盘里不再写的东西全部落在这里: | 列 | 内容 | diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index 94142356..93f7c630 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -1968,7 +1968,11 @@ button:disabled:where(:not([data-slot="button"])) { cursor: default; opacity: .4 .account-menu-danger, .account-menu-danger > svg { color: var(--color-danger); } .account-menu-danger[data-highlighted] { background: var(--color-danger-muted); } -:has(> [role="tooltip"]) { z-index: 40; max-width: calc(100vw - var(--space-6)); pointer-events: none; } +/* For portalled tooltip positioners only. The chart's symbol bubble is an inline + child of the stage that holds the whole drawing; matching it switched the + drawing's pointer events off while the bubble was up, so the mark lost the + hover, the bubble closed, the mark got it back — a flicker loop (BUG-1120). */ +:has(> [role="tooltip"]):not(.chart-page-symbol-help) { z-index: 40; max-width: calc(100vw - var(--space-6)); pointer-events: none; } [role="tooltip"] { max-width: min(240px, calc(100vw - var(--space-6))); padding: var(--space-2) var(--space-3); border: 1px solid var(--sidebar-border); border-radius: var(--radius-md); background: var(--sidebar-solid); color: var(--sidebar-foreground); box-shadow: var(--shadow-elevated); pointer-events: none; font-size: var(--type-caption); font-weight: 500; line-height: 1.4; transform-origin: var(--transform-origin); transition: opacity 120ms ease-out, transform 120ms var(--ease-out); } [role="tooltip"][data-starting-style], [role="tooltip"][data-ending-style] { opacity: 0; transform: translateX(var(--space-1)); } @@ -5345,7 +5349,8 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class .chart-page-varga-table-block { min-width: 0; } .chart-page-varga-table-block > .chart-page-planet-table-wrap + .chart-page-planet-table-wrap { margin-top: var(--space-4); } /* A body the Bhava boundaries move to another house. */ -.chart-page-planet-table tr.is-shifted { background: var(--color-selected); } +.chart-page-planet-table tr.is-shifted > td, +.chart-page-planet-table tr.is-shifted > th { background: var(--color-selected); } .chart-page-waiting-plot { width: 100%; min-width: 0; @@ -5482,7 +5487,6 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class /* Eight columns now (symbol+name, longitude, speed, house, nakshatra, its lord, pada, dignity); 26rem was sized for four and crushed the last three. */ min-width: 34rem; - border-collapse: collapse; background: var(--color-canvas); font-size: var(--type-body-sm); } @@ -5768,7 +5772,6 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class } .chart-page-western-table { width: 100%; - border-collapse: collapse; background: var(--color-canvas); font-size: var(--type-body-sm); } @@ -5787,8 +5790,28 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class } .chart-page-western-num { font-variant-numeric: tabular-nums; } .chart-page-western-table tbody tr[tabindex] { cursor: pointer; } -.chart-page-western-table tbody tr[tabindex]:hover { background: var(--color-canvas-muted); } -.chart-page-western-table tr.is-selected { background: var(--color-selected); } +.chart-page-western-table tbody tr[tabindex]:hover > td { background: var(--color-canvas-muted); } +.chart-page-western-table tr.is-selected > td { background: var(--color-selected); } +/* Rounded like the chart stage above them (2026-09-30, product: 「表格圆角怎么没了」). + Separate borders so the table's own radius clips; row tints sit on the cells + so the corner cells can round them too. */ +.chart-page-planet-table, +.chart-page-western-table { + border-collapse: separate; + border-spacing: 0; + border: 1px solid var(--color-border); + border-radius: var(--radius-lg); +} +.chart-page-planet-table thead th:first-child, +.chart-page-western-table thead th:first-child { border-top-left-radius: calc(var(--radius-lg) - 1px); } +.chart-page-planet-table thead th:last-child, +.chart-page-western-table thead th:last-child { border-top-right-radius: calc(var(--radius-lg) - 1px); } +.chart-page-planet-table tbody tr:last-child > :first-child, +.chart-page-western-table tbody tr:last-child > :first-child { border-bottom-left-radius: calc(var(--radius-lg) - 1px); } +.chart-page-planet-table tbody tr:last-child > :last-child, +.chart-page-western-table tbody tr:last-child > :last-child { border-bottom-right-radius: calc(var(--radius-lg) - 1px); } +.chart-page-planet-table tbody tr:last-child > *, +.chart-page-western-table tbody tr:last-child > * { border-bottom: 0; } .chart-page-unavailable > p { margin: 0 0 var(--space-3); font-size: var(--type-body-md); } @media (min-width: 768px) { diff --git a/frontend/tests/chart-symbol-help.test.tsx b/frontend/tests/chart-symbol-help.test.tsx index 80e850bb..22f39732 100644 --- a/frontend/tests/chart-symbol-help.test.tsx +++ b/frontend/tests/chart-symbol-help.test.tsx @@ -155,3 +155,16 @@ test("Western visible caption and hit target explain the same nearest planet as assert.deepEqual(h.errors, []); } finally { await h.close(); } }); + +test("the global tooltip-positioner rule does not switch off the chart stage's pointer events (BUG-1120)", () => { + // The bubble is an inline role="tooltip" child of .chart-page-symbol-help. A bare + // `:has(> [role="tooltip"]) { pointer-events: none }` matched the stage, so the + // drawing under the cursor stopped being hoverable while the bubble was up and + // the bubble flickered on every mouse move (reproduced in Chromium). + const css = readFileSync(new URL("../src/app/globals.css", import.meta.url), "utf8"); + const rules = [...css.matchAll(/([^{}]*:has\(>\s*\[role="tooltip"\]\)[^{}]*)\{([^}]*)\}/g)]; + assert.ok(rules.length > 0); + for (const [, selector, body] of rules) { + if (/pointer-events:\s*none/.test(body)) assert.match(selector, /:not\(\.chart-page-symbol-help\)/, selector.trim()); + } +});