Initial commit
This commit is contained in:
235
components/sliders/MusicGainSlider.vue
Normal file
235
components/sliders/MusicGainSlider.vue
Normal file
@@ -0,0 +1,235 @@
|
||||
<template>
|
||||
<div class="slider-wrapper">
|
||||
<!-- Slot for passing any audio element -->
|
||||
<img
|
||||
v-if="volumeValue == 0"
|
||||
style="width: 25px; height: 25px;"
|
||||
src="~/assets/image/music_muted.svg"
|
||||
:title="t('unmuteSlider')"
|
||||
@click="toggleMute()"
|
||||
>
|
||||
<img
|
||||
v-else
|
||||
style="width: 25px; height: 25px;"
|
||||
src="~/assets/image/music.svg"
|
||||
:title="t('muteSlider')"
|
||||
@click="toggleMute()"
|
||||
>
|
||||
<div class="slider">
|
||||
<input
|
||||
id="gain-control-music"
|
||||
ref="MusicSlider"
|
||||
type="range"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.001"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
:title="t('textSlider')"
|
||||
@input="changeVolumeOnTrack"
|
||||
@wheel.prevent="changeVolumeOnWheel"
|
||||
>
|
||||
<span
|
||||
class="slider-progress-bar"
|
||||
:style="{ width: `${volumeValue * 100}%` }"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { useAudioStore } from '~/stores/audio'
|
||||
|
||||
const MusicSlider = ref(null)
|
||||
const audioStore = useAudioStore()
|
||||
const { t } = useI18n()
|
||||
|
||||
// Computed volume value from the audio store
|
||||
const volumeValue = computed(() => audioStore.getVolume)
|
||||
// Stores volume before muting
|
||||
let volumeOnMute = audioStore.getVolume
|
||||
|
||||
/**
|
||||
* Toggles mute state:
|
||||
* - If volume > 0: saves current volume and sets to 0
|
||||
* - If volume == 0: restores saved volume
|
||||
*/
|
||||
const toggleMute = () => {
|
||||
if (audioStore.getVolume !== 0) {
|
||||
volumeOnMute = audioStore.getVolume
|
||||
audioStore.setVolume(0)
|
||||
} else {
|
||||
audioStore.setVolume(volumeOnMute)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Syncs external slider DOM element with the reactive volume state
|
||||
*/
|
||||
watch(volumeValue, (newValue) => {
|
||||
if (MusicSlider.value) {
|
||||
const inputSlider = MusicSlider.value as HTMLInputElement
|
||||
inputSlider.valueAsNumber = newValue
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Handles scroll wheel changes over the slider element to increment/decrement volume.
|
||||
* Clamped between 0 and 1 with 0.02 steps.
|
||||
*
|
||||
* @param {WheelEvent} event - Scroll event on the volume slider
|
||||
*/
|
||||
const changeVolumeOnWheel = (event: WheelEvent) => {
|
||||
const deltaY = event.deltaY
|
||||
if (deltaY < 0) {
|
||||
const volumeAdd = Math.min(1, volumeValue.value + 0.02)
|
||||
if (volumeAdd <= 1) { audioStore.setVolume(volumeAdd) }
|
||||
} else {
|
||||
const volumeCut = Math.max(0, volumeValue.value - 0.02)
|
||||
if (volumeCut >= 0) { audioStore.setVolume(volumeCut) }
|
||||
}
|
||||
audioStore.setVolume(volumeValue.value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets volume when user moves the range input (slider)
|
||||
*
|
||||
* @param {InputEvent} event - Input change from range slider
|
||||
*/
|
||||
const changeVolumeOnTrack = (event: InputEvent) => {
|
||||
const target = event.target as HTMLInputElement
|
||||
const volume = Number(target.value)
|
||||
if (volume >= 0 && volume <= 1) {
|
||||
audioStore.setVolume(volume)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.slider-wrapper{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.slider {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
margin: 1em auto;
|
||||
}
|
||||
|
||||
.slider-icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 576px) {
|
||||
.slider{
|
||||
max-width: 80%;
|
||||
}
|
||||
}
|
||||
|
||||
.slider-progress-bar {
|
||||
position: absolute;
|
||||
height: 10px;
|
||||
background-color: #e9c046;
|
||||
border-top-left-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
border-radius: 5px;
|
||||
left: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
/* Allgemeine Einstellungen für den Slider */
|
||||
input[type="range"] {
|
||||
-webkit-appearance: none; /* Entfernt das Standard-Styling in Webkit-Browsern */
|
||||
appearance: none; /* Entfernt Standard-Styling in anderen Browsern */
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
z-index:1;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
/* Styling für den Track in Webkit-Browsern */
|
||||
input[type="range"]::-webkit-slider-runnable-track {
|
||||
height: 10px;
|
||||
background: transparent;
|
||||
border-radius: 5px;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* Styling für den Thumb in Webkit-Browsern */
|
||||
input[type="range"]::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
background: #fff;
|
||||
border-radius: 50%;
|
||||
margin-top: -5px;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
border: 2px solid #e9c046;
|
||||
}
|
||||
|
||||
/* Styling für den Track in Firefox */
|
||||
input[type="range"]::-moz-range-track {
|
||||
height: 10px;
|
||||
background: transparent;
|
||||
border-radius: 5px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Styling für den Thumb in Firefox */
|
||||
input[type="range"]::-moz-range-thumb {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
background-color: #e9c046;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
border: 2px solid #e9c046;
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
input[type="range"]::-moz-range-progress {
|
||||
height: 10px;
|
||||
background-color: #e9c046;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* Styling für den Track in Internet Explorer/Edge */
|
||||
input[type="range"]::-ms-track {
|
||||
height: 10px;
|
||||
background: transparent;
|
||||
border-color: transparent;
|
||||
color: transparent;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* Styling für den Thumb in Internet Explorer/Edge */
|
||||
input[type="range"]::-ms-thumb {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
background: #f5f5f5;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
border: 2px solid #e9c046;
|
||||
}
|
||||
|
||||
/* Entfernt Ticks in IE */
|
||||
input[type="range"]::-ms-ticks-after,
|
||||
input[type="range"]::-ms-ticks-before {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
235
components/sliders/NoiseGainSlider.vue
Normal file
235
components/sliders/NoiseGainSlider.vue
Normal file
@@ -0,0 +1,235 @@
|
||||
<template>
|
||||
<div class="slider-wrapper">
|
||||
<!-- Slot for passing any audio element -->
|
||||
<img
|
||||
v-if="volumeValue == 0"
|
||||
style="width: 25px; height: 25px;"
|
||||
src="~/assets/image/sound_muted.svg"
|
||||
:title="t('unmuteSlider')"
|
||||
@click="toggleMute()"
|
||||
>
|
||||
<img
|
||||
v-else
|
||||
style="width: 25px; height: 25px;"
|
||||
src="~/assets/image/sound.svg"
|
||||
:title="t('muteSlider')"
|
||||
@click="toggleMute()"
|
||||
>
|
||||
<div class="slider">
|
||||
<input
|
||||
id="gain-control-music"
|
||||
ref="NoiseSlider"
|
||||
type="range"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.001"
|
||||
data-toggle="tooltip"
|
||||
data-placement="top"
|
||||
:title="t('textSlider')"
|
||||
@input="changeVolumeOnTrack"
|
||||
@wheel.prevent="changeVolumeOnWheel"
|
||||
>
|
||||
<span
|
||||
class="slider-progress-bar"
|
||||
:style="{ width: `${volumeValue * 100}%` }"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { useAudioStore } from '~/stores/audio'
|
||||
|
||||
const NoiseSlider = ref(null)
|
||||
const audioStore = useAudioStore()
|
||||
const { t } = useI18n()
|
||||
|
||||
// Computed volume value from the audio store
|
||||
const volumeValue = computed(() => audioStore.getNoiseVolume)
|
||||
// Stores volume before muting
|
||||
let volumeOnMute = audioStore.getNoiseVolume
|
||||
|
||||
/**
|
||||
* Toggles mute state:
|
||||
* - If volume > 0: saves current volume and sets to 0
|
||||
* - If volume == 0: restores saved volume
|
||||
*/
|
||||
const toggleMute = () => {
|
||||
if (audioStore.getNoiseVolume !== 0) {
|
||||
volumeOnMute = audioStore.getNoiseVolume
|
||||
audioStore.setNoiseVolume(0)
|
||||
} else {
|
||||
audioStore.setNoiseVolume(volumeOnMute)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Syncs external slider DOM element with the reactive volume state
|
||||
*/
|
||||
watch(volumeValue, (newValue) => {
|
||||
if (NoiseSlider.value) {
|
||||
const inputSlider = NoiseSlider.value as HTMLInputElement
|
||||
inputSlider.valueAsNumber = newValue
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Handles scroll wheel changes over the slider element to increment/decrement volume.
|
||||
* Clamped between 0 and 1 with 0.02 steps.
|
||||
*
|
||||
* @param {WheelEvent} event - Scroll event on the volume slider
|
||||
*/
|
||||
const changeVolumeOnWheel = (event: WheelEvent) => {
|
||||
const deltaY = event.deltaY
|
||||
if (deltaY < 0) {
|
||||
const volumeAdd = Math.min(1, volumeValue.value + 0.02)
|
||||
if (volumeAdd <= 1) { audioStore.setNoiseVolume(volumeAdd) }
|
||||
} else {
|
||||
const volumeCut = Math.max(0, volumeValue.value - 0.02)
|
||||
if (volumeCut >= 0) { audioStore.setNoiseVolume(volumeCut) }
|
||||
}
|
||||
audioStore.setNoiseVolume(volumeValue.value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets volume when user moves the range input (slider)
|
||||
*
|
||||
* @param {InputEvent} event - Input change from range slider
|
||||
*/
|
||||
const changeVolumeOnTrack = (event: InputEvent) => {
|
||||
const target = event.target as HTMLInputElement
|
||||
const volume = Number(target.value)
|
||||
if (volume >= 0 && volume <= 1) {
|
||||
audioStore.setNoiseVolume(volume)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.slider-wrapper{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.slider {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
margin: 1em auto;
|
||||
}
|
||||
|
||||
.slider-icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 576px) {
|
||||
.slider{
|
||||
max-width: 80%;
|
||||
}
|
||||
}
|
||||
|
||||
.slider-progress-bar {
|
||||
position: absolute;
|
||||
height: 10px;
|
||||
background-color: #e9c046;
|
||||
border-top-left-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
border-radius: 5px;
|
||||
left: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
/* Allgemeine Einstellungen für den Slider */
|
||||
input[type="range"] {
|
||||
-webkit-appearance: none; /* Entfernt das Standard-Styling in Webkit-Browsern */
|
||||
appearance: none; /* Entfernt Standard-Styling in anderen Browsern */
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
z-index:1;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
/* Styling für den Track in Webkit-Browsern */
|
||||
input[type="range"]::-webkit-slider-runnable-track {
|
||||
height: 10px;
|
||||
background: transparent;
|
||||
border-radius: 5px;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* Styling für den Thumb in Webkit-Browsern */
|
||||
input[type="range"]::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
background: #fff;
|
||||
border-radius: 50%;
|
||||
margin-top: -5px;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
border: 2px solid #e9c046;
|
||||
}
|
||||
|
||||
/* Styling für den Track in Firefox */
|
||||
input[type="range"]::-moz-range-track {
|
||||
height: 10px;
|
||||
background: transparent;
|
||||
border-radius: 5px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Styling für den Thumb in Firefox */
|
||||
input[type="range"]::-moz-range-thumb {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
background-color: #e9c046;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
border: 2px solid #e9c046;
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
input[type="range"]::-moz-range-progress {
|
||||
height: 10px;
|
||||
background-color: #e9c046;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* Styling für den Track in Internet Explorer/Edge */
|
||||
input[type="range"]::-ms-track {
|
||||
height: 10px;
|
||||
background: transparent;
|
||||
border-color: transparent;
|
||||
color: transparent;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* Styling für den Thumb in Internet Explorer/Edge */
|
||||
input[type="range"]::-ms-thumb {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
background: #f5f5f5;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 3px rgba(0, 0, 0, 0.3);
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
border: 2px solid #e9c046;
|
||||
}
|
||||
|
||||
/* Entfernt Ticks in IE */
|
||||
input[type="range"]::-ms-ticks-after,
|
||||
input[type="range"]::-ms-ticks-before {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user