Skip to content

Commit 78bf8ae

Browse files
committed
feat(notes): 过滤面板按 tag_colors 着色
1 parent 81d6296 commit 78bf8ae

3 files changed

Lines changed: 91 additions & 2 deletions

File tree

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// @vitest-environment jsdom
2+
/**
3+
* NoteListToolbar 过滤芯片着色测试(批 7 T18;§C2.4 / §C11.3「做」的落点)。
4+
*
5+
* @ai-context: 判据 = 「过滤面板的芯片色与 `tag_colors` 一致」(§C2.4 逐字)—— 与 `NoteListRow`
6+
* 同口径(`paletteHex(id, theme) + "22"` 透明度后缀)。上色**只动 `background`**:本文件的
7+
* `nativeButton 4 / 边框 3 / 越界圆角 2` 三格已满(§C9.12),判据见 `surfaceBaseline.ts`
8+
* 与 `nativeButtonBaseline.ts`(本件不做棘轮断言 —— 那是棘轮判据件的职责,重复一份会造两套口径)。
9+
* @ai-context: 具名断言的变量体 = 「删掉 toolbar 的 `tagColors` 透传」⇒ 有色芯片回落默认灰底,
10+
* 两条断言(等于查色值 / 不等于无色底)同时红。
11+
*/
12+
import { cleanup, render, screen } from "@testing-library/react";
13+
import { afterEach, describe, expect, it } from "vitest";
14+
import { paletteHex } from "../utils/colorPalette";
15+
import NoteListToolbar from "./NoteListToolbar";
16+
17+
afterEach(cleanup);
18+
19+
/**
20+
* `#RRGGBBAA` → jsdom(cssstyle)归一后的 `rgba(r, g, b, a)`。
21+
* Why 不写字面量:色板真源是 `paletteHex`(改真源时本判据应随之走,而不是留一个过期常量)。
22+
*/
23+
const asRgba = (hex8: string): string => {
24+
const [r, g, b] = [1, 3, 5].map((i) => parseInt(hex8.slice(i, i + 2), 16));
25+
const alpha = Number((parseInt(hex8.slice(7, 9), 16) / 255).toFixed(3));
26+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
27+
};
28+
29+
const baseProps = { selectionMode: false,
30+
selectionCount: 0,
31+
onToggleBatchMode: () => {},
32+
onCreate: () => {},
33+
keyword: "",
34+
onKeywordChange: () => {},
35+
onRefresh: () => {},
36+
sortMode: "updated-desc" as const,
37+
onSortModeChange: () => {},
38+
allTags: ["化妆", "编程"],
39+
tagFilter: null,
40+
onTagFilterChange: () => {},
41+
};
42+
43+
describe("NoteListToolbar 过滤芯片着色(批 7 T18 · §C11.3)", () => {
44+
it("① 有色芯片的底色 == paletteHex(查色表值) + 22(与 NoteListRow 同口径)", () => {
45+
// Arrange / Act
46+
render(<NoteListToolbar {...baseProps} tagColors={{ 化妆: "purple" }} />);
47+
// Assert
48+
const colored = screen.getByTestId("tag-chip-化妆");
49+
const plain = screen.getByTestId("tag-chip-编程");
50+
expect(colored.style.background, "有色芯片没取到查色表的值").toBe(asRgba(`${paletteHex("purple", "light")}22`));
51+
expect(colored.style.background, "有色芯片的底色不含色板 RGB(查色表取错了 id)").toContain("142, 78, 198");
52+
expect(plain.style.background, "无色芯片不该继承别人的色").not.toBe(colored.style.background);
53+
});
54+
55+
it("② 缺省 tagColors ⇒ 沿用原底色(加法式改动,无查色表时行为不变)", () => {
56+
// Arrange / Act
57+
render(<NoteListToolbar {...baseProps} />);
58+
// Assert:与加了空表的渲染逐字一致
59+
const chip = screen.getByTestId("tag-chip-化妆");
60+
expect(chip.style.background).toBe("rgb(249, 250, 251)");
61+
});
62+
63+
it("③ 选中态的边框/字色仍是原契约(上色不夺走选中态)", () => {
64+
// Arrange / Act
65+
render(<NoteListToolbar {...baseProps} tagFilter="化妆" tagColors={{ 化妆: "purple" }} />);
66+
// Assert
67+
const chip = screen.getByTestId("tag-chip-化妆");
68+
expect(chip.style.border).toContain("rgb(13, 148, 136)");
69+
expect(chip.style.color).toBe("rgb(13, 148, 136)");
70+
});
71+
});

