mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
20221212.0 (#14722)
This commit is contained in:
commit
9f8aa0b4bf
@ -5,33 +5,39 @@
|
|||||||
"context": ".."
|
"context": ".."
|
||||||
},
|
},
|
||||||
"appPort": "8124:8123",
|
"appPort": "8124:8123",
|
||||||
"context": "..",
|
|
||||||
"postCreateCommand": "script/bootstrap",
|
"postCreateCommand": "script/bootstrap",
|
||||||
"extensions": [
|
|
||||||
"github.vscode-pull-request-github",
|
|
||||||
"dbaeumer.vscode-eslint",
|
|
||||||
"ms-vscode.vscode-typescript-tslint-plugin",
|
|
||||||
"esbenp.prettier-vscode",
|
|
||||||
"bierner.lit-html",
|
|
||||||
"runem.lit-plugin",
|
|
||||||
"ms-python.vscode-pylance"
|
|
||||||
],
|
|
||||||
"containerEnv": {
|
"containerEnv": {
|
||||||
"WORKSPACE_DIRECTORY": "${containerWorkspaceFolder}"
|
"WORKSPACE_DIRECTORY": "${containerWorkspaceFolder}"
|
||||||
},
|
},
|
||||||
"settings": {
|
"customizations": {
|
||||||
"terminal.integrated.shell.linux": "/bin/bash",
|
"vscode": {
|
||||||
"files.eol": "\n",
|
"extensions": [
|
||||||
"editor.tabSize": 2,
|
"dbaeumer.vscode-eslint",
|
||||||
"editor.formatOnPaste": false,
|
"esbenp.prettier-vscode",
|
||||||
"editor.formatOnSave": true,
|
"runem.lit-plugin",
|
||||||
"editor.formatOnType": true,
|
"github.vscode-pull-request-github",
|
||||||
"[typescript]": {
|
"eamodio.gitlens"
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
],
|
||||||
},
|
"settings": {
|
||||||
"[javascript]": {
|
"files.eol": "\n",
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
"editor.tabSize": 2,
|
||||||
},
|
"editor.formatOnPaste": false,
|
||||||
"files.trimTrailingWhitespace": true
|
"editor.formatOnSave": true,
|
||||||
|
"editor.formatOnType": true,
|
||||||
|
"editor.renderWhitespace": "boundary",
|
||||||
|
"editor.rulers": [80],
|
||||||
|
"[typescript]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"[javascript]": {
|
||||||
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
|
},
|
||||||
|
"files.trimTrailingWhitespace": true,
|
||||||
|
"terminal.integrated.shell.linux": "/usr/bin/zsh",
|
||||||
|
"gitlens.showWelcomeOnInstall": false,
|
||||||
|
"gitlens.showWhatsNewAfterUpgrades": false,
|
||||||
|
"workbench.startupEditor": "none"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
90
.github/workflows/cast_deployment.yaml
vendored
Normal file
90
.github/workflows/cast_deployment.yaml
vendored
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
name: Cast deployment
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
env:
|
||||||
|
NODE_VERSION: 16
|
||||||
|
NODE_OPTIONS: --max_old_space_size=6144
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy_dev:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Deploy Development
|
||||||
|
if: github.event_name != 'push'
|
||||||
|
environment:
|
||||||
|
name: Cast Development
|
||||||
|
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
||||||
|
steps:
|
||||||
|
- name: Check out files from GitHub
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: dev
|
||||||
|
|
||||||
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
|
cache: yarn
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: yarn install
|
||||||
|
env:
|
||||||
|
CI: true
|
||||||
|
|
||||||
|
- name: Build Cast
|
||||||
|
run: ./node_modules/.bin/gulp build-cast
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Deploy to Netlify
|
||||||
|
id: deploy
|
||||||
|
uses: netlify/actions/cli@master
|
||||||
|
with:
|
||||||
|
args: deploy --dir=cast/dist --alias dev
|
||||||
|
env:
|
||||||
|
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||||
|
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_CAST_SITE_ID }}
|
||||||
|
|
||||||
|
deploy_master:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Deploy Production
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
environment:
|
||||||
|
name: Cast Production
|
||||||
|
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
||||||
|
steps:
|
||||||
|
- name: Check out files from GitHub
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
ref: master
|
||||||
|
|
||||||
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
|
cache: yarn
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: yarn install
|
||||||
|
env:
|
||||||
|
CI: true
|
||||||
|
|
||||||
|
- name: Build Cast
|
||||||
|
run: ./node_modules/.bin/gulp build-cast
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Deploy to Netlify
|
||||||
|
id: deploy
|
||||||
|
uses: netlify/actions/cli@master
|
||||||
|
with:
|
||||||
|
args: deploy --dir=cast/dist --prod
|
||||||
|
env:
|
||||||
|
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||||
|
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_CAST_SITE_ID }}
|
@ -1,6 +1,9 @@
|
|||||||
name: Demo
|
name: Demo deployment
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- dev
|
- dev
|
||||||
@ -12,24 +15,34 @@ env:
|
|||||||
jobs:
|
jobs:
|
||||||
deploy:
|
deploy:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
environment:
|
||||||
|
name: Demo
|
||||||
|
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Set up Node ${{ env.NODE_VERSION }}
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: yarn
|
cache: yarn
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: yarn install
|
run: yarn install
|
||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
|
|
||||||
- name: Build Demo
|
- name: Build Demo
|
||||||
run: ./node_modules/.bin/gulp build-demo
|
run: ./node_modules/.bin/gulp build-demo
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Deploy to Netlify
|
- name: Deploy to Netlify
|
||||||
run: npx netlify-cli deploy --dir=demo/dist --prod
|
id: deploy
|
||||||
|
uses: netlify/actions/cli@master
|
||||||
|
with:
|
||||||
|
args: deploy --dir=demo/dist --prod
|
||||||
env:
|
env:
|
||||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_DEMO_DEV_SITE_ID }}
|
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_DEMO_DEV_SITE_ID }}
|
45
.github/workflows/design_deployment.yaml
vendored
Normal file
45
.github/workflows/design_deployment.yaml
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
name: Design deployment
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 0 * * *"
|
||||||
|
|
||||||
|
env:
|
||||||
|
NODE_VERSION: 16
|
||||||
|
NODE_OPTIONS: --max_old_space_size=6144
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
environment:
|
||||||
|
name: Design
|
||||||
|
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL }}
|
||||||
|
steps:
|
||||||
|
- name: Check out files from GitHub
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
|
cache: yarn
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: yarn install
|
||||||
|
env:
|
||||||
|
CI: true
|
||||||
|
|
||||||
|
- name: Build Gallery
|
||||||
|
run: ./node_modules/.bin/gulp build-gallery
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Deploy to Netlify
|
||||||
|
id: deploy
|
||||||
|
uses: netlify/actions/cli@master
|
||||||
|
with:
|
||||||
|
args: deploy --dir=gallery/dist --prod
|
||||||
|
env:
|
||||||
|
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||||
|
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_GALLERY_SITE_ID }}
|
19
.github/workflows/netflify.yml
vendored
19
.github/workflows/netflify.yml
vendored
@ -1,19 +0,0 @@
|
|||||||
name: Netlify
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "0 0 * * *"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
trigger_builds:
|
|
||||||
name: Trigger netlify build preview
|
|
||||||
runs-on: "ubuntu-latest"
|
|
||||||
steps:
|
|
||||||
- name: Trigger Cast build
|
|
||||||
run: curl -X POST -d {} https://api.netlify.com/build_hooks/${{ secrets.NETLIFY_CAST_DEV_BUILD_HOOK }}
|
|
||||||
|
|
||||||
- name: Trigger Demo build
|
|
||||||
run: curl -X POST -d {} https://api.netlify.com/build_hooks/${{ secrets.NETLIFY_DEMO_DEV_BUILD_HOOK }}
|
|
||||||
|
|
||||||
- name: Trigger Design build
|
|
||||||
run: curl -X POST -d "NIGHTLY" https://api.netlify.com/build_hooks/${{ secrets.NETLIFY_GALLERY_DEV_BUILD_HOOK }}
|
|
5
.vscode/extensions.json
vendored
5
.vscode/extensions.json
vendored
@ -2,7 +2,8 @@
|
|||||||
"recommendations": [
|
"recommendations": [
|
||||||
"dbaeumer.vscode-eslint",
|
"dbaeumer.vscode-eslint",
|
||||||
"esbenp.prettier-vscode",
|
"esbenp.prettier-vscode",
|
||||||
"bierner.lit-html",
|
"runem.lit-plugin",
|
||||||
"runem.lit-plugin"
|
"github.vscode-pull-request-github",
|
||||||
|
"eamodio.gitlens"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
TARGET_LABEL="needs design preview"
|
TARGET_LABEL="needs design preview"
|
||||||
|
export SKIP_FETCH_NIGHTLY_TRANSLATIONS="true"
|
||||||
|
|
||||||
if [[ "$NETLIFY" != "true" ]]; then
|
if [[ "$NETLIFY" != "true" ]]; then
|
||||||
echo "This script can only be run on Netlify"
|
echo "This script can only be run on Netlify"
|
||||||
@ -30,6 +31,4 @@ if [[ "${PULL_REQUEST}" == "true" ]]; then
|
|||||||
else
|
else
|
||||||
createStatus "success" "Build was not requested by PR label"
|
createStatus "success" "Build was not requested by PR label"
|
||||||
fi
|
fi
|
||||||
elif [[ "$INCOMING_HOOK_BODY" == "NIGHTLY" ]]; then
|
|
||||||
gulp build-gallery
|
|
||||||
fi
|
fi
|
||||||
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "home-assistant-frontend"
|
name = "home-assistant-frontend"
|
||||||
version = "20221208.0"
|
version = "20221212.0"
|
||||||
license = {text = "Apache-2.0"}
|
license = {text = "Apache-2.0"}
|
||||||
description = "The Home Assistant frontend"
|
description = "The Home Assistant frontend"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
@ -52,7 +52,9 @@ import {
|
|||||||
mdiScriptText,
|
mdiScriptText,
|
||||||
mdiSineWave,
|
mdiSineWave,
|
||||||
mdiSpeedometer,
|
mdiSpeedometer,
|
||||||
|
mdiSunWireless,
|
||||||
mdiThermometer,
|
mdiThermometer,
|
||||||
|
mdiThermometerLines,
|
||||||
mdiThermostat,
|
mdiThermostat,
|
||||||
mdiTimerOutline,
|
mdiTimerOutline,
|
||||||
mdiVideo,
|
mdiVideo,
|
||||||
@ -126,6 +128,7 @@ export const FIXED_DOMAIN_ICONS = {
|
|||||||
export const FIXED_DEVICE_CLASS_ICONS = {
|
export const FIXED_DEVICE_CLASS_ICONS = {
|
||||||
apparent_power: mdiFlash,
|
apparent_power: mdiFlash,
|
||||||
aqi: mdiAirFilter,
|
aqi: mdiAirFilter,
|
||||||
|
atmospheric_pressure: mdiThermometerLines,
|
||||||
// battery: mdiBattery, => not included by design since `sensorIcon()` will dynamically determine the icon
|
// battery: mdiBattery, => not included by design since `sensorIcon()` will dynamically determine the icon
|
||||||
carbon_dioxide: mdiMoleculeCo2,
|
carbon_dioxide: mdiMoleculeCo2,
|
||||||
carbon_monoxide: mdiMoleculeCo,
|
carbon_monoxide: mdiMoleculeCo,
|
||||||
@ -138,6 +141,7 @@ export const FIXED_DEVICE_CLASS_ICONS = {
|
|||||||
gas: mdiMeterGas,
|
gas: mdiMeterGas,
|
||||||
humidity: mdiWaterPercent,
|
humidity: mdiWaterPercent,
|
||||||
illuminance: mdiBrightness5,
|
illuminance: mdiBrightness5,
|
||||||
|
irradiance: mdiSunWireless,
|
||||||
moisture: mdiWaterPercent,
|
moisture: mdiWaterPercent,
|
||||||
monetary: mdiCash,
|
monetary: mdiCash,
|
||||||
nitrogen_dioxide: mdiMolecule,
|
nitrogen_dioxide: mdiMolecule,
|
||||||
|
@ -13,6 +13,8 @@ export const alarmControlPanelColor = (state?: string): string | undefined => {
|
|||||||
return "alarm-arming";
|
return "alarm-arming";
|
||||||
case "triggered":
|
case "triggered":
|
||||||
return "alarm-triggered";
|
return "alarm-triggered";
|
||||||
|
case "disarmed":
|
||||||
|
return "alarm-disarmed";
|
||||||
default:
|
default:
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
export const lockColor = (state?: string): string | undefined => {
|
export const lockColor = (state?: string): string | undefined => {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
|
case "unlocked":
|
||||||
|
return "lock-unlocked";
|
||||||
case "locked":
|
case "locked":
|
||||||
return "lock-locked";
|
return "lock-locked";
|
||||||
case "jammed":
|
case "jammed":
|
||||||
|
@ -2,6 +2,8 @@ export const personColor = (state: string): string | undefined => {
|
|||||||
switch (state) {
|
switch (state) {
|
||||||
case "home":
|
case "home":
|
||||||
return "person-home";
|
return "person-home";
|
||||||
|
case "not_home":
|
||||||
|
return "person-not-home";
|
||||||
default:
|
default:
|
||||||
return "person-zone";
|
return "person-zone";
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,12 @@ import { batteryStateColor } from "./battery_color";
|
|||||||
|
|
||||||
export const sensorColor = (
|
export const sensorColor = (
|
||||||
stateObj: HassEntity,
|
stateObj: HassEntity,
|
||||||
compareState: string
|
state: string
|
||||||
): string | undefined => {
|
): string | undefined => {
|
||||||
const deviceClass = stateObj?.attributes.device_class;
|
const deviceClass = stateObj?.attributes.device_class;
|
||||||
|
|
||||||
if (deviceClass === "battery") {
|
if (deviceClass === "battery") {
|
||||||
return batteryStateColor(compareState);
|
return batteryStateColor(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
|
@ -16,15 +16,15 @@ export function stateActive(stateObj: HassEntity, state?: string): boolean {
|
|||||||
|
|
||||||
// Custom cases
|
// Custom cases
|
||||||
switch (domain) {
|
switch (domain) {
|
||||||
|
case "alarm_control_panel":
|
||||||
|
return compareState !== "disarmed";
|
||||||
case "cover":
|
case "cover":
|
||||||
return !["closed", "closing"].includes(compareState);
|
return !["closed", "closing"].includes(compareState);
|
||||||
case "device_tracker":
|
case "device_tracker":
|
||||||
case "person":
|
case "person":
|
||||||
return compareState !== "not_home";
|
return compareState !== "not_home";
|
||||||
case "alarm_control_panel":
|
|
||||||
return compareState !== "disarmed";
|
|
||||||
case "lock":
|
case "lock":
|
||||||
return compareState !== "unlocked";
|
return compareState !== "locked";
|
||||||
case "media_player":
|
case "media_player":
|
||||||
return compareState !== "standby";
|
return compareState !== "standby";
|
||||||
case "vacuum":
|
case "vacuum":
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/** Return an color representing a state. */
|
/** Return an color representing a state. */
|
||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
|
import { UNAVAILABLE } from "../../data/entity";
|
||||||
import { UpdateEntity, updateIsInstalling } from "../../data/update";
|
import { UpdateEntity, updateIsInstalling } from "../../data/update";
|
||||||
import { alarmControlPanelColor } from "./color/alarm_control_panel_color";
|
import { alarmControlPanelColor } from "./color/alarm_control_panel_color";
|
||||||
import { binarySensorColor } from "./color/binary_sensor_color";
|
import { binarySensorColor } from "./color/binary_sensor_color";
|
||||||
@ -10,7 +11,7 @@ import { sensorColor } from "./color/sensor_color";
|
|||||||
import { computeDomain } from "./compute_domain";
|
import { computeDomain } from "./compute_domain";
|
||||||
import { stateActive } from "./state_active";
|
import { stateActive } from "./state_active";
|
||||||
|
|
||||||
const STATIC_COLORED_DOMAIN = new Set([
|
const STATIC_ACTIVE_COLORED_DOMAIN = new Set([
|
||||||
"alert",
|
"alert",
|
||||||
"automation",
|
"automation",
|
||||||
"calendar",
|
"calendar",
|
||||||
@ -30,25 +31,33 @@ const STATIC_COLORED_DOMAIN = new Set([
|
|||||||
"vacuum",
|
"vacuum",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const stateColorCss = (stateObj?: HassEntity, state?: string) => {
|
export const stateColorCss = (stateObj: HassEntity, state?: string) => {
|
||||||
if (!stateObj || !stateActive(stateObj, state)) {
|
const compareState = state !== undefined ? state : stateObj?.state;
|
||||||
return `var(--rgb-disabled-color)`;
|
if (compareState === UNAVAILABLE) {
|
||||||
|
return `var(--rgb-state-unavailable-color)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const color = stateColor(stateObj, state);
|
const domainColor = stateColor(stateObj, state);
|
||||||
|
|
||||||
if (color) {
|
if (domainColor) {
|
||||||
return `var(--rgb-state-${color}-color)`;
|
return `var(--rgb-state-${domainColor}-color)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return `var(--rgb-state-default-color)`;
|
if (!stateActive(stateObj, state)) {
|
||||||
|
return `var(--rgb-state-inactive-color)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const stateColor = (stateObj: HassEntity, state?: string) => {
|
export const stateColor = (stateObj: HassEntity, state?: string) => {
|
||||||
const compareState = state !== undefined ? state : stateObj?.state;
|
const compareState = state !== undefined ? state : stateObj?.state;
|
||||||
const domain = computeDomain(stateObj.entity_id);
|
const domain = computeDomain(stateObj.entity_id);
|
||||||
|
|
||||||
if (STATIC_COLORED_DOMAIN.has(domain)) {
|
if (
|
||||||
|
STATIC_ACTIVE_COLORED_DOMAIN.has(domain) &&
|
||||||
|
stateActive(stateObj, state)
|
||||||
|
) {
|
||||||
return domain.replace("_", "-");
|
return domain.replace("_", "-");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,6 @@ export const iconColorCSS = css`
|
|||||||
|
|
||||||
/* Color the icon if unavailable */
|
/* Color the icon if unavailable */
|
||||||
ha-state-icon[data-state="unavailable"] {
|
ha-state-icon[data-state="unavailable"] {
|
||||||
color: var(--state-unavailable-color);
|
color: rgb(var(--rgb-state-unavailable-color));
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -37,8 +37,11 @@ export class TextBarElement extends BarElement {
|
|||||||
}
|
}
|
||||||
const textColor =
|
const textColor =
|
||||||
options.textColor ||
|
options.textColor ||
|
||||||
(options.backgroundColor &&
|
(options?.backgroundColor === "transparent"
|
||||||
(luminosity(hex2rgb(options.backgroundColor)) > 0.5 ? "#000" : "#fff"));
|
? "transparent"
|
||||||
|
: luminosity(hex2rgb(options.backgroundColor)) > 0.5
|
||||||
|
? "#000"
|
||||||
|
: "#fff");
|
||||||
|
|
||||||
// ctx.font = "12px arial";
|
// ctx.font = "12px arial";
|
||||||
ctx.fillStyle = textColor;
|
ctx.fillStyle = textColor;
|
||||||
|
@ -5,6 +5,7 @@ import { labBrighten } from "../../../common/color/lab";
|
|||||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||||
import { stateActive } from "../../../common/entity/state_active";
|
import { stateActive } from "../../../common/entity/state_active";
|
||||||
import { stateColor } from "../../../common/entity/state_color";
|
import { stateColor } from "../../../common/entity/state_color";
|
||||||
|
import { UNAVAILABLE } from "../../../data/entity";
|
||||||
|
|
||||||
const DOMAIN_STATE_SHADES: Record<string, Record<string, number>> = {
|
const DOMAIN_STATE_SHADES: Record<string, Record<string, number>> = {
|
||||||
media_player: {
|
media_player: {
|
||||||
@ -49,21 +50,23 @@ function computeTimelineStateColor(
|
|||||||
computedStyles: CSSStyleDeclaration,
|
computedStyles: CSSStyleDeclaration,
|
||||||
stateObj?: HassEntity
|
stateObj?: HassEntity
|
||||||
): string | undefined {
|
): string | undefined {
|
||||||
if (!stateObj || !stateActive(stateObj, state)) {
|
if (!stateObj || state === UNAVAILABLE) {
|
||||||
const rgb = cssToRgb("--rgb-disabled-color", computedStyles);
|
return "transparent";
|
||||||
|
}
|
||||||
|
|
||||||
|
const color = stateColor(stateObj, state);
|
||||||
|
|
||||||
|
if (!color && !stateActive(stateObj, state)) {
|
||||||
|
const rgb = cssToRgb("--rgb-state-inactive-color", computedStyles);
|
||||||
if (!rgb) return undefined;
|
if (!rgb) return undefined;
|
||||||
return rgb2hex(rgb);
|
return rgb2hex(rgb);
|
||||||
}
|
}
|
||||||
const color = stateColor(stateObj, state);
|
|
||||||
|
|
||||||
if (!color) return undefined;
|
|
||||||
|
|
||||||
const domain = computeDomain(stateObj.entity_id);
|
|
||||||
|
|
||||||
const rgb = cssToRgb(`--rgb-state-${color}-color`, computedStyles);
|
const rgb = cssToRgb(`--rgb-state-${color}-color`, computedStyles);
|
||||||
|
|
||||||
if (!rgb) return undefined;
|
if (!rgb) return undefined;
|
||||||
|
|
||||||
|
const domain = computeDomain(stateObj.entity_id);
|
||||||
const shade = DOMAIN_STATE_SHADES[domain]?.[state] as number | number;
|
const shade = DOMAIN_STATE_SHADES[domain]?.[state] as number | number;
|
||||||
if (!shade) {
|
if (!shade) {
|
||||||
return rgb2hex(rgb);
|
return rgb2hex(rgb);
|
||||||
|
@ -14,7 +14,7 @@ import { styleMap } from "lit/directives/style-map";
|
|||||||
import { computeDomain } from "../../common/entity/compute_domain";
|
import { computeDomain } from "../../common/entity/compute_domain";
|
||||||
import { computeStateDomain } from "../../common/entity/compute_state_domain";
|
import { computeStateDomain } from "../../common/entity/compute_state_domain";
|
||||||
import { stateActive } from "../../common/entity/state_active";
|
import { stateActive } from "../../common/entity/state_active";
|
||||||
import { stateColor } from "../../common/entity/state_color";
|
import { stateColorCss } from "../../common/entity/state_color";
|
||||||
import { iconColorCSS } from "../../common/style/icon_color_css";
|
import { iconColorCSS } from "../../common/style/icon_color_css";
|
||||||
import { cameraUrlWithWidthHeight } from "../../data/camera";
|
import { cameraUrlWithWidthHeight } from "../../data/camera";
|
||||||
import type { HomeAssistant } from "../../types";
|
import type { HomeAssistant } from "../../types";
|
||||||
@ -107,12 +107,13 @@ export class StateBadge extends LitElement {
|
|||||||
}
|
}
|
||||||
hostStyle.backgroundImage = `url(${imageUrl})`;
|
hostStyle.backgroundImage = `url(${imageUrl})`;
|
||||||
this._showIcon = false;
|
this._showIcon = false;
|
||||||
} else if (stateActive(stateObj) && this._stateColor) {
|
} else if (this._stateColor && stateActive(stateObj)) {
|
||||||
const iconColor = stateColor(stateObj);
|
const color = stateColorCss(stateObj);
|
||||||
|
if (color) {
|
||||||
|
iconStyle.color = `rgb(${color})`;
|
||||||
|
}
|
||||||
if (stateObj.attributes.rgb_color) {
|
if (stateObj.attributes.rgb_color) {
|
||||||
iconStyle.color = `rgb(${stateObj.attributes.rgb_color.join(",")})`;
|
iconStyle.color = `rgb(${stateObj.attributes.rgb_color.join(",")})`;
|
||||||
} else if (iconColor) {
|
|
||||||
iconStyle.color = `rgb(var(--rgb-state-${iconColor}-color))`;
|
|
||||||
}
|
}
|
||||||
if (stateObj.attributes.brightness) {
|
if (stateObj.attributes.brightness) {
|
||||||
const brightness = stateObj.attributes.brightness;
|
const brightness = stateObj.attributes.brightness;
|
||||||
|
@ -31,7 +31,7 @@ export interface HaFormBaseSchema {
|
|||||||
|
|
||||||
export interface HaFormGridSchema extends HaFormBaseSchema {
|
export interface HaFormGridSchema extends HaFormBaseSchema {
|
||||||
type: "grid";
|
type: "grid";
|
||||||
name: "";
|
name: string;
|
||||||
column_min_width?: string;
|
column_min_width?: string;
|
||||||
schema: readonly HaFormSchema[];
|
schema: readonly HaFormSchema[];
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,6 @@ const defaultFullCalendarConfig: CalendarOptions = {
|
|||||||
initialView: "dayGridMonth",
|
initialView: "dayGridMonth",
|
||||||
dayMaxEventRows: true,
|
dayMaxEventRows: true,
|
||||||
height: "parent",
|
height: "parent",
|
||||||
eventDisplay: "list-item",
|
|
||||||
locales: allLocales,
|
locales: allLocales,
|
||||||
views: {
|
views: {
|
||||||
listWeek: {
|
listWeek: {
|
||||||
@ -97,6 +96,8 @@ export class HAFullCalendar extends LitElement {
|
|||||||
|
|
||||||
@property() public initialView: FullCalendarView = "dayGridMonth";
|
@property() public initialView: FullCalendarView = "dayGridMonth";
|
||||||
|
|
||||||
|
@property() public eventDisplay = "auto";
|
||||||
|
|
||||||
@property({ attribute: false }) public error?: string = undefined;
|
@property({ attribute: false }) public error?: string = undefined;
|
||||||
|
|
||||||
private calendar?: Calendar;
|
private calendar?: Calendar;
|
||||||
@ -233,6 +234,10 @@ export class HAFullCalendar extends LitElement {
|
|||||||
this._fireViewChanged();
|
this._fireViewChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (changedProps.has("eventDisplay")) {
|
||||||
|
this.calendar!.setOption("eventDisplay", this.eventDisplay);
|
||||||
|
}
|
||||||
|
|
||||||
const oldHass = changedProps.get("hass") as HomeAssistant;
|
const oldHass = changedProps.get("hass") as HomeAssistant;
|
||||||
|
|
||||||
if (oldHass && oldHass.language !== this.hass.language) {
|
if (oldHass && oldHass.language !== this.hass.language) {
|
||||||
@ -246,6 +251,7 @@ export class HAFullCalendar extends LitElement {
|
|||||||
locale: this.hass.language,
|
locale: this.hass.language,
|
||||||
firstDay: firstWeekdayIndex(this.hass.locale),
|
firstDay: firstWeekdayIndex(this.hass.locale),
|
||||||
initialView: this.initialView,
|
initialView: this.initialView,
|
||||||
|
eventDisplay: this.eventDisplay,
|
||||||
eventTimeFormat: {
|
eventTimeFormat: {
|
||||||
hour: useAmPm(this.hass.locale) ? "numeric" : "2-digit",
|
hour: useAmPm(this.hass.locale) ? "numeric" : "2-digit",
|
||||||
minute: useAmPm(this.hass.locale) ? "numeric" : "2-digit",
|
minute: useAmPm(this.hass.locale) ? "numeric" : "2-digit",
|
||||||
@ -320,6 +326,7 @@ export class HAFullCalendar extends LitElement {
|
|||||||
this._activeView = "dayGridDay";
|
this._activeView = "dayGridDay";
|
||||||
this.calendar!.changeView("dayGridDay");
|
this.calendar!.changeView("dayGridDay");
|
||||||
this.calendar!.gotoDate(info.dateStr);
|
this.calendar!.gotoDate(info.dateStr);
|
||||||
|
this._fireViewChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleNext(): void {
|
private _handleNext(): void {
|
||||||
@ -537,6 +544,7 @@ export class HAFullCalendar extends LitElement {
|
|||||||
a.fc-daygrid-day-number {
|
a.fc-daygrid-day-number {
|
||||||
float: none !important;
|
float: none !important;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc .fc-daygrid-day-number {
|
.fc .fc-daygrid-day-number {
|
||||||
@ -547,12 +555,8 @@ export class HAFullCalendar extends LitElement {
|
|||||||
background: inherit;
|
background: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
td.fc-day-today .fc-daygrid-day-top {
|
|
||||||
padding-top: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
td.fc-day-today .fc-daygrid-day-number {
|
td.fc-day-today .fc-daygrid-day-number {
|
||||||
height: 24px;
|
height: 26px;
|
||||||
color: var(--text-primary-color) !important;
|
color: var(--text-primary-color) !important;
|
||||||
background-color: var(--primary-color);
|
background-color: var(--primary-color);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
@ -561,7 +565,6 @@ export class HAFullCalendar extends LitElement {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
width: max-content;
|
width: max-content;
|
||||||
min-width: 24px;
|
min-width: 24px;
|
||||||
line-height: 140%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc-daygrid-day-events {
|
.fc-daygrid-day-events {
|
||||||
@ -571,6 +574,7 @@ export class HAFullCalendar extends LitElement {
|
|||||||
.fc-event {
|
.fc-event {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
line-height: 1.7;
|
line-height: 1.7;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc-daygrid-block-event .fc-event-main {
|
.fc-daygrid-block-event .fc-event-main {
|
||||||
|
@ -3,6 +3,7 @@ import { customElement, property, state } from "lit/decorators";
|
|||||||
import { canShowPage } from "../../../common/config/can_show_page";
|
import { canShowPage } from "../../../common/config/can_show_page";
|
||||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||||
import { relativeTime } from "../../../common/datetime/relative_time";
|
import { relativeTime } from "../../../common/datetime/relative_time";
|
||||||
|
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import "../../../components/ha-navigation-list";
|
import "../../../components/ha-navigation-list";
|
||||||
import "../../../components/ha-tip";
|
import "../../../components/ha-tip";
|
||||||
@ -84,7 +85,7 @@ class HaConfigSystemNavigation extends LitElement {
|
|||||||
"percent_used",
|
"percent_used",
|
||||||
`${Math.round(
|
`${Math.round(
|
||||||
(this._storageInfo.used / this._storageInfo.total) * 100
|
(this._storageInfo.used / this._storageInfo.total) * 100
|
||||||
)}%`,
|
)}${blankBeforePercent(this.hass.locale)}%`,
|
||||||
"free_space",
|
"free_space",
|
||||||
`${this._storageInfo.free} GB`
|
`${this._storageInfo.free} GB`
|
||||||
)
|
)
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import {
|
import {
|
||||||
mdiCog,
|
mdiCog,
|
||||||
mdiDelete,
|
mdiDelete,
|
||||||
@ -7,18 +8,19 @@ import {
|
|||||||
mdiPencil,
|
mdiPencil,
|
||||||
mdiPlusCircle,
|
mdiPlusCircle,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
import "@material/mwc-list/mwc-list-item";
|
|
||||||
import "@polymer/paper-tooltip/paper-tooltip";
|
import "@polymer/paper-tooltip/paper-tooltip";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { ifDefined } from "lit/directives/if-defined";
|
import { ifDefined } from "lit/directives/if-defined";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||||
|
import { SENSOR_ENTITIES } from "../../../common/const";
|
||||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
import { stringCompare } from "../../../common/string/compare";
|
import { stringCompare } from "../../../common/string/compare";
|
||||||
import { slugify } from "../../../common/string/slugify";
|
import { slugify } from "../../../common/string/slugify";
|
||||||
|
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
|
||||||
import { groupBy } from "../../../common/util/group-by";
|
import { groupBy } from "../../../common/util/group-by";
|
||||||
import "../../../components/entity/ha-battery-icon";
|
import "../../../components/entity/ha-battery-icon";
|
||||||
import "../../../components/ha-alert";
|
import "../../../components/ha-alert";
|
||||||
@ -59,6 +61,7 @@ import {
|
|||||||
showConfirmationDialog,
|
showConfirmationDialog,
|
||||||
} from "../../../dialogs/generic/show-dialog-box";
|
} from "../../../dialogs/generic/show-dialog-box";
|
||||||
import "../../../layouts/hass-error-screen";
|
import "../../../layouts/hass-error-screen";
|
||||||
|
import "../../../layouts/hass-subpage";
|
||||||
import "../../../layouts/hass-tabs-subpage";
|
import "../../../layouts/hass-tabs-subpage";
|
||||||
import { haStyle } from "../../../resources/styles";
|
import { haStyle } from "../../../resources/styles";
|
||||||
import type { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
@ -74,8 +77,6 @@ import {
|
|||||||
loadDeviceRegistryDetailDialog,
|
loadDeviceRegistryDetailDialog,
|
||||||
showDeviceRegistryDetailDialog,
|
showDeviceRegistryDetailDialog,
|
||||||
} from "./device-registry-detail/show-dialog-device-registry-detail";
|
} from "./device-registry-detail/show-dialog-device-registry-detail";
|
||||||
import "../../../layouts/hass-subpage";
|
|
||||||
import { SENSOR_ENTITIES } from "../../../common/const";
|
|
||||||
|
|
||||||
export interface EntityRegistryStateEntry extends EntityRegistryEntry {
|
export interface EntityRegistryStateEntry extends EntityRegistryEntry {
|
||||||
stateName?: string | null;
|
stateName?: string | null;
|
||||||
@ -639,7 +640,11 @@ export class HaConfigDevicePage extends LitElement {
|
|||||||
batteryState
|
batteryState
|
||||||
? html`
|
? html`
|
||||||
<div class="battery">
|
<div class="battery">
|
||||||
${batteryIsBinary ? "" : batteryState.state + " %"}
|
${batteryIsBinary
|
||||||
|
? ""
|
||||||
|
: batteryState.state +
|
||||||
|
blankBeforePercent(this.hass.locale) +
|
||||||
|
"%"}
|
||||||
<ha-battery-icon
|
<ha-battery-icon
|
||||||
.hass=${this.hass!}
|
.hass=${this.hass!}
|
||||||
.batteryStateObj=${batteryState}
|
.batteryStateObj=${batteryState}
|
||||||
|
@ -7,6 +7,7 @@ import memoizeOne from "memoize-one";
|
|||||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||||
import { navigate } from "../../../common/navigate";
|
import { navigate } from "../../../common/navigate";
|
||||||
|
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
|
||||||
import { LocalizeFunc } from "../../../common/translations/localize";
|
import { LocalizeFunc } from "../../../common/translations/localize";
|
||||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||||
import {
|
import {
|
||||||
@ -339,7 +340,9 @@ export class HaConfigDeviceDashboard extends LitElement {
|
|||||||
battery && computeStateDomain(battery) === "binary_sensor";
|
battery && computeStateDomain(battery) === "binary_sensor";
|
||||||
return battery && (batteryIsBinary || !isNaN(battery.state as any))
|
return battery && (batteryIsBinary || !isNaN(battery.state as any))
|
||||||
? html`
|
? html`
|
||||||
${batteryIsBinary ? "" : battery.state + " %"}
|
${batteryIsBinary
|
||||||
|
? ""
|
||||||
|
: battery.state + blankBeforePercent(this.hass.locale) + "%"}
|
||||||
<ha-battery-icon
|
<ha-battery-icon
|
||||||
.hass=${this.hass!}
|
.hass=${this.hass!}
|
||||||
.batteryStateObj=${battery}
|
.batteryStateObj=${battery}
|
||||||
|
@ -9,6 +9,7 @@ import { ifDefined } from "lit/directives/if-defined";
|
|||||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||||
import { numberFormatToLocale } from "../../../common/number/format_number";
|
import { numberFormatToLocale } from "../../../common/number/format_number";
|
||||||
import { round } from "../../../common/number/round";
|
import { round } from "../../../common/number/round";
|
||||||
|
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
|
||||||
import "../../../components/buttons/ha-progress-button";
|
import "../../../components/buttons/ha-progress-button";
|
||||||
import "../../../components/chart/ha-chart-base";
|
import "../../../components/chart/ha-chart-base";
|
||||||
import "../../../components/ha-alert";
|
import "../../../components/ha-alert";
|
||||||
@ -169,7 +170,8 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
|
|||||||
max: 100,
|
max: 100,
|
||||||
min: 0,
|
min: 0,
|
||||||
stepSize: 1,
|
stepSize: 1,
|
||||||
callback: (value) => value + "%",
|
callback: (value) =>
|
||||||
|
value + blankBeforePercent(this.hass.locale) + "%",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
x: {
|
x: {
|
||||||
@ -386,7 +388,8 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div class="value">
|
<div class="value">
|
||||||
${this._systemStatusData.cpu_percent || "-"}%
|
${this._systemStatusData.cpu_percent ||
|
||||||
|
"-"}${blankBeforePercent(this.hass.locale)}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
|
@ -10,6 +10,8 @@ import { haStyle } from "../../../../../resources/styles";
|
|||||||
import { HomeAssistant } from "../../../../../types";
|
import { HomeAssistant } from "../../../../../types";
|
||||||
import "./mqtt-subscribe-card";
|
import "./mqtt-subscribe-card";
|
||||||
|
|
||||||
|
const qosLevel = ["0", "1", "2"];
|
||||||
|
|
||||||
@customElement("mqtt-config-panel")
|
@customElement("mqtt-config-panel")
|
||||||
class HaPanelDevMqtt extends LitElement {
|
class HaPanelDevMqtt extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@ -20,6 +22,8 @@ class HaPanelDevMqtt extends LitElement {
|
|||||||
|
|
||||||
@state() private payload = "";
|
@state() private payload = "";
|
||||||
|
|
||||||
|
@state() private qos = "0";
|
||||||
|
|
||||||
private inited = false;
|
private inited = false;
|
||||||
|
|
||||||
protected firstUpdated() {
|
protected firstUpdated() {
|
||||||
@ -29,6 +33,9 @@ class HaPanelDevMqtt extends LitElement {
|
|||||||
if (localStorage && localStorage["panel-dev-mqtt-payload"]) {
|
if (localStorage && localStorage["panel-dev-mqtt-payload"]) {
|
||||||
this.payload = localStorage["panel-dev-mqtt-payload"];
|
this.payload = localStorage["panel-dev-mqtt-payload"];
|
||||||
}
|
}
|
||||||
|
if (localStorage && localStorage["panel-dev-mqtt-qos"]) {
|
||||||
|
this.qos = localStorage["panel-dev-mqtt-qos"];
|
||||||
|
}
|
||||||
this.inited = true;
|
this.inited = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,6 +61,15 @@ class HaPanelDevMqtt extends LitElement {
|
|||||||
.value=${this.topic}
|
.value=${this.topic}
|
||||||
@change=${this._handleTopic}
|
@change=${this._handleTopic}
|
||||||
></ha-textfield>
|
></ha-textfield>
|
||||||
|
<ha-select
|
||||||
|
.label=${this.hass.localize("ui.panel.config.mqtt.qos")}
|
||||||
|
.value=${this.qos}
|
||||||
|
@selected=${this._handleQos}
|
||||||
|
>${qosLevel.map(
|
||||||
|
(qos) =>
|
||||||
|
html`<mwc-list-item .value=${qos}>${qos}</mwc-list-item>`
|
||||||
|
)}
|
||||||
|
</ha-select>
|
||||||
|
|
||||||
<p>${this.hass.localize("ui.panel.config.mqtt.payload")}</p>
|
<p>${this.hass.localize("ui.panel.config.mqtt.payload")}</p>
|
||||||
<ha-code-editor
|
<ha-code-editor
|
||||||
@ -95,6 +111,14 @@ class HaPanelDevMqtt extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _handleQos(ev: CustomEvent) {
|
||||||
|
const newValue = (ev.target! as any).value;
|
||||||
|
if (newValue >= 0 && newValue !== this.qos && localStorage && this.inited) {
|
||||||
|
this.qos = newValue;
|
||||||
|
localStorage["panel-dev-mqtt-qos"] = this.qos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private _publish(): void {
|
private _publish(): void {
|
||||||
if (!this.hass) {
|
if (!this.hass) {
|
||||||
return;
|
return;
|
||||||
@ -102,6 +126,7 @@ class HaPanelDevMqtt extends LitElement {
|
|||||||
this.hass.callService("mqtt", "publish", {
|
this.hass.callService("mqtt", "publish", {
|
||||||
topic: this.topic,
|
topic: this.topic,
|
||||||
payload_template: this.payload,
|
payload_template: this.payload,
|
||||||
|
qos: parseInt(this.qos),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ class HuiEnergyCarbonGaugeCard
|
|||||||
min="0"
|
min="0"
|
||||||
max="100"
|
max="100"
|
||||||
.value=${value}
|
.value=${value}
|
||||||
.locale=${this.hass!.locale}
|
.locale=${this.hass.locale}
|
||||||
label="%"
|
label="%"
|
||||||
style=${styleMap({
|
style=${styleMap({
|
||||||
"--gauge-color": this._computeSeverity(value),
|
"--gauge-color": this._computeSeverity(value),
|
||||||
|
@ -108,7 +108,7 @@ class HuiEnergySolarGaugeCard
|
|||||||
min="0"
|
min="0"
|
||||||
max="100"
|
max="100"
|
||||||
.value=${value}
|
.value=${value}
|
||||||
.locale=${this.hass!.locale}
|
.locale=${this.hass.locale}
|
||||||
label="%"
|
label="%"
|
||||||
style=${styleMap({
|
style=${styleMap({
|
||||||
"--gauge-color": this._computeSeverity(value),
|
"--gauge-color": this._computeSeverity(value),
|
||||||
|
@ -269,12 +269,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
--alarm-color-disarmed: var(--label-badge-green);
|
--alarm-state-color: rgb(var(--rgb-state-alarm-armed-color));
|
||||||
--alarm-color-pending: var(--label-badge-yellow);
|
|
||||||
--alarm-color-triggered: var(--label-badge-red);
|
|
||||||
--alarm-color-armed: var(--label-badge-red);
|
|
||||||
--alarm-color-autoarm: rgba(0, 153, 255, 0.1);
|
|
||||||
--alarm-state-color: var(--alarm-color-armed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-chip {
|
ha-chip {
|
||||||
@ -292,25 +287,25 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.unavailable {
|
.unavailable {
|
||||||
--alarm-state-color: var(--state-unavailable-color);
|
--alarm-state-color: rgb(var(--rgb-state-unavailable-color));
|
||||||
}
|
}
|
||||||
|
|
||||||
.disarmed {
|
.disarmed {
|
||||||
--alarm-state-color: var(--alarm-color-disarmed);
|
--alarm-state-color: rgb(var(--rgb-state-alarm-disarmed-color));
|
||||||
}
|
}
|
||||||
|
|
||||||
.triggered {
|
.triggered {
|
||||||
--alarm-state-color: var(--alarm-color-triggered);
|
--alarm-state-color: rgb(var(--rgb-state-alarm-trigger-color));
|
||||||
animation: pulse 1s infinite;
|
animation: pulse 1s infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
.arming {
|
.arming {
|
||||||
--alarm-state-color: var(--alarm-color-pending);
|
--alarm-state-color: rgb(var(--rgb-state-alarm-arming-color));
|
||||||
animation: pulse 1s infinite;
|
animation: pulse 1s infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pending {
|
.pending {
|
||||||
--alarm-state-color: var(--alarm-color-pending);
|
--alarm-state-color: rgb(var(--rgb-state-alarm-pending-color));
|
||||||
animation: pulse 1s infinite;
|
animation: pulse 1s infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ import { computeStateDisplay } from "../../../common/entity/compute_state_displa
|
|||||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
import { stateActive } from "../../../common/entity/state_active";
|
import { stateActive } from "../../../common/entity/state_active";
|
||||||
import { stateColor } from "../../../common/entity/state_color";
|
import { stateColorCss } from "../../../common/entity/state_color";
|
||||||
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
|
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
|
||||||
import { iconColorCSS } from "../../../common/style/icon_color_css";
|
import { iconColorCSS } from "../../../common/style/icon_color_css";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
@ -79,6 +79,15 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
@state() private _shouldRenderRipple = false;
|
@state() private _shouldRenderRipple = false;
|
||||||
|
|
||||||
|
private getStateColor(stateObj: HassEntity, config: ButtonCardConfig) {
|
||||||
|
const domain = stateObj ? computeStateDomain(stateObj) : undefined;
|
||||||
|
return (
|
||||||
|
config &&
|
||||||
|
(config.state_color ||
|
||||||
|
(domain === "light" && config.state_color !== false))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public getCardSize(): number {
|
public getCardSize(): number {
|
||||||
return (
|
return (
|
||||||
(this._config?.show_icon ? 4 : 0) + (this._config?.show_name ? 1 : 0)
|
(this._config?.show_icon ? 4 : 0) + (this._config?.show_name ? 1 : 0)
|
||||||
@ -146,13 +155,9 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
|
|||||||
const name = this._config.show_name
|
const name = this._config.show_name
|
||||||
? this._config.name || (stateObj ? computeStateName(stateObj) : "")
|
? this._config.name || (stateObj ? computeStateName(stateObj) : "")
|
||||||
: "";
|
: "";
|
||||||
const domain = stateObj ? computeStateDomain(stateObj) : undefined;
|
|
||||||
|
|
||||||
const active =
|
const active = stateObj && stateActive(stateObj);
|
||||||
(this._config.state_color ||
|
const colored = active && this.getStateColor(stateObj, this._config);
|
||||||
(domain === "light" && this._config.state_color !== false)) &&
|
|
||||||
stateObj &&
|
|
||||||
stateActive(stateObj);
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-card
|
<ha-card
|
||||||
@ -187,9 +192,8 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
|
|||||||
.icon=${this._config.icon}
|
.icon=${this._config.icon}
|
||||||
.state=${stateObj}
|
.state=${stateObj}
|
||||||
style=${styleMap({
|
style=${styleMap({
|
||||||
color: stateObj && active ? this._computeColor(stateObj) : "",
|
color: colored ? this._computeColor(stateObj) : "",
|
||||||
filter:
|
filter: colored ? this._computeBrightness(stateObj) : "",
|
||||||
stateObj && active ? this._computeBrightness(stateObj) : "",
|
|
||||||
height: this._config.icon_height
|
height: this._config.icon_height
|
||||||
? this._config.icon_height
|
? this._config.icon_height
|
||||||
: "",
|
: "",
|
||||||
@ -305,22 +309,24 @@ export class HuiButtonCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _computeBrightness(stateObj: HassEntity | LightEntity): string {
|
private _computeBrightness(stateObj: HassEntity | LightEntity): string {
|
||||||
if (!stateObj.attributes.brightness) {
|
if (!stateObj.attributes.brightness && stateActive(stateObj)) {
|
||||||
const brightness = stateObj.attributes.brightness;
|
const brightness = stateObj.attributes.brightness;
|
||||||
return `brightness(${(brightness + 245) / 5}%)`;
|
return `brightness(${(brightness + 245) / 5}%)`;
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
private _computeColor(stateObj: HassEntity | LightEntity): string {
|
private _computeColor(
|
||||||
if (stateObj.attributes.rgb_color) {
|
stateObj: HassEntity | LightEntity
|
||||||
|
): string | undefined {
|
||||||
|
if (stateObj.attributes.rgb_color && stateActive(stateObj)) {
|
||||||
return `rgb(${stateObj.attributes.rgb_color.join(",")})`;
|
return `rgb(${stateObj.attributes.rgb_color.join(",")})`;
|
||||||
}
|
}
|
||||||
const iconColor = stateColor(stateObj);
|
const iconColor = stateColorCss(stateObj);
|
||||||
if (iconColor) {
|
if (iconColor) {
|
||||||
return `rgb(var(--rgb-state-${iconColor}-color))`;
|
return `rgb(${iconColor})`;
|
||||||
}
|
}
|
||||||
return "";
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleAction(ev: ActionHandlerEvent) {
|
private _handleAction(ev: ActionHandlerEvent) {
|
||||||
|
@ -66,6 +66,8 @@ export class HuiCalendarCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
@state() private _calendars: Calendar[] = [];
|
@state() private _calendars: Calendar[] = [];
|
||||||
|
|
||||||
|
@state() private _eventDisplay = "list-item";
|
||||||
|
|
||||||
@state() private _narrow = false;
|
@state() private _narrow = false;
|
||||||
|
|
||||||
@state() private _veryNarrow = false;
|
@state() private _veryNarrow = false;
|
||||||
@ -134,6 +136,7 @@ export class HuiCalendarCard extends LitElement implements LovelaceCard {
|
|||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.views=${views}
|
.views=${views}
|
||||||
.initialView=${this._config.initial_view!}
|
.initialView=${this._config.initial_view!}
|
||||||
|
.eventDisplay=${this._eventDisplay}
|
||||||
.error=${this._error}
|
.error=${this._error}
|
||||||
@view-changed=${this._handleViewChanged}
|
@view-changed=${this._handleViewChanged}
|
||||||
></ha-full-calendar>
|
></ha-full-calendar>
|
||||||
@ -163,6 +166,8 @@ export class HuiCalendarCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _handleViewChanged(ev: HASSDomEvent<CalendarViewChanged>): void {
|
private _handleViewChanged(ev: HASSDomEvent<CalendarViewChanged>): void {
|
||||||
|
this._eventDisplay =
|
||||||
|
ev.detail.view === "dayGridMonth" ? "list-item" : "auto";
|
||||||
this._startDate = ev.detail.start;
|
this._startDate = ev.detail.start;
|
||||||
this._endDate = ev.detail.end;
|
this._endDate = ev.detail.end;
|
||||||
this._fetchCalendarEvents();
|
this._fetchCalendarEvents();
|
||||||
|
@ -16,7 +16,7 @@ import { computeStateDisplay } from "../../../common/entity/compute_state_displa
|
|||||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
import { stateActive } from "../../../common/entity/state_active";
|
import { stateActive } from "../../../common/entity/state_active";
|
||||||
import { stateColor } from "../../../common/entity/state_color";
|
import { stateColorCss } from "../../../common/entity/state_color";
|
||||||
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
|
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
|
||||||
import {
|
import {
|
||||||
formatNumber,
|
formatNumber,
|
||||||
@ -76,6 +76,15 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
private _footerElement?: HuiErrorCard | LovelaceHeaderFooter;
|
private _footerElement?: HuiErrorCard | LovelaceHeaderFooter;
|
||||||
|
|
||||||
|
private getStateColor(stateObj: HassEntity, config: EntityCardConfig) {
|
||||||
|
const domain = stateObj ? computeStateDomain(stateObj) : undefined;
|
||||||
|
return (
|
||||||
|
config &&
|
||||||
|
(config.state_color ||
|
||||||
|
(domain === "light" && config.state_color !== false))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public setConfig(config: EntityCardConfig): void {
|
public setConfig(config: EntityCardConfig): void {
|
||||||
if (!config.entity) {
|
if (!config.entity) {
|
||||||
throw new Error("Entity must be specified");
|
throw new Error("Entity must be specified");
|
||||||
@ -124,10 +133,8 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
const name = this._config.name || computeStateName(stateObj);
|
const name = this._config.name || computeStateName(stateObj);
|
||||||
|
|
||||||
const active =
|
const active = stateObj && stateActive(stateObj);
|
||||||
(this._config.state_color ||
|
const colored = active && this.getStateColor(stateObj, this._config);
|
||||||
(domain === "light" && this._config.state_color !== false)) &&
|
|
||||||
stateActive(stateObj);
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-card @click=${this._handleClick} tabindex="0">
|
<ha-card @click=${this._handleClick} tabindex="0">
|
||||||
@ -141,7 +148,7 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
|
|||||||
data-domain=${ifDefined(domain)}
|
data-domain=${ifDefined(domain)}
|
||||||
data-state=${stateObj.state}
|
data-state=${stateObj.state}
|
||||||
style=${styleMap({
|
style=${styleMap({
|
||||||
color: active ? this._computeColor(stateObj) : "",
|
color: colored ? this._computeColor(stateObj) : undefined,
|
||||||
height: this._config.icon_height
|
height: this._config.icon_height
|
||||||
? this._config.icon_height
|
? this._config.icon_height
|
||||||
: "",
|
: "",
|
||||||
@ -186,22 +193,14 @@ export class HuiEntityCard extends LitElement implements LovelaceCard {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _computeColor(stateObj: HassEntity | LightEntity): string {
|
private _computeColor(
|
||||||
const domain = computeStateDomain(stateObj);
|
stateObj: HassEntity | LightEntity
|
||||||
if (
|
): string | undefined {
|
||||||
!(
|
const iconColor = stateColorCss(stateObj);
|
||||||
this._config?.state_color ||
|
|
||||||
(domain === "light" && this._config?.state_color !== false)
|
|
||||||
) ||
|
|
||||||
!stateActive(stateObj)
|
|
||||||
) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
const iconColor = stateColor(stateObj);
|
|
||||||
if (iconColor) {
|
if (iconColor) {
|
||||||
return `rgb(var(--rgb-state-${iconColor}-color))`;
|
return `rgb(${iconColor})`;
|
||||||
}
|
}
|
||||||
return "";
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { memoize } from "@fullcalendar/common";
|
import { memoize } from "@fullcalendar/common";
|
||||||
import { mdiHelp } from "@mdi/js";
|
import { mdiExclamationThick, mdiHelp } from "@mdi/js";
|
||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
@ -9,7 +9,6 @@ import { hsv2rgb, rgb2hsv } from "../../../common/color/convert-color";
|
|||||||
import { DOMAINS_TOGGLE } from "../../../common/const";
|
import { DOMAINS_TOGGLE } from "../../../common/const";
|
||||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||||
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||||
import { stateActive } from "../../../common/entity/state_active";
|
|
||||||
import { stateColorCss } from "../../../common/entity/state_color";
|
import { stateColorCss } from "../../../common/entity/state_color";
|
||||||
import { stateIconPath } from "../../../common/entity/state_icon_path";
|
import { stateIconPath } from "../../../common/entity/state_icon_path";
|
||||||
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
|
import { blankBeforePercent } from "../../../common/translations/blank_before_percent";
|
||||||
@ -129,8 +128,9 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _computeStateColor = memoize((entity: HassEntity, color?: string) => {
|
private _computeStateColor = memoize((entity: HassEntity, color?: string) => {
|
||||||
if (UNAVAILABLE_STATES.includes(entity.state)) {
|
// Use custom color
|
||||||
return undefined;
|
if (color) {
|
||||||
|
return computeRgbColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use default color for person/device_tracker because color is on the badge
|
// Use default color for person/device_tracker because color is on the badge
|
||||||
@ -141,16 +141,7 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
|||||||
return "var(--rgb-state-default-color)";
|
return "var(--rgb-state-default-color)";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stateActive(entity)) {
|
// Use light color if the light support rgb
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (color) {
|
|
||||||
return computeRgbColor(color);
|
|
||||||
}
|
|
||||||
|
|
||||||
let stateColor = stateColorCss(entity);
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
computeDomain(entity.entity_id) === "light" &&
|
computeDomain(entity.entity_id) === "light" &&
|
||||||
entity.attributes.rgb_color
|
entity.attributes.rgb_color
|
||||||
@ -166,10 +157,11 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
|||||||
hsvColor[1] = 0.4;
|
hsvColor[1] = 0.4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stateColor = hsv2rgb(hsvColor).join(",");
|
return hsv2rgb(hsvColor).join(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
return stateColor;
|
// Fallback to state color
|
||||||
|
return stateColorCss(entity) ?? "var(--rgb-state-default-color)";
|
||||||
});
|
});
|
||||||
|
|
||||||
private _computeStateDisplay(stateObj: HassEntity): TemplateResult | string {
|
private _computeStateDisplay(stateObj: HassEntity): TemplateResult | string {
|
||||||
@ -233,10 +225,21 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
if (!stateObj) {
|
if (!stateObj) {
|
||||||
return html`
|
return html`
|
||||||
<ha-card class="disabled">
|
<ha-card
|
||||||
|
style=${styleMap({
|
||||||
|
"--tile-color": `var(--rgb-disabled-color)`,
|
||||||
|
})}
|
||||||
|
>
|
||||||
<div class="tile">
|
<div class="tile">
|
||||||
<div class="icon-container">
|
<div class="icon-container">
|
||||||
<ha-tile-icon .iconPath=${mdiHelp}></ha-tile-icon>
|
<ha-tile-icon class="icon" .iconPath=${mdiHelp}></ha-tile-icon>
|
||||||
|
<ha-tile-badge
|
||||||
|
class="badge"
|
||||||
|
.iconPath=${mdiExclamationThick}
|
||||||
|
style=${styleMap({
|
||||||
|
"--tile-badge-background-color": `rgb(var(--rgb-red-color))`,
|
||||||
|
})}
|
||||||
|
></ha-tile-badge>
|
||||||
</div>
|
</div>
|
||||||
<ha-tile-info
|
<ha-tile-info
|
||||||
.primary=${entityId}
|
.primary=${entityId}
|
||||||
@ -360,16 +363,13 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
|||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return css`
|
return css`
|
||||||
:host {
|
:host {
|
||||||
--tile-color: var(--rgb-disabled-color);
|
--tile-color: var(--rgb-state-default-color);
|
||||||
--tile-tap-padding: 6px;
|
--tile-tap-padding: 6px;
|
||||||
-webkit-tap-highlight-color: transparent;
|
-webkit-tap-highlight-color: transparent;
|
||||||
}
|
}
|
||||||
ha-card {
|
ha-card {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
ha-card.disabled {
|
|
||||||
background: rgba(var(--rgb-disabled-color), 0.1);
|
|
||||||
}
|
|
||||||
[role="button"] {
|
[role="button"] {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
@ -22,11 +22,11 @@ function personBadgeIcon(entity: HassEntity) {
|
|||||||
function personBadgeColor(entity: HassEntity) {
|
function personBadgeColor(entity: HassEntity) {
|
||||||
switch (entity.state) {
|
switch (entity.state) {
|
||||||
case "home":
|
case "home":
|
||||||
return "var(--rgb-badge-person-home-color)";
|
return "var(--rgb-state-person-home-color)";
|
||||||
case "not_home":
|
case "not_home":
|
||||||
return "var(--rgb-badge-person-not-home-color)";
|
return "var(--rgb-state-person-not-home-color)";
|
||||||
default:
|
default:
|
||||||
return "var(--rgb-badge-person-zone-color)";
|
return "var(--rgb-state-person-zone-color)";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,9 +491,15 @@ export const generateDefaultViewConfig = (
|
|||||||
|
|
||||||
const areaCards: LovelaceCardConfig[] = [];
|
const areaCards: LovelaceCardConfig[] = [];
|
||||||
|
|
||||||
for (const [areaId, areaEntities] of Object.entries(
|
const sortedAreas = Object.entries(
|
||||||
splittedByAreaDevice.areasWithEntities
|
splittedByAreaDevice.areasWithEntities
|
||||||
)) {
|
).sort((a, b) => {
|
||||||
|
const areaA = areaEntries[a[0]];
|
||||||
|
const areaB = areaEntries[b[0]];
|
||||||
|
return stringCompare(areaA.name, areaB.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const [areaId, areaEntities] of sortedAreas) {
|
||||||
const area = areaEntries[areaId];
|
const area = areaEntries[areaId];
|
||||||
areaCards.push(
|
areaCards.push(
|
||||||
...computeCards(
|
...computeCards(
|
||||||
@ -506,13 +512,20 @@ export const generateDefaultViewConfig = (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
areaCards.sort((a, b) => stringCompare(a.title || "", b.title || ""));
|
|
||||||
|
|
||||||
const deviceCards: LovelaceCardConfig[] = [];
|
const deviceCards: LovelaceCardConfig[] = [];
|
||||||
|
|
||||||
for (const [deviceId, deviceEntities] of Object.entries(
|
const sortedDevices = Object.entries(
|
||||||
splittedByAreaDevice.devicesWithEntities
|
splittedByAreaDevice.devicesWithEntities
|
||||||
)) {
|
).sort((a, b) => {
|
||||||
|
const deviceA = deviceEntries[a[0]];
|
||||||
|
const deviceB = deviceEntries[b[0]];
|
||||||
|
return stringCompare(
|
||||||
|
deviceA.name_by_user || deviceA.name || "",
|
||||||
|
deviceB.name_by_user || deviceB.name || ""
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const [deviceId, deviceEntities] of sortedDevices) {
|
||||||
const device = deviceEntries[deviceId];
|
const device = deviceEntries[deviceId];
|
||||||
deviceCards.push(
|
deviceCards.push(
|
||||||
...computeCards(
|
...computeCards(
|
||||||
@ -534,8 +547,6 @@ export const generateDefaultViewConfig = (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceCards.sort((a, b) => stringCompare(a.title || "", b.title || ""));
|
|
||||||
|
|
||||||
let energyCard: LovelaceCardConfig | undefined;
|
let energyCard: LovelaceCardConfig | undefined;
|
||||||
|
|
||||||
if (energyPrefs) {
|
if (energyPrefs) {
|
||||||
|
@ -93,7 +93,7 @@ export class HuiGaugeCardEditor
|
|||||||
...(showSeverity
|
...(showSeverity
|
||||||
? ([
|
? ([
|
||||||
{
|
{
|
||||||
name: "",
|
name: "severity",
|
||||||
type: "grid",
|
type: "grid",
|
||||||
schema: [
|
schema: [
|
||||||
{
|
{
|
||||||
|
@ -86,15 +86,17 @@ class HuiCoverOpenCloseTileFeature
|
|||||||
`
|
`
|
||||||
: null}
|
: null}
|
||||||
${supportsFeature(this.stateObj, CoverEntityFeature.STOP)
|
${supportsFeature(this.stateObj, CoverEntityFeature.STOP)
|
||||||
? html`<ha-tile-button
|
? html`
|
||||||
.label=${this.hass.localize(
|
<ha-tile-button
|
||||||
"ui.dialogs.more_info_control.cover.stop_cover"
|
.label=${this.hass.localize(
|
||||||
)}
|
"ui.dialogs.more_info_control.cover.stop_cover"
|
||||||
@click=${this._onStopTap}
|
)}
|
||||||
.disabled=${!canStop(this.stateObj)}
|
@click=${this._onStopTap}
|
||||||
>
|
.disabled=${!canStop(this.stateObj)}
|
||||||
<ha-svg-icon .path=${mdiStop}></ha-svg-icon>
|
>
|
||||||
</ha-tile-button> `
|
<ha-svg-icon .path=${mdiStop}></ha-svg-icon>
|
||||||
|
</ha-tile-button>
|
||||||
|
`
|
||||||
: null}
|
: null}
|
||||||
${supportsFeature(this.stateObj, CoverEntityFeature.CLOSE)
|
${supportsFeature(this.stateObj, CoverEntityFeature.CLOSE)
|
||||||
? html`
|
? html`
|
||||||
|
@ -80,15 +80,17 @@ class HuiCoverTiltTileFeature
|
|||||||
`
|
`
|
||||||
: null}
|
: null}
|
||||||
${supportsFeature(this.stateObj, CoverEntityFeature.STOP_TILT)
|
${supportsFeature(this.stateObj, CoverEntityFeature.STOP_TILT)
|
||||||
? html`<ha-tile-button
|
? html`
|
||||||
.label=${this.hass.localize(
|
<ha-tile-button
|
||||||
"ui.dialogs.more_info_control.cover.stop_cover"
|
.label=${this.hass.localize(
|
||||||
)}
|
"ui.dialogs.more_info_control.cover.stop_cover"
|
||||||
@click=${this._onStopTap}
|
)}
|
||||||
.disabled=${!canStopTilt(this.stateObj)}
|
@click=${this._onStopTap}
|
||||||
>
|
.disabled=${!canStopTilt(this.stateObj)}
|
||||||
<ha-svg-icon .path=${mdiStop}></ha-svg-icon>
|
>
|
||||||
</ha-tile-button> `
|
<ha-svg-icon .path=${mdiStop}></ha-svg-icon>
|
||||||
|
</ha-tile-button>
|
||||||
|
`
|
||||||
: null}
|
: null}
|
||||||
${supportsFeature(this.stateObj, CoverEntityFeature.CLOSE_TILT)
|
${supportsFeature(this.stateObj, CoverEntityFeature.CLOSE_TILT)
|
||||||
? html`
|
? html`
|
||||||
|
@ -40,7 +40,7 @@ export const VACUUM_COMMANDS_FEATURES: Record<
|
|||||||
VacuumCommand,
|
VacuumCommand,
|
||||||
VacuumEntityFeature[]
|
VacuumEntityFeature[]
|
||||||
> = {
|
> = {
|
||||||
start_pause: [VacuumEntityFeature.PAUSE],
|
start_pause: [VacuumEntityFeature.PAUSE, VacuumEntityFeature.START],
|
||||||
stop: [VacuumEntityFeature.STOP],
|
stop: [VacuumEntityFeature.STOP],
|
||||||
clean_spot: [VacuumEntityFeature.CLEAN_SPOT],
|
clean_spot: [VacuumEntityFeature.CLEAN_SPOT],
|
||||||
locate: [VacuumEntityFeature.LOCATE],
|
locate: [VacuumEntityFeature.LOCATE],
|
||||||
|
@ -13,7 +13,7 @@ class HaPickDashboardRow extends LitElement {
|
|||||||
|
|
||||||
@property() public narrow!: boolean;
|
@property() public narrow!: boolean;
|
||||||
|
|
||||||
@state() private _dashboards: LovelaceDashboard[] = [];
|
@state() private _dashboards?: LovelaceDashboard[];
|
||||||
|
|
||||||
protected firstUpdated(changedProps: PropertyValues) {
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
@ -29,30 +29,37 @@ class HaPickDashboardRow extends LitElement {
|
|||||||
<span slot="description">
|
<span slot="description">
|
||||||
${this.hass.localize("ui.panel.profile.dashboard.description")}
|
${this.hass.localize("ui.panel.profile.dashboard.description")}
|
||||||
</span>
|
</span>
|
||||||
<ha-select
|
${this._dashboards
|
||||||
.label=${this.hass.localize(
|
? html`<ha-select
|
||||||
"ui.panel.profile.dashboard.dropdown_label"
|
.label=${this.hass.localize(
|
||||||
)}
|
"ui.panel.profile.dashboard.dropdown_label"
|
||||||
.disabled=${!this._dashboards.length}
|
)}
|
||||||
.value=${this.hass.defaultPanel}
|
.disabled=${!this._dashboards?.length}
|
||||||
@selected=${this._dashboardChanged}
|
.value=${this.hass.defaultPanel}
|
||||||
>
|
@selected=${this._dashboardChanged}
|
||||||
<mwc-list-item value="lovelace">
|
>
|
||||||
${this.hass.localize(
|
<mwc-list-item value="lovelace">
|
||||||
"ui.panel.profile.dashboard.default_dashboard_label"
|
${this.hass.localize(
|
||||||
)}
|
"ui.panel.profile.dashboard.default_dashboard_label"
|
||||||
</mwc-list-item>
|
)}
|
||||||
${this._dashboards.map((dashboard) => {
|
|
||||||
if (!this.hass.user!.is_admin && dashboard.require_admin) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return html`
|
|
||||||
<mwc-list-item .value=${dashboard.url_path}>
|
|
||||||
${dashboard.title}
|
|
||||||
</mwc-list-item>
|
</mwc-list-item>
|
||||||
`;
|
${this._dashboards.map((dashboard) => {
|
||||||
})}
|
if (!this.hass.user!.is_admin && dashboard.require_admin) {
|
||||||
</ha-select>
|
return "";
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<mwc-list-item .value=${dashboard.url_path}>
|
||||||
|
${dashboard.title}
|
||||||
|
</mwc-list-item>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
</ha-select>`
|
||||||
|
: html`<ha-select
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.panel.profile.dashboard.dropdown_label"
|
||||||
|
)}
|
||||||
|
disabled
|
||||||
|
></ha-select>`}
|
||||||
</ha-settings-row>
|
</ha-settings-row>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -194,6 +194,10 @@ export class HaPickThemeRow extends LitElement {
|
|||||||
|
|
||||||
private _handleThemeSelection(ev) {
|
private _handleThemeSelection(ev) {
|
||||||
const theme = ev.target.value;
|
const theme = ev.target.value;
|
||||||
|
if (theme === this.hass.selectedTheme?.theme) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (theme === "Backend-selected") {
|
if (theme === "Backend-selected") {
|
||||||
if (this.hass.selectedTheme?.theme) {
|
if (this.hass.selectedTheme?.theme) {
|
||||||
fireEvent(this, "settheme", {
|
fireEvent(this, "settheme", {
|
||||||
|
@ -134,24 +134,29 @@ documentContainer.innerHTML = `<custom-style>
|
|||||||
--rgb-white-color: 255, 255, 255;
|
--rgb-white-color: 255, 255, 255;
|
||||||
|
|
||||||
/* rgb state color */
|
/* rgb state color */
|
||||||
--rgb-state-default-color: 68, 115, 158;
|
--rgb-state-default-color: var(--rgb-dark-primary-color, 68, 115, 158);
|
||||||
--rgb-state-alarm-armed-color: var(--rgb-red-color);
|
--rgb-state-inactive-color: var(--rgb-grey-color);
|
||||||
|
--rgb-state-unavailable-color: var(--rgb-disabled-color);
|
||||||
|
|
||||||
|
/* rgb state domain colors */
|
||||||
|
--rgb-state-alarm-armed-color: var(--rgb-green-color);
|
||||||
--rgb-state-alarm-arming-color: var(--rgb-orange-color);
|
--rgb-state-alarm-arming-color: var(--rgb-orange-color);
|
||||||
|
--rgb-state-alarm-disarmed-color: var(--rgb-grey-color);
|
||||||
--rgb-state-alarm-pending-color: var(--rgb-orange-color);
|
--rgb-state-alarm-pending-color: var(--rgb-orange-color);
|
||||||
--rgb-state-alarm-triggered-color: var(--rgb-red-color);
|
--rgb-state-alarm-triggered-color: var(--rgb-red-color);
|
||||||
--rgb-state-alert-color: var(--rgb-red-color);
|
--rgb-state-alert-color: var(--rgb-red-color);
|
||||||
--rgb-state-automation-color: var(--rgb-amber-color);
|
--rgb-state-automation-color: var(--rgb-amber-color);
|
||||||
--rgb-state-binary-sensor-alerting-color: var(--rgb-red-color);
|
--rgb-state-binary-sensor-alerting-color: var(--rgb-red-color);
|
||||||
--rgb-state-binary-sensor-color: var(--rgb-blue-color);
|
--rgb-state-binary-sensor-color: var(--rgb-amber-color);
|
||||||
--rgb-state-calendar-color: var(--rgb-blue-color);
|
--rgb-state-calendar-color: var(--rgb-amber-color);
|
||||||
--rgb-state-camera-color: var(--rgb-blue-color);
|
--rgb-state-camera-color: var(--rgb-amber-color);
|
||||||
--rgb-state-climate-auto-color: var(--rgb-green-color);
|
--rgb-state-climate-auto-color: var(--rgb-green-color);
|
||||||
--rgb-state-climate-cool-color: var(--rgb-blue-color);
|
--rgb-state-climate-cool-color: var(--rgb-blue-color);
|
||||||
--rgb-state-climate-dry-color: var(--rgb-orange-color);
|
--rgb-state-climate-dry-color: var(--rgb-orange-color);
|
||||||
--rgb-state-climate-fan-only-color: var(--rgb-cyan-color);
|
--rgb-state-climate-fan-only-color: var(--rgb-cyan-color);
|
||||||
--rgb-state-climate-heat-color: var(--rgb-deep-orange-color);
|
--rgb-state-climate-heat-color: var(--rgb-deep-orange-color);
|
||||||
--rgb-state-climate-heat-cool-color: var(--rgb-amber-color);
|
--rgb-state-climate-heat-cool-color: var(--rgb-amber-color);
|
||||||
--rgb-state-climate-idle-color: var(--rgb-disabled-color);
|
--rgb-state-climate-idle-color: var(--rgb-off-color);
|
||||||
--rgb-state-cover-color: var(--rgb-purple-color);
|
--rgb-state-cover-color: var(--rgb-purple-color);
|
||||||
--rgb-state-fan-color: var(--rgb-cyan-color);
|
--rgb-state-fan-color: var(--rgb-cyan-color);
|
||||||
--rgb-state-group-color: var(--rgb-amber-color);
|
--rgb-state-group-color: var(--rgb-amber-color);
|
||||||
@ -159,17 +164,19 @@ documentContainer.innerHTML = `<custom-style>
|
|||||||
--rgb-state-input-boolean-color: var(--rgb-amber-color);
|
--rgb-state-input-boolean-color: var(--rgb-amber-color);
|
||||||
--rgb-state-light-color: var(--rgb-amber-color);
|
--rgb-state-light-color: var(--rgb-amber-color);
|
||||||
--rgb-state-lock-jammed-color: var(--rgb-red-color);
|
--rgb-state-lock-jammed-color: var(--rgb-red-color);
|
||||||
--rgb-state-lock-locked-color: var(--rgb-red-color);
|
--rgb-state-lock-locked-color: var(--rgb-green-color);
|
||||||
--rgb-state-lock-pending-color: var(--rgb-orange-color);
|
--rgb-state-lock-pending-color: var(--rgb-orange-color);
|
||||||
--rgb-state-media-player-color: var(--rgb-indigo-color);
|
--rgb-state-lock-unlocked-color: var(--rgb-red-color);
|
||||||
|
--rgb-state-media-player-color: var(--rgb-light-blue-color);
|
||||||
--rgb-state-person-home-color: var(--rgb-green-color);
|
--rgb-state-person-home-color: var(--rgb-green-color);
|
||||||
|
--rgb-state-person-not-home-color: var(--rgb-grey-color);
|
||||||
--rgb-state-person-zone-color: var(--rgb-blue-color);
|
--rgb-state-person-zone-color: var(--rgb-blue-color);
|
||||||
--rgb-state-remote-color: var(--rgb-blue-color);
|
--rgb-state-remote-color: var(--rgb-amber-color);
|
||||||
--rgb-state-script-color: var(--rgb-amber-color);
|
--rgb-state-script-color: var(--rgb-amber-color);
|
||||||
--rgb-state-sensor-battery-high-color: var(--rgb-green-color);
|
--rgb-state-sensor-battery-high-color: var(--rgb-green-color);
|
||||||
--rgb-state-sensor-battery-low-color: var(--rgb-red-color);
|
--rgb-state-sensor-battery-low-color: var(--rgb-red-color);
|
||||||
--rgb-state-sensor-battery-medium-color: var(--rgb-orange-color);
|
--rgb-state-sensor-battery-medium-color: var(--rgb-orange-color);
|
||||||
--rgb-state-sensor-battery-unknown-color: var(--rgb-disabled-color);
|
--rgb-state-sensor-battery-unknown-color: var(--rgb-off-color);
|
||||||
--rgb-state-siren-color: var(--rgb-red-color);
|
--rgb-state-siren-color: var(--rgb-red-color);
|
||||||
--rgb-state-sun-day-color: var(--rgb-amber-color);
|
--rgb-state-sun-day-color: var(--rgb-amber-color);
|
||||||
--rgb-state-sun-night-color: var(--rgb-deep-purple-color);
|
--rgb-state-sun-night-color: var(--rgb-deep-purple-color);
|
||||||
@ -179,11 +186,6 @@ documentContainer.innerHTML = `<custom-style>
|
|||||||
--rgb-state-update-installing-color: var(--rgb-orange-color);
|
--rgb-state-update-installing-color: var(--rgb-orange-color);
|
||||||
--rgb-state-vacuum-color: var(--rgb-teal-color);
|
--rgb-state-vacuum-color: var(--rgb-teal-color);
|
||||||
|
|
||||||
/* rgb state badge color */
|
|
||||||
--rgb-badge-person-home-color: var(--rgb-state-person-home-color);
|
|
||||||
--rgb-badge-person-zone-color: var(--rgb-state-person-zone-color);
|
|
||||||
--rgb-badge-person-not-home-color: var(--rgb-red-color);
|
|
||||||
|
|
||||||
/* input components */
|
/* input components */
|
||||||
--input-idle-line-color: rgba(0, 0, 0, 0.42);
|
--input-idle-line-color: rgba(0, 0, 0, 0.42);
|
||||||
--input-hover-line-color: rgba(0, 0, 0, 0.87);
|
--input-hover-line-color: rgba(0, 0, 0, 0.87);
|
||||||
|
@ -48,7 +48,7 @@ export const darkStyles = {
|
|||||||
"energy-grid-return-color": "#a280db",
|
"energy-grid-return-color": "#a280db",
|
||||||
"map-filter":
|
"map-filter":
|
||||||
"invert(.9) hue-rotate(170deg) brightness(1.5) contrast(1.2) saturate(.3)",
|
"invert(.9) hue-rotate(170deg) brightness(1.5) contrast(1.2) saturate(.3)",
|
||||||
"rgb-disabled-color": "111, 111, 111",
|
"rgb-disabled-color": "70, 70, 70",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const derivedStyles = {
|
export const derivedStyles = {
|
||||||
|
@ -3233,7 +3233,8 @@
|
|||||||
"subscribe_to": "Topic to subscribe to",
|
"subscribe_to": "Topic to subscribe to",
|
||||||
"start_listening": "Start listening",
|
"start_listening": "Start listening",
|
||||||
"stop_listening": "Stop listening",
|
"stop_listening": "Stop listening",
|
||||||
"message_received": "Message {id} received on {topic} at {time}:"
|
"message_received": "Message {id} received on {topic} at {time}:",
|
||||||
|
"qos": "QoS"
|
||||||
},
|
},
|
||||||
"zha": {
|
"zha": {
|
||||||
"common": {
|
"common": {
|
||||||
@ -4349,6 +4350,7 @@
|
|||||||
"primary": "Primary",
|
"primary": "Primary",
|
||||||
"accent": "Accent",
|
"accent": "Accent",
|
||||||
"disabled": "Disabled",
|
"disabled": "Disabled",
|
||||||
|
"inactive": "Inactive",
|
||||||
"red": "Red",
|
"red": "Red",
|
||||||
"pink": "Pink",
|
"pink": "Pink",
|
||||||
"purple": "Purple",
|
"purple": "Purple",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user