Groundwork for redrawing the icons on their pixel grids. A name is now
<icon><px> (server14, server16, server24) and must match the size token
where it renders: 14 at --icon-size-sm, 16 at -md, 24 at -xl.
tdesignLoading is the one exception, since it spins. Every name not yet
redrawn aliases its TDesign glyph, so nothing changes on screen except
the manager-open overlay icon, which moves from lg to xl ("a status
mark on a card").
- pixel-icons.ts holds the redrawn glyphs, so far add14 (the + from
3f7145d, renamed from pixelAdd).
- TS code that picks icons takes Icon14 / Icon16 (menu items, file
glyphs, the copy arrow, toasts, transfer states), so build:ui
rejects a wrong name.
- icons.spec.ts checks every <ng-icon> in the skins: it has a size
token, and each literal name, both sides of a [name] ternary
included, is registered and drawn for that token's grid.
- TDesign's file1 is now fileText, since file1 plus a suffix would
read file114.
Co-Authored-By: Claude <noreply@anthropic.com>
34 lines
1.6 KiB
TypeScript
34 lines
1.6 KiB
TypeScript
import { expect, test } from 'bun:test';
|
|
import { APP_ICONS } from './icons';
|
|
|
|
// The px grid of each size token (styles.css); lg only carries the spinner.
|
|
const GRID: Record<string, string> = { sm: '14', md: '16', lg: '20', xl: '24' };
|
|
const SKINS = `${import.meta.dir}/../skins`;
|
|
|
|
// Templates can't type-check icon names, so read them: every <ng-icon> has a
|
|
// size token, and every literal name (both sides of a [name] ternary too) is
|
|
// registered and drawn for that token's grid. Names computed in TS are typed.
|
|
test('every template icon is registered and drawn for the size it renders at', async () => {
|
|
const problems: string[] = [];
|
|
for (const file of new Bun.Glob('**/*.{html,ts}').scanSync(SKINS)) {
|
|
const src = (await Bun.file(`${SKINS}/${file}`).text()).replace(/<!--[\s\S]*?-->/g, '');
|
|
for (const [tag] of src.matchAll(/<ng-icon\b[^>]*>/g)) {
|
|
const token = tag.match(/size="var\(--icon-size-(\w+)\)"/)?.[1];
|
|
if (!token || !GRID[token]) {
|
|
problems.push(`${file}: no size token in ${tag}`);
|
|
continue;
|
|
}
|
|
const bound = tag.match(/\[name\]="([^"]*)"/)?.[1] ?? '';
|
|
// a ternary's results, not its condition ('local' in `id === 'local' ? …`)
|
|
const names = [...tag.matchAll(/\bname="(\w+)"/g), ...bound.matchAll(/[?:]\s*'(\w+)'/g)].map((m) => m[1]);
|
|
for (const name of names) {
|
|
if (!Object.hasOwn(APP_ICONS, name)) problems.push(`${file}: ${name} is not registered`);
|
|
else if (name !== 'tdesignLoading' && !name.endsWith(GRID[token])) {
|
|
problems.push(`${file}: ${name} renders at ${token} (${GRID[token]}px)`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
expect(problems).toEqual([]);
|
|
});
|