mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-08 00:28:16 -06:00
feat: allow 'auto' as a colortheme preference
This commit is contained in:
parent
277b7039d8
commit
55d849d7cc
@ -1,10 +1,15 @@
|
|||||||
/**
|
/**
|
||||||
* Set the color mode on the `<html/>` element and in local storage.
|
* Set the color mode on the `<html/>` element and in local storage.
|
||||||
*
|
*
|
||||||
* @param mode {"dark" | "light"} UI color mode.
|
* @param mode {"dark" | "light" | "auto"} UI color mode.
|
||||||
*/
|
*/
|
||||||
function setMode(mode) {
|
function setMode(mode) {
|
||||||
document.documentElement.setAttribute("data-bs-theme", mode);
|
document.documentElement.setAttribute(
|
||||||
|
"data-bs-theme",
|
||||||
|
mode === "auto"
|
||||||
|
? window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
||||||
|
: mode
|
||||||
|
);
|
||||||
localStorage.setItem("netbox-color-mode", mode);
|
localStorage.setItem("netbox-color-mode", mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,6 +28,12 @@ function initMode() {
|
|||||||
if (clientMode !== null) {
|
if (clientMode !== null) {
|
||||||
return setMode(clientMode, false);
|
return setMode(clientMode, false);
|
||||||
}
|
}
|
||||||
|
// If client wants to auto-switch, attach an onchange listener to the media query
|
||||||
|
if (clientMode === 'auto') {
|
||||||
|
window.matchMedia('(prefers-color-scheme: light)').onchange = event => {
|
||||||
|
document.documentElement.dataset.bsTheme = (e.matches) ? 'light' : 'dark';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fall back to the mode preferred by the browser, if specified
|
// Fall back to the mode preferred by the browser, if specified
|
||||||
if (preferDark) {
|
if (preferDark) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { getElements, isTruthy } from './util';
|
import { getElements, isTruthy } from './util';
|
||||||
|
|
||||||
const COLOR_MODE_KEY = 'netbox-color-mode';
|
const COLOR_MODE_PREFERENCE_KEY = 'netbox-color-mode-preference';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if a value is a supported color mode string value.
|
* Determine if a value is a supported color mode string value.
|
||||||
@ -9,28 +9,41 @@ function isColorMode(value: unknown): value is ColorMode {
|
|||||||
return value === 'dark' || value === 'light';
|
return value === 'dark' || value === 'light';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isDefinedColorModePreference(value: unknown): value is ColorModePreference {
|
||||||
|
return value === 'auto' || isColorMode(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the color mode to light or dark.
|
* Set the color mode to light or dark.
|
||||||
*
|
*
|
||||||
* @param mode `'light'` or `'dark'`
|
* @param mode `'light'`, `'dark'` or `'auto'`
|
||||||
* @returns `true` if the color mode was successfully set, `false` if not.
|
* @returns `true` if the color mode was successfully set, `false` if not.
|
||||||
*/
|
*/
|
||||||
function storeColorMode(mode: ColorMode): void {
|
function storeColorMode(modePreference: ColorModePreference): void {
|
||||||
return localStorage.setItem(COLOR_MODE_KEY, mode);
|
return localStorage.setItem(COLOR_MODE_PREFERENCE_KEY, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateElements(targetMode: ColorMode): void {
|
function updateElements(targetMode: ColorModePreference): void {
|
||||||
const body = document.querySelector('body');
|
const body = document.querySelector('body');
|
||||||
if (body && targetMode == 'dark') {
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||||
body.setAttribute('data-bs-theme', 'dark');
|
const theme = (targetMode === 'auto')
|
||||||
} else if (body) {
|
? (mediaQuery.matches ? 'dark' : 'light'
|
||||||
body.setAttribute('data-bs-theme', 'light');
|
: (targetMode === 'none' ? targetMode : 'light');
|
||||||
|
|
||||||
|
if (body) {
|
||||||
|
body.setAttribute('data-bs-theme', theme);
|
||||||
|
}
|
||||||
|
if (body && targetMode === 'auto') {
|
||||||
|
mediaQuery.onchange = event => {
|
||||||
|
body.setAttribute('data-bs-theme', event.matches ? 'dark' : 'light');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const elevation of getElements<HTMLObjectElement>('.rack_elevation')) {
|
for (const elevation of getElements<HTMLObjectElement>('.rack_elevation')) {
|
||||||
const svg = elevation.contentDocument?.querySelector('svg') ?? null;
|
const svg = elevation.contentDocument?.querySelector('svg') ?? null;
|
||||||
if (svg !== null) {
|
if (svg !== null) {
|
||||||
svg.setAttribute(`data-bs-theme`, targetMode);
|
svg.setAttribute(`data-bs-theme`, theme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,7 +53,7 @@ function updateElements(targetMode: ColorMode): void {
|
|||||||
*
|
*
|
||||||
* @param mode Target color mode.
|
* @param mode Target color mode.
|
||||||
*/
|
*/
|
||||||
export function setColorMode(mode: ColorMode): void {
|
export function setColorMode(mode: ColorModePreference): void {
|
||||||
storeColorMode(mode);
|
storeColorMode(mode);
|
||||||
updateElements(mode);
|
updateElements(mode);
|
||||||
}
|
}
|
||||||
@ -49,11 +62,11 @@ export function setColorMode(mode: ColorMode): void {
|
|||||||
* Toggle the color mode when a color mode toggle is clicked.
|
* Toggle the color mode when a color mode toggle is clicked.
|
||||||
*/
|
*/
|
||||||
function handleColorModeToggle(): void {
|
function handleColorModeToggle(): void {
|
||||||
const currentValue = localStorage.getItem(COLOR_MODE_KEY);
|
const prevValue = localStorage.getItem(COLOR_MODE_PREFERENCE_KEY);
|
||||||
if (currentValue === 'light') {
|
if (isColorMode(prevValue)) {
|
||||||
setColorMode('dark');
|
setColorMode(prevValue === 'light' ? 'dark' : 'light');
|
||||||
} else if (currentValue === 'dark') {
|
} else if (prevValue === 'auto') {
|
||||||
setColorMode('light');
|
console.log('Ignoring color mode toggle in auto mode');
|
||||||
} else {
|
} else {
|
||||||
console.warn('Unable to determine the current color mode');
|
console.warn('Unable to determine the current color mode');
|
||||||
}
|
}
|
||||||
@ -64,33 +77,29 @@ function handleColorModeToggle(): void {
|
|||||||
*/
|
*/
|
||||||
function defaultColorMode(): void {
|
function defaultColorMode(): void {
|
||||||
// Get the current color mode value from local storage.
|
// Get the current color mode value from local storage.
|
||||||
const currentValue = localStorage.getItem(COLOR_MODE_KEY) as Nullable<ColorMode>;
|
const currentValue = localStorage.getItem(COLOR_MODE_PREFERENCE_KEY) as Nullable<ColorModePreference>;
|
||||||
|
|
||||||
if (isTruthy(currentValue)) {
|
|
||||||
return setColorMode(currentValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
let preference: ColorModePreference = 'none';
|
|
||||||
|
|
||||||
// Determine if the user prefers dark or light mode.
|
|
||||||
for (const mode of ['dark', 'light']) {
|
|
||||||
if (window.matchMedia(`(prefers-color-scheme: ${mode})`).matches) {
|
|
||||||
preference = mode as ColorModePreference;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isTruthy(currentValue) && isColorMode(currentValue)) {
|
if (isTruthy(currentValue) && isColorMode(currentValue)) {
|
||||||
return setColorMode(currentValue);
|
return setColorMode(currentValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let preference: ColorModePreference = 'none';
|
||||||
|
|
||||||
|
// Determine if the user prefers dark, light or auto mode.
|
||||||
|
if (preference !== 'auto') {
|
||||||
|
for (const mode of ['dark', 'light']) {
|
||||||
|
if (window.matchMedia(`(prefers-color-scheme: ${mode})`).matches) {
|
||||||
|
preference = mode as ColorModePreference;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
switch (preference) {
|
switch (preference) {
|
||||||
|
case 'auto':
|
||||||
case 'dark':
|
case 'dark':
|
||||||
return setColorMode('dark');
|
|
||||||
case 'light':
|
case 'light':
|
||||||
return setColorMode('light');
|
return setColorMode(preference);
|
||||||
case 'none':
|
case 'none':
|
||||||
return setColorMode('light');
|
|
||||||
default:
|
default:
|
||||||
return setColorMode('light');
|
return setColorMode('light');
|
||||||
}
|
}
|
||||||
|
2
netbox/project-static/src/global.d.ts
vendored
2
netbox/project-static/src/global.d.ts
vendored
@ -78,4 +78,4 @@ declare const messages: string[];
|
|||||||
type FormControls = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
|
type FormControls = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
|
||||||
|
|
||||||
type ColorMode = 'light' | 'dark';
|
type ColorMode = 'light' | 'dark';
|
||||||
type ColorModePreference = ColorMode | 'none';
|
type ColorModePreference = ColorMode | 'none' | 'auto';
|
||||||
|
Loading…
Reference in New Issue
Block a user