mirror of
https://github.com/owntone/owntone-server.git
synced 2025-03-27 07:51:00 -04:00
[web] Replace switch control
This commit is contained in:
parent
e12ab3dd08
commit
e0a2ab159e
70
web-src/src/components/ControlSwitch.vue
Normal file
70
web-src/src/components/ControlSwitch.vue
Normal file
@ -0,0 +1,70 @@
|
||||
<template>
|
||||
<label class="toggle">
|
||||
<input
|
||||
:checked="modelValue"
|
||||
type="checkbox"
|
||||
class="toggle-checkbox is-rounded mr-2"
|
||||
@change="$emit('update:modelValue', !modelValue)"
|
||||
/>
|
||||
<div class="toggle-switch"></div>
|
||||
<slot name="label" class="toggle-label" />
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ControlSwitch',
|
||||
props: {
|
||||
modelValue: Boolean
|
||||
},
|
||||
emits: ['update:modelValue']
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.toggle {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.toggle-switch {
|
||||
display: inline-block;
|
||||
background: var(--bulma-grey-light);
|
||||
border-radius: 1rem;
|
||||
width: 2.75rem;
|
||||
height: 1.5rem;
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
transition: background 0.25s;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
.toggle-switch:before,
|
||||
.toggle-switch:after {
|
||||
content: '';
|
||||
}
|
||||
.toggle-switch:before {
|
||||
display: block;
|
||||
background: var(--bulma-white);
|
||||
border-radius: 50%;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
position: absolute;
|
||||
top: 0.25rem;
|
||||
left: 0.25rem;
|
||||
transition: left 0.25s;
|
||||
}
|
||||
.toggle:hover .toggle-switch:before {
|
||||
background: var(--bulma-white);
|
||||
}
|
||||
.toggle-checkbox:checked + .toggle-switch {
|
||||
background: var(--bulma-primary);
|
||||
}
|
||||
.toggle-checkbox:checked + .toggle-switch:before {
|
||||
left: 1.5rem;
|
||||
}
|
||||
|
||||
.toggle-checkbox {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
}
|
||||
</style>
|
@ -9,7 +9,7 @@
|
||||
:url="item.artwork_url"
|
||||
:artist="item.artist"
|
||||
:album="item.name"
|
||||
class="fd-has-shadow fd-cover fd-cover-normal-image mb-5"
|
||||
class="fd-has-shadow fd-cover fd-cover-normal-image"
|
||||
/>
|
||||
<p class="title is-4">
|
||||
<a class="has-text-link" @click="open" v-text="item.name" />
|
||||
@ -184,5 +184,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
@ -86,5 +86,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
@ -87,13 +87,12 @@
|
||||
</p>
|
||||
<p>
|
||||
<span class="heading" v-text="$t('dialog.track.type')" />
|
||||
<span class="title is-6">
|
||||
<span
|
||||
v-text="
|
||||
`${$t(`media.kind.${item.media_kind}`)} - ${$t(`data.kind.${item.data_kind}`)}`
|
||||
"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="title is-6"
|
||||
v-text="
|
||||
`${$t(`media.kind.${item.media_kind}`)} - ${$t(`data.kind.${item.data_kind}`)}`
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
<p v-if="item.samplerate">
|
||||
<span class="heading" v-text="$t('dialog.track.quality')" />
|
||||
@ -296,5 +295,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
@ -2,18 +2,18 @@
|
||||
<modal-dialog
|
||||
:show="show"
|
||||
:title="$t('dialog.update.title')"
|
||||
:ok_action="library.updating ? '' : $t('dialog.update.rescan')"
|
||||
:ok_action="libraryStore.updating ? '' : $t('dialog.update.rescan')"
|
||||
:close_action="$t('dialog.update.cancel')"
|
||||
@ok="update_library"
|
||||
@close="close()"
|
||||
>
|
||||
<template #modal-content>
|
||||
<div v-if="!library.updating">
|
||||
<div v-if="!libraryStore.updating">
|
||||
<p class="mb-3" v-text="$t('dialog.update.info')" />
|
||||
<div v-if="spotify_enabled || rss.tracks > 0" class="field">
|
||||
<div class="control">
|
||||
<div class="select is-small">
|
||||
<select v-model="update_dialog_scan_kind">
|
||||
<select v-model="libraryStore.update_dialog_scan_kind">
|
||||
<option value="" v-text="$t('dialog.update.all')" />
|
||||
<option value="files" v-text="$t('dialog.update.local')" />
|
||||
<option
|
||||
@ -31,13 +31,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<input
|
||||
id="rescan"
|
||||
v-model="rescan_metadata"
|
||||
type="checkbox"
|
||||
class="switch is-rounded is-small"
|
||||
/>
|
||||
<label for="rescan" v-text="$t('dialog.update.rescan-metadata')" />
|
||||
<control-switch v-model="rescan_metadata">
|
||||
<template #label>
|
||||
<span v-text="$t('dialog.update.rescan-metadata')" />
|
||||
</template>
|
||||
</control-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
@ -48,6 +46,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ControlSwitch from '@/components/ControlSwitch.vue'
|
||||
import ModalDialog from '@/components/ModalDialog.vue'
|
||||
import { useLibraryStore } from '@/stores/library'
|
||||
import { useServicesStore } from '@/stores/services'
|
||||
@ -55,7 +54,7 @@ import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'ModalDialogUpdate',
|
||||
components: { ModalDialog },
|
||||
components: { ControlSwitch, ModalDialog },
|
||||
props: { show: Boolean },
|
||||
emits: ['close'],
|
||||
|
||||
@ -73,42 +72,26 @@ export default {
|
||||
},
|
||||
|
||||
computed: {
|
||||
library() {
|
||||
return this.libraryStore.$state
|
||||
},
|
||||
|
||||
rss() {
|
||||
return this.libraryStore.rss
|
||||
},
|
||||
|
||||
spotify_enabled() {
|
||||
return this.servicesStore.spotify.webapi_token_valid
|
||||
},
|
||||
|
||||
update_dialog_scan_kind: {
|
||||
get() {
|
||||
return this.library.update_dialog_scan_kind
|
||||
},
|
||||
set(value) {
|
||||
this.library.update_dialog_scan_kind = value
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
close() {
|
||||
this.update_dialog_scan_kind = ''
|
||||
this.libraryStore.update_dialog_scan_kind = ''
|
||||
this.$emit('close')
|
||||
},
|
||||
update_library() {
|
||||
if (this.rescan_metadata) {
|
||||
webapi.library_rescan(this.update_dialog_scan_kind)
|
||||
webapi.library_rescan(this.libraryStore.update_dialog_scan_kind)
|
||||
} else {
|
||||
webapi.library_update(this.update_dialog_scan_kind)
|
||||
webapi.library_update(this.libraryStore.update_dialog_scan_kind)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
@ -1,15 +1,14 @@
|
||||
<template>
|
||||
<div class="field">
|
||||
<input
|
||||
<control-switch
|
||||
:id="setting.name"
|
||||
v-model="setting.value"
|
||||
type="checkbox"
|
||||
class="switch is-rounded mr-2"
|
||||
@change="update_setting"
|
||||
/>
|
||||
<label class="pt-0" :for="setting.name">
|
||||
<slot name="label" />
|
||||
</label>
|
||||
@update:model-value="update_setting"
|
||||
>
|
||||
<template #label>
|
||||
<slot name="label" />
|
||||
</template>
|
||||
</control-switch>
|
||||
<i
|
||||
class="is-size-7"
|
||||
:class="{ 'has-text-info': is_success, 'has-text-danger': is_error }"
|
||||
@ -22,11 +21,13 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ControlSwitch from '@/components/ControlSwitch.vue'
|
||||
import { useSettingsStore } from '@/stores/settings'
|
||||
import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'SettingsCheckbox',
|
||||
components: { ControlSwitch },
|
||||
props: {
|
||||
category: { required: true, type: String },
|
||||
name: { required: true, type: String }
|
||||
@ -104,5 +105,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
@ -1,176 +1,7 @@
|
||||
@charset "utf-8";
|
||||
|
||||
@import 'bulma/bulma.sass';
|
||||
@import 'bulma-switch';
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body,
|
||||
html,
|
||||
.content table th,
|
||||
td,
|
||||
.fd-tabs-section {
|
||||
background-color: $black-ter !important;
|
||||
color: $grey-light;
|
||||
}
|
||||
.tabs ul {
|
||||
border-bottom-color: $grey-dark;
|
||||
}
|
||||
.tabs a:hover {
|
||||
border-bottom-color: $grey-lighter;
|
||||
color: $grey-lighter !important;
|
||||
}
|
||||
a:hover,
|
||||
a.has-text-dark:hover,
|
||||
a.has-text-dark:focus {
|
||||
color: $grey-lighter !important;
|
||||
}
|
||||
.media + .media {
|
||||
border-top-color: $grey-dark !important;
|
||||
}
|
||||
.tabs a {
|
||||
border-bottom-color: $grey-dark;
|
||||
}
|
||||
.tabs a,
|
||||
.hero.is-light .title,
|
||||
.title,
|
||||
.subtitle,
|
||||
.navbar.is-light .navbar-brand > .navbar-item,
|
||||
.navbar-item,
|
||||
.navbar.is-white .navbar-brand a.navbar-item,
|
||||
.navbar.is-dark .navbar-brand .navbar-item,
|
||||
.navbar.is-light .navbar-burger {
|
||||
color: $grey-light;
|
||||
}
|
||||
.navbar-item.has-dropdown-up .navbar-dropdown {
|
||||
border-bottom-color: $grey-dark;
|
||||
}
|
||||
.navbar-dropdown {
|
||||
background-color: $grey-darker;
|
||||
border-top-color: $grey-dark;
|
||||
}
|
||||
a.tag:hover,
|
||||
a.tag.is-delete:hover,
|
||||
a.dropdown-item:hover,
|
||||
a.dropdown-item:focus,
|
||||
a.navbar-item:hover,
|
||||
a.navbar-item:focus,
|
||||
a.navbar-item:active,
|
||||
.button:hover,
|
||||
.button.is-white:focus,
|
||||
.button.is-white:hover,
|
||||
.button.is-dark:hover,
|
||||
.button.is-light:hover,
|
||||
hr,
|
||||
.navbar-burger:hover,
|
||||
.navbar.is-white .navbar-brand > a.navbar-item:hover,
|
||||
.navbar.is-light .navbar-brand > a.navbar-item:focus,
|
||||
.navbar.is-light .navbar-brand > a.navbar-item:hover,
|
||||
.navbar.is-dark .navbar-brand > a.navbar-item:focus,
|
||||
.navbar.is-dark .navbar-brand > a.navbar-item:hover,
|
||||
.navbar-dropdown a.navbar-item:hover,
|
||||
.navbar-dropdown a.navbar-item:focus,
|
||||
.modal-content .input,
|
||||
.modal-content select,
|
||||
.tabs.is-toggle a:hover {
|
||||
background-color: $grey-dark;
|
||||
color: $grey-lighter;
|
||||
}
|
||||
.card-footer .has-text-dark,
|
||||
.media .has-text-dark {
|
||||
color: $grey-light !important;
|
||||
}
|
||||
.navbar-menu,
|
||||
.navbar-brand,
|
||||
.notification,
|
||||
.card {
|
||||
background-color: $grey-darker;
|
||||
color: $grey-light;
|
||||
}
|
||||
a.tag,
|
||||
.button,
|
||||
.button:active,
|
||||
.button:focus,
|
||||
.dropdown-content,
|
||||
.dropdown-item,
|
||||
.input,
|
||||
.input .switch {
|
||||
background-color: $grey-darker;
|
||||
border-width: 0;
|
||||
color: $grey-lighter;
|
||||
}
|
||||
.input::placeholder,
|
||||
.control.has-icons-left .icon {
|
||||
color: $grey;
|
||||
}
|
||||
.label,
|
||||
.tabs a:hover,
|
||||
.control.has-icons-left .input:focus ~ .icon {
|
||||
color: $grey-lighter;
|
||||
}
|
||||
.tabs.is-toggle a:hover,
|
||||
.navbar-item .buttons .button,
|
||||
.modal-content select,
|
||||
.modal-content select:hover {
|
||||
border-color: $grey-dark;
|
||||
border-width: 1px;
|
||||
}
|
||||
.tabs.is-toggle a {
|
||||
background-color: $grey-darker;
|
||||
border-color: $grey-darker;
|
||||
}
|
||||
.button.is-light,
|
||||
.button.is-dark,
|
||||
.button.is-white,
|
||||
.button[disabled],
|
||||
.button[disabled]:hover {
|
||||
background-color: $grey-darker;
|
||||
color: $grey-light;
|
||||
}
|
||||
.has-text-grey-light,
|
||||
a.has-text-grey-light:hover {
|
||||
color: $grey !important;
|
||||
}
|
||||
.table,
|
||||
code {
|
||||
background: transparent;
|
||||
}
|
||||
.card-footer {
|
||||
border-top-color: $grey-dark;
|
||||
}
|
||||
.card-footer-item:not(:last-child) {
|
||||
border-right-color: $grey-dark;
|
||||
}
|
||||
.hero.is-light.is-bold {
|
||||
background-image: linear-gradient(
|
||||
141deg,
|
||||
$black-ter 0%,
|
||||
$grey-darker 71%,
|
||||
$grey-dark
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* Lyrics animation */
|
||||
@keyframes pop-color {
|
||||
0% {
|
||||
color: $black;
|
||||
}
|
||||
100% {
|
||||
color: $success;
|
||||
}
|
||||
}
|
||||
|
||||
.media.with-progress h2:last-of-type {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.media.with-progress {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
a.navbar-item {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
@import 'bulma/bulma';
|
||||
@import 'bulma/sass/utilities/mixins';
|
||||
|
||||
.fd-is-not-allowed {
|
||||
cursor: not-allowed;
|
||||
@ -180,13 +11,6 @@ a.navbar-item {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.fd-is-square .button {
|
||||
height: 27px;
|
||||
min-width: 27px;
|
||||
padding-left: 0.25rem;
|
||||
padding-right: 0.25rem;
|
||||
}
|
||||
|
||||
.fd-is-text-clipped {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
@ -196,8 +20,7 @@ a.navbar-item {
|
||||
.fd-tabs-section {
|
||||
padding-bottom: 0;
|
||||
padding-top: 0;
|
||||
background: $white;
|
||||
top: $navbar-height;
|
||||
background: var(--bulma-body-background-color);
|
||||
z-index: 20;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
@ -205,16 +28,12 @@ a.navbar-item {
|
||||
|
||||
.fd-has-shadow img {
|
||||
box-shadow:
|
||||
0 4px 8px 0 rgba(0, 0, 0, 0.2),
|
||||
0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||||
}
|
||||
|
||||
.fd-page-with-tabs {
|
||||
margin-top: $navbar-height !important;
|
||||
0 0.25rem 0.5rem 0 var(--bulma-background-active),
|
||||
0 0.375rem 1.25rem 0 var(--bulma-background-active);
|
||||
}
|
||||
|
||||
.is-full-height {
|
||||
min-height: calc(100vh - calc(2 * $navbar-height));
|
||||
min-height: calc(100vh - calc(2 * var(--bulma-navbar-height)));
|
||||
}
|
||||
|
||||
.is-disabled {
|
||||
@ -233,23 +52,23 @@ a.navbar-item {
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
img {
|
||||
border-radius: $radius-small;
|
||||
border-radius: var(--bulma-radius-small);
|
||||
max-width: 4rem;
|
||||
max-height: 4rem;
|
||||
}
|
||||
}
|
||||
&-medium-image {
|
||||
@include from($tablet) {
|
||||
@include tablet {
|
||||
justify-content: right;
|
||||
}
|
||||
img {
|
||||
border-radius: $radius;
|
||||
border-radius: var(--bulma-radius);
|
||||
max-height: calc(150px - 1.5rem);
|
||||
}
|
||||
}
|
||||
&-normal-image {
|
||||
img {
|
||||
border-radius: $radius-large;
|
||||
border-radius: var(--bulma-radius-large);
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@ -262,7 +81,7 @@ a.navbar-item {
|
||||
}
|
||||
}
|
||||
img {
|
||||
border-radius: $radius-large;
|
||||
border-radius: var(--bulma-radius-large);
|
||||
max-height: calc(100vh - 26rem);
|
||||
}
|
||||
&.is-masked {
|
||||
@ -271,14 +90,6 @@ a.navbar-item {
|
||||
}
|
||||
}
|
||||
|
||||
.sortable-chosen .media-right {
|
||||
visibility: hidden;
|
||||
}
|
||||
.sortable-ghost h1,
|
||||
.sortable-ghost h2 {
|
||||
color: $danger;
|
||||
}
|
||||
|
||||
.media:first-of-type {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
@ -299,35 +110,20 @@ a.navbar-item {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Add a little bit of spacing between title and subtitle */
|
||||
.title:not(.is-spaced) + .subtitle + .subtitle {
|
||||
margin-top: -1.3rem !important;
|
||||
}
|
||||
|
||||
/* Only scroll content if modal contains a card component */
|
||||
.modal-content .card-content {
|
||||
max-height: calc(100vh - 200px);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.fd-width-auto {
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
/* Show scrollbar for navbar menu in desktop mode if content exceeds the screen size */
|
||||
@include desktop {
|
||||
.navbar-dropdown {
|
||||
max-height: calc(100vh - calc(2 * $navbar-height) - 2rem);
|
||||
max-height: calc(100vh - calc(2 * var(--bulma-navbar-height)) - 2rem);
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/* Limit the size of the bottom navbar menu to not be displayed behind the Safari browser menu on iOS */
|
||||
.fd-bottom-navbar .navbar-menu {
|
||||
max-height: calc(100vh - calc(2 * $navbar-height) - 1rem);
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
@include mobile {
|
||||
&.fd-is-centered-mobile {
|
||||
@ -342,12 +138,20 @@ a.navbar-item {
|
||||
}
|
||||
}
|
||||
|
||||
.heading {
|
||||
display: block;
|
||||
font-size: 0.75rem;
|
||||
letter-spacing: 1px;
|
||||
margin-bottom: 0px !important;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.column {
|
||||
&.fd-has-cover {
|
||||
@include mobile {
|
||||
margin: auto;
|
||||
}
|
||||
@include from($tablet) {
|
||||
@include tablet {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
@ -364,6 +168,17 @@ a.navbar-item {
|
||||
padding: 1.5rem !important;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
@include mobile {
|
||||
width: 100vw;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-content {
|
||||
max-height: calc(100vh - calc(2 * var(--bulma-navbar-height)));
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* Slider */
|
||||
@mixin thumb {
|
||||
-webkit-appearance: none;
|
||||
@ -371,43 +186,51 @@ a.navbar-item {
|
||||
height: var(--th);
|
||||
box-sizing: border-box;
|
||||
border-radius: 50%;
|
||||
background: $light;
|
||||
border: 1px solid $grey-light;
|
||||
background: var(--bulma-light);
|
||||
border: 1px solid var(--bulma-grey-light);
|
||||
@media (prefers-color-scheme: dark) {
|
||||
background: $grey-light;
|
||||
border: 1px solid $grey-dark;
|
||||
background: var(--bulma-grey-light);
|
||||
border: 1px solid var(--bulma-grey-dark);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin thumb-inactive {
|
||||
box-sizing: border-box;
|
||||
background-color: $light;
|
||||
background-color: var(--bulma-light);
|
||||
@media (prefers-color-scheme: dark) {
|
||||
background-color: $grey-dark;
|
||||
border: 1px solid $grey-darker;
|
||||
background-color: var(--bulma-grey-dark);
|
||||
border: 1px solid var(--bulma-grey-darker);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin track {
|
||||
height: calc(var(--sh));
|
||||
border-radius: calc(var(--sh) / 2);
|
||||
background: linear-gradient(90deg, $dark var(--sx), $grey-light var(--sx));
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
var(--bulma-dark) var(--sx),
|
||||
var(--bulma-grey-light) var(--sx)
|
||||
);
|
||||
@media (prefers-color-scheme: dark) {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
$grey-light var(--sx),
|
||||
$grey-dark var(--sx)
|
||||
var(--bulma-grey-light) var(--sx),
|
||||
var(--bulma-grey-dark) var(--sx)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin track-inactive {
|
||||
background: linear-gradient(90deg, $grey-light var(--sx), $light var(--sx));
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
var(--bulma-grey-light) var(--sx),
|
||||
var(--bulma-light) var(--sx)
|
||||
);
|
||||
@media (prefers-color-scheme: dark) {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
$grey-dark var(--sx),
|
||||
$black-ter var(--sx)
|
||||
var(--bulma-grey-dark) var(--sx),
|
||||
var(--bulma-black-ter) var(--sx)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,47 +1,33 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<div>
|
||||
<tabs-music />
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :indices="albums.indices" />
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<p class="heading mb-5" v-text="$t('page.albums.filter')" />
|
||||
<p class="heading" v-text="$t('page.albums.filter')" />
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input
|
||||
id="switchHideSingles"
|
||||
v-model="hide_singles"
|
||||
type="checkbox"
|
||||
class="switch is-rounded"
|
||||
/>
|
||||
<label
|
||||
for="switchHideSingles"
|
||||
v-text="$t('page.albums.hide-singles')"
|
||||
/>
|
||||
</div>
|
||||
<control-switch v-model="uiStore.hide_singles">
|
||||
<template #label>
|
||||
<span v-text="$t('page.albums.hide-singles')" />
|
||||
</template>
|
||||
</control-switch>
|
||||
<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"
|
||||
class="switch is-rounded"
|
||||
/>
|
||||
<label
|
||||
for="switchHideSpotify"
|
||||
v-text="$t('page.albums.hide-spotify')"
|
||||
/>
|
||||
</div>
|
||||
<control-switch v-model="uiStore.hide_spotify">
|
||||
<template #label>
|
||||
<span v-text="$t('page.albums.hide-spotify')" />
|
||||
</template>
|
||||
</control-switch>
|
||||
<p class="help" v-text="$t('page.albums.hide-spotify-help')" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<p class="heading mb-5" v-text="$t('page.albums.sort.title')" />
|
||||
<p class="heading" v-text="$t('page.albums.sort.title')" />
|
||||
<control-dropdown
|
||||
v-model:value="selected_grouping_id"
|
||||
v-model:value="uiStore.albums_sort"
|
||||
:options="groupings"
|
||||
/>
|
||||
</div>
|
||||
@ -54,7 +40,6 @@
|
||||
v-text="$t('page.albums.count', { count: albums.count })"
|
||||
/>
|
||||
</template>
|
||||
<template #heading-right />
|
||||
<template #content>
|
||||
<list-albums :items="albums" />
|
||||
</template>
|
||||
@ -65,6 +50,7 @@
|
||||
<script>
|
||||
import ContentWithHeading from '@/templates/ContentWithHeading.vue'
|
||||
import ControlDropdown from '@/components/ControlDropdown.vue'
|
||||
import ControlSwitch from '@/components/ControlSwitch.vue'
|
||||
import { GroupedList } from '@/lib/GroupedList'
|
||||
import IndexButtonList from '@/components/IndexButtonList.vue'
|
||||
import ListAlbums from '@/components/ListAlbums.vue'
|
||||
@ -88,6 +74,7 @@ export default {
|
||||
components: {
|
||||
ContentWithHeading,
|
||||
ControlDropdown,
|
||||
ControlSwitch,
|
||||
IndexButtonList,
|
||||
ListAlbums,
|
||||
TabsMusic
|
||||
@ -157,43 +144,17 @@ export default {
|
||||
computed: {
|
||||
albums() {
|
||||
const { options } = this.groupings.find(
|
||||
(grouping) => grouping.id === this.selected_grouping_id
|
||||
(grouping) => grouping.id === this.uiStore.albums_sort
|
||||
)
|
||||
options.filters = [
|
||||
(album) => !this.hide_singles || album.track_count > 2,
|
||||
(album) => !this.hide_spotify || album.data_kind !== 'spotify'
|
||||
(album) => !this.uiStore.hide_singles || album.track_count > 2,
|
||||
(album) => !this.uiStore.hide_spotify || album.data_kind !== 'spotify'
|
||||
]
|
||||
return this.albums_list.group(options)
|
||||
},
|
||||
hide_singles: {
|
||||
get() {
|
||||
return this.uiStore.hide_singles
|
||||
},
|
||||
set(value) {
|
||||
this.uiStore.hide_singles = value
|
||||
}
|
||||
},
|
||||
hide_spotify: {
|
||||
get() {
|
||||
return this.uiStore.hide_spotify
|
||||
},
|
||||
set(value) {
|
||||
this.uiStore.hide_spotify = value
|
||||
}
|
||||
},
|
||||
selected_grouping_id: {
|
||||
get() {
|
||||
return this.uiStore.albums_sort
|
||||
},
|
||||
set(value) {
|
||||
this.uiStore.albums_sort = value
|
||||
}
|
||||
},
|
||||
spotify_enabled() {
|
||||
return this.servicesStore.spotify.webapi_token_valid
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
@ -4,27 +4,20 @@
|
||||
<template #options>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<p class="heading mb-5" v-text="$t('page.artist.filter')" />
|
||||
<p class="heading" v-text="$t('page.artist.filter')" />
|
||||
<div v-if="spotify_enabled" class="field">
|
||||
<div class="control">
|
||||
<input
|
||||
id="switchHideSpotify"
|
||||
v-model="hide_spotify"
|
||||
type="checkbox"
|
||||
class="switch is-rounded"
|
||||
/>
|
||||
<label
|
||||
for="switchHideSpotify"
|
||||
v-text="$t('page.artist.hide-spotify')"
|
||||
/>
|
||||
</div>
|
||||
<control-switch v-model="uiStore.hide_spotify">
|
||||
<template #label>
|
||||
<span v-text="$t('page.artist.hide-spotify')" />
|
||||
</template>
|
||||
</control-switch>
|
||||
<p class="help" v-text="$t('page.artist.hide-spotify-help')" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<p class="heading mb-5" v-text="$t('page.artist.sort.title')" />
|
||||
<p class="heading" v-text="$t('page.artist.sort.title')" />
|
||||
<control-dropdown
|
||||
v-model:value="selected_grouping_id"
|
||||
v-model:value="uiStore.artist_albums_sort"
|
||||
:options="groupings"
|
||||
/>
|
||||
</div>
|
||||
@ -73,6 +66,7 @@
|
||||
<script>
|
||||
import ContentWithHeading from '@/templates/ContentWithHeading.vue'
|
||||
import ControlDropdown from '@/components/ControlDropdown.vue'
|
||||
import ControlSwitch from '@/components/ControlSwitch.vue'
|
||||
import { GroupedList } from '@/lib/GroupedList'
|
||||
import ListAlbums from '@/components/ListAlbums.vue'
|
||||
import ModalDialogArtist from '@/components/ModalDialogArtist.vue'
|
||||
@ -99,6 +93,7 @@ export default {
|
||||
components: {
|
||||
ContentWithHeading,
|
||||
ControlDropdown,
|
||||
ControlSwitch,
|
||||
ListAlbums,
|
||||
ModalDialogArtist
|
||||
},
|
||||
@ -136,29 +131,13 @@ export default {
|
||||
computed: {
|
||||
albums() {
|
||||
const { options } = this.groupings.find(
|
||||
(grouping) => grouping.id === this.selected_grouping_id
|
||||
(grouping) => grouping.id === this.uiStore.artist_albums_sort
|
||||
)
|
||||
options.filters = [
|
||||
(album) => !this.hide_spotify || album.data_kind !== 'spotify'
|
||||
(album) => !this.uiStore.hide_spotify || album.data_kind !== 'spotify'
|
||||
]
|
||||
return this.albums_list.group(options)
|
||||
},
|
||||
hide_spotify: {
|
||||
get() {
|
||||
return this.uiStore.hide_spotify
|
||||
},
|
||||
set(value) {
|
||||
this.uiStore.hide_spotify = value
|
||||
}
|
||||
},
|
||||
selected_grouping_id: {
|
||||
get() {
|
||||
return this.uiStore.artist_albums_sort
|
||||
},
|
||||
set(value) {
|
||||
this.uiStore.artist_albums_sort = value
|
||||
}
|
||||
},
|
||||
spotify_enabled() {
|
||||
return this.servicesStore.spotify.webapi_token_valid
|
||||
},
|
||||
@ -187,5 +166,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
@ -5,27 +5,20 @@
|
||||
<index-button-list :indices="tracks.indices" />
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<p class="heading mb-5" v-text="$t('page.artist.filter')" />
|
||||
<p class="heading" v-text="$t('page.artist.filter')" />
|
||||
<div v-if="spotify_enabled" class="field">
|
||||
<div class="control">
|
||||
<input
|
||||
id="switchHideSpotify"
|
||||
v-model="hide_spotify"
|
||||
type="checkbox"
|
||||
class="switch is-rounded"
|
||||
/>
|
||||
<label
|
||||
for="switchHideSpotify"
|
||||
v-text="$t('page.artist.hide-spotify')"
|
||||
/>
|
||||
</div>
|
||||
<control-switch v-model="uiStore.hide_spotify">
|
||||
<template #label>
|
||||
<span v-text="$t('page.artist.hide-spotify')" />
|
||||
</template>
|
||||
</control-switch>
|
||||
<p class="help" v-text="$t('page.artist.hide-spotify-help')" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<p class="heading mb-5" v-text="$t('page.artist.sort.title')" />
|
||||
<p class="heading" v-text="$t('page.artist.sort.title')" />
|
||||
<control-dropdown
|
||||
v-model:value="selected_grouping_id"
|
||||
v-model:value="uiStore.artist_tracks_sort"
|
||||
:options="groupings"
|
||||
/>
|
||||
</div>
|
||||
@ -74,6 +67,7 @@
|
||||
<script>
|
||||
import ContentWithHeading from '@/templates/ContentWithHeading.vue'
|
||||
import ControlDropdown from '@/components/ControlDropdown.vue'
|
||||
import ControlSwitch from '@/components/ControlSwitch.vue'
|
||||
import { GroupedList } from '@/lib/GroupedList'
|
||||
import IndexButtonList from '@/components/IndexButtonList.vue'
|
||||
import ListTracks from '@/components/ListTracks.vue'
|
||||
@ -101,6 +95,7 @@ export default {
|
||||
components: {
|
||||
ContentWithHeading,
|
||||
ControlDropdown,
|
||||
ControlSwitch,
|
||||
IndexButtonList,
|
||||
ListTracks,
|
||||
ModalDialogArtist
|
||||
@ -147,22 +142,6 @@ export default {
|
||||
.map((track) => track.item.album_id)
|
||||
).size
|
||||
},
|
||||
hide_spotify: {
|
||||
get() {
|
||||
return this.uiStore.hide_spotify
|
||||
},
|
||||
set(value) {
|
||||
this.uiStore.hide_spotify = value
|
||||
}
|
||||
},
|
||||
selected_grouping_id: {
|
||||
get() {
|
||||
return this.uiStore.artist_tracks_sort
|
||||
},
|
||||
set(value) {
|
||||
this.uiStore.artist_tracks_sort = value
|
||||
}
|
||||
},
|
||||
spotify_enabled() {
|
||||
return this.servicesStore.spotify.webapi_token_valid
|
||||
},
|
||||
@ -171,10 +150,10 @@ export default {
|
||||
},
|
||||
tracks() {
|
||||
const { options } = this.groupings.find(
|
||||
(grouping) => grouping.id === this.selected_grouping_id
|
||||
(grouping) => grouping.id === this.uiStore.artist_tracks_sort
|
||||
)
|
||||
options.filters = [
|
||||
(track) => !this.hide_spotify || track.data_kind !== 'spotify'
|
||||
(track) => !this.uiStore.hide_spotify || track.data_kind !== 'spotify'
|
||||
]
|
||||
return this.tracks_list.group(options)
|
||||
}
|
||||
@ -197,5 +176,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
@ -1,47 +1,33 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<div>
|
||||
<tabs-music />
|
||||
<content-with-heading>
|
||||
<template #options>
|
||||
<index-button-list :indices="artists.indices" />
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<p class="heading mb-5" v-text="$t('page.artists.filter')" />
|
||||
<p class="heading" v-text="$t('page.artists.filter')" />
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input
|
||||
id="switchHideSingles"
|
||||
v-model="hide_singles"
|
||||
type="checkbox"
|
||||
class="switch is-rounded"
|
||||
/>
|
||||
<label
|
||||
for="switchHideSingles"
|
||||
v-text="$t('page.artists.hide-singles')"
|
||||
/>
|
||||
</div>
|
||||
<control-switch v-model="uiStore.hide_singles">
|
||||
<template #label>
|
||||
<span v-text="$t('page.artists.hide-singles')" />
|
||||
</template>
|
||||
</control-switch>
|
||||
<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"
|
||||
class="switch is-rounded"
|
||||
/>
|
||||
<label
|
||||
for="switchHideSpotify"
|
||||
v-text="$t('page.artists.hide-spotify')"
|
||||
/>
|
||||
</div>
|
||||
<control-switch v-model="uiStore.hide_spotify">
|
||||
<template #label>
|
||||
<span v-text="$t('page.artists.hide-spotify')" />
|
||||
</template>
|
||||
</control-switch>
|
||||
<p class="help" v-text="$t('page.artists.hide-spotify-help')" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<p class="heading mb-5" v-text="$t('page.artists.sort.title')" />
|
||||
<p class="heading" v-text="$t('page.artists.sort.title')" />
|
||||
<control-dropdown
|
||||
v-model:value="selected_grouping_id"
|
||||
v-model:value="uiStore.artists_sort"
|
||||
:options="groupings"
|
||||
/>
|
||||
</div>
|
||||
@ -54,7 +40,6 @@
|
||||
v-text="$t('page.artists.count', { count: artists.count })"
|
||||
/>
|
||||
</template>
|
||||
<template #heading-right />
|
||||
<template #content>
|
||||
<list-artists :items="artists" />
|
||||
</template>
|
||||
@ -65,6 +50,7 @@
|
||||
<script>
|
||||
import ContentWithHeading from '@/templates/ContentWithHeading.vue'
|
||||
import ControlDropdown from '@/components/ControlDropdown.vue'
|
||||
import ControlSwitch from '@/components/ControlSwitch.vue'
|
||||
import { GroupedList } from '@/lib/GroupedList'
|
||||
import IndexButtonList from '@/components/IndexButtonList.vue'
|
||||
import ListArtists from '@/components/ListArtists.vue'
|
||||
@ -88,6 +74,7 @@ export default {
|
||||
components: {
|
||||
ContentWithHeading,
|
||||
ControlDropdown,
|
||||
ControlSwitch,
|
||||
IndexButtonList,
|
||||
ListArtists,
|
||||
TabsMusic
|
||||
@ -125,47 +112,21 @@ export default {
|
||||
},
|
||||
|
||||
computed: {
|
||||
// Wraps GroupedList and updates it if filter or sort changes
|
||||
artists() {
|
||||
const { options } = this.groupings.find(
|
||||
(grouping) => grouping.id === this.selected_grouping_id
|
||||
(grouping) => grouping.id === this.uiStore.artists_sort
|
||||
)
|
||||
options.filters = [
|
||||
(artist) =>
|
||||
!this.hide_singles || artist.track_count > artist.album_count * 2,
|
||||
(artist) => !this.hide_spotify || artist.data_kind !== 'spotify'
|
||||
!this.uiStore.hide_singles ||
|
||||
artist.track_count > artist.album_count * 2,
|
||||
(artist) => !this.uiStore.hide_spotify || artist.data_kind !== 'spotify'
|
||||
]
|
||||
return this.artists_list.group(options)
|
||||
},
|
||||
hide_singles: {
|
||||
get() {
|
||||
return this.uiStore.hide_singles
|
||||
},
|
||||
set(value) {
|
||||
this.uiStore.hide_singles = value
|
||||
}
|
||||
},
|
||||
hide_spotify: {
|
||||
get() {
|
||||
return this.uiStore.hide_spotify
|
||||
},
|
||||
set(value) {
|
||||
this.uiStore.hide_spotify = value
|
||||
}
|
||||
},
|
||||
selected_grouping_id: {
|
||||
get() {
|
||||
return this.uiStore.artists_sort
|
||||
},
|
||||
set(value) {
|
||||
this.uiStore.artists_sort = value
|
||||
}
|
||||
},
|
||||
spotify_enabled() {
|
||||
return this.servicesStore.spotify.webapi_token_valid
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
@ -87,5 +87,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
@ -104,5 +104,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
@ -5,9 +5,9 @@
|
||||
<index-button-list :indices="tracks.indices" />
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<p class="heading mb-5" v-text="$t('page.artist.sort.title')" />
|
||||
<p class="heading" v-text="$t('page.artist.sort.title')" />
|
||||
<control-dropdown
|
||||
v-model:value="selected_grouping_id"
|
||||
v-model:value="uiStore.composer_tracks_sort"
|
||||
:options="groupings"
|
||||
/>
|
||||
</div>
|
||||
@ -130,17 +130,9 @@ export default {
|
||||
expression() {
|
||||
return `composer is "${this.composer.name}" and media_kind is music`
|
||||
},
|
||||
selected_grouping_id: {
|
||||
get() {
|
||||
return this.uiStore.composer_tracks_sort
|
||||
},
|
||||
set(value) {
|
||||
this.uiStore.composer_tracks_sort = value
|
||||
}
|
||||
},
|
||||
tracks() {
|
||||
const { options } = this.groupings.find(
|
||||
(grouping) => grouping.id === this.selected_grouping_id
|
||||
(grouping) => grouping.id === this.uiStore.composer_tracks_sort
|
||||
)
|
||||
return this.tracks_list.group(options)
|
||||
}
|
||||
@ -160,5 +152,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
@ -5,9 +5,9 @@
|
||||
<index-button-list :indices="tracks.indices" />
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
<p class="heading mb-5" v-text="$t('page.genre.sort.title')" />
|
||||
<p class="heading" v-text="$t('page.genre.sort.title')" />
|
||||
<control-dropdown
|
||||
v-model:value="selected_grouping_id"
|
||||
v-model:value="uiStore.genre_tracks_sort"
|
||||
:options="groupings"
|
||||
/>
|
||||
</div>
|
||||
@ -126,17 +126,9 @@ export default {
|
||||
expression() {
|
||||
return `genre is "${this.genre.name}" and media_kind is ${this.media_kind}`
|
||||
},
|
||||
selected_grouping_id: {
|
||||
get() {
|
||||
return this.uiStore.genre_tracks_sort
|
||||
},
|
||||
set(value) {
|
||||
this.uiStore.genre_tracks_sort = value
|
||||
}
|
||||
},
|
||||
tracks() {
|
||||
const { options } = this.groupings.find(
|
||||
(grouping) => grouping.id === this.selected_grouping_id
|
||||
(grouping) => grouping.id === this.uiStore.genre_tracks_sort
|
||||
)
|
||||
return this.tracks_list.group(options)
|
||||
}
|
||||
@ -157,5 +149,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="fd-page-with-tabs">
|
||||
<div>
|
||||
<tabs-settings />
|
||||
<content-with-heading>
|
||||
<template #heading-left>
|
||||
@ -51,16 +51,15 @@
|
||||
/>
|
||||
<div v-for="output in outputs" :key="output.id">
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<input
|
||||
:id="output.id"
|
||||
v-model="output.selected"
|
||||
type="checkbox"
|
||||
class="switch is-rounded mr-2"
|
||||
@change="output_toggle(output.id)"
|
||||
/>
|
||||
<label :for="output.id" class="checkbox" v-text="output.name" />
|
||||
</div>
|
||||
<control-switch
|
||||
:id="output.id"
|
||||
v-model="output.selected"
|
||||
@update:model-value="toggleOutput(output.id)"
|
||||
>
|
||||
<template #label>
|
||||
<span v-text="output.name" />
|
||||
</template>
|
||||
</control-switch>
|
||||
</div>
|
||||
<form
|
||||
v-if="output.needs_auth_key"
|
||||
@ -94,6 +93,7 @@
|
||||
|
||||
<script>
|
||||
import ContentWithHeading from '@/templates/ContentWithHeading.vue'
|
||||
import ControlSwitch from '@/components/ControlSwitch.vue'
|
||||
import TabsSettings from '@/components/TabsSettings.vue'
|
||||
import { useOutputsStore } from '@/stores/outputs'
|
||||
import { useRemotesStore } from '@/stores/remotes'
|
||||
@ -101,7 +101,7 @@ import webapi from '@/webapi'
|
||||
|
||||
export default {
|
||||
name: 'PageSettingsRemotesOutputs',
|
||||
components: { ContentWithHeading, TabsSettings },
|
||||
components: { ContentWithHeading, ControlSwitch, TabsSettings },
|
||||
|
||||
setup() {
|
||||
return { outputsStore: useOutputsStore(), remotesStore: useRemotesStore() }
|
||||
@ -127,14 +127,12 @@ export default {
|
||||
kickoff_pairing() {
|
||||
webapi.pairing_kickoff(this.pairing_req)
|
||||
},
|
||||
kickoff_verification(outputId) {
|
||||
webapi.output_update(outputId, this.verification_req)
|
||||
kickoff_verification(identifier) {
|
||||
webapi.output_update(identifier, this.verification_req)
|
||||
},
|
||||
output_toggle(outputId) {
|
||||
webapi.output_toggle(outputId)
|
||||
toggleOutput(identifier) {
|
||||
webapi.output_toggle(identifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
Loading…
x
Reference in New Issue
Block a user