fix(ui): replace icon ligatures missing from the font and guard them (#1864)

* fix(ui): replace icon ligatures missing from the font and guard them

The download and recording queues showed the literal text "file_off" for a
missing file: the bundled Material Icons font (material-design-icons-iconfont
6.7.0) has no such ligature, so it rendered as text overflowing the icon box.
Use error_outline, which the missing state's tertiary palette keeps distinct
from the filled error glyph of a failed download.

Add `pnpm run styles:icon-ligatures:validate` (CI): it parses templates with
@angular/compiler and TypeScript with the compiler API, collects static
<mat-icon> text, the string results of its bindings, icon/*Icon inputs and
icon-named TypeScript values, and fails on a name missing from the font's
codepoints file. Two listed codepoints the font has no ligature for
(rounded_corner, stairs) are excluded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(tools): check quoted inline templates in the icon guard

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(tools): accept every codepoint and report escaped template lines

The first measurement rendered the names without the package's CSS. With
material-design-icons.css, all 2,193 codepoint names, rounded_corner and
stairs included, draw as one glyph, so the guard accepts the whole file.

Inline templates now map each cooked position back to the source through
escapes, line continuations and CRLF, so a name after `\n` in a quoted
template is reported on the line it is written on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Opus 5.5 authored and GitHub committed 2026-10-10 10:31:21 +02:00
1 parent 8fabb88106
commit 2dff91c9f2
14 files changed
+813 -4

No files matched your search

@@ -881,6 +881,18 @@ text) and `subject` (pasted text in the add flow). Use
`getPlaylistSourceIcon()` for a stored playlist. An icon never stands for two
providers, and the Dashboard rail icon is never a provider icon.
## Icon Names
`<mat-icon>` draws its text through the ligatures of the Material Icons font
from `material-design-icons-iconfont`, imported in `apps/web/src/styles.scss`.
The font renders a name it does not know as plain text, so pick names from its
`dist/fonts/MaterialIcons-Regular.json` codepoints file: newer Material Symbols
names such as `file_off` or `arrow_outward` are not in it.
`pnpm run styles:icon-ligatures:validate` (CI) checks static `<mat-icon>` text,
the string results of its bindings, `icon` / `*Icon` inputs, and TypeScript
values named `icon`, `*Icon`, `*_ICON`, `*Icons` or `*_ICONS`. Name a member
that feeds an icon that way, so the check can see its values.
## Phone Layout
`640px` is the phone breakpoint. Use `@media (max-width: 640px)` rather than