[web] Simplify pages

This commit is contained in:
Alain Nussbaumer 2025-03-18 21:54:27 +01:00
parent 15e8854349
commit be44c0ce9f
38 changed files with 1353 additions and 1457 deletions

View File

@ -20,22 +20,14 @@
<slot name="actions" /> <slot name="actions" />
</div> </div>
</div> </div>
<template v-for="item in items" :key="item.path"> <list-item
<div v-for="item in items"
class="media is-align-items-center is-clickable mb-0" :key="item.path"
@click="open(item)" icon="folder"
> :lines="[item.name]"
<mdicon class="media-left icon" name="folder" /> @open="open(item)"
<div class="media-content"> @open-details="openDetails(item)"
<div class="is-size-6 has-text-weight-bold" v-text="item.name" /> />
</div>
<div class="media-right">
<a @click.prevent.stop="openDetails(item)">
<mdicon class="icon has-text-grey" name="dots-vertical" size="16" />
</a>
</div>
</div>
</template>
<modal-dialog-directory <modal-dialog-directory
:item="selectedItem" :item="selectedItem"
:show="showDetailsModal" :show="showDetailsModal"
@ -44,17 +36,16 @@
</template> </template>
<script> <script>
import ListItem from '@/components/ListItem.vue'
import ModalDialogDirectory from '@/components/ModalDialogDirectory.vue' import ModalDialogDirectory from '@/components/ModalDialogDirectory.vue'
export default { export default {
name: 'ListDirectories', name: 'ListDirectories',
components: { ModalDialogDirectory }, components: { ListItem, ModalDialogDirectory },
props: { items: { required: true, type: Array } }, props: { items: { required: true, type: Array } },
data() { data() {
return { selectedItem: '', showDetailsModal: false } return { selectedItem: '', showDetailsModal: false }
}, },
computed: { computed: {
directories() { directories() {
const directories = [] const directories = []
@ -69,7 +60,6 @@ export default {
return directories return directories
} }
}, },
methods: { methods: {
open(item) { open(item) {
const route = { name: 'files' } const route = { name: 'files' }

View File

@ -1,85 +1,83 @@
<template> <template>
<div> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title :content="{ title: $t('page.about.library') }" />
<heading-title :content="{ title: $t('page.about.library') }" /> </template>
</template> <template #actions>
<template #actions> <control-button
<control-button :button="{
:button="{ handler: openUpdateDialog,
handler: openUpdateDialog, icon: 'refresh',
icon: 'refresh', key: 'page.about.update'
key: 'page.about.update' }"
}" :class="{ 'is-loading': libraryStore.updating }"
:class="{ 'is-loading': libraryStore.updating }" :disabled="libraryStore.updating"
:disabled="libraryStore.updating" />
/> </template>
</template> <template #content>
<template #content> <div
v-for="property in properties"
:key="property.key"
class="media is-align-items-center mb-0"
>
<div <div
v-for="property in properties" class="media-content has-text-weight-bold"
:key="property.key" v-text="$t(property.key)"
class="media is-align-items-center mb-0" />
> <div class="media-right">
<div <span v-text="property.value" />
class="media-content has-text-weight-bold" <span
v-text="$t(property.key)" v-if="property.alternate"
class="has-text-grey"
v-text="` (${property.alternate})`"
/> />
<div class="media-right">
<span v-text="property.value" />
<span
v-if="property.alternate"
class="has-text-grey"
v-text="` (${property.alternate})`"
/>
</div>
</div> </div>
<div </div>
class="is-size-7 mt-6" <div
v-text=" class="is-size-7 mt-6"
$t('page.about.version', { v-text="
version: configurationStore.version $t('page.about.version', {
}) version: configurationStore.version
" })
/> "
<div />
class="is-size-7" <div
v-text=" class="is-size-7"
$t('page.about.compiled-with', { v-text="
options: configurationStore.buildoptions.join(', ') $t('page.about.compiled-with', {
}) options: configurationStore.buildoptions.join(', ')
" })
/> "
<i18n-t />
tag="div" <i18n-t
class="is-size-7" tag="div"
keypath="page.about.built-with" class="is-size-7"
scope="global" keypath="page.about.built-with"
> scope="global"
<template #bulma> >
<a href="https://bulma.io">Bulma</a> <template #bulma>
</template> <a href="https://bulma.io">Bulma</a>
<template #mdi> </template>
<a href="https://pictogrammers.com/library/mdi/"> <template #mdi>
Material Design Icons <a href="https://pictogrammers.com/library/mdi/">
</a> Material Design Icons
</template> </a>
<template #vuejs> </template>
<a href="https://vuejs.org/">Vue.js</a> <template #vuejs>
</template> <a href="https://vuejs.org/">Vue.js</a>
<template #axios> </template>
<a href="https://github.com/axios/axios">axios</a> <template #axios>
</template> <a href="https://github.com/axios/axios">axios</a>
<template #others> </template>
<a <template #others>
href="https://github.com/owntone/owntone-server/network/dependencies" <a
v-text="$t('page.about.more')" href="https://github.com/owntone/owntone-server/network/dependencies"
/> v-text="$t('page.about.more')"
</template> />
</i18n-t> </template>
</template> </i18n-t>
</content-with-heading> </template>
</div> </content-with-heading>
</template> </template>
<script> <script>

View File

@ -1,27 +1,25 @@
<template> <template>
<div> <content-with-hero>
<content-with-hero> <template #heading>
<template #heading> <heading-hero :content="heading" />
<heading-hero :content="heading" /> </template>
</template> <template #image>
<template #image> <control-image
<control-image :url="album.artwork_url"
:url="album.artwork_url" :caption="album.name"
:caption="album.name" class="is-clickable is-medium"
class="is-clickable is-medium" @click="openDetails"
@click="openDetails" />
/> </template>
</template> <template #content>
<template #content> <list-tracks :items="tracks" :uris="album.uri" />
<list-tracks :items="tracks" :uris="album.uri" /> </template>
<modal-dialog-album </content-with-hero>
:item="album" <modal-dialog-album
:show="showDetailsModal" :item="album"
@close="showDetailsModal = false" :show="showDetailsModal"
/> @close="showDetailsModal = false"
</template> />
</content-with-hero>
</div>
</template> </template>
<script> <script>

View File

@ -1,27 +1,25 @@
<template> <template>
<div> <content-with-hero>
<content-with-hero> <template #heading>
<template #heading> <heading-hero :content="heading" />
<heading-hero :content="heading" /> </template>
</template> <template #image>
<template #image> <control-image
<control-image :url="album.images?.[0]?.url ?? ''"
:url="album.images?.[0]?.url ?? ''" :caption="album.name"
:caption="album.name" class="is-clickable is-medium"
class="is-clickable is-medium" @click="openDetails"
@click="openDetails" />
/> </template>
</template> <template #content>
<template #content> <list-tracks-spotify :items="tracks" :context_uri="album.uri" />
<list-tracks-spotify :items="tracks" :context_uri="album.uri" /> </template>
<modal-dialog-album-spotify </content-with-hero>
:item="album" <modal-dialog-album-spotify
:show="showDetailsModal" :item="album"
@close="showDetailsModal = false" :show="showDetailsModal"
/> @close="showDetailsModal = false"
</template> />
</content-with-hero>
</div>
</template> </template>
<script> <script>

View File

@ -1,47 +1,45 @@
<template> <template>
<div> <tabs-music />
<tabs-music /> <content-with-heading>
<content-with-heading> <template #options>
<template #options> <index-button-list :indices="albums.indices" />
<index-button-list :indices="albums.indices" /> <list-options>
<list-options> <template #filter>
<template #filter> <control-switch v-model="uiStore.hideSingles">
<control-switch v-model="uiStore.hideSingles"> <template #label>
<template #label> <span v-text="$t('options.filter.hide-singles')" />
<span v-text="$t('options.filter.hide-singles')" /> </template>
</template> <template #help>
<template #help> <span v-text="$t('options.filter.hide-singles-help')" />
<span v-text="$t('options.filter.hide-singles-help')" /> </template>
</template> </control-switch>
</control-switch> <control-switch
<control-switch v-if="servicesStore.isSpotifyActive"
v-if="servicesStore.isSpotifyActive" v-model="uiStore.hideSpotify"
v-model="uiStore.hideSpotify" >
> <template #label>
<template #label> <span v-text="$t('options.filter.hide-spotify')" />
<span v-text="$t('options.filter.hide-spotify')" /> </template>
</template> <template #help>
<template #help> <span v-text="$t('options.filter.hide-spotify-help')" />
<span v-text="$t('options.filter.hide-spotify-help')" /> </template>
</template> </control-switch>
</control-switch> </template>
</template> <template #sort>
<template #sort> <control-dropdown
<control-dropdown v-model:value="uiStore.albumsSort"
v-model:value="uiStore.albumsSort" :options="groupings"
:options="groupings" />
/> </template>
</template> </list-options>
</list-options> </template>
</template> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #content>
<template #content> <list-albums :items="albums" />
<list-albums :items="albums" /> </template>
</template> </content-with-heading>
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,50 +1,48 @@
<template> <template>
<div> <content-with-heading>
<content-with-heading> <template #options>
<template #options> <list-options>
<list-options> <template #filter>
<template #filter> <control-switch
<control-switch v-if="servicesStore.isSpotifyActive"
v-if="servicesStore.isSpotifyActive" v-model="uiStore.hideSpotify"
v-model="uiStore.hideSpotify" >
> <template #label>
<template #label> <span v-text="$t('page.artist.filter.hide-spotify')" />
<span v-text="$t('page.artist.filter.hide-spotify')" /> </template>
</template> <template #help>
<template #help> <span v-text="$t('page.artist.filter.hide-spotify-help')" />
<span v-text="$t('page.artist.filter.hide-spotify-help')" /> </template>
</template> </control-switch>
</control-switch> </template>
</template> <template #sort>
<template #sort> <control-dropdown
<control-dropdown v-model:value="uiStore.artistAlbumsSort"
v-model:value="uiStore.artistAlbumsSort" :options="groupings"
:options="groupings" />
/> </template>
</template> </list-options>
</list-options> </template>
</template> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #actions>
<template #actions> <control-button
<control-button :button="{ handler: openDetails, icon: 'dots-horizontal' }"
:button="{ handler: openDetails, icon: 'dots-horizontal' }" />
/> <control-button
<control-button :button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }"
:button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }" />
/> </template>
</template> <template #content>
<template #content> <list-albums :items="albums" />
<list-albums :items="albums" /> </template>
<modal-dialog-artist </content-with-heading>
:item="artist" <modal-dialog-artist
:show="showDetailsModal" :item="artist"
@close="showDetailsModal = false" :show="showDetailsModal"
/> @close="showDetailsModal = false"
</template> />
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,42 +1,40 @@
<template> <template>
<div> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #actions>
<template #actions> <control-button
<control-button :button="{ handler: openDetails, icon: 'dots-horizontal' }"
:button="{ handler: openDetails, icon: 'dots-horizontal' }" />
/> <control-button
<control-button :button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }"
:button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }" />
/> </template>
</template> <template #content>
<template #content> <list-albums-spotify :items="albums" />
<list-albums-spotify :items="albums" /> <vue-eternal-loading v-if="offset < total" :load="loadNext">
<vue-eternal-loading v-if="offset < total" :load="loadNext"> <template #loading>
<template #loading> <div class="columns is-centered">
<div class="columns is-centered"> <div class="column has-text-centered">
<div class="column has-text-centered"> <mdicon class="icon mdi-spin" name="loading" />
<mdicon class="icon mdi-spin" name="loading" />
</div>
</div> </div>
</template> </div>
<template #no-more> </template>
<br /> <template #no-more>
</template> <br />
<template #no-results> </template>
<br /> <template #no-results>
</template> <br />
</vue-eternal-loading> </template>
<modal-dialog-artist-spotify </vue-eternal-loading>
:item="artist" </template>
:show="showDetailsModal" </content-with-heading>
@close="showDetailsModal = false" <modal-dialog-artist-spotify
/> :item="artist"
</template> :show="showDetailsModal"
</content-with-heading> @close="showDetailsModal = false"
</div> />
</template> </template>
<script> <script>

View File

@ -1,51 +1,49 @@
<template> <template>
<div> <content-with-heading>
<content-with-heading> <template #options>
<template #options> <index-button-list :indices="tracks.indices" />
<index-button-list :indices="tracks.indices" /> <list-options>
<list-options> <template #filter>
<template #filter> <control-switch
<control-switch v-if="servicesStore.isSpotifyActive"
v-if="servicesStore.isSpotifyActive" v-model="uiStore.hideSpotify"
v-model="uiStore.hideSpotify" >
> <template #label>
<template #label> <span v-text="$t('options.filter.hide-spotify')" />
<span v-text="$t('options.filter.hide-spotify')" /> </template>
</template> <template #help>
<template #help> <span v-text="$t('options.filter.hide-spotify-help')" />
<span v-text="$t('options.filter.hide-spotify-help')" /> </template>
</template> </control-switch>
</control-switch> </template>
</template> <template #sort>
<template #sort> <control-dropdown
<control-dropdown v-model:value="uiStore.artistTracksSort"
v-model:value="uiStore.artistTracksSort" :options="groupings"
:options="groupings" />
/> </template>
</template> </list-options>
</list-options> </template>
</template> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #actions>
<template #actions> <control-button
<control-button :button="{ handler: openDetails, icon: 'dots-horizontal' }"
:button="{ handler: openDetails, icon: 'dots-horizontal' }" />
/> <control-button
<control-button :button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }"
:button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }" />
/> </template>
</template> <template #content>
<template #content> <list-tracks :items="tracks" :uris="trackUris" />
<list-tracks :items="tracks" :uris="trackUris" /> </template>
<modal-dialog-artist </content-with-heading>
:item="artist" <modal-dialog-artist
:show="showDetailsModal" :item="artist"
@close="showDetailsModal = false" :show="showDetailsModal"
/> @close="showDetailsModal = false"
</template> />
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,47 +1,45 @@
<template> <template>
<div> <tabs-music />
<tabs-music /> <content-with-heading>
<content-with-heading> <template #options>
<template #options> <index-button-list :indices="artists.indices" />
<index-button-list :indices="artists.indices" /> <list-options>
<list-options> <template #filter>
<template #filter> <control-switch v-model="uiStore.hideSingles">
<control-switch v-model="uiStore.hideSingles"> <template #label>
<template #label> <span v-text="$t('options.filter.hide-singles')" />
<span v-text="$t('options.filter.hide-singles')" /> </template>
</template> <template #help>
<template #help> <span v-text="$t('options.filter.hide-singles-help')" />
<span v-text="$t('options.filter.hide-singles-help')" /> </template>
</template> </control-switch>
</control-switch> <control-switch
<control-switch v-if="servicesStore.isSpotifyActive"
v-if="servicesStore.isSpotifyActive" v-model="uiStore.hideSpotify"
v-model="uiStore.hideSpotify" >
> <template #label>
<template #label> <span v-text="$t('options.filter.hide-spotify')" />
<span v-text="$t('options.filter.hide-spotify')" /> </template>
</template> <template #help>
<template #help> <span v-text="$t('options.filter.hide-spotify-help')" />
<span v-text="$t('options.filter.hide-spotify-help')" /> </template>
</template> </control-switch>
</control-switch> </template>
</template> <template #sort>
<template #sort> <control-dropdown
<control-dropdown v-model:value="uiStore.artistsSort"
v-model:value="uiStore.artistsSort" :options="groupings"
:options="groupings" />
/> </template>
</template> </list-options>
</list-options> </template>
</template> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #content>
<template #content> <list-artists :items="artists" />
<list-artists :items="artists" /> </template>
</template> </content-with-heading>
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,28 +1,26 @@
<template> <template>
<div> <content-with-hero>
<content-with-hero> <template #heading>
<template #heading> <heading-hero :content="heading" />
<heading-hero :content="heading" /> </template>
</template> <template #image>
<template #image> <control-image
<control-image :url="album.artwork_url"
:url="album.artwork_url" :caption="album.name"
:caption="album.name" class="is-clickable is-medium"
class="is-clickable is-medium" @click="openDetails"
@click="openDetails" />
/> </template>
</template> <template #content>
<template #content> <list-tracks :items="tracks" :show-progress="true" :uris="album.uri" />
<list-tracks :items="tracks" :show-progress="true" :uris="album.uri" /> </template>
<modal-dialog-album </content-with-hero>
:item="album" <modal-dialog-album
:show="showDetailsModal" :item="album"
:media_kind="'audiobook'" :show="showDetailsModal"
@close="showDetailsModal = false" :media_kind="'audiobook'"
/> @close="showDetailsModal = false"
</template> />
</content-with-hero>
</div>
</template> </template>
<script> <script>

View File

@ -1,18 +1,16 @@
<template> <template>
<div> <tabs-audiobooks />
<tabs-audiobooks /> <content-with-heading>
<content-with-heading> <template #options>
<template #options> <index-button-list :indices="albums.indices" />
<index-button-list :indices="albums.indices" /> </template>
</template> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #content>
<template #content> <list-albums :items="albums" />
<list-albums :items="albums" /> </template>
</template> </content-with-heading>
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,27 +1,25 @@
<template> <template>
<div> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #actions>
<template #actions> <control-button
<control-button :button="{ handler: openDetails, icon: 'dots-horizontal' }"
:button="{ handler: openDetails, icon: 'dots-horizontal' }" />
/> <control-button
<control-button :button="{ handler: play, icon: 'play', key: 'actions.play' }"
:button="{ handler: play, icon: 'play', key: 'actions.play' }" />
/> </template>
</template> <template #content>
<template #content> <list-albums :items="albums" />
<list-albums :items="albums" /> </template>
<modal-dialog-artist </content-with-heading>
:item="artist" <modal-dialog-artist
:show="showDetailsModal" :item="artist"
@close="showDetailsModal = false" :show="showDetailsModal"
/> @close="showDetailsModal = false"
</template> />
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,18 +1,16 @@
<template> <template>
<div> <tabs-audiobooks />
<tabs-audiobooks /> <content-with-heading>
<content-with-heading> <template #options>
<template #options> <index-button-list :indices="artists.indices" />
<index-button-list :indices="artists.indices" /> </template>
</template> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #content>
<template #content> <list-artists :items="artists" />
<list-artists :items="artists" /> </template>
</template> </content-with-heading>
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,18 +1,16 @@
<template> <template>
<div> <tabs-audiobooks />
<tabs-audiobooks /> <content-with-heading>
<content-with-heading> <template #options>
<template #options> <index-button-list :indices="genres.indices" />
<index-button-list :indices="genres.indices" /> </template>
</template> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #content>
<template #content> <list-genres :items="genres" :media_kind="'audiobook'" />
<list-genres :items="genres" :media_kind="'audiobook'" /> </template>
</template> </content-with-heading>
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,27 +1,25 @@
<template> <template>
<div> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #actions>
<template #actions> <control-button
<control-button :button="{ handler: openDetails, icon: 'dots-horizontal' }"
:button="{ handler: openDetails, icon: 'dots-horizontal' }" />
/> <control-button
<control-button :button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }"
:button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }" />
/> </template>
</template> <template #content>
<template #content> <list-albums :items="albums" />
<list-albums :items="albums" /> </template>
<modal-dialog-composer </content-with-heading>
:item="composer" <modal-dialog-composer
:show="showDetailsModal" :item="composer"
@close="showDetailsModal = false" :show="showDetailsModal"
/> @close="showDetailsModal = false"
</template> />
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,38 +1,36 @@
<template> <template>
<div> <content-with-heading>
<content-with-heading> <template #options>
<template #options> <index-button-list :indices="tracks.indices" />
<index-button-list :indices="tracks.indices" /> <list-options>
<list-options> <template #sort>
<template #sort> <control-dropdown
<control-dropdown v-model:value="uiStore.composerTracksSort"
v-model:value="uiStore.composerTracksSort" :options="groupings"
:options="groupings" />
/> </template>
</template> </list-options>
</list-options> </template>
</template> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #actions>
<template #actions> <control-button
<control-button :button="{ handler: openDetails, icon: 'dots-horizontal' }"
:button="{ handler: openDetails, icon: 'dots-horizontal' }" />
/> <control-button
<control-button :button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }"
:button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }" />
/> </template>
</template> <template #content>
<template #content> <list-tracks :items="tracks" :expression="expression" />
<list-tracks :items="tracks" :expression="expression" /> </template>
<modal-dialog-composer </content-with-heading>
:item="composer" <modal-dialog-composer
:show="showDetailsModal" :item="composer"
@close="showDetailsModal = false" :show="showDetailsModal"
/> @close="showDetailsModal = false"
</template> />
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,18 +1,16 @@
<template> <template>
<div> <tabs-music />
<tabs-music /> <content-with-heading>
<content-with-heading> <template #options>
<template #options> <index-button-list :indices="composers.indices" />
<index-button-list :indices="composers.indices" /> </template>
</template> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #content>
<template #content> <list-composers :items="composers" />
<list-composers :items="composers" /> </template>
</template> </content-with-heading>
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,28 +1,22 @@
<template> <template>
<div> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title :content="{ title: name }" />
<heading-title :content="{ title: name }" /> </template>
</template> <template #actions>
<template #actions> <control-button
<control-button :button="{ handler: openDetails, icon: 'dots-horizontal' }"
:button="{ handler: openDetails, icon: 'dots-horizontal' }" />
/> <control-button
<control-button :button="{ handler: play, icon: 'play', key: 'actions.play' }"
:button="{ handler: play, icon: 'play', key: 'actions.play' }" />
/> </template>
</template> <template #content>
<template #content> <list-directories :items="directories" />
<list-directories :items="directories" /> <list-playlists :items="playlists" />
<list-playlists :items="playlists" /> <list-tracks :items="tracks" icon="file-music-outline" />
<list-tracks </template>
:expression="expression" </content-with-heading>
:items="tracks"
icon="file-music-outline"
/>
</template>
</content-with-heading>
</div>
<modal-dialog-playable <modal-dialog-playable
:item="playable" :item="playable"
:show="showDetailsModal" :show="showDetailsModal"
@ -109,9 +103,6 @@ export default {
current() { current() {
return this.$route.query?.directory || '/' return this.$route.query?.directory || '/'
}, },
expression() {
return `path starts with "${this.current}" order by path asc`
},
name() { name() {
if (this.current !== '/') { if (this.current !== '/') {
return this.current?.slice(this.current.lastIndexOf('/') + 1) return this.current?.slice(this.current.lastIndexOf('/') + 1)

View File

@ -1,31 +1,29 @@
<template> <template>
<div> <content-with-heading>
<content-with-heading> <template #options>
<template #options> <index-button-list :indices="albums.indices" />
<index-button-list :indices="albums.indices" /> </template>
</template> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #actions>
<template #actions> <control-button
<control-button :button="{ handler: openDetails, icon: 'dots-horizontal' }"
:button="{ handler: openDetails, icon: 'dots-horizontal' }" />
/> <control-button
<control-button :button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }"
:button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }" />
/> </template>
</template> <template #content>
<template #content> <list-albums :items="albums" />
<list-albums :items="albums" /> </template>
<modal-dialog-genre </content-with-heading>
:item="genre" <modal-dialog-genre
:media_kind="media_kind" :item="genre"
:show="showDetailsModal" :media_kind="media_kind"
@close="showDetailsModal = false" :show="showDetailsModal"
/> @close="showDetailsModal = false"
</template> />
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,39 +1,37 @@
<template> <template>
<div> <content-with-heading>
<content-with-heading> <template #options>
<template #options> <index-button-list :indices="tracks.indices" />
<index-button-list :indices="tracks.indices" /> <list-options>
<list-options> <template #sort>
<template #sort> <control-dropdown
<control-dropdown v-model:value="uiStore.genreTracksSort"
v-model:value="uiStore.genreTracksSort" :options="groupings"
:options="groupings" />
/> </template>
</template> </list-options>
</list-options> </template>
</template> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #actions>
<template #actions> <control-button
<control-button :button="{ handler: openDetails, icon: 'dots-horizontal' }"
:button="{ handler: openDetails, icon: 'dots-horizontal' }" />
/> <control-button
<control-button :button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }"
:button="{ handler: play, icon: 'shuffle', key: 'actions.shuffle' }" />
/> </template>
</template> <template #content>
<template #content> <list-tracks :items="tracks" :expression="expression" />
<list-tracks :items="tracks" :expression="expression" /> </template>
<modal-dialog-genre </content-with-heading>
:item="genre" <modal-dialog-genre
:media_kind="media_kind" :item="genre"
:show="showDetailsModal" :media_kind="media_kind"
@close="showDetailsModal = false" :show="showDetailsModal"
/> @close="showDetailsModal = false"
</template> />
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,18 +1,16 @@
<template> <template>
<div> <tabs-music />
<tabs-music /> <content-with-heading>
<content-with-heading> <template #options>
<template #options> <index-button-list :indices="genres.indices" />
<index-button-list :indices="genres.indices" /> </template>
</template> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #content>
<template #content> <list-genres :items="genres" :media_kind="'music'" />
<list-genres :items="genres" :media_kind="'music'" /> </template>
</template> </content-with-heading>
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,43 +1,41 @@
<template> <template>
<div> <tabs-music />
<tabs-music /> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title
<heading-title :content="{ title: $t('page.music.recently-added.title') }"
:content="{ title: $t('page.music.recently-added.title') }" />
/> </template>
</template> <template #content>
<template #content> <list-albums :items="albums" />
<list-albums :items="albums" /> </template>
</template> <template #footer>
<template #footer> <router-link
<router-link class="button is-small is-rounded"
class="button is-small is-rounded" :to="{ name: 'music-recently-added' }"
:to="{ name: 'music-recently-added' }" >
> {{ $t('actions.show-more') }}
{{ $t('actions.show-more') }} </router-link>
</router-link> </template>
</template> </content-with-heading>
</content-with-heading> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title
<heading-title :content="{ title: $t('page.music.recently-played.title') }"
:content="{ title: $t('page.music.recently-played.title') }" />
/> </template>
</template> <template #content>
<template #content> <list-tracks :items="tracks" />
<list-tracks :items="tracks" /> </template>
</template> <template #footer>
<template #footer> <router-link
<router-link class="button is-small is-rounded"
class="button is-small is-rounded" :to="{ name: 'music-recently-played' }"
:to="{ name: 'music-recently-played' }" >
> {{ $t('actions.show-more') }}
{{ $t('actions.show-more') }} </router-link>
</router-link> </template>
</template> </content-with-heading>
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,17 +1,15 @@
<template> <template>
<div> <tabs-music />
<tabs-music /> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title
<heading-title :content="{ title: $t('page.music.recently-added.title') }"
:content="{ title: $t('page.music.recently-added.title') }" />
/> </template>
</template> <template #content>
<template #content> <list-albums :items="albums" />
<list-albums :items="albums" /> </template>
</template> </content-with-heading>
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,17 +1,15 @@
<template> <template>
<div> <tabs-music />
<tabs-music /> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title
<heading-title :content="{ title: $t('page.music.recently-played.title') }"
:content="{ title: $t('page.music.recently-played.title') }" />
/> </template>
</template> <template #content>
<template #content> <list-tracks :items="tracks" />
<list-tracks :items="tracks" /> </template>
</template> </content-with-heading>
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,43 +1,41 @@
<template> <template>
<div> <tabs-music />
<tabs-music /> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title
<heading-title :content="{ title: $t('page.spotify.music.new-releases') }"
:content="{ title: $t('page.spotify.music.new-releases') }" />
/> </template>
</template> <template #content>
<template #content> <list-albums-spotify :items="albums" />
<list-albums-spotify :items="albums" /> </template>
</template> <template #footer>
<template #footer> <router-link
<router-link :to="{ name: 'music-spotify-new-releases' }"
:to="{ name: 'music-spotify-new-releases' }" class="button is-small is-rounded"
class="button is-small is-rounded" >
> {{ $t('actions.show-more') }}
{{ $t('actions.show-more') }} </router-link>
</router-link> </template>
</template> </content-with-heading>
</content-with-heading> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title
<heading-title :content="{ title: $t('page.spotify.music.featured-playlists') }"
:content="{ title: $t('page.spotify.music.featured-playlists') }" />
/> </template>
</template> <template #content>
<template #content> <list-playlists-spotify :items="playlists" />
<list-playlists-spotify :items="playlists" /> </template>
</template> <template #footer>
<template #footer> <router-link
<router-link :to="{ name: 'music-spotify-featured-playlists' }"
:to="{ name: 'music-spotify-featured-playlists' }" class="button is-small is-rounded"
class="button is-small is-rounded" >
> {{ $t('actions.show-more') }}
{{ $t('actions.show-more') }} </router-link>
</router-link> </template>
</template> </content-with-heading>
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,15 +1,13 @@
<template> <template>
<div> <tabs-music />
<tabs-music /> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #content>
<template #content> <list-playlists-spotify :items="playlists" />
<list-playlists-spotify :items="playlists" /> </template>
</template> </content-with-heading>
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,15 +1,13 @@
<template> <template>
<div> <tabs-music />
<tabs-music /> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #content>
<template #content> <list-albums-spotify :items="albums" />
<list-albums-spotify :items="albums" /> </template>
</template> </content-with-heading>
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,14 +1,12 @@
<template> <template>
<div> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #content>
<template #content> <list-playlists :items="playlists" />
<list-playlists :items="playlists" /> </template>
</template> </content-with-heading>
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,33 +1,31 @@
<template> <template>
<div> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #actions>
<template #actions> <control-button
<control-button :button="{ handler: openDetails, icon: 'dots-horizontal' }"
:button="{ handler: openDetails, icon: 'dots-horizontal' }" />
/> <control-button
<control-button :button="{
:button="{ handler: play,
handler: play, icon: 'shuffle',
icon: 'shuffle', key: 'actions.shuffle'
key: 'actions.shuffle' }"
}" :disabled="tracks.count === 0"
:disabled="tracks.count === 0" />
/> </template>
</template> <template #content>
<template #content> <list-tracks :items="tracks" :uris="uris" />
<list-tracks :items="tracks" :uris="uris" /> </template>
<modal-dialog-playlist </content-with-heading>
:item="playlist" <modal-dialog-playlist
:show="showDetailsModal" :item="playlist"
:uris="uris" :show="showDetailsModal"
@close="showDetailsModal = false" :uris="uris"
/> @close="showDetailsModal = false"
</template> />
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,44 +1,42 @@
<template> <template>
<div> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #actions>
<template #actions> <control-button
<control-button :button="{ handler: openDetails, icon: 'dots-horizontal' }"
:button="{ handler: openDetails, icon: 'dots-horizontal' }" />
/> <control-button
<control-button :button="{
:button="{ handler: play,
handler: play, icon: 'shuffle',
icon: 'shuffle', key: 'actions.shuffle'
key: 'actions.shuffle' }"
}" :disabled="playlist.tracks.total === 0"
:disabled="playlist.tracks.total === 0" />
/> </template>
</template> <template #content>
<template #content> <list-tracks-spotify :items="tracks" :context_uri="playlist.uri" />
<list-tracks-spotify :items="tracks" :context_uri="playlist.uri" /> <vue-eternal-loading v-if="offset < total" :load="load">
<vue-eternal-loading v-if="offset < total" :load="load"> <template #loading>
<template #loading> <div class="columns is-centered">
<div class="columns is-centered"> <div class="column has-text-centered">
<div class="column has-text-centered"> <mdicon class="icon mdi-spin" name="loading" />
<mdicon class="icon mdi-spin" name="loading" />
</div>
</div> </div>
</template> </div>
<template #no-more> </template>
<br /> <template #no-more>
</template> <br />
</vue-eternal-loading> </template>
<modal-dialog-playlist-spotify </vue-eternal-loading>
:item="playlist" </template>
:show="showDetailsModal" </content-with-heading>
@close="showDetailsModal = false" <modal-dialog-playlist-spotify
/> :item="playlist"
</template> :show="showDetailsModal"
</content-with-heading> @close="showDetailsModal = false"
</div> />
</template> </template>
<script> <script>

