mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-14 08:15:02 -05:00
[web] Create a slider component
As a component, the slider is easier to maintain.
This commit is contained in:
parent
4cddfa4dfc
commit
583b676489
29
web-src/src/components/ControlSlider.vue
Normal file
29
web-src/src/components/ControlSlider.vue
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<template>
|
||||||
|
<input
|
||||||
|
:value="value"
|
||||||
|
:disabled="disabled"
|
||||||
|
class="slider"
|
||||||
|
:class="{ 'is-inactive': disabled }"
|
||||||
|
:max="max"
|
||||||
|
type="range"
|
||||||
|
:style="{
|
||||||
|
'--ratio': ratio,
|
||||||
|
'--cursor': $filters.cursor(cursor)
|
||||||
|
}"
|
||||||
|
@input="$emit('update:value', $event.target.value)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'ControlSlider',
|
||||||
|
props: ['value', 'max', 'disabled', 'cursor'],
|
||||||
|
emits: ['update:value'],
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
ratio() {
|
||||||
|
return this.value / this.max
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -112,12 +112,9 @@
|
|||||||
<div class="level-item">
|
<div class="level-item">
|
||||||
<div>
|
<div>
|
||||||
<p class="heading" v-text="$t('navigation.volume')" />
|
<p class="heading" v-text="$t('navigation.volume')" />
|
||||||
<input
|
<control-slider
|
||||||
v-model="player.volume"
|
v-model:value="player.volume"
|
||||||
class="slider"
|
:max="100"
|
||||||
max="100"
|
|
||||||
type="range"
|
|
||||||
:style="{ '--ratio': player.volume / 100 }"
|
|
||||||
@change="change_volume"
|
@change="change_volume"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -163,17 +160,11 @@
|
|||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<control-slider
|
||||||
v-model="stream_volume"
|
v-model:value="stream_volume"
|
||||||
:disabled="!playing"
|
:disabled="!playing"
|
||||||
class="slider"
|
:max="100"
|
||||||
:class="{ 'is-inactive': !playing }"
|
:cursor="cursor"
|
||||||
max="100"
|
|
||||||
type="range"
|
|
||||||
:style="{
|
|
||||||
'--ratio': stream_volume / 100,
|
|
||||||
'--cursor': $filters.cursor(cursor)
|
|
||||||
}"
|
|
||||||
@change="change_stream_volume"
|
@change="change_stream_volume"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -229,12 +220,9 @@
|
|||||||
<div class="level-item">
|
<div class="level-item">
|
||||||
<div class="is-flex-grow-1">
|
<div class="is-flex-grow-1">
|
||||||
<p class="heading" v-text="$t('navigation.volume')" />
|
<p class="heading" v-text="$t('navigation.volume')" />
|
||||||
<input
|
<control-slider
|
||||||
v-model="player.volume"
|
v-model:value="player.volume"
|
||||||
class="slider"
|
:max="100"
|
||||||
max="100"
|
|
||||||
type="range"
|
|
||||||
:style="{ '--ratio': player.volume / 100 }"
|
|
||||||
@change="change_volume"
|
@change="change_volume"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -279,17 +267,11 @@
|
|||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<control-slider
|
||||||
v-model="stream_volume"
|
v-model:value="stream_volume"
|
||||||
:disabled="!playing"
|
:disabled="!playing"
|
||||||
class="slider"
|
:max="100"
|
||||||
:class="{ 'is-inactive': !playing }"
|
:cursor="cursor"
|
||||||
max="100"
|
|
||||||
type="range"
|
|
||||||
:style="{
|
|
||||||
'--ratio': stream_volume / 100,
|
|
||||||
'--cursor': $filters.cursor(cursor)
|
|
||||||
}"
|
|
||||||
@change="change_stream_volume"
|
@change="change_stream_volume"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -303,8 +285,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import webapi from '@/webapi'
|
import * as types from '@/store/mutation_types'
|
||||||
import _audio from '@/audio'
|
import _audio from '@/audio'
|
||||||
|
import ControlSlider from '@/components/ControlSlider.vue'
|
||||||
import { mdiCancel } from '@mdi/js'
|
import { mdiCancel } from '@mdi/js'
|
||||||
import NavbarItemLink from './NavbarItemLink.vue'
|
import NavbarItemLink from './NavbarItemLink.vue'
|
||||||
import NavbarItemOutput from './NavbarItemOutput.vue'
|
import NavbarItemOutput from './NavbarItemOutput.vue'
|
||||||
@ -316,11 +299,12 @@ import PlayerButtonConsume from '@/components/PlayerButtonConsume.vue'
|
|||||||
import PlayerButtonRepeat from '@/components/PlayerButtonRepeat.vue'
|
import PlayerButtonRepeat from '@/components/PlayerButtonRepeat.vue'
|
||||||
import PlayerButtonSeekBack from '@/components/PlayerButtonSeekBack.vue'
|
import PlayerButtonSeekBack from '@/components/PlayerButtonSeekBack.vue'
|
||||||
import PlayerButtonSeekForward from '@/components/PlayerButtonSeekForward.vue'
|
import PlayerButtonSeekForward from '@/components/PlayerButtonSeekForward.vue'
|
||||||
import * as types from '@/store/mutation_types'
|
import webapi from '@/webapi'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'NavbarBottom',
|
name: 'NavbarBottom',
|
||||||
components: {
|
components: {
|
||||||
|
ControlSlider,
|
||||||
NavbarItemLink,
|
NavbarItemLink,
|
||||||
NavbarItemOutput,
|
NavbarItemOutput,
|
||||||
PlayerButtonPlayPause,
|
PlayerButtonPlayPause,
|
||||||
|
@ -23,17 +23,11 @@
|
|||||||
:class="{ 'has-text-grey-light': !output.selected }"
|
:class="{ 'has-text-grey-light': !output.selected }"
|
||||||
v-text="output.name"
|
v-text="output.name"
|
||||||
/>
|
/>
|
||||||
<input
|
<control-slider
|
||||||
v-model="volume"
|
v-model:value="volume"
|
||||||
:disabled="!output.selected"
|
:disabled="!output.selected"
|
||||||
class="slider"
|
:max="100"
|
||||||
:class="{ 'is-inactive': !output.selected }"
|
:cursor="cursor"
|
||||||
max="100"
|
|
||||||
type="range"
|
|
||||||
:style="{
|
|
||||||
'--ratio': volume / 100,
|
|
||||||
'--cursor': $filters.cursor(cursor)
|
|
||||||
}"
|
|
||||||
@change="change_volume"
|
@change="change_volume"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -44,14 +38,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import ControlSlider from '@/components/ControlSlider.vue'
|
||||||
import { mdiCancel } from '@mdi/js'
|
import { mdiCancel } from '@mdi/js'
|
||||||
import webapi from '@/webapi'
|
import webapi from '@/webapi'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'NavbarItemOutput',
|
name: 'NavbarItemOutput',
|
||||||
|
|
||||||
props: ['output'],
|
props: ['output'],
|
||||||
|
components: {
|
||||||
|
ControlSlider
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
volume: this.output.selected ? this.output.volume : 0,
|
volume: this.output.selected ? this.output.volume : 0,
|
||||||
|
@ -63,28 +63,16 @@
|
|||||||
<b v-text="$t('navigation.music')" />
|
<b v-text="$t('navigation.music')" />
|
||||||
</navbar-item-link>
|
</navbar-item-link>
|
||||||
<navbar-item-link to="/music/artists">
|
<navbar-item-link to="/music/artists">
|
||||||
<span
|
<span class="pl-5" v-text="$t('navigation.artists')" />
|
||||||
class="pl-5"
|
|
||||||
v-text="$t('navigation.artists')"
|
|
||||||
/>
|
|
||||||
</navbar-item-link>
|
</navbar-item-link>
|
||||||
<navbar-item-link to="/music/albums">
|
<navbar-item-link to="/music/albums">
|
||||||
<span
|
<span class="pl-5" v-text="$t('navigation.albums')" />
|
||||||
class="pl-5"
|
|
||||||
v-text="$t('navigation.albums')"
|
|
||||||
/>
|
|
||||||
</navbar-item-link>
|
</navbar-item-link>
|
||||||
<navbar-item-link to="/music/genres">
|
<navbar-item-link to="/music/genres">
|
||||||
<span
|
<span class="pl-5" v-text="$t('navigation.genres')" />
|
||||||
class="pl-5"
|
|
||||||
v-text="$t('navigation.genres')"
|
|
||||||
/>
|
|
||||||
</navbar-item-link>
|
</navbar-item-link>
|
||||||
<navbar-item-link v-if="spotify_enabled" to="/music/spotify">
|
<navbar-item-link v-if="spotify_enabled" to="/music/spotify">
|
||||||
<span
|
<span class="pl-5" v-text="$t('navigation.spotify')" />
|
||||||
class="pl-5"
|
|
||||||
v-text="$t('navigation.spotify')"
|
|
||||||
/>
|
|
||||||
</navbar-item-link>
|
</navbar-item-link>
|
||||||
<navbar-item-link to="/podcasts">
|
<navbar-item-link to="/podcasts">
|
||||||
<mdicon class="icon" name="microphone" size="16" />
|
<mdicon class="icon" name="microphone" size="16" />
|
||||||
@ -132,8 +120,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import NavbarItemLink from './NavbarItemLink.vue'
|
|
||||||
import * as types from '@/store/mutation_types'
|
import * as types from '@/store/mutation_types'
|
||||||
|
import NavbarItemLink from './NavbarItemLink.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'NavbarTop',
|
name: 'NavbarTop',
|
||||||
|
@ -9,17 +9,12 @@
|
|||||||
class="is-clickable fd-has-shadow fd-cover-big-image"
|
class="is-clickable fd-has-shadow fd-cover-big-image"
|
||||||
@click="open_dialog(track)"
|
@click="open_dialog(track)"
|
||||||
/>
|
/>
|
||||||
<input
|
<control-slider
|
||||||
v-model.number="track_progress"
|
v-model:value="track_progress"
|
||||||
:max="track_progress_max"
|
class="mt-5"
|
||||||
type="range"
|
|
||||||
class="slider mt-5"
|
|
||||||
:class="{ 'is-inactive': is_live }"
|
|
||||||
:style="{
|
|
||||||
'--ratio': track_progress_ratio,
|
|
||||||
'--cursor': $filters.cursor(cursor)
|
|
||||||
}"
|
|
||||||
:disabled="is_live"
|
:disabled="is_live"
|
||||||
|
:max="track_progress_max"
|
||||||
|
:cursor="cursor"
|
||||||
@change="seek"
|
@change="seek"
|
||||||
@mousedown="start_dragging"
|
@mousedown="start_dragging"
|
||||||
@mouseup="end_dragging"
|
@mouseup="end_dragging"
|
||||||
@ -58,19 +53,21 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import * as types from '@/store/mutation_types'
|
||||||
|
import ControlSlider from '@/components/ControlSlider.vue'
|
||||||
import CoverArtwork from '@/components/CoverArtwork.vue'
|
import CoverArtwork from '@/components/CoverArtwork.vue'
|
||||||
import { mdiCancel } from '@mdi/js'
|
import { mdiCancel } from '@mdi/js'
|
||||||
import ModalDialogQueueItem from '@/components/ModalDialogQueueItem.vue'
|
import ModalDialogQueueItem from '@/components/ModalDialogQueueItem.vue'
|
||||||
import webapi from '@/webapi'
|
import webapi from '@/webapi'
|
||||||
import * as types from '@/store/mutation_types'
|
|
||||||
|
|
||||||
const INTERVAL = 1000
|
const INTERVAL = 1000
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'PageNowPlaying',
|
name: 'PageNowPlaying',
|
||||||
components: {
|
components: {
|
||||||
ModalDialogQueueItem,
|
ControlSlider,
|
||||||
CoverArtwork
|
CoverArtwork,
|
||||||
|
ModalDialogQueueItem
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
@ -79,8 +76,8 @@ export default {
|
|||||||
INTERVAL,
|
INTERVAL,
|
||||||
interval_id: 0,
|
interval_id: 0,
|
||||||
is_dragged: false,
|
is_dragged: false,
|
||||||
show_details_modal: false,
|
selected_item: {},
|
||||||
selected_item: {}
|
show_details_modal: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -98,10 +95,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
track_progress_ratio() {
|
|
||||||
return this.track_progress / this.track_progress_max
|
|
||||||
},
|
|
||||||
|
|
||||||
player() {
|
player() {
|
||||||
return this.$store.state.player
|
return this.$store.state.player
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user