Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1279321
Initial version
spacegaier Jan 21, 2021
36b1f6b
Initial support for dark_styles
spacegaier Feb 7, 2021
66facd6
Store all effective darkMode info in selectedTheme
spacegaier Feb 7, 2021
745598a
Working solution
spacegaier Feb 7, 2021
365786e
Cleanup
spacegaier Feb 7, 2021
a665d2e
Merge branch 'dev' of https://github.com/home-assistant/frontend into…
spacegaier Feb 7, 2021
14d81e2
Lint
spacegaier Feb 7, 2021
a7ffd2c
Fixes for dark app header bar
spacegaier Feb 8, 2021
4cab2ec
Proper primary and accent color handling
spacegaier Feb 8, 2021
d89dd5b
Adjust rgb contrast value to not break app header
spacegaier Feb 8, 2021
bd3cbc1
Rename YAML keys
spacegaier Feb 14, 2021
dfc8d66
Add support for color defaults
spacegaier Feb 14, 2021
671b19b
Always apply default colors on theme change + comment cleanups
spacegaier Feb 14, 2021
2b31a89
Cleanup
spacegaier Mar 9, 2021
ec3b0c8
Merge branch 'dev' of https://github.com/home-assistant/frontend into…
spacegaier Mar 9, 2021
634482c
Merge branch 'dev' of https://github.com/home-assistant/frontend into…
spacegaier Apr 25, 2021
9d393d3
Remove color picker support for custom themes again
spacegaier Apr 25, 2021
18fa413
Revert color contrast fixes
spacegaier Apr 25, 2021
0bdb5c4
Revert missed color contrast fixes
spacegaier Apr 25, 2021
009e1a3
Lint + consistent var naming
spacegaier Apr 25, 2021
89ef813
Apply suggestions from code review
spacegaier Apr 27, 2021
f461e52
Cleanup
spacegaier Apr 27, 2021
9432a26
Merge branch 'dev' of https://github.com/home-assistant/frontend into…
spacegaier May 22, 2021
3b0df20
Adjust to new "modes" structure
spacegaier May 22, 2021
524942b
Changes from review
spacegaier May 24, 2021
1535178
Apply suggestions from code review
spacegaier May 24, 2021
b7146e7
Cleanup
spacegaier May 24, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions hassio/src/hassio-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,33 +103,35 @@ export class HassioMain extends SupervisorBaseElement {

private _applyTheme() {
let themeName: string;
let options: Partial<HomeAssistant["selectedTheme"]> | undefined;
let themeSettings:
| Partial<HomeAssistant["selectedThemeSettings"]>
| undefined;

if (atLeastVersion(this.hass.config.version, 0, 114)) {
themeName =
this.hass.selectedTheme?.theme ||
this.hass.selectedThemeSettings?.theme ||
(this.hass.themes.darkMode && this.hass.themes.default_dark_theme
? this.hass.themes.default_dark_theme!
: this.hass.themes.default_theme);

options = this.hass.selectedTheme;
if (themeName === "default" && options?.dark === undefined) {
options = {
...this.hass.selectedTheme,
themeSettings = this.hass.selectedThemeSettings;
if (themeSettings?.dark === undefined) {
themeSettings = {
...this.hass.selectedThemeSettings,
dark: this.hass.themes.darkMode,
};
}
} else {
themeName =
((this.hass.selectedTheme as unknown) as string) ||
((this.hass.selectedThemeSettings as unknown) as string) ||
this.hass.themes.default_theme;
}

applyThemesOnElement(
this.parentElement,
this.hass.themes,
themeName,
options
themeSettings
);
}
}
Expand Down
108 changes: 68 additions & 40 deletions src/common/dom/apply_themes_on_element.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Theme } from "../../data/ws-themes";
import { ThemeVars } from "../../data/ws-themes";
import { darkStyles, derivedStyles } from "../../resources/styles";
import type { HomeAssistant } from "../../types";
import {
Expand All @@ -23,62 +23,90 @@ let PROCESSED_THEMES: Record<string, ProcessedTheme> = {};
* Apply a theme to an element by setting the CSS variables on it.
*
* element: Element to apply theme on.
* themes: HASS Theme information
* selectedTheme: selected theme.
* themes: HASS theme information.
* selectedTheme: Selected theme.
* themeSettings: Settings such as selected dark mode and colors.
*/
export const applyThemesOnElement = (
element,
themes: HomeAssistant["themes"],
selectedTheme?: string,
themeOptions?: Partial<HomeAssistant["selectedTheme"]>
themeSettings?: Partial<HomeAssistant["selectedThemeSettings"]>
) => {
let cacheKey = selectedTheme;
let themeRules: Partial<Theme> = {};
let themeRules: Partial<ThemeVars> = {};

if (selectedTheme === "default" && themeOptions) {
if (themeOptions.dark) {
if (themeSettings) {
if (themeSettings.dark) {
cacheKey = `${cacheKey}__dark`;
themeRules = darkStyles;
if (themeOptions.primaryColor) {
}

if (selectedTheme === "default") {
// Determine the primary and accent colors from the current settings.
// Fallbacks are implicitly the HA default blue and orange or the
// derived "darkStyles" values, depending on the light vs dark mode.
const primaryColor = themeSettings.primaryColor;
const accentColor = themeSettings.accentColor;

if (themeSettings.dark && primaryColor) {
themeRules["app-header-background-color"] = hexBlend(
themeOptions.primaryColor,
primaryColor,
"#121212",
8
);
}
}
if (themeOptions.primaryColor) {
cacheKey = `${cacheKey}__primary_${themeOptions.primaryColor}`;
const rgbPrimaryColor = hex2rgb(themeOptions.primaryColor);
const labPrimaryColor = rgb2lab(rgbPrimaryColor);
themeRules["primary-color"] = themeOptions.primaryColor;
const rgbLigthPrimaryColor = lab2rgb(labBrighten(labPrimaryColor));
themeRules["light-primary-color"] = rgb2hex(rgbLigthPrimaryColor);
themeRules["dark-primary-color"] = lab2hex(labDarken(labPrimaryColor));
themeRules["text-primary-color"] =
rgbContrast(rgbPrimaryColor, [33, 33, 33]) < 6 ? "#fff" : "#212121";
themeRules["text-light-primary-color"] =
rgbContrast(rgbLigthPrimaryColor, [33, 33, 33]) < 6
? "#fff"
: "#212121";
themeRules["state-icon-color"] = themeRules["dark-primary-color"];
}
if (themeOptions.accentColor) {
cacheKey = `${cacheKey}__accent_${themeOptions.accentColor}`;
themeRules["accent-color"] = themeOptions.accentColor;
const rgbAccentColor = hex2rgb(themeOptions.accentColor);
themeRules["text-accent-color"] =
rgbContrast(rgbAccentColor, [33, 33, 33]) < 6 ? "#fff" : "#212121";
}

// Nothing was changed
if (element._themes?.cacheKey === cacheKey) {
return;
if (primaryColor) {
cacheKey = `${cacheKey}__primary_${primaryColor}`;
const rgbPrimaryColor = hex2rgb(primaryColor);
const labPrimaryColor = rgb2lab(rgbPrimaryColor);
themeRules["primary-color"] = primaryColor;
const rgbLightPrimaryColor = lab2rgb(labBrighten(labPrimaryColor));
themeRules["light-primary-color"] = rgb2hex(rgbLightPrimaryColor);
themeRules["dark-primary-color"] = lab2hex(labDarken(labPrimaryColor));
themeRules["text-primary-color"] =
rgbContrast(rgbPrimaryColor, [33, 33, 33]) < 6 ? "#fff" : "#212121";
themeRules["text-light-primary-color"] =
rgbContrast(rgbLightPrimaryColor, [33, 33, 33]) < 6
? "#fff"
: "#212121";
themeRules["state-icon-color"] = themeRules["dark-primary-color"];
}
if (accentColor) {
cacheKey = `${cacheKey}__accent_${accentColor}`;
themeRules["accent-color"] = accentColor;
const rgbAccentColor = hex2rgb(accentColor);
themeRules["text-accent-color"] =
rgbContrast(rgbAccentColor, [33, 33, 33]) < 6 ? "#fff" : "#212121";
}

// Nothing was changed
if (element._themes?.cacheKey === cacheKey) {
return;
}
}
}

if (selectedTheme && themes.themes[selectedTheme]) {
themeRules = themes.themes[selectedTheme];
// Custom theme logic (not relevant for default theme, since it would override
// the derived calculations from above)
if (
selectedTheme &&
selectedTheme !== "default" &&
themes.themes[selectedTheme]
) {
// Apply theme vars that are relevant for all modes (but extract the "modes" section first)
const { modes, ...baseThemeRules } = themes.themes[selectedTheme];
themeRules = { ...themeRules, ...baseThemeRules };

// Apply theme vars for the specific mode if available
if (modes) {
if (themeSettings?.dark) {
themeRules = { ...themeRules, ...modes.dark };
} else {
themeRules = { ...themeRules, ...modes.light };
}
}
}

if (!element._themes?.keys && !Object.keys(themeRules).length) {
Expand Down Expand Up @@ -106,12 +134,12 @@ export const applyThemesOnElement = (

const processTheme = (
cacheKey: string,
theme: Partial<Theme>
theme: Partial<ThemeVars>
): ProcessedTheme | undefined => {
if (!theme || !Object.keys(theme).length) {
return undefined;
}
const combinedTheme: Partial<Theme> = {
const combinedTheme: Partial<ThemeVars> = {
...derivedStyles,
...theme,
};
Expand Down
6 changes: 3 additions & 3 deletions src/components/map/ha-location-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ class LocationEditor extends LitElement {

if (changedProps.has("hass")) {
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
if (!oldHass || oldHass.themes?.darkMode === this.hass.themes?.darkMode) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this no longer needed? We still init themes as null?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should not have been needed before the PR either. Basically no usages of hass.themes do check via ? (e.g. none of the cards do).

if (!oldHass || oldHass.themes.darkMode === this.hass.themes.darkMode) {
return;
}
if (!this._leafletMap || !this._tileLayer) {
Expand All @@ -118,7 +118,7 @@ class LocationEditor extends LitElement {
this.Leaflet,
this._leafletMap,
this._tileLayer,
this.hass.themes?.darkMode
this.hass.themes.darkMode
);
}
}
Expand All @@ -130,7 +130,7 @@ class LocationEditor extends LitElement {
private async _initMap(): Promise<void> {
[this._leafletMap, this.Leaflet, this._tileLayer] = await setupLeafletMap(
this._mapEl,
this.darkMode ?? this.hass.themes?.darkMode,
this.darkMode ?? this.hass.themes.darkMode,
Boolean(this.radius)
);
this._leafletMap.addEventListener(
Expand Down
12 changes: 11 additions & 1 deletion src/data/ws-themes.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
import { Connection, createCollection } from "home-assistant-js-websocket";

export interface Theme {
export interface ThemeVars {
// Incomplete
"primary-color": string;
"text-primary-color": string;
"accent-color": string;
[key: string]: string;
}

export type Theme = ThemeVars & {
modes?: {
light?: ThemeVars;
dark?: ThemeVars;
};
};

export interface Themes {
default_theme: string;
default_dark_theme: string | null;
themes: Record<string, Theme>;
// Currently effective dark mode. Will never be undefined. If user selected "auto"
// 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.
darkMode: boolean;
}

Expand Down
8 changes: 6 additions & 2 deletions src/data/zone.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { navigate } from "../common/navigate";
import {
DEFAULT_ACCENT_COLOR,
DEFAULT_PRIMARY_COLOR,
} from "../resources/ha-style";
import { HomeAssistant } from "../types";

export const defaultRadiusColor = "#FF9800";
export const homeRadiusColor = "#03a9f4";
export const defaultRadiusColor = DEFAULT_ACCENT_COLOR;
export const homeRadiusColor = DEFAULT_PRIMARY_COLOR;
export const passiveRadiusColor = "#9b9b9b";

export interface Zone {
Expand Down
6 changes: 3 additions & 3 deletions src/fake_data/provide_hass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,19 +277,19 @@ export const provideHass = (
mockTheme(theme) {
invalidateThemeCache();
hass().updateHass({
selectedTheme: { theme: theme ? "mock" : "default" },
selectedThemeSettings: { theme: theme ? "mock" : "default" },
themes: {
...hass().themes,
themes: {
mock: theme as any,
},
},
});
const { themes, selectedTheme } = hass();
const { themes, selectedThemeSettings } = hass();
applyThemesOnElement(
document.documentElement,
themes,
selectedTheme!.theme
selectedThemeSettings!.theme
);
},

Expand Down
18 changes: 10 additions & 8 deletions src/layouts/supervisor-error-screen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,33 +81,35 @@ class SupervisorErrorScreen extends LitElement {

private _applyTheme() {
let themeName: string;
let options: Partial<HomeAssistant["selectedTheme"]> | undefined;
let themeSettings:
| Partial<HomeAssistant["selectedThemeSettings"]>
| undefined;

if (atLeastVersion(this.hass.config.version, 0, 114)) {
themeName =
this.hass.selectedTheme?.theme ||
this.hass.selectedThemeSettings?.theme ||
(this.hass.themes.darkMode && this.hass.themes.default_dark_theme
? this.hass.themes.default_dark_theme!
: this.hass.themes.default_theme);

options = this.hass.selectedTheme;
if (themeName === "default" && options?.dark === undefined) {
options = {
...this.hass.selectedTheme,
themeSettings = this.hass.selectedThemeSettings;
if (themeName === "default" && themeSettings?.dark === undefined) {
themeSettings = {
...this.hass.selectedThemeSettings,
dark: this.hass.themes.darkMode,
};
}
} else {
themeName =
((this.hass.selectedTheme as unknown) as string) ||
((this.hass.selectedThemeSettings as unknown) as string) ||
this.hass.themes.default_theme;
}

applyThemesOnElement(
this.parentElement,
this.hass.themes,
themeName,
options
themeSettings
);
}

Expand Down
2 changes: 1 addition & 1 deletion src/panels/lovelace/views/hui-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export class HUIView extends ReactiveElement {
changedProperties.has("hass") &&
(!oldHass ||
this.hass.themes !== oldHass.themes ||
this.hass.selectedTheme !== oldHass.selectedTheme)
this.hass.selectedThemeSettings !== oldHass.selectedThemeSettings)
) {
applyThemesOnElement(this, this.hass.themes, this._viewConfigTheme);
}
Expand Down
Loading