mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-15 13:26:34 +00:00
Ensure we always have an active theme name (fixes dark theme issues) (#10780)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
1df11e9bf1
commit
ea18fc0078
@ -52,17 +52,13 @@ class DemoBlackWhiteRow extends LitElement {
|
|||||||
|
|
||||||
firstUpdated(changedProps) {
|
firstUpdated(changedProps) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
applyThemesOnElement(
|
applyThemesOnElement(this.shadowRoot!.querySelector(".dark"), {
|
||||||
this.shadowRoot!.querySelector(".dark"),
|
default_theme: "default",
|
||||||
{
|
default_dark_theme: "default",
|
||||||
default_theme: "default",
|
themes: {},
|
||||||
default_dark_theme: "default",
|
darkMode: true,
|
||||||
themes: {},
|
theme: "default",
|
||||||
darkMode: false,
|
});
|
||||||
},
|
|
||||||
"default",
|
|
||||||
{ dark: true }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit(ev) {
|
handleSubmit(ev) {
|
||||||
|
@ -159,17 +159,13 @@ export class DemoHaAlert extends LitElement {
|
|||||||
|
|
||||||
firstUpdated(changedProps) {
|
firstUpdated(changedProps) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
applyThemesOnElement(
|
applyThemesOnElement(this.shadowRoot!.querySelector(".dark"), {
|
||||||
this.shadowRoot!.querySelector(".dark"),
|
default_theme: "default",
|
||||||
{
|
default_dark_theme: "default",
|
||||||
default_theme: "default",
|
themes: {},
|
||||||
default_dark_theme: "default",
|
darkMode: true,
|
||||||
themes: {},
|
theme: "default",
|
||||||
darkMode: false,
|
});
|
||||||
},
|
|
||||||
"default",
|
|
||||||
{ dark: true }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
|
@ -101,17 +101,13 @@ class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
|
|||||||
this._fetchAuthProviders();
|
this._fetchAuthProviders();
|
||||||
|
|
||||||
if (matchMedia("(prefers-color-scheme: dark)").matches) {
|
if (matchMedia("(prefers-color-scheme: dark)").matches) {
|
||||||
applyThemesOnElement(
|
applyThemesOnElement(document.documentElement, {
|
||||||
document.documentElement,
|
default_theme: "default",
|
||||||
{
|
default_dark_theme: null,
|
||||||
default_theme: "default",
|
themes: {},
|
||||||
default_dark_theme: null,
|
darkMode: true,
|
||||||
themes: {},
|
theme: "default",
|
||||||
darkMode: false,
|
});
|
||||||
},
|
|
||||||
"default",
|
|
||||||
{ dark: true }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.redirectUri) {
|
if (!this.redirectUri) {
|
||||||
|
@ -23,9 +23,9 @@ let PROCESSED_THEMES: Record<string, ProcessedTheme> = {};
|
|||||||
* Apply a theme to an element by setting the CSS variables on it.
|
* Apply a theme to an element by setting the CSS variables on it.
|
||||||
*
|
*
|
||||||
* element: Element to apply theme on.
|
* element: Element to apply theme on.
|
||||||
* themes: HASS theme information.
|
* themes: HASS theme information (e.g. active dark mode and globally active theme name).
|
||||||
* selectedTheme: Selected theme.
|
* selectedTheme: Selected theme (used to override the globally active theme for this element).
|
||||||
* themeSettings: Settings such as selected dark mode and colors.
|
* themeSettings: Additional settings such as selected colors.
|
||||||
*/
|
*/
|
||||||
export const applyThemesOnElement = (
|
export const applyThemesOnElement = (
|
||||||
element,
|
element,
|
||||||
@ -33,31 +33,33 @@ export const applyThemesOnElement = (
|
|||||||
selectedTheme?: string,
|
selectedTheme?: string,
|
||||||
themeSettings?: Partial<HomeAssistant["selectedTheme"]>
|
themeSettings?: Partial<HomeAssistant["selectedTheme"]>
|
||||||
) => {
|
) => {
|
||||||
let cacheKey = selectedTheme;
|
// If there is no explicitly desired theme provided, we automatically
|
||||||
let themeRules: Partial<ThemeVars> = {};
|
// use the active one from `themes`.
|
||||||
|
const themeToApply = selectedTheme || themes.theme;
|
||||||
|
|
||||||
// If there is no explicitly desired dark mode provided, we automatically
|
// If there is no explicitly desired dark mode provided, we automatically
|
||||||
// use the active one from hass.themes.
|
// use the active one from `themes`.
|
||||||
if (!themeSettings || themeSettings?.dark === undefined) {
|
const darkMode =
|
||||||
themeSettings = {
|
themeSettings && themeSettings?.dark !== undefined
|
||||||
...themeSettings,
|
? themeSettings?.dark
|
||||||
dark: themes.darkMode,
|
: themes.darkMode;
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (themeSettings.dark) {
|
let cacheKey = themeToApply;
|
||||||
|
let themeRules: Partial<ThemeVars> = {};
|
||||||
|
|
||||||
|
if (darkMode) {
|
||||||
cacheKey = `${cacheKey}__dark`;
|
cacheKey = `${cacheKey}__dark`;
|
||||||
themeRules = { ...darkStyles };
|
themeRules = { ...darkStyles };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedTheme === "default") {
|
if (themeToApply === "default") {
|
||||||
// Determine the primary and accent colors from the current settings.
|
// Determine the primary and accent colors from the current settings.
|
||||||
// Fallbacks are implicitly the HA default blue and orange or the
|
// Fallbacks are implicitly the HA default blue and orange or the
|
||||||
// derived "darkStyles" values, depending on the light vs dark mode.
|
// derived "darkStyles" values, depending on the light vs dark mode.
|
||||||
const primaryColor = themeSettings.primaryColor;
|
const primaryColor = themeSettings?.primaryColor;
|
||||||
const accentColor = themeSettings.accentColor;
|
const accentColor = themeSettings?.accentColor;
|
||||||
|
|
||||||
if (themeSettings.dark && primaryColor) {
|
if (darkMode && primaryColor) {
|
||||||
themeRules["app-header-background-color"] = hexBlend(
|
themeRules["app-header-background-color"] = hexBlend(
|
||||||
primaryColor,
|
primaryColor,
|
||||||
"#121212",
|
"#121212",
|
||||||
@ -98,17 +100,17 @@ export const applyThemesOnElement = (
|
|||||||
// Custom theme logic (not relevant for default theme, since it would override
|
// Custom theme logic (not relevant for default theme, since it would override
|
||||||
// the derived calculations from above)
|
// the derived calculations from above)
|
||||||
if (
|
if (
|
||||||
selectedTheme &&
|
themeToApply &&
|
||||||
selectedTheme !== "default" &&
|
themeToApply !== "default" &&
|
||||||
themes.themes[selectedTheme]
|
themes.themes[themeToApply]
|
||||||
) {
|
) {
|
||||||
// Apply theme vars that are relevant for all modes (but extract the "modes" section first)
|
// Apply theme vars that are relevant for all modes (but extract the "modes" section first)
|
||||||
const { modes, ...baseThemeRules } = themes.themes[selectedTheme];
|
const { modes, ...baseThemeRules } = themes.themes[themeToApply];
|
||||||
themeRules = { ...themeRules, ...baseThemeRules };
|
themeRules = { ...themeRules, ...baseThemeRules };
|
||||||
|
|
||||||
// Apply theme vars for the specific mode if available
|
// Apply theme vars for the specific mode if available
|
||||||
if (modes) {
|
if (modes) {
|
||||||
if (themeSettings?.dark) {
|
if (darkMode) {
|
||||||
themeRules = { ...themeRules, ...modes.dark };
|
themeRules = { ...themeRules, ...modes.dark };
|
||||||
} else {
|
} else {
|
||||||
themeRules = { ...themeRules, ...modes.light };
|
themeRules = { ...themeRules, ...modes.light };
|
||||||
|
@ -23,6 +23,8 @@ export interface Themes {
|
|||||||
// in theme picker, this property will still contain either true or false based on
|
// in theme picker, this property will still contain either true or false based on
|
||||||
// what has been determined via system preferences and support from the selected theme.
|
// what has been determined via system preferences and support from the selected theme.
|
||||||
darkMode: boolean;
|
darkMode: boolean;
|
||||||
|
// Currently globally active theme name
|
||||||
|
theme: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchThemes = (conn) =>
|
const fetchThemes = (conn) =>
|
||||||
|
@ -201,6 +201,7 @@ export const provideHass = (
|
|||||||
default_dark_theme: null,
|
default_dark_theme: null,
|
||||||
themes: {},
|
themes: {},
|
||||||
darkMode: false,
|
darkMode: false,
|
||||||
|
theme: "default",
|
||||||
},
|
},
|
||||||
panels: demoPanels,
|
panels: demoPanels,
|
||||||
services: demoServices,
|
services: demoServices,
|
||||||
|
@ -133,17 +133,13 @@ class HaOnboarding extends litLocalizeLiteMixin(HassElement) {
|
|||||||
import("./particles");
|
import("./particles");
|
||||||
}
|
}
|
||||||
if (matchMedia("(prefers-color-scheme: dark)").matches) {
|
if (matchMedia("(prefers-color-scheme: dark)").matches) {
|
||||||
applyThemesOnElement(
|
applyThemesOnElement(document.documentElement, {
|
||||||
document.documentElement,
|
default_theme: "default",
|
||||||
{
|
default_dark_theme: null,
|
||||||
default_theme: "default",
|
themes: {},
|
||||||
default_dark_theme: null,
|
darkMode: true,
|
||||||
themes: {},
|
theme: "default",
|
||||||
darkMode: false,
|
});
|
||||||
},
|
|
||||||
"default",
|
|
||||||
{ dark: true }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,17 +38,13 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
|||||||
});
|
});
|
||||||
mql.addListener((ev) => this._applyTheme(ev.matches));
|
mql.addListener((ev) => this._applyTheme(ev.matches));
|
||||||
if (!this._themeApplied && mql.matches) {
|
if (!this._themeApplied && mql.matches) {
|
||||||
applyThemesOnElement(
|
applyThemesOnElement(document.documentElement, {
|
||||||
document.documentElement,
|
default_theme: "default",
|
||||||
{
|
default_dark_theme: null,
|
||||||
default_theme: "default",
|
themes: {},
|
||||||
default_dark_theme: null,
|
darkMode: true,
|
||||||
themes: {},
|
theme: "default",
|
||||||
darkMode: false,
|
});
|
||||||
},
|
|
||||||
"default",
|
|
||||||
{ dark: true }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,6 +85,9 @@ export default <T extends Constructor<HassBaseEl>>(superClass: T) =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
themeSettings = { ...this.hass.selectedTheme, dark: darkMode };
|
themeSettings = { ...this.hass.selectedTheme, dark: darkMode };
|
||||||
|
this._updateHass({
|
||||||
|
themes: { ...this.hass.themes!, theme: themeName },
|
||||||
|
});
|
||||||
|
|
||||||
applyThemesOnElement(
|
applyThemesOnElement(
|
||||||
document.documentElement,
|
document.documentElement,
|
||||||
|
@ -84,9 +84,12 @@ export interface CurrentUser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Currently selected theme and its settings. These are the values stored in local storage.
|
// Currently selected theme and its settings. These are the values stored in local storage.
|
||||||
|
// Note: These values are not meant to be used at runtime to check whether dark mode is active
|
||||||
|
// or which theme name to use, as this interface represents the config data for the theme picker.
|
||||||
|
// The actually active dark mode and theme name can be read from hass.themes.
|
||||||
export interface ThemeSettings {
|
export interface ThemeSettings {
|
||||||
theme: string;
|
theme: string;
|
||||||
// Radio box selection for theme picker. Do not use in cards as
|
// Radio box selection for theme picker. Do not use in Lovelace rendering as
|
||||||
// it can be undefined == auto.
|
// it can be undefined == auto.
|
||||||
// Property hass.themes.darkMode carries effective current mode.
|
// Property hass.themes.darkMode carries effective current mode.
|
||||||
dark?: boolean;
|
dark?: boolean;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user