mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-31 05:06:38 +00:00
Add color palettes (#26271)
This commit is contained in:
parent
641e406502
commit
3e67d91d1a
@ -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",
|
||||
@ -164,6 +165,7 @@
|
||||
"@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",
|
||||
|
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 - css 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["text-primary-color"] =
|
||||
|
@ -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;
|
||||
|
@ -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";
|
||||
@ -12,9 +12,9 @@ import "../../../components/buttons/ha-progress-button";
|
||||
import "../../../components/chart/ha-chart-base";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-md-list-item";
|
||||
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";
|
||||
@ -23,6 +23,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";
|
||||
@ -30,13 +31,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;
|
||||
|
||||
|
@ -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,26 +1,26 @@
|
||||
import "@material/mwc-button";
|
||||
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) {
|
||||
|
@ -3,6 +3,7 @@ import "@material/mwc-button/mwc-button";
|
||||
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";
|
||||
@ -14,7 +15,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";
|
||||
|
||||
@ -171,6 +172,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;
|
||||
--light-primary-color: #b3e5fc;
|
||||
--accent-color: #ff9800;
|
||||
@ -24,7 +24,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;
|
||||
@ -303,7 +303,7 @@ export const colorStyles = css`
|
||||
}
|
||||
`;
|
||||
|
||||
const darkColorStyles = css`
|
||||
export const darkColorStyles = css`
|
||||
html {
|
||||
--primary-background-color: #111111;
|
||||
--card-background-color: #1c1c1c;
|
||||
@ -359,9 +359,11 @@ const darkColorStyles = css`
|
||||
--disabled-color: #464646;
|
||||
}
|
||||
`;
|
||||
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");
|
77
src/resources/theme/color/core.globals.ts
Normal file
77
src/resources/theme/color/core.globals.ts
Normal file
@ -0,0 +1,77 @@
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
`;
|
||||
|
||||
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(),
|
||||
];
|
293
src/resources/theme/color/semantic.globals.ts
Normal file
293
src/resources/theme/color/semantic.globals.ts
Normal file
@ -0,0 +1,293 @@
|
||||
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);
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
`;
|
@ -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("");
|
||||
|
||||
|
16
yarn.lock
16
yarn.lock
@ -4474,6 +4474,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/culori@npm:4":
|
||||
version: 4.0.0
|
||||
resolution: "@types/culori@npm:4.0.0"
|
||||
checksum: 10/62a9058d6125fe489ca1e7df27ac9837ea7a34c772b8bed8e5e00177b141574830efaa0c93363e9532878490d3245a9c9c8183ebee181a450097584af0cfefc1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/deep-eql@npm:*":
|
||||
version: 4.0.2
|
||||
resolution: "@types/deep-eql@npm:4.0.2"
|
||||
@ -7040,6 +7047,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"culori@npm:4.0.2":
|
||||
version: 4.0.2
|
||||
resolution: "culori@npm:4.0.2"
|
||||
checksum: 10/9d297ca5c6fc86b2637200e1d9edb5a7d1015a2e978a6748781ef53c9577269ce1df96dc0925b0002239c85665ba881a3d580564dfd2807c65ee65dc2e829849
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"data-urls@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "data-urls@npm:5.0.0"
|
||||
@ -9388,6 +9402,7 @@ __metadata:
|
||||
"@types/chromecast-caf-receiver": "npm:6.0.22"
|
||||
"@types/chromecast-caf-sender": "npm:1.0.11"
|
||||
"@types/color-name": "npm:2.0.0"
|
||||
"@types/culori": "npm:4"
|
||||
"@types/html-minifier-terser": "npm:7.0.2"
|
||||
"@types/js-yaml": "npm:4.0.9"
|
||||
"@types/leaflet": "npm:1.9.20"
|
||||
@ -9417,6 +9432,7 @@ __metadata:
|
||||
comlink: "npm:4.4.2"
|
||||
core-js: "npm:3.44.0"
|
||||
cropperjs: "npm:1.6.2"
|
||||
culori: "npm:4.0.2"
|
||||
date-fns: "npm:4.1.0"
|
||||
date-fns-tz: "npm:3.2.0"
|
||||
deep-clone-simple: "npm:1.1.1"
|
||||
|
Loading…
x
Reference in New Issue
Block a user