侧栏此前在第一条会话之前压着三段:星盘名字 chip 组、收藏对话 <details>、
历史对话 <details>——两个折叠箭头,底下都没有值得折叠的东西。现在是一条
平铺列表:收藏作为首个标签组(带 13px 星标),其余沿用既有的日期分组。
星盘入口收敛到一处。这里与任务书 D6 的字面写法方向相反:D6 说留侧栏删
账户菜单,我做的是删侧栏留账户菜单。理由——D6 写于侧栏只有 2 个导航项时,
现在是 4 个;且 chip 点下去只是开弹窗(page.tsx 里三个回调都是
openAccountDialog("chart-library")),一组只会开弹窗的名字没有导航价值。
连带删 charts/onSelectChart/onAddChart props、SidebarChart 类型、
sidebarCharts 派生与一批 CSS。
助手头像删除,--assistant-content-inset 由 calc(32px + gap) 归零,
追问 chip 与运行时间轴改为与正文对齐。/jyotish-logo.png 文件保留。
顺带关闭 R2 留下的隐患:入口 pill 36px 低于 44px 触摸推荐值,补
::after inset -4px 热区扩展,并在 touch-target-contract 里接替
已删除的 .chart-nav-chip。
测试 3350 不变,fail 仍 31 且与基线逐条一致;/ 仍 Static;
CSS gzip 41,044→39,825(−3.0%),三轮累计 −3.1%。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
65 lines
3.3 KiB
TypeScript
65 lines
3.3 KiB
TypeScript
import assert from "node:assert/strict";
|
||
import { readFileSync } from "node:fs";
|
||
import test from "node:test";
|
||
|
||
import { cssDeclarations } from "./css-contract-test-support.ts";
|
||
|
||
const globalStyles = readFileSync(new URL("../src/app/globals.css", import.meta.url), "utf8");
|
||
|
||
function minHeightPx(selector: string) {
|
||
const matches = [...cssDeclarations(selector, globalStyles).matchAll(/min-height:\s*(\d+)px/g)]
|
||
.map((hit) => Number(hit[1]));
|
||
assert.ok(matches.length > 0, `${selector} must declare min-height`);
|
||
return Math.max(...matches);
|
||
}
|
||
|
||
function hasHitExpandPseudo(selector: string) {
|
||
const after = cssDeclarations(`${selector}::after`, globalStyles);
|
||
assert.match(after, /position:\s*absolute/);
|
||
assert.match(after, /content:\s*""/);
|
||
return after;
|
||
}
|
||
|
||
test("40px controls grow to a 44px box when that does not pack a scrolling list badly", () => {
|
||
assert.ok(minHeightPx(".select-item") >= 44);
|
||
assert.ok(minHeightPx(".birth-time-window-details .birth-time-skip-button") >= 44);
|
||
assert.ok(minHeightPx(".report-center-section-heading button") >= 44);
|
||
});
|
||
|
||
test("icon and chip controls keep their visual size and expand the hit with a pseudo-element", () => {
|
||
const actions = cssDeclarations(".message-actions button", globalStyles);
|
||
assert.match(actions, /width:\s*26px/);
|
||
assert.match(actions, /height:\s*26px/);
|
||
assert.match(cssDeclarations(".message-actions", globalStyles), /gap:\s*1px/);
|
||
const actionHit = hasHitExpandPseudo(".message-actions button");
|
||
// 原值: 热区锁 27×34(44×44 会与相邻按钮和 follow-up 重叠)。
|
||
// 新值: 细指针仍是 27×34;粗指针见下一条,gap 20px + 底边 20px 后才放大到 44×44。
|
||
// 原因: BUG-695,触屏点赞容易点成点踩。
|
||
assert.match(actionHit, /width:\s*27px/);
|
||
assert.match(actionHit, /height:\s*34px/);
|
||
|
||
// 原值:`.chart-nav-chip`(侧栏星盘列表的名字 chip)
|
||
// 新值:`.starter-entry`(空态的两枚入口 pill)
|
||
// 原因:星盘列表 chip 已随入口收敛删除(D6)。空态的入口 pill 是这一类「视觉小于
|
||
// 44px、靠伪元素扩热区」控件的新成员,36px 视觉 + -4px 外扩,正好归这条合同管。
|
||
assert.equal(minHeightPx(".starter-entry"), 36);
|
||
assert.match(hasHitExpandPseudo(".starter-entry"), /inset:\s*-4px/);
|
||
|
||
const auth = cssDeclarations(".auth-links button", globalStyles);
|
||
assert.match(auth, /min-height:\s*32px/);
|
||
assert.match(hasHitExpandPseudo(".auth-links button"), /inset:\s*-4px/);
|
||
});
|
||
|
||
test("coarse pointers get a 44×44 message-action hit that does not overlap neighbours", () => {
|
||
const coarseStart = globalStyles.indexOf("@media (pointer: coarse)");
|
||
assert.notEqual(coarseStart, -1);
|
||
const coarse = globalStyles.slice(coarseStart, globalStyles.indexOf("}", globalStyles.indexOf(".markdown-code-copy", coarseStart)) + 1);
|
||
assert.match(coarse, /\.message-actions \{[\s\S]*gap:\s*var\(--space-5\)/);
|
||
assert.match(coarse, /margin-bottom:\s*var\(--space-5\)/);
|
||
assert.match(coarse, /\.message-actions button::after \{[\s\S]*width:\s*44px;[\s\S]*height:\s*44px;/);
|
||
assert.match(coarse, /\.markdown-code-copy \{[\s\S]*min-height:\s*44px;/);
|
||
const base = globalStyles.slice(0, coarseStart);
|
||
assert.match(base, /\.message-actions \{[\s\S]*gap:\s*1px;/);
|
||
assert.match(base, /\.message-actions button::after \{[\s\S]*width:\s*27px;[\s\S]*height:\s*34px;/);
|
||
});
|