View File

@ -1,52 +1,50 @@
<template> <template>
<div> <content-with-hero>
<content-with-hero> <template #heading>
<template #heading> <heading-hero :content="heading" />
<heading-hero :content="heading" /> </template>
</template> <template #image>
<template #image> <control-image
<control-image :url="album.artwork_url"
:url="album.artwork_url" :caption="album.name"
:caption="album.name" class="is-clickable is-medium"
class="is-clickable is-medium" @click="openDetails"
@click="openDetails" />
/> </template>
</template> <template #content>
<template #content> <list-tracks
<list-tracks :items="tracks"
:items="tracks" :show-progress="true"
:show-progress="true" @play-count-changed="reloadTracks"
@play-count-changed="reloadTracks" />
/> <modal-dialog-album
<modal-dialog-album :item="album"
:item="album" :show="showDetailsModal"
:show="showDetailsModal" :media_kind="'podcast'"
:media_kind="'podcast'" @close="showDetailsModal = false"
@close="showDetailsModal = false" @play-count-changed="reloadTracks"
@play-count-changed="reloadTracks" @remove-podcast="openRemovePodcastDialog"
@remove-podcast="openRemovePodcastDialog" />
/> <modal-dialog
<modal-dialog :actions="actions"
:actions="actions" :show="showRemovePodcastModal"
:show="showRemovePodcastModal" :title="$t('page.podcast.remove-podcast')"
:title="$t('page.podcast.remove-podcast')" @cancel="showRemovePodcastModal = false"
@cancel="showRemovePodcastModal = false" @remove="removePodcast"
@remove="removePodcast" >
> <template #content>
<template #content> <i18n-t keypath="page.podcast.remove-info" tag="p" scope="global">
<i18n-t keypath="page.podcast.remove-info" tag="p" scope="global"> <template #separator>
<template #separator> <br />
<br /> </template>
</template> <template #name>
<template #name> <b v-text="playlistToRemove.name" />
<b v-text="playlistToRemove.name" /> </template>
</template> </i18n-t>
</i18n-t> </template>
</template> </modal-dialog>
</modal-dialog> </template>
</template> </content-with-hero>
</content-with-hero>
</div>
</template> </template>
<script> <script>

