PlayerExtras se fusiona en PlayerBar, que ahora renderiza volumen y botón de cola inline y usa el nuevo Slider (input range real con grosor de thumb controlado por variables CSS) para barra de progreso y volumen, sustituyendo a SeekBar y VolumeControl (se confirmó por grep que el modo `compact` de SeekBar era código muerto). Sidebar y TabsBar migran a appNavLinks(user, counts?) (creado en P5), eliminando la duplicación de los enlaces de navegación entre ambos. Decisión tomada sin bloquear: Sidebar gana la marca-gradiente Logo que no tenía antes, para consistencia visual con MobileHeader y la pantalla de login. z-index de PlayerDock y MobileHeader corregido a z-(--z-sticky) (son barras fijas, no menús) y el de SegmentedControl a z-(--z-raised), tal como indica la nota B.1.5 del plan. glass-bar y theme-transition se aplican en PlayerBar (ambas variantes), TabsBar, Queue e Inicio (hero/spotlight), sustituyendo estilos duplicados de blur/transición. Verificado con npm run check (0 errores) y npm run build; smoke test de /login sin errores de consola. Sin QA visual autenticada (Docker no disponible en esta sesión). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
63 lines
1.3 KiB
Svelte
63 lines
1.3 KiB
Svelte
<script lang="ts">
|
|
interface Props {
|
|
value: number;
|
|
max: number;
|
|
label: string;
|
|
oninput: (value: number) => void;
|
|
variant: 'seek' | 'volume';
|
|
}
|
|
|
|
let { value, max, label, oninput, variant }: Props = $props();
|
|
|
|
const percent = $derived(max > 0 ? (value / max) * 100 : 0);
|
|
|
|
function handleInput(event: Event) {
|
|
oninput(Number((event.currentTarget as HTMLInputElement).value));
|
|
}
|
|
</script>
|
|
|
|
<input
|
|
type="range"
|
|
min="0"
|
|
{max}
|
|
{value}
|
|
oninput={handleInput}
|
|
aria-label={label}
|
|
class="mf-slider mf-slider-{variant}"
|
|
style="background:linear-gradient(to right, var(--mf-text-2) {percent}%, var(--mf-track) {percent}%)"
|
|
/>
|
|
|
|
<style>
|
|
.mf-slider {
|
|
-webkit-appearance: none;
|
|
appearance: none;
|
|
height: var(--mf-range-h);
|
|
border-radius: 100px;
|
|
outline: none;
|
|
cursor: pointer;
|
|
}
|
|
.mf-slider-seek {
|
|
width: 100%;
|
|
}
|
|
.mf-slider-volume {
|
|
width: var(--mf-volume-w);
|
|
}
|
|
.mf-slider::-webkit-slider-thumb {
|
|
-webkit-appearance: none;
|
|
appearance: none;
|
|
width: var(--mf-range-thumb);
|
|
height: var(--mf-range-thumb);
|
|
border-radius: 50%;
|
|
background: var(--mf-text);
|
|
cursor: pointer;
|
|
}
|
|
.mf-slider::-moz-range-thumb {
|
|
width: var(--mf-range-thumb);
|
|
height: var(--mf-range-thumb);
|
|
border-radius: 50%;
|
|
background: var(--mf-text);
|
|
border: none;
|
|
cursor: pointer;
|
|
}
|
|
</style>
|