-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #421 from bcc-code/feature/314_volume-control
Volume control & draggable sliders
- Loading branch information
Showing
9 changed files
with
285 additions
and
48 deletions.
There are no files selected for viewing
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
<script setup lang="ts"> | ||
import * as slider from "@zag-js/slider"; | ||
import { normalizeProps, useMachine } from "@zag-js/vue"; | ||
const { currentPosition, currentTrackDuration } = useNuxtApp().$mediaPlayer; | ||
const newPosition = ref<number | null>(null); | ||
const [positionState, positionSend] = useMachine( | ||
slider.machine({ | ||
id: "position", | ||
value: [0], | ||
step: 0.01, | ||
onValueChange(details) { | ||
const [value] = details.value; | ||
if (value) newPosition.value = value; | ||
}, | ||
onValueChangeEnd(details) { | ||
const [value] = details.value; | ||
if (value) { | ||
currentPosition.value = (value / 100) * currentTrackDuration.value; | ||
newPosition.value = null; | ||
} | ||
}, | ||
}), | ||
); | ||
const positionSlider = computed(() => | ||
slider.connect(positionState.value, positionSend, normalizeProps), | ||
); | ||
const currentOrNewPosition = computed(() => | ||
newPosition.value === null | ||
? currentPosition.value | ||
: (newPosition.value / 100) * currentTrackDuration.value, | ||
); | ||
watch([currentPosition, currentTrackDuration], () => { | ||
if (newPosition.value === null && currentTrackDuration.value > 0) { | ||
const value = (currentPosition.value / currentTrackDuration.value) * 100; | ||
positionSlider.value.setValue([value]); | ||
newPosition.value = null; | ||
} | ||
}); | ||
</script> | ||
|
||
<template> | ||
<div class="group/position px-4 py-2" v-bind="positionSlider.rootProps"> | ||
<div class="flex items-center"> | ||
<div class="h-7"></div> | ||
<div | ||
class="h-6 w-full transition-all duration-200 group-hover/position:h-7" | ||
> | ||
<div | ||
v-bind="positionSlider.controlProps" | ||
class="h-full cursor-pointer py-2" | ||
> | ||
<div class="h-full overflow-hidden rounded-full"> | ||
<div | ||
v-bind="positionSlider.trackProps" | ||
class="h-full cursor-pointer bg-background-2" | ||
> | ||
<div | ||
v-bind="positionSlider.rangeProps" | ||
class="h-full cursor-pointer bg-label-1" | ||
/> | ||
</div> | ||
</div> | ||
<div | ||
v-for="(_, index) in positionSlider.value" | ||
:key="index" | ||
v-bind="positionSlider.getThumbProps({ index })" | ||
> | ||
<input v-bind="positionSlider.getHiddenInputProps({ index })" /> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
<div class="flex justify-between py-0.5 text-sm"> | ||
<span> | ||
<TimeDuration :duration="currentOrNewPosition"></TimeDuration | ||
></span> | ||
<span> | ||
<TimeDuration | ||
:duration=" | ||
Math.max(Math.floor(currentTrackDuration) - currentOrNewPosition, 0) | ||
" | ||
></TimeDuration | ||
></span> | ||
</div> | ||
</div> | ||
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
<script setup lang="ts"> | ||
import * as slider from "@zag-js/slider"; | ||
import { normalizeProps, useMachine } from "@zag-js/vue"; | ||
const { volume } = useNuxtApp().$mediaPlayer; | ||
const [volumeState, volumeSend] = useMachine( | ||
slider.machine({ | ||
id: "volume", | ||
value: [volume.value * 100], | ||
onValueChange(details) { | ||
const [value] = details.value; | ||
if (value) volume.value = value / 100; | ||
}, | ||
}), | ||
); | ||
const volumeSlider = computed(() => | ||
slider.connect(volumeState.value, volumeSend, normalizeProps), | ||
); | ||
const setVolume = (value: number) => { | ||
volume.value = value; | ||
volumeSlider.value.setValue([value * 100]); | ||
}; | ||
</script> | ||
<template> | ||
<div class="px-4 pb-2 pt-5" v-bind="volumeSlider.rootProps"> | ||
<div | ||
class="group/volume flex items-center gap-3 rounded-3xl border border-label-separator px-[16px] py-[1px]" | ||
> | ||
<NuxtIcon | ||
name="icon.audio.off" | ||
class="my-1.5 cursor-pointer text-2xl" | ||
@click.stop="setVolume(0)" | ||
/> | ||
<div | ||
class="h-8 w-full transition-all duration-200 group-hover/volume:h-9" | ||
> | ||
<div | ||
v-bind="volumeSlider.controlProps" | ||
class="h-full cursor-pointer py-3" | ||
> | ||
<div class="h-full overflow-hidden rounded-full"> | ||
<div | ||
v-bind="volumeSlider.trackProps" | ||
class="h-full cursor-pointer bg-background-2" | ||
> | ||
<div | ||
v-bind="volumeSlider.rangeProps" | ||
class="h-full cursor-pointer bg-label-1" | ||
/> | ||
</div> | ||
</div> | ||
<div | ||
v-for="(_, index) in volumeSlider.value" | ||
:key="index" | ||
v-bind="volumeSlider.getThumbProps({ index })" | ||
> | ||
<input v-bind="volumeSlider.getHiddenInputProps({ index })" /> | ||
</div> | ||
</div> | ||
</div> | ||
<NuxtIcon | ||
name="icon.audio.on" | ||
class="cursor-pointer text-2xl" | ||
@click.stop="setVolume(1)" | ||
/> | ||
</div> | ||
</div> | ||
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.