View File

@ -1,61 +1,59 @@
<template> <template>
<div> <content-with-heading v-if="tracks.items.length > 0">
<content-with-heading v-if="tracks.items.length > 0"> <template #heading>
<template #heading> <heading-title :content="{ title: $t('page.podcasts.new-episodes') }" />
<heading-title :content="{ title: $t('page.podcasts.new-episodes') }" /> </template>
</template> <template #actions>
<template #actions> <control-button
<control-button :button="{
:button="{ handler: markAllAsPlayed,
handler: markAllAsPlayed, icon: 'pencil',
icon: 'pencil', key: 'actions.mark-all-played'
key: 'actions.mark-all-played' }"
}" />
/> </template>
</template> <template #content>
<template #content> <list-tracks
<list-tracks :items="tracks"
:items="tracks" :show-progress="true"
:show-progress="true" @play-count-changed="reloadNewEpisodes"
@play-count-changed="reloadNewEpisodes" />
/> </template>
</template> </content-with-heading>
</content-with-heading> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #actions>
<template #actions> <control-button
<control-button v-if="rss.tracks > 0"
v-if="rss.tracks > 0" :button="{
:button="{ handler: updateRss,
handler: updateRss, icon: 'refresh',
icon: 'refresh', key: 'actions.update'
key: 'actions.update' }"
}" />
/> <control-button
<control-button :button="{
:button="{ handler: openAddPodcastDialog,
handler: openAddPodcastDialog, icon: 'rss',
icon: 'rss', key: 'actions.add'
key: 'actions.add' }"
}" />
/> </template>
</template> <template #content>
<template #content> <list-albums
<list-albums :items="albums"
:items="albums" @play-count-changed="reloadNewEpisodes()"
@play-count-changed="reloadNewEpisodes()" @podcast-deleted="reloadPodcasts()"
@podcast-deleted="reloadPodcasts()" />
/> </template>
<modal-dialog-add-rss </content-with-heading>
:show="showAddPodcastModal" <modal-dialog-add-rss
@close="showAddPodcastModal = false" :show="showAddPodcastModal"
@podcast-added="reloadPodcasts()" @close="showAddPodcastModal = false"
/> @podcast-added="reloadPodcasts()"
</template> />
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,97 +1,95 @@
<template> <template>
<div> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #actions>
<template #actions> <control-button
<control-button :button="{
:button="{ handler: uiStore.toggleHideReadItems,
handler: uiStore.toggleHideReadItems, icon: 'eye-off-outline',
icon: 'eye-off-outline', key: 'actions.hide-previous'
key: 'actions.hide-previous' }"
}" :class="{ 'is-dark': uiStore.hideReadItems }"
:class="{ 'is-dark': uiStore.hideReadItems }" />
/> <control-button
<control-button :button="{
:button="{ handler: openAddStreamDialog,
handler: openAddStreamDialog, icon: 'web',
icon: 'web', key: 'actions.add-stream'
key: 'actions.add-stream' }"
}" />
/> <control-button
<control-button :button="{
:button="{ handler: toggleEdit,
handler: toggleEdit, icon: 'pencil',
icon: 'pencil', key: 'actions.edit'
key: 'actions.edit' }"
}" :class="{ 'is-dark': editing }"
:class="{ 'is-dark': editing }" :disabled="queueStore.isEmpty"
:disabled="queueStore.isEmpty" />
/> <control-button
<control-button :button="{
:button="{ handler: clearQueue,
handler: clearQueue, icon: 'delete-empty',
icon: 'delete-empty', key: 'actions.clear'
key: 'actions.clear' }"
}" :disabled="queueStore.isEmpty"
:disabled="queueStore.isEmpty" />
/> <control-button
<control-button v-if="queueStore.isSavingAllowed"
v-if="queueStore.isSavingAllowed" :button="{
:button="{ handler: openSaveDialog,
handler: openSaveDialog, icon: 'download',
icon: 'download', key: 'actions.save'
key: 'actions.save' }"
}" :disabled="queueStore.isEmpty"
:disabled="queueStore.isEmpty" />
/> </template>
</template> <template #content>
<template #content> <draggable v-model="items" item-key="id" @end="moveItem">
<draggable v-model="items" item-key="id" @end="moveItem"> <template #item="{ element, index }">
<template #item="{ element, index }"> <list-item-queue-item
<list-item-queue-item :item="element"
:item="element" :position="index"
:position="index" :current-position="currentPosition"
:current-position="currentPosition" :hide-read-items="uiStore.hideReadItems"
:hide-read-items="uiStore.hideReadItems" :editing="editing"
:editing="editing" >
> <template #actions>
<template #actions> <a v-if="!editing" @click.prevent.stop="openDetails(element)">
<a v-if="!editing" @click.prevent.stop="openDetails(element)"> <mdicon
<mdicon class="icon has-text-grey"
class="icon has-text-grey" name="dots-vertical"
name="dots-vertical" size="16"
size="16" />
/> </a>
</a> <a
<a v-if="isRemovable(element)"
v-if="isRemovable(element)" @click.prevent.stop="remove(element)"
@click.prevent.stop="remove(element)" >
> <mdicon class="icon has-text-grey" name="delete" size="18" />
<mdicon class="icon has-text-grey" name="delete" size="18" /> </a>
</a> </template>
</template> </list-item-queue-item>
</list-item-queue-item> </template>
</template> </draggable>
</draggable> </template>
<modal-dialog-queue-item </content-with-heading>
:show="showDetailsModal" <modal-dialog-queue-item
:item="selectedItem" :show="showDetailsModal"
@close="showDetailsModal = false" :item="selectedItem"
/> @close="showDetailsModal = false"
<modal-dialog-add-stream />
:show="showAddStreamDialog" <modal-dialog-add-stream
@close="showAddStreamDialog = false" :show="showAddStreamDialog"
/> @close="showAddStreamDialog = false"
<modal-dialog-playlist-save />
v-if="queueStore.isSavingAllowed" <modal-dialog-playlist-save
:show="showSaveModal" v-if="queueStore.isSavingAllowed"
@close="showSaveModal = false" :show="showSaveModal"
/> @close="showSaveModal = false"
</template> />
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,14 +1,12 @@
<template> <template>
<div> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title :content="heading" />
<heading-title :content="heading" /> </template>
</template> <template #content>
<template #content> <list-tracks :items="tracks" />
<list-tracks :items="tracks" /> </template>
</template> </content-with-heading>
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,81 +1,71 @@
<template> <template>
<div> <tabs-settings />
<tabs-settings /> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title :content="{ title: $t('page.settings.artwork.title') }" />
<heading-title </template>
:content="{ title: $t('page.settings.artwork.title') }" <template #content>
/> <div class="content" v-text="$t('page.settings.artwork.explanation-1')" />
</template> <div class="content">
<template #content> <control-setting-switch category="artwork" name="streamurl_ignore">
<div <template #label>
class="content" <span v-text="$t('page.settings.artwork.streaming')" />
v-text="$t('page.settings.artwork.explanation-1')" </template>
/> </control-setting-switch>
<div class="content"> <control-setting-switch
<control-setting-switch category="artwork" name="streamurl_ignore"> category="artwork"
<template #label> name="show_cover_artwork_in_album_lists"
<span v-text="$t('page.settings.artwork.streaming')" /> >
</template> <template #label>
</control-setting-switch> <span v-text="$t('page.settings.artwork.show-coverart')" />
<control-setting-switch </template>
category="artwork" </control-setting-switch>
name="show_cover_artwork_in_album_lists" </div>
> <div class="content" v-text="$t('page.settings.artwork.explanation-2')" />
<template #label> <div class="content">
<span v-text="$t('page.settings.artwork.show-coverart')" /> <control-setting-switch
</template> v-if="servicesStore.spotify_logged_in"
</control-setting-switch> category="artwork"
</div> name="use_artwork_source_spotify"
<div >
class="content" <template #label>
v-text="$t('page.settings.artwork.explanation-2')" <span v-text="$t('page.settings.artwork.spotify')" />
/> <a href="https://www.spotify.com/" target="_blank">
<div class="content"> <span class="icon">
<control-setting-switch <mdicon name="open-in-new" size="16" />
v-if="servicesStore.spotify_logged_in" </span>
category="artwork" </a>
name="use_artwork_source_spotify" </template>
> </control-setting-switch>
<template #label> <control-setting-switch
<span v-text="$t('page.settings.artwork.spotify')" /> category="artwork"
<a href="https://www.spotify.com/" target="_blank"> name="use_artwork_source_discogs"
<span class="icon"> >
<mdicon name="open-in-new" size="16" /> <template #label>
</span> <span v-text="$t('page.settings.artwork.discogs')" />
</a> <a href="https://www.discogs.com/" target="_blank">
</template> <span class="icon">
</control-setting-switch> <mdicon name="open-in-new" size="16" />
<control-setting-switch </span>
category="artwork" </a>
name="use_artwork_source_discogs" </template>
> </control-setting-switch>
<template #label> <control-setting-switch
<span v-text="$t('page.settings.artwork.discogs')" /> category="artwork"
<a href="https://www.discogs.com/" target="_blank"> name="use_artwork_source_coverartarchive"
<span class="icon"> >
<mdicon name="open-in-new" size="16" /> <template #label>
</span> <span v-text="$t('page.settings.artwork.coverartarchive')" />
</a> <a href="https://coverartarchive.org/" target="_blank">
</template> <span class="icon">
</control-setting-switch> <mdicon name="open-in-new" size="16" />
<control-setting-switch </span>
category="artwork" </a>
name="use_artwork_source_coverartarchive" </template>
> </control-setting-switch>
<template #label> </div>
<span v-text="$t('page.settings.artwork.coverartarchive')" /> </template>
<a href="https://coverartarchive.org/" target="_blank"> </content-with-heading>
<span class="icon">
<mdicon name="open-in-new" size="16" />
</span>
</a>
</template>
</control-setting-switch>
</div>
</template>
</content-with-heading>
</div>
</template> </template>
<script> <script>

