35 lines
1.5 KiB
TypeScript
35 lines
1.5 KiB
TypeScript
import { readdirSync, readFileSync } from "node:fs";
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
// DESIGN "A glyph means one thing": a menu row wears the glyph its action wears everywhere else. The
|
|
// "…" menus' Play from the beginning wore the skip arrow ⏮, which beside the player is Previous, while
|
|
// the card's own Restart wore RotateCcw — and RotateCcw was the same menu's Reset, the Files menu's
|
|
// Redownload. Each row is a `label: t("…")` followed by its `icon`.
|
|
const ROW_GLYPHS: Record<string, string> = {
|
|
"card.restartTitle": "RotateCcw",
|
|
"card.clearProgress": "Eraser",
|
|
"files.actions.redownload": "RefreshCw",
|
|
};
|
|
|
|
const root = new URL("../", import.meta.url);
|
|
const sources = () =>
|
|
readdirSync(root, { recursive: true, encoding: "utf8" })
|
|
.map((f) => f.replace(/\\/g, "/"))
|
|
.filter((f) => /\.tsx?$/.test(f) && !f.includes(".test.") && !f.startsWith("design-lab/"))
|
|
.map((f) => ({ f, src: readFileSync(new URL(f, root), "utf8") }));
|
|
|
|
describe("a menu row's glyph", () => {
|
|
for (const [key, glyph] of Object.entries(ROW_GLYPHS))
|
|
it(`${key} wears ${glyph}`, () => {
|
|
const row = new RegExp(
|
|
`label: t\\("${key.replace(/\./g, "\\.")}"\\),\\s*icon: (?:<|icon\\()(\\w+)`,
|
|
"g",
|
|
);
|
|
const worn = sources().flatMap(({ f, src }) =>
|
|
[...src.matchAll(row)].map((m) => `${f}: ${m[1]}`),
|
|
);
|
|
expect(worn.length, key).toBeGreaterThan(0);
|
|
expect(worn.filter((w) => !w.endsWith(`: ${glyph}`))).toEqual([]);
|
|
});
|
|
});
|