faeb7521ae
Build Kvitt images / build (push) Failing after 2h19m45s
SPEC §15.6 W-21 to W-23, §9.12 CP-1 to CP-14, FR-22 (D-174, D-180): - api/cards.ts: the card snapshot read through E-40 (pulled from 0, then from its cursor on focus, every 60 s and after every card write; cursor_ahead restarts), E-44 sent at once; shared because cards, expenses, accounts and settings read it. - features/cards: W-21 Kortköp (header with artwork, Uppdatera via E-42, filters with counts, day groups, Preliminär/Insättning/Utländsk valuta, the CP-10 match chip, the purchase as a side panel from 720 px and a dialog below with every S-23 sheet action, expiring/expired/fetch-failed/first-fetch/empty states, ?attempt= polling E-38 every 2 s, ?account= as S-27); W-22 catalogue and connect step (history 7/30/90/180, E-37 with client web, the bank's https page in the same tab); W-23 the connection (E-41 shorter history, renew, E-43 with erase_handled). The committed SJ Prio artwork mapped from image key sj_prio_mastercard, the D-173 drawn card for unknown keys. - lib/domain/matchCardPurchase (§14.5.8) with its cases; vectors.test.ts runs K1's match_card_purchase.json against it (moved from NOT_PORTED to PORTED). - W-5 ?cardPurchase= prefill per CP-9 and the link on save; W-6 card line with Ta bort koppling; W-3 "Från kortköp" while connected; W-13 "Anslut kort" row. - Sidebar and bottom bar: Kortköp after Översikt (D-172); icons credit_card, link_off, visibility_off added to the generated table; /cards in the dev proxy. - test/cards.ts fixtures and the fake server's card endpoints. Strings: the §13.3 keys from K2's docs/ux/strings.csv (dictionaries regenerated), plus K2's cards_foreign_amount (the foreign amount) and settings_cards_expired (W-13 row of an ended connection); web-only texts as web_cards_ and web_expenses_ keys. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
196 lines
4.9 KiB
JavaScript
196 lines
4.9 KiB
JavaScript
// Builds src/design/icons.generated.ts from Material Symbols Rounded (design-spec §2.12; Apache-2.0):
|
|
// outline = @material-symbols/svg-500 (FILL 0, weight 500), filled = @material-symbols/svg-600 (FILL 1, weight 600).
|
|
// Only the icons listed here are embedded; a feature plan adds a name and runs `npm run icons:import`.
|
|
// `--check` compares with the file on disk instead of writing.
|
|
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
|
|
/** The 33 category icon tokens of SPEC §9.7, in CategoryIcons.ALL order. Both variants (picker and tiles). */
|
|
export const CATEGORY_ICONS = [
|
|
'shopping_cart',
|
|
'restaurant',
|
|
'local_cafe',
|
|
'home',
|
|
'bolt',
|
|
'water_drop',
|
|
'wifi',
|
|
'directions_car',
|
|
'train',
|
|
'local_gas_station',
|
|
'flight',
|
|
'hotel',
|
|
'luggage',
|
|
'movie',
|
|
'music_note',
|
|
'sports_esports',
|
|
'fitness_center',
|
|
'medical_services',
|
|
'medication',
|
|
'shopping_bag',
|
|
'checkroom',
|
|
'pets',
|
|
'child_care',
|
|
'school',
|
|
'card_giftcard',
|
|
'celebration',
|
|
'build',
|
|
'chair',
|
|
'subscriptions',
|
|
'category',
|
|
'key',
|
|
'shield',
|
|
'account_balance',
|
|
];
|
|
|
|
/** UI icons of design-spec §2.12 plus the web's own (search, keyboard, logout, language, theme). Outline variant. */
|
|
const UI_OUTLINE = [
|
|
'home',
|
|
'bar_chart',
|
|
'settings',
|
|
'add',
|
|
'close',
|
|
'arrow_back',
|
|
'more_vert',
|
|
'edit',
|
|
'delete',
|
|
'check',
|
|
'swap_horiz',
|
|
'handshake',
|
|
'cloud_upload',
|
|
'cloud_off',
|
|
'cloud_done',
|
|
'sync',
|
|
'sync_problem',
|
|
'warning',
|
|
'error',
|
|
'info',
|
|
'check_circle',
|
|
'chevron_right',
|
|
'expand_more',
|
|
'expand_less',
|
|
'inventory_2',
|
|
'unarchive',
|
|
'event',
|
|
'call_split',
|
|
'notes',
|
|
'person',
|
|
'apps',
|
|
'backspace',
|
|
'calculate',
|
|
'date_range',
|
|
'content_paste',
|
|
'link',
|
|
'dns',
|
|
'person_add',
|
|
'add_a_photo',
|
|
'photo_library',
|
|
'receipt_long',
|
|
'schedule',
|
|
'pause',
|
|
'event_repeat',
|
|
'drag_indicator',
|
|
'restart_alt',
|
|
'lock',
|
|
'download',
|
|
'refresh',
|
|
'phonelink_erase',
|
|
'smartphone',
|
|
'block',
|
|
'devices',
|
|
'add_link',
|
|
'key',
|
|
'share',
|
|
'content_copy',
|
|
'memory',
|
|
'open_in_new',
|
|
'arrow_forward',
|
|
'search',
|
|
'keyboard',
|
|
'logout',
|
|
'language',
|
|
'contrast',
|
|
'lightbulb',
|
|
// K3 card purchases (Kortköp nav, unlink, ignore).
|
|
'credit_card',
|
|
'link_off',
|
|
'visibility_off',
|
|
];
|
|
|
|
/** Filled UI icons of design-spec §2.12 (selected nav, status, handshake, app mark). */
|
|
const UI_FILLED = [
|
|
'home',
|
|
'bar_chart',
|
|
'settings',
|
|
'handshake',
|
|
'cloud_done',
|
|
'warning',
|
|
'error',
|
|
'check_circle',
|
|
'receipt_long',
|
|
'search',
|
|
'lightbulb',
|
|
'credit_card',
|
|
];
|
|
|
|
/**
|
|
* Spec token names that Material Symbols 0.48 ships under another file name (the glyph is the same). The spec's name
|
|
* stays the key in the generated tables. The APK-update icons of S-17 are not embedded: the web has no APK update.
|
|
*/
|
|
const FILE_NAMES = {
|
|
card_giftcard: 'redeem',
|
|
expand_more: 'keyboard_arrow_down',
|
|
expand_less: 'keyboard_arrow_up',
|
|
phonelink_erase: 'mobile_cancel',
|
|
smartphone: 'mobile',
|
|
};
|
|
|
|
const root = new URL('../', import.meta.url);
|
|
|
|
function pathOf(pkg, file) {
|
|
const url = new URL(`node_modules/@material-symbols/${pkg}/rounded/${file}.svg`, root);
|
|
const svg = readFileSync(url, 'utf-8');
|
|
if (!svg.includes('viewBox="0 -960 960 960"')) throw new Error(`${pkg}/${file}: unexpected viewBox`);
|
|
const paths = [...svg.matchAll(/<path d="([^"]+)"\/>/g)].map((m) => m[1]);
|
|
if (paths.length !== 1) throw new Error(`${pkg}/${file}: expected one path, found ${paths.length}`);
|
|
return paths[0];
|
|
}
|
|
|
|
function table(names, pkg, suffix) {
|
|
const unique = [...new Set(names)].sort();
|
|
return unique.map((name) => ` ${name}: '${pathOf(pkg, (FILE_NAMES[name] ?? name) + suffix)}',`).join('\n');
|
|
}
|
|
|
|
const text = `// Generated by scripts/gen-icons.mjs (npm run icons:import). Do not edit.
|
|
// Material Symbols Rounded, viewBox 0 -960 960 960; outline from @material-symbols/svg-500, filled from
|
|
// @material-symbols/svg-600. Licence: Apache License 2.0 (Google).
|
|
|
|
export const OUTLINE = {
|
|
${table([...CATEGORY_ICONS, ...UI_OUTLINE], 'svg-500', '')}
|
|
} as const;
|
|
|
|
export const FILLED = {
|
|
${table([...CATEGORY_ICONS, ...UI_FILLED], 'svg-600', '-fill')}
|
|
} as const;
|
|
|
|
export const CATEGORY_ICON_TOKENS = [
|
|
${CATEGORY_ICONS.map((n) => ` '${n}',`).join('\n')}
|
|
] as const;
|
|
|
|
export type OutlineIconName = keyof typeof OUTLINE;
|
|
export type FilledIconName = keyof typeof FILLED;
|
|
export type CategoryIconToken = (typeof CATEGORY_ICON_TOKENS)[number];
|
|
`;
|
|
|
|
const target = new URL('src/design/icons.generated.ts', root);
|
|
if (process.argv.includes('--check')) {
|
|
const current = existsSync(target) ? readFileSync(target, 'utf-8') : '';
|
|
if (current !== text) {
|
|
console.error('src/design/icons.generated.ts is stale: run npm run icons:import');
|
|
process.exit(1);
|
|
}
|
|
} else {
|
|
writeFileSync(target, text);
|
|
console.log(
|
|
`src/design/icons.generated.ts: ${new Set([...CATEGORY_ICONS, ...UI_OUTLINE]).size} outline, ${new Set([...CATEGORY_ICONS, ...UI_FILLED]).size} filled`,
|
|
);
|
|
}
|