View File

@ -1,124 +1,119 @@
<template> <template>
<div> <tabs-settings />
<tabs-settings /> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title
<heading-title :content="{ title: $t('page.settings.services.spotify.title') }"
:content="{ title: $t('page.settings.services.spotify.title') }" />
</template>
<template #content>
<div v-if="servicesStore.isSpotifyEnabled">
<div v-text="$t('page.settings.services.spotify.grant-access')" />
<div
class="notification help"
v-text="
$t('page.settings.services.spotify.requirements', {
scopes: servicesStore.requiredSpotifyScopes.join(', ')
})
"
/> />
</template> <div v-if="servicesStore.isSpotifyActive">
<template #content>
<div v-if="servicesStore.isSpotifyEnabled">
<div v-text="$t('page.settings.services.spotify.grant-access')" />
<div <div
class="notification help"
v-text=" v-text="
$t('page.settings.services.spotify.requirements', { $t('page.settings.services.spotify.user', {
scopes: servicesStore.requiredSpotifyScopes.join(', ') user: servicesStore.spotify.webapi_user
}) })
" "
/> />
<div v-if="servicesStore.isSpotifyActive">
<div
v-text="
$t('page.settings.services.spotify.user', {
user: servicesStore.spotify.webapi_user
})
"
/>
<div
v-if="servicesStore.hasMissingSpotifyScopes"
class="notification help is-danger is-light"
v-text="
$t('page.settings.services.spotify.reauthorize', {
scopes: servicesStore.missingSpotifyScopes.join(', ')
})
"
/>
</div>
<div class="field is-grouped mt-5">
<div v-if="servicesStore.isAuthorizationRequired" class="control">
<a
class="button"
:href="servicesStore.spotify.oauth_uri"
v-text="$t('page.settings.services.spotify.authorize')"
/>
</div>
<div v-if="servicesStore.isSpotifyActive" class="control">
<button
class="button is-danger"
@click="logoutSpotify"
v-text="$t('actions.logout')"
/>
</div>
</div>
</div>
<div v-else v-text="$t('page.settings.services.spotify.no-support')" />
</template>
</content-with-heading>
<content-with-heading>
<template #heading>
<heading-title
:content="{ title: $t('page.settings.services.lastfm.title') }"
/>
</template>
<template #content>
<div v-if="servicesStore.isLastfmEnabled">
<div v-text="$t('page.settings.services.lastfm.grant-access')" />
<div <div
class="notification help" v-if="servicesStore.hasMissingSpotifyScopes"
v-text="$t('page.settings.services.lastfm.info')" class="notification help is-danger is-light"
v-text="
$t('page.settings.services.spotify.reauthorize', {
scopes: servicesStore.missingSpotifyScopes.join(', ')
})
"
/> />
<div v-if="!servicesStore.isLastfmActive"> </div>
<form @submit.prevent="loginLastfm"> <div class="field is-grouped mt-5">
<div class="field is-grouped"> <div v-if="servicesStore.isAuthorizationRequired" class="control">
<div class="control"> <a
<input class="button"
v-model="lastfm_login.user" :href="servicesStore.spotify.oauth_uri"
class="input" v-text="$t('page.settings.services.spotify.authorize')"
type="text" />
:placeholder="$t('page.settings.services.username')"
/>
<div
class="help is-danger"
v-text="lastfm_login.errors.user"
/>
</div>
<div class="control">
<input
v-model="lastfm_login.password"
class="input"
type="password"
:placeholder="$t('page.settings.services.password')"
/>
<div
class="help is-danger"
v-text="lastfm_login.errors.password"
/>
</div>
<div class="control">
<button
class="button"
type="submit"
v-text="$t('actions.login')"
/>
</div>
</div>
<div class="help is-danger" v-text="lastfm_login.errors.error" />
</form>
</div> </div>
<div v-else> <div v-if="servicesStore.isSpotifyActive" class="control">
<button <button
class="button is-danger" class="button is-danger"
@click="logoutLastfm" @click="logoutSpotify"
v-text="$t('actions.logout')" v-text="$t('actions.logout')"
/> />
</div> </div>
</div> </div>
<div v-else v-text="$t('page.settings.services.lastfm.no-support')" /> </div>
</template> <div v-else v-text="$t('page.settings.services.spotify.no-support')" />
</content-with-heading> </template>
</div> </content-with-heading>
<content-with-heading>
<template #heading>
<heading-title
:content="{ title: $t('page.settings.services.lastfm.title') }"
/>
</template>
<template #content>
<div v-if="servicesStore.isLastfmEnabled">
<div v-text="$t('page.settings.services.lastfm.grant-access')" />
<div
class="notification help"
v-text="$t('page.settings.services.lastfm.info')"
/>
<div v-if="!servicesStore.isLastfmActive">
<form @submit.prevent="loginLastfm">
<div class="field is-grouped">
<div class="control">
<input
v-model="lastfm_login.user"
class="input"
type="text"
:placeholder="$t('page.settings.services.username')"
/>
<div class="help is-danger" v-text="lastfm_login.errors.user" />
</div>
<div class="control">
<input
v-model="lastfm_login.password"
class="input"
type="password"
:placeholder="$t('page.settings.services.password')"
/>
<div
class="help is-danger"
v-text="lastfm_login.errors.password"
/>
</div>
<div class="control">
<button
class="button"
type="submit"
v-text="$t('actions.login')"
/>
</div>
</div>
<div class="help is-danger" v-text="lastfm_login.errors.error" />
</form>
</div>
<div v-else>
<button
class="button is-danger"
@click="logoutLastfm"
v-text="$t('actions.logout')"
/>
</div>
</div>
<div v-else v-text="$t('page.settings.services.lastfm.no-support')" />
</template>
</content-with-heading>
</template> </template>
<script> <script>