‎app/src/components/NoteListToolbar.tsx‎

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,15 @@
1212
* 避免两处样式漂移;`btn` 仅作为其基底,保持模块私有。
1313
* @ai-context: 边界——`SortMode` 以 **type-only import** 自 NoteListView 取(编译期
1414
* 擦除,无运行时循环依赖);公共 API(`export type SortMode`)仍归主文件。
15+
* @ai-context: 批 7 T18(C2.4 / §C11.3):过滤芯片按 `tagColors` **上色**——与 `NoteListRow`
16+
* 同口径(`paletteHex(id, theme) + "22"` 透明度后缀)。`allTags` 仍是 `string[]`,
17+
* 只多一张可选查色表;本文件 nativeButton 4 / 边框 3 / 越界圆角 2 三格已满
18+
* ⇒ 上色只动 `background`,**不新增**这三类字面量。
1519
*/
20+
import { useMemo } from "react";
1621
import type { SortMode } from "./NoteListView";
22+
import { paletteHex } from "../utils/colorPalette";
23+
import type { ThemeMode } from "../utils/colorPalette";
1724

1825
const btn: React.CSSProperties = { padding: "5px 10px", cursor: "pointer", fontSize: 12 };
1926
/** 幽灵按钮基底(顶栏「选择」+ 批量栏/选集菜单 6 处共用) */
@@ -36,13 +43,23 @@ interface Props {
3643
allTags: string[];
3744
tagFilter: string | null;
3845
onTagFilterChange: (tag: string | null) => void;
46+
/** 批 7 T18(C2.4):标签 → 色板 id 查色表(缺省 ⇒ 芯片沿用原底色) */
47+
tagColors?: Record<string, string>;
3948
}
4049

4150
export default function NoteListToolbar({
4251
selectionMode, selectionCount, onToggleBatchMode, onCreate, onCollapse,
4352
keyword, onKeywordChange, onRefresh, sortMode, onSortModeChange,
44-
allTags, tagFilter, onTagFilterChange,
53+
allTags, tagFilter, onTagFilterChange, tagColors,
4554
}: Props) {
55+
// v0.14 B:当前主题(跟随 prefers-color-scheme;jsdom 无 matchMedia 回退 light)
56+
const theme: ThemeMode = useMemo(
57+
() => (typeof window !== "undefined" && window.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light"),
58+
[],
59+
);
60+
/** 芯片底色:有标签色 ⇒ 与 `NoteListRow` 同口径的色板值 + `22`;否则沿用原选中/默认底色 */
61+
const chipBackground = (t: string): string =>
62+
tagColors?.[t] ? `${paletteHex(tagColors[t], theme)}22` : tagFilter === t ? "#f0fdfa" : "#f9fafb";
4663
return (
4764
<>
4865
<div style={{ padding: "10px 14px", borderBottom: "1px solid #e5e7eb", fontWeight: 600, display: "flex", alignItems: "center", gap: 8 }}>
@@ -85,7 +102,7 @@ export default function NoteListToolbar({
85102
<span onClick={() => onTagFilterChange(null)} style={{ fontSize: 11, color: "#6b7280", cursor: "pointer", border: "1px solid #d1d5db", borderRadius: 10, padding: "1px 6px", background: "#f3f4f6" }}>清除过滤 ✕</span>
86103
)}
87104
{allTags.map((t) => (
88-
<span key={t} onClick={() => onTagFilterChange(t)} style={{ fontSize: 11, cursor: "pointer", border: `1px solid ${tagFilter === t ? "#0d9488" : "#e5e7eb"}`, borderRadius: 10, padding: "1px 6px", background: tagFilter === t ? "#f0fdfa" : "#f9fafb", color: tagFilter === t ? "#0d9488" : "#6b7280" }}>{t}</span>
105+
<span key={t} data-testid={`tag-chip-${t}`} onClick={() => onTagFilterChange(t)} style={{ fontSize: 11, cursor: "pointer", border: `1px solid ${tagFilter === t ? "#0d9488" : "#e5e7eb"}`, borderRadius: 10, padding: "1px 6px", background: chipBackground(t), color: tagFilter === t ? "#0d9488" : "#6b7280" }}>{t}</span>
89106
))}
90107
</div>
91108
)}

‎app/src/components/NoteListView.tsx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ export default function NoteListView({
160160
allTags={allTags}
161161
tagFilter={tagFilter}
162162
onTagFilterChange={onTagFilterChange}
163+
tagColors={tagColors}
163164
/>
164165

165166
<NoteListBody

0 commit comments

Comments
 (0)