#1458 Translation of Web UI

This commit is contained in:
Alain Nussbaumer
2022-05-20 13:44:22 +02:00
parent 2b38ebaa12
commit 167ba86211
104 changed files with 4863 additions and 3355 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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
},

View File

@@ -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
},

View File

@@ -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>

View File

@@ -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
},

View File

@@ -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>

View File

@@ -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" />

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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" />

View File

@@ -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" />

View File

@@ -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>

View File

@@ -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>

View File

@@ -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" />

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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" />

View File

@@ -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
},

View File

@@ -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>

View File

@@ -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" />

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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(),

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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
&quot;now playing page&quot;
<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 &quot;now playing page&quot;.
</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 &quot;Contemporary Classical&quot;.<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) }
})
}
}
}
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>