mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-30 04:36:36 +00:00
Merge branch 'color-palettes' of github.com:home-assistant/frontend into ha-button
This commit is contained in:
commit
6eb8261525
19
package.json
19
package.json
@ -26,7 +26,7 @@
|
||||
"license": "Apache-2.0",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.27.6",
|
||||
"@babel/runtime": "7.28.2",
|
||||
"@braintree/sanitize-url": "7.1.1",
|
||||
"@codemirror/autocomplete": "6.18.6",
|
||||
"@codemirror/commands": "6.8.1",
|
||||
@ -101,6 +101,7 @@
|
||||
"comlink": "4.4.2",
|
||||
"core-js": "3.44.0",
|
||||
"cropperjs": "1.6.2",
|
||||
"culori": "4.0.2",
|
||||
"date-fns": "4.1.0",
|
||||
"date-fns-tz": "3.2.0",
|
||||
"deep-clone-simple": "1.1.1",
|
||||
@ -153,17 +154,18 @@
|
||||
"@babel/plugin-transform-runtime": "7.28.0",
|
||||
"@babel/preset-env": "7.28.0",
|
||||
"@bundle-stats/plugin-webpack-filter": "4.21.0",
|
||||
"@lokalise/node-api": "14.9.1",
|
||||
"@lokalise/node-api": "15.0.0",
|
||||
"@octokit/auth-oauth-device": "8.0.1",
|
||||
"@octokit/plugin-retry": "8.0.1",
|
||||
"@octokit/rest": "22.0.0",
|
||||
"@rsdoctor/rspack-plugin": "1.1.8",
|
||||
"@rspack/cli": "1.4.8",
|
||||
"@rspack/core": "1.4.8",
|
||||
"@rsdoctor/rspack-plugin": "1.1.10",
|
||||
"@rspack/cli": "1.4.10",
|
||||
"@rspack/core": "1.4.10",
|
||||
"@types/babel__plugin-transform-runtime": "7.9.5",
|
||||
"@types/chromecast-caf-receiver": "6.0.22",
|
||||
"@types/chromecast-caf-sender": "1.0.11",
|
||||
"@types/color-name": "2.0.0",
|
||||
"@types/culori": "4",
|
||||
"@types/html-minifier-terser": "7.0.2",
|
||||
"@types/js-yaml": "4.0.9",
|
||||
"@types/leaflet": "1.9.20",
|
||||
@ -188,7 +190,7 @@
|
||||
"eslint-import-resolver-webpack": "0.13.10",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
"eslint-plugin-lit": "2.1.1",
|
||||
"eslint-plugin-lit-a11y": "5.1.0",
|
||||
"eslint-plugin-lit-a11y": "5.1.1",
|
||||
"eslint-plugin-unused-imports": "4.1.4",
|
||||
"eslint-plugin-wc": "3.0.1",
|
||||
"fancy-log": "2.0.0",
|
||||
@ -216,7 +218,7 @@
|
||||
"terser-webpack-plugin": "5.3.14",
|
||||
"ts-lit-plugin": "2.0.2",
|
||||
"typescript": "5.8.3",
|
||||
"typescript-eslint": "8.37.0",
|
||||
"typescript-eslint": "8.38.0",
|
||||
"vite-tsconfig-paths": "5.1.4",
|
||||
"vitest": "3.2.4",
|
||||
"webpack-stats-plugin": "1.1.3",
|
||||
@ -232,7 +234,8 @@
|
||||
"@fullcalendar/daygrid": "6.1.18",
|
||||
"globals": "16.3.0",
|
||||
"tslib": "2.8.1",
|
||||
"@material/mwc-list@^0.27.0": "patch:@material/mwc-list@npm%3A0.27.0#~/.yarn/patches/@material-mwc-list-npm-0.27.0-5344fc9de4.patch"
|
||||
"@material/mwc-list@^0.27.0": "patch:@material/mwc-list@npm%3A0.27.0#~/.yarn/patches/@material-mwc-list-npm-0.27.0-5344fc9de4.patch",
|
||||
"@vaadin/vaadin-themable-mixin": "24.7.9"
|
||||
},
|
||||
"packageManager": "yarn@4.9.2"
|
||||
}
|
||||
|
115
src/common/color/palette.ts
Normal file
115
src/common/color/palette.ts
Normal file
@ -0,0 +1,115 @@
|
||||
import { formatHex, oklch, wcagLuminance, type Oklch } from "culori";
|
||||
|
||||
const MIN_LUMINANCE = 0.3;
|
||||
const MAX_LUMINANCE = 0.6;
|
||||
|
||||
/**
|
||||
* Normalizes the luminance of a given color to ensure it falls within the specified minimum and maximum luminance range.
|
||||
* This helps to keep everything readable and accessible, especially for text and UI elements.
|
||||
*
|
||||
* This function converts the input color to the OKLCH color space, calculates its luminance,
|
||||
* and adjusts the lightness component if the luminance is outside the allowed range.
|
||||
* The adjustment is performed using a binary search to find the appropriate lightness value.
|
||||
* If the color is already within the range, it is returned unchanged.
|
||||
*
|
||||
* @param color - HEX color string
|
||||
* @returns The normalized color as a hex string, or the original color if normalization is not needed.
|
||||
* @throws If the provided color is invalid or cannot be parsed.
|
||||
*/
|
||||
export const normalizeLuminance = (color: string): string => {
|
||||
const baseOklch = oklch(color);
|
||||
|
||||
if (baseOklch === undefined) {
|
||||
throw new Error("Invalid color provided");
|
||||
}
|
||||
|
||||
const luminance = wcagLuminance(baseOklch);
|
||||
|
||||
if (luminance >= MIN_LUMINANCE && luminance <= MAX_LUMINANCE) {
|
||||
return color;
|
||||
}
|
||||
const targetLuminance =
|
||||
luminance < MIN_LUMINANCE ? MIN_LUMINANCE : MAX_LUMINANCE;
|
||||
|
||||
function findLightness(lowL = 0, highL = 1, iterations = 10) {
|
||||
if (iterations <= 0) {
|
||||
return (lowL + highL) / 2;
|
||||
}
|
||||
|
||||
const midL = (lowL + highL) / 2;
|
||||
const testColor = { ...baseOklch, l: midL } as Oklch;
|
||||
const testLuminance = wcagLuminance(testColor);
|
||||
|
||||
if (Math.abs(testLuminance - targetLuminance) < 0.01) {
|
||||
return midL;
|
||||
}
|
||||
if (testLuminance < targetLuminance) {
|
||||
return findLightness(midL, highL, iterations--);
|
||||
}
|
||||
return findLightness(lowL, midL, iterations--);
|
||||
}
|
||||
|
||||
baseOklch.l = findLightness();
|
||||
|
||||
return formatHex(baseOklch) || color;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a color palette based on a base color using the OKLCH color space.
|
||||
*
|
||||
* The palette consists of multiple shades, both lighter and darker than the base color,
|
||||
* calculated by adjusting the lightness and chroma values. Each shade is labeled and
|
||||
* returned as a tuple containing the shade name and its hexadecimal color value.
|
||||
*
|
||||
* @param baseColor - The base color in a HEX format.
|
||||
* @param label - A string label used to name each color variant in the palette.
|
||||
* @param steps - An array of numbers representing the percentage steps for generating shades (default: [5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 95]).
|
||||
* @returns An array of tuples, each containing the shade name and its corresponding hex color value.
|
||||
* @throws If the provided base color is invalid or cannot be parsed by the `oklch` function.
|
||||
*/
|
||||
export const generateColorPalette = (
|
||||
baseColor: string,
|
||||
label: string,
|
||||
steps = [5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 95]
|
||||
) => {
|
||||
const baseOklch = oklch(baseColor);
|
||||
|
||||
if (baseOklch === undefined) {
|
||||
throw new Error("Invalid base color provided");
|
||||
}
|
||||
|
||||
return steps.map((step) => {
|
||||
const name = `color-${label}-${step}`;
|
||||
|
||||
// Base color at 50%
|
||||
if (step === 50) {
|
||||
return [name, formatHex(baseOklch)];
|
||||
}
|
||||
|
||||
// For darker shades (below 50%)
|
||||
if (step < 50) {
|
||||
const darkFactor = step / 50;
|
||||
|
||||
// Adjust lightness and chroma to create darker variants
|
||||
const darker = {
|
||||
...baseOklch,
|
||||
l: baseOklch.l * darkFactor, // darkening
|
||||
c: baseOklch.c * (0.9 + 0.1 * darkFactor), // Slightly adjust chroma
|
||||
};
|
||||
|
||||
return [name, formatHex(darker)];
|
||||
}
|
||||
|
||||
// For lighter shades (above 50%)
|
||||
const lightFactor = (step - 50) / 45; // Normalized from 0 to 1
|
||||
|
||||
// Adjust lightness and reduce chroma for lighter variants
|
||||
const lighter = {
|
||||
...baseOklch,
|
||||
l: Math.min(1, baseOklch.l + (1 - baseOklch.l) * lightFactor), // Increase lightness
|
||||
c: baseOklch.c * Math.max(0, 1 - lightFactor * 0.7), // Gradually reduce chroma
|
||||
};
|
||||
|
||||
return [name, formatHex(lighter)];
|
||||
});
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
import type { ThemeVars } from "../../data/ws-themes";
|
||||
import { darkColorVariables } from "../../resources/theme/color.globals";
|
||||
import { darkColorVariables } from "../../resources/theme/color";
|
||||
import { derivedStyles } from "../../resources/theme/theme";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import {
|
||||
@ -11,6 +11,7 @@ import {
|
||||
} from "../color/convert-color";
|
||||
import { hexBlend } from "../color/hex";
|
||||
import { labBrighten, labDarken } from "../color/lab";
|
||||
import { generateColorPalette } from "../color/palette";
|
||||
import { rgbContrast } from "../color/rgb";
|
||||
|
||||
interface ProcessedTheme {
|
||||
@ -75,6 +76,11 @@ export const applyThemesOnElement = (
|
||||
const labPrimaryColor = rgb2lab(rgbPrimaryColor);
|
||||
themeRules["primary-color"] = primaryColor;
|
||||
const rgbLightPrimaryColor = lab2rgb(labBrighten(labPrimaryColor));
|
||||
|
||||
generateColorPalette(primaryColor, "primary").forEach(([key, color]) => {
|
||||
themeRules[key] = color;
|
||||
});
|
||||
|
||||
themeRules["light-primary-color"] = rgb2hex(rgbLightPrimaryColor);
|
||||
themeRules["dark-primary-color"] = lab2hex(labDarken(labPrimaryColor));
|
||||
themeRules["darker-primary-color"] = lab2hex(
|
||||
|
@ -18,7 +18,43 @@ const _extractCssVars = (
|
||||
return variables;
|
||||
};
|
||||
|
||||
export const extractVar = (css: CSSResult, varName: string) => {
|
||||
/**
|
||||
* Recursively resolves a CSS variable reference from a base variable map.
|
||||
*
|
||||
* If the value of the specified variable in `baseVars` is itself a CSS variable reference
|
||||
* (i.e., starts with `var(`), this function will recursively resolve the reference until
|
||||
* it finds a concrete value or reaches an undefined variable.
|
||||
*
|
||||
* @param varName - The name of the CSS variable to resolve.
|
||||
* @param baseVars - A record mapping variable names to their values or references.
|
||||
* @returns The resolved value of the variable, or `undefined` if not found.
|
||||
*/
|
||||
const extractVarFromBase = (
|
||||
varName: string,
|
||||
baseVars: Record<string, string>
|
||||
): string | undefined => {
|
||||
if (baseVars[varName] && baseVars[varName].startsWith("var(")) {
|
||||
const baseVarName = baseVars[varName]
|
||||
.substring(6, baseVars[varName].length - 1)
|
||||
.trim();
|
||||
return extractVarFromBase(baseVarName, baseVars);
|
||||
}
|
||||
return baseVars[varName];
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts the value of a CSS custom property (CSS variable) from a given CSSResult object.
|
||||
*
|
||||
* @param css - The CSSResult object containing the CSS string to search.
|
||||
* @param varName - The name of the CSS variable (without the leading '--') to extract.
|
||||
* @param baseVars - (Optional) A record of base variable names and their values, used to resolve variables that reference other variables via `var()`.
|
||||
* @returns The value of the CSS variable if found, otherwise an empty string. If the variable references another variable and `baseVars` is provided, attempts to resolve it from `baseVars`.
|
||||
*/
|
||||
export const extractVar = (
|
||||
css: CSSResult,
|
||||
varName: string,
|
||||
baseVars?: Record<string, string>
|
||||
) => {
|
||||
const cssString = css.toString();
|
||||
const search = `--${varName}:`;
|
||||
const startIndex = cssString.indexOf(search);
|
||||
@ -27,10 +63,17 @@ export const extractVar = (css: CSSResult, varName: string) => {
|
||||
}
|
||||
|
||||
const endIndex = cssString.indexOf(";", startIndex + search.length);
|
||||
return cssString
|
||||
const value = cssString
|
||||
.substring(startIndex + search.length, endIndex)
|
||||
.replaceAll("}", "")
|
||||
.trim();
|
||||
|
||||
if (baseVars && value.startsWith("var(")) {
|
||||
const baseVarName = value.substring(6, value.length - 1).trim();
|
||||
return extractVarFromBase(baseVarName, baseVars) || value;
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
export const extractVars = (css: CSSResult) => {
|
||||
|
@ -29,7 +29,7 @@ import { formatTimeLabel } from "./axis-label";
|
||||
import { ensureArray } from "../../common/array/ensure-array";
|
||||
import "../chips/ha-assist-chip";
|
||||
import { downSampleLineData } from "./down-sample";
|
||||
import { colorVariables } from "../../resources/theme/color.globals";
|
||||
import { colorVariables } from "../../resources/theme/color/color.globals";
|
||||
|
||||
export const MIN_TIME_BETWEEN_UPDATES = 60 * 5 * 1000;
|
||||
const LEGEND_OVERFLOW_LIMIT = 10;
|
||||
|
@ -95,6 +95,7 @@ export class HaColorTempSelector extends LitElement {
|
||||
);
|
||||
|
||||
private _valueChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
fireEvent(this, "value-changed", {
|
||||
value: Number((ev.detail as any).value),
|
||||
});
|
||||
|
@ -279,6 +279,7 @@ export class HaObjectSelector extends LitElement {
|
||||
}
|
||||
|
||||
private _handleChange(ev) {
|
||||
ev.stopPropagation();
|
||||
this._valueChangedFromChild = true;
|
||||
const value = ev.target.value;
|
||||
if (!ev.target.isValid) {
|
||||
|
@ -71,6 +71,7 @@ export class HaTemplateSelector extends LitElement {
|
||||
}
|
||||
|
||||
private _handleChange(ev) {
|
||||
ev.stopPropagation();
|
||||
let value = ev.target.value;
|
||||
if (this.value === value) {
|
||||
return;
|
||||
|
@ -111,6 +111,7 @@ export class HaTextSelector extends LitElement {
|
||||
}
|
||||
|
||||
private _handleChange(ev) {
|
||||
ev.stopPropagation();
|
||||
let value = ev.detail?.value ?? ev.target.value;
|
||||
if (this.value === value) {
|
||||
return;
|
||||
|
@ -33,6 +33,7 @@ export class HaSelectorUiAction extends LitElement {
|
||||
}
|
||||
|
||||
private _valueChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
fireEvent(this, "value-changed", { value: ev.detail.value });
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ export class HaSelectorUiColor extends LitElement {
|
||||
}
|
||||
|
||||
private _valueChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
fireEvent(this, "value-changed", { value: ev.detail.value });
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +146,12 @@ const cloudyStates = new Set<string>([
|
||||
"lightning-rainy",
|
||||
]);
|
||||
|
||||
const rainStates = new Set<string>(["hail", "rainy", "pouring"]);
|
||||
const rainStates = new Set<string>([
|
||||
"hail",
|
||||
"rainy",
|
||||
"pouring",
|
||||
"lightning-rainy",
|
||||
]);
|
||||
|
||||
const windyStates = new Set<string>(["windy", "windy-variant"]);
|
||||
|
||||
|
@ -1,9 +1,19 @@
|
||||
import { mdiDotsVertical, mdiDownload } from "@mdi/js";
|
||||
import type { TemplateResult } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-list-item";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import { getSignedPath } from "../../../data/auth";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import type { HomeAssistant, Route } from "../../../types";
|
||||
import "./ha-config-analytics";
|
||||
import {
|
||||
downloadFileSupported,
|
||||
fileDownload,
|
||||
} from "../../../util/file_download";
|
||||
|
||||
@customElement("ha-config-section-analytics")
|
||||
class HaConfigSectionAnalytics extends LitElement {
|
||||
@ -21,6 +31,26 @@ class HaConfigSectionAnalytics extends LitElement {
|
||||
.narrow=${this.narrow}
|
||||
.header=${this.hass.localize("ui.panel.config.analytics.caption")}
|
||||
>
|
||||
${downloadFileSupported(this.hass)
|
||||
? html`
|
||||
<ha-button-menu
|
||||
@action=${this._handleOverflowAction}
|
||||
slot="toolbar-icon"
|
||||
>
|
||||
<ha-icon-button slot="trigger" .path=${mdiDotsVertical}>
|
||||
</ha-icon-button>
|
||||
<ha-list-item graphic="icon">
|
||||
<ha-svg-icon
|
||||
slot="graphic"
|
||||
.path=${mdiDownload}
|
||||
></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.analytics.download_device_info"
|
||||
)}
|
||||
</ha-list-item>
|
||||
</ha-button-menu>
|
||||
`
|
||||
: nothing}
|
||||
<div class="content">
|
||||
<ha-config-analytics .hass=${this.hass}></ha-config-analytics>
|
||||
</div>
|
||||
@ -28,6 +58,11 @@ class HaConfigSectionAnalytics extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private async _handleOverflowAction(): Promise<void> {
|
||||
const signedPath = await getSignedPath(this.hass, "/api/analytics/devices");
|
||||
fileDownload(signedPath.path);
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
.content {
|
||||
padding: 28px 20px 0;
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { mdiPower } from "@mdi/js";
|
||||
import type { SeriesOption } from "echarts/types/dist/shared";
|
||||
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import type { PropertyValues } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import type { SeriesOption } from "echarts/types/dist/shared";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { round } from "../../../common/number/round";
|
||||
@ -11,11 +11,11 @@ import { blankBeforePercent } from "../../../common/translations/blank_before_pe
|
||||
import "../../../components/buttons/ha-progress-button";
|
||||
import "../../../components/chart/ha-chart-base";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-button";
|
||||
import "../../../components/ha-md-list-item";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-icon-next";
|
||||
import "../../../components/ha-md-list-item";
|
||||
import "../../../components/ha-settings-row";
|
||||
import type { ConfigEntry } from "../../../data/config_entries";
|
||||
import { subscribeConfigEntries } from "../../../data/config_entries";
|
||||
@ -24,6 +24,7 @@ import type {
|
||||
SystemStatusStreamMessage,
|
||||
} from "../../../data/hardware";
|
||||
import { BOARD_NAMES } from "../../../data/hardware";
|
||||
import { extractApiErrorMessage } from "../../../data/hassio/common";
|
||||
import type { HassioHassOSInfo } from "../../../data/hassio/host";
|
||||
import { fetchHassioHassOsInfo } from "../../../data/hassio/host";
|
||||
import { scanUSBDevices } from "../../../data/usb";
|
||||
@ -31,13 +32,12 @@ import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-
|
||||
import { showRestartDialog } from "../../../dialogs/restart/show-dialog-restart";
|
||||
import "../../../layouts/hass-subpage";
|
||||
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||
import { DefaultPrimaryColor } from "../../../resources/theme/color.globals";
|
||||
import type { ECOption } from "../../../resources/echarts";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import { DefaultPrimaryColor } from "../../../resources/theme/color/color.globals";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { hardwareBrandsUrl } from "../../../util/brands-url";
|
||||
import { showhardwareAvailableDialog } from "./show-dialog-hardware-available";
|
||||
import { extractApiErrorMessage } from "../../../data/hassio/common";
|
||||
import type { ECOption } from "../../../resources/echarts";
|
||||
|
||||
const DATASAMPLES = 60;
|
||||
|
||||
|
@ -95,15 +95,12 @@ class AddIntegrationDialog extends LitElement {
|
||||
|
||||
public async showDialog(params?: AddIntegrationDialogParams): Promise<void> {
|
||||
const loadPromise = this._load();
|
||||
this._open = true;
|
||||
this._pickedBrand = params?.brand;
|
||||
this._initialFilter = params?.initialFilter;
|
||||
this._narrow = matchMedia(
|
||||
"all and (max-width: 450px), all and (max-height: 500px)"
|
||||
).matches;
|
||||
if (params?.domain) {
|
||||
this._createFlow(params.domain);
|
||||
// Just open the config flow dialog, do not show this dialog
|
||||
await this._createFlow(params.domain);
|
||||
return;
|
||||
}
|
||||
|
||||
if (params?.brand) {
|
||||
await loadPromise;
|
||||
const brand = this._integrations?.[params.brand];
|
||||
@ -111,6 +108,13 @@ class AddIntegrationDialog extends LitElement {
|
||||
this._fetchFlowsInProgress(Object.keys(brand.integrations));
|
||||
}
|
||||
}
|
||||
// Only open the dialog if no domain is provided
|
||||
this._open = true;
|
||||
this._pickedBrand = params?.brand;
|
||||
this._initialFilter = params?.initialFilter;
|
||||
this._narrow = matchMedia(
|
||||
"all and (max-width: 450px), all and (max-height: 500px)"
|
||||
).matches;
|
||||
}
|
||||
|
||||
public closeDialog() {
|
||||
|
@ -1,18 +1,20 @@
|
||||
import { html, LitElement, css } from "lit";
|
||||
import type { CSSResultGroup } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import type {
|
||||
CallbackDataParams,
|
||||
TopLevelFormatterParams,
|
||||
} from "echarts/types/dist/shared";
|
||||
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import type { CSSResultGroup } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import type { HomeAssistant, Route } from "../../../../../types";
|
||||
import { relativeTime } from "../../../../../common/datetime/relative_time";
|
||||
import { navigate } from "../../../../../common/navigate";
|
||||
import { throttle } from "../../../../../common/util/throttle";
|
||||
import "../../../../../components/chart/ha-network-graph";
|
||||
import type {
|
||||
NetworkData,
|
||||
NetworkNode,
|
||||
NetworkLink,
|
||||
NetworkNode,
|
||||
} from "../../../../../components/chart/ha-network-graph";
|
||||
import type {
|
||||
BluetoothDeviceData,
|
||||
@ -24,11 +26,9 @@ import {
|
||||
} from "../../../../../data/bluetooth";
|
||||
import type { DeviceRegistryEntry } from "../../../../../data/device_registry";
|
||||
import "../../../../../layouts/hass-subpage";
|
||||
import { colorVariables } from "../../../../../resources/theme/color.globals";
|
||||
import { navigate } from "../../../../../common/navigate";
|
||||
import { colorVariables } from "../../../../../resources/theme/color/color.globals";
|
||||
import type { HomeAssistant, Route } from "../../../../../types";
|
||||
import { bluetoothAdvertisementMonitorTabs } from "./bluetooth-advertisement-monitor";
|
||||
import { relativeTime } from "../../../../../common/datetime/relative_time";
|
||||
import { throttle } from "../../../../../common/util/throttle";
|
||||
|
||||
const UPDATE_THROTTLE_TIME = 10000;
|
||||
|
||||
|
@ -1,25 +1,25 @@
|
||||
import type { CSSResultGroup, PropertyValues } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { mdiRefresh } from "@mdi/js";
|
||||
import type {
|
||||
CallbackDataParams,
|
||||
TopLevelFormatterParams,
|
||||
} from "echarts/types/dist/shared";
|
||||
import { mdiRefresh } from "@mdi/js";
|
||||
import type { CSSResultGroup, PropertyValues } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { navigate } from "../../../../../common/navigate";
|
||||
import "../../../../../components/chart/ha-network-graph";
|
||||
import type {
|
||||
NetworkData,
|
||||
NetworkNode,
|
||||
NetworkLink,
|
||||
NetworkNode,
|
||||
} from "../../../../../components/chart/ha-network-graph";
|
||||
import type { ZHADevice } from "../../../../../data/zha";
|
||||
import { fetchDevices, refreshTopology } from "../../../../../data/zha";
|
||||
import "../../../../../layouts/hass-tabs-subpage";
|
||||
import { colorVariables } from "../../../../../resources/theme/color/color.globals";
|
||||
import type { HomeAssistant, Route } from "../../../../../types";
|
||||
import { formatAsPaddedHex } from "./functions";
|
||||
import { zhaTabs } from "./zha-config-dashboard";
|
||||
import { colorVariables } from "../../../../../resources/theme/color.globals";
|
||||
import { navigate } from "../../../../../common/navigate";
|
||||
|
||||
@customElement("zha-network-visualization-page")
|
||||
export class ZHANetworkVisualizationPage extends LitElement {
|
||||
|
@ -1,33 +1,33 @@
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import memoizeOne from "memoize-one";
|
||||
import type {
|
||||
CallbackDataParams,
|
||||
TopLevelFormatterParams,
|
||||
} from "echarts/types/dist/shared";
|
||||
import type { HomeAssistant, Route } from "../../../../../types";
|
||||
import { configTabs } from "./zwave_js-config-router";
|
||||
import { SubscribeMixin } from "../../../../../mixins/subscribe-mixin";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { navigate } from "../../../../../common/navigate";
|
||||
import { debounce } from "../../../../../common/util/debounce";
|
||||
import "../../../../../components/chart/ha-network-graph";
|
||||
import type {
|
||||
NetworkData,
|
||||
NetworkLink,
|
||||
NetworkNode,
|
||||
} from "../../../../../components/chart/ha-network-graph";
|
||||
import "../../../../../components/chart/ha-network-graph";
|
||||
import "../../../../../layouts/hass-tabs-subpage";
|
||||
import type { DeviceRegistryEntry } from "../../../../../data/device_registry";
|
||||
import type {
|
||||
ZWaveJSNodeStatisticsUpdatedMessage,
|
||||
ZWaveJSNodeStatus,
|
||||
} from "../../../../../data/zwave_js";
|
||||
import {
|
||||
fetchZwaveNetworkStatus,
|
||||
NodeStatus,
|
||||
subscribeZwaveNodeStatistics,
|
||||
} from "../../../../../data/zwave_js";
|
||||
import type {
|
||||
ZWaveJSNodeStatisticsUpdatedMessage,
|
||||
ZWaveJSNodeStatus,
|
||||
} from "../../../../../data/zwave_js";
|
||||
import { colorVariables } from "../../../../../resources/theme/color.globals";
|
||||
import type { DeviceRegistryEntry } from "../../../../../data/device_registry";
|
||||
import { debounce } from "../../../../../common/util/debounce";
|
||||
import { navigate } from "../../../../../common/navigate";
|
||||
import "../../../../../layouts/hass-tabs-subpage";
|
||||
import { SubscribeMixin } from "../../../../../mixins/subscribe-mixin";
|
||||
import { colorVariables } from "../../../../../resources/theme/color/color.globals";
|
||||
import type { HomeAssistant, Route } from "../../../../../types";
|
||||
import { configTabs } from "./zwave_js-config-router";
|
||||
|
||||
@customElement("zwave_js-network-visualization")
|
||||
export class ZWaveJSNetworkVisualization extends SubscribeMixin(LitElement) {
|
||||
|
@ -140,7 +140,7 @@ export class HuiActionEditor extends LitElement {
|
||||
.value=${action}
|
||||
@closed=${stopPropagation}
|
||||
fixedMenuPosition
|
||||
naturalMenuWidt
|
||||
naturalMenuWidth
|
||||
>
|
||||
<ha-list-item value="default">
|
||||
${this.hass!.localize(
|
||||
|
@ -25,6 +25,7 @@ export interface GUIModeChangedEvent {
|
||||
export interface ViewEditEvent extends Event {
|
||||
detail: {
|
||||
config: LovelaceViewConfig;
|
||||
valid?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,8 @@ export class HuiDialogEditView extends LitElement {
|
||||
|
||||
@state() private _dirty = false;
|
||||
|
||||
@state() private _valid = true;
|
||||
|
||||
@state() private _yamlMode = false;
|
||||
|
||||
@query("ha-yaml-editor") private _editor?: HaYamlEditor;
|
||||
@ -309,6 +311,7 @@ export class HuiDialogEditView extends LitElement {
|
||||
?disabled=${!this._config ||
|
||||
this._saving ||
|
||||
!this._dirty ||
|
||||
!this._valid ||
|
||||
convertToSection ||
|
||||
convertNotSupported}
|
||||
@click=${this._save}
|
||||
@ -580,6 +583,9 @@ export class HuiDialogEditView extends LitElement {
|
||||
ev.detail.config &&
|
||||
!deepEqual(this._config, ev.detail.config)
|
||||
) {
|
||||
if (ev.detail.valid !== undefined) {
|
||||
this._valid = ev.detail.valid;
|
||||
}
|
||||
this._config = ev.detail.config;
|
||||
this._dirty = true;
|
||||
}
|
||||
|
@ -23,10 +23,13 @@ declare global {
|
||||
interface HASSDomEvents {
|
||||
"view-config-changed": {
|
||||
config: LovelaceViewConfig;
|
||||
valid?: boolean;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const VALID_PATH_REGEX = /^[a-zA-Z0-9_-]+$/;
|
||||
|
||||
@customElement("hui-view-editor")
|
||||
export class HuiViewEditor extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
@ -35,6 +38,8 @@ export class HuiViewEditor extends LitElement {
|
||||
|
||||
@state() private _config!: LovelaceViewConfig;
|
||||
|
||||
@state() private _error: Record<string, string> | undefined;
|
||||
|
||||
private _suggestedPath = false;
|
||||
|
||||
private _schema = memoizeOne(
|
||||
@ -144,6 +149,8 @@ export class HuiViewEditor extends LitElement {
|
||||
.schema=${schema}
|
||||
.computeLabel=${this._computeLabel}
|
||||
.computeHelper=${this._computeHelper}
|
||||
.computeError=${this._computeError}
|
||||
.error=${this._error}
|
||||
@value-changed=${this._valueChanged}
|
||||
></ha-form>
|
||||
`;
|
||||
@ -168,9 +175,20 @@ export class HuiViewEditor extends LitElement {
|
||||
config.path = slugify(config.title || "", "-");
|
||||
}
|
||||
|
||||
fireEvent(this, "view-config-changed", { config });
|
||||
let valid = true;
|
||||
this._error = undefined;
|
||||
if (config.path && !VALID_PATH_REGEX.test(config.path)) {
|
||||
valid = false;
|
||||
this._error = { path: "error_invalid_path" };
|
||||
}
|
||||
|
||||
fireEvent(this, "view-config-changed", { valid, config });
|
||||
}
|
||||
|
||||
private _computeError = (error: string) =>
|
||||
this.hass.localize(`ui.panel.lovelace.editor.edit_view.${error}` as any) ||
|
||||
error;
|
||||
|
||||
private _computeLabel = (
|
||||
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||
) => {
|
||||
@ -197,6 +215,7 @@ export class HuiViewEditor extends LitElement {
|
||||
schema: SchemaUnion<ReturnType<typeof this._schema>>
|
||||
) => {
|
||||
switch (schema.name) {
|
||||
case "path":
|
||||
case "subview":
|
||||
case "dense_section_placement":
|
||||
case "top_margin":
|
||||
|
@ -1,6 +1,7 @@
|
||||
import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { normalizeLuminance } from "../../common/color/palette";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import "../../components/ha-formfield";
|
||||
import "../../components/ha-list-item";
|
||||
@ -13,7 +14,7 @@ import "../../components/ha-textfield";
|
||||
import {
|
||||
DefaultAccentColor,
|
||||
DefaultPrimaryColor,
|
||||
} from "../../resources/theme/color.globals";
|
||||
} from "../../resources/theme/color/color.globals";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import { documentationUrl } from "../../util/documentation-url";
|
||||
|
||||
@ -174,6 +175,12 @@ export class HaPickThemeRow extends LitElement {
|
||||
|
||||
private _handleColorChange(ev: CustomEvent) {
|
||||
const target = ev.target as any;
|
||||
|
||||
// normalize primary color if needed for contrast
|
||||
if (target.name === "primaryColor") {
|
||||
target.value = normalizeLuminance(target.value);
|
||||
}
|
||||
|
||||
fireEvent(this, "settheme", { [target.name]: target.value });
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { tsParticles } from "@tsparticles/engine";
|
||||
import { loadLinksPreset } from "@tsparticles/preset-links";
|
||||
import { DefaultPrimaryColor } from "./theme/color.globals";
|
||||
import { DefaultPrimaryColor } from "./theme/color/color.globals";
|
||||
|
||||
loadLinksPreset(tsParticles).then(() => {
|
||||
tsParticles.load({
|
||||
|
@ -1,21 +1,21 @@
|
||||
import { css } from "lit";
|
||||
import {
|
||||
extractDerivedVars,
|
||||
extractVar,
|
||||
extractVars,
|
||||
} from "../../common/style/derived-css-vars";
|
||||
} from "../../../common/style/derived-css-vars";
|
||||
import { coreColorVariables } from "./core.globals";
|
||||
|
||||
export const colorStyles = css`
|
||||
html {
|
||||
/* text */
|
||||
--primary-text-color: #212121;
|
||||
--secondary-text-color: #727272;
|
||||
--primary-text-color: var(--color-text-primary);
|
||||
--secondary-text-color: var(--color-text-secondary);
|
||||
--text-primary-color: #ffffff;
|
||||
--text-light-primary-color: #212121;
|
||||
--disabled-text-color: #bdbdbd;
|
||||
|
||||
/* main interface colors */
|
||||
--primary-color: #03a9f4;
|
||||
--primary-color: var(--color-primary-40);
|
||||
--dark-primary-color: #0288d1;
|
||||
--darker-primary-color: #016194;
|
||||
--light-primary-color: #b3e5fc;
|
||||
@ -25,7 +25,7 @@ export const colorStyles = css`
|
||||
--outline-hover-color: rgba(0, 0, 0, 0.24);
|
||||
|
||||
/* rgb */
|
||||
--rgb-primary-color: 3, 169, 244;
|
||||
--rgb-primary-color: 0, 154, 199;
|
||||
--rgb-accent-color: 255, 152, 0;
|
||||
--rgb-primary-text-color: 33, 33, 33;
|
||||
--rgb-secondary-text-color: 114, 114, 114;
|
||||
@ -330,7 +330,7 @@ export const colorStyles = css`
|
||||
}
|
||||
`;
|
||||
|
||||
const darkColorStyles = css`
|
||||
export const darkColorStyles = css`
|
||||
html {
|
||||
--primary-background-color: #111111;
|
||||
--card-background-color: #1c1c1c;
|
||||
@ -391,9 +391,11 @@ const darkColorStyles = css`
|
||||
--ha-button-neutral-light-color: #6a7081;
|
||||
}
|
||||
`;
|
||||
export const colorDerivedVariables = extractDerivedVars(colorStyles);
|
||||
export const colorVariables = extractVars(colorStyles);
|
||||
export const darkColorVariables = extractVars(darkColorStyles);
|
||||
|
||||
export const DefaultPrimaryColor = extractVar(colorStyles, "primary-color");
|
||||
export const DefaultPrimaryColor = extractVar(
|
||||
colorStyles,
|
||||
"primary-color",
|
||||
coreColorVariables
|
||||
);
|
||||
export const DefaultAccentColor = extractVar(colorStyles, "accent-color");
|
154
src/resources/theme/color/core.globals.ts
Normal file
154
src/resources/theme/color/core.globals.ts
Normal file
@ -0,0 +1,154 @@
|
||||
import { css } from "lit";
|
||||
import { extractVars } from "../../../common/style/derived-css-vars";
|
||||
|
||||
export const coreColorStyles = css`
|
||||
html {
|
||||
--white: #ffffff;
|
||||
--black: #000000;
|
||||
--transparent-none: rgba(255, 255, 255, 0);
|
||||
|
||||
/* primary */
|
||||
--color-primary-05: #001721;
|
||||
--color-primary-10: #002e3e;
|
||||
--color-primary-20: #004156;
|
||||
--color-primary-30: #006787;
|
||||
--color-primary-40: #009ac7;
|
||||
--color-primary-50: #18bcf2;
|
||||
--color-primary-60: #37c8fd;
|
||||
--color-primary-70: #7bd4fb;
|
||||
--color-primary-80: #b9e6fc;
|
||||
--color-primary-90: #b9e6fc;
|
||||
--color-primary-95: #eff9fe;
|
||||
|
||||
/* neutral */
|
||||
--color-neutral-05: #101219;
|
||||
--color-neutral-10: #1b1d26;
|
||||
--color-neutral-20: #2f323f;
|
||||
--color-neutral-30: #424554;
|
||||
--color-neutral-40: #545868;
|
||||
--color-neutral-50: #717584;
|
||||
--color-neutral-60: #9194a2;
|
||||
--color-neutral-70: #abaeb9;
|
||||
--color-neutral-80: #c7c9d0;
|
||||
--color-neutral-90: #e4e5e9;
|
||||
--color-neutral-95: #f1f2f3;
|
||||
|
||||
/* indigo */
|
||||
--color-indigo-05: #0d0a3a;
|
||||
--color-indigo-10: #181255;
|
||||
--color-indigo-20: #292381;
|
||||
--color-indigo-30: #3933a7;
|
||||
--color-indigo-40: #4945cb;
|
||||
--color-indigo-50: #6163f2;
|
||||
--color-indigo-60: #808aff;
|
||||
--color-indigo-70: #9da9ff;
|
||||
--color-indigo-80: #bcc7ff;
|
||||
--color-indigo-90: #dfe5ff;
|
||||
--color-indigo-95: #f0f2ff;
|
||||
|
||||
/* purple */
|
||||
--color-purple-05: #1e0532;
|
||||
--color-purple-10: #2d0b48;
|
||||
--color-purple-20: #491870;
|
||||
--color-purple-30: #612692;
|
||||
--color-purple-40: #7936b3;
|
||||
--color-purple-50: #9951db;
|
||||
--color-purple-60: #b678f5;
|
||||
--color-purple-70: #ca99ff;
|
||||
--color-purple-80: #ddbdff;
|
||||
--color-purple-90: #eedfff;
|
||||
--color-purple-95: #f7f0ff;
|
||||
|
||||
/* orange */
|
||||
--color-orange-05: #280700;
|
||||
--color-orange-10: #3b0f00;
|
||||
--color-orange-20: #5e1c00;
|
||||
--color-orange-30: #7e2900;
|
||||
--color-orange-40: #9d3800;
|
||||
--color-orange-50: #c94e00;
|
||||
--color-orange-60: #f36d00;
|
||||
--color-orange-70: #ff9342;
|
||||
--color-orange-80: #ffbb89;
|
||||
--color-orange-90: #ffe0c8;
|
||||
--color-orange-95: #fff0e4;
|
||||
|
||||
/* pink */
|
||||
--color-pink-05: #28041a;
|
||||
--color-pink-10: #3c0828;
|
||||
--color-pink-20: #5e1342;
|
||||
--color-pink-30: #7d1e58;
|
||||
--color-pink-40: #9e2a6c;
|
||||
--color-pink-50: #c84382;
|
||||
--color-pink-60: #e66ba3;
|
||||
--color-pink-70: #f78dbf;
|
||||
--color-pink-80: #fcb5d8;
|
||||
--color-pink-90: #feddf0;
|
||||
--color-pink-95: #feeff9;
|
||||
|
||||
/* red */
|
||||
--color-red-05: #2a040b;
|
||||
--color-red-10: #3e0913;
|
||||
--color-red-20: #631323;
|
||||
--color-red-30: #8a132c;
|
||||
--color-red-40: #b30532;
|
||||
--color-red-50: #dc3146;
|
||||
--color-red-60: #f3676c;
|
||||
--color-red-70: #fd8f90;
|
||||
--color-red-80: #ffb8b6;
|
||||
--color-red-90: #ffdedc;
|
||||
--color-red-95: #fff0ef;
|
||||
|
||||
/* yellow */
|
||||
--color-yellow-05: #220c00;
|
||||
--color-yellow-10: #331600;
|
||||
--color-yellow-20: #532600;
|
||||
--color-yellow-30: #6f3601;
|
||||
--color-yellow-40: #8c4602;
|
||||
--color-yellow-50: #b45f04;
|
||||
--color-yellow-60: #da7e00;
|
||||
--color-yellow-70: #ef9d00;
|
||||
--color-yellow-80: #fac22b;
|
||||
--color-yellow-90: #ffe495;
|
||||
--color-yellow-95: #fef3cd;
|
||||
|
||||
/* green */
|
||||
--color-green-05: #031608;
|
||||
--color-green-10: #052310;
|
||||
--color-green-20: #0a3a1d --color-green-30: #0a5027;
|
||||
--color-green-40: #036730;
|
||||
--color-green-50: #00883c;
|
||||
--color-green-60: #00ac49;
|
||||
--color-green-70: #5dc36f;
|
||||
--color-green-80: #93da98;
|
||||
--color-green-90: #c2f2c1;
|
||||
--color-green-95: #e3f9e3;
|
||||
|
||||
/* cyan */
|
||||
--color-cyan-05: #00151b;
|
||||
--color-cyan-10: #002129;
|
||||
--color-cyan-20: #003844;
|
||||
--color-cyan-30: #014c5b;
|
||||
--color-cyan-40: #026274;
|
||||
--color-cyan-50: #078098;
|
||||
--color-cyan-60: #00a3c0;
|
||||
--color-cyan-70: #2fbedc;
|
||||
--color-cyan-80: #7fd6ec;
|
||||
--color-cyan-90: #c5ecf7;
|
||||
--color-cyan-95: #e3f6fb;
|
||||
|
||||
/* blue */
|
||||
--color-blue-05: #000f35;
|
||||
--color-blue-10: #001a4e;
|
||||
--color-blue-20: #002d77;
|
||||
--color-blue-30: #003f9c;
|
||||
--color-blue-40: #0053c0;
|
||||
--color-blue-50: #0071ec;
|
||||
--color-blue-60: #3e96ff;
|
||||
--color-blue-70: #6eb3ff;
|
||||
--color-blue-80: #9fceff;
|
||||
--color-blue-90: #d1e8ff;
|
||||
--color-blue-95: #e8f3ff;
|
||||
}
|
||||
`;
|
||||
|
||||
export const coreColorVariables = extractVars(coreColorStyles);
|
26
src/resources/theme/color/index.ts
Normal file
26
src/resources/theme/color/index.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import {
|
||||
extractDerivedVars,
|
||||
extractVars,
|
||||
} from "../../../common/style/derived-css-vars";
|
||||
import { colorStyles, darkColorStyles } from "./color.globals";
|
||||
import { coreColorStyles } from "./core.globals";
|
||||
import {
|
||||
darkSemanticColorStyles,
|
||||
semanticColorStyles,
|
||||
} from "./semantic.globals";
|
||||
|
||||
export const darkColorVariables = {
|
||||
...extractVars(darkColorStyles),
|
||||
...extractVars(darkSemanticColorStyles),
|
||||
};
|
||||
|
||||
export const colorDerivedVariables = {
|
||||
...extractDerivedVars(colorStyles),
|
||||
...extractDerivedVars(semanticColorStyles),
|
||||
};
|
||||
|
||||
export const colorStylesCollection = [
|
||||
coreColorStyles.toString(),
|
||||
semanticColorStyles.toString(),
|
||||
colorStyles.toString(),
|
||||
];
|
353
src/resources/theme/color/semantic.globals.ts
Normal file
353
src/resources/theme/color/semantic.globals.ts
Normal file
@ -0,0 +1,353 @@
|
||||
import { css } from "lit";
|
||||
|
||||
export const semanticColorStyles = css`
|
||||
html {
|
||||
--color-overlay-modal: rgba(0, 0, 0, 0.25);
|
||||
--color-focus: var(--color-orange-60);
|
||||
|
||||
/* surface */
|
||||
--color-surface-lower: var(--color-neutral-90);
|
||||
--color-surface-low: var(--color-neutral-95);
|
||||
--color-surface-default: var(--white);
|
||||
|
||||
/* text */
|
||||
--color-text-primary: var(--color-neutral-05);
|
||||
--color-text-secondary: var(--color-neutral-40);
|
||||
--color-text-disabled: var(--color-neutral-60);
|
||||
--color-text-link: var(--color-primary-40);
|
||||
|
||||
/* text purple */
|
||||
--color-text-purple-type: var(--color-neutral-05);
|
||||
--color-text-purple-property: var(--color-purple-40);
|
||||
--color-text-purple-target: var(--color-primary-40);
|
||||
|
||||
/* border primary */
|
||||
--color-border-quiet: var(--color-primary-80);
|
||||
--color-border-normal: var(--color-primary-70);
|
||||
--color-border-loud: var(--color-primary-40);
|
||||
|
||||
/* border neutral */
|
||||
--color-border-neutral-quiet: var(--color-neutral-80);
|
||||
--color-border-neutral-normal: var(--color-neutral-60);
|
||||
--color-border-neutral-loud: var(--color-neutral-40);
|
||||
|
||||
/* border danger */
|
||||
--color-border-danger-quiet: var(--color-red-80);
|
||||
--color-border-danger-normal: var(--color-red-70);
|
||||
--color-border-danger-loud: var(--color-red-40);
|
||||
|
||||
/* border warning */
|
||||
--color-border-warning-quiet: var(--color-orange-80);
|
||||
--color-border-warning-normal: var(--color-orange-70);
|
||||
--color-border-warning-loud: var(--color-orange-40);
|
||||
|
||||
/* border success */
|
||||
--color-border-success-quiet: var(--color-green-80);
|
||||
--color-border-success-normal: var(--color-green-70);
|
||||
--color-border-success-loud: var(--color-green-40);
|
||||
|
||||
/* border purple */
|
||||
--color-border-purple-quiet: var(--color-purple-80);
|
||||
--color-border-purple-normal: var(--color-purple-70);
|
||||
--color-border-purple-loud: var(--color-purple-40);
|
||||
|
||||
/* fill primary quiet */
|
||||
--color-fill-primary-quiet-resting: var(--color-primary-95);
|
||||
--color-fill-primary-quiet-hover: var(--color-primary-90);
|
||||
--color-fill-primary-quiet-active: var(--color-primary-95);
|
||||
|
||||
/* fill primary normal */
|
||||
--color-fill-primary-normal-resting: var(--color-primary-90);
|
||||
--color-fill-primary-normal-hover: var(--color-primary-80);
|
||||
--color-fill-primary-normal-active: var(--color-primary-90);
|
||||
|
||||
/* fill primary loud */
|
||||
--color-fill-primary-loud-resting: var(--color-primary-40);
|
||||
--color-fill-primary-loud-hover: var(--color-primary-30);
|
||||
--color-fill-primary-loud-active: var(--color-primary-40);
|
||||
|
||||
/* fill neutral quiet */
|
||||
--color-fill-neutral-quiet-resting: var(--color-neutral-95);
|
||||
--color-fill-neutral-quiet-hover: var(--color-neutral-90);
|
||||
--color-fill-neutral-quiet-active: var(--color-neutral-95);
|
||||
|
||||
/* fill neutral normal */
|
||||
--color-fill-neutral-normal-resting: var(--color-neutral-90);
|
||||
--color-fill-neutral-normal-hover: var(--color-neutral-80);
|
||||
--color-fill-neutral-normal-active: var(--color-neutral-90);
|
||||
|
||||
/* fill neutral loud */
|
||||
--color-fill-neutral-loud-resting: var(--color-neutral-40);
|
||||
--color-fill-neutral-loud-hover: var(--color-neutral-30);
|
||||
--color-fill-neutral-loud-active: var(--color-neutral-40);
|
||||
|
||||
/* fill disabled quiet */
|
||||
--color-fill-disabled-quiet-resting: var(--color-neutral-95);
|
||||
|
||||
/* fill disabled normal */
|
||||
--color-fill-disabled-normal-resting: var(--color-neutral-95);
|
||||
|
||||
/* fill disabled loud */
|
||||
--color-fill-disabled-loud-resting: var(--color-neutral-80);
|
||||
|
||||
/* fill danger quiet */
|
||||
--color-fill-danger-quiet-resting: var(--color-red-95);
|
||||
--color-fill-danger-quiet-hover: var(--color-red-90);
|
||||
--color-fill-danger-quiet-active: var(--color-red-95);
|
||||
|
||||
/* fill danger normal */
|
||||
--color-fill-danger-normal-resting: var(--color-red-90);
|
||||
--color-fill-danger-normal-hover: var(--color-red-80);
|
||||
--color-fill-danger-normal-active: var(--color-red-90);
|
||||
|
||||
/* fill danger loud */
|
||||
--color-fill-danger-loud-resting: var(--color-red-50);
|
||||
--color-fill-danger-loud-hover: var(--color-red-40);
|
||||
--color-fill-danger-loud-active: var(--color-red-50);
|
||||
|
||||
/* fill warning quiet */
|
||||
--color-fill-warning-quiet-resting: var(--color-orange-95);
|
||||
--color-fill-warning-quiet-hover: var(--color-orange-90);
|
||||
--color-fill-warning-quiet-active: var(--color-orange-95);
|
||||
|
||||
/* fill warning normal */
|
||||
--color-fill-warning-normal-resting: var(--color-orange-90);
|
||||
--color-fill-warning-normal-hover: var(--color-orange-80);
|
||||
--color-fill-warning-normal-active: var(--color-orange-90);
|
||||
|
||||
/* fill warning loud */
|
||||
--color-fill-warning-loud-resting: var(--color-orange-70);
|
||||
--color-fill-warning-loud-hover: var(--color-orange-50);
|
||||
--color-fill-warning-loud-active: var(--color-orange-70);
|
||||
|
||||
/* fill success quiet */
|
||||
--color-fill-success-quiet-resting: var(--color-green-95);
|
||||
--color-fill-success-quiet-hover: var(--color-green-90);
|
||||
--color-fill-success-quiet-active: var(--color-green-95);
|
||||
|
||||
/* fill success normal */
|
||||
--color-fill-success-normal-resting: var(--color-green-90);
|
||||
--color-fill-success-normal-hover: var(--color-green-80);
|
||||
--color-fill-success-normal-active: var(--color-green-90);
|
||||
|
||||
/* fill success loud */
|
||||
--color-fill-success-loud-resting: var(--color-green-50);
|
||||
--color-fill-success-loud-hover: var(--color-green-40);
|
||||
--color-fill-success-loud-active: var(--color-green-50);
|
||||
|
||||
/* fill purple quiet */
|
||||
--color-fill-purple-quiet-resting: var(--color-purple-95);
|
||||
--color-fill-purple-quiet-hover: var(--color-purple-90);
|
||||
--color-fill-purple-quiet-active: var(--color-purple-95);
|
||||
|
||||
/* fill purple normal */
|
||||
--color-fill-purple-normal-resting: var(--color-purple-90);
|
||||
--color-fill-purple-normal-hover: var(--color-purple-80);
|
||||
--color-fill-purple-normal-active: var(--color-purple-90);
|
||||
|
||||
/* fill purple loud */
|
||||
--color-fill-purple-loud-resting: var(--color-purple-50);
|
||||
--color-fill-purple-loud-hover: var(--color-purple-40);
|
||||
--color-fill-purple-loud-active: var(--color-purple-50);
|
||||
|
||||
/* on primary */
|
||||
--color-on-primary-quiet: var(--color-primary-50);
|
||||
--color-on-primary-normal: var(--color-primary-40);
|
||||
--color-on-primary-loud: var(--white);
|
||||
|
||||
/* on neutral */
|
||||
--color-on-neutral-quiet: var(--color-neutral-50);
|
||||
--color-on-neutral-normal: var(--color-neutral-40);
|
||||
--color-on-neutral-loud: var(--white);
|
||||
|
||||
/* on disabled */
|
||||
--color-on-disabled-quiet: var(--color-neutral-80);
|
||||
--color-on-disabled-normal: var(--color-neutral-70);
|
||||
--color-on-disabled-loud: var(--color-neutral-95);
|
||||
|
||||
/* on danger */
|
||||
--color-on-danger-quiet: var(--color-red-50);
|
||||
--color-on-danger-normal: var(--color-red-40);
|
||||
--color-on-danger-loud: var(--white);
|
||||
|
||||
/* on warning */
|
||||
--color-on-warning-quiet: var(--color-orange-50);
|
||||
--color-on-warning-normal: var(--color-orange-40);
|
||||
--color-on-warning-loud: var(--white);
|
||||
|
||||
/* on success */
|
||||
--color-on-success-quiet: var(--color-green-50);
|
||||
--color-on-success-normal: var(--color-green-40);
|
||||
--color-on-success-loud: var(--white);
|
||||
|
||||
/* on purple */
|
||||
--color-on-purple-quiet: var(--color-purple-30);
|
||||
--color-on-purple-normal: var(--color-purple-40);
|
||||
--color-on-purple-loud: var(--white);
|
||||
|
||||
/* logo */
|
||||
--color-logo-primary: var(--color-primary-50);
|
||||
}
|
||||
`;
|
||||
|
||||
export const darkSemanticColorStyles = css`
|
||||
html {
|
||||
/* surface */
|
||||
--color-surface-lower: var(--black);
|
||||
--color-surface-low: var(--color-neutral-05);
|
||||
--color-surface-default: var(--color-neutral-10);
|
||||
|
||||
/* text */
|
||||
--color-text-primary: var(--white);
|
||||
--color-text-secondary: var(--color-neutral-80);
|
||||
--color-text-link: var(--color-primary-60);
|
||||
|
||||
/* text purple */
|
||||
--color-text-purple-type: var(--white);
|
||||
--color-text-purple-property: var(--color-purple-60);
|
||||
--color-text-purple-target: var(--color-primary-60);
|
||||
|
||||
/* border primary */
|
||||
--color-border-normal: var(--color-primary-50);
|
||||
|
||||
/* border neutral */
|
||||
--color-border-neutral-quiet: var(--color-neutral-40);
|
||||
--color-border-neutral-normal: var(--color-neutral-50);
|
||||
--color-border-neutral-loud: var(--color-neutral-70);
|
||||
|
||||
/* border danger */
|
||||
--color-border-danger-normal: var(--color-red-50);
|
||||
--color-border-danger-loud: var(--color-red-50);
|
||||
|
||||
/* border warning */
|
||||
--color-border-warning-normal: var(--color-orange-50);
|
||||
--color-border-warning-loud: var(--color-orange-50);
|
||||
|
||||
/* border purple */
|
||||
--color-border-purple-normal: var(--color-purple-50);
|
||||
--color-border-purple-loud: var(--color-purple-50);
|
||||
|
||||
/* fill primary quiet */
|
||||
--color-fill-primary-quiet-resting: var(--color-primary-05);
|
||||
--color-fill-primary-quiet-hover: var(--color-primary-10);
|
||||
--color-fill-primary-quiet-active: var(--color-primary-05);
|
||||
|
||||
/* fill primary normal */
|
||||
--color-fill-primary-normal-resting: var(--color-primary-10);
|
||||
--color-fill-primary-normal-hover: var(--color-primary-20);
|
||||
--color-fill-primary-normal-active: var(--color-primary-10);
|
||||
|
||||
/* fill neutral quiet */
|
||||
--color-fill-neutral-quiet-resting: var(--color-neutral-05);
|
||||
--color-fill-neutral-quiet-hover: var(--color-neutral-10);
|
||||
--color-fill-neutral-quiet-active: var(--color-neutral-00);
|
||||
|
||||
/* fill neutral normal */
|
||||
--color-fill-neutral-normal-resting: var(--color-neutral-10);
|
||||
--color-fill-neutral-normal-hover: var(--color-neutral-20);
|
||||
--color-fill-neutral-normal-active: var(--color-neutral-10);
|
||||
|
||||
/* fill disabled quiet */
|
||||
--color-fill-disabled-quiet-resting: var(--color-neutral-10);
|
||||
|
||||
/* fill disabled normal */
|
||||
--color-fill-disabled-normal-resting: var(--color-neutral-20);
|
||||
|
||||
/* fill disabled loud */
|
||||
--color-fill-disabled-loud-resting: var(--color-neutral-30);
|
||||
|
||||
/* fill danger quiet */
|
||||
--color-fill-danger-quiet-resting: var(--color-red-05);
|
||||
--color-fill-danger-quiet-hover: var(--color-red-10);
|
||||
--color-fill-danger-quiet-active: var(--color-red-05);
|
||||
|
||||
/* fill danger normal */
|
||||
--color-fill-danger-normal-resting: var(--color-red-10);
|
||||
--color-fill-danger-normal-hover: var(--color-red-20);
|
||||
--color-fill-danger-normal-active: var(--color-red-10);
|
||||
|
||||
/* fill danger loud */
|
||||
--color-fill-danger-loud-resting: var(--color-red-40);
|
||||
--color-fill-danger-loud-hover: var(--color-red-30);
|
||||
--color-fill-danger-loud-active: var(--color-red-40);
|
||||
|
||||
/* fill warning quiet */
|
||||
--color-fill-warning-quiet-resting: var(--color-orange-05);
|
||||
--color-fill-warning-quiet-hover: var(--color-orange-10);
|
||||
--color-fill-warning-quiet-active: var(--color-orange-05);
|
||||
|
||||
/* fill warning normal */
|
||||
--color-fill-warning-normal-resting: var(--color-orange-10);
|
||||
--color-fill-warning-normal-hover: var(--color-orange-20);
|
||||
--color-fill-warning-normal-active: var(--color-orange-10);
|
||||
|
||||
/* fill warning loud */
|
||||
--color-fill-warning-loud-resting: var(--color-orange-40);
|
||||
--color-fill-warning-loud-hover: var(--color-orange-30);
|
||||
--color-fill-warning-loud-active: var(--color-orange-40);
|
||||
|
||||
/* fill success quiet */
|
||||
--color-fill-success-quiet-resting: var(--color-green-05);
|
||||
--color-fill-success-quiet-hover: var(--color-green-10);
|
||||
--color-fill-success-quiet-active: var(--color-green-05);
|
||||
|
||||
/* fill success normal */
|
||||
--color-fill-success-normal-resting: var(--color-green-10);
|
||||
--color-fill-success-normal-hover: var(--color-green-20);
|
||||
--color-fill-success-normal-active: var(--color-green-10);
|
||||
|
||||
/* fill success loud */
|
||||
--color-fill-success-loud-resting: var(--color-green-40);
|
||||
--color-fill-success-loud-hover: var(--color-green-30);
|
||||
--color-fill-success-loud-active: var(--color-green-40);
|
||||
|
||||
/* fill purple quiet */
|
||||
--color-fill-purple-quiet-resting: var(--color-purple-05);
|
||||
--color-fill-purple-quiet-hover: var(--color-purple-10);
|
||||
--color-fill-purple-quiet-active: var(--color-purple-05);
|
||||
|
||||
/* fill purple normal */
|
||||
--color-fill-purple-normal-resting: var(--color-purple-10);
|
||||
--color-fill-purple-normal-hover: var(--color-purple-20);
|
||||
--color-fill-purple-normal-active: var(--color-purple-10);
|
||||
|
||||
/* fill purple loud */
|
||||
--color-fill-purple-loud-resting: var(--color-purple-40);
|
||||
--color-fill-purple-loud-hover: var(--color-purple-30);
|
||||
--color-fill-purple-loud-active: var(--color-purple-40);
|
||||
|
||||
/* on primary */
|
||||
--color-on-primary-quiet: var(--color-primary-70);
|
||||
--color-on-primary-normal: var(--color-primary-80);
|
||||
|
||||
/* on neutral */
|
||||
--color-on-neutral-quiet: var(--color-neutral-70);
|
||||
--color-on-neutral-normal: var(--color-neutral-60);
|
||||
--color-on-neutral-loud: var(--white);
|
||||
|
||||
/* on disabled */
|
||||
--color-on-disabled-quiet: var(--color-neutral-40);
|
||||
--color-on-disabled-normal: var(--color-neutral-50);
|
||||
--color-on-disabled-loud: var(--color-neutral-50);
|
||||
|
||||
/* on danger */
|
||||
--color-on-danger-quiet: var(--color-red-70);
|
||||
--color-on-danger-normal: var(--color-red-60);
|
||||
--color-on-danger-loud: var(--white);
|
||||
|
||||
/* on warning */
|
||||
--color-on-warning-quiet: var(--color-orange-70);
|
||||
--color-on-warning-normal: var(--color-orange-60);
|
||||
--color-on-warning-loud: var(--white);
|
||||
|
||||
/* on success */
|
||||
--color-on-success-quiet: var(--color-green-70);
|
||||
--color-on-success-normal: var(--color-green-60);
|
||||
--color-on-success-loud: var(--white);
|
||||
|
||||
/* on purple */
|
||||
--color-on-purple-quiet: var(--color-purple-70);
|
||||
--color-on-purple-normal: var(--color-purple-60);
|
||||
--color-on-purple-loud: var(--white);
|
||||
}
|
||||
`;
|
@ -1,5 +1,5 @@
|
||||
import { fontStyles } from "../roboto";
|
||||
import { colorDerivedVariables, colorStyles } from "./color.globals";
|
||||
import { colorDerivedVariables, colorStylesCollection } from "./color";
|
||||
import { mainDerivedVariables, mainStyles } from "./main.globals";
|
||||
import {
|
||||
typographyDerivedVariables,
|
||||
@ -9,7 +9,7 @@ import {
|
||||
export const themeStyles = [
|
||||
mainStyles.toString(),
|
||||
typographyStyles.toString(),
|
||||
colorStyles.toString(),
|
||||
...colorStylesCollection,
|
||||
fontStyles.toString(),
|
||||
].join("");
|
||||
|
||||
|
@ -6541,7 +6541,8 @@
|
||||
},
|
||||
"need_base_enabled": "You need to enable basic analytics for this option to be available",
|
||||
"learn_more": "How we process your data",
|
||||
"intro": "Share anonymized information from your installation to help make Home Assistant better and help us convince manufacturers to add local control and privacy-focused features."
|
||||
"intro": "Share anonymized information from your installation to help make Home Assistant better and help us convince manufacturers to add local control and privacy-focused features.",
|
||||
"download_device_info": "Preview device analytics"
|
||||
},
|
||||
"network": {
|
||||
"caption": "Network",
|
||||
@ -7028,10 +7029,12 @@
|
||||
"top_margin": "Add additional space above",
|
||||
"top_margin_helper": "Helps reveal more of the background",
|
||||
"subview_helper": "Subviews don't appear in tabs and have a back button.",
|
||||
"path_helper": "This value will become part of the URL path to open this view.",
|
||||
"edit_ui": "Edit in visual editor",
|
||||
"edit_yaml": "Edit in YAML",
|
||||
"saving_failed": "Saving failed",
|
||||
"error_same_url": "You cannot save a view with the same URL as a different existing view.",
|
||||
"error_invalid_path": "URL contains invalid/reserved characters. Please enter a simple string only for the path of this view.",
|
||||
"move_to_dashboard": "Move to dashboard"
|
||||
},
|
||||
"edit_view_header": {
|
||||
@ -8849,7 +8852,7 @@
|
||||
"uploading": "[%key:ui::components::file-upload::uploading%]",
|
||||
"details": {
|
||||
"home_assistant_missing": "This backup does not include your Home Assistant configuration, you cannot use it to restore your instance.",
|
||||
"addons_unsupported": "Your installation method doesn’t support add-ons. If you wan’t to restore these, you have to install Home Assistant Operating System",
|
||||
"addons_unsupported": "Your installation method doesn’t support add-ons. If you want to restore these, you have to install Home Assistant Operating System",
|
||||
"summary": {
|
||||
"created": "[%key:ui::panel::config::backup::details::summary::created%]",
|
||||
"content": "Content"
|
||||
|
Loading…
x
Reference in New Issue
Block a user