mirror of
https://github.com/owntone/owntone-server.git
synced 2025-07-21 06:21:19 -04:00
[web] Add the ability to change the appearance of the UI
This commit is contained in:
parent
a7d4501632
commit
4bd8736346
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
16
web-src/package-lock.json
generated
16
web-src/package-lock.json
generated
@ -15,7 +15,7 @@
|
|||||||
"bulma": "^1.0.4",
|
"bulma": "^1.0.4",
|
||||||
"luxon": "^3.6.1",
|
"luxon": "^3.6.1",
|
||||||
"mdi-vue": "^3.0.13",
|
"mdi-vue": "^3.0.13",
|
||||||
"pinia": "^3.0.2",
|
"pinia": "^3.0.3",
|
||||||
"reconnectingwebsocket": "^1.0.0",
|
"reconnectingwebsocket": "^1.0.0",
|
||||||
"spotify-web-api-js": "^1.5.2",
|
"spotify-web-api-js": "^1.5.2",
|
||||||
"vue": "^3.5.16",
|
"vue": "^3.5.16",
|
||||||
@ -30,7 +30,7 @@
|
|||||||
"@vitejs/plugin-vue": "^5.2.4",
|
"@vitejs/plugin-vue": "^5.2.4",
|
||||||
"eslint": "^9.28.0",
|
"eslint": "^9.28.0",
|
||||||
"eslint-config-prettier": "^10.1.5",
|
"eslint-config-prettier": "^10.1.5",
|
||||||
"eslint-plugin-vue": "^10.1.0",
|
"eslint-plugin-vue": "^10.2.0",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"sass": "^1.89.1",
|
"sass": "^1.89.1",
|
||||||
"vite": "^6.3.5"
|
"vite": "^6.3.5"
|
||||||
@ -2512,9 +2512,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-plugin-vue": {
|
"node_modules/eslint-plugin-vue": {
|
||||||
"version": "10.1.0",
|
"version": "10.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.2.0.tgz",
|
||||||
"integrity": "sha512-/VTiJ1eSfNLw6lvG9ENySbGmcVvz6wZ9nA7ZqXlLBY2RkaF15iViYKxglWiIch12KiLAj0j1iXPYU6W4wTROFA==",
|
"integrity": "sha512-tl9s+KN3z0hN2b8fV2xSs5ytGl7Esk1oSCxULLwFcdaElhZ8btYYZFrWxvh4En+czrSDtuLCeCOGa8HhEZuBdQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -3570,9 +3570,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pinia": {
|
"node_modules/pinia": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.3.tgz",
|
||||||
"integrity": "sha512-sH2JK3wNY809JOeiiURUR0wehJ9/gd9qFN2Y828jCbxEzKEmEt0pzCXwqiSTfuRsK9vQsOflSdnbdBOGrhtn+g==",
|
"integrity": "sha512-ttXO/InUULUXkMHpTdp9Fj4hLpD/2AoJdmAbAeW2yu1iy1k+pkFekQXw5VpC0/5p51IOR/jDaDRfRWRnMMsGOA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/devtools-api": "^7.7.2"
|
"@vue/devtools-api": "^7.7.2"
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
"bulma": "^1.0.4",
|
"bulma": "^1.0.4",
|
||||||
"luxon": "^3.6.1",
|
"luxon": "^3.6.1",
|
||||||
"mdi-vue": "^3.0.13",
|
"mdi-vue": "^3.0.13",
|
||||||
"pinia": "^3.0.2",
|
"pinia": "^3.0.3",
|
||||||
"reconnectingwebsocket": "^1.0.0",
|
"reconnectingwebsocket": "^1.0.0",
|
||||||
"spotify-web-api-js": "^1.5.2",
|
"spotify-web-api-js": "^1.5.2",
|
||||||
"vue": "^3.5.16",
|
"vue": "^3.5.16",
|
||||||
@ -34,7 +34,7 @@
|
|||||||
"@vitejs/plugin-vue": "^5.2.4",
|
"@vitejs/plugin-vue": "^5.2.4",
|
||||||
"eslint": "^9.28.0",
|
"eslint": "^9.28.0",
|
||||||
"eslint-config-prettier": "^10.1.5",
|
"eslint-config-prettier": "^10.1.5",
|
||||||
"eslint-plugin-vue": "^10.1.0",
|
"eslint-plugin-vue": "^10.2.0",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"sass": "^1.89.1",
|
"sass": "^1.89.1",
|
||||||
"vite": "^6.3.5"
|
"vite": "^6.3.5"
|
||||||
|
@ -36,50 +36,27 @@ export default {
|
|||||||
height: var(--th);
|
height: var(--th);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: var(--bulma-light);
|
background: var(--bulma-text);
|
||||||
border: 1px solid var(--bulma-grey-lighter);
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
background: var(--bulma-grey-lighter);
|
|
||||||
border: 1px solid var(--bulma-grey-dark);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@mixin thumb-inactive {
|
@mixin thumb-inactive {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
background-color: var(--bulma-light);
|
background-color: var(--bulma-border);
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
background-color: var(--bulma-grey-dark);
|
|
||||||
border: 1px solid var(--bulma-grey-darker);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@mixin track {
|
@mixin track {
|
||||||
height: calc(var(--sh));
|
height: calc(var(--sh));
|
||||||
border-radius: calc(var(--sh) / 2);
|
border-radius: calc(var(--sh) / 2);
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
90deg,
|
90deg,
|
||||||
var(--bulma-dark) var(--sx),
|
var(--bulma-text) var(--sx),
|
||||||
var(--bulma-grey-lighter) var(--sx)
|
var(--bulma-border) var(--sx)
|
||||||
);
|
);
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
background: linear-gradient(
|
|
||||||
90deg,
|
|
||||||
var(--bulma-grey-lighter) var(--sx),
|
|
||||||
var(--bulma-grey-dark) var(--sx)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@mixin track-inactive {
|
@mixin track-inactive {
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
90deg,
|
90deg,
|
||||||
var(--bulma-grey-light) var(--sx),
|
var(--bulma-border) var(--sx),
|
||||||
var(--bulma-light) var(--sx)
|
var(--bulma-background) var(--sx)
|
||||||
);
|
);
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
background: linear-gradient(
|
|
||||||
90deg,
|
|
||||||
var(--bulma-grey-dark) var(--sx),
|
|
||||||
var(--bulma-black-ter) var(--sx)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
input[type='range'].slider {
|
input[type='range'].slider {
|
||||||
--ratio: v-bind(ratio);
|
--ratio: v-bind(ratio);
|
||||||
|
@ -34,7 +34,7 @@ export default {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
&-switch {
|
&-switch {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
background: var(--bulma-grey-lighter);
|
background: var(--bulma-border);
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
width: 2.25rem;
|
width: 2.25rem;
|
||||||
height: 1.25rem;
|
height: 1.25rem;
|
||||||
@ -45,7 +45,7 @@ export default {
|
|||||||
&:before {
|
&:before {
|
||||||
content: '';
|
content: '';
|
||||||
display: block;
|
display: block;
|
||||||
background: var(--bulma-white);
|
background: var(--bulma-background);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
width: 1rem;
|
width: 1rem;
|
||||||
height: 1rem;
|
height: 1rem;
|
||||||
@ -56,12 +56,12 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:hover &-switch:before {
|
&:hover &-switch:before {
|
||||||
background: var(--bulma-white);
|
background: var(--bulma-background);
|
||||||
}
|
}
|
||||||
&-checkbox {
|
&-checkbox {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
&:checked + .toggle-switch {
|
&:checked + .toggle-switch {
|
||||||
background: var(--bulma-dark);
|
background: var(--bulma-text);
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
left: 1.125rem;
|
left: 1.125rem;
|
||||||
|
@ -55,6 +55,10 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.card-content {
|
||||||
|
max-height: calc(100vh - calc(4 * var(--bulma-navbar-height)));
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
.fade-leave-active {
|
.fade-leave-active {
|
||||||
transition: opacity 0.2s ease;
|
transition: opacity 0.2s ease;
|
||||||
}
|
}
|
||||||
@ -69,10 +73,6 @@ export default {
|
|||||||
.fade-leave-from {
|
.fade-leave-from {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
.card-content {
|
|
||||||
max-height: calc(100vh - calc(4 * var(--bulma-navbar-height)));
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
.is-disabled {
|
.is-disabled {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
@ -80,4 +80,7 @@ export default {
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.modal-background {
|
||||||
|
background-color: rgba(10, 10, 10, 0.5);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<nav class="navbar is-fixed-bottom" :class="{ 'is-dark': !isPlayerPage }">
|
<nav class="navbar is-fixed-bottom" :class="{ 'is-bottom': !isPlayerPage }">
|
||||||
<div class="navbar-brand is-flex-grow-1">
|
<div class="navbar-brand is-flex-grow-1">
|
||||||
<control-link class="navbar-item" :to="{ name: 'queue' }">
|
<control-link class="navbar-item" :to="{ name: 'queue' }">
|
||||||
<mdicon class="icon" name="playlist-play" />
|
<mdicon class="icon" name="playlist-play" />
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<nav class="navbar is-fixed-top is-light" :style="zindex">
|
<nav class="navbar is-fixed-top is-top" :style="zindex">
|
||||||
<div class="navbar-brand is-flex-grow-1">
|
<div class="navbar-brand is-flex-grow-1">
|
||||||
<control-link
|
<control-link
|
||||||
v-for="menu in menus.filter((menu) => menu.show && !menu.sub)"
|
v-for="menu in menus.filter((menu) => menu.show && !menu.sub)"
|
||||||
|
@ -331,6 +331,12 @@
|
|||||||
"request-failed": "Anfrage gescheitert (Status: {status} {cause} {url})"
|
"request-failed": "Anfrage gescheitert (Status: {status} {cause} {url})"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
|
"appearance": {
|
||||||
|
"auto": "Automatisch",
|
||||||
|
"dark": "Dunkel",
|
||||||
|
"light": "Hell",
|
||||||
|
"title": "Erscheinungsbild"
|
||||||
|
},
|
||||||
"artwork": {
|
"artwork": {
|
||||||
"explanation-1": "OwnTone verarbeitet PNG- und JPEG-Artwork, welches in einer eigenen Datei in der Bibliothek, in die Dateien eingebettet oder online von Radiostationen bereitgestellt werden kann.",
|
"explanation-1": "OwnTone verarbeitet PNG- und JPEG-Artwork, welches in einer eigenen Datei in der Bibliothek, in die Dateien eingebettet oder online von Radiostationen bereitgestellt werden kann.",
|
||||||
"explanation-2": "Zusätzlich kann auf folgende Artwork-Anbieter zugegriffen werden:",
|
"explanation-2": "Zusätzlich kann auf folgende Artwork-Anbieter zugegriffen werden:",
|
||||||
|
@ -331,6 +331,12 @@
|
|||||||
"request-failed": "Request failed (status: {status} {cause} {url})"
|
"request-failed": "Request failed (status: {status} {cause} {url})"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
|
"appearance": {
|
||||||
|
"auto": "Auto",
|
||||||
|
"dark": "Dark",
|
||||||
|
"light": "Light",
|
||||||
|
"title": "Appearance"
|
||||||
|
},
|
||||||
"artwork": {
|
"artwork": {
|
||||||
"explanation-1": "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.",
|
"explanation-1": "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.",
|
||||||
"explanation-2": "In addition to that, you can enable fetching artwork from the following artwork providers:",
|
"explanation-2": "In addition to that, you can enable fetching artwork from the following artwork providers:",
|
||||||
|
@ -331,6 +331,12 @@
|
|||||||
"request-failed": "La requête a échoué (status: {status} {cause} {url})"
|
"request-failed": "La requête a échoué (status: {status} {cause} {url})"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
|
"appearance": {
|
||||||
|
"auto": "Automatique",
|
||||||
|
"dark": "Sombre",
|
||||||
|
"light": "Clair",
|
||||||
|
"title": "Mode d’apparence"
|
||||||
|
},
|
||||||
"artwork": {
|
"artwork": {
|
||||||
"explanation-1": "OwnTone prend en charge les illustrations au format PNG et JPEG qui sont soit placées dans la bibliothèque en tant que fichiers image séparés, soit intégrées dans les fichiers média, soit mises à disposition en ligne par les stations de radio.",
|
"explanation-1": "OwnTone prend en charge les illustrations au format PNG et JPEG qui sont soit placées dans la bibliothèque en tant que fichiers image séparés, soit intégrées dans les fichiers média, soit mises à disposition en ligne par les stations de radio.",
|
||||||
"explanation-2": "En outre, vous pouvez activer la récupération des illustrations à partir des fournisseurs d’illustrations suivants :",
|
"explanation-2": "En outre, vous pouvez activer la récupération des illustrations à partir des fournisseurs d’illustrations suivants :",
|
||||||
|
@ -331,6 +331,12 @@
|
|||||||
"request-failed": "请求失败 (状态:{status} {cause} {url})"
|
"request-failed": "请求失败 (状态:{status} {cause} {url})"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
|
"appearance": {
|
||||||
|
"auto": "自动",
|
||||||
|
"dark": "深色",
|
||||||
|
"light": "浅色",
|
||||||
|
"title": "外观"
|
||||||
|
},
|
||||||
"artwork": {
|
"artwork": {
|
||||||
"explanation-1": "OwnTone支持PNG和 JPEG封面,这些封面可以作为单独的图像文件放置在库中或嵌入到媒体文件中,也可以通过广播电台在线提供",
|
"explanation-1": "OwnTone支持PNG和 JPEG封面,这些封面可以作为单独的图像文件放置在库中或嵌入到媒体文件中,也可以通过广播电台在线提供",
|
||||||
"explanation-2": "除此之外,您还可以从以下素材提供者获取封面:",
|
"explanation-2": "除此之外,您还可以从以下素材提供者获取封面:",
|
||||||
|
@ -331,6 +331,12 @@
|
|||||||
"request-failed": "請求失敗 (狀態:{status} {cause} {url})"
|
"request-failed": "請求失敗 (狀態:{status} {cause} {url})"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
|
"appearance": {
|
||||||
|
"auto": "自動",
|
||||||
|
"dark": "深色",
|
||||||
|
"light": "淺色",
|
||||||
|
"title": "外觀"
|
||||||
|
},
|
||||||
"artwork": {
|
"artwork": {
|
||||||
"explanation-1": "OwnTone支持PNG和 JPEG封面,這些封面可以作為單獨的圖像文件放置在庫中或嵌入到媒體文件中,也可以通過電台在線提供",
|
"explanation-1": "OwnTone支持PNG和 JPEG封面,這些封面可以作為單獨的圖像文件放置在庫中或嵌入到媒體文件中,也可以通過電台在線提供",
|
||||||
"explanation-2": "除此之外,您還可以從以下素材提供者獲取封面:",
|
"explanation-2": "除此之外,您還可以從以下素材提供者獲取封面:",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import './mystyles.scss'
|
import './styles.scss'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import VueClickAway from 'vue3-click-away'
|
import VueClickAway from 'vue3-click-away'
|
||||||
import VueLazyLoad from 'vue3-lazyload'
|
import VueLazyLoad from 'vue3-lazyload'
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
@charset "utf-8";
|
|
||||||
|
|
||||||
@use 'bulma/bulma';
|
|
||||||
@use 'bulma/sass/utilities/mixins';
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
.navbar {
|
|
||||||
background-color: var(--bulma-dark);
|
|
||||||
&-item {
|
|
||||||
--bulma-navbar-item-color: hsl(
|
|
||||||
var(--bulma-navbar-invert-h),
|
|
||||||
var(--bulma-navbar-invert-s),
|
|
||||||
var(--bulma-navbar-item-color-invert-l)
|
|
||||||
);
|
|
||||||
--bulma-navbar-item-background-l: var(--bulma-light-invert-l);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
button.navbar-item {
|
|
||||||
background-color: hsla(
|
|
||||||
var(--bulma-navbar-h),
|
|
||||||
var(--bulma-navbar-s),
|
|
||||||
calc(
|
|
||||||
var(--bulma-navbar-item-background-l) +
|
|
||||||
var(--bulma-navbar-item-background-l-delta)
|
|
||||||
),
|
|
||||||
var(--bulma-navbar-item-background-a)
|
|
||||||
);
|
|
||||||
&:hover {
|
|
||||||
--bulma-navbar-item-background-l-delta: var(
|
|
||||||
--bulma-navbar-item-hover-background-l-delta
|
|
||||||
);
|
|
||||||
--bulma-navbar-item-background-a: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-item {
|
|
||||||
width: var(--bulma-navbar-height);
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media:first-of-type {
|
|
||||||
padding-top: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-background {
|
|
||||||
background-color: rgba(10, 10, 10, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.overlay-fullscreen {
|
|
||||||
@extend .is-overlay;
|
|
||||||
z-index: 25;
|
|
||||||
background-color: rgba(10, 10, 10, 0.5);
|
|
||||||
position: fixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-menu.is-mobile {
|
|
||||||
@include mixins.mobile {
|
|
||||||
width: 100vw;
|
|
||||||
}
|
|
||||||
.dropdown-content {
|
|
||||||
max-height: calc(100vh - calc(2 * var(--bulma-navbar-height)));
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,6 +11,17 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</content-with-heading>
|
</content-with-heading>
|
||||||
|
<content-with-heading>
|
||||||
|
<template #heading>
|
||||||
|
<pane-title :content="{ title: $t('settings.appearance.title') }" />
|
||||||
|
</template>
|
||||||
|
<template #content>
|
||||||
|
<control-dropdown
|
||||||
|
v-model:value="appearance"
|
||||||
|
:options="settingsStore.appearances"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</content-with-heading>
|
||||||
<content-with-heading>
|
<content-with-heading>
|
||||||
<template #heading>
|
<template #heading>
|
||||||
<pane-title
|
<pane-title
|
||||||
@ -127,6 +138,14 @@ export default {
|
|||||||
return { settingsStore: useSettingsStore() }
|
return { settingsStore: useSettingsStore() }
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
appearance: {
|
||||||
|
get() {
|
||||||
|
return this.settingsStore.currentAppearance()
|
||||||
|
},
|
||||||
|
set(appearance) {
|
||||||
|
this.settingsStore.setAppearance(appearance)
|
||||||
|
}
|
||||||
|
},
|
||||||
locale: {
|
locale: {
|
||||||
get() {
|
get() {
|
||||||
return this.settingsStore.currentLocale()
|
return this.settingsStore.currentLocale()
|
||||||
|
@ -6,6 +6,9 @@ const { t, availableLocales } = i18n.global
|
|||||||
|
|
||||||
export const useSettingsStore = defineStore('SettingsStore', {
|
export const useSettingsStore = defineStore('SettingsStore', {
|
||||||
actions: {
|
actions: {
|
||||||
|
currentAppearance() {
|
||||||
|
return this.$state.appearance
|
||||||
|
},
|
||||||
currentLocale() {
|
currentLocale() {
|
||||||
const languages = availableLocales
|
const languages = availableLocales
|
||||||
let locale = languages.find((lang) => lang === i18n.global.locale.value)
|
let locale = languages.find((lang) => lang === i18n.global.locale.value)
|
||||||
@ -31,6 +34,16 @@ export const useSettingsStore = defineStore('SettingsStore', {
|
|||||||
async initialise() {
|
async initialise() {
|
||||||
this.$state = await settings.state()
|
this.$state = await settings.state()
|
||||||
},
|
},
|
||||||
|
setAppearance(appearance) {
|
||||||
|
this.$state.appearance = appearance
|
||||||
|
if (appearance === 'dark') {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark')
|
||||||
|
} else if (appearance === 'light') {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'light')
|
||||||
|
} else {
|
||||||
|
document.documentElement.removeAttribute('data-theme')
|
||||||
|
}
|
||||||
|
},
|
||||||
setLocale(locale) {
|
setLocale(locale) {
|
||||||
i18n.global.locale.value = locale
|
i18n.global.locale.value = locale
|
||||||
},
|
},
|
||||||
@ -50,6 +63,13 @@ export const useSettingsStore = defineStore('SettingsStore', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
|
appearances() {
|
||||||
|
return [
|
||||||
|
{ id: 'auto', name: t('settings.appearance.auto') },
|
||||||
|
{ id: 'light', name: t('settings.appearance.light') },
|
||||||
|
{ id: 'dark', name: t('settings.appearance.dark') }
|
||||||
|
]
|
||||||
|
},
|
||||||
locales() {
|
locales() {
|
||||||
return availableLocales.map((item) => ({
|
return availableLocales.map((item) => ({
|
||||||
id: item,
|
id: item,
|
||||||
@ -81,5 +101,5 @@ export const useSettingsStore = defineStore('SettingsStore', {
|
|||||||
showMenuItemSearch: (state) =>
|
showMenuItemSearch: (state) =>
|
||||||
state.get('webinterface', 'show_menu_item_search')?.value ?? false
|
state.get('webinterface', 'show_menu_item_search')?.value ?? false
|
||||||
},
|
},
|
||||||
state: () => ({ categories: [] })
|
state: () => ({ appearance: 'auto', categories: [] })
|
||||||
})
|
})
|
||||||
|
55
web-src/src/styles.scss
Normal file
55
web-src/src/styles.scss
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
@charset "utf-8";
|
||||||
|
|
||||||
|
@use 'bulma/bulma';
|
||||||
|
@use 'bulma/sass/utilities/mixins';
|
||||||
|
|
||||||
|
@mixin navbar($theme) {
|
||||||
|
$bg: '--bulma-#{$theme}';
|
||||||
|
$bg-l: '--bulma-#{$theme}-l';
|
||||||
|
$color-l: '--bulma-#{$theme}-invert-l';
|
||||||
|
--bulma-navbar-background-color: var(#{$bg});
|
||||||
|
--bulma-navbar-item-background-l: var(#{$bg-l});
|
||||||
|
--bulma-navbar-item-color-l: var(#{$color-l});
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
.is-top {
|
||||||
|
@include navbar(dark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
.is-top {
|
||||||
|
@include navbar(light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-bottom {
|
||||||
|
@include navbar(dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-item {
|
||||||
|
width: var(--bulma-navbar-height);
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media:first-of-type {
|
||||||
|
padding-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay-fullscreen {
|
||||||
|
@extend .is-overlay;
|
||||||
|
z-index: 25;
|
||||||
|
background-color: rgba(10, 10, 10, 0.5);
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-menu.is-mobile {
|
||||||
|
@include mixins.mobile {
|
||||||
|
width: 100vw;
|
||||||
|
}
|
||||||
|
.dropdown-content {
|
||||||
|
max-height: calc(100vh - calc(2 * var(--bulma-navbar-height)));
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user