View File

@ -1,90 +1,88 @@
<template> <template>
<div> <tabs-settings />
<tabs-settings /> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title
<heading-title :content="{ title: $t('page.settings.devices.pairing') }"
:content="{ title: $t('page.settings.devices.pairing') }" />
/> </template>
</template> <template #content>
<template #content> <div v-if="pairing.active">
<div v-if="pairing.active"> <form @submit.prevent="kickoffPairing">
<form @submit.prevent="kickoffPairing"> <label class="label has-text-weight-normal content">
<label class="label has-text-weight-normal content"> <span v-text="$t('page.settings.devices.pairing-request')" />
<span v-text="$t('page.settings.devices.pairing-request')" /> <b v-text="pairing.remote" />
<b v-text="pairing.remote" /> </label>
</label> <div class="field is-grouped">
<div class="field is-grouped"> <div class="control">
<div class="control"> <input
<input v-model="pairingRequest.pin"
v-model="pairingRequest.pin" class="input"
class="input" inputmode="numeric"
inputmode="numeric" pattern="[\d]{4}"
pattern="[\d]{4}" :placeholder="$t('page.settings.devices.pairing-code')"
:placeholder="$t('page.settings.devices.pairing-code')" />
/>
</div>
<div class="control">
<button
class="button"
type="submit"
v-text="$t('actions.send')"
/>
</div>
</div> </div>
</form> <div class="control">
</div> <button
<div v-else v-text="$t('page.settings.devices.no-active-pairing')" /> class="button"
</template> type="submit"
</content-with-heading> v-text="$t('actions.send')"
<content-with-heading> />
<template #heading>
<heading-title
:content="{ title: $t('page.settings.devices.speaker-pairing') }"
/>
</template>
<template #content>
<div
class="content"
v-text="$t('page.settings.devices.speaker-pairing-info')"
/>
<div v-for="output in outputs" :key="output.id">
<control-switch
v-model="output.selected"
@update:model-value="toggleOutput(output.id)"
>
<template #label>
<span v-text="output.name" />
</template>
</control-switch>
<form
v-if="output.needs_auth_key"
class="mb-5"
@submit.prevent="kickoffVerification(output.id)"
>
<div class="field is-grouped">
<div class="control">
<input
v-model="verificationRequest.pin"
class="input"
inputmode="numeric"
pattern="[\d]{4}"
:placeholder="$t('page.settings.devices.verification-code')"
/>
</div>
<div class="control">
<button
class="button"
type="submit"
v-text="$t('actions.verify')"
/>
</div>
</div> </div>
</form> </div>
</div> </form>
</template> </div>
</content-with-heading> <div v-else v-text="$t('page.settings.devices.no-active-pairing')" />
</div> </template>
</content-with-heading>
<content-with-heading>
<template #heading>
<heading-title
:content="{ title: $t('page.settings.devices.speaker-pairing') }"
/>
</template>
<template #content>
<div
class="content"
v-text="$t('page.settings.devices.speaker-pairing-info')"
/>
<div v-for="output in outputs" :key="output.id">
<control-switch
v-model="output.selected"
@update:model-value="toggleOutput(output.id)"
>
<template #label>
<span v-text="output.name" />
</template>
</control-switch>
<form
v-if="output.needs_auth_key"
class="mb-5"
@submit.prevent="kickoffVerification(output.id)"
>
<div class="field is-grouped">
<div class="control">
<input
v-model="verificationRequest.pin"
class="input"
inputmode="numeric"
pattern="[\d]{4}"
:placeholder="$t('page.settings.devices.verification-code')"
/>
</div>
<div class="control">
<button
class="button"
type="submit"
v-text="$t('actions.verify')"
/>
</div>
</div>
</form>
</div>
</template>
</content-with-heading>
</template> </template>
<script> <script>

