Add manual dark/light switch (#3901)
* Add manual dark/light switch * Improve color theme labels
This commit is contained in:
parent
47287956a6
commit
a3aba01adc
13 changed files with 219 additions and 143 deletions
|
|
@ -60,18 +60,16 @@
|
|||
"Segoe UI Symbol", "Noto Color Emoji";
|
||||
}
|
||||
|
||||
@media (--dark-mode) {
|
||||
:root {
|
||||
--evcc-grid: var(--bs-gray-medium);
|
||||
--evcc-background: var(--bs-gray-deep);
|
||||
--evcc-box: var(--bs-gray-dark);
|
||||
--evcc-default-text: var(--bs-white);
|
||||
--evcc-gray: var(--bs-gray-light);
|
||||
--evcc-accent1: var(--evcc-yellow);
|
||||
--evcc-accent2: var(--evcc-dark-green);
|
||||
--evcc-accent3: var(--evcc-darker-green);
|
||||
--bs-primary: var(--evcc-dark-green);
|
||||
}
|
||||
:root.dark {
|
||||
--evcc-grid: var(--bs-gray-medium);
|
||||
--evcc-background: var(--bs-gray-deep);
|
||||
--evcc-box: var(--bs-gray-dark);
|
||||
--evcc-default-text: var(--bs-white);
|
||||
--evcc-gray: var(--bs-gray-light);
|
||||
--evcc-accent1: var(--evcc-yellow);
|
||||
--evcc-accent2: var(--evcc-dark-green);
|
||||
--evcc-accent3: var(--evcc-darker-green);
|
||||
--bs-primary: var(--evcc-dark-green);
|
||||
}
|
||||
|
||||
html {
|
||||
|
|
@ -80,6 +78,10 @@ html {
|
|||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
html.no-transitions * {
|
||||
transition-duration: 0ms !important;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--evcc-background);
|
||||
color: var(--evcc-default-text);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import VueNumber from "vue-number-animation";
|
|||
import router from "./router";
|
||||
import i18n from "./i18n";
|
||||
import featureflags from "./featureflags";
|
||||
import { watchThemeChanges } from "./theme";
|
||||
|
||||
smoothscroll.polyfill();
|
||||
|
||||
|
|
@ -76,10 +77,4 @@ window.setInterval(function () {
|
|||
api.get("health").then(window.app.setOnline).catch(window.app.setOffline);
|
||||
}, 5000);
|
||||
|
||||
const isDarkMode = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
isDarkMode.addEventListener("change", updateThemeColor);
|
||||
function updateThemeColor() {
|
||||
const $el = document.querySelector("meta[name=theme-color]");
|
||||
$el.setAttribute("content", isDarkMode.matches ? "#020318" : "#f3f3f7");
|
||||
}
|
||||
updateThemeColor();
|
||||
watchThemeChanges();
|
||||
|
|
|
|||
|
|
@ -217,11 +217,10 @@ export default {
|
|||
background-color: var(--evcc-grid);
|
||||
color: var(--bs-white);
|
||||
}
|
||||
@media (--dark-mode) {
|
||||
.grid-import {
|
||||
color: var(--bs-dark);
|
||||
}
|
||||
html.dark .grid-import {
|
||||
color: var(--bs-dark);
|
||||
}
|
||||
|
||||
.self-consumption {
|
||||
background-color: var(--evcc-self);
|
||||
color: var(--bs-dark);
|
||||
|
|
|
|||
|
|
@ -31,9 +31,7 @@ export default {
|
|||
.letter {
|
||||
fill: #18191a;
|
||||
}
|
||||
@media (--dark-mode) {
|
||||
.letter {
|
||||
fill: var(--bs-white);
|
||||
}
|
||||
html.dark .letter {
|
||||
fill: var(--bs-white);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -53,11 +53,10 @@ export default {
|
|||
border-radius: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
@media (--dark-mode) {
|
||||
.phase {
|
||||
background-color: var(--bs-gray-bright);
|
||||
}
|
||||
html.dark .phase {
|
||||
background-color: var(--bs-gray-bright);
|
||||
}
|
||||
|
||||
.phase.inactive {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,11 @@
|
|||
{{ $t("header.about") }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<button type="button" class="dropdown-item" @click.stop="toggleTheme">
|
||||
{{ $t(`header.theme.${theme}`) }}
|
||||
</button>
|
||||
</li>
|
||||
<template v-if="providerLogins.length > 0">
|
||||
<li><hr class="dropdown-divider" /></li>
|
||||
<li>
|
||||
|
|
@ -64,7 +69,9 @@
|
|||
|
||||
<script>
|
||||
import "@h2d2/shopicons/es/regular/menu";
|
||||
|
||||
import baseAPI from "../baseapi";
|
||||
import { getThemePreference, setThemePreference, THEMES } from "../theme";
|
||||
|
||||
export default {
|
||||
name: "TopNavigation",
|
||||
|
|
@ -76,6 +83,9 @@ export default {
|
|||
},
|
||||
},
|
||||
},
|
||||
data: function () {
|
||||
return { theme: getThemePreference() };
|
||||
},
|
||||
computed: {
|
||||
logoutCount() {
|
||||
return this.providerLogins.filter((login) => !login.loggedIn).length;
|
||||
|
|
@ -90,6 +100,12 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
toggleTheme: function () {
|
||||
const currentIndex = THEMES.indexOf(this.theme);
|
||||
const nextIndex = currentIndex < THEMES.length - 1 ? currentIndex + 1 : 0;
|
||||
this.theme = THEMES[nextIndex];
|
||||
setThemePreference(this.theme);
|
||||
},
|
||||
handleProviderAuthorization: async function (provider) {
|
||||
if (!provider.loggedIn) {
|
||||
baseAPI.post(provider.loginPath).then(function (response) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,11 @@ export default {
|
|||
github: "GitHub",
|
||||
login: "Fahrzeug Logins",
|
||||
about: "Über evcc",
|
||||
theme: {
|
||||
auto: "Design: System",
|
||||
light: "Design: Hell",
|
||||
dark: "Design: Dunkel",
|
||||
},
|
||||
},
|
||||
footer: {
|
||||
version: {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,11 @@ export default {
|
|||
github: "GitHub",
|
||||
login: "Vehicle Logins",
|
||||
about: "About evcc",
|
||||
theme: {
|
||||
auto: "Design: System",
|
||||
light: "Design: Light",
|
||||
dark: "Design: Dark",
|
||||
},
|
||||
},
|
||||
footer: {
|
||||
version: {
|
||||
|
|
|
|||
57
assets/js/theme.js
Normal file
57
assets/js/theme.js
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
const darkModeMatcher = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
|
||||
const THEME_AUTO = "auto";
|
||||
const THEME_LIGHT = "light";
|
||||
const THEME_DARK = "dark";
|
||||
export const THEMES = [THEME_AUTO, THEME_LIGHT, THEME_DARK];
|
||||
const LOCAL_STORAGE_KEY = "theme";
|
||||
|
||||
export function getThemePreference() {
|
||||
try {
|
||||
const theme = window.localStorage[LOCAL_STORAGE_KEY];
|
||||
if (THEMES.includes(theme)) {
|
||||
return theme;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("unable to read theme from localStorage", e);
|
||||
}
|
||||
return THEME_AUTO;
|
||||
}
|
||||
|
||||
export function setThemePreference(theme) {
|
||||
console.log({ theme });
|
||||
if (!THEMES.includes(theme)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
window.localStorage[LOCAL_STORAGE_KEY] = theme;
|
||||
updateTheme();
|
||||
} catch (e) {
|
||||
console.error("unable to write theme to localStorage", e);
|
||||
}
|
||||
}
|
||||
|
||||
function updateTheme() {
|
||||
let theme = getThemePreference();
|
||||
|
||||
if (theme === THEME_AUTO) {
|
||||
theme = darkModeMatcher.matches ? THEME_DARK : THEME_LIGHT;
|
||||
}
|
||||
|
||||
// update iOS title bar color
|
||||
const themeColors = { light: "#f3f3f7", dark: "#020318" };
|
||||
document.querySelector("meta[name=theme-color]").setAttribute("content", themeColors[theme]);
|
||||
|
||||
// toggle the class on html root
|
||||
const $html = document.querySelector(":root");
|
||||
$html.classList.add("no-transitions");
|
||||
$html.classList.toggle("dark", theme === THEME_DARK);
|
||||
window.requestAnimationFrame(function () {
|
||||
$html.classList.remove("no-transitions");
|
||||
});
|
||||
}
|
||||
|
||||
export function watchThemeChanges() {
|
||||
darkModeMatcher.addEventListener("change", updateTheme);
|
||||
updateTheme();
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
109
dist/assets/index.aadc69fd.js
vendored
Normal file
109
dist/assets/index.aadc69fd.js
vendored
Normal file
File diff suppressed because one or more lines are too long
109
dist/assets/index.f9e9d211.js
vendored
109
dist/assets/index.f9e9d211.js
vendored
File diff suppressed because one or more lines are too long
4
dist/index.html
vendored
4
dist/index.html
vendored
|
|
@ -20,8 +20,8 @@
|
|||
<meta name="theme-color" content="#020318" />
|
||||
|
||||
<title>evcc</title>
|
||||
<script type="module" crossorigin src="./assets/index.f9e9d211.js"></script>
|
||||
<link rel="stylesheet" href="./assets/index.36f32821.css">
|
||||
<script type="module" crossorigin src="./assets/index.aadc69fd.js"></script>
|
||||
<link rel="stylesheet" href="./assets/index.78e2f4a8.css">
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue