fix(player): volume slider fill
This commit is contained in:
@@ -1,14 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {
|
import { Play, Pause, SkipBack, SkipForward, List } from 'lucide-svelte';
|
||||||
Play,
|
|
||||||
Pause,
|
|
||||||
SkipBack,
|
|
||||||
SkipForward,
|
|
||||||
VolumeX,
|
|
||||||
Volume1,
|
|
||||||
Volume2,
|
|
||||||
List
|
|
||||||
} from 'lucide-svelte';
|
|
||||||
import { Button } from '$lib/components/ui/button';
|
import { Button } from '$lib/components/ui/button';
|
||||||
import { Progress } from '$lib/components/ui/progress';
|
import { Progress } from '$lib/components/ui/progress';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
@@ -18,6 +9,7 @@
|
|||||||
import { getPlayerState } from '$lib/player.svelte';
|
import { getPlayerState } from '$lib/player.svelte';
|
||||||
import { enhance } from '$app/forms';
|
import { enhance } from '$app/forms';
|
||||||
import { getCoverUrl } from '$lib/covers';
|
import { getCoverUrl } from '$lib/covers';
|
||||||
|
import VolumeSlider from '$lib/components/groove/VolumeSlider.svelte';
|
||||||
import type { SubmitFunction } from '../../../routes/player/$types';
|
import type { SubmitFunction } from '../../../routes/player/$types';
|
||||||
|
|
||||||
dayjs.extend(duration);
|
dayjs.extend(duration);
|
||||||
@@ -34,7 +26,6 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
let progressBar = $state<HTMLElement | null>(null);
|
let progressBar = $state<HTMLElement | null>(null);
|
||||||
let volumeForm = $state<HTMLFormElement | null>(null);
|
|
||||||
|
|
||||||
const seekProgressValue: SubmitFunction = ({ formData, cancel }) => {
|
const seekProgressValue: SubmitFunction = ({ formData, cancel }) => {
|
||||||
if (!player.currentlyPlaying || !progressBar) {
|
if (!player.currentlyPlaying || !progressBar) {
|
||||||
@@ -76,20 +67,6 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const submitVolumeForm: SubmitFunction = async ({ formData }) => {
|
|
||||||
formData.set('volume', player.volume.toString());
|
|
||||||
|
|
||||||
return async ({ update, result }) => {
|
|
||||||
await update({
|
|
||||||
invalidateAll: false
|
|
||||||
});
|
|
||||||
|
|
||||||
if (result.type === 'success' && result.data && 'volume' in result.data) {
|
|
||||||
player.volume = result.data.volume;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function onMouseMove(e: MouseEvent) {
|
function onMouseMove(e: MouseEvent) {
|
||||||
mouse.offsetX = e.offsetX;
|
mouse.offsetX = e.offsetX;
|
||||||
mouse.offsetY = e.offsetY;
|
mouse.offsetY = e.offsetY;
|
||||||
@@ -179,47 +156,7 @@
|
|||||||
</Popover.Content>
|
</Popover.Content>
|
||||||
</Popover.Root>
|
</Popover.Root>
|
||||||
|
|
||||||
<div class="flex grow flex-row items-center gap-4">
|
<VolumeSlider />
|
||||||
<div class="min-w-6 text-muted-foreground">
|
|
||||||
{#if player.volume <= 0.0}
|
|
||||||
<VolumeX class="size-full" />
|
|
||||||
{:else if player.volume < 0.5}
|
|
||||||
<Volume1 class="size-full" />
|
|
||||||
{:else}
|
|
||||||
<Volume2 class="size-full" />
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<form
|
|
||||||
bind:this={volumeForm}
|
|
||||||
class="volume-form flex-1"
|
|
||||||
method="POST"
|
|
||||||
action="/player?/volume"
|
|
||||||
use:enhance={submitVolumeForm}
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
class="volume-slider min-w-40"
|
|
||||||
type="range"
|
|
||||||
min={0.0}
|
|
||||||
max={1.0}
|
|
||||||
step={0.01}
|
|
||||||
bind:value={player.volume}
|
|
||||||
oninput={() => {
|
|
||||||
volumeForm?.requestSubmit();
|
|
||||||
}}
|
|
||||||
onmousedown={() => {
|
|
||||||
player.adjustingVolume = true;
|
|
||||||
}}
|
|
||||||
onmouseup={() => {
|
|
||||||
player.adjustingVolume = false;
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</form>
|
|
||||||
<div class="min-w-10 self-center">
|
|
||||||
<p class="text-sm text-muted-foreground">
|
|
||||||
{Math.round(player.volume * 100.0)}%
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -249,36 +186,3 @@
|
|||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<svelte:window onmousemove={onMouseMove} />
|
<svelte:window onmousemove={onMouseMove} />
|
||||||
|
|
||||||
<style>
|
|
||||||
.volume-slider {
|
|
||||||
-webkit-appearance: none !important; /* Override default CSS styles */
|
|
||||||
appearance: none !important;
|
|
||||||
width: 100%; /* Full-width */
|
|
||||||
height: 8px; /* Specified height */
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
background: hsl(var(--secondary));
|
|
||||||
outline: none; /* Remove outline */
|
|
||||||
opacity: 0.7; /* Set transparency (for mouse-over effects on hover) */
|
|
||||||
-webkit-transition: 0.2s; /* 0.2 seconds transition on hover */
|
|
||||||
transition: opacity 0.2s;
|
|
||||||
-webkit-user-drag: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.volume-slider::-webkit-slider-thumb {
|
|
||||||
@apply size-4 bg-background ring ring-secondary ring-offset-0 ring-offset-transparent transition-colors;
|
|
||||||
|
|
||||||
-webkit-user-drag: none;
|
|
||||||
appearance: none;
|
|
||||||
background-color: hsl(var(--primary));
|
|
||||||
border-radius: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.volume-slider::-webkit-slider-thumb:active {
|
|
||||||
@apply ring-offset-2 ring-offset-background;
|
|
||||||
}
|
|
||||||
|
|
||||||
.volume-form {
|
|
||||||
-webkit-user-drag: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
102
src/lib/components/groove/VolumeSlider.svelte
Normal file
102
src/lib/components/groove/VolumeSlider.svelte
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { enhance } from '$app/forms';
|
||||||
|
import { getPlayerState } from '$lib/player.svelte';
|
||||||
|
import { Volume1, Volume2, VolumeX } from 'lucide-svelte';
|
||||||
|
import type { SubmitFunction } from '../../../routes/player/$types';
|
||||||
|
|
||||||
|
const player = getPlayerState();
|
||||||
|
|
||||||
|
let volumeForm = $state<HTMLFormElement | null>(null);
|
||||||
|
|
||||||
|
const submitVolumeForm: SubmitFunction = async ({ formData }) => {
|
||||||
|
formData.set('volume', player.volume.toString());
|
||||||
|
|
||||||
|
return async ({ update, result }) => {
|
||||||
|
await update({
|
||||||
|
invalidateAll: false
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.type === 'success' && result.data && 'volume' in result.data) {
|
||||||
|
player.volume = result.data.volume;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex grow flex-row items-center gap-4">
|
||||||
|
<div class="min-w-6 text-muted-foreground">
|
||||||
|
{#if player.volume <= 0.0}
|
||||||
|
<VolumeX class="size-full" />
|
||||||
|
{:else if player.volume < 0.5}
|
||||||
|
<Volume1 class="size-full" />
|
||||||
|
{:else}
|
||||||
|
<Volume2 class="size-full" />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<form
|
||||||
|
bind:this={volumeForm}
|
||||||
|
class="volume-form flex-1"
|
||||||
|
method="POST"
|
||||||
|
action="/player?/volume"
|
||||||
|
use:enhance={submitVolumeForm}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
class="volume-slider min-w-40"
|
||||||
|
type="range"
|
||||||
|
min={0.0}
|
||||||
|
max={1.0}
|
||||||
|
step={0.01}
|
||||||
|
bind:value={player.volume}
|
||||||
|
oninput={() => {
|
||||||
|
volumeForm?.requestSubmit();
|
||||||
|
}}
|
||||||
|
onmousedown={() => {
|
||||||
|
player.adjustingVolume = true;
|
||||||
|
}}
|
||||||
|
onmouseup={() => {
|
||||||
|
player.adjustingVolume = false;
|
||||||
|
}}
|
||||||
|
style="background-size: {(player.volume / 1.0) * 100}% 100%"
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
<div class="min-w-10 self-center">
|
||||||
|
<p class="text-sm text-muted-foreground">
|
||||||
|
{Math.round(player.volume * 100.0)}%
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.volume-slider {
|
||||||
|
-webkit-user-drag: none;
|
||||||
|
appearance: none;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
height: 8px;
|
||||||
|
outline: none;
|
||||||
|
background: hsl(var(--secondary));
|
||||||
|
background-image: linear-gradient(hsl(var(--primary)), hsl(var(--primary)));
|
||||||
|
/* background-size: 50% 100%; */
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
-webkit-user-drag: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.volume-slider::-webkit-slider-thumb {
|
||||||
|
@apply size-4 bg-background ring ring-secondary ring-offset-0 ring-offset-transparent transition-colors;
|
||||||
|
|
||||||
|
-webkit-user-drag: none;
|
||||||
|
appearance: none;
|
||||||
|
|
||||||
|
background-color: hsl(var(--primary));
|
||||||
|
border-radius: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.volume-slider::-webkit-slider-thumb:active {
|
||||||
|
@apply ring-offset-2 ring-offset-background;
|
||||||
|
}
|
||||||
|
|
||||||
|
.volume-form {
|
||||||
|
-webkit-user-drag: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user