mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-25 21:53:17 -05:00
#1458 Translation of Web UI
This commit is contained in:
parent
2b38ebaa12
commit
167ba86211
File diff suppressed because one or more lines are too long
4019
web-src/package-lock.json
generated
4019
web-src/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -2,17 +2,19 @@
|
||||
"name": "owntone-web",
|
||||
"version": "2.0.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"serve": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src",
|
||||
"format": "prettier . --write"
|
||||
"dev": "vite",
|
||||
"format": "prettier . --write",
|
||||
"i18n:report": "vue-cli-service i18n:report --src \"./src/**/*.?(js|vue)\" --locales \"./src/locales/**/*.json\"",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aacassandra/vue3-progressbar": "^1.0.3",
|
||||
"@mdi/js": "^6.6.96",
|
||||
"@ts-pro/vue-eternal-loading": "^1.2.0",
|
||||
"@vue/cli-shared-utils": "^5.0.4",
|
||||
"@vueform/slider": "github:chme/slider#faff83ed8a77f2cdbcb7252505ef734301efd139",
|
||||
"axios": "^0.26.1",
|
||||
"bulma": "^0.9.3",
|
||||
@ -23,6 +25,7 @@
|
||||
"spotify-web-api-js": "^1.5.2",
|
||||
"string-to-color": "^2.2.2",
|
||||
"vue": "^3.2.33",
|
||||
"vue-i18n": "^9.1.0",
|
||||
"vue-router": "^4.0.14",
|
||||
"vue-scrollto": "^2.20.0",
|
||||
"vue3-click-away": "^1.2.4",
|
||||
@ -31,12 +34,15 @@
|
||||
"vuex": "^4.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@intlify/vite-plugin-vue-i18n": "^3.4.0",
|
||||
"@intlify/vue-i18n-loader": "^3.0.0",
|
||||
"@vitejs/plugin-vue": "^2.3.1",
|
||||
"eslint": "^8.13.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-vue": "^8.6.0",
|
||||
"prettier": "2.6.2",
|
||||
"sass": "^1.50.0",
|
||||
"vite": "^2.9.5"
|
||||
"vite": "^2.9.8",
|
||||
"vue-cli-plugin-i18n": "~2.3.1"
|
||||
}
|
||||
}
|
||||
|
@ -116,15 +116,6 @@ export default {
|
||||
|
||||
methods: {
|
||||
connect: function () {
|
||||
/*
|
||||
this.$store.dispatch('add_notification', {
|
||||
text: 'Connecting to OwnTone server',
|
||||
type: 'info',
|
||||
topic: 'connection',
|
||||
timeout: 2000
|
||||
})
|
||||
*/
|
||||
|
||||
webapi
|
||||
.config()
|
||||
.then(({ data }) => {
|
||||
@ -137,7 +128,7 @@ export default {
|
||||
})
|
||||
.catch(() => {
|
||||
this.$store.dispatch('add_notification', {
|
||||
text: 'Failed to connect to OwnTone server',
|
||||
text: this.$t('server.connection.failed'),
|
||||
type: 'danger',
|
||||
topic: 'connection'
|
||||
})
|
||||
@ -147,7 +138,7 @@ export default {
|
||||
open_ws: function () {
|
||||
if (this.$store.state.config.websocket_port <= 0) {
|
||||
this.$store.dispatch('add_notification', {
|
||||
text: 'Missing websocket port',
|
||||
text: this.$t('server.missing-port'),
|
||||
type: 'danger'
|
||||
})
|
||||
return
|
||||
@ -183,14 +174,6 @@ export default {
|
||||
})
|
||||
|
||||
socket.onopen = function () {
|
||||
/*
|
||||
vm.$store.dispatch('add_notification', {
|
||||
text: 'Connection to server established',
|
||||
type: 'primary',
|
||||
topic: 'connection',
|
||||
timeout: 2000
|
||||
})
|
||||
*/
|
||||
vm.reconnect_attempts = 0
|
||||
socket.send(
|
||||
JSON.stringify({
|
||||
@ -221,17 +204,6 @@ export default {
|
||||
socket.onclose = function () {
|
||||
// vm.$store.dispatch('add_notification', { text: 'Connection closed', type: 'danger', timeout: 2000 })
|
||||
}
|
||||
/*
|
||||
socket.onerror = function () {
|
||||
vm.reconnect_attempts++
|
||||
vm.$store.dispatch('add_notification', {
|
||||
text:
|
||||
'Connection lost. Reconnecting ... (' + vm.reconnect_attempts + ')',
|
||||
type: 'danger',
|
||||
topic: 'connection'
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
// When the app becomes active, force an update of all information, because we
|
||||
// may have missed notifications while the app was inactive.
|
||||
|
@ -1,9 +1,6 @@
|
||||
<template>
|
||||
<figure>
|
||||
<img
|
||||
v-lazy="{ src: artwork_url_with_size, lifecycle: lazy_lifecycle }"
|
||||
@click="$emit('click')"
|
||||
/>
|
||||
<img v-lazy="{ src: artwork_url_with_size, lifecycle: lazy_lifecycle }" @click="$emit('click')" />
|
||||
</figure>
|
||||
</template>
|
||||
|
||||
|
@ -1,33 +1,14 @@
|
||||
<template>
|
||||
<div
|
||||
v-click-away="onClickOutside"
|
||||
class="dropdown"
|
||||
:class="{ 'is-active': is_active }"
|
||||
>
|
||||
<div v-click-away="onClickOutside" class="dropdown" :class="{ 'is-active': is_active }">
|
||||
<div class="dropdown-trigger">
|
||||
<button
|
||||
class="button"
|
||||
aria-haspopup="true"
|
||||
aria-controls="dropdown-menu"
|
||||
@click="is_active = !is_active"
|
||||
>
|
||||
<span>{{ modelValue }}</span>
|
||||
<span class="icon">
|
||||
<mdicon name="chevron-down" size="16" />
|
||||
</span>
|
||||
<button class="button" aria-haspopup="true" aria-controls="dropdown-menu" @click="is_active = !is_active">
|
||||
<span v-text="option.name" />
|
||||
<mdicon class="icon" name="chevron-down" size="16" />
|
||||
</button>
|
||||
</div>
|
||||
<div id="dropdown-menu" class="dropdown-menu" role="menu">
|
||||
<div class="dropdown-content">
|
||||
<a
|
||||
v-for="option in options"
|
||||
:key="option"
|
||||
class="dropdown-item"
|
||||
:class="{ 'is-active': modelValue === option }"
|
||||
@click="select(option)"
|
||||
>
|
||||
{{ option }}
|
||||
</a>
|
||||
<a v-for="option in options" :key="option.id" class="dropdown-item" :class="{ 'is-active': modelValue === option.id }" @click="select(option)" v-text="option.name" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -36,8 +17,6 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'DropdownMenu',
|
||||
|
||||
// eslint-disable-next-line vue/prop-name-casing
|
||||
props: ['modelValue', 'options'],
|
||||
emits: ['update:modelValue'],
|
||||
|
||||
@ -47,6 +26,14 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
option: {
|
||||
get() {
|
||||
return this.options.find((option) => option.id === this.modelValue)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onClickOutside(event) {
|
||||
this.is_active = false
|
||||
@ -54,7 +41,7 @@ export default {
|
||||
|
||||
select(option) {
|
||||
this.is_active = false
|
||||
this.$emit('update:modelValue', option)
|
||||
this.$emit('update:modelValue', option.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,7 @@
|
||||
<template>
|
||||
<section>
|
||||
<nav class="buttons is-centered fd-is-square" style="margin-bottom: 16px">
|
||||
<a
|
||||
v-for="char in filtered_index"
|
||||
:key="char"
|
||||
class="button is-small"
|
||||
@click="nav(char)"
|
||||
>{{ char }}</a
|
||||
>
|
||||
<a v-for="char in filtered_index" :key="char" class="button is-small" @click="nav(char)" v-text="char" />
|
||||
</nav>
|
||||
</section>
|
||||
</template>
|
||||
@ -15,9 +9,7 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'IndexButtonList',
|
||||
|
||||
props: ['index'],
|
||||
|
||||
computed: {
|
||||
filtered_index() {
|
||||
if (!this.index) {
|
||||
@ -27,7 +19,6 @@ export default {
|
||||
return this.index.filter((c) => !specialChars.includes(c))
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
nav: function (id) {
|
||||
this.$router.push({ hash: '#index_' + id })
|
||||
|
@ -1,75 +1,38 @@
|
||||
<template>
|
||||
<template v-for="album in albums" :key="album.itemId">
|
||||
<div v-if="!album.isItem && !hide_group_title" class="mt-6 mb-5 py-2">
|
||||
<span
|
||||
:id="'index_' + album.groupKey"
|
||||
class="tag is-info is-light is-small has-text-weight-bold"
|
||||
>{{ album.groupKey }}</span
|
||||
>
|
||||
<span :id="'index_' + album.groupKey" class="tag is-info is-light is-small has-text-weight-bold" v-text="album.groupKey" />
|
||||
</div>
|
||||
<div v-else-if="album.isItem" class="media" @click="open_album(album.item)">
|
||||
<div v-if="is_visible_artwork" class="media-left fd-has-action">
|
||||
<div class="image is-64x64 fd-has-shadow fd-has-action">
|
||||
<figure>
|
||||
<img
|
||||
v-lazy="{
|
||||
src: artwork_url_with_size(album.item.artwork_url),
|
||||
lifecycle: artwork_options.lazy_lifecycle
|
||||
}"
|
||||
:album="album.item.name"
|
||||
:artist="album.item.artist"
|
||||
/>
|
||||
<img v-lazy="{ src: artwork_url_with_size(album.item.artwork_url), lifecycle: artwork_options.lazy_lifecycle }" :album="album.item.name" :artist="album.item.artist" />
|
||||
</figure>
|
||||
</div>
|
||||
</div>
|
||||
<div class="media-content fd-has-action is-clipped">
|
||||
<div style="margin-top: 0.7rem">
|
||||
<h1 class="title is-6">
|
||||
{{ album.item.name }}
|
||||
</h1>
|
||||
<h1 class="title is-6" v-text="album.item.name" />
|
||||
<h2 class="subtitle is-7 has-text-grey">
|
||||
<b>{{ album.item.artist }}</b>
|
||||
</h2>
|
||||
<h2
|
||||
v-if="album.item.date_released && album.item.media_kind === 'music'"
|
||||
class="subtitle is-7 has-text-grey has-text-weight-normal"
|
||||
>
|
||||
{{ $filters.date(album.item.date_released) }}
|
||||
<b v-text="album.item.artist" />
|
||||
</h2>
|
||||
<h2 v-if="album.item.date_released && album.item.media_kind === 'music'" class="subtitle is-7 has-text-grey has-text-weight-normal" v-text="$filters.date(album.item.date_released)" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="media-right" style="padding-top: 0.7rem">
|
||||
<a @click.prevent.stop="open_dialog(album.item)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<teleport to="#app">
|
||||
<modal-dialog-album
|
||||
:show="show_details_modal"
|
||||
:album="selected_album"
|
||||
:media_kind="media_kind"
|
||||
@remove-podcast="open_remove_podcast_dialog()"
|
||||
@play-count-changed="play_count_changed()"
|
||||
@close="show_details_modal = false"
|
||||
/>
|
||||
<modal-dialog
|
||||
:show="show_remove_podcast_modal"
|
||||
title="Remove podcast"
|
||||
delete_action="Remove"
|
||||
@close="show_remove_podcast_modal = false"
|
||||
@delete="remove_podcast"
|
||||
>
|
||||
<modal-dialog-album :show="show_details_modal" :album="selected_album" :media_kind="media_kind" @remove-podcast="open_remove_podcast_dialog()" @play-count-changed="play_count_changed()" @close="show_details_modal = false" />
|
||||
<modal-dialog :show="show_remove_podcast_modal" title="Remove podcast" delete_action="Remove" @close="show_remove_podcast_modal = false" @delete="remove_podcast">
|
||||
<template #modal-content>
|
||||
<p>Permanently remove this podcast from your library?</p>
|
||||
<p class="is-size-7">
|
||||
(This will also remove the RSS playlist
|
||||
<b>{{ rss_playlist_to_remove.name }}</b
|
||||
>.)
|
||||
</p>
|
||||
<p v-text="$t('list.albums.info-1')" />
|
||||
<p class="is-size-7" v-html="$t('list.albums.info-2', { name: rss_playlist_to_remove.name })" />
|
||||
</template>
|
||||
</modal-dialog>
|
||||
</teleport>
|
||||
@ -152,7 +115,7 @@ export default {
|
||||
const rssPlaylists = data.items.filter((pl) => pl.type === 'rss')
|
||||
if (rssPlaylists.length !== 1) {
|
||||
this.$store.dispatch('add_notification', {
|
||||
text: 'Podcast cannot be removed. Probably it was not added as an RSS playlist.',
|
||||
text: this.$t('list.albums.notification'),
|
||||
type: 'danger'
|
||||
})
|
||||
return
|
||||
|
@ -2,39 +2,22 @@
|
||||
<template v-for="artist in artists" :key="artist.itemId">
|
||||
<div v-if="!artist.isItem && !hide_group_title" class="mt-6 mb-5 py-2">
|
||||
<div class="media-content is-clipped">
|
||||
<span
|
||||
:id="'index_' + artist.groupKey"
|
||||
class="tag is-info is-light is-small has-text-weight-bold"
|
||||
>{{ artist.groupKey }}</span
|
||||
>
|
||||
<span :id="'index_' + artist.groupKey" class="tag is-info is-light is-small has-text-weight-bold" v-text="artist.groupKey" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="artist.isItem"
|
||||
class="media"
|
||||
@click="open_artist(artist.item)"
|
||||
>
|
||||
<div v-else-if="artist.isItem" class="media" @click="open_artist(artist.item)">
|
||||
<div class="media-content fd-has-action is-clipped">
|
||||
<h1 class="title is-6">
|
||||
{{ artist.item.name }}
|
||||
</h1>
|
||||
<h1 class="title is-6" v-text="artist.item.name" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="open_dialog(artist.item)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<teleport to="#app">
|
||||
<modal-dialog-artist
|
||||
:show="show_details_modal"
|
||||
:artist="selected_artist"
|
||||
:media_kind="media_kind"
|
||||
@close="show_details_modal = false"
|
||||
/>
|
||||
<modal-dialog-artist :show="show_details_modal" :artist="selected_artist" :media_kind="media_kind" @close="show_details_modal = false" />
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
|
@ -2,39 +2,22 @@
|
||||
<template v-for="composer in composers" :key="composer.itemId">
|
||||
<div v-if="!composer.isItem && !hide_group_title" class="mt-6 mb-5 py-2">
|
||||
<div class="media-content is-clipped">
|
||||
<span
|
||||
:id="'index_' + composer.groupKey"
|
||||
class="tag is-info is-light is-small has-text-weight-bold"
|
||||
>{{ composer.groupKey }}</span
|
||||
>
|
||||
<span :id="'index_' + composer.groupKey" class="tag is-info is-light is-small has-text-weight-bold" v-text="composer.groupKey" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="composer.isItem"
|
||||
class="media"
|
||||
@click="open_composer(composer.item)"
|
||||
>
|
||||
<div v-else-if="composer.isItem" class="media" @click="open_composer(composer.item)">
|
||||
<div class="media-content fd-has-action is-clipped">
|
||||
<h1 class="title is-6">
|
||||
{{ composer.item.name }}
|
||||
</h1>
|
||||
<h1 class="title is-6" v-text="composer.item.name" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="open_dialog(composer.item)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<teleport to="#app">
|
||||
<modal-dialog-composer
|
||||
:show="show_details_modal"
|
||||
:composer="selected_composer"
|
||||
:media_kind="media_kind"
|
||||
@close="show_details_modal = false"
|
||||
/>
|
||||
<modal-dialog-composer :show="show_details_modal" :composer="selected_composer" :media_kind="media_kind" @close="show_details_modal = false" />
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
@ -44,7 +27,6 @@ import ModalDialogComposer from '@/components/ModalDialogComposer.vue'
|
||||
export default {
|
||||
name: 'ListComposers',
|
||||
components: { ModalDialogComposer },
|
||||
|
||||
props: ['composers', 'media_kind', 'hide_group_title'],
|
||||
|
||||
data() {
|
||||
|
@ -1,13 +1,7 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="$route.query.directory"
|
||||
class="media"
|
||||
@click="open_parent_directory()"
|
||||
>
|
||||
<div v-if="$route.query.directory" class="media" @click="open_parent_directory()">
|
||||
<figure class="media-left fd-has-action">
|
||||
<span class="icon">
|
||||
<mdicon name="subdirectory-arrow-left" size="16" />
|
||||
</span>
|
||||
<mdicon class="icon" name="subdirectory-arrow-left" size="16" />
|
||||
</figure>
|
||||
<div class="media-content fd-has-action is-clipped">
|
||||
<h1 class="title is-6">..</h1>
|
||||
@ -19,33 +13,21 @@
|
||||
<template v-for="directory in directories" :key="directory.path">
|
||||
<div class="media" @click="open_directory(directory)">
|
||||
<figure class="media-left fd-has-action">
|
||||
<span class="icon">
|
||||
<mdicon name="folder" size="16" />
|
||||
</span>
|
||||
<mdicon class="icon" name="folder" size="16" />
|
||||
</figure>
|
||||
<div class="media-content fd-has-action is-clipped">
|
||||
<h1 class="title is-6">
|
||||
{{ directory.path.substring(directory.path.lastIndexOf('/') + 1) }}
|
||||
</h1>
|
||||
<h2 class="subtitle is-7 has-text-grey-light">
|
||||
{{ directory.path }}
|
||||
</h2>
|
||||
<h1 class="title is-6" v-text="directory.path.substring(directory.path.lastIndexOf('/') + 1)" />
|
||||
<h2 class="subtitle is-7 has-text-grey-light" v-text="directory.path" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="open_dialog(directory)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<teleport to="#app">
|
||||
<modal-dialog-directory
|
||||
:show="show_details_modal"
|
||||
:directory="selected_directory"
|
||||
@close="show_details_modal = false"
|
||||
/>
|
||||
<modal-dialog-directory :show="show_details_modal" :directory="selected_directory" @close="show_details_modal = false" />
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
|
@ -2,34 +2,22 @@
|
||||
<template v-for="genre in genres" :key="genre.itemId">
|
||||
<div v-if="!genre.isItem && !hide_group_title" class="mt-6 mb-5 py-2">
|
||||
<div class="media-content is-clipped">
|
||||
<span
|
||||
:id="'index_' + genre.groupKey"
|
||||
class="tag is-info is-light is-small has-text-weight-bold"
|
||||
>{{ genre.groupKey }}</span
|
||||
>
|
||||
<span :id="'index_' + genre.groupKey" class="tag is-info is-light is-small has-text-weight-bold" v-text="genre.groupKey" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="genre.isItem" class="media" @click="open_genre(genre.item)">
|
||||
<div class="media-content fd-has-action is-clipped">
|
||||
<h1 class="title is-6">
|
||||
{{ genre.item.name }}
|
||||
</h1>
|
||||
<h1 class="title is-6" v-text="genre.item.name" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="open_dialog(genre.item)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<teleport to="#app">
|
||||
<modal-dialog-genre
|
||||
:show="show_details_modal"
|
||||
:genre="selected_genre"
|
||||
@close="show_details_modal = false"
|
||||
/>
|
||||
<modal-dialog-genre :show="show_details_modal" :genre="selected_genre" @close="show_details_modal = false" />
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
|
@ -1,41 +1,14 @@
|
||||
<template>
|
||||
<div v-if="is_next || !show_only_next_items" class="media">
|
||||
<div v-if="edit_mode" class="media-left">
|
||||
<span class="icon has-text-grey fd-is-movable handle"
|
||||
><mdicon name="drag-horizontal" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-grey fd-is-movable handle" name="drag-horizontal" size="16" />
|
||||
</div>
|
||||
|
||||
<div class="media-content fd-has-action is-clipped" @click="play">
|
||||
<h1
|
||||
class="title is-6"
|
||||
:class="{
|
||||
'has-text-primary': item.id === state.item_id,
|
||||
'has-text-grey-light': !is_next
|
||||
}"
|
||||
>
|
||||
{{ item.title }}
|
||||
</h1>
|
||||
<h2
|
||||
class="subtitle is-7"
|
||||
:class="{
|
||||
'has-text-primary': item.id === state.item_id,
|
||||
'has-text-grey-light': !is_next,
|
||||
'has-text-grey': is_next && item.id !== state.item_id
|
||||
}"
|
||||
>
|
||||
<b>{{ item.artist }}</b>
|
||||
</h2>
|
||||
<h2
|
||||
class="subtitle is-7"
|
||||
:class="{
|
||||
'has-text-primary': item.id === state.item_id,
|
||||
'has-text-grey-light': !is_next,
|
||||
'has-text-grey': is_next && item.id !== state.item_id
|
||||
}"
|
||||
>
|
||||
{{ item.album }}
|
||||
<h1 class="title is-6" :class="{ 'has-text-primary': item.id === state.item_id, 'has-text-grey-light': !is_next }" v-text="item.title" />
|
||||
<h2 class="subtitle is-7" :class="{ 'has-text-primary': item.id === state.item_id, 'has-text-grey-light': !is_next, 'has-text-grey': is_next && item.id !== state.item_id }">
|
||||
<b v-text="item.artist" />
|
||||
</h2>
|
||||
<h2 class="subtitle is-7" :class="{ 'has-text-primary': item.id === state.item_id, 'has-text-grey-light': !is_next, 'has-text-grey': is_next && item.id !== state.item_id }" v-text="item.album" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<slot name="actions" />
|
||||
|
@ -1,35 +1,19 @@
|
||||
<template>
|
||||
<div
|
||||
v-for="playlist in playlists"
|
||||
:key="playlist.itemId"
|
||||
class="media"
|
||||
:playlist="playlist"
|
||||
@click="open_playlist(playlist.item)"
|
||||
>
|
||||
<div v-for="playlist in playlists" :key="playlist.itemId" class="media" :playlist="playlist" @click="open_playlist(playlist.item)">
|
||||
<figure class="media-left fd-has-action">
|
||||
<span class="icon">
|
||||
<mdicon :name="icon_name(playlist.item)" size="16" />
|
||||
</span>
|
||||
<mdicon class="icon" :name="icon_name(playlist.item)" size="16" />
|
||||
</figure>
|
||||
<div class="media-content fd-has-action is-clipped">
|
||||
<h1 class="title is-6">
|
||||
{{ playlist.item.name }}
|
||||
</h1>
|
||||
<h1 class="title is-6" v-text="playlist.item.name" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="open_dialog(playlist.item)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<teleport to="#app">
|
||||
<modal-dialog-playlist
|
||||
:show="show_details_modal"
|
||||
:playlist="selected_playlist"
|
||||
@close="show_details_modal = false"
|
||||
/>
|
||||
<modal-dialog-playlist :show="show_details_modal" :playlist="selected_playlist" @close="show_details_modal = false" />
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
|
@ -1,55 +1,22 @@
|
||||
<template>
|
||||
<div
|
||||
v-for="(track, index) in tracks"
|
||||
:id="'index_' + track.title_sort.charAt(0).toUpperCase()"
|
||||
:key="track.id"
|
||||
class="media"
|
||||
:class="{ 'with-progress': show_progress }"
|
||||
@click="play_track(index, track)"
|
||||
>
|
||||
<div v-for="(track, index) in tracks" :id="'index_' + track.title_sort.charAt(0).toUpperCase()" :key="track.id" class="media" :class="{ 'with-progress': show_progress }" @click="play_track(index, track)">
|
||||
<figure v-if="show_icon" class="media-left fd-has-action">
|
||||
<span class="icon">
|
||||
<mdicon name="file-outline" size="16" />
|
||||
</span>
|
||||
<mdicon class="icon" name="file-outline" size="16" />
|
||||
</figure>
|
||||
<div class="media-content fd-has-action is-clipped">
|
||||
<h1
|
||||
class="title is-6"
|
||||
:class="{
|
||||
'has-text-grey':
|
||||
track.media_kind === 'podcast' && track.play_count > 0
|
||||
}"
|
||||
>
|
||||
{{ track.title }}
|
||||
</h1>
|
||||
<h2 class="subtitle is-7 has-text-grey">
|
||||
<b>{{ track.artist }}</b>
|
||||
</h2>
|
||||
<h2 class="subtitle is-7 has-text-grey">
|
||||
{{ track.album }}
|
||||
</h2>
|
||||
<progress-bar
|
||||
v-if="show_progress"
|
||||
:max="track.length_ms"
|
||||
:value="track.seek_ms"
|
||||
/>
|
||||
<h1 class="title is-6" :class="{ 'has-text-grey': track.media_kind === 'podcast' && track.play_count > 0 }" v-text="track.title" />
|
||||
<h2 class="subtitle is-7 has-text-grey" v-text="track.artist" />
|
||||
<h2 class="subtitle is-7 has-text-grey" v-text="track.album" />
|
||||
<progress-bar v-if="show_progress" :max="track.length_ms" :value="track.seek_ms" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<a @click.prevent.stop="open_dialog(track)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<teleport to="#app">
|
||||
<modal-dialog-track
|
||||
:show="show_details_modal"
|
||||
:track="selected_track"
|
||||
@close="show_details_modal = false"
|
||||
@play-count-changed="$emit('play-count-changed')"
|
||||
/>
|
||||
<modal-dialog-track :show="show_details_modal" :track="selected_track" @close="show_details_modal = false" @play-count-changed="$emit('play-count-changed')" />
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
|
@ -6,42 +6,26 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p v-if="title" class="title is-4">
|
||||
{{ title }}
|
||||
</p>
|
||||
<p v-if="title" class="title is-4" v-text="title" />
|
||||
<slot name="modal-content" />
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="$emit('close')">
|
||||
<span class="icon"><mdicon name="cancel" size="16" /></span>
|
||||
<span class="is-size-7">{{
|
||||
close_action ? close_action : 'Cancel'
|
||||
}}</span>
|
||||
<mdicon class="icon" name="cancel" size="16" />
|
||||
<span class="is-size-7" v-text="close_action ? close_action : t('dialog.cancel')" />
|
||||
</a>
|
||||
<a
|
||||
v-if="delete_action"
|
||||
class="card-footer-item has-background-danger has-text-white has-text-weight-bold"
|
||||
@click="$emit('delete')"
|
||||
>
|
||||
<span class="icon"><mdicon name="delete" size="16" /></span>
|
||||
<span class="is-size-7">{{ delete_action }}</span>
|
||||
<a v-if="delete_action" class="card-footer-item has-background-danger has-text-white has-text-weight-bold" @click="$emit('delete')">
|
||||
<mdicon class="icon" name="delete" size="16" />
|
||||
<span class="is-size-7" v-text="delete_action" />
|
||||
</a>
|
||||
<a
|
||||
v-if="ok_action"
|
||||
class="card-footer-item has-background-info has-text-white has-text-weight-bold"
|
||||
@click="$emit('ok')"
|
||||
>
|
||||
<span class="icon"><mdicon name="check" size="16" /></span>
|
||||
<span class="is-size-7">{{ ok_action }}</span>
|
||||
<a v-if="ok_action" class="card-footer-item has-background-info has-text-white has-text-weight-bold" @click="$emit('ok')">
|
||||
<mdicon class="icon" name="check" size="16" />
|
||||
<span class="is-size-7" v-text="ok_action" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="modal-close is-large"
|
||||
aria-label="close"
|
||||
@click="$emit('close')"
|
||||
/>
|
||||
<button class="modal-close is-large" aria-label="close" @click="$emit('close')" />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -6,60 +6,36 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">Add Podcast RSS feed URL</p>
|
||||
<p class="title is-4" v-text="$t('dialog.add.rss.title')" />
|
||||
<form @submit.prevent="add_stream">
|
||||
<div class="field">
|
||||
<p class="control is-expanded has-icons-left">
|
||||
<input
|
||||
ref="url_field"
|
||||
v-model="url"
|
||||
class="input is-shadowless"
|
||||
type="text"
|
||||
placeholder="http://url-to-rss"
|
||||
:disabled="loading"
|
||||
/>
|
||||
<span class="icon is-left">
|
||||
<mdicon name="rss" size="16" />
|
||||
</span>
|
||||
</p>
|
||||
<p class="help">
|
||||
Adding a podcast includes creating an RSS playlist, that
|
||||
will allow OwnTone to manage the podcast subscription.
|
||||
<input ref="url_field" v-model="url" class="input is-shadowless" type="text" :placeholder="$t('dialog.add.rss.placeholder')" :disabled="loading" />
|
||||
<mdicon class="icon is-left" name="rss" size="16" />
|
||||
</p>
|
||||
<p class="help" v-text="$t('dialog.add.rss.help')" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<footer v-if="loading" class="card-footer">
|
||||
<a class="card-footer-item button is-loading">
|
||||
<span class="icon"><mdicon name="web" size="16" /></span>
|
||||
<span class="is-size-7">Processing ...</span>
|
||||
<mdicon class="icon" name="web" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.add.rss.processing')" />
|
||||
</a>
|
||||
</footer>
|
||||
<footer v-else class="card-footer">
|
||||
<a
|
||||
class="card-footer-item has-text-danger"
|
||||
@click="$emit('close')"
|
||||
>
|
||||
<span class="icon"><mdicon name="cancel" size="16" /></span>
|
||||
<span class="is-size-7">Cancel</span>
|
||||
<a class="card-footer-item has-text-danger" @click="$emit('close')">
|
||||
<mdicon class="icon" name="cancel" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.add.rss.cancel')" />
|
||||
</a>
|
||||
<a
|
||||
class="card-footer-item has-background-info has-text-white has-text-weight-bold"
|
||||
@click="add_stream"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<a class="card-footer-item has-background-info has-text-white has-text-weight-bold" @click="add_stream">
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.add.rss.add')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="modal-close is-large"
|
||||
aria-label="close"
|
||||
@click="$emit('close')"
|
||||
/>
|
||||
<button class="modal-close is-large" aria-label="close" @click="$emit('close')" />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -6,60 +6,39 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">Add stream URL</p>
|
||||
<p class="title is-4" v-text="$t('dialog.add.stream.title')" />
|
||||
<form class="fd-has-margin-bottom" @submit.prevent="play">
|
||||
<div class="field">
|
||||
<p class="control is-expanded has-icons-left">
|
||||
<input
|
||||
ref="url_field"
|
||||
v-model="url"
|
||||
class="input is-shadowless"
|
||||
type="text"
|
||||
placeholder="http://url-to-stream"
|
||||
:disabled="loading"
|
||||
/>
|
||||
<span class="icon is-left">
|
||||
<mdicon name="web" size="16" />
|
||||
</span>
|
||||
<input ref="url_field" v-model="url" class="input is-shadowless" type="text" :placeholder="$t('dialog.add.stream.placeholder')" :disabled="loading" />
|
||||
<mdicon class="icon is-left" name="web" size="16" />
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<footer v-if="loading" class="card-footer">
|
||||
<a class="card-footer-item has-text-dark">
|
||||
<span class="icon"><mdicon name="web" size="16" /></span>
|
||||
<span class="is-size-7">Loading ...</span>
|
||||
<mdicon class="icon" name="web" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.add.stream.loading')" />
|
||||
</a>
|
||||
</footer>
|
||||
<footer v-else class="card-footer">
|
||||
<a
|
||||
class="card-footer-item has-text-danger"
|
||||
@click="$emit('close')"
|
||||
>
|
||||
<span class="icon"><mdicon name="cancel" size="16" /></span>
|
||||
<span class="is-size-7">Cancel</span>
|
||||
<a class="card-footer-item has-text-danger" @click="$emit('close')">
|
||||
<mdicon class="icon" name="cancel" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.add.stream.cancel')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="add_stream">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.add.stream.add')" />
|
||||
</a>
|
||||
<a
|
||||
class="card-footer-item has-background-info has-text-white has-text-weight-bold"
|
||||
@click="play"
|
||||
>
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<a class="card-footer-item has-background-info has-text-white has-text-weight-bold" @click="play">
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.add.stream.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="modal-close is-large"
|
||||
aria-label="close"
|
||||
@click="$emit('close')"
|
||||
/>
|
||||
<button class="modal-close is-large" aria-label="close" @click="$emit('close')" />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -6,91 +6,62 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<cover-artwork
|
||||
:artwork_url="album.artwork_url"
|
||||
:artist="album.artist"
|
||||
:album="album.name"
|
||||
class="image is-square fd-has-margin-bottom fd-has-shadow"
|
||||
/>
|
||||
<cover-artwork :artwork_url="album.artwork_url" :artist="album.artist" :album="album.name" class="image is-square fd-has-margin-bottom fd-has-shadow" />
|
||||
<p class="title is-4">
|
||||
<a class="has-text-link" @click="open_album">{{
|
||||
album.name
|
||||
}}</a>
|
||||
<a class="has-text-link" @click="open_album" v-text="album.name" />
|
||||
</p>
|
||||
<div v-if="media_kind_resolved === 'podcast'" class="buttons">
|
||||
<a class="button is-small" @click="mark_played"
|
||||
>Mark as played</a
|
||||
>
|
||||
<a class="button is-small" @click="$emit('remove-podcast')"
|
||||
>Remove podcast</a
|
||||
>
|
||||
<a class="button is-small" @click="mark_played" v-text="$t('dialog.album.mark-as-played')" />
|
||||
<a class="button is-small" @click="$emit('remove-podcast')" v-text="$t('dialog.album.remove-podcast')" />
|
||||
</div>
|
||||
<div class="content is-small">
|
||||
<p v-if="album.artist">
|
||||
<span class="heading">Album artist</span>
|
||||
<a class="title is-6 has-text-link" @click="open_artist">{{
|
||||
album.artist
|
||||
}}</a>
|
||||
<span class="heading" v-text="$t('dialog.album.artist')" />
|
||||
<a class="title is-6 has-text-link" @click="open_artist" v-text="album.artist" />
|
||||
</p>
|
||||
<p v-if="album.date_released">
|
||||
<span class="heading">Release date</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.date(album.date_released)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.album.release-date')" />
|
||||
<span class="title is-6" v-text="$filters.date(album.date_released)" />
|
||||
</p>
|
||||
<p v-else-if="album.year > 0">
|
||||
<span class="heading">Year</span>
|
||||
<span class="title is-6">{{ album.year }}</span>
|
||||
<span class="heading" v-text="$t('dialog.album.year')" />
|
||||
<span class="title is-6" v-text="album.year" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Tracks</span>
|
||||
<span class="title is-6">{{ album.track_count }}</span>
|
||||
<span class="heading" v-text="$t('dialog.album.tracks')" />
|
||||
<span class="title is-6" v-text="album.track_count" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Length</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.durationInHours(album.length_ms)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.album.duration')" />
|
||||
<span class="title is-6" v-text="$filters.durationInHours(album.length_ms)" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Type</span>
|
||||
<span class="title is-6"
|
||||
>{{ album.media_kind }} - {{ album.data_kind }}</span
|
||||
>
|
||||
<span class="heading" v-text="$t('dialog.album.type')" />
|
||||
<span class="title is-6" v-text="[t('media.kind.' + album.media_kind), t('data.kind.' + album.data_kind)].join(' - ')" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Added at</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.datetime(album.time_added)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.album.added-on')" />
|
||||
<span class="title is-6" v-text="$filters.datetime(album.time_added)" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.album.add')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.album.add-next')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.album.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="modal-close is-large"
|
||||
aria-label="close"
|
||||
@click="$emit('close')"
|
||||
/>
|
||||
<button class="modal-close is-large" aria-label="close" @click="$emit('close')" />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -7,56 +7,44 @@
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
<a class="has-text-link" @click="open_artist">{{
|
||||
artist.name
|
||||
}}</a>
|
||||
<a class="has-text-link" @click="open_artist" v-text="artist.name" />
|
||||
</p>
|
||||
<div class="content is-small">
|
||||
<p>
|
||||
<span class="heading">Albums</span>
|
||||
<span class="title is-6">{{ artist.album_count }}</span>
|
||||
<span class="heading" v-text="$t('dialog.artist.albums')" />
|
||||
<span class="title is-6" v-text="artist.album_count" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Tracks</span>
|
||||
<span class="title is-6">{{ artist.track_count }}</span>
|
||||
<span class="heading" v-text="$t('dialog.artist.tracks')" />
|
||||
<span class="title is-6" v-text="artist.track_count" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Type</span>
|
||||
<span class="title is-6">{{ artist.data_kind }}</span>
|
||||
<span class="heading" v-text="$t('dialog.artist.type')" />
|
||||
<span class="title is-6" v-text="$t('data.kind.' + artist.data_kind)" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Added at</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.datetime(artist.time_added)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.artist.added-on')" />
|
||||
<span class="title is-6" v-text="$filters.datetime(artist.time_added)" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.artist.add')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.artist.add-next')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.artist.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="modal-close is-large"
|
||||
aria-label="close"
|
||||
@click="$emit('close')"
|
||||
/>
|
||||
<button class="modal-close is-large" aria-label="close" @click="$emit('close')" />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -7,54 +7,38 @@
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
<a class="has-text-link" @click="open_albums">{{
|
||||
composer.name
|
||||
}}</a>
|
||||
<a class="has-text-link" @click="open_albums" v-text="composer.name" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Albums</span>
|
||||
<a class="has-text-link is-6" @click="open_albums">{{
|
||||
composer.album_count
|
||||
}}</a>
|
||||
<span class="heading" v-text="$t('dialog.composer.albums')" />
|
||||
<a class="has-text-link is-6" @click="open_albums" v-text="composer.album_count" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Tracks</span>
|
||||
<a class="has-text-link is-6" @click="open_tracks">{{
|
||||
composer.track_count
|
||||
}}</a>
|
||||
<span class="heading" v-text="$t('dialog.composer.tracks')" />
|
||||
<a class="has-text-link is-6" @click="open_tracks" v-text="composer.track_count" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Length</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.durationInHours(composer.length_ms)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.composer.duration')" />
|
||||
<span class="title is-6" v-text="$filters.durationInHours(composer.length_ms)" />
|
||||
</p>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.composer.add')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.composer.add-next')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.composer.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="modal-close is-large"
|
||||
aria-label="close"
|
||||
@click="$emit('close')"
|
||||
/>
|
||||
<button class="modal-close is-large" aria-label="close" @click="$emit('close')" />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -6,35 +6,25 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
{{ directory.path }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="directory.path" />
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.directory.add')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.directory.add-next')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.directory.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="modal-close is-large"
|
||||
aria-label="close"
|
||||
@click="$emit('close')"
|
||||
/>
|
||||
<button class="modal-close is-large" aria-label="close" @click="$emit('close')" />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -7,52 +7,40 @@
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
<a class="has-text-link" @click="open_genre">{{
|
||||
genre.name
|
||||
}}</a>
|
||||
<a class="has-text-link" @click="open_genre" v-text="genre.name" />
|
||||
</p>
|
||||
<div class="content is-small">
|
||||
<p>
|
||||
<span class="heading">Albums</span>
|
||||
<span class="title is-6">{{ genre.album_count }}</span>
|
||||
<span class="heading" v-text="$t('dialog.genre.albums')" />
|
||||
<span class="title is-6" v-text="genre.album_count" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Tracks</span>
|
||||
<span class="title is-6">{{ genre.track_count }}</span>
|
||||
<span class="heading" v-text="$t('dialog.genre.tracks')" />
|
||||
<span class="title is-6" v-text="genre.track_count" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Length</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.durationInHours(genre.length_ms)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.genre.duration')" />
|
||||
<span class="title is-6" v-text="$filters.durationInHours(genre.length_ms)" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.genre.add')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.genre.add-next')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.genre.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="modal-close is-large"
|
||||
aria-label="close"
|
||||
@click="$emit('close')"
|
||||
/>
|
||||
<button class="modal-close is-large" aria-label="close" @click="$emit('close')" />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -7,50 +7,40 @@
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
<a class="has-text-link" @click="open_playlist">{{
|
||||
playlist.name
|
||||
}}</a>
|
||||
<a class="has-text-link" @click="open_playlist" v-text="playlist.name" />
|
||||
</p>
|
||||
<div class="content is-small">
|
||||
<p>
|
||||
<span class="heading">Path</span>
|
||||
<span class="title is-6">{{ playlist.path }}</span>
|
||||
<span class="title is-6" v-text="playlist.path" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Type</span>
|
||||
<span class="title is-6">{{ playlist.type }}</span>
|
||||
<span class="heading" v-text="$t('dialog.playlist.type')" />
|
||||
<span class="title is-6" v-text="playlist.type" />
|
||||
</p>
|
||||
<p v-if="!playlist.folder">
|
||||
<span class="heading">Track count</span>
|
||||
<span class="title is-6">{{ playlist.item_count }}</span>
|
||||
<span class="heading" v-text="$t('dialog.playlist.track-count')" />
|
||||
<span class="title is-6" v-text="playlist.item_count" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer v-if="!playlist.folder" class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.playlist.add')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.playlist.add-next')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.playlist.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="modal-close is-large"
|
||||
aria-label="close"
|
||||
@click="$emit('close')"
|
||||
/>
|
||||
<button class="modal-close is-large" aria-label="close" @click="$emit('close')" />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -6,56 +6,35 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">Save queue to playlist</p>
|
||||
<p class="title is-4" v-text="$t('dialog.playlist.save.title')" />
|
||||
<form class="fd-has-margin-bottom" @submit.prevent="save">
|
||||
<div class="field">
|
||||
<p class="control is-expanded has-icons-left">
|
||||
<input
|
||||
ref="playlist_name_field"
|
||||
v-model="playlist_name"
|
||||
class="input is-shadowless"
|
||||
type="text"
|
||||
placeholder="Playlist name"
|
||||
:disabled="loading"
|
||||
/>
|
||||
<span class="icon is-left">
|
||||
<mdicon name="file-music" size="16" />
|
||||
</span>
|
||||
<input ref="playlist_name_field" v-model="playlist_name" class="input is-shadowless" type="text" placeholder="Playlist name" :disabled="loading" />
|
||||
<mdicon class="icon is-left" name="file-music" size="16" />
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<footer v-if="loading" class="card-footer">
|
||||
<a class="card-footer-item has-text-dark">
|
||||
<span class="icon"><mdicon name="web" size="16" /></span>
|
||||
<span class="is-size-7">Saving ...</span>
|
||||
<mdicon class="icon" name="web" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.playlist.save.saving')" />
|
||||
</a>
|
||||
</footer>
|
||||
<footer v-else class="card-footer">
|
||||
<a
|
||||
class="card-footer-item has-text-danger"
|
||||
@click="$emit('close')"
|
||||
>
|
||||
<span class="icon"><mdicon name="cancel" size="16" /></span>
|
||||
<span class="is-size-7">Cancel</span>
|
||||
<a class="card-footer-item has-text-danger" @click="$emit('close')">
|
||||
<mdicon class="icon" name="cancel" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.playlist.save.cancel')" />
|
||||
</a>
|
||||
<a
|
||||
class="card-footer-item has-background-info has-text-white has-text-weight-bold"
|
||||
@click="save"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon name="content-save" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Save</span>
|
||||
<a class="card-footer-item has-background-info has-text-white has-text-weight-bold" @click="save">
|
||||
<mdicon class="icon" name="content-save" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.playlist.save.save')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="modal-close is-large"
|
||||
aria-label="close"
|
||||
@click="$emit('close')"
|
||||
/>
|
||||
<button class="modal-close is-large" aria-label="close" @click="$emit('close')" />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -6,107 +6,77 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
{{ item.title }}
|
||||
</p>
|
||||
<p class="subtitle">
|
||||
{{ item.artist }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="item.title" />
|
||||
<p class="subtitle" v-text="item.artist" />
|
||||
<div class="content is-small">
|
||||
<p>
|
||||
<span class="heading">Album</span>
|
||||
<a
|
||||
v-if="item.album_id"
|
||||
class="title is-6 has-text-link"
|
||||
@click="open_album"
|
||||
>{{ item.album }}</a
|
||||
>
|
||||
<span v-else class="title is-6">{{ item.album }}</span>
|
||||
<span class="heading" v-text="$t('dialog.queue-item.album')" />
|
||||
<a v-if="item.album_id" class="title is-6 has-text-link" @click="open_album" v-text="item.album" />
|
||||
<span v-else class="title is-6" v-text="item.album" />
|
||||
</p>
|
||||
<p v-if="item.album_artist">
|
||||
<span class="heading">Album artist</span>
|
||||
<a
|
||||
v-if="item.album_artist_id"
|
||||
class="title is-6 has-text-link"
|
||||
@click="open_album_artist"
|
||||
>{{ item.album_artist }}</a
|
||||
>
|
||||
<span v-else class="title is-6">{{ item.album_artist }}</span>
|
||||
<span class="heading" v-text="$t('dialog.queue-item.album-artist')" />
|
||||
<a v-if="item.album_artist_id" class="title is-6 has-text-link" @click="open_album_artist" v-text="item.album_artist" />
|
||||
<span v-else class="title is-6" v-text="item.album_artist" />
|
||||
</p>
|
||||
<p v-if="item.composer">
|
||||
<span class="heading">Composer</span>
|
||||
<span class="title is-6">{{ item.composer }}</span>
|
||||
<span class="heading" v-text="$t('dialog.queue-item.composer')" />
|
||||
<span class="title is-6" v-text="item.composer" />
|
||||
</p>
|
||||
<p v-if="item.year > 0">
|
||||
<span class="heading">Year</span>
|
||||
<span class="title is-6">{{ item.year }}</span>
|
||||
<span class="heading" v-text="$t('dialog.queue-item.year')" />
|
||||
<span class="title is-6" v-text="item.year" />
|
||||
</p>
|
||||
<p v-if="item.genre">
|
||||
<span class="heading">Genre</span>
|
||||
<a class="title is-6 has-text-link" @click="open_genre">{{
|
||||
item.genre
|
||||
}}</a>
|
||||
<span class="heading" v-text="$t('dialog.queue-item.genre')" />
|
||||
<a class="title is-6 has-text-link" @click="open_genre" v-text="item.genre" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Track / Disc</span>
|
||||
<span class="title is-6"
|
||||
>{{ item.track_number }} / {{ item.disc_number }}</span
|
||||
>
|
||||
<span class="heading" v-text="$t('dialog.queue-item.position')" />
|
||||
<span class="title is-6" v-text="[ item.disc_number, item.track_number ].join(' / ')" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Length</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.durationInHours(item.length_ms)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.queue-item.duration')" />
|
||||
<span class="title is-6" v-text="$filters.durationInHours(item.length_ms)" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Path</span>
|
||||
<span class="title is-6">{{ item.path }}</span>
|
||||
<span class="heading" v-text="$t('dialog.queue-item.path')" />
|
||||
<span class="title is-6" v-text="item.path" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Type</span>
|
||||
<span class="title is-6"
|
||||
>{{ item.media_kind }} - {{ item.data_kind }}
|
||||
<span
|
||||
v-if="item.data_kind === 'spotify'"
|
||||
class="has-text-weight-normal"
|
||||
>(<a @click="open_spotify_artist">artist</a>,
|
||||
<a @click="open_spotify_album">album</a>)</span
|
||||
></span
|
||||
>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Quality</span>
|
||||
<span class="heading" v-text="$t('dialog.queue-item.type')" />
|
||||
<span class="title is-6">
|
||||
{{ item.type }}
|
||||
<span v-if="item.samplerate">
|
||||
| {{ item.samplerate }} Hz</span
|
||||
>
|
||||
<span v-if="item.channels">
|
||||
| {{ $filters.channels(item.channels) }}</span
|
||||
>
|
||||
<span v-if="item.bitrate"> | {{ item.bitrate }} Kb/s</span>
|
||||
<span v-text="[item.media_kind, item.data_kind].join(' - ')" />
|
||||
<span v-if="item.data_kind === 'spotify'" class="has-text-weight-normal">
|
||||
(<a @click="open_spotify_artist" v-text="$t('dialog.queue-item.spotify-artist')" />,
|
||||
<a @click="open_spotify_album" v-text="$t('dialog.queue-item.spotify-album')" />)
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading" v-text="$t('dialog.queue-item.quality')" />
|
||||
<span class="title is-6">
|
||||
<span v-text="item.type" />
|
||||
<span v-if="item.samplerate" v-text="$t('dialog.queue-item.samplerate', { rate: item.samplerate })" />
|
||||
<span v-if="item.channels" v-text="$t('dialog.queue-item.channels', { channels: $filters.channels(item.channels) })" />
|
||||
<span v-if="item.bitrate" v-text="$t('dialog.queue-item.bitrate', { rate: item.bitrate })" />
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="remove">
|
||||
<span class="icon"><mdicon name="delete" size="16" /></span>
|
||||
<span class="is-size-7">Remove</span>
|
||||
<mdicon class="icon" name="delete" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.queue-item.remove')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.queue-item.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="modal-close is-large"
|
||||
aria-label="close"
|
||||
@click="$emit('close')"
|
||||
/>
|
||||
<button class="modal-close is-large" aria-label="close" @click="$emit('close')" />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -6,47 +6,29 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">Remote pairing request</p>
|
||||
<p class="title is-4" v-text="$t('dialog.remote-pairing.title')" />
|
||||
<form @submit.prevent="kickoff_pairing">
|
||||
<label class="label">
|
||||
{{ pairing.remote }}
|
||||
</label>
|
||||
<label class="label" v-text="pairing.remote" />
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input
|
||||
ref="pin_field"
|
||||
v-model="pairing_req.pin"
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder="Enter pairing code"
|
||||
/>
|
||||
<input ref="pin_field" v-model="pairing_req.pin" class="input" type="text" placeholder="Enter pairing code" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a
|
||||
class="card-footer-item has-text-danger"
|
||||
@click="$emit('close')"
|
||||
>
|
||||
<span class="icon"><mdicon name="cancel" size="16" /></span>
|
||||
<span class="is-size-7">Cancel</span>
|
||||
<a class="card-footer-item has-text-danger" @click="$emit('close')">
|
||||
<mdicon class="icon" name="cancel" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.remote-pairing.cancel')" />
|
||||
</a>
|
||||
<a
|
||||
class="card-footer-item has-background-info has-text-white has-text-weight-bold"
|
||||
@click="kickoff_pairing"
|
||||
>
|
||||
<span class="icon"><mdicon name="cellphone" size="16" /></span>
|
||||
<span class="is-size-7">Pair Remote</span>
|
||||
<a class="card-footer-item has-background-info has-text-white has-text-weight-bold" @click="kickoff_pairing">
|
||||
<mdicon class="icon" name="cellphone" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.remote-pairing.pair')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="modal-close is-large"
|
||||
aria-label="close"
|
||||
@click="$emit('close')"
|
||||
/>
|
||||
<button class="modal-close is-large" aria-label="close" @click="$emit('close')" />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -6,147 +6,99 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
{{ track.title }}
|
||||
</p>
|
||||
<p class="subtitle">
|
||||
{{ track.artist }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="track.title" />
|
||||
<p class="subtitle" v-text="track.artist" />
|
||||
<div v-if="track.media_kind === 'podcast'" class="buttons">
|
||||
<a
|
||||
v-if="track.play_count > 0"
|
||||
class="button is-small"
|
||||
@click="mark_new"
|
||||
>Mark as new</a
|
||||
>
|
||||
<a
|
||||
v-if="track.play_count === 0"
|
||||
class="button is-small"
|
||||
@click="mark_played"
|
||||
>Mark as played</a
|
||||
>
|
||||
<a v-if="track.play_count > 0" class="button is-small" @click="mark_new" v-text="$t('dialog.track.mark-as-new')" />
|
||||
<a v-if="track.play_count === 0" class="button is-small" @click="mark_played" v-text="$t('dialog.track.mark-as-played')" />
|
||||
</div>
|
||||
<div class="content is-small">
|
||||
<p>
|
||||
<span class="heading">Album</span>
|
||||
<a class="title is-6 has-text-link" @click="open_album">{{
|
||||
track.album
|
||||
}}</a>
|
||||
<span class="heading" v-text="$t('dialog.track.album')" />
|
||||
<a class="title is-6 has-text-link" @click="open_album" v-text="track.album" />
|
||||
</p>
|
||||
<p
|
||||
v-if="track.album_artist && track.media_kind !== 'audiobook'"
|
||||
>
|
||||
<span class="heading">Album artist</span>
|
||||
<a class="title is-6 has-text-link" @click="open_artist">{{
|
||||
track.album_artist
|
||||
}}</a>
|
||||
<p v-if="track.album_artist && track.media_kind !== 'audiobook'">
|
||||
<span class="heading" v-text="$t('dialog.track.album-artist')" />
|
||||
<a class="title is-6 has-text-link" @click="open_artist" v-text="track.album_artist" />
|
||||
</p>
|
||||
<p v-if="track.composer">
|
||||
<span class="heading">Composer</span>
|
||||
<span class="title is-6">{{ track.composer }}</span>
|
||||
<span class="heading" v-text="$t('dialog.track.composer')" />
|
||||
<span class="title is-6" v-text="track.composer" />
|
||||
</p>
|
||||
<p v-if="track.date_released">
|
||||
<span class="heading">Release date</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.date(track.date_released)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.track.release-date')" />
|
||||
<span class="title is-6" v-text="$filters.date(track.date_released)" />
|
||||
</p>
|
||||
<p v-else-if="track.year > 0">
|
||||
<span class="heading">Year</span>
|
||||
<span class="title is-6">{{ track.year }}</span>
|
||||
<span class="heading" v-text="$t('dialog.track.year')" />
|
||||
<span class="title is-6" v-text="track.year" />
|
||||
</p>
|
||||
<p v-if="track.genre">
|
||||
<span class="heading">Genre</span>
|
||||
<a class="title is-6 has-text-link" @click="open_genre">{{
|
||||
track.genre
|
||||
}}</a>
|
||||
<span class="heading" v-text="$t('dialog.track.genre')" />
|
||||
<a class="title is-6 has-text-link" @click="open_genre" v-text="track.genre" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Track / Disc</span>
|
||||
<span class="title is-6"
|
||||
>{{ track.track_number }} / {{ track.disc_number }}</span
|
||||
>
|
||||
<span class="heading" v-text="$t('dialog.track.position')" />
|
||||
<span class="title is-6" v-text="[track.disc_number, track.track_number].join(' / ')" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Length</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.durationInHours(track.length_ms)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.track.duration')" />
|
||||
<span class="title is-6" v-text="$filters.durationInHours(track.length_ms)" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Path</span>
|
||||
<span class="title is-6">{{ track.path }}</span>
|
||||
<span class="heading" v-text="$t('dialog.track.path')" />
|
||||
<span class="title is-6" v-text="track.path" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Type</span>
|
||||
<span class="title is-6"
|
||||
>{{ track.media_kind }} - {{ track.data_kind }}
|
||||
<span
|
||||
v-if="track.data_kind === 'spotify'"
|
||||
class="has-text-weight-normal"
|
||||
>(<a @click="open_spotify_artist">artist</a>,
|
||||
<a @click="open_spotify_album">album</a>)</span
|
||||
></span
|
||||
>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Quality</span>
|
||||
<span class="heading" v-text="$t('dialog.track.type')" />
|
||||
<span class="title is-6">
|
||||
{{ track.type }}
|
||||
<span v-if="track.samplerate">
|
||||
| {{ track.samplerate }} Hz</span
|
||||
>
|
||||
<span v-if="track.channels">
|
||||
| {{ $filters.channels(track.channels) }}</span
|
||||
>
|
||||
<span v-if="track.bitrate">
|
||||
| {{ track.bitrate }} Kb/s</span
|
||||
>
|
||||
<span v-text="[track.media_kind, track.data_kind].join(' - ')" />
|
||||
<span v-if="track.data_kind === 'spotify'" class="has-text-weight-normal">
|
||||
(<a @click="open_spotify_artist" v-text="$t('dialog.track.spotify-artist')" />,
|
||||
<a @click="open_spotify_album" v-text="$t('dialog.track.spotify-album')" />)
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Added at</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.datetime(track.time_added)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.track.quality')" />
|
||||
<span class="title is-6">
|
||||
<span v-text="track.type" />
|
||||
<span v-if="track.samplerate" v-text="$t('dialog.track.samplerate', { rate: track.samplerate })" />
|
||||
<span v-if="track.channels" v-text="$t('dialog.track.channels', { channels: $filters.channels(track.channels) })" />
|
||||
<span v-if="track.bitrate" v-text="$t('dialog.track.bitrate', { rate: track.bitrate })" />
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Rating</span>
|
||||
<span class="title is-6"
|
||||
>{{ Math.floor(track.rating / 10) }} / 10</span
|
||||
>
|
||||
<span class="heading" v-text="$t('dialog.track.added-on')" />
|
||||
<span class="title is-6" v-text="$filters.datetime(track.time_added)" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading" v-text="$t('dialog.track.rating')" />
|
||||
<span class="title is-6" v-text="$t('dialog.track.rating-value', { rating: Math.floor(track.rating / 10) })" />
|
||||
</p>
|
||||
<p v-if="track.comment">
|
||||
<span class="heading">Comment</span>
|
||||
<span class="title is-6">{{ track.comment }}</span>
|
||||
<span class="heading" v-text="$t('dialog.track.comment')" />
|
||||
<span class="title is-6" v-text="track.comment" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.track.add')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.track.add-next')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play_track">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.track.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="modal-close is-large"
|
||||
aria-label="close"
|
||||
@click="$emit('close')"
|
||||
/>
|
||||
<button class="modal-close is-large" aria-label="close" @click="$emit('close')" />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -1,40 +1,29 @@
|
||||
<template>
|
||||
<modal-dialog
|
||||
:show="show"
|
||||
title="Update library"
|
||||
:ok_action="library.updating ? '' : 'Rescan'"
|
||||
close_action="Close"
|
||||
@ok="update_library"
|
||||
@close="close()"
|
||||
>
|
||||
<modal-dialog :show="show" :title="$t('dialog.update.title')" :ok_action="library.updating ? '' : $t('dialog.update.rescan')" :close_action="$t('dialog.update.cancel')" @ok="update_library" @close="close()">
|
||||
<template #modal-content>
|
||||
<div v-if="!library.updating">
|
||||
<p class="mb-3">Scan for new, deleted and modified files</p>
|
||||
<p class="mb-3" v-text="$t('dialog.update.info')" />
|
||||
<div v-if="spotify_enabled || rss.tracks > 0" class="field">
|
||||
<div class="control">
|
||||
<div class="select is-small">
|
||||
<select v-model="update_dialog_scan_kind">
|
||||
<option value="">Update everything</option>
|
||||
<option value="files">Only update local library</option>
|
||||
<option v-if="spotify_enabled" value="spotify">
|
||||
Only update Spotify
|
||||
</option>
|
||||
<option v-if="rss.tracks > 0" value="rss">
|
||||
Only update RSS feeds
|
||||
</option>
|
||||
<option value="" v-text="$t('dialog.update.all')" />
|
||||
<option value="files" v-text="$t('dialog.update.local')" />
|
||||
<option v-if="spotify_enabled" value="spotify" v-text="$t('dialog.update.spotify')" />
|
||||
<option v-if="rss.tracks > 0" value="rss" v-text="$t('dialog.update.feeds')" />
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="checkbox is-size-7 is-small">
|
||||
<input v-model="rescan_metadata" type="checkbox" />
|
||||
Rescan metadata for unmodified files
|
||||
<input v-model="rescan_metadata" type="checkbox" style="margin-right: 5px" />
|
||||
<span v-text="$t('dialog.update.rescan-metadata')" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p class="mb-3">Library update in progress ...</p>
|
||||
<p class="mb-3" v-text="$t('dialog.update.progress')" />
|
||||
</div>
|
||||
</template>
|
||||
</modal-dialog>
|
||||
|
@ -1,208 +1,86 @@
|
||||
<template>
|
||||
<nav
|
||||
class="fd-bottom-navbar navbar is-white is-fixed-bottom"
|
||||
:style="zindex"
|
||||
:class="{
|
||||
'is-transparent': is_now_playing_page,
|
||||
'is-dark': !is_now_playing_page
|
||||
}"
|
||||
role="navigation"
|
||||
aria-label="player controls"
|
||||
>
|
||||
<nav class="fd-bottom-navbar navbar is-white is-fixed-bottom" :style="zindex" :class="{ 'is-transparent': is_now_playing_page, 'is-dark': !is_now_playing_page }" role="navigation" aria-label="player controls">
|
||||
<div class="navbar-brand fd-expanded">
|
||||
<!-- Link to queue -->
|
||||
<navbar-item-link to="/" exact>
|
||||
<span class="icon"><mdicon name="playlist-play" size="24" /></span>
|
||||
<mdicon class="icon" name="playlist-play" size="24" />
|
||||
</navbar-item-link>
|
||||
|
||||
<!-- Now playing artist/title (not visible on "now playing" page) -->
|
||||
<router-link
|
||||
v-if="!is_now_playing_page"
|
||||
to="/now-playing"
|
||||
class="navbar-item is-expanded is-clipped"
|
||||
active-class="is-active"
|
||||
exact
|
||||
>
|
||||
<router-link v-if="!is_now_playing_page" to="/now-playing" class="navbar-item is-expanded is-clipped" active-class="is-active" exact>
|
||||
<div class="is-clipped">
|
||||
<p class="is-size-7 fd-is-text-clipped">
|
||||
<strong>{{ now_playing.title }}</strong
|
||||
><br />
|
||||
{{ now_playing.artist
|
||||
}}<span v-if="now_playing.data_kind === 'url'">
|
||||
- {{ now_playing.album }}</span
|
||||
>
|
||||
<strong v-text="now_playing.title" />
|
||||
<br />
|
||||
<span v-text="now_playing.artist" />
|
||||
<span v-if="now_playing.data_kind === 'url'" v-text="$t('navigation.now-playing', { album: now_playing.album })" />
|
||||
</p>
|
||||
</div>
|
||||
</router-link>
|
||||
|
||||
<!-- Skip previous (not visible on "now playing" page) -->
|
||||
<player-button-previous
|
||||
v-if="is_now_playing_page"
|
||||
class="navbar-item fd-margin-left-auto"
|
||||
:icon_size="24"
|
||||
/>
|
||||
<player-button-seek-back
|
||||
v-if="is_now_playing_page"
|
||||
:seek_ms="10000"
|
||||
class="navbar-item"
|
||||
:icon_size="24"
|
||||
/>
|
||||
<player-button-previous v-if="is_now_playing_page" class="navbar-item fd-margin-left-auto" :icon_size="24" />
|
||||
<player-button-seek-back v-if="is_now_playing_page" :seek_ms="10000" class="navbar-item" :icon_size="24" />
|
||||
<!-- Play/pause -->
|
||||
<player-button-play-pause
|
||||
class="navbar-item"
|
||||
:icon_size="36"
|
||||
show_disabled_message
|
||||
/>
|
||||
<player-button-seek-forward
|
||||
v-if="is_now_playing_page"
|
||||
:seek_ms="30000"
|
||||
class="navbar-item"
|
||||
:icon_size="24"
|
||||
/>
|
||||
<player-button-play-pause class="navbar-item" :icon_size="36" show_disabled_message />
|
||||
<player-button-seek-forward v-if="is_now_playing_page" :seek_ms="30000" class="navbar-item" :icon_size="24" />
|
||||
<!-- Skip next (not visible on "now playing" page) -->
|
||||
<player-button-next
|
||||
v-if="is_now_playing_page"
|
||||
class="navbar-item"
|
||||
:icon_size="24"
|
||||
/>
|
||||
|
||||
<player-button-next v-if="is_now_playing_page" class="navbar-item" :icon_size="24" />
|
||||
<!-- Player menu button (only visible on mobile and tablet) -->
|
||||
<a
|
||||
class="navbar-item fd-margin-left-auto is-hidden-desktop"
|
||||
@click="show_player_menu = !show_player_menu"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon
|
||||
:name="show_player_menu ? 'chevron-down' : 'chevron-up'"
|
||||
size="18"
|
||||
/></span>
|
||||
<a class="navbar-item fd-margin-left-auto is-hidden-desktop" @click="show_player_menu = !show_player_menu">
|
||||
<mdicon class="icon" :name="show_player_menu ? 'chevron-down' : 'chevron-up'" size="18" />
|
||||
</a>
|
||||
|
||||
<!-- Player menu dropup menu (only visible on desktop) -->
|
||||
<div
|
||||
class="navbar-item has-dropdown has-dropdown-up fd-margin-left-auto is-hidden-touch"
|
||||
:class="{ 'is-active': show_player_menu }"
|
||||
>
|
||||
<a
|
||||
class="navbar-link is-arrowless"
|
||||
@click="show_player_menu = !show_player_menu"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon
|
||||
:name="show_player_menu ? 'chevron-down' : 'chevron-up'"
|
||||
size="18"
|
||||
/></span>
|
||||
<div class="navbar-item has-dropdown has-dropdown-up fd-margin-left-auto is-hidden-touch" :class="{ 'is-active': show_player_menu }">
|
||||
<a class="navbar-link is-arrowless" @click="show_player_menu = !show_player_menu">
|
||||
<mdicon class="icon" :name="show_player_menu ? 'chevron-down' : 'chevron-up'" size="18" />
|
||||
</a>
|
||||
|
||||
<div
|
||||
class="navbar-dropdown is-right is-boxed"
|
||||
style="margin-right: 6px; margin-bottom: 6px; border-radius: 6px"
|
||||
>
|
||||
<div class="navbar-dropdown is-right is-boxed" style="margin-right: 6px; margin-bottom: 6px; border-radius: 6px">
|
||||
<div class="navbar-item">
|
||||
<!-- Outputs: master volume -->
|
||||
<div class="level is-mobile">
|
||||
<div class="level-left fd-expanded">
|
||||
<div class="level-item" style="flex-grow: 0">
|
||||
<a
|
||||
class="button is-white is-small"
|
||||
@click="toggle_mute_volume"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon
|
||||
:name="player.volume > 0 ? 'volume-high' : 'volume-off'"
|
||||
size="18"
|
||||
/></span>
|
||||
<a class="button is-white is-small" @click="toggle_mute_volume">
|
||||
<mdicon class="icon" :name="player.volume > 0 ? 'volume-high' : 'volume-off'" size="18" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="level-item fd-expanded">
|
||||
<div class="fd-expanded">
|
||||
<p class="heading">Volume</p>
|
||||
<Slider
|
||||
v-model="player.volume"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:step="1"
|
||||
:tooltips="false"
|
||||
:classes="{ target: 'slider' }"
|
||||
@change="set_volume"
|
||||
/>
|
||||
<!--range-slider
|
||||
class="slider fd-has-action"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
:value="player.volume"
|
||||
@change="set_volume">
|
||||
</range-slider-->
|
||||
<p class="heading" v-text="$t('navigation.volume')" />
|
||||
<Slider v-model="player.volume" :min="0" :max="100" :step="1" :tooltips="false" :classes="{ target: 'slider' }" @change="set_volume" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Outputs: master volume -->
|
||||
<hr class="fd-navbar-divider" />
|
||||
<navbar-item-output
|
||||
v-for="output in outputs"
|
||||
:key="output.id"
|
||||
:output="output"
|
||||
/>
|
||||
|
||||
<navbar-item-output v-for="output in outputs" :key="output.id" :output="output" />
|
||||
<!-- Outputs: stream volume -->
|
||||
<hr class="fd-navbar-divider" />
|
||||
<div class="navbar-item">
|
||||
<div class="level is-mobile">
|
||||
<div class="level-left fd-expanded">
|
||||
<div class="level-item" style="flex-grow: 0">
|
||||
<a
|
||||
class="button is-white is-small"
|
||||
:class="{ 'is-loading': loading }"
|
||||
><span
|
||||
class="icon fd-has-action"
|
||||
:class="{
|
||||
'has-text-grey-light': !playing && !loading,
|
||||
'is-loading': loading
|
||||
}"
|
||||
@click="togglePlay"
|
||||
><mdicon name="radio-tower" size="18" /></span
|
||||
></a>
|
||||
<a class="button is-white is-small" :class="{ 'is-loading': loading }">
|
||||
<span class="icon fd-has-action" :class="{ 'has-text-grey-light': !playing && !loading, 'is-loading': loading }" @click="togglePlay">
|
||||
<mdicon name="broadcast" size="18" />
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="level-item fd-expanded">
|
||||
<div class="fd-expanded">
|
||||
<p
|
||||
class="heading"
|
||||
:class="{ 'has-text-grey-light': !playing }"
|
||||
>
|
||||
HTTP stream
|
||||
<a href="stream.mp3"
|
||||
><span class="is-lowercase">(stream.mp3)</span></a
|
||||
>
|
||||
<p class="heading" :class="{ 'has-text-grey-light': !playing }">
|
||||
<span v-text="$t('navigation.stream')" />
|
||||
<a href="stream.mp3" style="margin-left: 5px" target="_blank">
|
||||
<mdicon class="icon" name="open-in-new" size="16" style="vertical-align: middle" />
|
||||
</a>
|
||||
</p>
|
||||
<Slider
|
||||
v-model="stream_volume"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:step="1"
|
||||
:tooltips="false"
|
||||
:disabled="!playing"
|
||||
:classes="{ target: 'slider' }"
|
||||
@change="set_stream_volume"
|
||||
/>
|
||||
<!--range-slider
|
||||
class="slider fd-has-action"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
:disabled="!playing"
|
||||
:value="stream_volume"
|
||||
@change="set_stream_volume">
|
||||
</range-slider-->
|
||||
<Slider v-model="stream_volume" :min="0" :max="100" :step="1" :tooltips="false" :disabled="!playing" :classes="{ target: 'slider' }" @change="set_stream_volume" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Playback controls -->
|
||||
<hr class="fd-navbar-divider" />
|
||||
<div class="navbar-item">
|
||||
@ -219,12 +97,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Player menu (only visible on mobile and tablet) -->
|
||||
<div
|
||||
class="navbar-menu is-hidden-desktop"
|
||||
:class="{ 'is-active': show_player_menu }"
|
||||
>
|
||||
<div class="navbar-menu is-hidden-desktop" :class="{ 'is-active': show_player_menu }">
|
||||
<div class="navbar-start" />
|
||||
<div class="navbar-end">
|
||||
<!-- Repeat/shuffle/consume -->
|
||||
@ -235,106 +109,48 @@
|
||||
<player-button-consume class="button" :icon_size="18" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="fd-navbar-divider" />
|
||||
|
||||
<!-- Outputs: master volume -->
|
||||
<div class="navbar-item">
|
||||
<div class="level is-mobile">
|
||||
<div class="level-left fd-expanded">
|
||||
<div class="level-item" style="flex-grow: 0">
|
||||
<a class="button is-white is-small" @click="toggle_mute_volume">
|
||||
<span class="icon"
|
||||
><mdicon
|
||||
:name="player.volume > 0 ? 'volume-high' : 'volume-off'"
|
||||
size="18"
|
||||
/></span>
|
||||
<mdicon class="icon" :name="player.volume > 0 ? 'volume-high' : 'volume-off'" size="18" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="level-item fd-expanded">
|
||||
<div class="fd-expanded">
|
||||
<p class="heading">Volume</p>
|
||||
<Slider
|
||||
v-model="player.volume"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:step="1"
|
||||
:tooltips="false"
|
||||
:classes="{ target: 'slider' }"
|
||||
@change="set_volume"
|
||||
/>
|
||||
<!--range-slider
|
||||
class="slider fd-has-action"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
:value="player.volume"
|
||||
@change="set_volume">
|
||||
</range-slider-->
|
||||
<p class="heading" v-text="$t('navigation.volume')" />
|
||||
<Slider v-model="player.volume" :min="0" :max="100" :step="1" :tooltips="false" :classes="{ target: 'slider' }" @change="set_volume" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Outputs: speaker volumes -->
|
||||
<navbar-item-output
|
||||
v-for="output in outputs"
|
||||
:key="output.id"
|
||||
:output="output"
|
||||
/>
|
||||
|
||||
<navbar-item-output v-for="output in outputs" :key="output.id" :output="output" />
|
||||
<!-- Outputs: stream volume -->
|
||||
<hr class="fd-navbar-divider" />
|
||||
<div class="navbar-item fd-has-margin-bottom">
|
||||
<div class="level is-mobile">
|
||||
<div class="level-left fd-expanded">
|
||||
<div class="level-item" style="flex-grow: 0">
|
||||
<a
|
||||
class="button is-white is-small"
|
||||
:class="{ 'is-loading': loading }"
|
||||
>
|
||||
<span
|
||||
class="icon fd-has-action"
|
||||
:class="{
|
||||
'has-text-grey-light': !playing && !loading,
|
||||
'is-loading': loading
|
||||
}"
|
||||
@click="togglePlay"
|
||||
><mdicon name="radio-tower" size="16" />
|
||||
<a class="button is-white is-small" :class="{ 'is-loading': loading }">
|
||||
<span class="icon fd-has-action" :class="{ 'has-text-grey-light': !playing && !loading, 'is-loading': loading }" @click="togglePlay">
|
||||
<mdicon name="broadcast" size="16" />
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="level-item fd-expanded">
|
||||
<div class="fd-expanded">
|
||||
<p
|
||||
class="heading"
|
||||
:class="{ 'has-text-grey-light': !playing }"
|
||||
>
|
||||
HTTP stream
|
||||
<a href="stream.mp3"
|
||||
><span class="is-lowercase">(stream.mp3)</span></a
|
||||
>
|
||||
<p class="heading" :class="{ 'has-text-grey-light': !playing }">
|
||||
<span v-text="$t('navigation.stream')" />
|
||||
<a href="stream.mp3" style="margin-left: 5px" target="_blank">
|
||||
<mdicon class="icon" name="open-in-new" size="16" style="vertical-align: middle" />
|
||||
</a>
|
||||
</p>
|
||||
<Slider
|
||||
v-model="stream_volume"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:step="1"
|
||||
:tooltips="false"
|
||||
:disabled="!playing"
|
||||
:classes="{ target: 'slider' }"
|
||||
@change="set_stream_volume"
|
||||
/>
|
||||
<!-- range-slider
|
||||
class="slider fd-has-action"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
:disabled="!playing"
|
||||
:value="stream_volume"
|
||||
@change="set_stream_volume">
|
||||
</range-slider-->
|
||||
<Slider v-model="stream_volume" :min="0" :max="100" :step="1" :tooltips="false" :disabled="!playing" :classes="{ target: 'slider' }" @change="set_stream_volume" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -358,7 +174,6 @@ import PlayerButtonConsume from '@/components/PlayerButtonConsume.vue'
|
||||
import PlayerButtonRepeat from '@/components/PlayerButtonRepeat.vue'
|
||||
import PlayerButtonSeekBack from '@/components/PlayerButtonSeekBack.vue'
|
||||
import PlayerButtonSeekForward from '@/components/PlayerButtonSeekForward.vue'
|
||||
//import RangeSlider from 'vue-range-slider'
|
||||
import Slider from '@vueform/slider'
|
||||
import * as types from '@/store/mutation_types'
|
||||
|
||||
@ -367,7 +182,6 @@ export default {
|
||||
components: {
|
||||
NavbarItemLink,
|
||||
NavbarItemOutput,
|
||||
//RangeSlider,
|
||||
Slider,
|
||||
PlayerButtonPlayPause,
|
||||
PlayerButtonNext,
|
||||
@ -382,11 +196,9 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
old_volume: 0,
|
||||
|
||||
playing: false,
|
||||
loading: false,
|
||||
stream_volume: 10,
|
||||
|
||||
show_outputs_menu: false,
|
||||
show_desktop_outputs_menu: false
|
||||
}
|
||||
@ -488,7 +300,7 @@ export default {
|
||||
a.addEventListener('error', (e) => {
|
||||
this.closeAudio()
|
||||
this.$store.dispatch('add_notification', {
|
||||
text: 'HTTP stream error: failed to load stream or stopped loading due to network problem',
|
||||
text: this.$t('navigation.stream-error'),
|
||||
type: 'danger'
|
||||
})
|
||||
this.playing = false
|
||||
|
@ -1,10 +1,5 @@
|
||||
<template>
|
||||
<a
|
||||
class="navbar-item"
|
||||
:class="{ 'is-active': is_active }"
|
||||
:href="full_path()"
|
||||
@click.stop.prevent="open_link()"
|
||||
>
|
||||
<a class="navbar-item" :class="{ 'is-active': is_active }" :href="full_path()" @click.stop.prevent="open_link()">
|
||||
<slot />
|
||||
</a>
|
||||
</template>
|
||||
|
@ -4,42 +4,15 @@
|
||||
<div class="level-left fd-expanded">
|
||||
<div class="level-item" style="flex-grow: 0">
|
||||
<a class="button is-white is-small">
|
||||
<span
|
||||
class="icon fd-has-action"
|
||||
:class="{ 'has-text-grey-light': !output.selected }"
|
||||
@click="set_enabled"
|
||||
>
|
||||
<span class="icon fd-has-action" :class="{ 'has-text-grey-light': !output.selected }" @click="set_enabled">
|
||||
<mdicon :name="type_class" size="18" :title="output.type" />
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="level-item fd-expanded">
|
||||
<div class="fd-expanded">
|
||||
<p
|
||||
class="heading"
|
||||
:class="{ 'has-text-grey-light': !output.selected }"
|
||||
>
|
||||
{{ output.name }}
|
||||
</p>
|
||||
<Slider
|
||||
v-model="volume"
|
||||
:min="0"
|
||||
:max="100"
|
||||
:step="1"
|
||||
:tooltips="false"
|
||||
:disabled="!output.selected"
|
||||
:classes="{ target: 'slider' }"
|
||||
@change="set_volume"
|
||||
/>
|
||||
<!--range-slider
|
||||
class="slider fd-has-action"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
:disabled="!output.selected"
|
||||
:value="volume"
|
||||
@change="set_volume" >
|
||||
</range-slider-->
|
||||
<p class="heading" :class="{ 'has-text-grey-light': !output.selected }" v-text="output.name" />
|
||||
<Slider v-model="volume" :min="0" :max="100" :step="1" :tooltips="false" :disabled="!output.selected" :classes="{ target: 'slider' }" @change="set_volume" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -48,14 +21,12 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
//import RangeSlider from 'vue-range-slider'
|
||||
import Slider from '@vueform/slider'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'NavbarItemOutput',
|
||||
components: {
|
||||
// RangeSlider
|
||||
Slider
|
||||
},
|
||||
|
||||
|
@ -1,131 +1,93 @@
|
||||
<template>
|
||||
<nav
|
||||
class="fd-top-navbar navbar is-light is-fixed-top"
|
||||
:style="zindex"
|
||||
role="navigation"
|
||||
aria-label="main navigation"
|
||||
>
|
||||
<nav class="fd-top-navbar navbar is-light is-fixed-top" :style="zindex" role="navigation" aria-label="main navigation">
|
||||
<div class="navbar-brand">
|
||||
<navbar-item-link v-if="is_visible_playlists" to="/playlists">
|
||||
<span class="icon"><mdicon name="music-box-multiple" size="16" /></span>
|
||||
<mdicon class="icon" name="music-box-multiple" size="16" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link v-if="is_visible_music" to="/music">
|
||||
<span class="icon"><mdicon name="music" size="16" /></span>
|
||||
<mdicon class="icon" name="music" size="16" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link v-if="is_visible_podcasts" to="/podcasts">
|
||||
<span class="icon"><mdicon name="microphone" size="16" /></span>
|
||||
<mdicon class="icon" name="podcast" size="16" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link v-if="is_visible_audiobooks" to="/audiobooks">
|
||||
<span class="icon"><mdicon name="book-open-variant" size="16" /></span>
|
||||
<mdicon class="icon" name="book-open-variant" size="16" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link v-if="is_visible_radio" to="/radio">
|
||||
<span class="icon"><mdicon name="radio" size="16" /></span>
|
||||
<mdicon class="icon" name="radio-tower" size="16" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link v-if="is_visible_files" to="/files">
|
||||
<span class="icon"><mdicon name="folder-open" size="16" /></span>
|
||||
<mdicon class="icon" name="folder-open" size="16" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link v-if="is_visible_search" to="/search">
|
||||
<span class="icon"><mdicon name="magnify" size="16" /></span>
|
||||
<mdicon class="icon" name="magnify" size="16" />
|
||||
</navbar-item-link>
|
||||
|
||||
<div
|
||||
class="navbar-burger"
|
||||
:class="{ 'is-active': show_burger_menu }"
|
||||
@click="show_burger_menu = !show_burger_menu"
|
||||
>
|
||||
<div class="navbar-burger" :class="{ 'is-active': show_burger_menu }" @click="show_burger_menu = !show_burger_menu">
|
||||
<span />
|
||||
<span />
|
||||
<span />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="navbar-menu" :class="{ 'is-active': show_burger_menu }">
|
||||
<div class="navbar-start" />
|
||||
|
||||
<div class="navbar-end">
|
||||
<!-- Burger menu entries -->
|
||||
<div
|
||||
class="navbar-item has-dropdown is-hoverable"
|
||||
:class="{ 'is-active': show_settings_menu }"
|
||||
@click="on_click_outside_settings"
|
||||
>
|
||||
<div class="navbar-item has-dropdown is-hoverable" :class="{ 'is-active': show_settings_menu }" @click="on_click_outside_settings">
|
||||
<a class="navbar-link is-arrowless">
|
||||
<span class="icon is-hidden-touch"
|
||||
><mdicon name="menu" size="24"
|
||||
/></span>
|
||||
<span class="is-hidden-desktop has-text-weight-bold">OwnTone</span>
|
||||
<mdicon class="icon is-hidden-touch" name="menu" size="24" />
|
||||
<span class="is-hidden-desktop has-text-weight-bold" v-text="$t('navigation.title')" />
|
||||
</a>
|
||||
|
||||
<div class="navbar-dropdown is-right">
|
||||
<navbar-item-link to="/playlists">
|
||||
<span class="icon"
|
||||
><mdicon name="music-box-multiple" size="16"
|
||||
/></span>
|
||||
<b>Playlists</b>
|
||||
<mdicon class="icon" name="music-box-multiple" size="16" />
|
||||
<b v-text="$t('navigation.playlists')" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link to="/music" exact>
|
||||
<span class="icon"><mdicon name="music" size="16" /></span>
|
||||
<b>Music</b>
|
||||
<mdicon class="icon" name="music" size="16" />
|
||||
<b v-text="$t('navigation.music')" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link to="/music/artists">
|
||||
<span class="fd-navbar-item-level2">Artists</span>
|
||||
<span class="fd-navbar-item-level2" v-text="$t('navigation.artists')" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link to="/music/albums">
|
||||
<span class="fd-navbar-item-level2">Albums</span>
|
||||
<span class="fd-navbar-item-level2" v-text="$t('navigation.albums')" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link to="/music/genres">
|
||||
<span class="fd-navbar-item-level2">Genres</span>
|
||||
<span class="fd-navbar-item-level2" v-text="$t('navigation.genres')" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link v-if="spotify_enabled" to="/music/spotify">
|
||||
<span class="fd-navbar-item-level2">Spotify</span>
|
||||
<span class="fd-navbar-item-level2" v-text="$t('navigation.spotify')" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link to="/podcasts">
|
||||
<span class="icon"><mdicon name="microphone" size="16" /></span>
|
||||
<b>Podcasts</b>
|
||||
<mdicon class="icon" name="podcast" size="16" />
|
||||
<b v-text="$t('navigation.podcasts')" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link to="/audiobooks">
|
||||
<span class="icon"
|
||||
><mdicon name="book-open-variant" size="16"
|
||||
/></span>
|
||||
<b>Audiobooks</b>
|
||||
<mdicon class="icon" name="book-open-variant" size="16" />
|
||||
<b v-text="$t('navigation.audiobooks')" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link to="/radio">
|
||||
<span class="icon"><mdicon name="radio" size="16" /></span>
|
||||
<b>Radio</b>
|
||||
<mdicon class="icon" name="radio-tower" size="16" />
|
||||
<b v-text="$t('navigation.radio')" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link to="/files">
|
||||
<span class="icon"><mdicon name="folder-open" size="16" /></span>
|
||||
<b>Files</b>
|
||||
<mdicon class="icon" name="folder-open" size="16" />
|
||||
<b v-text="$t('navigation.files')" />
|
||||
</navbar-item-link>
|
||||
<navbar-item-link to="/search">
|
||||
<span class="icon"><mdicon name="magnify" size="16" /></span>
|
||||
<b>Search</b>
|
||||
<mdicon class="icon" name="magnify" size="16" />
|
||||
<b v-text="$t('navigation.search')" />
|
||||
</navbar-item-link>
|
||||
<hr class="fd-navbar-divider" />
|
||||
|
||||
<navbar-item-link to="/settings/webinterface">
|
||||
Settings
|
||||
</navbar-item-link>
|
||||
<a class="navbar-item" @click.stop.prevent="open_update_dialog()">
|
||||
Update Library
|
||||
</a>
|
||||
<navbar-item-link to="/about"> About </navbar-item-link>
|
||||
|
||||
<div
|
||||
class="navbar-item is-hidden-desktop"
|
||||
style="margin-bottom: 2.5rem"
|
||||
/>
|
||||
<navbar-item-link to="/settings/webinterface" v-text="$t('navigation.settings')" />
|
||||
<a class="navbar-item" @click.stop.prevent="open_update_dialog()" v-text="$t('navigation.update-library')" />
|
||||
<navbar-item-link to="/about" v-text="$t('navigation.about')" />
|
||||
<div class="navbar-item is-hidden-desktop" style="margin-bottom: 2.5rem" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-show="show_settings_menu"
|
||||
class="is-overlay"
|
||||
style="z-index: 10; width: 100vw; height: 100vh"
|
||||
@click="show_settings_menu = false"
|
||||
/>
|
||||
<div v-show="show_settings_menu" class="is-overlay" style="z-index: 10; width: 100vw; height: 100vh" @click="show_settings_menu = false" />
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
|
@ -2,17 +2,9 @@
|
||||
<section v-if="notifications.length > 0" class="fd-notifications">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-half">
|
||||
<div
|
||||
v-for="notification in notifications"
|
||||
:key="notification.id"
|
||||
class="notification has-shadow"
|
||||
:class="[
|
||||
'notification',
|
||||
notification.type ? `is-${notification.type}` : ''
|
||||
]"
|
||||
>
|
||||
<div v-for="notification in notifications" :key="notification.id" class="notification has-shadow" :class="[ 'notification', notification.type ? `is-${notification.type}` : '' ]">
|
||||
<button class="delete" @click="remove(notification)" />
|
||||
{{ notification.text }}
|
||||
<span v-text="notification.text" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<a :class="{ 'is-warning': is_consume }" @click="toggle_consume_mode">
|
||||
<span class="icon"><mdicon name="fire" :size="icon_size" /></span>
|
||||
<mdicon class="icon" name="fire" :size="icon_size" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<a :disabled="disabled" @click="play_next">
|
||||
<span class="icon"><mdicon name="skip-forward" :size="icon_size" /></span>
|
||||
<mdicon class="icon" name="skip-forward" :size="icon_size" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<a :disabled="disabled" @click="toggle_play_pause">
|
||||
<span class="icon"><mdicon :name="icon_name" :size="icon_size" /></span>
|
||||
<mdicon class="icon" :name="icon_name" :size="icon_size" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
@ -49,7 +49,7 @@ export default {
|
||||
if (this.disabled) {
|
||||
if (this.show_disabled_message) {
|
||||
this.$store.dispatch('add_notification', {
|
||||
text: 'Queue is empty',
|
||||
text: this.$t('server.empty-queue'),
|
||||
type: 'info',
|
||||
topic: 'connection',
|
||||
timeout: 2000
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<a :disabled="disabled" @click="play_previous">
|
||||
<span class="icon"><mdicon name="skip-backward" :size="icon_size" /></span>
|
||||
<mdicon class="icon" name="skip-backward" :size="icon_size" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<a :class="{ 'is-warning': !is_repeat_off }" @click="toggle_repeat_mode">
|
||||
<span class="icon"><mdicon :name="icon_name" :size="icon_size" /></span>
|
||||
<mdicon class="icon" :name="icon_name" :size="icon_size" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<a v-if="visible" :disabled="disabled" @click="seek">
|
||||
<span class="icon"><mdicon name="rewind" :size="icon_size" /></span>
|
||||
<mdicon class="icon" name="rewind" :size="icon_size" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<a v-if="visible" :disabled="disabled" @click="seek">
|
||||
<span class="icon"><mdicon name="fast-forward" :size="icon_size" /></span>
|
||||
<mdicon class="icon" name="fast-forward" :size="icon_size" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<a :class="{ 'is-warning': is_shuffle }" @click="toggle_shuffle_mode">
|
||||
<span class="icon"><mdicon :name="icon_name" :size="icon_size" /></span>
|
||||
<mdicon class="icon" :name="icon_name" :size="icon_size" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
|
@ -1,9 +1,5 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="width > 0"
|
||||
class="progress-bar mt-2"
|
||||
:style="{ width: width_percent }"
|
||||
/>
|
||||
<div v-if="width > 0" class="progress-bar mt-2" :style="{ width: width_percent }" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -1,22 +1,9 @@
|
||||
<template>
|
||||
<div class="field">
|
||||
<label class="checkbox">
|
||||
<input
|
||||
ref="settings_checkbox"
|
||||
type="checkbox"
|
||||
:checked="value"
|
||||
@change="set_update_timer"
|
||||
/>
|
||||
<label class="switch">
|
||||
<input ref="setting" type="checkbox" :checked="value" style="margin-right: 5px" @change="set_update_timer"/>
|
||||
<slot name="label" />
|
||||
<i
|
||||
class="is-size-7"
|
||||
:class="{
|
||||
'has-text-info': statusUpdate === 'success',
|
||||
'has-text-danger': statusUpdate === 'error'
|
||||
}"
|
||||
>
|
||||
{{ info }}</i
|
||||
>
|
||||
<i class="is-size-7" :class="{ 'has-text-info': is_success, 'has-text-danger': is_error }" v-text="info" />
|
||||
</label>
|
||||
<p v-if="$slots['info']" class="help">
|
||||
<slot name="info" />
|
||||
@ -30,15 +17,12 @@ import * as types from '@/store/mutation_types'
|
||||
|
||||
export default {
|
||||
name: 'SettingsCheckbox',
|
||||
|
||||
props: ['category_name', 'option_name'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
timerDelay: 2000,
|
||||
timerId: -1,
|
||||
|
||||
// <empty>: default/no changes, 'success': update succesful, 'error': update failed
|
||||
statusUpdate: ''
|
||||
}
|
||||
},
|
||||
@ -65,11 +49,19 @@ export default {
|
||||
|
||||
info() {
|
||||
if (this.statusUpdate === 'success') {
|
||||
return '(setting saved)'
|
||||
return this.$t('setting.saved')
|
||||
} else if (this.statusUpdate === 'error') {
|
||||
return '(error saving setting)'
|
||||
return this.$t('setting.not-saved')
|
||||
}
|
||||
return ''
|
||||
},
|
||||
|
||||
is_success() {
|
||||
return this.statusUpdate === 'success'
|
||||
},
|
||||
|
||||
is_error() {
|
||||
return this.statusUpdate === 'error'
|
||||
}
|
||||
},
|
||||
|
||||
@ -81,7 +73,7 @@ export default {
|
||||
}
|
||||
|
||||
this.statusUpdate = ''
|
||||
const newValue = this.$refs.settings_checkbox.checked
|
||||
const newValue = this.$refs.setting.checked
|
||||
if (newValue !== this.value) {
|
||||
this.timerId = window.setTimeout(this.update_setting, this.timerDelay)
|
||||
}
|
||||
@ -90,8 +82,8 @@ export default {
|
||||
update_setting() {
|
||||
this.timerId = -1
|
||||
|
||||
const newValue = this.$refs.settings_checkbox.checked
|
||||
console.log(this.$refs.settings_checkbox)
|
||||
const newValue = this.$refs.setting.checked
|
||||
console.log(this.$refs.setting)
|
||||
if (newValue === this.value) {
|
||||
this.statusUpdate = ''
|
||||
return
|
||||
@ -110,7 +102,7 @@ export default {
|
||||
})
|
||||
.catch(() => {
|
||||
this.statusUpdate = 'error'
|
||||
this.$refs.settings_checkbox.checked = this.value
|
||||
this.$refs.setting.checked = this.value
|
||||
})
|
||||
.finally(() => {
|
||||
this.timerId = window.setTimeout(this.clear_status, this.timerDelay)
|
||||
|
@ -3,27 +3,10 @@
|
||||
<div class="field">
|
||||
<label class="label has-text-weight-normal">
|
||||
<slot name="label" />
|
||||
<i
|
||||
class="is-size-7"
|
||||
:class="{
|
||||
'has-text-info': statusUpdate === 'success',
|
||||
'has-text-danger': statusUpdate === 'error'
|
||||
}"
|
||||
>
|
||||
{{ info }}</i
|
||||
>
|
||||
<i class="is-size-7" :class="{ 'has-text-info': is_success, 'has-text-danger': is_error }" v-text="info" />
|
||||
</label>
|
||||
<div class="control">
|
||||
<input
|
||||
ref="settings_number"
|
||||
class="input"
|
||||
type="number"
|
||||
min="0"
|
||||
style="width: 10em"
|
||||
:placeholder="placeholder"
|
||||
:value="value"
|
||||
@input="set_update_timer"
|
||||
/>
|
||||
<input ref="setting" class="input" type="number" min="0" style="width: 10em" :placeholder="placeholder" :value="value" @input="set_update_timer" />
|
||||
</div>
|
||||
<p v-if="$slots['info']" class="help">
|
||||
<slot name="info" />
|
||||
@ -38,14 +21,12 @@ import * as types from '@/store/mutation_types'
|
||||
|
||||
export default {
|
||||
name: 'SettingsIntfield',
|
||||
|
||||
props: ['category_name', 'option_name', 'placeholder', 'disabled'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
timerDelay: 2000,
|
||||
timerId: -1,
|
||||
|
||||
statusUpdate: ''
|
||||
}
|
||||
},
|
||||
@ -72,11 +53,19 @@ export default {
|
||||
|
||||
info() {
|
||||
if (this.statusUpdate === 'success') {
|
||||
return '(setting saved)'
|
||||
return this.$t('setting.saved')
|
||||
} else if (this.statusUpdate === 'error') {
|
||||
return '(error saving setting)'
|
||||
return this.$t('setting.not-saved')
|
||||
}
|
||||
return ''
|
||||
},
|
||||
|
||||
is_success() {
|
||||
return this.statusUpdate === 'success'
|
||||
},
|
||||
|
||||
is_error() {
|
||||
return this.statusUpdate === 'error'
|
||||
}
|
||||
},
|
||||
|
||||
@ -88,7 +77,7 @@ export default {
|
||||
}
|
||||
|
||||
this.statusUpdate = ''
|
||||
const newValue = this.$refs.settings_number.value
|
||||
const newValue = this.$refs.setting.value
|
||||
if (newValue !== this.value) {
|
||||
this.timerId = window.setTimeout(this.update_setting, this.timerDelay)
|
||||
}
|
||||
@ -97,7 +86,7 @@ export default {
|
||||
update_setting() {
|
||||
this.timerId = -1
|
||||
|
||||
const newValue = this.$refs.settings_number.value
|
||||
const newValue = this.$refs.setting.value
|
||||
if (newValue === this.value) {
|
||||
this.statusUpdate = ''
|
||||
return
|
||||
@ -116,7 +105,7 @@ export default {
|
||||
})
|
||||
.catch(() => {
|
||||
this.statusUpdate = 'error'
|
||||
this.$refs.settings_number.value = this.value
|
||||
this.$refs.setting.value = this.value
|
||||
})
|
||||
.finally(() => {
|
||||
this.timerId = window.setTimeout(this.clear_status, this.timerDelay)
|
||||
|
@ -3,25 +3,10 @@
|
||||
<div class="field">
|
||||
<label class="label has-text-weight-normal">
|
||||
<slot name="label" />
|
||||
<i
|
||||
class="is-size-7"
|
||||
:class="{
|
||||
'has-text-info': statusUpdate === 'success',
|
||||
'has-text-danger': statusUpdate === 'error'
|
||||
}"
|
||||
>
|
||||
{{ info }}</i
|
||||
>
|
||||
<i class="is-size-7" :class="{ 'has-text-info': is_success, 'has-text-danger': is_error }" v-text="info" />
|
||||
</label>
|
||||
<div class="control">
|
||||
<input
|
||||
ref="settings_text"
|
||||
class="input"
|
||||
type="text"
|
||||
:placeholder="placeholder"
|
||||
:value="value"
|
||||
@input="set_update_timer"
|
||||
/>
|
||||
<input ref="setting" class="input" type="text" :placeholder="placeholder" :value="value" @input="set_update_timer" />
|
||||
</div>
|
||||
<p v-if="$slots['info']" class="help">
|
||||
<slot name="info" />
|
||||
@ -43,8 +28,6 @@ export default {
|
||||
return {
|
||||
timerDelay: 2000,
|
||||
timerId: -1,
|
||||
|
||||
// <empty>: default/no changes, 'success': update succesful, 'error': update failed
|
||||
statusUpdate: ''
|
||||
}
|
||||
},
|
||||
@ -71,11 +54,19 @@ export default {
|
||||
|
||||
info() {
|
||||
if (this.statusUpdate === 'success') {
|
||||
return '(setting saved)'
|
||||
return this.$t('setting.saved')
|
||||
} else if (this.statusUpdate === 'error') {
|
||||
return '(error saving setting)'
|
||||
return this.$t('setting.not-saved')
|
||||
}
|
||||
return ''
|
||||
},
|
||||
|
||||
is_success() {
|
||||
return this.statusUpdate === 'success'
|
||||
},
|
||||
|
||||
is_error() {
|
||||
return this.statusUpdate === 'error'
|
||||
}
|
||||
},
|
||||
|
||||
@ -87,7 +78,7 @@ export default {
|
||||
}
|
||||
|
||||
this.statusUpdate = ''
|
||||
const newValue = this.$refs.settings_text.value
|
||||
const newValue = this.$refs.setting.value
|
||||
if (newValue !== this.value) {
|
||||
this.timerId = window.setTimeout(this.update_setting, this.timerDelay)
|
||||
}
|
||||
@ -96,7 +87,7 @@ export default {
|
||||
update_setting() {
|
||||
this.timerId = -1
|
||||
|
||||
const newValue = this.$refs.settings_text.value
|
||||
const newValue = this.$refs.setting.value
|
||||
if (newValue === this.value) {
|
||||
this.statusUpdate = ''
|
||||
return
|
||||
@ -115,7 +106,7 @@ export default {
|
||||
})
|
||||
.catch(() => {
|
||||
this.statusUpdate = 'error'
|
||||
this.$refs.settings_text.value = this.value
|
||||
this.$refs.setting.value = this.value
|
||||
})
|
||||
.finally(() => {
|
||||
this.timerId = window.setTimeout(this.clear_status, this.timerDelay)
|
||||
|
@ -4,15 +4,11 @@
|
||||
<slot name="artwork" />
|
||||
</div>
|
||||
<div class="media-content fd-has-action is-clipped">
|
||||
<h1 class="title is-6">
|
||||
{{ album.name }}
|
||||
</h1>
|
||||
<h1 class="title is-6" v-text="album.name" />
|
||||
<h2 class="subtitle is-7 has-text-grey">
|
||||
<b>{{ album.artists[0].name }}</b>
|
||||
</h2>
|
||||
<h2 class="subtitle is-7 has-text-grey has-text-weight-normal">
|
||||
({{ album.album_type }}, {{ $filters.date(album.release_date) }})
|
||||
<b v-text="album.artists[0].name" />
|
||||
</h2>
|
||||
<h2 class="subtitle is-7 has-text-grey has-text-weight-normal" v-text="[album.album_type, $filters.date(album.release_date)].join(', ')" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<slot name="actions" />
|
||||
|
@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<div class="media">
|
||||
<div class="media-content fd-has-action is-clipped" @click="open_artist">
|
||||
<h1 class="title is-6">
|
||||
{{ artist.name }}
|
||||
</h1>
|
||||
<h1 class="title is-6" v-text="artist.name" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<slot name="actions" />
|
||||
|
@ -1,12 +1,8 @@
|
||||
<template>
|
||||
<div class="media">
|
||||
<div class="media-content fd-has-action is-clipped" @click="open_playlist">
|
||||
<h1 class="title is-6">
|
||||
{{ playlist.name }}
|
||||
</h1>
|
||||
<h2 class="subtitle is-7">
|
||||
{{ playlist.owner.display_name }}
|
||||
</h2>
|
||||
<h1 class="title is-6" v-text="playlist.name" />
|
||||
<h2 class="subtitle is-7" v-text="playlist.owner.display_name" />
|
||||
</div>
|
||||
<div class="media-right">
|
||||
<slot name="actions" />
|
||||
|
@ -1,26 +1,13 @@
|
||||
<template>
|
||||
<div class="media">
|
||||
<div class="media-content fd-has-action is-clipped" @click="play">
|
||||
<h1
|
||||
class="title is-6"
|
||||
:class="{ 'has-text-grey-light': track.is_playable === false }"
|
||||
>
|
||||
{{ track.name }}
|
||||
</h1>
|
||||
<h2
|
||||
class="subtitle is-7"
|
||||
:class="{
|
||||
'has-text-grey': track.is_playable,
|
||||
'has-text-grey-light': track.is_playable === false
|
||||
}"
|
||||
>
|
||||
<b>{{ track.artists[0].name }}</b>
|
||||
<h1 class="title is-6" :class="{ 'has-text-grey-light': track.is_playable === false }" v-text="track.name" />
|
||||
<h2 class="subtitle is-7" :class="{ 'has-text-grey': track.is_playable, 'has-text-grey-light': track.is_playable === false }">
|
||||
<b v-text="track.artists[0].name" />
|
||||
</h2>
|
||||
<h2 v-if="track.is_playable === false" class="subtitle is-7">
|
||||
(Track is not playable<span
|
||||
v-if="track.restrictions && track.restrictions.reason"
|
||||
>, restriction reason: {{ track.restrictions.reason }}</span
|
||||
>)
|
||||
(<span v-text="$t('list.spotify.not-playable-track')" />
|
||||
<span v-if="track.restrictions && track.restrictions.reason" v-text="$t('list.spotify.restriction-reason', { reason: track.restrictions.reason })" />)
|
||||
</h2>
|
||||
</div>
|
||||
<div class="media-right">
|
||||
@ -34,9 +21,7 @@ import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'SpotifyListItemTrack',
|
||||
|
||||
props: ['track', 'position', 'album', 'context_uri'],
|
||||
|
||||
methods: {
|
||||
play: function () {
|
||||
webapi.player_play_uri(this.context_uri, false, this.position)
|
||||
|
@ -6,66 +6,44 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<figure
|
||||
v-show="artwork_visible"
|
||||
class="image is-square fd-has-margin-bottom"
|
||||
>
|
||||
<img
|
||||
:src="artwork_url"
|
||||
class="fd-has-shadow"
|
||||
@load="artwork_loaded"
|
||||
@error="artwork_error"
|
||||
/>
|
||||
<figure v-show="artwork_visible" class="image is-square fd-has-margin-bottom">
|
||||
<img :src="artwork_url" class="fd-has-shadow" @load="artwork_loaded" @error="artwork_error" />
|
||||
</figure>
|
||||
<p class="title is-4">
|
||||
<a class="has-text-link" @click="open_album">{{
|
||||
album.name
|
||||
}}</a>
|
||||
<a class="has-text-link" @click="open_album" v-text="album.name" />
|
||||
</p>
|
||||
<div class="content is-small">
|
||||
<p>
|
||||
<span class="heading">Album artist</span>
|
||||
<a class="title is-6 has-text-link" @click="open_artist">{{
|
||||
album.artists[0].name
|
||||
}}</a>
|
||||
<span class="heading" v-text="$t('dialog.spotify.album.album-artist')" />
|
||||
<a class="title is-6 has-text-link" @click="open_artist" v-text="album.artists[0].name" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Release date</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.date(album.release_date)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.spotify.album.release-date')" />
|
||||
<span class="title is-6" v-text="$filters.date(album.release_date)" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Type</span>
|
||||
<span class="title is-6">{{ album.album_type }}</span>
|
||||
<span class="heading" v-text="$t('dialog.spotify.album.type')" />
|
||||
<span class="title is-6" v-text="album.album_type" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.spotify.album.add')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.spotify.album.add-next')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.spotify.album.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="modal-close is-large"
|
||||
aria-label="close"
|
||||
@click="$emit('close')"
|
||||
/>
|
||||
<button class="modal-close is-large" aria-label="close" @click="$emit('close')" />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -7,49 +7,36 @@
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
<a class="has-text-link" @click="open_artist">{{
|
||||
artist.name
|
||||
}}</a>
|
||||
<a class="has-text-link" @click="open_artist" v-text="artist.name" />
|
||||
</p>
|
||||
<div class="content is-small">
|
||||
<p>
|
||||
<span class="heading">Popularity / Followers</span>
|
||||
<span class="title is-6"
|
||||
>{{ artist.popularity }} /
|
||||
{{ artist.followers.total }}</span
|
||||
>
|
||||
<span class="heading" v-text="$t('dialog.spotify.artist.popularity')" />
|
||||
<span class="title is-6" v-text="[artist.popularity, artist.followers.total].join(' / ')" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Genres</span>
|
||||
<span class="title is-6">{{ artist.genres.join(', ') }}</span>
|
||||
<span class="heading" v-text="$t('dialog.spotify.artist.genres')" />
|
||||
<span class="title is-6" v-text="artist.genres.join(', ')" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.spotify.artist.add')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.spotify.artist.add-next')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.spotify.artist.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="modal-close is-large"
|
||||
aria-label="close"
|
||||
@click="$emit('close')"
|
||||
/>
|
||||
<button class="modal-close is-large" aria-label="close" @click="$emit('close')" />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -7,52 +7,40 @@
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
<a class="has-text-link" @click="open_playlist">{{
|
||||
playlist.name
|
||||
}}</a>
|
||||
<a class="has-text-link" @click="open_playlist" v-text="playlist.name" />
|
||||
</p>
|
||||
<div class="content is-small">
|
||||
<p>
|
||||
<span class="heading">Owner</span>
|
||||
<span class="title is-6">{{
|
||||
playlist.owner.display_name
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.spotify.playlist.owner')" />
|
||||
<span class="title is-6" v-text="playlist.owner.display_name" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Tracks</span>
|
||||
<span class="title is-6">{{ playlist.tracks.total }}</span>
|
||||
<span class="heading" v-text="$t('dialog.spotify.playlist.tracks')" />
|
||||
<span class="title is-6" v-text="playlist.tracks.total" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Path</span>
|
||||
<span class="title is-6">{{ playlist.uri }}</span>
|
||||
<span class="heading" v-text="$t('dialog.spotify.playlist.path')" />
|
||||
<span class="title is-6" v-text="playlist.uri" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.spotify.playlist.add')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.spotify.playlist.add-next')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.spotify.playlist.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="modal-close is-large"
|
||||
aria-label="close"
|
||||
@click="$emit('close')"
|
||||
/>
|
||||
<button class="modal-close is-large" aria-label="close" @click="$emit('close')" />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -6,74 +6,52 @@
|
||||
<div class="modal-content fd-modal-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title is-4">
|
||||
{{ track.name }}
|
||||
</p>
|
||||
<p class="subtitle">
|
||||
{{ track.artists[0].name }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="track.name" />
|
||||
<p class="subtitle" v-text="track.artists[0].name" />
|
||||
<div class="content is-small">
|
||||
<p>
|
||||
<span class="heading">Album</span>
|
||||
<a class="title is-6 has-text-link" @click="open_album">{{
|
||||
album.name
|
||||
}}</a>
|
||||
<span class="heading" v-text="$t('dialog.spotify.track.album')" />
|
||||
<a class="title is-6 has-text-link" @click="open_album" v-text="album.name" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Album artist</span>
|
||||
<a class="title is-6 has-text-link" @click="open_artist">{{
|
||||
album.artists[0].name
|
||||
}}</a>
|
||||
<span class="heading" v-text="$t('dialog.spotify.track.album-artist')" />
|
||||
<a class="title is-6 has-text-link" @click="open_artist" v-text="album.artists[0].name" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Release date</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.date(album.release_date)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.spotify.track.release-date')" />
|
||||
<span class="title is-6" v-text="$filters.date(album.release_date)" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Track / Disc</span>
|
||||
<span class="title is-6"
|
||||
>{{ track.track_number }} / {{ track.disc_number }}</span
|
||||
>
|
||||
<span class="heading" v-text="$t('dialog.spotify.track.position')" />
|
||||
<span class="title is-6" v-text="[ track.disc_number, track.track_number ].join(' / ')" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Length</span>
|
||||
<span class="title is-6">{{
|
||||
$filters.durationInHours(track.duration_ms)
|
||||
}}</span>
|
||||
<span class="heading" v-text="$t('dialog.spotify.track.duration')" />
|
||||
<span class="title is-6" v-text="$filters.durationInHours(track.duration_ms)" />
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading">Path</span>
|
||||
<span class="title is-6">{{ track.uri }}</span>
|
||||
<span class="heading" v-text="$t('dialog.spotify.track.path')" />
|
||||
<span class="title is-6" v-text="track.uri" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-plus" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add</span>
|
||||
<mdicon class="icon" name="playlist-plus" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.spotify.track.add')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="queue_add_next">
|
||||
<span class="icon"
|
||||
><mdicon name="playlist-play" size="16"
|
||||
/></span>
|
||||
<span class="is-size-7">Add Next</span>
|
||||
<mdicon class="icon" name="playlist-play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.spotify.track.add-next')" />
|
||||
</a>
|
||||
<a class="card-footer-item has-text-dark" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span class="is-size-7">Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span class="is-size-7" v-text="$t('dialog.spotify.track.play')" />
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="modal-close is-large"
|
||||
aria-label="close"
|
||||
@click="$emit('close')"
|
||||
/>
|
||||
<button class="modal-close is-large" aria-label="close" @click="$emit('close')" />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
|
@ -5,31 +5,19 @@
|
||||
<div class="column is-four-fifths">
|
||||
<div class="tabs is-centered is-small">
|
||||
<ul>
|
||||
<router-link
|
||||
v-slot="{ navigate, isActive }"
|
||||
to="/audiobooks/artists"
|
||||
custom
|
||||
>
|
||||
<router-link v-slot="{ navigate, isActive }" to="/audiobooks/artists" custom>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="account-music" size="16"
|
||||
/></span>
|
||||
<span class="">Authors</span>
|
||||
<mdicon class="icon is-small" name="account-music" size="16" />
|
||||
<span v-text="$t('tabs.audiobooks.authors')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
<router-link
|
||||
v-slot="{ navigate, isActive }"
|
||||
to="/audiobooks/albums"
|
||||
custom
|
||||
>
|
||||
<router-link v-slot="{ navigate, isActive }" to="/audiobooks/albums" custom>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="album" size="16"
|
||||
/></span>
|
||||
<span class="">Audiobooks</span>
|
||||
<mdicon class="icon is-small" name="album" size="16" />
|
||||
<span v-text="$t('tabs.audiobooks.audiobooks')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
|
@ -5,88 +5,51 @@
|
||||
<div class="column is-four-fifths">
|
||||
<div class="tabs is-centered is-small">
|
||||
<ul>
|
||||
<router-link
|
||||
v-slot="{ navigate, isActive }"
|
||||
to="/music/browse"
|
||||
custom
|
||||
>
|
||||
<router-link v-slot="{ navigate, isActive }" to="/music/browse" custom>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="web" size="16"
|
||||
/></span>
|
||||
<span class="">Browse</span>
|
||||
<mdicon class="icon is-small" name="web" size="16" />
|
||||
<span v-text="$t('page.settings.tabs.music.browse')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
<router-link
|
||||
v-slot="{ navigate, isActive }"
|
||||
to="/music/artists"
|
||||
custom
|
||||
>
|
||||
<router-link v-slot="{ navigate, isActive }" to="/music/artists" custom>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="account-music" size="16"
|
||||
/></span>
|
||||
<span class="">Artists</span>
|
||||
<mdicon class="icon is-small" name="account-music" size="16" />
|
||||
<span v-text="$t('page.settings.tabs.music.artists')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
<router-link
|
||||
v-slot="{ navigate, isActive }"
|
||||
to="/music/albums"
|
||||
custom
|
||||
>
|
||||
<router-link v-slot="{ navigate, isActive }" to="/music/albums" custom>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="album" size="16"
|
||||
/></span>
|
||||
<span class="">Albums</span>
|
||||
<mdicon class="icon is-small" name="album" size="16" />
|
||||
<span v-text="$t('page.settings.tabs.music.albums')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
<router-link
|
||||
v-slot="{ navigate, isActive }"
|
||||
to="/music/genres"
|
||||
custom
|
||||
>
|
||||
<router-link v-slot="{ navigate, isActive }" to="/music/genres" custom>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="speaker" size="16"
|
||||
/></span>
|
||||
<span class="">Genres</span>
|
||||
<mdicon class="icon is-small" name="speaker" size="16" />
|
||||
<span v-text="$t('page.settings.tabs.music.genres')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
<router-link
|
||||
v-slot="{ navigate, isActive }"
|
||||
to="/music/composers"
|
||||
custom
|
||||
>
|
||||
<router-link v-slot="{ navigate, isActive }" to="/music/composers" custom>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="book-open-page-variant" size="16"
|
||||
/></span>
|
||||
<span class="">Composers</span>
|
||||
<mdicon class="icon is-small" name="book-open-page-variant" size="16" />
|
||||
<span v-text="$t('page.settings.tabs.music.composers')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
<router-link
|
||||
v-if="spotify_enabled"
|
||||
v-slot="{ navigate, isActive }"
|
||||
to="/music/spotify"
|
||||
custom
|
||||
>
|
||||
<router-link v-if="spotify_enabled" v-slot="{ navigate, isActive }" to="/music/spotify" custom>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="spotify" size="16"
|
||||
/></span>
|
||||
<span class="">Spotify</span>
|
||||
<mdicon class="icon is-small" name="spotify" size="16" />
|
||||
<span v-text="$t('page.settings.tabs.music.spotify')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
|
@ -5,28 +5,16 @@
|
||||
<div class="column is-four-fifths">
|
||||
<div class="tabs is-centered is-small is-toggle is-toggle-rounded">
|
||||
<ul>
|
||||
<li
|
||||
:class="{
|
||||
'is-active': $store.state.search_path === '/search/library'
|
||||
}"
|
||||
>
|
||||
<li :class="{ 'is-active': $store.state.search_path === '/search/library' }">
|
||||
<a @click="search_library">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="bookshelf" size="16"
|
||||
/></span>
|
||||
<span class="">Library</span>
|
||||
<mdicon class="icon is-small" name="bookshelf" size="16" />
|
||||
<span v-text="$t('tabs.search.library')" />
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
:class="{
|
||||
'is-active': $store.state.search_path === '/search/spotify'
|
||||
}"
|
||||
>
|
||||
<li :class="{ 'is-active': $store.state.search_path === '/search/spotify' }">
|
||||
<a @click="search_spotify">
|
||||
<span class="icon is-small"
|
||||
><mdicon name="spotify" size="16"
|
||||
/></span>
|
||||
<span class="">Spotify</span>
|
||||
<mdicon class="icon is-small" name="spotify" size="16" />
|
||||
<span v-text="$t('tabs.search.spotify')" />
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -5,47 +5,31 @@
|
||||
<div class="column is-four-fifths">
|
||||
<div class="tabs is-centered is-small">
|
||||
<ul>
|
||||
<router-link
|
||||
v-slot="{ navigate, isActive }"
|
||||
to="/settings/webinterface"
|
||||
custom
|
||||
>
|
||||
<router-link v-slot="{ navigate, isActive }" to="/settings/webinterface" custom>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="">Webinterface</span>
|
||||
<span v-text="$t('page.settings.tabs.settings.general')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
<router-link
|
||||
v-slot="{ navigate, isActive }"
|
||||
to="/settings/remotes-outputs"
|
||||
custom
|
||||
>
|
||||
<router-link v-slot="{ navigate, isActive }" to="/settings/remotes-outputs" custom>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="">Remotes & Outputs</span>
|
||||
<span v-text="$t('page.settings.tabs.settings.remotes-and-outputs')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
<router-link
|
||||
v-slot="{ navigate, isActive }"
|
||||
to="/settings/artwork"
|
||||
custom
|
||||
>
|
||||
<router-link v-slot="{ navigate, isActive }" to="/settings/artwork" custom>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="">Artwork</span>
|
||||
<span v-text="$t('page.settings.tabs.settings.artwork')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
<router-link
|
||||
v-slot="{ navigate, isActive }"
|
||||
to="/settings/online-services"
|
||||
custom
|
||||
>
|
||||
<router-link v-slot="{ navigate, isActive }" to="/settings/online-services" custom>
|
||||
<li :class="{ 'is-active': isActive }">
|
||||
<a @click="navigate" @keypress.enter="navigate">
|
||||
<span class="">Online Services</span>
|
||||
<span v-text="$t('page.settings.tabs.settings.online-services')" />
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
@ -59,9 +43,7 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'TabsSettings',
|
||||
|
||||
computed: {}
|
||||
name: 'TabsSettings'
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -2,8 +2,8 @@ import {
|
||||
mdiAccountMusic,
|
||||
mdiAlbum,
|
||||
mdiArrowCollapseDown,
|
||||
mdiBookOpenVariant,
|
||||
mdiBookOpenPageVariant,
|
||||
mdiBookOpenVariant,
|
||||
mdiBookshelf,
|
||||
mdiCancel,
|
||||
mdiCast,
|
||||
@ -24,9 +24,10 @@ import {
|
||||
mdiFire,
|
||||
mdiFolder,
|
||||
mdiFolderOpen,
|
||||
mdiOpenInNew,
|
||||
mdiMagnify,
|
||||
mdiMenu,
|
||||
mdiMicrophone,
|
||||
mdiPodcast,
|
||||
mdiMusic,
|
||||
mdiMusicBoxMultiple,
|
||||
mdiPause,
|
||||
@ -35,7 +36,7 @@ import {
|
||||
mdiPlay,
|
||||
mdiPlaylistPlay,
|
||||
mdiPlaylistPlus,
|
||||
mdiRadio,
|
||||
mdiBroadcast,
|
||||
mdiRadioTower,
|
||||
mdiRefresh,
|
||||
mdiRepeat,
|
||||
@ -61,8 +62,8 @@ export const icons = {
|
||||
mdiAccountMusic,
|
||||
mdiAlbum,
|
||||
mdiArrowCollapseDown,
|
||||
mdiBookOpenVariant,
|
||||
mdiBookOpenPageVariant,
|
||||
mdiBookOpenVariant,
|
||||
mdiBookshelf,
|
||||
mdiCancel,
|
||||
mdiCast,
|
||||
@ -83,9 +84,10 @@ export const icons = {
|
||||
mdiFire,
|
||||
mdiFolder,
|
||||
mdiFolderOpen,
|
||||
mdiOpenInNew,
|
||||
mdiMagnify,
|
||||
mdiMenu,
|
||||
mdiMicrophone,
|
||||
mdiPodcast,
|
||||
mdiMusic,
|
||||
mdiMusicBoxMultiple,
|
||||
mdiPause,
|
||||
@ -94,7 +96,7 @@ export const icons = {
|
||||
mdiPlay,
|
||||
mdiPlaylistPlay,
|
||||
mdiPlaylistPlus,
|
||||
mdiRadio,
|
||||
mdiBroadcast,
|
||||
mdiRadioTower,
|
||||
mdiRefresh,
|
||||
mdiRepeat,
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { createApp } from 'vue'
|
||||
import i18n from './i18n'
|
||||
import store from './store'
|
||||
import { router } from './router'
|
||||
import VueProgressBar from '@aacassandra/vue3-progressbar'
|
||||
@ -30,6 +31,7 @@ const app = createApp(App)
|
||||
.use(mdiVue, {
|
||||
icons: icons
|
||||
})
|
||||
.use(i18n)
|
||||
|
||||
app.config.globalProperties.$filters = filters
|
||||
app.mount('#app')
|
||||
|
@ -4,10 +4,8 @@
|
||||
<div class="container">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-four-fifths has-text-centered-mobile">
|
||||
<p class="heading"><b>OwnTone</b> - version {{ config.version }}</p>
|
||||
<h1 class="title is-4">
|
||||
{{ config.library_name }}
|
||||
</h1>
|
||||
<p class="heading" v-html="$t('page.about.version', {version: config.version})" />
|
||||
<h1 class="title is-4" v-text="config.library_name" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -21,65 +19,49 @@
|
||||
<!-- Left side -->
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<h2 class="title is-5">Library</h2>
|
||||
<h2 class="title is-5" v-text="$t('page.about.library')" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right side -->
|
||||
<div class="level-right">
|
||||
<div v-if="library.updating">
|
||||
<a class="button is-small is-loading">Update</a>
|
||||
<a class="button is-small is-loading" v-text="$t('page.about.update')" />
|
||||
</div>
|
||||
<div v-else>
|
||||
<a class="button is-small" @click="showUpdateDialog()"
|
||||
>Update</a
|
||||
>
|
||||
<a class="button is-small" @click="showUpdateDialog()" v-text="$t('page.about.update')" />
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Artists</th>
|
||||
<th v-text="$t('page.about.artists')" />
|
||||
<td class="has-text-right" v-text="$filters.number(library.artists)" />
|
||||
</tr>
|
||||
<tr>
|
||||
<th v-text="$t('page.about.albums')" />
|
||||
<td class="has-text-right" v-text="$filters.number(library.albums)" />
|
||||
</tr>
|
||||
<tr>
|
||||
<th v-text="$t('page.about.tracks')" />
|
||||
<td class="has-text-right" v-text="$filters.number(library.songs)" />
|
||||
</tr>
|
||||
<tr>
|
||||
<th v-text="$t('page.about.total-playtime')" />
|
||||
<td class="has-text-right" v-text="$filters.durationInDays(library.db_playtime * 1000)" />
|
||||
</tr>
|
||||
<tr>
|
||||
<th v-text="$t('page.about.updated')" />
|
||||
<td class="has-text-right">
|
||||
{{ $filters.number(library.artists) }}
|
||||
<span v-text="$t('page.about.updated-on', { time: $filters.timeFromNow(library.updated_at) })" />
|
||||
(<span class="has-text-grey" v-text="$filters.datetime(library.updated_at)" />)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Albums</th>
|
||||
<th v-text="$t('page.about.uptime')" />
|
||||
<td class="has-text-right">
|
||||
{{ $filters.number(library.albums) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Tracks</th>
|
||||
<td class="has-text-right">
|
||||
{{ $filters.number(library.songs) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Total playtime</th>
|
||||
<td class="has-text-right">
|
||||
{{ $filters.durationInDays(library.db_playtime * 1000) }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Library updated</th>
|
||||
<td class="has-text-right">
|
||||
{{ $filters.timeFromNow(library.updated_at) }} ago
|
||||
<span class="has-text-grey"
|
||||
>({{ $filters.datetime(library.updated_at) }})</span
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Uptime</th>
|
||||
<td class="has-text-right">
|
||||
{{ $filters.timeFromNow(library.started_at, true) }}
|
||||
<span class="has-text-grey"
|
||||
>({{ $filters.datetime(library.started_at) }})</span
|
||||
>
|
||||
<span v-text="$filters.timeFromNow(library.started_at, true)" />
|
||||
(<span class="has-text-grey" v-text="$filters.datetime(library.started_at)" />)
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -94,20 +76,8 @@
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-four-fifths">
|
||||
<div class="content has-text-centered-mobile">
|
||||
<p class="is-size-7">
|
||||
Compiled with support for {{ config.buildoptions.join(', ') }}.
|
||||
</p>
|
||||
<p class="is-size-7">
|
||||
Web interface built with <a href="http://bulma.io">Bulma</a>,
|
||||
<a href="https://materialdesignicons.com/"
|
||||
>Material Design Icons</a
|
||||
>, <a href="https://vuejs.org/">Vue.js</a>,
|
||||
<a href="https://github.com/mzabriskie/axios">axios</a> and
|
||||
<a
|
||||
href="https://github.com/owntone/owntone-server/network/dependencies"
|
||||
>more</a
|
||||
>.
|
||||
</p>
|
||||
<p class="is-size-7" v-text="$t('page.about.compiled-with', { options: config.buildoptions.join(', ') })" />
|
||||
<p class="is-size-7" v-html="$t('page.about.built-with')" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,46 +1,29 @@
|
||||
<template>
|
||||
<content-with-hero>
|
||||
<template #heading-left>
|
||||
<h1 class="title is-5">
|
||||
{{ album.name }}
|
||||
</h1>
|
||||
<h1 class="title is-5" v-text="album.name" />
|
||||
<h2 class="subtitle is-6 has-text-link has-text-weight-normal">
|
||||
<a class="has-text-link" @click="open_artist">{{ album.artist }}</a>
|
||||
<a class="has-text-link" @click="open_artist" v-text="album.artist" />
|
||||
</h2>
|
||||
|
||||
<div class="buttons fd-is-centered-mobile fd-has-margin-top">
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.album.shuffle')" />
|
||||
</a>
|
||||
<a
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_album_details_modal = true"
|
||||
>
|
||||
<span class="icon"><mdicon name="dots-horizontal" size="16" /></span>
|
||||
<a class="button is-small is-light is-rounded" @click="show_album_details_modal = true">
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<p class="image is-square fd-has-shadow fd-has-action">
|
||||
<cover-artwork
|
||||
:artwork_url="album.artwork_url"
|
||||
:artist="album.artist"
|
||||
:album="album.name"
|
||||
@click="show_album_details_modal = true"
|
||||
/>
|
||||
<cover-artwork :artwork_url="album.artwork_url" :artist="album.artist" :album="album.name" @click="show_album_details_modal = true" />
|
||||
</p>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading is-7 has-text-centered-mobile fd-has-margin-top">
|
||||
{{ album.track_count }} tracks
|
||||
</p>
|
||||
<p class="heading is-7 has-text-centered-mobile fd-has-margin-top" v-text="$t('page.album.track-count', {count: album.track_count})" />
|
||||
<list-tracks :tracks="tracks" :uris="album.uri" />
|
||||
<modal-dialog-album
|
||||
:show="show_album_details_modal"
|
||||
:album="album"
|
||||
@close="show_album_details_modal = false"
|
||||
/>
|
||||
<modal-dialog-album :show="show_album_details_modal" :album="album" @close="show_album_details_modal = false" />
|
||||
</template>
|
||||
</content-with-hero>
|
||||
</template>
|
||||
|
@ -1,59 +1,36 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-music />
|
||||
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="albums.indexList" />
|
||||
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<p class="heading" style="margin-bottom: 24px">Filter</p>
|
||||
<p class="heading" style="margin-bottom: 24px" v-text="$t('page.albums.filter')" />
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input
|
||||
id="switchHideSingles"
|
||||
v-model="hide_singles"
|
||||
type="checkbox"
|
||||
name="switchHideSingles"
|
||||
class="switch"
|
||||
/>
|
||||
<label for="switchHideSingles">Hide singles</label>
|
||||
<input id="switchHideSingles" v-model="hide_singles" type="checkbox" name="switchHideSingles" class="switch" />
|
||||
<label for="switchHideSingles" v-text="$t('page.albums.hide-singles')" />
|
||||
</div>
|
||||
<p class="help">
|
||||
If active, hides singles and albums with tracks that only appear
|
||||
in playlists.
|
||||
</p>
|
||||
<p class="help" v-text="$t('page.albums.hide-singles-help')" />
|
||||
</div>
|
||||
<div v-if="spotify_enabled" class="field">
|
||||
<div class="control">
|
||||
<input
|
||||
id="switchHideSpotify"
|
||||
v-model="hide_spotify"
|
||||
type="checkbox"
|
||||
name="switchHideSpotify"
|
||||
class="switch"
|
||||
/>
|
||||
<label for="switchHideSpotify">Hide albums from Spotify</label>
|
||||
<input id="switchHideSpotify" v-model="hide_spotify" type="checkbox" name="switchHideSpotify" class="switch" />
|
||||
<label for="switchHideSpotify" v-text="$t('page.albums.hide-spotify')" />
|
||||
</div>
|
||||
<p class="help">
|
||||
If active, hides albums that only appear in your Spotify
|
||||
library.
|
||||
</p>
|
||||
<p class="help" v-text="$t('page.albums.hide-spotify-help')" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<p class="heading" style="margin-bottom: 24px">Sort by</p>
|
||||
<dropdown-menu
|
||||
v-model="selected_groupby_option_name"
|
||||
:options="groupby_option_names"
|
||||
/>
|
||||
<p class="heading" style="margin-bottom: 24px" v-text="$t('page.albums.sort-by.title')" />
|
||||
<dropdown-menu v-model="selected_groupby_option_id" :options="groupby_options" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Albums</p>
|
||||
<p class="heading">{{ albums.count }} Albums</p>
|
||||
<p class="title is-4" v-text="$t('page.albums.title')" />
|
||||
<p class="heading" v-text="$t('page.albums.count', { count: albums.count })" />
|
||||
</template>
|
||||
<template #heading-right />
|
||||
<template #content>
|
||||
@ -117,16 +94,22 @@ export default {
|
||||
|
||||
// List of group by/sort options for itemsGroupByList
|
||||
groupby_options: [
|
||||
{ name: 'Name', options: bySortName('name_sort') },
|
||||
{
|
||||
name: 'Recently added',
|
||||
id: 1,
|
||||
name: this.$t('page.albums.sort-by.name'),
|
||||
options: bySortName('name_sort')
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: this.$t('page.albums.sort-by.recently-added'),
|
||||
options: byYear('time_added', {
|
||||
direction: 'desc',
|
||||
defaultValue: '0000'
|
||||
})
|
||||
},
|
||||
{
|
||||
name: 'Recently released',
|
||||
id: 3,
|
||||
name: this.$t('page.albums.sort-by.recently-released'),
|
||||
options: byYear('date_released', {
|
||||
direction: 'desc',
|
||||
defaultValue: '0000'
|
||||
@ -139,7 +122,7 @@ export default {
|
||||
computed: {
|
||||
albums() {
|
||||
const groupBy = this.groupby_options.find(
|
||||
(o) => o.name === this.selected_groupby_option_name
|
||||
(o) => o.id === this.selected_groupby_option_id
|
||||
)
|
||||
this.albums_list.group(groupBy.options, [
|
||||
(album) => !this.hide_singles || album.track_count > 2,
|
||||
@ -149,11 +132,7 @@ export default {
|
||||
return this.albums_list
|
||||
},
|
||||
|
||||
groupby_option_names() {
|
||||
return [...this.groupby_options].map((o) => o.name)
|
||||
},
|
||||
|
||||
selected_groupby_option_name: {
|
||||
selected_groupby_option_id: {
|
||||
get() {
|
||||
return this.$store.state.albums_sort
|
||||
},
|
||||
|
@ -3,46 +3,32 @@
|
||||
<template #options>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<p class="heading" style="margin-bottom: 24px">Sort by</p>
|
||||
<dropdown-menu
|
||||
v-model="selected_groupby_option_name"
|
||||
:options="groupby_option_names"
|
||||
/>
|
||||
<p class="heading" style="margin-bottom: 24px" v-text="$t('page.artist.sort-by.title')" />
|
||||
<dropdown-menu v-model="selected_groupby_option_id" :options="groupby_options"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ artist.name }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="artist.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
<a
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_artist_details_modal = true"
|
||||
>
|
||||
<span class="icon"><mdicon name="dots-horizontal" size="16" /></span>
|
||||
<a class="button is-small is-light is-rounded" @click="show_artist_details_modal = true">
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.artist.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
{{ artist.album_count }} albums |
|
||||
<a class="has-text-link" @click="open_tracks"
|
||||
>{{ artist.track_count }} tracks</a
|
||||
>
|
||||
<span v-text="$t('page.artist.album-count', { count: artist.album_count })" />
|
||||
<a class="has-text-link" @click="open_tracks" v-text="$t('page.artist.track-count', { count: artist.track_count })" />
|
||||
</p>
|
||||
<list-albums :albums="albums" :hide_group_title="true" />
|
||||
<modal-dialog-artist
|
||||
:show="show_artist_details_modal"
|
||||
:artist="artist"
|
||||
@close="show_artist_details_modal = false"
|
||||
/>
|
||||
<modal-dialog-artist :show="show_artist_details_modal" :artist="artist" @close="show_artist_details_modal = false" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</template>
|
||||
@ -99,9 +85,14 @@ export default {
|
||||
|
||||
// List of group by/sort options for itemsGroupByList
|
||||
groupby_options: [
|
||||
{ name: 'Name', options: bySortName('name_sort') },
|
||||
{
|
||||
name: 'Release date',
|
||||
id: 1,
|
||||
name: this.$t('page.artist.sort-by.name'),
|
||||
options: bySortName('name_sort')
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: this.$t('page.artist.sort-by.release-date'),
|
||||
options: byYear('date_released', {
|
||||
direction: 'asc',
|
||||
defaultValue: '0000'
|
||||
@ -116,18 +107,14 @@ export default {
|
||||
computed: {
|
||||
albums() {
|
||||
const groupBy = this.groupby_options.find(
|
||||
(o) => o.name === this.selected_groupby_option_name
|
||||
(o) => o.name === this.selected_groupby_option_id
|
||||
)
|
||||
this.albums_list.group(groupBy.options)
|
||||
|
||||
return this.albums_list
|
||||
},
|
||||
|
||||
groupby_option_names() {
|
||||
return [...this.groupby_options].map((o) => o.name)
|
||||
},
|
||||
|
||||
selected_groupby_option_name: {
|
||||
selected_groupby_option_id: {
|
||||
get() {
|
||||
return this.$store.state.artist_albums_sort
|
||||
},
|
||||
|
@ -5,39 +5,25 @@
|
||||
<index-button-list :index="index_list" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ artist.name }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="artist.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
<a
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_artist_details_modal = true"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon name="dots-horizontal" size="16"
|
||||
/></span>
|
||||
<a class="button is-small is-light is-rounded" @click="show_artist_details_modal = true">
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.artist.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
<a class="has-text-link" @click="open_artist"
|
||||
>{{ artist.album_count }} albums</a
|
||||
>
|
||||
| {{ artist.track_count }} tracks
|
||||
<a class="has-text-link" @click="open_artist" v-text="$t('page.artist.track-count', { albums: artist.album_count, tracks: artist.track_count})" />
|
||||
</p>
|
||||
<list-tracks :tracks="tracks.items" :uris="track_uris" />
|
||||
<modal-dialog-artist
|
||||
:show="show_artist_details_modal"
|
||||
:artist="artist"
|
||||
@close="show_artist_details_modal = false"
|
||||
/>
|
||||
<modal-dialog-artist :show="show_artist_details_modal" :artist="artist" @close="show_artist_details_modal = false" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</div>
|
||||
|
@ -1,59 +1,36 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-music />
|
||||
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="artists.indexList" />
|
||||
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<p class="heading" style="margin-bottom: 24px">Filter</p>
|
||||
<p class="heading" style="margin-bottom: 24px" v-text="$t('page.artists.filter')" />
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input
|
||||
id="switchHideSingles"
|
||||
v-model="hide_singles"
|
||||
type="checkbox"
|
||||
name="switchHideSingles"
|
||||
class="switch"
|
||||
/>
|
||||
<label for="switchHideSingles">Hide singles</label>
|
||||
<input id="switchHideSingles" v-model="hide_singles" type="checkbox" name="switchHideSingles" class="switch" />
|
||||
<label for="switchHideSingles" v-text="$t('page.artists.hide-singles')" />
|
||||
</div>
|
||||
<p class="help">
|
||||
If active, hides artists that only appear on singles or
|
||||
playlists.
|
||||
</p>
|
||||
<p class="help" v-text="$t('page.artists.hide-singles-help')" />
|
||||
</div>
|
||||
<div v-if="spotify_enabled" class="field">
|
||||
<div class="control">
|
||||
<input
|
||||
id="switchHideSpotify"
|
||||
v-model="hide_spotify"
|
||||
type="checkbox"
|
||||
name="switchHideSpotify"
|
||||
class="switch"
|
||||
/>
|
||||
<label for="switchHideSpotify">Hide artists from Spotify</label>
|
||||
<input id="switchHideSpotify" v-model="hide_spotify" type="checkbox" name="switchHideSpotify" class="switch" />
|
||||
<label for="switchHideSpotify" v-text="$t('page.artists.hide-spotify')" />
|
||||
</div>
|
||||
<p class="help">
|
||||
If active, hides artists that only appear in your Spotify
|
||||
library.
|
||||
</p>
|
||||
<p class="help" v-text="$t('page.artists.hide-spotify-help')" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<p class="heading" style="margin-bottom: 24px">Sort by</p>
|
||||
<dropdown-menu
|
||||
v-model="selected_groupby_option_name"
|
||||
:options="groupby_option_names"
|
||||
/>
|
||||
<p class="heading" style="margin-bottom: 24px" v-text="$t('page.artists.sort-by.title')" />
|
||||
<dropdown-menu v-model="selected_groupby_option_id" :options="groupby_options" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Artists</p>
|
||||
<p class="heading">{{ artists.count }} Artists</p>
|
||||
<p class="title is-4" v-text="$t('page.artists.title')" />
|
||||
<p class="heading" v-text="$t('page.artists.count', { count: artists.count })" />
|
||||
</template>
|
||||
<template #heading-right />
|
||||
<template #content>
|
||||
@ -118,9 +95,14 @@ export default {
|
||||
|
||||
// List of group by/sort options for itemsGroupByList
|
||||
groupby_options: [
|
||||
{ name: 'Name', options: bySortName('name_sort') },
|
||||
{
|
||||
name: 'Recently added',
|
||||
id: 1,
|
||||
name: this.$t('page.artists.sort-by.name'),
|
||||
options: bySortName('name_sort')
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: this.$t('page.artists.sort-by.recently-added'),
|
||||
options: byYear('time_added', {
|
||||
direction: 'desc',
|
||||
defaultValue: '0000'
|
||||
@ -138,7 +120,7 @@ export default {
|
||||
}
|
||||
|
||||
const groupBy = this.groupby_options.find(
|
||||
(o) => o.name === this.selected_groupby_option_name
|
||||
(o) => o.id === this.selected_groupby_option_id
|
||||
)
|
||||
this.artists_list.group(groupBy.options, [
|
||||
(artist) =>
|
||||
@ -149,12 +131,7 @@ export default {
|
||||
return this.artists_list
|
||||
},
|
||||
|
||||
// List for the drop down menu
|
||||
groupby_option_names() {
|
||||
return [...this.groupby_options].map((o) => o.name)
|
||||
},
|
||||
|
||||
selected_groupby_option_name: {
|
||||
selected_groupby_option_id: {
|
||||
get() {
|
||||
return this.$store.state.artists_sort
|
||||
},
|
||||
|
@ -1,47 +1,29 @@
|
||||
<template>
|
||||
<content-with-hero>
|
||||
<template #heading-left>
|
||||
<h1 class="title is-5">
|
||||
{{ album.name }}
|
||||
</h1>
|
||||
<h1 class="title is-5" v-text="album.name" />
|
||||
<h2 class="subtitle is-6 has-text-link has-text-weight-normal">
|
||||
<a class="has-text-link" @click="open_artist">{{ album.artist }}</a>
|
||||
<a class="has-text-link" @click="open_artist" v-text="album.artist" />
|
||||
</h2>
|
||||
|
||||
<div class="buttons fd-is-centered-mobile fd-has-margin-top">
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span>Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span v-text="$t('page.audiobooks.album.play')" />
|
||||
</a>
|
||||
<a
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_album_details_modal = true"
|
||||
>
|
||||
<span class="icon"><mdicon name="dots-horizontal" size="16" /></span>
|
||||
<a class="button is-small is-light is-rounded" @click="show_album_details_modal = true">
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<p class="image is-square fd-has-shadow fd-has-action">
|
||||
<cover-artwork
|
||||
:artwork_url="album.artwork_url"
|
||||
:artist="album.artist"
|
||||
:album="album.name"
|
||||
@click="show_album_details_modal = true"
|
||||
/>
|
||||
<cover-artwork :artwork_url="album.artwork_url" :artist="album.artist" :album="album.name" @click="show_album_details_modal = true" />
|
||||
</p>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading is-7 has-text-centered-mobile fd-has-margin-top">
|
||||
{{ album.track_count }} tracks
|
||||
</p>
|
||||
<p class="heading is-7 has-text-centered-mobile fd-has-margin-top" v-text="$t('page.audiobooks.album.track-count', { count: album.track_count })" />
|
||||
<list-tracks :tracks="tracks" :uris="album.uri" />
|
||||
<modal-dialog-album
|
||||
:show="show_album_details_modal"
|
||||
:album="album"
|
||||
:media_kind="'audiobook'"
|
||||
@close="show_album_details_modal = false"
|
||||
/>
|
||||
<modal-dialog-album :show="show_album_details_modal" :album="album" :media_kind="'audiobook'" @close="show_album_details_modal = false" />
|
||||
</template>
|
||||
</content-with-hero>
|
||||
</template>
|
||||
|
@ -1,14 +1,13 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-audiobooks />
|
||||
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="albums.indexList" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Audiobooks</p>
|
||||
<p class="heading">{{ albums.count }} Audiobooks</p>
|
||||
<p class="title is-4" v-text="$t('page.audiobooks.albums.title')" />
|
||||
<p class="heading" v-text="$t('page.audiobooks.albums.count', { count: albums.count })" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums :albums="albums" />
|
||||
|
@ -1,34 +1,23 @@
|
||||
<template>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ artist.name }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="artist.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
<a
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_artist_details_modal = true"
|
||||
>
|
||||
<span class="icon"><mdicon name="dots-horizontal" size="16" /></span>
|
||||
<a class="button is-small is-light is-rounded" @click="show_artist_details_modal = true">
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span v-text="$t('page.audiobooks.artist.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
{{ artist.album_count }} albums
|
||||
</p>
|
||||
<p class="heading has-text-centered-mobile" v-text="$t('page.audiobooks.artist.album-count', { count: artist.album_count })" />
|
||||
<list-albums :albums="albums" />
|
||||
<modal-dialog-artist
|
||||
:show="show_artist_details_modal"
|
||||
:artist="artist"
|
||||
@close="show_artist_details_modal = false"
|
||||
/>
|
||||
<modal-dialog-artist :show="show_artist_details_modal" :artist="artist" @close="show_artist_details_modal = false" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</template>
|
||||
|
@ -1,14 +1,13 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-audiobooks />
|
||||
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="artists.indexList" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Authors</p>
|
||||
<p class="heading">{{ artists.count }} Authors</p>
|
||||
<p class="title is-4" v-text="$t('page.audiobooks.artists.title')" />
|
||||
<p class="heading" v-text="$t('page.audiobooks.artists.count', { count: tists.count })" />
|
||||
</template>
|
||||
<template #heading-right />
|
||||
<template #content>
|
||||
|
@ -1,12 +1,11 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-music />
|
||||
|
||||
<!-- Recently added -->
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Recently added</p>
|
||||
<p class="heading">albums</p>
|
||||
<p class="title is-4" v-text="$t('page.browse.recently-added.title')" />
|
||||
<p class="heading" v-text="$t('page.browse.albums')"/>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums :albums="recently_added" />
|
||||
@ -14,21 +13,16 @@
|
||||
<template #footer>
|
||||
<nav class="level">
|
||||
<p class="level-item">
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_browse('recently_added')"
|
||||
>Show more</a
|
||||
>
|
||||
<a class="button is-light is-small is-rounded" @click="open_browse('recently_added')" v-text="$t('page.browse.show-more')" />
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
|
||||
<!-- Recently played -->
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Recently played</p>
|
||||
<p class="heading">tracks</p>
|
||||
<p class="title is-4" v-text="$t('page.browse.recently-played.title')" />
|
||||
<p class="heading" v-text="$t('page.browse.tracks')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-tracks :tracks="recently_played.items" />
|
||||
@ -36,11 +30,7 @@
|
||||
<template #footer>
|
||||
<nav class="level">
|
||||
<p class="level-item">
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_browse('recently_played')"
|
||||
>Show more</a
|
||||
>
|
||||
<a class="button is-light is-small is-rounded" @click="open_browse('recently_played')" v-text="$t('page.browse.show-more')" />
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
|
@ -1,11 +1,10 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-music />
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Recently added</p>
|
||||
<p class="heading">albums</p>
|
||||
<p class="title is-4" v-text="$t('page.browse.recently.added.title')" />
|
||||
<p class="heading" v-text="$t('page.browse.recently.added.albums')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums :albums="recently_added" />
|
||||
|
@ -1,11 +1,10 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-music />
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Recently played</p>
|
||||
<p class="heading">tracks</p>
|
||||
<p class="title is-4" v-text="$t('page.browse.recently.played.title')" />
|
||||
<p class="heading" v-text="$t('page.browse.recently.played.tracks')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-tracks :tracks="recently_played.items" />
|
||||
|
@ -2,40 +2,26 @@
|
||||
<div>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ composer.name }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="composer.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
<a
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_composer_details_modal = true"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon name="dots-horizontal" size="16"
|
||||
/></span>
|
||||
<a class="button is-small is-light is-rounded" @click="show_composer_details_modal = true">
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.composer.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
{{ composer.album_count }} albums |
|
||||
<a class="has-text-link" @click="open_tracks"
|
||||
>{{ composer.track_count }} tracks</a
|
||||
>
|
||||
<span v-text="$t('page.composer.album-count', { count: composer.album_count })" />
|
||||
<a class="has-text-link" @click="open_tracks" v-text="$t('page.composer.track-count', { count: composer.track_count })" />
|
||||
</p>
|
||||
<list-albums :albums="albums_list" :hide_group_title="true" />
|
||||
|
||||
<modal-dialog-composer
|
||||
:show="show_composer_details_modal"
|
||||
:composer="composer"
|
||||
@close="show_composer_details_modal = false"
|
||||
/>
|
||||
<modal-dialog-composer :show="show_composer_details_modal" :composer="composer" @close="show_composer_details_modal = false" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</div>
|
||||
|
@ -2,39 +2,26 @@
|
||||
<div>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ composer.name }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="composer.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
<a
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_composer_details_modal = true"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon name="dots-horizontal" size="16"
|
||||
/></span>
|
||||
<a class="button is-small is-light is-rounded" @click="show_composer_details_modal = true">
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.composer.tracks.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
<a class="has-text-link" @click="open_albums"
|
||||
>{{ composer.album_count }} albums</a
|
||||
>
|
||||
| {{ composer.track_count }} tracks
|
||||
<a class="has-text-link" @click="open_albums" v-text="$t('page.composer.tracks.album-count', { count: composer.album_count })" />
|
||||
<span v-text="$t('page.composer.track-count', {count: composer.track_count })" />
|
||||
</p>
|
||||
<list-tracks :tracks="tracks.items" :expression="play_expression" />
|
||||
<modal-dialog-composer
|
||||
:show="show_composer_details_modal"
|
||||
:composer="composer"
|
||||
@close="show_composer_details_modal = false"
|
||||
/>
|
||||
<modal-dialog-composer :show="show_composer_details_modal" :composer="composer" @close="show_composer_details_modal = false" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</div>
|
||||
|
@ -1,14 +1,13 @@
|
||||
<template>
|
||||
<div>
|
||||
<tabs-music />
|
||||
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="composers.indexList" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Composers</p>
|
||||
<p class="heading">{{ composers.total }} composers</p>
|
||||
<p class="title is-4" v-text="$t('page.composers.title')" />
|
||||
<p class="heading" v-text="$t('page.composers.count', { count: composers.total })" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-composers :composers="composers" />
|
||||
|
@ -2,43 +2,25 @@
|
||||
<div>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Files</p>
|
||||
<p class="title is-7 has-text-grey">
|
||||
{{ current_directory }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="$t('page.files.title')" />
|
||||
<p class="title is-7 has-text-grey" v-text="current_directory" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
<a
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="open_directory_dialog({ path: current_directory })"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon name="dots-horizontal" size="16"
|
||||
/></span>
|
||||
<a class="button is-small is-light is-rounded" @click="open_directory_dialog({ path: current_directory })">
|
||||
<mdicon class="icon" name="dots-horizontal" size="16"/>
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="play" size="16" /></span>
|
||||
<span>Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span v-text="$t('page.files.play')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-directories :directories="files.directories" />
|
||||
|
||||
<list-playlists :playlists="files.playlists.items" />
|
||||
|
||||
<list-tracks
|
||||
:tracks="files.tracks.items"
|
||||
:expression="play_expression"
|
||||
:show_icon="true"
|
||||
/>
|
||||
|
||||
<modal-dialog-directory
|
||||
:show="show_directory_details_modal"
|
||||
:directory="selected_directory"
|
||||
@close="show_directory_details_modal = false"
|
||||
/>
|
||||
<list-tracks :tracks="files.tracks.items" :expression="play_expression" :show_icon="true" />
|
||||
<modal-dialog-directory :show="show_directory_details_modal" :directory="selected_directory" @close="show_directory_details_modal = false" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</div>
|
||||
|
@ -5,39 +5,26 @@
|
||||
<index-button-list :index="albums_list.indexList" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ genre.name }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="genre.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
<a
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_genre_details_modal = true"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon name="dots-horizontal" size="16"
|
||||
/></span>
|
||||
<a class="button is-small is-light is-rounded" @click="show_genre_details_modal = true">
|
||||
<mdicon class="icon" name="dots-horizontal" size="16"/>
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.genre.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
{{ genre.album_count }} albums |
|
||||
<a class="has-text-link" @click="open_tracks"
|
||||
>{{ genre.track_count }} tracks</a
|
||||
>
|
||||
<span v-text="$t('page.genre.album-count', { count: genre.album_count })" />
|
||||
<a class="has-text-link" @click="open_tracks" v-text="$t('page.genre.track-count', { count: genre.track_count })" />
|
||||
</p>
|
||||
<list-albums :albums="albums_list" />
|
||||
<modal-dialog-genre
|
||||
:show="show_genre_details_modal"
|
||||
:genre="genre"
|
||||
@close="show_genre_details_modal = false"
|
||||
/>
|
||||
<modal-dialog-genre :show="show_genre_details_modal" :genre="genre" @close="show_genre_details_modal = false" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</div>
|
||||
|
@ -5,39 +5,26 @@
|
||||
<index-button-list :index="index_list" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ genre.name }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="genre.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
<a
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_genre_details_modal = true"
|
||||
>
|
||||
<span class="icon"
|
||||
><mdicon name="dots-horizontal" size="16"
|
||||
/></span>
|
||||
<a class="button is-small is-light is-rounded" @click="show_genre_details_modal = true">
|
||||
<mdicon class="icon" name="dots-horizontal" size="16"/>
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.genre.tracks.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
<a class="has-text-link" @click="open_genre"
|
||||
>{{ genre.album_count }} albums</a
|
||||
>
|
||||
| {{ genre.track_count }} tracks
|
||||
<a class="has-text-link" @click="open_genre" v-text="$t('page.genre.tracks.album-count', { count: genre.album_count })" />
|
||||
<span v-text="$t('page.genre.tracks.count', { count: genre.track_count })" />
|
||||
</p>
|
||||
<list-tracks :tracks="tracks.items" :expression="expression" />
|
||||
<modal-dialog-genre
|
||||
:show="show_genre_details_modal"
|
||||
:genre="genre"
|
||||
@close="show_genre_details_modal = false"
|
||||
/>
|
||||
<modal-dialog-genre :show="show_genre_details_modal" :genre="genre" @close="show_genre_details_modal = false" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</div>
|
||||
|
@ -1,14 +1,13 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-music />
|
||||
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :index="genres.indexList" />
|
||||
</template>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Genres</p>
|
||||
<p class="heading">{{ genres.total }} genres</p>
|
||||
<p class="title is-4" v-text="$t('page.genres.title')" />
|
||||
<p class="heading" v-text="$t('page.genres.count', { count: genres.total })" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-genres :genres="genres" />
|
||||
|
@ -2,90 +2,41 @@
|
||||
<section>
|
||||
<div v-if="now_playing.id > 0" class="fd-is-fullheight">
|
||||
<div class="fd-is-expanded">
|
||||
<cover-artwork
|
||||
:artwork_url="now_playing.artwork_url"
|
||||
:artist="now_playing.artist"
|
||||
:album="now_playing.album"
|
||||
class="fd-cover-image fd-has-action"
|
||||
@click="open_dialog(now_playing)"
|
||||
/>
|
||||
<cover-artwork :artwork_url="now_playing.artwork_url" :artist="now_playing.artist" :album="now_playing.album" class="fd-cover-image fd-has-action" @click="open_dialog(now_playing)" />
|
||||
</div>
|
||||
<div class="fd-has-padding-left-right">
|
||||
<div class="container has-text-centered">
|
||||
<p class="control has-text-centered fd-progress-now-playing">
|
||||
<Slider
|
||||
ref="slider"
|
||||
v-model="item_progress_ms"
|
||||
:min="0"
|
||||
:max="state.item_length_ms"
|
||||
:step="1000"
|
||||
:tooltips="false"
|
||||
:disabled="state.state === 'stop'"
|
||||
:classes="{ target: 'seek-slider' }"
|
||||
@change="seek"
|
||||
@start="start_dragging"
|
||||
@end="end_dragging"
|
||||
/>
|
||||
<!--range-slider
|
||||
class="seek-slider fd-has-action"
|
||||
min="0"
|
||||
:max="state.item_length_ms"
|
||||
:value="item_progress_ms"
|
||||
:disabled="state.state === 'stop'"
|
||||
step="1000"
|
||||
@change="seek" >
|
||||
</range-slider-->
|
||||
<Slider ref="slider" v-model="item_progress_ms" :min="0" :max="state.item_length_ms" :step="1000" :tooltips="false" :disabled="state.state === 'stop'" :classes="{ target: 'seek-slider' }" @change="seek" @start="start_dragging" @end="end_dragging" />
|
||||
</p>
|
||||
<p class="content">
|
||||
<span
|
||||
>{{ $filters.durationInHours(item_progress_ms) }} /
|
||||
{{ $filters.durationInHours(now_playing.length_ms) }}</span
|
||||
>
|
||||
<span v-text="[$filters.durationInHours(item_progress_ms), $filters.durationInHours(now_playing.length_ms)].join(' / ')" />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fd-has-padding-left-right">
|
||||
<div class="container has-text-centered fd-has-margin-top">
|
||||
<h1 class="title is-5">
|
||||
{{ now_playing.title }}
|
||||
</h1>
|
||||
<h2 class="title is-6">
|
||||
{{ now_playing.artist }}
|
||||
</h2>
|
||||
<h2
|
||||
v-if="composer"
|
||||
class="subtitle is-6 has-text-grey has-text-weight-bold"
|
||||
>
|
||||
{{ composer }}
|
||||
</h2>
|
||||
<h3 class="subtitle is-6">
|
||||
{{ now_playing.album }}
|
||||
</h3>
|
||||
<h1 class="title is-5" v-text="now_playing.title" />
|
||||
<h2 class="title is-6" v-text="now_playing.artist" />
|
||||
<h2 v-if="composer" class="subtitle is-6 has-text-grey has-text-weight-bold" v-text="composer" />
|
||||
<h3 class="subtitle is-6" v-text="now_playing.album" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="fd-is-fullheight">
|
||||
<div
|
||||
class="fd-is-expanded fd-has-padding-left-right"
|
||||
style="flex-direction: column"
|
||||
>
|
||||
<div class="fd-is-expanded fd-has-padding-left-right" style="flex-direction: column">
|
||||
<div class="content has-text-centered">
|
||||
<h1 class="title is-5">Your play queue is empty</h1>
|
||||
<p>Add some tracks by browsing your library</p>
|
||||
<h1 class="title is-5" v-text="$('page.now-playing.title')" />
|
||||
<p v-text="$('page.now-playing.info')" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<modal-dialog-queue-item
|
||||
:show="show_details_modal"
|
||||
:item="selected_item"
|
||||
@close="show_details_modal = false"
|
||||
/>
|
||||
<modal-dialog-queue-item :show="show_details_modal" :item="selected_item" @close="show_details_modal = false" />
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ModalDialogQueueItem from '@/components/ModalDialogQueueItem.vue'
|
||||
//import RangeSlider from 'vue-range-slider'
|
||||
import Slider from '@vueform/slider'
|
||||
import CoverArtwork from '@/components/CoverArtwork.vue'
|
||||
import webapi from '@/webapi'
|
||||
@ -95,7 +46,6 @@ export default {
|
||||
name: 'PageNowPlaying',
|
||||
components: {
|
||||
ModalDialogQueueItem,
|
||||
// RangeSlider,
|
||||
Slider,
|
||||
CoverArtwork
|
||||
},
|
||||
|
@ -1,33 +1,23 @@
|
||||
<template>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">
|
||||
{{ playlist.name }}
|
||||
</div>
|
||||
<div class="title is-4" v-text="playlist.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
<a
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_playlist_details_modal = true"
|
||||
>
|
||||
<span class="icon"><mdicon name="dots-horizontal" size="16" /></span>
|
||||
<a class="button is-small is-light is-rounded" @click="show_playlist_details_modal = true">
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.playlist.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">{{ tracks.length }} tracks</p>
|
||||
<p class="heading has-text-centered-mobile" v-text="$t('page.playlist.length', { length: tracks.length })" />
|
||||
<list-tracks :tracks="tracks" :uris="uris" />
|
||||
<modal-dialog-playlist
|
||||
:show="show_playlist_details_modal"
|
||||
:playlist="playlist"
|
||||
:uris="uris"
|
||||
@close="show_playlist_details_modal = false"
|
||||
/>
|
||||
<modal-dialog-playlist :show="show_playlist_details_modal" :playlist="playlist" :uris="uris" @close="show_playlist_details_modal = false" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</template>
|
||||
|
@ -1,10 +1,8 @@
|
||||
<template>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ playlist.name }}
|
||||
</p>
|
||||
<p class="heading">{{ playlists.count }} playlists</p>
|
||||
<p class="title is-4" v-text="playlist.name" />
|
||||
<p class="heading" v-text="$t('page.playlists.count', { count: playlists.count })" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-playlists :playlists="playlists" />
|
||||
|
@ -1,57 +1,29 @@
|
||||
<template>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">
|
||||
{{ album.name }}
|
||||
</div>
|
||||
<div class="title is-4" v-text="album.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
<a
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_album_details_modal = true"
|
||||
>
|
||||
<span class="icon"><mdicon name="dots-horizontal" size="16" /></span>
|
||||
<a class="button is-small is-light is-rounded" @click="show_album_details_modal = true">
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon">
|
||||
<mdicon name="play" size="16" />
|
||||
</span>
|
||||
<span>Play</span>
|
||||
<mdicon class="icon" name="play" size="16" />
|
||||
<span v-text="$t('page.podcast.play')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
{{ album.track_count }} tracks
|
||||
</p>
|
||||
<list-tracks
|
||||
:tracks="tracks"
|
||||
:show_progress="true"
|
||||
@play-count-changed="reload_tracks"
|
||||
/>
|
||||
<modal-dialog-album
|
||||
:show="show_album_details_modal"
|
||||
:album="album"
|
||||
:media_kind="'podcast'"
|
||||
:new_tracks="new_tracks"
|
||||
@close="show_album_details_modal = false"
|
||||
@play-count-changed="reload_tracks"
|
||||
@remove-podcast="open_remove_podcast_dialog"
|
||||
/>
|
||||
<modal-dialog
|
||||
:show="show_remove_podcast_modal"
|
||||
title="Remove podcast"
|
||||
delete_action="Remove"
|
||||
@close="show_remove_podcast_modal = false"
|
||||
@delete="remove_podcast"
|
||||
>
|
||||
<p class="heading has-text-centered-mobile" v-text="$t('page.podcast.track-count', { count: album.track_count })" />
|
||||
<list-tracks :tracks="tracks" :show_progress="true" @play-count-changed="reload_tracks" />
|
||||
<modal-dialog-album :show="show_album_details_modal" :album="album" :media_kind="'podcast'" :new_tracks="new_tracks" @close="show_album_details_modal = false" @play-count-changed="reload_tracks" @remove-podcast="open_remove_podcast_dialog" />
|
||||
<modal-dialog :show="show_remove_podcast_modal" title="Remove podcast" delete_action="Remove" @close="show_remove_podcast_modal = false" @delete="remove_podcast">
|
||||
<template #modal-content>
|
||||
<p>Permanently remove this podcast from your library?</p>
|
||||
<p v-text="$t('page.podcast.remove-info-1')" />
|
||||
<p class="is-size-7">
|
||||
(This will also remove the RSS playlist
|
||||
<b>{{ rss_playlist_to_remove.name }}</b
|
||||
>.)
|
||||
(<span v-text="$t('page.podcast.remove-info-2')" />
|
||||
<b v-text="rss_playlist_to_remove.name" />)
|
||||
</p>
|
||||
</template>
|
||||
</modal-dialog>
|
||||
@ -131,7 +103,7 @@ export default {
|
||||
const rssPlaylists = data.items.filter((pl) => pl.type === 'rss')
|
||||
if (rssPlaylists.length !== 1) {
|
||||
this.$store.dispatch('add_notification', {
|
||||
text: 'Podcast cannot be removed. Probably it was not added as an RSS playlist.',
|
||||
text: this.$t('page.podcast.remove-error'),
|
||||
type: 'danger'
|
||||
})
|
||||
return
|
||||
|
@ -2,59 +2,40 @@
|
||||
<div>
|
||||
<content-with-heading v-if="new_episodes.items.length > 0">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">New episodes</p>
|
||||
<p class="title is-4" v-text="$t('page.podcasts.new-episodes')" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
<a class="button is-small" @click="mark_all_played">
|
||||
<span class="icon">
|
||||
<mdicon name="pencil" size="16" />
|
||||
</span>
|
||||
<span>Mark All Played</span>
|
||||
<mdicon class="icon" name="pencil" size="16" />
|
||||
<span v-text="$t('page.podcasts.mark-all-played')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-tracks
|
||||
:tracks="new_episodes.items"
|
||||
:show_progress="true"
|
||||
@play-count-changed="reload_new_episodes"
|
||||
/>
|
||||
<list-tracks :tracks="new_episodes.items" :show_progress="true" @play-count-changed="reload_new_episodes" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Podcasts</p>
|
||||
<p class="heading">{{ albums.total }} podcasts</p>
|
||||
<p class="title is-4" v-text="$t('page.podcasts.title')" />
|
||||
<p class="heading" v-text="$t('page.podcasts.count', { count: albums.total })" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
<a v-if="rss.tracks > 0" class="button is-small" @click="update_rss">
|
||||
<span class="icon">
|
||||
<mdicon name="refresh" size="16" />
|
||||
</span>
|
||||
<span>Update</span>
|
||||
<mdicon class="icon" name="refresh" size="16" />
|
||||
<span v-text="$t('page.podcasts.update')" />
|
||||
</a>
|
||||
<a class="button is-small" @click="open_add_podcast_dialog">
|
||||
<span class="icon">
|
||||
<mdicon name="rss" size="16" />
|
||||
</span>
|
||||
<span>Add Podcast</span>
|
||||
<mdicon class="icon" name="rss" size="16" />
|
||||
<span v-text="$t('page.podcasts.add')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums
|
||||
:albums="albums"
|
||||
@play-count-changed="reload_new_episodes()"
|
||||
@podcast-deleted="reload_podcasts()"
|
||||
/>
|
||||
<modal-dialog-add-rss
|
||||
:show="show_url_modal"
|
||||
@close="show_url_modal = false"
|
||||
@podcast-added="reload_podcasts()"
|
||||
/>
|
||||
<list-albums :albums="albums" @play-count-changed="reload_new_episodes()" @podcast-deleted="reload_podcasts()" />
|
||||
<modal-dialog-add-rss :show="show_url_modal" @close="show_url_modal = false" @podcast-added="reload_podcasts()" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</div>
|
||||
|
@ -1,103 +1,51 @@
|
||||
<template>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="heading">{{ queue.count }} tracks</p>
|
||||
<p class="title is-4">Queue</p>
|
||||
<p class="title is-4" v-text="$t('page.queue.title')" />
|
||||
<p class="heading" v-text="$t('page.queue.count', { count: queue.count })" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
<a
|
||||
class="button is-small"
|
||||
:class="{ 'is-info': show_only_next_items }"
|
||||
@click="update_show_next_items"
|
||||
>
|
||||
<span class="icon">
|
||||
<mdicon name="arrow-collapse-down" size="16" />
|
||||
</span>
|
||||
<span>Hide previous</span>
|
||||
<a class="button is-small" :class="{ 'is-info': show_only_next_items }" @click="update_show_next_items">
|
||||
<mdicon class="icon" name="arrow-collapse-down" size="16" />
|
||||
<span v-text="$t('page.queue.hide-previous')" />
|
||||
</a>
|
||||
<a class="button is-small" @click="open_add_stream_dialog">
|
||||
<span class="icon">
|
||||
<mdicon name="web" size="16" />
|
||||
</span>
|
||||
<span>Add Stream</span>
|
||||
<mdicon class="icon" name="web" size="16" />
|
||||
<span v-text="$t('page.queue.add-stream')" />
|
||||
</a>
|
||||
<a
|
||||
class="button is-small"
|
||||
:class="{ 'is-info': edit_mode }"
|
||||
@click="edit_mode = !edit_mode"
|
||||
>
|
||||
<span class="icon">
|
||||
<mdicon name="pencil" size="16" />
|
||||
</span>
|
||||
<span>Edit</span>
|
||||
<a class="button is-small" :class="{ 'is-info': edit_mode }" @click="edit_mode = !edit_mode">
|
||||
<mdicon class="icon" name="pencil" size="16" />
|
||||
<span v-text="$t('page.queue.edit')" />
|
||||
</a>
|
||||
<a class="button is-small" @click="queue_clear">
|
||||
<span class="icon">
|
||||
<mdicon name="delete-empty" size="16" />
|
||||
</span>
|
||||
<span>Clear</span>
|
||||
<mdicon class="icon" name="delete-empty" size="16" />
|
||||
<span v-text="$t('page.queue.clear')" />
|
||||
</a>
|
||||
<a
|
||||
v-if="is_queue_save_allowed"
|
||||
class="button is-small"
|
||||
:disabled="queue_items.length === 0"
|
||||
@click="save_dialog"
|
||||
>
|
||||
<span class="icon">
|
||||
<mdicon name="content-save" size="16" />
|
||||
</span>
|
||||
<span>Save</span>
|
||||
<a v-if="is_queue_save_allowed" class="button is-small" :disabled="queue_items.length === 0" @click="save_dialog">
|
||||
<mdicon class="icon" name="content-save" size="16" />
|
||||
<span v-text="$t('page.queue.save')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<draggable
|
||||
v-model="queue_items"
|
||||
handle=".handle"
|
||||
item-key="id"
|
||||
@end="move_item"
|
||||
>
|
||||
<draggable v-model="queue_items" handle=".handle" item-key="id" @end="move_item">
|
||||
<template #item="{ element, index }">
|
||||
<list-item-queue-item
|
||||
:item="element"
|
||||
:position="index"
|
||||
:current_position="current_position"
|
||||
:show_only_next_items="show_only_next_items"
|
||||
:edit_mode="edit_mode"
|
||||
>
|
||||
<list-item-queue-item :item="element" :position="index" :current_position="current_position" :show_only_next_items="show_only_next_items" :edit_mode="edit_mode">
|
||||
<template #actions>
|
||||
<a v-if="!edit_mode" @click.prevent.stop="open_dialog(element)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16"/>
|
||||
</a>
|
||||
<a
|
||||
v-if="element.id !== state.item_id && edit_mode"
|
||||
@click.prevent.stop="remove(element)"
|
||||
>
|
||||
<span class="icon has-text-grey"
|
||||
><mdicon name="delete" size="18"
|
||||
/></span>
|
||||
<a v-if="element.id !== state.item_id && edit_mode" @click.prevent.stop="remove(element)">
|
||||
<mdicon class="icon has-text-grey" name="delete" size="18"/>
|
||||
</a>
|
||||
</template>
|
||||
</list-item-queue-item>
|
||||
</template>
|
||||
</draggable>
|
||||
<modal-dialog-queue-item
|
||||
:show="show_details_modal"
|
||||
:item="selected_item"
|
||||
@close="show_details_modal = false"
|
||||
/>
|
||||
<modal-dialog-add-url-stream
|
||||
:show="show_url_modal"
|
||||
@close="show_url_modal = false"
|
||||
/>
|
||||
<modal-dialog-playlist-save
|
||||
v-if="is_queue_save_allowed"
|
||||
:show="show_pls_save_modal"
|
||||
@close="show_pls_save_modal = false"
|
||||
/>
|
||||
<modal-dialog-queue-item :show="show_details_modal" :item="selected_item" @close="show_details_modal = false" />
|
||||
<modal-dialog-add-url-stream :show="show_url_modal" @close="show_url_modal = false" />
|
||||
<modal-dialog-playlist-save v-if="is_queue_save_allowed" :show="show_pls_save_modal" @close="show_pls_save_modal = false" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</template>
|
||||
|
@ -2,12 +2,10 @@
|
||||
<div>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Radio</p>
|
||||
<p class="title is-4" v-text="$t('page.radio.title')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
{{ tracks.total }} tracks
|
||||
</p>
|
||||
<p class="heading has-text-centered-mobile" v-text="$t('page.radio.count', { count: tracks.total })" />
|
||||
<list-tracks :tracks="tracks.items" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
|
@ -8,49 +8,26 @@
|
||||
<form @submit.prevent="new_search">
|
||||
<div class="field">
|
||||
<p class="control is-expanded has-icons-left">
|
||||
<input
|
||||
ref="search_field"
|
||||
v-model="search_query"
|
||||
class="input is-rounded is-shadowless"
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<span class="icon is-left">
|
||||
<mdicon name="magnify" size="16" />
|
||||
</span>
|
||||
<input ref="search_field" v-model="search_query" class="input is-rounded is-shadowless" type="text" placeholder="Search" autocomplete="off" />
|
||||
<mdicon class="icon is-left" name="magnify" size="16" />
|
||||
</p>
|
||||
<p class="help has-text-centered">
|
||||
Tip: you can search by a smart playlist query language
|
||||
<a
|
||||
href="https://github.com/owntone/owntone-server/blob/master/README_SMARTPL.md"
|
||||
target="_blank"
|
||||
>expression</a
|
||||
>
|
||||
if you prefix it with <code>query:</code>.
|
||||
<span v-html="$t('page.search.help')" />
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
<div class="tags" style="margin-top: 16px">
|
||||
<a
|
||||
v-for="recent_search in recent_searches"
|
||||
:key="recent_search"
|
||||
class="tag"
|
||||
@click="open_recent_search(recent_search)"
|
||||
>{{ recent_search }}</a
|
||||
>
|
||||
<a v-for="recent_search in recent_searches" :key="recent_search" class="tag" @click="open_recent_search(recent_search)" v-text="recent_search" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<tabs-search :query="search_query" />
|
||||
|
||||
<!-- Tracks -->
|
||||
<content-with-heading v-if="show_tracks && tracks.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Tracks</p>
|
||||
<p class="title is-4" v-text="$t('page.search.tracks')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-tracks :tracks="tracks.items" />
|
||||
@ -58,25 +35,20 @@
|
||||
<template #footer>
|
||||
<nav v-if="show_all_tracks_button" class="level">
|
||||
<p class="level-item">
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_tracks"
|
||||
>Show all {{ tracks.total.toLocaleString() }} tracks</a
|
||||
>
|
||||
<a class="button is-light is-small is-rounded" @click="open_search_tracks" v-text="$t('page.search.show.tracks', { count: tracks.total.toLocaleString() })" />
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_tracks && !tracks.total" class="mt-6">
|
||||
<template #content>
|
||||
<p><i>No tracks found</i></p>
|
||||
<p><i v-text="$t('page.search.no-tracks')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
|
||||
<!-- Artists -->
|
||||
<content-with-heading v-if="show_artists && artists.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Artists</p>
|
||||
<p class="title is-4" v-text="$t('page.search.artists')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-artists :artists="artists" :hide_group_title="true" />
|
||||
@ -84,25 +56,20 @@
|
||||
<template #footer>
|
||||
<nav v-if="show_all_artists_button" class="level">
|
||||
<p class="level-item">
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_artists"
|
||||
>Show all {{ artists.total.toLocaleString() }} artists</a
|
||||
>
|
||||
<a class="button is-light is-small is-rounded" @click="open_search_artists" v-text="$t('page.search.show.artists', { count:artists.total.toLocaleString() })" />
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_artists && !artists.total">
|
||||
<template #content>
|
||||
<p><i>No artists found</i></p>
|
||||
<p><i v-text="$t('page.search.no-artists')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
|
||||
<!-- Albums -->
|
||||
<content-with-heading v-if="show_albums && albums.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Albums</p>
|
||||
<p class="title is-4" v-text="$t('page.search.albums')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums :albums="albums" :hide_group_title="true" />
|
||||
@ -110,25 +77,20 @@
|
||||
<template #footer>
|
||||
<nav v-if="show_all_albums_button" class="level">
|
||||
<p class="level-item">
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_albums"
|
||||
>Show all {{ albums.total.toLocaleString() }} albums</a
|
||||
>
|
||||
<a class="button is-light is-small is-rounded" @click="open_search_albums" v-text="$t('page.search.show-albums', { count: albums.total.toLocaleString()})" />
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_albums && !albums.total">
|
||||
<template #content>
|
||||
<p><i>No albums found</i></p>
|
||||
<p><i v-text="$t('page.search.no-albums')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
|
||||
<!-- Composers -->
|
||||
<content-with-heading v-if="show_composers && composers.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Composers</p>
|
||||
<p class="title is-4" v-text="$t('page.search.composers')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-composers :composers="composers" />
|
||||
@ -136,25 +98,20 @@
|
||||
<template #footer>
|
||||
<nav v-if="show_all_composers_button" class="level">
|
||||
<p class="level-item">
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_composers"
|
||||
>Show all {{ composers.total.toLocaleString() }} composers</a
|
||||
>
|
||||
<a class="button is-light is-small is-rounded" @click="open_search_composers" v-text="$t('page.search.show.composers', { count: composers.total.toLocaleString() })" />
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_composers && !composers.total">
|
||||
<template #content>
|
||||
<p><i>No composers found</i></p>
|
||||
<p><i v-text="$t('page.search.no-composers')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
|
||||
<!-- Playlists -->
|
||||
<content-with-heading v-if="show_playlists && playlists.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Playlists</p>
|
||||
<p class="title is-4" v-text="$t('page.search.playlists')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-playlists :playlists="playlists" />
|
||||
@ -162,25 +119,20 @@
|
||||
<template #footer>
|
||||
<nav v-if="show_all_playlists_button" class="level">
|
||||
<p class="level-item">
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_playlists"
|
||||
>Show all {{ playlists.total.toLocaleString() }} playlists</a
|
||||
>
|
||||
<a class="button is-light is-small is-rounded" @click="open_search_playlists" v-text="$t('page.search.show.playlists', { count: playlists.total.toLocaleString() })" />
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_playlists && !playlists.total">
|
||||
<template #content>
|
||||
<p><i>No playlists found</i></p>
|
||||
<p><i v-text="$t('page.search.no-playlists')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
|
||||
<!-- Podcasts -->
|
||||
<content-with-heading v-if="show_podcasts && podcasts.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Podcasts</p>
|
||||
<p class="title is-4" v-text="$t('page.search.podcasts')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums :albums="podcasts" />
|
||||
@ -188,25 +140,21 @@
|
||||
<template #footer>
|
||||
<nav v-if="show_all_podcasts_button" class="level">
|
||||
<p class="level-item">
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_podcasts"
|
||||
>Show all {{ podcasts.total.toLocaleString() }} podcasts</a
|
||||
>
|
||||
<a class="button is-light is-small is-rounded" @click="open_search_podcasts" v-text="$t('page.search.show.podcasts', { count: podcasts.total.toLocaleString() })" />
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_podcasts && !podcasts.total">
|
||||
<template #content>
|
||||
<p><i>No podcasts found</i></p>
|
||||
<p><i v-text="$t('page.search.no-podcasts')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
|
||||
<!-- Audiobooks -->
|
||||
<content-with-heading v-if="show_audiobooks && audiobooks.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Audiobooks</p>
|
||||
<p class="title is-4" v-text="$t('page.search.audiobooks')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<list-albums :albums="audiobooks" />
|
||||
@ -214,18 +162,14 @@
|
||||
<template #footer>
|
||||
<nav v-if="show_all_audiobooks_button" class="level">
|
||||
<p class="level-item">
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_audiobooks"
|
||||
>Show all {{ audiobooks.total.toLocaleString() }} audiobooks</a
|
||||
>
|
||||
<a class="button is-light is-small is-rounded" @click="open_search_audiobooks" v-text="$t('page.search.show.audiobooks', { count: audiobooks.total.toLocaleString() })" />
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_audiobooks && !audiobooks.total">
|
||||
<template #content>
|
||||
<p><i>No audiobooks found</i></p>
|
||||
<p><i v-text="$t('page.search.no-audiobooks')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
</div>
|
||||
@ -260,7 +204,6 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
search_query: '',
|
||||
|
||||
tracks: { items: [], total: 0 },
|
||||
artists: new GroupByList(),
|
||||
albums: new GroupByList(),
|
||||
|
@ -1,49 +1,35 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-settings />
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">Artwork</div>
|
||||
<div class="title is-4" v-text="$t('page.settings.artwork.artwork')" />
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<div class="content">
|
||||
<p>
|
||||
OwnTone supports PNG and JPEG artwork which is either placed as
|
||||
separate image files in the library, embedded in the media files or
|
||||
made available online by radio stations.
|
||||
</p>
|
||||
<p>
|
||||
In addition to that, you can enable fetching artwork from the
|
||||
following artwork providers:
|
||||
</p>
|
||||
</div>
|
||||
<settings-checkbox
|
||||
v-if="spotify.libspotify_logged_in"
|
||||
category_name="artwork"
|
||||
option_name="use_artwork_source_spotify"
|
||||
>
|
||||
<template #label> Spotify </template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox
|
||||
category_name="artwork"
|
||||
option_name="use_artwork_source_discogs"
|
||||
>
|
||||
<div class="content" v-text="$t('page.settings.artwork.explanation-1')" />
|
||||
<div class="content" v-text="$t('page.settings.artwork.explanation-2')" />
|
||||
<settings-checkbox v-if="spotify.libspotify_logged_in" category_name="artwork" option_name="use_artwork_source_spotify">
|
||||
<template #label>
|
||||
Discogs (<a href="https://www.discogs.com/"
|
||||
>https://www.discogs.com/</a
|
||||
>)
|
||||
<span v-text="$t('page.settings.artwork.spotify')" />
|
||||
<a href="https://www.spotify.com/" target="_blank">
|
||||
<mdicon class="icon" name="open-in-new" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox
|
||||
category_name="artwork"
|
||||
option_name="use_artwork_source_coverartarchive"
|
||||
>
|
||||
<settings-checkbox category_name="artwork" option_name="use_artwork_source_discogs">
|
||||
<template #label>
|
||||
Cover Art Archive (<a href="https://coverartarchive.org/"
|
||||
>https://coverartarchive.org/</a
|
||||
>)
|
||||
<span v-text="$t('page.settings.artwork.discogs')" />
|
||||
<a href="https://www.discogs.com/" target="_blank">
|
||||
<mdicon class="icon" name="open-in-new" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox category_name="artwork" option_name="use_artwork_source_coverartarchive">
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.artwork.coverartarchive')" />
|
||||
<a href="https://coverartarchive.org/" target="_blank">
|
||||
<mdicon class="icon" name="open-in-new" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
</template>
|
||||
|
@ -1,187 +1,105 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-settings />
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">Spotify</div>
|
||||
<div class="title is-4" v-text="$t('page.settings.services.spotify.title')" />
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<div v-if="!spotify.spotify_installed" class="notification is-size-7">
|
||||
<p>
|
||||
OwnTone was either built without support for Spotify or libspotify
|
||||
is not installed.
|
||||
</p>
|
||||
<p v-text="$t('page.settings.services.spotify.no-support')" />
|
||||
</div>
|
||||
<div v-if="spotify.spotify_installed">
|
||||
<div class="notification is-size-7">
|
||||
<b>You must have a Spotify premium account</b>.
|
||||
<span v-if="use_libspotity"
|
||||
>If you normally log into Spotify with your Facebook account you
|
||||
must first go to Spotify's web site where you can get the Spotify
|
||||
username and password that matches your account.</span
|
||||
>
|
||||
<b v-text="$t('page.settings.services.spotify.requirements')" />
|
||||
<span v-if="use_libspotity" v-text="$t('page.settings.services.spotify.help')" />
|
||||
</div>
|
||||
|
||||
<div v-if="use_libspotity">
|
||||
<p class="content">
|
||||
<b>libspotify</b> - Login with your Spotify username and password
|
||||
<b v-text="$t('page.settings.services.spotify')" />
|
||||
<span v-text="$t('page.settings.services.spotify.credentials')" />
|
||||
</p>
|
||||
<p v-if="spotify.libspotify_logged_in" class="fd-has-margin-bottom">
|
||||
Logged in as
|
||||
<b
|
||||
><code>{{ spotify.libspotify_user }}</code></b
|
||||
>
|
||||
<span v-text="$t('page.settings.services.spotify.logged-as')" />
|
||||
<b><code v-text="spotify.libspotify_user" /></b>
|
||||
</p>
|
||||
<form
|
||||
v-if="spotify.spotify_installed && !spotify.libspotify_logged_in"
|
||||
@submit.prevent="login_libspotify"
|
||||
>
|
||||
<form v-if="spotify.spotify_installed && !spotify.libspotify_logged_in" @submit.prevent="login_libspotify">
|
||||
<div class="field is-grouped">
|
||||
<div class="control is-expanded">
|
||||
<input
|
||||
v-model="libspotify.user"
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
/>
|
||||
<p class="help is-danger">
|
||||
{{ libspotify.errors.user }}
|
||||
</p>
|
||||
<input v-model="libspotify.user" class="input" type="text" placeholder="Username" />
|
||||
<p class="help is-danger" v-text="libspotify.errors.user" />
|
||||
</div>
|
||||
<div class="control is-expanded">
|
||||
<input
|
||||
v-model="libspotify.password"
|
||||
class="input"
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
/>
|
||||
<p class="help is-danger">
|
||||
{{ libspotify.errors.password }}
|
||||
</p>
|
||||
<input v-model="libspotify.password" class="input" type="password" placeholder="Password" />
|
||||
<p class="help is-danger" v-text="libspotify.errors.password" />
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button is-info">Login</button>
|
||||
<button class="button is-info" v-text="$t('page.settings.services.login')" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<p class="help is-danger">
|
||||
{{ libspotify.errors.error }}
|
||||
</p>
|
||||
<p class="help">
|
||||
libspotify enables OwnTone to play Spotify tracks.
|
||||
</p>
|
||||
<p class="help">
|
||||
OwnTone will not store your password, but will still be able to
|
||||
log you in automatically afterwards, because libspotify saves a
|
||||
login token.
|
||||
</p>
|
||||
<p class="help is-danger" v-text="libspotify.errors.error" />
|
||||
<p class="help" v-text="$t('page.settings.services.spotify.help-1')" />
|
||||
<p class="help" v-text="$t('page.settings.services.spotify.help-2')" />
|
||||
</div>
|
||||
|
||||
<div class="fd-has-margin-top">
|
||||
<p class="content">
|
||||
<b>Spotify Web API</b> - Grant access to the Spotify Web API
|
||||
</p>
|
||||
<p class="content" v-html="$t('page.settings.services.spotify.grant-access')" />
|
||||
<p v-if="spotify.webapi_token_valid">
|
||||
Access granted for
|
||||
<b
|
||||
><code>{{ spotify.webapi_user }}</code></b
|
||||
>
|
||||
<span v-text="$t('page.settings.services.spotify.user')" />
|
||||
<code v-text="spotify.webapi_user" />
|
||||
</p>
|
||||
<p v-if="spotify_missing_scope.length > 0" class="help is-danger">
|
||||
Please reauthorize Web API access to grant OwnTone the following
|
||||
additional access rights:
|
||||
<b
|
||||
><code>{{ spotify_missing_scope.join() }}</code></b
|
||||
>
|
||||
<span v-text="$t('page.settings.services.spotify.reauthorize')" />
|
||||
<code v-text="spotify_missing_scope.join()" />
|
||||
</p>
|
||||
<div class="field fd-has-margin-top">
|
||||
<div class="control">
|
||||
<a
|
||||
class="button"
|
||||
:class="{
|
||||
'is-info':
|
||||
!spotify.webapi_token_valid ||
|
||||
spotify_missing_scope.length > 0
|
||||
}"
|
||||
:href="spotify.oauth_uri"
|
||||
>Authorize Web API access</a
|
||||
>
|
||||
<a class="button" :class="{ 'is-info': !spotify.webapi_token_valid || spotify_missing_scope.length > 0 }" :href="spotify.oauth_uri" v-text="$t('page.settings.services.spotify.authorize')" />
|
||||
</div>
|
||||
</div>
|
||||
<p class="help">
|
||||
Access to the Spotify Web API enables scanning of your Spotify
|
||||
library. Required scopes are
|
||||
<code>{{ spotify_required_scope.join() }}</code
|
||||
>.
|
||||
<span v-text="$t('page.settings.services.spotify.scopes')" />
|
||||
<code v-text="spotify_required_scope.join()" />
|
||||
</p>
|
||||
<div
|
||||
v-if="spotify.webapi_token_valid"
|
||||
class="field fd-has-margin-top"
|
||||
>
|
||||
<div v-if="spotify.webapi_token_valid" class="field fd-has-margin-top">
|
||||
<div class="control">
|
||||
<a class="button is-danger" @click="logout_spotify">Logout</a>
|
||||
<a class="button is-danger" @click="logout_spotify" v-text="$t('page.settings.services.logout')" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">Last.fm</div>
|
||||
<div class="title is-4" v-text="$t('page.settings.services.lastfm.title')" />
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<div v-if="!lastfm.enabled" class="notification is-size-7">
|
||||
<p>OwnTone was built without support for Last.fm.</p>
|
||||
<p v-text="$t('page.settings.services.lastfm.no-support')" />
|
||||
</div>
|
||||
<div v-if="lastfm.enabled">
|
||||
<p class="content">
|
||||
<b>Last.fm</b> - Login with your Last.fm username and password to
|
||||
enable scrobbling
|
||||
</p>
|
||||
<p class="content" v-html="$t('page.settings.services.lastfm.grant-access')" />
|
||||
<div v-if="lastfm.scrobbling_enabled">
|
||||
<a class="button" @click="logoutLastfm">Stop scrobbling</a>
|
||||
<a class="button" @click="logoutLastfm" v-text="$t('page.settings.services.lastfm.stop-scrobbling')" />
|
||||
</div>
|
||||
<div v-if="!lastfm.scrobbling_enabled">
|
||||
<form @submit.prevent="login_lastfm">
|
||||
<div class="field is-grouped">
|
||||
<div class="control is-expanded">
|
||||
<input
|
||||
v-model="lastfm_login.user"
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
/>
|
||||
<p class="help is-danger">
|
||||
{{ lastfm_login.errors.user }}
|
||||
</p>
|
||||
<input v-model="lastfm_login.user" class="input" type="text" placeholder="Username" />
|
||||
<p class="help is-danger" v-text="lastfm_login.errors.user" />
|
||||
</div>
|
||||
<div class="control is-expanded">
|
||||
<input
|
||||
v-model="lastfm_login.password"
|
||||
class="input"
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
/>
|
||||
<p class="help is-danger">
|
||||
{{ lastfm_login.errors.password }}
|
||||
</p>
|
||||
<input v-model="lastfm_login.password" class="input" type="password" placeholder="Password" />
|
||||
<p class="help is-danger" v-text="lastfm_login.errors.password" />
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button is-info" type="submit">Login</button>
|
||||
<button class="button is-info" type="submit" v-text="$t('page.settings.services.login')" />
|
||||
</div>
|
||||
</div>
|
||||
<p class="help is-danger">
|
||||
{{ lastfm_login.errors.error }}
|
||||
</p>
|
||||
<p class="help">
|
||||
OwnTone will not store your Last.fm username/password, only the
|
||||
session key. The session key does not expire.
|
||||
</p>
|
||||
<p class="help is-danger" v-text="lastfm_login.errors.error" />
|
||||
<p class="help" v-text="$t('page.settings.services.lastfm.info')" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,81 +1,53 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-settings />
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">Remote Pairing</div>
|
||||
<div class="title is-4" v-text="$t('page.settings.devices.pairing')" />
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<!-- Paring request active -->
|
||||
<div v-if="pairing.active" class="notification">
|
||||
<form @submit.prevent="kickoff_pairing">
|
||||
<label class="label has-text-weight-normal">
|
||||
Remote pairing request from <b>{{ pairing.remote }}</b>
|
||||
</label>
|
||||
<label class="label has-text-weight-normal" v-html="$t('page.settings.devices.pairing-request', { remote: pairing.remote})" />
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<input
|
||||
v-model="pairing_req.pin"
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder="Enter pairing code"
|
||||
/>
|
||||
<input v-model="pairing_req.pin" class="input" type="text" placeholder="Enter pairing code" />
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button is-info" type="submit">Send</button>
|
||||
<button class="button is-info" type="submit" v-text="$t('page.settings.devices.send')" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<!-- No pairing requests -->
|
||||
<div v-if="!pairing.active" class="content">
|
||||
<p>No active pairing request.</p>
|
||||
<p v-text="$t('page.settings.devices.no-active-pairing')" />
|
||||
</div>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">Speaker pairing and device verification</div>
|
||||
<div class="title is-4" v-text="$t('page.settings.devices.speaker-pairing')" />
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<p class="content">
|
||||
If your speaker requires pairing then activate it below and enter the
|
||||
PIN that it displays.
|
||||
</p>
|
||||
|
||||
<p class="content" v-text="$t('page.settings.devices.speaker-pairing-info')" />
|
||||
<div v-for="output in outputs" :key="output.id">
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<label class="checkbox">
|
||||
<input
|
||||
v-model="output.selected"
|
||||
type="checkbox"
|
||||
@change="output_toggle(output.id)"
|
||||
/>
|
||||
{{ output.name }}
|
||||
<input v-model="output.selected" type="checkbox" style="margin-right: 5px" @change="output_toggle(output.id)"/>
|
||||
<span v-text="output.name" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<form
|
||||
v-if="output.needs_auth_key"
|
||||
class="fd-has-margin-bottom"
|
||||
@submit.prevent="kickoff_verification(output.id)"
|
||||
>
|
||||
<form v-if="output.needs_auth_key" class="fd-has-margin-bottom" @submit.prevent="kickoff_verification(output.id)">
|
||||
<div class="field is-grouped">
|
||||
<div class="control">
|
||||
<input
|
||||
v-model="verification_req.pin"
|
||||
class="input"
|
||||
type="text"
|
||||
placeholder="Enter verification code"
|
||||
/>
|
||||
<input v-model="verification_req.pin" class="input" type="text" :placeholder="$t('page.settings.devices.verification-code')" />
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button is-info" type="submit">Verify</button>
|
||||
<button class="button is-info" type="submit" v-text="$t('page.settings.devices.verify')" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -1,130 +1,103 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-settings />
|
||||
|
||||
<content-with-heading>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">Navbar items</div>
|
||||
<div class="title is-4" v-text="$t('page.settings.general.language')" />
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<p class="content">Select the top navigation bar menu items</p>
|
||||
<div class="notification is-size-7">
|
||||
If you select more items than can be shown on your screen then the
|
||||
burger menu will disappear.
|
||||
</div>
|
||||
<settings-checkbox
|
||||
category_name="webinterface"
|
||||
option_name="show_menu_item_playlists"
|
||||
>
|
||||
<template #label> Playlists </template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox
|
||||
category_name="webinterface"
|
||||
option_name="show_menu_item_music"
|
||||
>
|
||||
<template #label> Music </template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox
|
||||
category_name="webinterface"
|
||||
option_name="show_menu_item_podcasts"
|
||||
>
|
||||
<template #label> Podcasts </template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox
|
||||
category_name="webinterface"
|
||||
option_name="show_menu_item_audiobooks"
|
||||
>
|
||||
<template #label> Audiobooks </template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox
|
||||
category_name="webinterface"
|
||||
option_name="show_menu_item_radio"
|
||||
>
|
||||
<template #label> Radio </template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox
|
||||
category_name="webinterface"
|
||||
option_name="show_menu_item_files"
|
||||
>
|
||||
<template #label> Files </template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox
|
||||
category_name="webinterface"
|
||||
option_name="show_menu_item_search"
|
||||
>
|
||||
<template #label> Search </template>
|
||||
</settings-checkbox>
|
||||
<dropdown-menu v-model="locale" :options="locales" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">Album lists</div>
|
||||
<div class="title is-4" v-text="$t('page.settings.general.navigation-items')" />
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<settings-checkbox
|
||||
category_name="webinterface"
|
||||
option_name="show_cover_artwork_in_album_lists"
|
||||
>
|
||||
<template #label> Show cover artwork in album list </template>
|
||||
</settings-checkbox>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">Now playing page</div>
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<settings-checkbox
|
||||
category_name="webinterface"
|
||||
option_name="show_composer_now_playing"
|
||||
>
|
||||
<template #label> Show composer </template>
|
||||
<template #info>
|
||||
If enabled the composer of the current playing track is shown on the
|
||||
"now playing page"
|
||||
<p class="content" v-text="$t('page.settings.general.navigation-item-selection')" />
|
||||
<div class="notification is-size-7" v-text="$t('page.settings.general.navigation-item-selection-info')" />
|
||||
<settings-checkbox category_name="webinterface" option_name="show_menu_item_playlists">
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.playlists')" />
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
<settings-textfield
|
||||
category_name="webinterface"
|
||||
option_name="show_composer_for_genre"
|
||||
:disabled="!settings_option_show_composer_now_playing"
|
||||
placeholder="Genres"
|
||||
>
|
||||
<template #label> Show composer only for listed genres </template>
|
||||
<settings-checkbox category_name="webinterface" option_name="show_menu_item_music">
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.music')" />
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox category_name="webinterface" option_name="show_menu_item_podcasts">
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.podcasts')" />
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox category_name="webinterface" option_name="show_menu_item_audiobooks">
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.audiobooks')" />
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox category_name="webinterface" option_name="show_menu_item_radio">
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.radio')" />
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox category_name="webinterface" option_name="show_menu_item_files">
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.files')" />
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
<settings-checkbox category_name="webinterface" option_name="show_menu_item_search">
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.search')" />
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4" v-text="$t('page.settings.general.album-lists')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<settings-checkbox category_name="webinterface" option_name="show_cover_artwork_in_album_lists">
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.show-coverart')" />
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4" v-text="$t('page.settings.general.now-playing-page')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<settings-checkbox category_name="webinterface" option_name="show_composer_now_playing">
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.show-composer')" />
|
||||
</template>
|
||||
<template #info>
|
||||
<p class="help">
|
||||
Comma separated list of genres the composer should be displayed on
|
||||
the "now playing page".
|
||||
</p>
|
||||
<p class="help">Leave empty to always show the composer.</p>
|
||||
<p class="help">
|
||||
The genre tag of the current track is matched by checking, if one
|
||||
of the defined genres are included. For example setting to
|
||||
<code>classical, soundtrack</code> will show the composer for
|
||||
tracks with a genre tag of "Contemporary Classical".<br />
|
||||
</p>
|
||||
<span v-text="$t('page.settings.general.show-composer-info')" />
|
||||
</template>
|
||||
</settings-checkbox>
|
||||
<settings-textfield category_name="webinterface" option_name="show_composer_for_genre" :disabled="!settings_option_show_composer_now_playing" placeholder="Genres">
|
||||
<template #label>
|
||||
<span v-text="$t('page.settings.general.show-composer-genres')" />
|
||||
</template>
|
||||
<template #info>
|
||||
<p class="help" v-text="$t('page.settings.general.show-composer-genres-info-1')" />
|
||||
<p class="help" v-text="$t('page.settings.general.show-composer-genres-info-2')" />
|
||||
<p class="help" v-text="$t('page.settings.general.show-composer-genres-info-3')" />
|
||||
</template>
|
||||
</settings-textfield>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">Recently added page</div>
|
||||
<div class="title is-4" v-text="$t('page.settings.general.recently-added-page')" />
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<settings-intfield
|
||||
category_name="webinterface"
|
||||
option_name="recently_added_limit"
|
||||
>
|
||||
<settings-intfield category_name="webinterface" option_name="recently_added_limit">
|
||||
<template #label>
|
||||
Limit the number of albums shown on the "Recently Added" page
|
||||
<span v-text="$t('page.settings.general.recently-added-page-info')" />
|
||||
</template>
|
||||
</settings-intfield>
|
||||
</template>
|
||||
@ -138,6 +111,7 @@ import TabsSettings from '@/components/TabsSettings.vue'
|
||||
import SettingsCheckbox from '@/components/SettingsCheckbox.vue'
|
||||
import SettingsTextfield from '@/components/SettingsTextfield.vue'
|
||||
import SettingsIntfield from '@/components/SettingsIntfield.vue'
|
||||
import DropdownMenu from '@/components/DropdownMenu.vue'
|
||||
|
||||
export default {
|
||||
name: 'SettingsPageWebinterface',
|
||||
@ -146,12 +120,28 @@ export default {
|
||||
TabsSettings,
|
||||
SettingsCheckbox,
|
||||
SettingsTextfield,
|
||||
SettingsIntfield
|
||||
SettingsIntfield,
|
||||
DropdownMenu
|
||||
},
|
||||
|
||||
computed: {
|
||||
settings_option_show_composer_now_playing() {
|
||||
return this.$store.getters.settings_option_show_composer_now_playing
|
||||
},
|
||||
locale: {
|
||||
get() {
|
||||
return this.$i18n.locale
|
||||
},
|
||||
set(locale) {
|
||||
this.$i18n.locale = locale
|
||||
}
|
||||
},
|
||||
locales: {
|
||||
get() {
|
||||
return this.$i18n.availableLocales.map((item) => {
|
||||
return { id: item, name: this.$t('language.' + item) }
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,71 +1,36 @@
|
||||
<template>
|
||||
<content-with-hero>
|
||||
<template #heading-left>
|
||||
<h1 class="title is-5">
|
||||
{{ album.name }}
|
||||
</h1>
|
||||
<h1 class="title is-5" v-text="album.name" />
|
||||
<h2 class="subtitle is-6 has-text-link has-text-weight-normal">
|
||||
<a class="has-text-link" @click="open_artist">{{
|
||||
album.artists[0].name
|
||||
}}</a>
|
||||
<a class="has-text-link" @click="open_artist" v-text="album.artists[0].name" />
|
||||
</h2>
|
||||
|
||||
<div class="buttons fd-is-centered-mobile fd-has-margin-top">
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.spotify.album.shuffle')" />
|
||||
</a>
|
||||
<a
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_album_details_modal = true"
|
||||
>
|
||||
<span class="icon"><mdicon name="dots-horizontal" size="16" /></span>
|
||||
<a class="button is-small is-light is-rounded" @click="show_album_details_modal = true">
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #heading-right>
|
||||
<p class="image is-square fd-has-shadow fd-has-action">
|
||||
<cover-artwork
|
||||
:artwork_url="artwork_url"
|
||||
:artist="album.artist"
|
||||
:album="album.name"
|
||||
@click="show_album_details_modal = true"
|
||||
/>
|
||||
<cover-artwork :artwork_url="artwork_url" :artist="album.artist" :album="album.name" @click="show_album_details_modal = true" />
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<p class="heading is-7 has-text-centered-mobile fd-has-margin-top">
|
||||
{{ album.tracks.total }} tracks
|
||||
</p>
|
||||
<spotify-list-item-track
|
||||
v-for="(track, index) in album.tracks.items"
|
||||
:key="track.id"
|
||||
:track="track"
|
||||
:position="index"
|
||||
:album="album"
|
||||
:context_uri="album.uri"
|
||||
>
|
||||
<p class="heading is-7 has-text-centered-mobile fd-has-margin-top" v-text="$t('page.spotify.album.track-count', { count: album.tracks.total })" />
|
||||
<spotify-list-item-track v-for="(track, index) in album.tracks.items" :key="track.id" :track="track" :position="index" :album="album" :context_uri="album.uri">
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_track_dialog(track)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-track>
|
||||
<spotify-modal-dialog-track
|
||||
:show="show_track_details_modal"
|
||||
:track="selected_track"
|
||||
:album="album"
|
||||
@close="show_track_details_modal = false"
|
||||
/>
|
||||
<spotify-modal-dialog-album
|
||||
:show="show_album_details_modal"
|
||||
:album="album"
|
||||
@close="show_album_details_modal = false"
|
||||
/>
|
||||
<spotify-modal-dialog-track :show="show_track_details_modal" :track="selected_track" :album="album" @close="show_track_details_modal = false" />
|
||||
<spotify-modal-dialog-album :show="show_album_details_modal" :album="album" @close="show_album_details_modal = false" />
|
||||
</template>
|
||||
</content-with-hero>
|
||||
</template>
|
||||
|
@ -1,64 +1,38 @@
|
||||
<template>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">
|
||||
{{ artist.name }}
|
||||
</p>
|
||||
<p class="title is-4" v-text="artist.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
<a
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_artist_details_modal = true"
|
||||
>
|
||||
<span class="icon"><mdicon name="dots-horizontal" size="16" /></span>
|
||||
<a class="button is-small is-light is-rounded" @click="show_artist_details_modal = true">
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.spotify.artist.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">{{ total }} albums</p>
|
||||
<spotify-list-item-album
|
||||
v-for="album in albums"
|
||||
:key="album.id"
|
||||
:album="album"
|
||||
@click="open_album(album)"
|
||||
>
|
||||
<p class="heading has-text-centered-mobile" v-text="$t('page.spotify.artist.album-count', { count: total })" />
|
||||
<spotify-list-item-album v-for="album in albums" :key="album.id" :album="album" @click="open_album(album)">
|
||||
<template v-if="is_visible_artwork" #artwork>
|
||||
<p class="image is-64x64 fd-has-shadow fd-has-action">
|
||||
<cover-artwork
|
||||
:artwork_url="artwork_url(album)"
|
||||
:artist="album.artist"
|
||||
:album="album.name"
|
||||
:maxwidth="64"
|
||||
:maxheight="64"
|
||||
/>
|
||||
<cover-artwork :artwork_url="artwork_url(album)" :artist="album.artist" :album="album.name" :maxwidth="64" :maxheight="64" />
|
||||
</p>
|
||||
</template>
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_dialog(album)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-album>
|
||||
<VueEternalLoading v-if="offset < total" :load="load_next">
|
||||
<template #no-more> . </template>
|
||||
</VueEternalLoading>
|
||||
<spotify-modal-dialog-album
|
||||
:show="show_details_modal"
|
||||
:album="selected_album"
|
||||
@close="show_details_modal = false"
|
||||
/>
|
||||
<spotify-modal-dialog-artist
|
||||
:show="show_artist_details_modal"
|
||||
:artist="artist"
|
||||
@close="show_artist_details_modal = false"
|
||||
/>
|
||||
<spotify-modal-dialog-album :show="show_details_modal" :album="selected_album" @close="show_details_modal = false" />
|
||||
<spotify-modal-dialog-artist :show="show_artist_details_modal" :artist="artist" @close="show_artist_details_modal = false" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</template>
|
||||
|
@ -1,92 +1,53 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-music />
|
||||
|
||||
<!-- New Releases -->
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">New Releases</p>
|
||||
<p class="title is-4" v-text="$t('page.spotify.browse.new-releases')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<spotify-list-item-album
|
||||
v-for="album in new_releases"
|
||||
:key="album.id"
|
||||
:album="album"
|
||||
@click="open_album(album)"
|
||||
>
|
||||
<spotify-list-item-album v-for="album in new_releases" :key="album.id" :album="album" @click="open_album(album)">
|
||||
<template v-if="is_visible_artwork" #artwork>
|
||||
<p class="image is-64x64 fd-has-shadow fd-has-action">
|
||||
<cover-artwork
|
||||
:artwork_url="artwork_url(album)"
|
||||
:artist="album.artist"
|
||||
:album="album.name"
|
||||
:maxwidth="64"
|
||||
:maxheight="64"
|
||||
/>
|
||||
<cover-artwork :artwork_url="artwork_url(album)" :artist="album.artist" :album="album.name" :maxwidth="64" :maxheight="64" />
|
||||
</p>
|
||||
</template>
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_album_dialog(album)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-album>
|
||||
<spotify-modal-dialog-album
|
||||
:show="show_album_details_modal"
|
||||
:album="selected_album"
|
||||
@close="show_album_details_modal = false"
|
||||
/>
|
||||
<spotify-modal-dialog-album :show="show_album_details_modal" :album="selected_album" @close="show_album_details_modal = false" />
|
||||
</template>
|
||||
<template #footer>
|
||||
<nav class="level">
|
||||
<p class="level-item">
|
||||
<router-link
|
||||
to="/music/spotify/new-releases"
|
||||
class="button is-light is-small is-rounded"
|
||||
>
|
||||
Show more
|
||||
</router-link>
|
||||
<router-link to="/music/spotify/new-releases" class="button is-light is-small is-rounded" v-text="$t('page.spotify.browse.show-more')" />
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
|
||||
<!-- Featured Playlists -->
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Featured Playlists</p>
|
||||
<p class="title is-4" v-text="$t('page.spotify.browse.featured-playlists')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<spotify-list-item-playlist
|
||||
v-for="playlist in featured_playlists"
|
||||
:key="playlist.id"
|
||||
:playlist="playlist"
|
||||
>
|
||||
<spotify-list-item-playlist v-for="playlist in featured_playlists" :key="playlist.id" :playlist="playlist">
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_playlist_dialog(playlist)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-playlist>
|
||||
<spotify-modal-dialog-playlist
|
||||
:show="show_playlist_details_modal"
|
||||
:playlist="selected_playlist"
|
||||
@close="show_playlist_details_modal = false"
|
||||
/>
|
||||
<spotify-modal-dialog-playlist :show="show_playlist_details_modal" :playlist="selected_playlist" @close="show_playlist_details_modal = false" />
|
||||
</template>
|
||||
<template #footer>
|
||||
<nav class="level">
|
||||
<p class="level-item">
|
||||
<router-link
|
||||
to="/music/spotify/featured-playlists"
|
||||
class="button is-light is-small is-rounded"
|
||||
>
|
||||
Show more
|
||||
</router-link>
|
||||
<router-link to="/music/spotify/featured-playlists" class="button is-light is-small is-rounded" v-text="$t('page.spotify.browse.show-more')" />
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
|
@ -1,30 +1,19 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-music />
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Featured Playlists</p>
|
||||
</template>
|
||||
<template #content>
|
||||
<spotify-list-item-playlist
|
||||
v-for="playlist in featured_playlists"
|
||||
:key="playlist.id"
|
||||
:playlist="playlist"
|
||||
>
|
||||
<spotify-list-item-playlist v-for="playlist in featured_playlists" :key="playlist.id" :playlist="playlist">
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_playlist_dialog(playlist)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<a @click.prevent.stop="open_playlist_dialog(playlist)">
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-playlist>
|
||||
<spotify-modal-dialog-playlist
|
||||
:show="show_playlist_details_modal"
|
||||
:playlist="selected_playlist"
|
||||
@close="show_playlist_details_modal = false"
|
||||
/>
|
||||
<spotify-modal-dialog-playlist :show="show_playlist_details_modal" :playlist="selected_playlist" @close="show_playlist_details_modal = false" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</div>
|
||||
|
@ -1,42 +1,24 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<tabs-music />
|
||||
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<p class="title is-4">New Releases</p>
|
||||
</template>
|
||||
<template #content>
|
||||
<spotify-list-item-album
|
||||
v-for="album in new_releases"
|
||||
:key="album.id"
|
||||
:album="album"
|
||||
@click="open_album(album)"
|
||||
>
|
||||
<spotify-list-item-album v-for="album in new_releases" :key="album.id" :album="album" @click="open_album(album)">
|
||||
<template v-if="is_visible_artwork" #artwork>
|
||||
<p class="image is-64x64 fd-has-shadow fd-has-action">
|
||||
<cover-artwork
|
||||
:artwork_url="artwork_url(album)"
|
||||
:artist="album.artist"
|
||||
:album="album.name"
|
||||
:maxwidth="64"
|
||||
:maxheight="64"
|
||||
/>
|
||||
<cover-artwork :artwork_url="artwork_url(album)" :artist="album.artist" :album="album.name" :maxwidth="64" :maxheight="64" />
|
||||
</p>
|
||||
</template>
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_album_dialog(album)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-album>
|
||||
<spotify-modal-dialog-album
|
||||
:show="show_album_details_modal"
|
||||
:album="selected_album"
|
||||
@close="show_album_details_modal = false"
|
||||
/>
|
||||
<spotify-modal-dialog-album :show="show_album_details_modal" :album="selected_album" @close="show_album_details_modal = false" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</div>
|
||||
|
@ -1,58 +1,33 @@
|
||||
<template>
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
<div class="title is-4">
|
||||
{{ playlist.name }}
|
||||
</div>
|
||||
<div class="title is-4" v-text="playlist.name" />
|
||||
</template>
|
||||
<template #heading-right>
|
||||
<div class="buttons is-centered">
|
||||
<a
|
||||
class="button is-small is-light is-rounded"
|
||||
@click="show_playlist_details_modal = true"
|
||||
>
|
||||
<span class="icon"><mdicon name="dots-horizontal" size="16" /></span>
|
||||
<a class="button is-small is-light is-rounded" @click="show_playlist_details_modal = true">
|
||||
<mdicon class="icon" name="dots-horizontal" size="16" />
|
||||
</a>
|
||||
<a class="button is-small is-dark is-rounded" @click="play">
|
||||
<span class="icon"><mdicon name="shuffle" size="16" /></span>
|
||||
<span>Shuffle</span>
|
||||
<mdicon class="icon" name="shuffle" size="16" />
|
||||
<span v-text="$t('page.spotify.playlist.shuffle')" />
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<p class="heading has-text-centered-mobile">
|
||||
{{ playlist.tracks.total }} tracks
|
||||
</p>
|
||||
<spotify-list-item-track
|
||||
v-for="(item, index) in tracks"
|
||||
:key="item.track.id"
|
||||
:track="item.track"
|
||||
:album="item.track.album"
|
||||
:position="index"
|
||||
:context_uri="playlist.uri"
|
||||
>
|
||||
<p class="heading has-text-centered-mobile" v-text="$t('page.spotify.playlist.count', {count: playlist.tracks.total})" />
|
||||
<spotify-list-item-track v-for="(item, index) in tracks" :key="item.track.id" :track="item.track" :album="item.track.album" :position="index" :context_uri="playlist.uri">
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_track_dialog(item.track)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-track>
|
||||
<VueEternalLoading v-if="offset < total" :load="load_next">
|
||||
<template #no-more> . </template>
|
||||
</VueEternalLoading>
|
||||
<spotify-modal-dialog-track
|
||||
:show="show_track_details_modal"
|
||||
:track="selected_track"
|
||||
:album="selected_track.album"
|
||||
@close="show_track_details_modal = false"
|
||||
/>
|
||||
<spotify-modal-dialog-playlist
|
||||
:show="show_playlist_details_modal"
|
||||
:playlist="playlist"
|
||||
@close="show_playlist_details_modal = false"
|
||||
/>
|
||||
<spotify-modal-dialog-track :show="show_track_details_modal" :track="selected_track" :album="selected_track.album" @close="show_track_details_modal = false" />
|
||||
<spotify-modal-dialog-playlist :show="show_playlist_details_modal" :playlist="playlist" @close="show_playlist_details_modal = false" />
|
||||
</template>
|
||||
</content-with-heading>
|
||||
</template>
|
||||
|
@ -8,245 +8,146 @@
|
||||
<form @submit.prevent="new_search">
|
||||
<div class="field">
|
||||
<p class="control is-expanded has-icons-left">
|
||||
<input
|
||||
ref="search_field"
|
||||
v-model="search_query"
|
||||
class="input is-rounded is-shadowless"
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<span class="icon is-left">
|
||||
<mdicon name="magnify" size="16" />
|
||||
</span>
|
||||
<input ref="search_field" v-model="search_query" class="input is-rounded is-shadowless" type="text" placeholder="Search" autocomplete="off" />
|
||||
<mdicon class="icon is-left" name="magnify" size="16" />
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
<div class="tags" style="margin-top: 16px">
|
||||
<a
|
||||
v-for="recent_search in recent_searches"
|
||||
:key="recent_search"
|
||||
class="tag"
|
||||
@click="open_recent_search(recent_search)"
|
||||
>{{ recent_search }}</a
|
||||
>
|
||||
<a v-for="recent_search in recent_searches" :key="recent_search" class="tag" @click="open_recent_search(recent_search)" v-text="recent_search" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<tabs-search :query="search_query" />
|
||||
|
||||
<!-- Tracks -->
|
||||
<content-with-heading v-if="show_tracks && tracks.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Tracks</p>
|
||||
<p class="title is-4" v-text="$t('page.spotify.search.tracks')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<spotify-list-item-track
|
||||
v-for="track in tracks.items"
|
||||
:key="track.id"
|
||||
:track="track"
|
||||
:album="track.album"
|
||||
:position="0"
|
||||
:context_uri="track.uri"
|
||||
>
|
||||
<spotify-list-item-track v-for="track in tracks.items" :key="track.id" :track="track" :album="track.album" :position="0" :context_uri="track.uri">
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_track_dialog(track)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-track>
|
||||
<VueEternalLoading
|
||||
v-if="query.type === 'track'"
|
||||
:load="search_tracks_next"
|
||||
>
|
||||
<VueEternalLoading v-if="query.type === 'track'" :load="search_tracks_next">
|
||||
<template #no-more> . </template>
|
||||
</VueEternalLoading>
|
||||
<spotify-modal-dialog-track
|
||||
:show="show_track_details_modal"
|
||||
:track="selected_track"
|
||||
:album="selected_track.album"
|
||||
@close="show_track_details_modal = false"
|
||||
/>
|
||||
<spotify-modal-dialog-track :show="show_track_details_modal" :track="selected_track" :album="selected_track.album" @close="show_track_details_modal = false" />
|
||||
</template>
|
||||
<template #footer>
|
||||
<nav v-if="show_all_tracks_button" class="level">
|
||||
<p class="level-item">
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_tracks"
|
||||
>Show all {{ tracks.total.toLocaleString() }} tracks</a
|
||||
>
|
||||
<a class="button is-light is-small is-rounded" @click="open_search_tracks" v-text="$t('page.spotify.search.show-all-tracks', { count: tracks.total.toLocaleString() })" />
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_tracks && !tracks.total" class="mt-6">
|
||||
<template #content>
|
||||
<p><i>No tracks found</i></p>
|
||||
<p><i v-text="$t('page.spotify.search.no-tracks')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
|
||||
<!-- Artists -->
|
||||
<content-with-heading v-if="show_artists && artists.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Artists</p>
|
||||
<p class="title is-4" v-text="$t('page.spotify.search.artists')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<spotify-list-item-artist
|
||||
v-for="artist in artists.items"
|
||||
:key="artist.id"
|
||||
:artist="artist"
|
||||
>
|
||||
<spotify-list-item-artist v-for="artist in artists.items" :key="artist.id" :artist="artist">
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_artist_dialog(artist)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-artist>
|
||||
<VueEternalLoading
|
||||
v-if="query.type === 'artist'"
|
||||
:load="search_artists_next"
|
||||
>
|
||||
<VueEternalLoading v-if="query.type === 'artist'" :load="search_artists_next">
|
||||
<template #no-more> . </template>
|
||||
</VueEternalLoading>
|
||||
<spotify-modal-dialog-artist
|
||||
:show="show_artist_details_modal"
|
||||
:artist="selected_artist"
|
||||
@close="show_artist_details_modal = false"
|
||||
/>
|
||||
<spotify-modal-dialog-artist :show="show_artist_details_modal" :artist="selected_artist" @close="show_artist_details_modal = false" />
|
||||
</template>
|
||||
<template #footer>
|
||||
<nav v-if="show_all_artists_button" class="level">
|
||||
<p class="level-item">
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_artists"
|
||||
>Show all {{ artists.total.toLocaleString() }} artists</a
|
||||
>
|
||||
<a class="button is-light is-small is-rounded" @click="open_search_artists" v-text="$t('page.spotify.search.show-all-artists', { count: artists.total.toLocaleString() })" />
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_artists && !artists.total">
|
||||
<template #content>
|
||||
<p><i>No artists found</i></p>
|
||||
<p><i v-text="$t('page.spotify.search.no-artists')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
|
||||
<!-- Albums -->
|
||||
<content-with-heading v-if="show_albums && albums.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Albums</p>
|
||||
<p class="title is-4" v-text="$t('page.spotify.search.albums')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<spotify-list-item-album
|
||||
v-for="album in albums.items"
|
||||
:key="album.id"
|
||||
:album="album"
|
||||
@click="open_album(album)"
|
||||
>
|
||||
<spotify-list-item-album v-for="album in albums.items" :key="album.id" :album="album" @click="open_album(album)">
|
||||
<template v-if="is_visible_artwork" #artwork>
|
||||
<p class="image is-64x64 fd-has-shadow fd-has-action">
|
||||
<cover-artwork
|
||||
:artwork_url="artwork_url(album)"
|
||||
:artist="album.artist"
|
||||
:album="album.name"
|
||||
:maxwidth="64"
|
||||
:maxheight="64"
|
||||
/>
|
||||
<cover-artwork :artwork_url="artwork_url(album)" :artist="album.artist" :album="album.name" :maxwidth="64" :maxheight="64" />
|
||||
</p>
|
||||
</template>
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_album_dialog(album)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-album>
|
||||
<VueEternalLoading
|
||||
v-if="query.type === 'album'"
|
||||
:load="search_albums_next"
|
||||
>
|
||||
<VueEternalLoading v-if="query.type === 'album'" :load="search_albums_next">
|
||||
<template #no-more> . </template>
|
||||
</VueEternalLoading>
|
||||
<spotify-modal-dialog-album
|
||||
:show="show_album_details_modal"
|
||||
:album="selected_album"
|
||||
@close="show_album_details_modal = false"
|
||||
/>
|
||||
<spotify-modal-dialog-album :show="show_album_details_modal" :album="selected_album" @close="show_album_details_modal = false" />
|
||||
</template>
|
||||
<template #footer>
|
||||
<nav v-if="show_all_albums_button" class="level">
|
||||
<p class="level-item">
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_albums"
|
||||
>Show all {{ albums.total.toLocaleString() }} albums</a
|
||||
>
|
||||
<a class="button is-light is-small is-rounded" @click="open_search_albums" v-text="$t('page.spotify.search.show-all-albums', { count: albums.total.toLocaleString() })" />
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_albums && !albums.total">
|
||||
<template #content>
|
||||
<p><i>No albums found</i></p>
|
||||
<p><i v-text="$t('page.spotify.search.no-albums')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
|
||||
<!-- Playlists -->
|
||||
<content-with-heading v-if="show_playlists && playlists.total">
|
||||
<template #heading-left>
|
||||
<p class="title is-4">Playlists</p>
|
||||
<p class="title is-4" v-text="$t('page.spotify.search.playlists')" />
|
||||
</template>
|
||||
<template #content>
|
||||
<spotify-list-item-playlist
|
||||
v-for="playlist in playlists.items"
|
||||
:key="playlist.id"
|
||||
:playlist="playlist"
|
||||
>
|
||||
<spotify-list-item-playlist v-for="playlist in playlists.items" :key="playlist.id" :playlist="playlist">
|
||||
<template #actions>
|
||||
<a @click.prevent.stop="open_playlist_dialog(playlist)">
|
||||
<span class="icon has-text-dark"
|
||||
><mdicon name="dots-vertical" size="16"
|
||||
/></span>
|
||||
<mdicon class="icon has-text-dark" name="dots-vertical" size="16" />
|
||||
</a>
|
||||
</template>
|
||||
</spotify-list-item-playlist>
|
||||
<VueEternalLoading
|
||||
v-if="query.type === 'playlist'"
|
||||
:load="search_playlists_next"
|
||||
>
|
||||
<VueEternalLoading v-if="query.type === 'playlist'" :load="search_playlists_next">
|
||||
<template #no-more> . </template>
|
||||
</VueEternalLoading>
|
||||
<spotify-modal-dialog-playlist
|
||||
:show="show_playlist_details_modal"
|
||||
:playlist="selected_playlist"
|
||||
@close="show_playlist_details_modal = false"
|
||||
/>
|
||||
<spotify-modal-dialog-playlist :show="show_playlist_details_modal" :playlist="selected_playlist" @close="show_playlist_details_modal = false" />
|
||||
</template>
|
||||
<template #footer>
|
||||
<nav v-if="show_all_playlists_button" class="level">
|
||||
<p class="level-item">
|
||||
<a
|
||||
class="button is-light is-small is-rounded"
|
||||
@click="open_search_playlists"
|
||||
>Show all {{ playlists.total.toLocaleString() }} playlists</a
|
||||
>
|
||||
<a class="button is-light is-small is-rounded" @click="open_search_playlists" v-text="$t('page.spotify.search.show-all-playlists', { count: playlists.total.toLocaleString() })" />
|
||||
</p>
|
||||
</nav>
|
||||
</template>
|
||||
</content-with-heading>
|
||||
<content-text v-if="show_playlists && !playlists.total">
|
||||
<template #content>
|
||||
<p><i>No playlists found</i></p>
|
||||
<p><i v-text="$t('page.spotify.search.no-playlists')" /></p>
|
||||
</template>
|
||||
</content-text>
|
||||
</div>
|
||||
|
@ -55,9 +55,9 @@ export default createStore({
|
||||
|
||||
hide_singles: false,
|
||||
hide_spotify: false,
|
||||
artists_sort: 'Name',
|
||||
artist_albums_sort: 'Name',
|
||||
albums_sort: 'Name',
|
||||
artists_sort: 1,
|
||||
artist_albums_sort: 1,
|
||||
albums_sort: 1,
|
||||
show_only_next_items: false,
|
||||
show_burger_menu: false,
|
||||
show_player_menu: false,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user