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:
Philip Allgaier 2021-12-03 18:02:54 +01:00 committed by GitHub
parent 1df11e9bf1
commit ea18fc0078
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 69 additions and 78 deletions

View File

@ -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) {

View File

@ -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() {

View File

@ -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) {

View File

@ -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 };

View File

@ -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) =>

View File

@ -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,

View File

@ -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 }
);
} }
} }

View File

@ -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,

View File

@ -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;