From 5101ca7a1e800b5b117afd70d7e89f7c06428bc6 Mon Sep 17 00:00:00 2001 From: Vithorio Polten Date: Fri, 24 May 2024 22:28:39 -0300 Subject: [PATCH] feat(ui): Dark Mode (#2493) --- src_assets/common/assets/web/Navbar.vue | 121 +++++++++++------- src_assets/common/assets/web/ThemeToggle.vue | 46 +++++++ src_assets/common/assets/web/apps.html | 6 +- src_assets/common/assets/web/config.html | 8 +- .../assets/web/configs/tabs/AudioVideo.vue | 3 + .../tabs/audiovideo/DisplayModesSettings.vue | 8 ++ src_assets/common/assets/web/index.html | 2 +- src_assets/common/assets/web/init.js | 5 + src_assets/common/assets/web/password.html | 2 +- src_assets/common/assets/web/pin.html | 2 +- .../assets/web/public/assets/css/sunshine.css | 12 ++ .../assets/web/public/assets/locale/en.json | 4 + .../common/assets/web/template_header.html | 1 - src_assets/common/assets/web/theme.js | 84 ++++++++++++ .../common/assets/web/troubleshooting.html | 2 +- src_assets/common/assets/web/welcome.html | 2 +- 16 files changed, 246 insertions(+), 62 deletions(-) create mode 100644 src_assets/common/assets/web/ThemeToggle.vue create mode 100644 src_assets/common/assets/web/theme.js diff --git a/src_assets/common/assets/web/Navbar.vue b/src_assets/common/assets/web/Navbar.vue index 9e4e1be64f5..838c630f45a 100644 --- a/src_assets/common/assets/web/Navbar.vue +++ b/src_assets/common/assets/web/Navbar.vue @@ -1,60 +1,89 @@ diff --git a/src_assets/common/assets/web/ThemeToggle.vue b/src_assets/common/assets/web/ThemeToggle.vue new file mode 100644 index 00000000000..7c34916adc9 --- /dev/null +++ b/src_assets/common/assets/web/ThemeToggle.vue @@ -0,0 +1,46 @@ + + + + + diff --git a/src_assets/common/assets/web/apps.html b/src_assets/common/assets/web/apps.html index 0fd0651aa13..9a8c65d16ae 100644 --- a/src_assets/common/assets/web/apps.html +++ b/src_assets/common/assets/web/apps.html @@ -1,5 +1,5 @@ - + <%- header %> @@ -355,10 +355,10 @@

{{ $t('apps.env_vars_about') }}

diff --git a/src_assets/common/assets/web/theme.js b/src_assets/common/assets/web/theme.js new file mode 100644 index 00000000000..a1f497802fa --- /dev/null +++ b/src_assets/common/assets/web/theme.js @@ -0,0 +1,84 @@ +const getStoredTheme = () => localStorage.getItem('theme') +const setStoredTheme = theme => localStorage.setItem('theme', theme) + +export const getPreferredTheme = () => { + const storedTheme = getStoredTheme() + if (storedTheme) { + return storedTheme + } + + return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' +} + +const setTheme = theme => { + if (theme === 'auto') { + document.documentElement.setAttribute( + 'data-bs-theme', + (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') + ) + } else { + document.documentElement.setAttribute('data-bs-theme', theme) + } +} + +export const showActiveTheme = (theme, focus = false) => { + const themeSwitcher = document.querySelector('#bd-theme') + + if (!themeSwitcher) { + return + } + + const themeSwitcherText = document.querySelector('#bd-theme-text') + const activeThemeIcon = document.querySelector('.theme-icon-active i') + const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`) + const classListOfActiveBtn = btnToActive.querySelector('i').classList + + document.querySelectorAll('[data-bs-theme-value]').forEach(element => { + element.classList.remove('active') + element.setAttribute('aria-pressed', 'false') + }) + + btnToActive.classList.add('active') + btnToActive.setAttribute('aria-pressed', 'true') + activeThemeIcon.classList.remove(...activeThemeIcon.classList.values()) + activeThemeIcon.classList.add(...classListOfActiveBtn) + const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.textContent.trim()})` + themeSwitcher.setAttribute('aria-label', themeSwitcherLabel) + + if (focus) { + themeSwitcher.focus() + } +} + +export function setupThemeToggleListener() { + document.querySelectorAll('[data-bs-theme-value]') + .forEach(toggle => { + toggle.addEventListener('click', () => { + const theme = toggle.getAttribute('data-bs-theme-value') + setStoredTheme(theme) + setTheme(theme) + showActiveTheme(theme, true) + }) + }) + + showActiveTheme(getPreferredTheme(), false) +} + +export function loadAutoTheme() { + (() => { + 'use strict' + + setTheme(getPreferredTheme()) + + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { + const storedTheme = getStoredTheme() + if (storedTheme !== 'light' && storedTheme !== 'dark') { + setTheme(getPreferredTheme()) + } + }) + + window.addEventListener('DOMContentLoaded', () => { + showActiveTheme(getPreferredTheme()) + }) + })() +} diff --git a/src_assets/common/assets/web/troubleshooting.html b/src_assets/common/assets/web/troubleshooting.html index 00497741368..0adc16542af 100644 --- a/src_assets/common/assets/web/troubleshooting.html +++ b/src_assets/common/assets/web/troubleshooting.html @@ -1,5 +1,5 @@ - + <%- header %> diff --git a/src_assets/common/assets/web/welcome.html b/src_assets/common/assets/web/welcome.html index cf1e74ba8e6..18c67b2ee79 100644 --- a/src_assets/common/assets/web/welcome.html +++ b/src_assets/common/assets/web/welcome.html @@ -1,5 +1,5 @@ - + <%- header %>