View File

@ -1,160 +1,156 @@
<template> <template>
<div> <tabs-settings />
<tabs-settings /> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title
<heading-title :content="{ title: $t('page.settings.general.language') }"
:content="{ title: $t('page.settings.general.language') }" />
/> </template>
</template> <template #content>
<template #content> <control-dropdown
<control-dropdown v-model:value="locale"
v-model:value="locale" :options="settingsStore.locales"
:options="settingsStore.locales" />
/> </template>
</template> </content-with-heading>
</content-with-heading> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title
<heading-title :content="{ title: $t('page.settings.general.navigation-items') }"
:content="{ title: $t('page.settings.general.navigation-items') }" />
/> </template>
</template> <template #content>
<template #content> <div
<div class=" "
class=" " v-text="$t('page.settings.general.navigation-item-selection')"
v-text="$t('page.settings.general.navigation-item-selection')" />
/> <div
<div class="notification is-size-7"
class="notification is-size-7" v-text="$t('page.settings.general.navigation-item-selection-info')"
v-text="$t('page.settings.general.navigation-item-selection-info')" />
/> <control-setting-switch
<control-setting-switch category="webinterface"
category="webinterface" name="show_menu_item_playlists"
name="show_menu_item_playlists" >
> <template #label>
<template #label> <span v-text="$t('page.settings.general.playlists')" />
<span v-text="$t('page.settings.general.playlists')" /> </template>
</template> </control-setting-switch>
</control-setting-switch> <control-setting-switch
<control-setting-switch category="webinterface"
category="webinterface" name="show_menu_item_music"
name="show_menu_item_music" >
> <template #label>
<template #label> <span v-text="$t('page.settings.general.music')" />
<span v-text="$t('page.settings.general.music')" /> </template>
</template> </control-setting-switch>
</control-setting-switch> <control-setting-switch
<control-setting-switch category="webinterface"
category="webinterface" name="show_menu_item_podcasts"
name="show_menu_item_podcasts" >
> <template #label>
<template #label> <span v-text="$t('page.settings.general.podcasts')" />
<span v-text="$t('page.settings.general.podcasts')" /> </template>
</template> </control-setting-switch>
</control-setting-switch> <control-setting-switch
<control-setting-switch category="webinterface"
category="webinterface" name="show_menu_item_audiobooks"
name="show_menu_item_audiobooks" >
> <template #label>
<template #label> <span v-text="$t('page.settings.general.audiobooks')" />
<span v-text="$t('page.settings.general.audiobooks')" /> </template>
</template> </control-setting-switch>
</control-setting-switch> <control-setting-switch
<control-setting-switch category="webinterface"
category="webinterface" name="show_menu_item_radio"
name="show_menu_item_radio" >
> <template #label>
<template #label> <span v-text="$t('page.settings.general.radio')" />
<span v-text="$t('page.settings.general.radio')" /> </template>
</template> </control-setting-switch>
</control-setting-switch> <control-setting-switch
<control-setting-switch category="webinterface"
category="webinterface" name="show_menu_item_files"
name="show_menu_item_files" >
> <template #label>
<template #label> <span v-text="$t('page.settings.general.files')" />
<span v-text="$t('page.settings.general.files')" /> </template>
</template> </control-setting-switch>
</control-setting-switch> <control-setting-switch
<control-setting-switch category="webinterface"
category="webinterface" name="show_menu_item_search"
name="show_menu_item_search" >
> <template #label>
<template #label> <span v-text="$t('page.settings.general.search')" />
<span v-text="$t('page.settings.general.search')" /> </template>
</template> </control-setting-switch>
</control-setting-switch> </template>
</template> </content-with-heading>
</content-with-heading> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title
<heading-title :content="{ title: $t('page.settings.general.now-playing-page') }"
:content="{ title: $t('page.settings.general.now-playing-page') }" />
/> </template>
</template> <template #content>
<template #content> <control-setting-switch
<control-setting-switch category="webinterface"
category="webinterface" name="show_filepath_now_playing"
name="show_filepath_now_playing" >
> <template #label>
<template #label> <span v-text="$t('page.settings.general.show-path')" />
<span v-text="$t('page.settings.general.show-path')" /> </template>
</template> </control-setting-switch>
</control-setting-switch> <control-setting-switch
<control-setting-switch category="webinterface"
category="webinterface" name="show_composer_now_playing"
name="show_composer_now_playing" >
> <template #label>
<template #label> <span v-text="$t('page.settings.general.show-composer')" />
<span v-text="$t('page.settings.general.show-composer')" /> </template>
</template> <template #help>
<template #help> <span v-text="$t('page.settings.general.show-composer-info')" />
<span v-text="$t('page.settings.general.show-composer-info')" /> </template>
</template> </control-setting-switch>
</control-setting-switch> <control-setting-text-field
<control-setting-text-field category="webinterface"
category="webinterface" name="show_composer_for_genre"
name="show_composer_for_genre" :disabled="!settingsStore.show_composer_now_playing"
:disabled="!settingsStore.show_composer_now_playing" :placeholder="$t('page.settings.general.genres')"
:placeholder="$t('page.settings.general.genres')" >
> <template #label>
<template #label> <span v-text="$t('page.settings.general.show-composer-genres')" />
<span v-text="$t('page.settings.general.show-composer-genres')" /> </template>
</template> <template #help>
<template #help> <i18n-t
<i18n-t keypath="page.settings.general.show-composer-genres-help"
keypath="page.settings.general.show-composer-genres-help" tag="p"
tag="p" class="help"
class="help" scope="global"
scope="global" >
> <br />
<br /> </i18n-t>
</i18n-t> </template>
</template> </control-setting-text-field>
</control-setting-text-field> </template>
</template> </content-with-heading>
</content-with-heading> <content-with-heading>
<content-with-heading> <template #heading>
<template #heading> <heading-title
<heading-title :content="{ title: $t('page.settings.general.recently-added-page') }"
:content="{ title: $t('page.settings.general.recently-added-page') }" />
/> </template>
</template> <template #content>
<template #content> <control-setting-integer-field
<control-setting-integer-field category="webinterface"
category="webinterface" name="recently_added_limit"
name="recently_added_limit" >
> <template #label>
<template #label> <span v-text="$t('page.settings.general.recently-added-page-info')" />
<span </template>
v-text="$t('page.settings.general.recently-added-page-info')" </control-setting-integer-field>
/> </template>
</template> </content-with-heading>
</control-setting-integer-field>
</template>
</content-with-heading>
</div>
</template> </template>
<script> <script>