web-player: final sweep and guardrails

Add scripts/check-tokens.mjs (npm run lint:tokens, wired into lint) as
a guardrail: fails if src/**/*.svelte reintroduces arbitrary values
outside the B.4 allowlist, factory rounded-*, h-N w-N pairs (should
be size-N), quarter-step fractional spacing, or literal hex/rgba()
colors.

Cleans up the repo until the script reports 0 violations: ~40 h-N w-N
pairs -> size-N (mostly icons, via a one-off script), ~26 quarter-step
fractional spacings rounded to the nearest integer (delta <=1px, e.g.
py-2.75->py-3, gap-1.75->gap-2), stray factory radii (rounded-sm/lg,
bare rounded) migrated to the matching tokens, and two
tracking-[-0.02em] that matched the existing tracking-display token
exactly but had never been migrated. Removes the
stroke-thin/regular/bold recipes (added earlier, zero consumers) —
decision made, not blocking: strokeWidth={n} (13 values, across
almost every component) isn't migrated to CSS because there's no way
to verify without Docker that lucide-svelte honors stroke-width by
class instead of the prop, and a regression there would be silent
across the whole app; the script documents this gap explicitly
instead of pretending full coverage.

Orphan detector: 0 components with no importers. Removes
docs/design-system-refactor-plan.md (earlier plan, superseded by
frontend-refactor-plan.md). web-player/CLAUDE.md gains a "Styles"
section with the B.4 allowlist and the base components to reuse.
Recalculates the baseline table (A.4) and logs it: 61->47 components,
44->11 arbitrary values (the remaining 11 on the allowlist), 13->8
distinct radii, 0 lint:tokens violations.

Verified with npm run check (0 errors), npm run lint:tokens (0
violations) and npm run build. Smoke-tested /login with no console
errors attributable to this change.
This commit is contained in:
2026-09-21 15:05:07 +02:00
parent b60a87adb5
commit 1b6d7ecb42
32 changed files with 200 additions and 453 deletions
@@ -27,7 +27,7 @@
{#snippet actions()}
{#if items.length > 0}
<Button onclick={() => (creating = true)}>
<Plus class="h-4 w-4" strokeWidth={2.5} />
<Plus class="size-4" strokeWidth={2.5} />
Nuevo álbum
</Button>
{/if}
@@ -76,20 +76,20 @@
{#snippet actions()}
<Button size="sm" onclick={playAll} disabled={tracks.length === 0}>
{#if isCurrentQueue && player.playing}
<Pause class="h-4 w-4" strokeWidth={1.5} />
<Pause class="size-4" strokeWidth={1.5} />
Pausar
{:else}
<Play class="h-4 w-4" strokeWidth={1.5} />
<Play class="size-4" strokeWidth={1.5} />
Reproducir
{/if}
</Button>
{#if isOwner}
<Button size="sm" variant="secondary" onclick={() => (editing = true)}>
<SquarePencil class="h-4 w-4" strokeWidth={1.5} />
<SquarePencil class="size-4" strokeWidth={1.5} />
Editar
</Button>
<Button size="sm" variant="secondary" onclick={() => (confirmingDelete = true)}>
<Trash class="h-4 w-4" strokeWidth={1.5} />
<Trash class="size-4" strokeWidth={1.5} />
Eliminar
</Button>
{/if}