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:
@@ -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}
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
)} en canciones, álbumes, playlists y usuarios"
|
||||
/>
|
||||
|
||||
<div class="mb-7 flex flex-wrap gap-1.75 sm:mb-8">
|
||||
<div class="mb-7 flex flex-wrap gap-2 sm:mb-8">
|
||||
{#each chips as chip (chip.label)}
|
||||
<Chip
|
||||
selected={sfilter === chip.label}
|
||||
@@ -249,11 +249,11 @@
|
||||
{/if}
|
||||
|
||||
<div class="flex h-22 min-w-0 flex-1 flex-col justify-center gap-3">
|
||||
<div class="text-xs leading-none font-semibold tracking-[0.14em] text-fg-3 uppercase">
|
||||
<div class="text-eyebrow leading-none font-semibold text-fg-3">
|
||||
Mejor resultado · {TOP_RESULT_KIND_LABEL[topResult.kind]}
|
||||
</div>
|
||||
<div
|
||||
class="truncate font-display text-lg leading-none font-medium tracking-[-0.02em] text-fg"
|
||||
class="truncate font-display text-lg leading-none font-medium tracking-display text-fg"
|
||||
>
|
||||
{topResult.kind === 'track'
|
||||
? topResult.track.title
|
||||
@@ -313,7 +313,7 @@
|
||||
{#each genreTiles as genre, i (genre.query)}
|
||||
<a
|
||||
href={searchHref(genre.query)}
|
||||
class="animate-enter group relative flex h-28 flex-col gap-1 overflow-hidden rounded-panel p-4.25 transition-[filter] genre-tile hover:brightness-110"
|
||||
class="animate-enter group relative flex h-28 flex-col gap-1 overflow-hidden rounded-panel p-4 transition-[filter] genre-tile hover:brightness-110"
|
||||
style="--i:{i}; --tile-hue:{genre.hue}"
|
||||
>
|
||||
<div class="text-on-art">
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
{#snippet actions()}
|
||||
{#if items.length > 0}
|
||||
<Button href="/upload">
|
||||
<Upload class="h-4 w-4" />
|
||||
<Upload class="size-4" />
|
||||
Subir canción
|
||||
</Button>
|
||||
{/if}
|
||||
@@ -56,7 +56,7 @@
|
||||
>
|
||||
{#snippet actions()}
|
||||
<Button href="/upload">
|
||||
<Upload class="h-4 w-4" />
|
||||
<Upload class="size-4" />
|
||||
Sube la primera
|
||||
</Button>
|
||||
{/snippet}
|
||||
|
||||
@@ -75,10 +75,10 @@
|
||||
{#snippet actions()}
|
||||
<Button size="sm" onclick={() => playAllOrToggle(queue)} disabled={queue.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>
|
||||
@@ -88,7 +88,7 @@
|
||||
onclick={() => playShuffled(queue)}
|
||||
disabled={queue.length === 0}
|
||||
>
|
||||
<Shuffle class="h-4 w-4" />
|
||||
<Shuffle class="size-4" />
|
||||
Aleatorio
|
||||
</Button>
|
||||
{/snippet}
|
||||
|
||||
@@ -66,19 +66,19 @@
|
||||
{#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>
|
||||
<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>
|
||||
{/snippet}
|
||||
|
||||
@@ -110,14 +110,13 @@
|
||||
<Surface padding="sm" class={stepClass(stepStates[i])}>
|
||||
<div class="flex items-center gap-3">
|
||||
<span
|
||||
class="grid h-7 w-7 shrink-0 place-items-center rounded-full text-sm {stepStates[
|
||||
i
|
||||
] === 'idle'
|
||||
class="grid size-7 shrink-0 place-items-center rounded-full text-sm {stepStates[i] ===
|
||||
'idle'
|
||||
? 'bg-surface-2 text-fg-2'
|
||||
: 'bg-accent-btn text-accent-soft'}"
|
||||
>
|
||||
{#if stepStates[i] === 'done'}
|
||||
<Check class="h-3.5 w-3.5" strokeWidth={2.5} />
|
||||
<Check class="size-3.5" strokeWidth={2.5} />
|
||||
{:else}
|
||||
{i + 1}
|
||||
{/if}
|
||||
@@ -132,10 +131,10 @@
|
||||
|
||||
{#if status === 'done'}
|
||||
<Surface padding="lg" class="mt-10 bg-accent-tint text-center">
|
||||
<span class="mx-auto grid h-14 w-14 place-items-center rounded-full bg-accent-soft text-ink">
|
||||
<Check class="h-7 w-7" strokeWidth={2.5} />
|
||||
<span class="mx-auto grid size-14 place-items-center rounded-full bg-accent-soft text-ink">
|
||||
<Check class="size-7" strokeWidth={2.5} />
|
||||
</span>
|
||||
<h2 class="mt-6 font-display text-2xl font-semibold tracking-[-0.02em] text-fg">¡Subida!</h2>
|
||||
<h2 class="mt-6 font-display text-2xl font-semibold tracking-display text-fg">¡Subida!</h2>
|
||||
<p class="mt-3 text-sm text-fg-2">
|
||||
«{publishedTitle}» se está procesando. Aparecerá lista para reproducir en tu biblioteca en
|
||||
unos momentos.
|
||||
@@ -192,9 +191,9 @@
|
||||
aria-label="Seleccionar archivo de audio"
|
||||
/>
|
||||
{#if audioName === ''}
|
||||
<Headphones class="h-9 w-9 text-muted sm:h-10 sm:w-10" strokeWidth={1.4} />
|
||||
<Headphones class="size-9 text-muted sm:size-10" strokeWidth={1.4} />
|
||||
{:else}
|
||||
<Music class="h-9 w-9 text-accent-soft sm:h-10 sm:w-10" strokeWidth={1.4} />
|
||||
<Music class="size-9 text-accent-soft sm:size-10" strokeWidth={1.4} />
|
||||
{/if}
|
||||
{#if audioName === ''}
|
||||
<p class="mt-4 text-sm font-medium text-fg">
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
|
||||
<Page>
|
||||
<div
|
||||
class="relative overflow-hidden rounded-3xl hero-surface px-6 py-8 theme-transition sm:px-9 sm:py-8.5"
|
||||
class="relative overflow-hidden rounded-panel-lg hero-surface px-6 py-8 theme-transition sm:px-9 sm:py-8.5"
|
||||
>
|
||||
<div
|
||||
class="relative flex flex-col items-start gap-7 lg:flex-row lg:flex-wrap lg:items-end lg:justify-between"
|
||||
|
||||
@@ -97,16 +97,6 @@
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
|
||||
@utility stroke-thin {
|
||||
stroke-width: 1.3;
|
||||
}
|
||||
@utility stroke-regular {
|
||||
stroke-width: 1.8;
|
||||
}
|
||||
@utility stroke-bold {
|
||||
stroke-width: 2.5;
|
||||
}
|
||||
|
||||
@utility text-display-1 {
|
||||
@apply font-display text-3xl font-medium tracking-tight sm:text-4xl;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user