diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 746fa30697..3c53eacb7e 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -5,33 +5,39 @@ "context": ".." }, "appPort": "8124:8123", - "context": "..", "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": { "WORKSPACE_DIRECTORY": "${containerWorkspaceFolder}" }, - "settings": { - "terminal.integrated.shell.linux": "/bin/bash", - "files.eol": "\n", - "editor.tabSize": 2, - "editor.formatOnPaste": false, - "editor.formatOnSave": true, - "editor.formatOnType": true, - "[typescript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[javascript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "files.trimTrailingWhitespace": true + "customizations": { + "vscode": { + "extensions": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "runem.lit-plugin", + "github.vscode-pull-request-github", + "eamodio.gitlens" + ], + "settings": { + "files.eol": "\n", + "editor.tabSize": 2, + "editor.formatOnPaste": false, + "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" + } + } } } diff --git a/.github/workflows/cast_deployment.yaml b/.github/workflows/cast_deployment.yaml new file mode 100644 index 0000000000..4634ae0136 --- /dev/null +++ b/.github/workflows/cast_deployment.yaml @@ -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 }} \ No newline at end of file diff --git a/.github/workflows/demo.yaml b/.github/workflows/demo_deployment.yaml similarity index 73% rename from .github/workflows/demo.yaml rename to .github/workflows/demo_deployment.yaml index 9ff90402f6..aa489d0ba6 100644 --- a/.github/workflows/demo.yaml +++ b/.github/workflows/demo_deployment.yaml @@ -1,6 +1,9 @@ -name: Demo +name: Demo deployment on: + workflow_dispatch: + schedule: + - cron: "0 0 * * *" push: branches: - dev @@ -12,24 +15,34 @@ env: jobs: deploy: runs-on: ubuntu-latest + environment: + name: Demo + 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 Demo run: ./node_modules/.bin/gulp build-demo env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - 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: NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} NETLIFY_SITE_ID: ${{ secrets.NETLIFY_DEMO_DEV_SITE_ID }} diff --git a/.github/workflows/design_deployment.yaml b/.github/workflows/design_deployment.yaml new file mode 100644 index 0000000000..e152f7b4c1 --- /dev/null +++ b/.github/workflows/design_deployment.yaml @@ -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 }} diff --git a/.github/workflows/netflify.yml b/.github/workflows/netflify.yml deleted file mode 100644 index 51989057ba..0000000000 --- a/.github/workflows/netflify.yml +++ /dev/null @@ -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 }} diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 8bea127242..ea7763d5de 100755 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,7 +2,8 @@ "recommendations": [ "dbaeumer.vscode-eslint", "esbenp.prettier-vscode", - "bierner.lit-html", - "runem.lit-plugin" + "runem.lit-plugin", + "github.vscode-pull-request-github", + "eamodio.gitlens" ] } diff --git a/gallery/script/netlify_build_gallery b/gallery/script/netlify_build_gallery index db8be615d1..97c95ebf2a 100755 --- a/gallery/script/netlify_build_gallery +++ b/gallery/script/netlify_build_gallery @@ -1,6 +1,7 @@ #!/bin/bash TARGET_LABEL="needs design preview" +export SKIP_FETCH_NIGHTLY_TRANSLATIONS="true" if [[ "$NETLIFY" != "true" ]]; then echo "This script can only be run on Netlify" @@ -30,6 +31,4 @@ if [[ "${PULL_REQUEST}" == "true" ]]; then else createStatus "success" "Build was not requested by PR label" fi -elif [[ "$INCOMING_HOOK_BODY" == "NIGHTLY" ]]; then - gulp build-gallery fi diff --git a/pyproject.toml b/pyproject.toml index 6d99314ec9..2c4a530952 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20221208.0" +version = "20221212.0" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md" diff --git a/src/common/const.ts b/src/common/const.ts index 8f9902c31e..f9ed0e8ff6 100644 --- a/src/common/const.ts +++ b/src/common/const.ts @@ -52,7 +52,9 @@ import { mdiScriptText, mdiSineWave, mdiSpeedometer, + mdiSunWireless, mdiThermometer, + mdiThermometerLines, mdiThermostat, mdiTimerOutline, mdiVideo, @@ -126,6 +128,7 @@ export const FIXED_DOMAIN_ICONS = { export const FIXED_DEVICE_CLASS_ICONS = { apparent_power: mdiFlash, aqi: mdiAirFilter, + atmospheric_pressure: mdiThermometerLines, // battery: mdiBattery, => not included by design since `sensorIcon()` will dynamically determine the icon carbon_dioxide: mdiMoleculeCo2, carbon_monoxide: mdiMoleculeCo, @@ -138,6 +141,7 @@ export const FIXED_DEVICE_CLASS_ICONS = { gas: mdiMeterGas, humidity: mdiWaterPercent, illuminance: mdiBrightness5, + irradiance: mdiSunWireless, moisture: mdiWaterPercent, monetary: mdiCash, nitrogen_dioxide: mdiMolecule, diff --git a/src/common/entity/color/alarm_control_panel_color.ts b/src/common/entity/color/alarm_control_panel_color.ts index ef72805c11..deb8846088 100644 --- a/src/common/entity/color/alarm_control_panel_color.ts +++ b/src/common/entity/color/alarm_control_panel_color.ts @@ -13,6 +13,8 @@ export const alarmControlPanelColor = (state?: string): string | undefined => { return "alarm-arming"; case "triggered": return "alarm-triggered"; + case "disarmed": + return "alarm-disarmed"; default: return undefined; } diff --git a/src/common/entity/color/lock_color.ts b/src/common/entity/color/lock_color.ts index faecef1288..6d0ec06665 100644 --- a/src/common/entity/color/lock_color.ts +++ b/src/common/entity/color/lock_color.ts @@ -1,5 +1,7 @@ export const lockColor = (state?: string): string | undefined => { switch (state) { + case "unlocked": + return "lock-unlocked"; case "locked": return "lock-locked"; case "jammed": diff --git a/src/common/entity/color/person_color.ts b/src/common/entity/color/person_color.ts index e1158ab8e1..efdabbd33d 100644 --- a/src/common/entity/color/person_color.ts +++ b/src/common/entity/color/person_color.ts @@ -2,6 +2,8 @@ export const personColor = (state: string): string | undefined => { switch (state) { case "home": return "person-home"; + case "not_home": + return "person-not-home"; default: return "person-zone"; } diff --git a/src/common/entity/color/sensor_color.ts b/src/common/entity/color/sensor_color.ts index 5da0eeb0a2..298f996f26 100644 --- a/src/common/entity/color/sensor_color.ts +++ b/src/common/entity/color/sensor_color.ts @@ -3,12 +3,12 @@ import { batteryStateColor } from "./battery_color"; export const sensorColor = ( stateObj: HassEntity, - compareState: string + state: string ): string | undefined => { const deviceClass = stateObj?.attributes.device_class; if (deviceClass === "battery") { - return batteryStateColor(compareState); + return batteryStateColor(state); } return undefined; diff --git a/src/common/entity/state_active.ts b/src/common/entity/state_active.ts index 5bd58e9f2c..415be5f055 100644 --- a/src/common/entity/state_active.ts +++ b/src/common/entity/state_active.ts @@ -16,15 +16,15 @@ export function stateActive(stateObj: HassEntity, state?: string): boolean { // Custom cases switch (domain) { + case "alarm_control_panel": + return compareState !== "disarmed"; case "cover": return !["closed", "closing"].includes(compareState); case "device_tracker": case "person": return compareState !== "not_home"; - case "alarm_control_panel": - return compareState !== "disarmed"; case "lock": - return compareState !== "unlocked"; + return compareState !== "locked"; case "media_player": return compareState !== "standby"; case "vacuum": diff --git a/src/common/entity/state_color.ts b/src/common/entity/state_color.ts index 4cf278e231..aed20531e3 100644 --- a/src/common/entity/state_color.ts +++ b/src/common/entity/state_color.ts @@ -1,5 +1,6 @@ /** Return an color representing a state. */ import { HassEntity } from "home-assistant-js-websocket"; +import { UNAVAILABLE } from "../../data/entity"; import { UpdateEntity, updateIsInstalling } from "../../data/update"; import { alarmControlPanelColor } from "./color/alarm_control_panel_color"; import { binarySensorColor } from "./color/binary_sensor_color"; @@ -10,7 +11,7 @@ import { sensorColor } from "./color/sensor_color"; import { computeDomain } from "./compute_domain"; import { stateActive } from "./state_active"; -const STATIC_COLORED_DOMAIN = new Set([ +const STATIC_ACTIVE_COLORED_DOMAIN = new Set([ "alert", "automation", "calendar", @@ -30,25 +31,33 @@ const STATIC_COLORED_DOMAIN = new Set([ "vacuum", ]); -export const stateColorCss = (stateObj?: HassEntity, state?: string) => { - if (!stateObj || !stateActive(stateObj, state)) { - return `var(--rgb-disabled-color)`; +export const stateColorCss = (stateObj: HassEntity, state?: string) => { + const compareState = state !== undefined ? state : stateObj?.state; + if (compareState === UNAVAILABLE) { + return `var(--rgb-state-unavailable-color)`; } - const color = stateColor(stateObj, state); + const domainColor = stateColor(stateObj, state); - if (color) { - return `var(--rgb-state-${color}-color)`; + if (domainColor) { + 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) => { const compareState = state !== undefined ? state : stateObj?.state; 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("_", "-"); } diff --git a/src/common/style/icon_color_css.ts b/src/common/style/icon_color_css.ts index 8e5f66d90c..fef56682b5 100644 --- a/src/common/style/icon_color_css.ts +++ b/src/common/style/icon_color_css.ts @@ -21,6 +21,6 @@ export const iconColorCSS = css` /* Color the icon if unavailable */ ha-state-icon[data-state="unavailable"] { - color: var(--state-unavailable-color); + color: rgb(var(--rgb-state-unavailable-color)); } `; diff --git a/src/components/chart/timeline-chart/textbar-element.ts b/src/components/chart/timeline-chart/textbar-element.ts index 93cc953ccd..1f11a8f433 100644 --- a/src/components/chart/timeline-chart/textbar-element.ts +++ b/src/components/chart/timeline-chart/textbar-element.ts @@ -37,8 +37,11 @@ export class TextBarElement extends BarElement { } const textColor = options.textColor || - (options.backgroundColor && - (luminosity(hex2rgb(options.backgroundColor)) > 0.5 ? "#000" : "#fff")); + (options?.backgroundColor === "transparent" + ? "transparent" + : luminosity(hex2rgb(options.backgroundColor)) > 0.5 + ? "#000" + : "#fff"); // ctx.font = "12px arial"; ctx.fillStyle = textColor; diff --git a/src/components/chart/timeline-chart/timeline-color.ts b/src/components/chart/timeline-chart/timeline-color.ts index 012c9315f6..ecbf9a78cc 100644 --- a/src/components/chart/timeline-chart/timeline-color.ts +++ b/src/components/chart/timeline-chart/timeline-color.ts @@ -5,6 +5,7 @@ import { labBrighten } from "../../../common/color/lab"; import { computeDomain } from "../../../common/entity/compute_domain"; import { stateActive } from "../../../common/entity/state_active"; import { stateColor } from "../../../common/entity/state_color"; +import { UNAVAILABLE } from "../../../data/entity"; const DOMAIN_STATE_SHADES: Record> = { media_player: { @@ -49,21 +50,23 @@ function computeTimelineStateColor( computedStyles: CSSStyleDeclaration, stateObj?: HassEntity ): string | undefined { - if (!stateObj || !stateActive(stateObj, state)) { - const rgb = cssToRgb("--rgb-disabled-color", computedStyles); + if (!stateObj || state === UNAVAILABLE) { + return "transparent"; + } + + const color = stateColor(stateObj, state); + + if (!color && !stateActive(stateObj, state)) { + const rgb = cssToRgb("--rgb-state-inactive-color", computedStyles); if (!rgb) return undefined; 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); if (!rgb) return undefined; + const domain = computeDomain(stateObj.entity_id); const shade = DOMAIN_STATE_SHADES[domain]?.[state] as number | number; if (!shade) { return rgb2hex(rgb); diff --git a/src/components/entity/state-badge.ts b/src/components/entity/state-badge.ts index 30022f677f..fdf507b0d0 100644 --- a/src/components/entity/state-badge.ts +++ b/src/components/entity/state-badge.ts @@ -14,7 +14,7 @@ import { styleMap } from "lit/directives/style-map"; import { computeDomain } from "../../common/entity/compute_domain"; import { computeStateDomain } from "../../common/entity/compute_state_domain"; 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 { cameraUrlWithWidthHeight } from "../../data/camera"; import type { HomeAssistant } from "../../types"; @@ -107,12 +107,13 @@ export class StateBadge extends LitElement { } hostStyle.backgroundImage = `url(${imageUrl})`; this._showIcon = false; - } else if (stateActive(stateObj) && this._stateColor) { - const iconColor = stateColor(stateObj); + } else if (this._stateColor && stateActive(stateObj)) { + const color = stateColorCss(stateObj); + if (color) { + iconStyle.color = `rgb(${color})`; + } if (stateObj.attributes.rgb_color) { iconStyle.color = `rgb(${stateObj.attributes.rgb_color.join(",")})`; - } else if (iconColor) { - iconStyle.color = `rgb(var(--rgb-state-${iconColor}-color))`; } if (stateObj.attributes.brightness) { const brightness = stateObj.attributes.brightness; diff --git a/src/components/ha-form/types.ts b/src/components/ha-form/types.ts index a41fad2d6e..287b904780 100644 --- a/src/components/ha-form/types.ts +++ b/src/components/ha-form/types.ts @@ -31,7 +31,7 @@ export interface HaFormBaseSchema { export interface HaFormGridSchema extends HaFormBaseSchema { type: "grid"; - name: ""; + name: string; column_min_width?: string; schema: readonly HaFormSchema[]; } diff --git a/src/panels/calendar/ha-full-calendar.ts b/src/panels/calendar/ha-full-calendar.ts index 90f6e3d4c4..d3007ba5e6 100644 --- a/src/panels/calendar/ha-full-calendar.ts +++ b/src/panels/calendar/ha-full-calendar.ts @@ -69,7 +69,6 @@ const defaultFullCalendarConfig: CalendarOptions = { initialView: "dayGridMonth", dayMaxEventRows: true, height: "parent", - eventDisplay: "list-item", locales: allLocales, views: { listWeek: { @@ -97,6 +96,8 @@ export class HAFullCalendar extends LitElement { @property() public initialView: FullCalendarView = "dayGridMonth"; + @property() public eventDisplay = "auto"; + @property({ attribute: false }) public error?: string = undefined; private calendar?: Calendar; @@ -233,6 +234,10 @@ export class HAFullCalendar extends LitElement { this._fireViewChanged(); } + if (changedProps.has("eventDisplay")) { + this.calendar!.setOption("eventDisplay", this.eventDisplay); + } + const oldHass = changedProps.get("hass") as HomeAssistant; if (oldHass && oldHass.language !== this.hass.language) { @@ -246,6 +251,7 @@ export class HAFullCalendar extends LitElement { locale: this.hass.language, firstDay: firstWeekdayIndex(this.hass.locale), initialView: this.initialView, + eventDisplay: this.eventDisplay, eventTimeFormat: { hour: 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.calendar!.changeView("dayGridDay"); this.calendar!.gotoDate(info.dateStr); + this._fireViewChanged(); } private _handleNext(): void { @@ -537,6 +544,7 @@ export class HAFullCalendar extends LitElement { a.fc-daygrid-day-number { float: none !important; font-size: 12px; + cursor: pointer; } .fc .fc-daygrid-day-number { @@ -547,12 +555,8 @@ export class HAFullCalendar extends LitElement { background: inherit; } - td.fc-day-today .fc-daygrid-day-top { - padding-top: 4px; - } - td.fc-day-today .fc-daygrid-day-number { - height: 24px; + height: 26px; color: var(--text-primary-color) !important; background-color: var(--primary-color); border-radius: 50%; @@ -561,7 +565,6 @@ export class HAFullCalendar extends LitElement { white-space: nowrap; width: max-content; min-width: 24px; - line-height: 140%; } .fc-daygrid-day-events { @@ -571,6 +574,7 @@ export class HAFullCalendar extends LitElement { .fc-event { border-radius: 4px; line-height: 1.7; + cursor: pointer; } .fc-daygrid-block-event .fc-event-main { diff --git a/src/panels/config/core/ha-config-system-navigation.ts b/src/panels/config/core/ha-config-system-navigation.ts index 6f1dba83e0..6bab7dfb82 100644 --- a/src/panels/config/core/ha-config-system-navigation.ts +++ b/src/panels/config/core/ha-config-system-navigation.ts @@ -3,6 +3,7 @@ import { customElement, property, state } from "lit/decorators"; import { canShowPage } from "../../../common/config/can_show_page"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import { relativeTime } from "../../../common/datetime/relative_time"; +import { blankBeforePercent } from "../../../common/translations/blank_before_percent"; import "../../../components/ha-card"; import "../../../components/ha-navigation-list"; import "../../../components/ha-tip"; @@ -84,7 +85,7 @@ class HaConfigSystemNavigation extends LitElement { "percent_used", `${Math.round( (this._storageInfo.used / this._storageInfo.total) * 100 - )}%`, + )}${blankBeforePercent(this.hass.locale)}%`, "free_space", `${this._storageInfo.free} GB` ) diff --git a/src/panels/config/devices/ha-config-device-page.ts b/src/panels/config/devices/ha-config-device-page.ts index 025f048f9e..143f2a8f51 100644 --- a/src/panels/config/devices/ha-config-device-page.ts +++ b/src/panels/config/devices/ha-config-device-page.ts @@ -1,3 +1,4 @@ +import "@material/mwc-list/mwc-list-item"; import { mdiCog, mdiDelete, @@ -7,18 +8,19 @@ import { mdiPencil, mdiPlusCircle, } from "@mdi/js"; -import "@material/mwc-list/mwc-list-item"; import "@polymer/paper-tooltip/paper-tooltip"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; import { ifDefined } from "lit/directives/if-defined"; import memoizeOne from "memoize-one"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; +import { SENSOR_ENTITIES } from "../../../common/const"; import { computeDomain } from "../../../common/entity/compute_domain"; import { computeStateDomain } from "../../../common/entity/compute_state_domain"; import { computeStateName } from "../../../common/entity/compute_state_name"; import { stringCompare } from "../../../common/string/compare"; import { slugify } from "../../../common/string/slugify"; +import { blankBeforePercent } from "../../../common/translations/blank_before_percent"; import { groupBy } from "../../../common/util/group-by"; import "../../../components/entity/ha-battery-icon"; import "../../../components/ha-alert"; @@ -59,6 +61,7 @@ import { showConfirmationDialog, } from "../../../dialogs/generic/show-dialog-box"; import "../../../layouts/hass-error-screen"; +import "../../../layouts/hass-subpage"; import "../../../layouts/hass-tabs-subpage"; import { haStyle } from "../../../resources/styles"; import type { HomeAssistant } from "../../../types"; @@ -74,8 +77,6 @@ import { loadDeviceRegistryDetailDialog, showDeviceRegistryDetailDialog, } from "./device-registry-detail/show-dialog-device-registry-detail"; -import "../../../layouts/hass-subpage"; -import { SENSOR_ENTITIES } from "../../../common/const"; export interface EntityRegistryStateEntry extends EntityRegistryEntry { stateName?: string | null; @@ -639,7 +640,11 @@ export class HaConfigDevicePage extends LitElement { batteryState ? html`
- ${batteryIsBinary ? "" : batteryState.state + " %"} + ${batteryIsBinary + ? "" + : batteryState.state + + blankBeforePercent(this.hass.locale) + + "%"} value + "%", + callback: (value) => + value + blankBeforePercent(this.hass.locale) + "%", }, }, x: { @@ -386,7 +388,8 @@ class HaConfigHardware extends SubscribeMixin(LitElement) { )}
- ${this._systemStatusData.cpu_percent || "-"}% + ${this._systemStatusData.cpu_percent || + "-"}${blankBeforePercent(this.hass.locale)}%
diff --git a/src/panels/config/integrations/integration-panels/mqtt/mqtt-config-panel.ts b/src/panels/config/integrations/integration-panels/mqtt/mqtt-config-panel.ts index f658f0b6fb..c5eab6b79e 100644 --- a/src/panels/config/integrations/integration-panels/mqtt/mqtt-config-panel.ts +++ b/src/panels/config/integrations/integration-panels/mqtt/mqtt-config-panel.ts @@ -10,6 +10,8 @@ import { haStyle } from "../../../../../resources/styles"; import { HomeAssistant } from "../../../../../types"; import "./mqtt-subscribe-card"; +const qosLevel = ["0", "1", "2"]; + @customElement("mqtt-config-panel") class HaPanelDevMqtt extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -20,6 +22,8 @@ class HaPanelDevMqtt extends LitElement { @state() private payload = ""; + @state() private qos = "0"; + private inited = false; protected firstUpdated() { @@ -29,6 +33,9 @@ class HaPanelDevMqtt extends LitElement { if (localStorage && 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; } @@ -54,6 +61,15 @@ class HaPanelDevMqtt extends LitElement { .value=${this.topic} @change=${this._handleTopic} > + ${qosLevel.map( + (qos) => + html`${qos}` + )} +

${this.hass.localize("ui.panel.config.mqtt.payload")}

= 0 && newValue !== this.qos && localStorage && this.inited) { + this.qos = newValue; + localStorage["panel-dev-mqtt-qos"] = this.qos; + } + } + private _publish(): void { if (!this.hass) { return; @@ -102,6 +126,7 @@ class HaPanelDevMqtt extends LitElement { this.hass.callService("mqtt", "publish", { topic: this.topic, payload_template: this.payload, + qos: parseInt(this.qos), }); } diff --git a/src/panels/lovelace/cards/energy/hui-energy-carbon-consumed-gauge-card.ts b/src/panels/lovelace/cards/energy/hui-energy-carbon-consumed-gauge-card.ts index 33271eeca4..9c266c54ad 100644 --- a/src/panels/lovelace/cards/energy/hui-energy-carbon-consumed-gauge-card.ts +++ b/src/panels/lovelace/cards/energy/hui-energy-carbon-consumed-gauge-card.ts @@ -129,7 +129,7 @@ class HuiEnergyCarbonGaugeCard min="0" max="100" .value=${value} - .locale=${this.hass!.locale} + .locale=${this.hass.locale} label="%" style=${styleMap({ "--gauge-color": this._computeSeverity(value), diff --git a/src/panels/lovelace/cards/energy/hui-energy-solar-consumed-gauge-card.ts b/src/panels/lovelace/cards/energy/hui-energy-solar-consumed-gauge-card.ts index 5e5df30f85..fd5de64399 100644 --- a/src/panels/lovelace/cards/energy/hui-energy-solar-consumed-gauge-card.ts +++ b/src/panels/lovelace/cards/energy/hui-energy-solar-consumed-gauge-card.ts @@ -108,7 +108,7 @@ class HuiEnergySolarGaugeCard min="0" max="100" .value=${value} - .locale=${this.hass!.locale} + .locale=${this.hass.locale} label="%" style=${styleMap({ "--gauge-color": this._computeSeverity(value), diff --git a/src/panels/lovelace/cards/hui-alarm-panel-card.ts b/src/panels/lovelace/cards/hui-alarm-panel-card.ts index 84f1d3b103..b9d01da1c0 100644 --- a/src/panels/lovelace/cards/hui-alarm-panel-card.ts +++ b/src/panels/lovelace/cards/hui-alarm-panel-card.ts @@ -269,12 +269,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard { flex-direction: column; align-items: center; box-sizing: border-box; - --alarm-color-disarmed: var(--label-badge-green); - --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); + --alarm-state-color: rgb(var(--rgb-state-alarm-armed-color)); } ha-chip { @@ -292,25 +287,25 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard { } .unavailable { - --alarm-state-color: var(--state-unavailable-color); + --alarm-state-color: rgb(var(--rgb-state-unavailable-color)); } .disarmed { - --alarm-state-color: var(--alarm-color-disarmed); + --alarm-state-color: rgb(var(--rgb-state-alarm-disarmed-color)); } .triggered { - --alarm-state-color: var(--alarm-color-triggered); + --alarm-state-color: rgb(var(--rgb-state-alarm-trigger-color)); animation: pulse 1s infinite; } .arming { - --alarm-state-color: var(--alarm-color-pending); + --alarm-state-color: rgb(var(--rgb-state-alarm-arming-color)); animation: pulse 1s infinite; } .pending { - --alarm-state-color: var(--alarm-color-pending); + --alarm-state-color: rgb(var(--rgb-state-alarm-pending-color)); animation: pulse 1s infinite; } diff --git a/src/panels/lovelace/cards/hui-button-card.ts b/src/panels/lovelace/cards/hui-button-card.ts index 3e274f957a..4686c82f50 100644 --- a/src/panels/lovelace/cards/hui-button-card.ts +++ b/src/panels/lovelace/cards/hui-button-card.ts @@ -26,7 +26,7 @@ import { computeStateDisplay } from "../../../common/entity/compute_state_displa import { computeStateDomain } from "../../../common/entity/compute_state_domain"; import { computeStateName } from "../../../common/entity/compute_state_name"; 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 { iconColorCSS } from "../../../common/style/icon_color_css"; import "../../../components/ha-card"; @@ -79,6 +79,15 @@ export class HuiButtonCard extends LitElement implements LovelaceCard { @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 { return ( (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 ? this._config.name || (stateObj ? computeStateName(stateObj) : "") : ""; - const domain = stateObj ? computeStateDomain(stateObj) : undefined; - const active = - (this._config.state_color || - (domain === "light" && this._config.state_color !== false)) && - stateObj && - stateActive(stateObj); + const active = stateObj && stateActive(stateObj); + const colored = active && this.getStateColor(stateObj, this._config); return html` @@ -163,6 +166,8 @@ export class HuiCalendarCard extends LitElement implements LovelaceCard { } private _handleViewChanged(ev: HASSDomEvent): void { + this._eventDisplay = + ev.detail.view === "dayGridMonth" ? "list-item" : "auto"; this._startDate = ev.detail.start; this._endDate = ev.detail.end; this._fetchCalendarEvents(); diff --git a/src/panels/lovelace/cards/hui-entity-card.ts b/src/panels/lovelace/cards/hui-entity-card.ts index 692d67b5ba..3b73f770c9 100644 --- a/src/panels/lovelace/cards/hui-entity-card.ts +++ b/src/panels/lovelace/cards/hui-entity-card.ts @@ -16,7 +16,7 @@ import { computeStateDisplay } from "../../../common/entity/compute_state_displa import { computeStateDomain } from "../../../common/entity/compute_state_domain"; import { computeStateName } from "../../../common/entity/compute_state_name"; 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 { formatNumber, @@ -76,6 +76,15 @@ export class HuiEntityCard extends LitElement implements LovelaceCard { 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 { if (!config.entity) { 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 active = - (this._config.state_color || - (domain === "light" && this._config.state_color !== false)) && - stateActive(stateObj); + const active = stateObj && stateActive(stateObj); + const colored = active && this.getStateColor(stateObj, this._config); return html` @@ -141,7 +148,7 @@ export class HuiEntityCard extends LitElement implements LovelaceCard { data-domain=${ifDefined(domain)} data-state=${stateObj.state} style=${styleMap({ - color: active ? this._computeColor(stateObj) : "", + color: colored ? this._computeColor(stateObj) : undefined, 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 { - const domain = computeStateDomain(stateObj); - if ( - !( - this._config?.state_color || - (domain === "light" && this._config?.state_color !== false) - ) || - !stateActive(stateObj) - ) { - return ""; - } - const iconColor = stateColor(stateObj); + private _computeColor( + stateObj: HassEntity | LightEntity + ): string | undefined { + const iconColor = stateColorCss(stateObj); if (iconColor) { - return `rgb(var(--rgb-state-${iconColor}-color))`; + return `rgb(${iconColor})`; } - return ""; + return undefined; } protected shouldUpdate(changedProps: PropertyValues): boolean { diff --git a/src/panels/lovelace/cards/hui-tile-card.ts b/src/panels/lovelace/cards/hui-tile-card.ts index 52c8b9b96a..17aea90e51 100644 --- a/src/panels/lovelace/cards/hui-tile-card.ts +++ b/src/panels/lovelace/cards/hui-tile-card.ts @@ -1,5 +1,5 @@ import { memoize } from "@fullcalendar/common"; -import { mdiHelp } from "@mdi/js"; +import { mdiExclamationThick, mdiHelp } from "@mdi/js"; import { HassEntity } from "home-assistant-js-websocket"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; 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 { computeDomain } from "../../../common/entity/compute_domain"; import { computeStateDisplay } from "../../../common/entity/compute_state_display"; -import { stateActive } from "../../../common/entity/state_active"; import { stateColorCss } from "../../../common/entity/state_color"; import { stateIconPath } from "../../../common/entity/state_icon_path"; 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) => { - if (UNAVAILABLE_STATES.includes(entity.state)) { - return undefined; + // Use custom color + if (color) { + return computeRgbColor(color); } // 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)"; } - if (!stateActive(entity)) { - return undefined; - } - - if (color) { - return computeRgbColor(color); - } - - let stateColor = stateColorCss(entity); - + // Use light color if the light support rgb if ( computeDomain(entity.entity_id) === "light" && entity.attributes.rgb_color @@ -166,10 +157,11 @@ export class HuiTileCard extends LitElement implements LovelaceCard { 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 { @@ -233,10 +225,21 @@ export class HuiTileCard extends LitElement implements LovelaceCard { if (!stateObj) { return html` - +
- + +
{ + 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]; areaCards.push( ...computeCards( @@ -506,13 +512,20 @@ export const generateDefaultViewConfig = ( ); } - areaCards.sort((a, b) => stringCompare(a.title || "", b.title || "")); - const deviceCards: LovelaceCardConfig[] = []; - for (const [deviceId, deviceEntities] of Object.entries( + const sortedDevices = Object.entries( 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]; deviceCards.push( ...computeCards( @@ -534,8 +547,6 @@ export const generateDefaultViewConfig = ( ); } - deviceCards.sort((a, b) => stringCompare(a.title || "", b.title || "")); - let energyCard: LovelaceCardConfig | undefined; if (energyPrefs) { diff --git a/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts index 0c19e9872d..89c2656cf3 100644 --- a/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts @@ -93,7 +93,7 @@ export class HuiGaugeCardEditor ...(showSeverity ? ([ { - name: "", + name: "severity", type: "grid", schema: [ { diff --git a/src/panels/lovelace/tile-features/hui-cover-open-close-tile-feature.ts b/src/panels/lovelace/tile-features/hui-cover-open-close-tile-feature.ts index 0c64f461b1..05d4e6dce7 100644 --- a/src/panels/lovelace/tile-features/hui-cover-open-close-tile-feature.ts +++ b/src/panels/lovelace/tile-features/hui-cover-open-close-tile-feature.ts @@ -86,15 +86,17 @@ class HuiCoverOpenCloseTileFeature ` : null} ${supportsFeature(this.stateObj, CoverEntityFeature.STOP) - ? html` - - ` + ? html` + + + + ` : null} ${supportsFeature(this.stateObj, CoverEntityFeature.CLOSE) ? html` diff --git a/src/panels/lovelace/tile-features/hui-cover-tilt-tile-feature.ts b/src/panels/lovelace/tile-features/hui-cover-tilt-tile-feature.ts index 314184c854..018a0fb307 100644 --- a/src/panels/lovelace/tile-features/hui-cover-tilt-tile-feature.ts +++ b/src/panels/lovelace/tile-features/hui-cover-tilt-tile-feature.ts @@ -80,15 +80,17 @@ class HuiCoverTiltTileFeature ` : null} ${supportsFeature(this.stateObj, CoverEntityFeature.STOP_TILT) - ? html` - - ` + ? html` + + + + ` : null} ${supportsFeature(this.stateObj, CoverEntityFeature.CLOSE_TILT) ? html` diff --git a/src/panels/lovelace/tile-features/hui-vacuum-commands-tile-feature.ts b/src/panels/lovelace/tile-features/hui-vacuum-commands-tile-feature.ts index d3f9565881..6c19958a77 100644 --- a/src/panels/lovelace/tile-features/hui-vacuum-commands-tile-feature.ts +++ b/src/panels/lovelace/tile-features/hui-vacuum-commands-tile-feature.ts @@ -40,7 +40,7 @@ export const VACUUM_COMMANDS_FEATURES: Record< VacuumCommand, VacuumEntityFeature[] > = { - start_pause: [VacuumEntityFeature.PAUSE], + start_pause: [VacuumEntityFeature.PAUSE, VacuumEntityFeature.START], stop: [VacuumEntityFeature.STOP], clean_spot: [VacuumEntityFeature.CLEAN_SPOT], locate: [VacuumEntityFeature.LOCATE], diff --git a/src/panels/profile/ha-pick-dashboard-row.ts b/src/panels/profile/ha-pick-dashboard-row.ts index 4b5d647002..39354f25bc 100644 --- a/src/panels/profile/ha-pick-dashboard-row.ts +++ b/src/panels/profile/ha-pick-dashboard-row.ts @@ -13,7 +13,7 @@ class HaPickDashboardRow extends LitElement { @property() public narrow!: boolean; - @state() private _dashboards: LovelaceDashboard[] = []; + @state() private _dashboards?: LovelaceDashboard[]; protected firstUpdated(changedProps: PropertyValues) { super.firstUpdated(changedProps); @@ -29,30 +29,37 @@ class HaPickDashboardRow extends LitElement { ${this.hass.localize("ui.panel.profile.dashboard.description")} - - - ${this.hass.localize( - "ui.panel.profile.dashboard.default_dashboard_label" - )} - - ${this._dashboards.map((dashboard) => { - if (!this.hass.user!.is_admin && dashboard.require_admin) { - return ""; - } - return html` - - ${dashboard.title} + ${this._dashboards + ? html` + + ${this.hass.localize( + "ui.panel.profile.dashboard.default_dashboard_label" + )} - `; - })} - + ${this._dashboards.map((dashboard) => { + if (!this.hass.user!.is_admin && dashboard.require_admin) { + return ""; + } + return html` + + ${dashboard.title} + + `; + })} + ` + : html``} `; } diff --git a/src/panels/profile/ha-pick-theme-row.ts b/src/panels/profile/ha-pick-theme-row.ts index 59d9774712..0dcdaca9dd 100644 --- a/src/panels/profile/ha-pick-theme-row.ts +++ b/src/panels/profile/ha-pick-theme-row.ts @@ -194,6 +194,10 @@ export class HaPickThemeRow extends LitElement { private _handleThemeSelection(ev) { const theme = ev.target.value; + if (theme === this.hass.selectedTheme?.theme) { + return; + } + if (theme === "Backend-selected") { if (this.hass.selectedTheme?.theme) { fireEvent(this, "settheme", { diff --git a/src/resources/ha-style.ts b/src/resources/ha-style.ts index 63ed84aa9a..07b2fbde32 100644 --- a/src/resources/ha-style.ts +++ b/src/resources/ha-style.ts @@ -134,24 +134,29 @@ documentContainer.innerHTML = ` --rgb-white-color: 255, 255, 255; /* rgb state color */ - --rgb-state-default-color: 68, 115, 158; - --rgb-state-alarm-armed-color: var(--rgb-red-color); + --rgb-state-default-color: var(--rgb-dark-primary-color, 68, 115, 158); + --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-disarmed-color: var(--rgb-grey-color); --rgb-state-alarm-pending-color: var(--rgb-orange-color); --rgb-state-alarm-triggered-color: var(--rgb-red-color); --rgb-state-alert-color: var(--rgb-red-color); --rgb-state-automation-color: var(--rgb-amber-color); --rgb-state-binary-sensor-alerting-color: var(--rgb-red-color); - --rgb-state-binary-sensor-color: var(--rgb-blue-color); - --rgb-state-calendar-color: var(--rgb-blue-color); - --rgb-state-camera-color: var(--rgb-blue-color); + --rgb-state-binary-sensor-color: var(--rgb-amber-color); + --rgb-state-calendar-color: var(--rgb-amber-color); + --rgb-state-camera-color: var(--rgb-amber-color); --rgb-state-climate-auto-color: var(--rgb-green-color); --rgb-state-climate-cool-color: var(--rgb-blue-color); --rgb-state-climate-dry-color: var(--rgb-orange-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-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-fan-color: var(--rgb-cyan-color); --rgb-state-group-color: var(--rgb-amber-color); @@ -159,17 +164,19 @@ documentContainer.innerHTML = ` --rgb-state-input-boolean-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-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-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-not-home-color: var(--rgb-grey-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-sensor-battery-high-color: var(--rgb-green-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-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-sun-day-color: var(--rgb-amber-color); --rgb-state-sun-night-color: var(--rgb-deep-purple-color); @@ -179,11 +186,6 @@ documentContainer.innerHTML = ` --rgb-state-update-installing-color: var(--rgb-orange-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-idle-line-color: rgba(0, 0, 0, 0.42); --input-hover-line-color: rgba(0, 0, 0, 0.87); diff --git a/src/resources/styles.ts b/src/resources/styles.ts index 83ddd066dc..3f18eb7445 100644 --- a/src/resources/styles.ts +++ b/src/resources/styles.ts @@ -48,7 +48,7 @@ export const darkStyles = { "energy-grid-return-color": "#a280db", "map-filter": "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 = { diff --git a/src/translations/en.json b/src/translations/en.json index 008434e0c5..aaa1798ded 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -3233,7 +3233,8 @@ "subscribe_to": "Topic to subscribe to", "start_listening": "Start 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": { "common": { @@ -4349,6 +4350,7 @@ "primary": "Primary", "accent": "Accent", "disabled": "Disabled", + "inactive": "Inactive", "red": "Red", "pink": "Pink", "purple": "Purple",