Something went wrong. Try again.
a simple but full-featured web player for OpenSubsonic music servers (Navidrome, Gonic, Ampache, etc) devins.page/tinysub
svelte typescript javascript subsonic gonic navidrome
Something went wrong. Try again.
4.0 kB · 194 lines
Svelte
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195<script lang="ts">type RangeEvent<T extends Event = Event> = T & { currentTarget: HTMLInputElement;};
let { value, min = 0, max = 1, step = 0.01, disabled = false, loading = false, variant = "native", oninput, onkeydown, onpointerdown,}: { value: number; min?: number; max?: number; step?: number; disabled?: boolean; loading?: boolean; variant?: "native" | "simple" | "triangle"; oninput?: (event: RangeEvent) => void; onkeydown?: (event: RangeEvent<KeyboardEvent>) => void; onpointerdown?: (event: RangeEvent<PointerEvent>) => void;} = $props();
const percentage = $derived( variant === "native" ? undefined : `${Math.max(0, Math.min(100, ((value - min) / (max - min || 1)) * 100))}%`,);</script>
<div class="progress-bar" class:simple={variant === "simple"} class:triangle={variant === "triangle"} class:disabled class:loading={loading} style:--percentage={percentage}> {#if variant !== "native"} <div class="track"> <div class="fill"></div> </div> {/if} <input class:custom={variant !== "native"} tabindex="-1" type="range" {min} {max} {step} {value} {disabled} {oninput} {onkeydown} {onpointerdown} ></div>
<style>.progress-bar { display: flex; align-items: center; inline-size: 100%;
> input { inline-size: 100%; }}.progress-bar.loading > input:not(.custom) { accent-color: orange;}:global(html.dynamic-colors) .progress-bar:not(.loading) > input:not(.custom) { accent-color: var(--text);}.simple,.triangle { --thumb-opacity: 0; position: relative; block-size: 0.75rem; transform-origin: center;}.triangle { transform-origin: bottom center;}.simple:not(.disabled):hover,.simple:not(.disabled):global(.is-activated) { --thumb-opacity: 1;}:global(html.motion) :is(.simple, .triangle) { transition: transform var(--button-hover-duration) ease-out;}
:global(html.motion) :is(.simple, .triangle):not(.disabled):active { transform: scaleY(var(--progress-press-scale, var(--button-press-scale-y))); transition-duration: var(--button-press-duration);}:global(html.motion) .loading .track::after { position: absolute; inset: 0; background: linear-gradient( 90deg, transparent 35%, color-mix(currentColor 50%, transparent) 65%, transparent 65% ); animation: loading 1s ease-in-out 1s infinite backwards; content: "";}.track { position: relative; overflow: hidden; inline-size: 100%; block-size: 0.25rem; background-color: color-mix(currentColor 25%, transparent);}.simple .track { border-radius: var(--radius-sm); corner-shape: squircle;}.fill { block-size: 100%; background-color: currentColor;}.simple .fill { inline-size: var(--percentage);}.triangle .track { block-size: 0.75rem; clip-path: polygon(0 75%, 100% 0, 100% 100%, 0 100%);}.triangle .fill { position: absolute; inset: 0; clip-path: inset(0 calc(100% - var(--percentage)) 0 0);}.custom { --thumb-block-size: 1rem; --thumb-inline-size: 0.25rem; position: absolute; inset: 0; block-size: 100%; margin: 0; appearance: none; background: transparent; color: inherit;}.custom::-webkit-slider-runnable-track { background: transparent;}.custom::-webkit-slider-thumb { appearance: none; inline-size: var(--thumb-inline-size); block-size: var(--thumb-block-size); border-radius: var(--radius-md); corner-shape: squircle; background: currentColor; opacity: var(--thumb-opacity);}.custom::-moz-range-track,.custom::-moz-range-progress { background: transparent;}.custom::-moz-range-thumb { inline-size: var(--thumb-inline-size); block-size: var(--thumb-block-size); border: 0; border-radius: var(--radius-md); corner-shape: squircle; background: currentColor; opacity: var(--thumb-opacity);}.disabled { opacity: 0.5;}@keyframes loading { from { transform: translateX(-100%); } to { transform: translateX(100%); }}@media (pointer: coarse) { .custom { --thumb-inline-size: 1.5rem; }}</style>