mirror of
https://github.com/home-assistant/frontend.git
synced 2025-12-23 08:27:36 +00:00
Compare commits
1 Commits
dev
...
disable-cr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
074fb1424a |
3
.coderabbit.yaml
Normal file
3
.coderabbit.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
issue_enrichment:
|
||||||
|
auto_enrich:
|
||||||
|
enabled: false
|
||||||
2
.github/copilot-instructions.md
vendored
2
.github/copilot-instructions.md
vendored
@@ -154,7 +154,7 @@ try {
|
|||||||
|
|
||||||
- **Use CSS custom properties**: Leverage the theme system
|
- **Use CSS custom properties**: Leverage the theme system
|
||||||
- **Use spacing tokens**: Prefer `--ha-space-*` tokens over hardcoded values for consistent spacing
|
- **Use spacing tokens**: Prefer `--ha-space-*` tokens over hardcoded values for consistent spacing
|
||||||
- Spacing scale: `--ha-space-1` (4px) through `--ha-space-20` (80px) in 4px increments
|
- Spacing scale: `--ha-space-0` (0px) through `--ha-space-20` (80px) in 4px increments
|
||||||
- Defined in `src/resources/theme/core.globals.ts`
|
- Defined in `src/resources/theme/core.globals.ts`
|
||||||
- Common values: `--ha-space-2` (8px), `--ha-space-4` (16px), `--ha-space-8` (32px)
|
- Common values: `--ha-space-2` (8px), `--ha-space-4` (16px), `--ha-space-8` (32px)
|
||||||
- **Mobile-first responsive**: Design for mobile, enhance for desktop
|
- **Mobile-first responsive**: Design for mobile, enhance for desktop
|
||||||
|
|||||||
6
.github/workflows/codeql-analysis.yml
vendored
6
.github/workflows/codeql-analysis.yml
vendored
@@ -36,14 +36,14 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
|
uses: github/codeql-action/init@1b168cd39490f61582a9beae412bb7057a6b2c4e # v4.31.8
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
|
uses: github/codeql-action/autobuild@1b168cd39490f61582a9beae412bb7057a6b2c4e # v4.31.8
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 https://git.io/JvXDl
|
# 📚 https://git.io/JvXDl
|
||||||
@@ -57,4 +57,4 @@ jobs:
|
|||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
|
uses: github/codeql-action/analyze@1b168cd39490f61582a9beae412bb7057a6b2c4e # v4.31.8
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
compressionLevel: mixed
|
compressionLevel: mixed
|
||||||
|
|
||||||
npmMinimalAgeGate: "3d"
|
|
||||||
|
|
||||||
defaultSemverRangePrefix: ""
|
defaultSemverRangePrefix: ""
|
||||||
|
|
||||||
enableGlobalCache: false
|
enableGlobalCache: false
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ module.exports.ignorePackages = () => [];
|
|||||||
// Files from NPM packages that we should replace with empty file
|
// Files from NPM packages that we should replace with empty file
|
||||||
module.exports.emptyPackages = ({ isHassioBuild, isLandingPageBuild }) =>
|
module.exports.emptyPackages = ({ isHassioBuild, isLandingPageBuild }) =>
|
||||||
[
|
[
|
||||||
|
require.resolve("@vaadin/vaadin-material-styles/typography.js"),
|
||||||
|
require.resolve("@vaadin/vaadin-material-styles/font-icons.js"),
|
||||||
// Icons in supervisor conflict with icons in HA so we don't load.
|
// Icons in supervisor conflict with icons in HA so we don't load.
|
||||||
(isHassioBuild || isLandingPageBuild) &&
|
(isHassioBuild || isLandingPageBuild) &&
|
||||||
require.resolve(
|
require.resolve(
|
||||||
|
|||||||
@@ -168,16 +168,12 @@ const createRspackConfig = ({
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
bundle.emptyPackages({ isHassioBuild, isLandingPageBuild }).length
|
new rspack.NormalModuleReplacementPlugin(
|
||||||
? new rspack.NormalModuleReplacementPlugin(
|
new RegExp(
|
||||||
new RegExp(
|
bundle.emptyPackages({ isHassioBuild, isLandingPageBuild }).join("|")
|
||||||
bundle
|
),
|
||||||
.emptyPackages({ isHassioBuild, isLandingPageBuild })
|
path.resolve(paths.root_dir, "src/util/empty.js")
|
||||||
.join("|")
|
),
|
||||||
),
|
|
||||||
path.resolve(paths.root_dir, "src/util/empty.js")
|
|
||||||
)
|
|
||||||
: false,
|
|
||||||
!isProdBuild && new LogStartCompilePlugin(),
|
!isProdBuild && new LogStartCompilePlugin(),
|
||||||
isProdBuild &&
|
isProdBuild &&
|
||||||
new StatsWriterPlugin({
|
new StatsWriterPlugin({
|
||||||
@@ -221,42 +217,6 @@ const createRspackConfig = ({
|
|||||||
"@lit-labs/virtualizer/polyfills/resize-observer-polyfill/ResizeObserver.js",
|
"@lit-labs/virtualizer/polyfills/resize-observer-polyfill/ResizeObserver.js",
|
||||||
"@lit-labs/observers/resize-controller":
|
"@lit-labs/observers/resize-controller":
|
||||||
"@lit-labs/observers/resize-controller.js",
|
"@lit-labs/observers/resize-controller.js",
|
||||||
"@formatjs/intl-durationformat/should-polyfill$":
|
|
||||||
"@formatjs/intl-durationformat/should-polyfill.js",
|
|
||||||
"@formatjs/intl-durationformat/polyfill-force$":
|
|
||||||
"@formatjs/intl-durationformat/polyfill-force.js",
|
|
||||||
"@formatjs/intl-datetimeformat/should-polyfill":
|
|
||||||
"@formatjs/intl-datetimeformat/should-polyfill.js",
|
|
||||||
"@formatjs/intl-datetimeformat/polyfill-force":
|
|
||||||
"@formatjs/intl-datetimeformat/polyfill-force.js",
|
|
||||||
"@formatjs/intl-displaynames/should-polyfill":
|
|
||||||
"@formatjs/intl-displaynames/should-polyfill.js",
|
|
||||||
"@formatjs/intl-displaynames/polyfill-force":
|
|
||||||
"@formatjs/intl-displaynames/polyfill-force.js",
|
|
||||||
"@formatjs/intl-getcanonicallocales/should-polyfill":
|
|
||||||
"@formatjs/intl-getcanonicallocales/should-polyfill.js",
|
|
||||||
"@formatjs/intl-getcanonicallocales/polyfill-force":
|
|
||||||
"@formatjs/intl-getcanonicallocales/polyfill-force.js",
|
|
||||||
"@formatjs/intl-listformat/should-polyfill":
|
|
||||||
"@formatjs/intl-listformat/should-polyfill.js",
|
|
||||||
"@formatjs/intl-listformat/polyfill-force":
|
|
||||||
"@formatjs/intl-listformat/polyfill-force.js",
|
|
||||||
"@formatjs/intl-locale/should-polyfill":
|
|
||||||
"@formatjs/intl-locale/should-polyfill.js",
|
|
||||||
"@formatjs/intl-locale/polyfill-force":
|
|
||||||
"@formatjs/intl-locale/polyfill-force.js",
|
|
||||||
"@formatjs/intl-numberformat/should-polyfill":
|
|
||||||
"@formatjs/intl-numberformat/should-polyfill.js",
|
|
||||||
"@formatjs/intl-numberformat/polyfill-force":
|
|
||||||
"@formatjs/intl-numberformat/polyfill-force.js",
|
|
||||||
"@formatjs/intl-pluralrules/should-polyfill":
|
|
||||||
"@formatjs/intl-pluralrules/should-polyfill.js",
|
|
||||||
"@formatjs/intl-pluralrules/polyfill-force":
|
|
||||||
"@formatjs/intl-pluralrules/polyfill-force.js",
|
|
||||||
"@formatjs/intl-relativetimeformat/should-polyfill":
|
|
||||||
"@formatjs/intl-relativetimeformat/should-polyfill.js",
|
|
||||||
"@formatjs/intl-relativetimeformat/polyfill-force":
|
|
||||||
"@formatjs/intl-relativetimeformat/polyfill-force.js",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
|
|||||||
@@ -40,9 +40,6 @@ const ENTITIES = [
|
|||||||
getEntity("switch", "coffee", "off", {
|
getEntity("switch", "coffee", "off", {
|
||||||
friendly_name: "Coffee",
|
friendly_name: "Coffee",
|
||||||
}),
|
}),
|
||||||
getEntity("number", "number", 5, {
|
|
||||||
friendly_name: "Number",
|
|
||||||
}),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const DEVICES: DeviceRegistryEntry[] = [
|
const DEVICES: DeviceRegistryEntry[] = [
|
||||||
@@ -380,33 +377,6 @@ const SCHEMAS: {
|
|||||||
name: "Constant",
|
name: "Constant",
|
||||||
selector: { constant: { value: true, label: "Yes!" } },
|
selector: { constant: { value: true, label: "Yes!" } },
|
||||||
},
|
},
|
||||||
choose: {
|
|
||||||
name: "Choose",
|
|
||||||
selector: {
|
|
||||||
choose: {
|
|
||||||
choices: {
|
|
||||||
number: {
|
|
||||||
selector: {
|
|
||||||
number: {
|
|
||||||
min: 0,
|
|
||||||
max: 100,
|
|
||||||
step: 0.1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
entity: {
|
|
||||||
selector: {
|
|
||||||
entity: {
|
|
||||||
filter: {
|
|
||||||
domain: "number",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
38
package.json
38
package.json
@@ -29,7 +29,7 @@
|
|||||||
"@babel/runtime": "7.28.4",
|
"@babel/runtime": "7.28.4",
|
||||||
"@braintree/sanitize-url": "7.1.1",
|
"@braintree/sanitize-url": "7.1.1",
|
||||||
"@codemirror/autocomplete": "6.20.0",
|
"@codemirror/autocomplete": "6.20.0",
|
||||||
"@codemirror/commands": "6.10.1",
|
"@codemirror/commands": "6.10.0",
|
||||||
"@codemirror/language": "6.11.3",
|
"@codemirror/language": "6.11.3",
|
||||||
"@codemirror/legacy-modes": "6.5.2",
|
"@codemirror/legacy-modes": "6.5.2",
|
||||||
"@codemirror/search": "6.5.11",
|
"@codemirror/search": "6.5.11",
|
||||||
@@ -37,15 +37,15 @@
|
|||||||
"@codemirror/view": "6.39.4",
|
"@codemirror/view": "6.39.4",
|
||||||
"@date-fns/tz": "1.4.1",
|
"@date-fns/tz": "1.4.1",
|
||||||
"@egjs/hammerjs": "2.0.17",
|
"@egjs/hammerjs": "2.0.17",
|
||||||
"@formatjs/intl-datetimeformat": "7.0.4",
|
"@formatjs/intl-datetimeformat": "6.18.2",
|
||||||
"@formatjs/intl-displaynames": "7.0.4",
|
"@formatjs/intl-displaynames": "6.8.13",
|
||||||
"@formatjs/intl-durationformat": "0.8.4",
|
"@formatjs/intl-durationformat": "0.7.6",
|
||||||
"@formatjs/intl-getcanonicallocales": "3.0.3",
|
"@formatjs/intl-getcanonicallocales": "2.5.6",
|
||||||
"@formatjs/intl-listformat": "8.0.4",
|
"@formatjs/intl-listformat": "7.7.13",
|
||||||
"@formatjs/intl-locale": "5.0.4",
|
"@formatjs/intl-locale": "4.2.13",
|
||||||
"@formatjs/intl-numberformat": "9.0.5",
|
"@formatjs/intl-numberformat": "8.15.6",
|
||||||
"@formatjs/intl-pluralrules": "6.0.4",
|
"@formatjs/intl-pluralrules": "5.4.6",
|
||||||
"@formatjs/intl-relativetimeformat": "12.0.5",
|
"@formatjs/intl-relativetimeformat": "11.4.13",
|
||||||
"@fullcalendar/core": "6.1.19",
|
"@fullcalendar/core": "6.1.19",
|
||||||
"@fullcalendar/daygrid": "6.1.19",
|
"@fullcalendar/daygrid": "6.1.19",
|
||||||
"@fullcalendar/interaction": "6.1.19",
|
"@fullcalendar/interaction": "6.1.19",
|
||||||
@@ -89,6 +89,8 @@
|
|||||||
"@thomasloven/round-slider": "0.6.0",
|
"@thomasloven/round-slider": "0.6.0",
|
||||||
"@tsparticles/engine": "3.9.1",
|
"@tsparticles/engine": "3.9.1",
|
||||||
"@tsparticles/preset-links": "3.2.0",
|
"@tsparticles/preset-links": "3.2.0",
|
||||||
|
"@vaadin/combo-box": "24.9.6",
|
||||||
|
"@vaadin/vaadin-themable-mixin": "24.9.6",
|
||||||
"@vibrant/color": "4.0.0",
|
"@vibrant/color": "4.0.0",
|
||||||
"@vue/web-component-wrapper": "1.3.0",
|
"@vue/web-component-wrapper": "1.3.0",
|
||||||
"@webcomponents/scoped-custom-element-registry": "0.0.10",
|
"@webcomponents/scoped-custom-element-registry": "0.0.10",
|
||||||
@@ -112,7 +114,7 @@
|
|||||||
"hls.js": "1.6.15",
|
"hls.js": "1.6.15",
|
||||||
"home-assistant-js-websocket": "9.6.0",
|
"home-assistant-js-websocket": "9.6.0",
|
||||||
"idb-keyval": "6.2.2",
|
"idb-keyval": "6.2.2",
|
||||||
"intl-messageformat": "11.0.4",
|
"intl-messageformat": "10.7.18",
|
||||||
"js-yaml": "4.1.1",
|
"js-yaml": "4.1.1",
|
||||||
"leaflet": "1.9.4",
|
"leaflet": "1.9.4",
|
||||||
"leaflet-draw": "patch:leaflet-draw@npm%3A1.0.4#./.yarn/patches/leaflet-draw-npm-1.0.4-0ca0ebcf65.patch",
|
"leaflet-draw": "patch:leaflet-draw@npm%3A1.0.4#./.yarn/patches/leaflet-draw-npm-1.0.4-0ca0ebcf65.patch",
|
||||||
@@ -151,12 +153,12 @@
|
|||||||
"@babel/plugin-transform-runtime": "7.28.5",
|
"@babel/plugin-transform-runtime": "7.28.5",
|
||||||
"@babel/preset-env": "7.28.5",
|
"@babel/preset-env": "7.28.5",
|
||||||
"@bundle-stats/plugin-webpack-filter": "4.21.7",
|
"@bundle-stats/plugin-webpack-filter": "4.21.7",
|
||||||
"@lokalise/node-api": "15.6.0",
|
"@lokalise/node-api": "15.4.0",
|
||||||
"@octokit/auth-oauth-device": "8.0.3",
|
"@octokit/auth-oauth-device": "8.0.3",
|
||||||
"@octokit/plugin-retry": "8.0.3",
|
"@octokit/plugin-retry": "8.0.3",
|
||||||
"@octokit/rest": "22.0.1",
|
"@octokit/rest": "22.0.1",
|
||||||
"@rsdoctor/rspack-plugin": "1.3.16",
|
"@rsdoctor/rspack-plugin": "1.3.16",
|
||||||
"@rspack/core": "1.6.8",
|
"@rspack/core": "1.6.7",
|
||||||
"@rspack/dev-server": "1.1.4",
|
"@rspack/dev-server": "1.1.4",
|
||||||
"@types/babel__plugin-transform-runtime": "7.9.5",
|
"@types/babel__plugin-transform-runtime": "7.9.5",
|
||||||
"@types/chromecast-caf-receiver": "6.0.25",
|
"@types/chromecast-caf-receiver": "6.0.25",
|
||||||
@@ -176,7 +178,7 @@
|
|||||||
"@types/tar": "6.1.13",
|
"@types/tar": "6.1.13",
|
||||||
"@types/ua-parser-js": "0.7.39",
|
"@types/ua-parser-js": "0.7.39",
|
||||||
"@types/webspeechapi": "0.0.29",
|
"@types/webspeechapi": "0.0.29",
|
||||||
"@vitest/coverage-v8": "4.0.16",
|
"@vitest/coverage-v8": "4.0.15",
|
||||||
"babel-loader": "10.0.0",
|
"babel-loader": "10.0.0",
|
||||||
"babel-plugin-template-html-minifier": "4.1.0",
|
"babel-plugin-template-html-minifier": "4.1.0",
|
||||||
"browserslist-useragent-regexp": "4.1.3",
|
"browserslist-useragent-regexp": "4.1.3",
|
||||||
@@ -191,7 +193,7 @@
|
|||||||
"eslint-plugin-unused-imports": "4.3.0",
|
"eslint-plugin-unused-imports": "4.3.0",
|
||||||
"eslint-plugin-wc": "3.0.2",
|
"eslint-plugin-wc": "3.0.2",
|
||||||
"fancy-log": "2.0.0",
|
"fancy-log": "2.0.0",
|
||||||
"fs-extra": "11.3.3",
|
"fs-extra": "11.3.2",
|
||||||
"glob": "13.0.0",
|
"glob": "13.0.0",
|
||||||
"gulp": "5.0.1",
|
"gulp": "5.0.1",
|
||||||
"gulp-brotli": "3.0.0",
|
"gulp-brotli": "3.0.0",
|
||||||
@@ -210,14 +212,14 @@
|
|||||||
"prettier": "3.7.4",
|
"prettier": "3.7.4",
|
||||||
"rspack-manifest-plugin": "5.2.0",
|
"rspack-manifest-plugin": "5.2.0",
|
||||||
"serve": "14.2.5",
|
"serve": "14.2.5",
|
||||||
"sinon": "21.0.1",
|
"sinon": "21.0.0",
|
||||||
"tar": "7.5.2",
|
"tar": "7.5.2",
|
||||||
"terser-webpack-plugin": "5.3.16",
|
"terser-webpack-plugin": "5.3.16",
|
||||||
"ts-lit-plugin": "2.0.2",
|
"ts-lit-plugin": "2.0.2",
|
||||||
"typescript": "5.9.3",
|
"typescript": "5.9.3",
|
||||||
"typescript-eslint": "8.50.0",
|
"typescript-eslint": "8.50.0",
|
||||||
"vite-tsconfig-paths": "6.0.3",
|
"vite-tsconfig-paths": "6.0.1",
|
||||||
"vitest": "4.0.16",
|
"vitest": "4.0.15",
|
||||||
"webpack-stats-plugin": "1.1.3",
|
"webpack-stats-plugin": "1.1.3",
|
||||||
"webpackbar": "7.0.0",
|
"webpackbar": "7.0.0",
|
||||||
"workbox-build": "patch:workbox-build@npm%3A7.1.1#~/.yarn/patches/workbox-build-npm-7.1.1-a854f3faae.patch"
|
"workbox-build": "patch:workbox-build@npm%3A7.1.1#~/.yarn/patches/workbox-build-npm-7.1.1-a854f3faae.patch"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { RenderItemFunction } from "@lit-labs/virtualizer/virtualize";
|
import type { ComboBoxLitRenderer } from "@vaadin/combo-box/lit";
|
||||||
import type { HassEntity } from "home-assistant-js-websocket";
|
import type { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { html, LitElement, nothing, type PropertyValues } from "lit";
|
import { html, LitElement, nothing, type PropertyValues } from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
@@ -162,7 +162,7 @@ export class HaDevicePicker extends LitElement {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
private _rowRenderer: RenderItemFunction<DevicePickerItem> = (item) => html`
|
private _rowRenderer: ComboBoxLitRenderer<DevicePickerItem> = (item) => html`
|
||||||
<ha-combo-box-item type="button">
|
<ha-combo-box-item type="button">
|
||||||
${item.domain
|
${item.domain
|
||||||
? html`
|
? html`
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { RenderItemFunction } from "@lit-labs/virtualizer/virtualize";
|
|
||||||
import { mdiPlus, mdiShape } from "@mdi/js";
|
import { mdiPlus, mdiShape } from "@mdi/js";
|
||||||
|
import type { ComboBoxLitRenderer } from "@vaadin/combo-box/lit";
|
||||||
import { html, LitElement, nothing, type PropertyValues } from "lit";
|
import { html, LitElement, nothing, type PropertyValues } from "lit";
|
||||||
import { customElement, property, query } from "lit/decorators";
|
import { customElement, property, query } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
@@ -172,9 +172,9 @@ export class HaEntityPicker extends LitElement {
|
|||||||
return this.showEntityId || this.hass.userData?.showEntityIdPicker;
|
return this.showEntityId || this.hass.userData?.showEntityIdPicker;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _rowRenderer: RenderItemFunction<EntityComboBoxItem> = (
|
private _rowRenderer: ComboBoxLitRenderer<EntityComboBoxItem> = (
|
||||||
item,
|
item,
|
||||||
index
|
{ index }
|
||||||
) => {
|
) => {
|
||||||
const showEntityId = this._showEntityId;
|
const showEntityId = this._showEntityId;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { RenderItemFunction } from "@lit-labs/virtualizer/virtualize";
|
|
||||||
import { mdiChartLine, mdiHelpCircle, mdiShape } from "@mdi/js";
|
import { mdiChartLine, mdiHelpCircle, mdiShape } from "@mdi/js";
|
||||||
|
import type { ComboBoxLitRenderer } from "@vaadin/combo-box/lit";
|
||||||
import type { HassEntity } from "home-assistant-js-websocket";
|
import type { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { html, LitElement, nothing, type PropertyValues } from "lit";
|
import { html, LitElement, nothing, type PropertyValues } from "lit";
|
||||||
import { customElement, property, query } from "lit/decorators";
|
import { customElement, property, query } from "lit/decorators";
|
||||||
@@ -424,9 +424,9 @@ export class HaStatisticPicker extends LitElement {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private _rowRenderer: RenderItemFunction<StatisticComboBoxItem> = (
|
private _rowRenderer: ComboBoxLitRenderer<StatisticComboBoxItem> = (
|
||||||
item,
|
item,
|
||||||
index
|
{ index }
|
||||||
) => {
|
) => {
|
||||||
const showEntityId = this.hass.userData?.showEntityIdPicker;
|
const showEntityId = this.hass.userData?.showEntityIdPicker;
|
||||||
return html`
|
return html`
|
||||||
@@ -473,7 +473,6 @@ export class HaStatisticPicker extends LitElement {
|
|||||||
.allowCustomValue=${this.allowCustomEntity}
|
.allowCustomValue=${this.allowCustomEntity}
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
.label=${this.label}
|
.label=${this.label}
|
||||||
use-top-label
|
|
||||||
.placeholder=${placeholder}
|
.placeholder=${placeholder}
|
||||||
.value=${this.value}
|
.value=${this.value}
|
||||||
.notFoundLabel=${this._notFoundLabel}
|
.notFoundLabel=${this._notFoundLabel}
|
||||||
|
|||||||
@@ -157,13 +157,7 @@ export class HaAdaptiveDialog extends LitElement {
|
|||||||
.headerSubtitlePosition=${this.headerSubtitlePosition}
|
.headerSubtitlePosition=${this.headerSubtitlePosition}
|
||||||
flexcontent
|
flexcontent
|
||||||
>
|
>
|
||||||
<slot name="headerNavigationIcon" slot="headerNavigationIcon">
|
<slot name="headerNavigationIcon" slot="headerNavigationIcon"></slot>
|
||||||
<ha-icon-button
|
|
||||||
data-dialog="close"
|
|
||||||
.label=${this.hass.localize("ui.common.close")}
|
|
||||||
.path=${mdiClose}
|
|
||||||
></ha-icon-button>
|
|
||||||
</slot>
|
|
||||||
<slot name="headerTitle" slot="headerTitle"></slot>
|
<slot name="headerTitle" slot="headerTitle"></slot>
|
||||||
<slot name="headerSubtitle" slot="headerSubtitle"></slot>
|
<slot name="headerSubtitle" slot="headerSubtitle"></slot>
|
||||||
<slot name="headerActionItems" slot="headerActionItems"></slot>
|
<slot name="headerActionItems" slot="headerActionItems"></slot>
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ export class HaAutomationRow extends LitElement {
|
|||||||
::slotted([slot="header"]) {
|
::slotted([slot="header"]) {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-wrap: anywhere;
|
overflow-wrap: anywhere;
|
||||||
margin: 0 var(--ha-space-3);
|
margin: var(--ha-space-0) var(--ha-space-3);
|
||||||
}
|
}
|
||||||
.icons {
|
.icons {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ export class HaBottomSheet extends ScrollableFadeMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
slot[name="footer"] {
|
slot[name="footer"] {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 0;
|
padding: var(--ha-space-0);
|
||||||
}
|
}
|
||||||
::slotted([slot="footer"]) {
|
::slotted([slot="footer"]) {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -46,14 +46,14 @@ export class HaCard extends LitElement {
|
|||||||
line-height: var(--ha-line-height-expanded);
|
line-height: var(--ha-line-height-expanded);
|
||||||
padding: var(--ha-space-3) var(--ha-space-4) var(--ha-space-4);
|
padding: var(--ha-space-3) var(--ha-space-4) var(--ha-space-4);
|
||||||
display: block;
|
display: block;
|
||||||
margin-block-start: 0;
|
margin-block-start: var(--ha-space-0);
|
||||||
margin-block-end: 0;
|
margin-block-end: var(--ha-space-0);
|
||||||
font-weight: var(--ha-font-weight-normal);
|
font-weight: var(--ha-font-weight-normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
:host ::slotted(.card-content:not(:first-child)),
|
:host ::slotted(.card-content:not(:first-child)),
|
||||||
slot:not(:first-child)::slotted(.card-content) {
|
slot:not(:first-child)::slotted(.card-content) {
|
||||||
padding-top: 0;
|
padding-top: var(--ha-space-0);
|
||||||
margin-top: calc(var(--ha-space-2) * -1);
|
margin-top: calc(var(--ha-space-2) * -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
433
src/components/ha-combo-box.ts
Normal file
433
src/components/ha-combo-box.ts
Normal file
@@ -0,0 +1,433 @@
|
|||||||
|
import { mdiClose, mdiMenuDown, mdiMenuUp } from "@mdi/js";
|
||||||
|
import type { ComboBoxLitRenderer } from "@vaadin/combo-box/lit";
|
||||||
|
import { comboBoxRenderer } from "@vaadin/combo-box/lit";
|
||||||
|
import "@vaadin/combo-box/theme/material/vaadin-combo-box-light";
|
||||||
|
import type {
|
||||||
|
ComboBoxDataProvider,
|
||||||
|
ComboBoxLight,
|
||||||
|
ComboBoxLightFilterChangedEvent,
|
||||||
|
ComboBoxLightOpenedChangedEvent,
|
||||||
|
ComboBoxLightValueChangedEvent,
|
||||||
|
} from "@vaadin/combo-box/vaadin-combo-box-light";
|
||||||
|
import { registerStyles } from "@vaadin/vaadin-themable-mixin/register-styles";
|
||||||
|
import type { TemplateResult } from "lit";
|
||||||
|
import { css, html, LitElement } from "lit";
|
||||||
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
|
import { ifDefined } from "lit/directives/if-defined";
|
||||||
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
|
import type { HomeAssistant } from "../types";
|
||||||
|
import "./ha-combo-box-item";
|
||||||
|
import "./ha-combo-box-textfield";
|
||||||
|
import "./ha-icon-button";
|
||||||
|
import "./ha-input-helper-text";
|
||||||
|
import "./ha-textfield";
|
||||||
|
import type { HaTextField } from "./ha-textfield";
|
||||||
|
|
||||||
|
registerStyles(
|
||||||
|
"vaadin-combo-box-item",
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
:host([focused]:not([disabled])) {
|
||||||
|
background-color: rgba(var(--rgb-primary-text-color, 0, 0, 0), 0.12);
|
||||||
|
}
|
||||||
|
:host([selected]:not([disabled])) {
|
||||||
|
background-color: transparent;
|
||||||
|
color: var(--mdc-theme-primary);
|
||||||
|
--mdc-ripple-color: var(--mdc-theme-primary);
|
||||||
|
--mdc-theme-text-primary-on-background: var(--mdc-theme-primary);
|
||||||
|
}
|
||||||
|
:host([selected]:not([disabled])):before {
|
||||||
|
background-color: var(--mdc-theme-primary);
|
||||||
|
opacity: 0.12;
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
:host([selected][focused]:not([disabled])):before {
|
||||||
|
opacity: 0.24;
|
||||||
|
}
|
||||||
|
:host(:hover:not([disabled])) {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
[part="content"] {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
[part="checkmark"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
@customElement("ha-combo-box")
|
||||||
|
export class HaComboBox extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public label?: string;
|
||||||
|
|
||||||
|
@property() public value?: string;
|
||||||
|
|
||||||
|
@property() public placeholder?: string;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public validationMessage?: string;
|
||||||
|
|
||||||
|
@property() public helper?: string;
|
||||||
|
|
||||||
|
@property({ attribute: "error-message" }) public errorMessage?: string;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public invalid = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public icon = false;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public items?: any[];
|
||||||
|
|
||||||
|
@property({ attribute: false }) public filteredItems?: any[];
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
public dataProvider?: ComboBoxDataProvider<any>;
|
||||||
|
|
||||||
|
@property({ attribute: "allow-custom-value", type: Boolean })
|
||||||
|
public allowCustomValue = false;
|
||||||
|
|
||||||
|
@property({ attribute: "item-value-path" }) public itemValuePath = "value";
|
||||||
|
|
||||||
|
@property({ attribute: "item-label-path" }) public itemLabelPath = "label";
|
||||||
|
|
||||||
|
@property({ attribute: "item-id-path" }) public itemIdPath?: string;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public renderer?: ComboBoxLitRenderer<any>;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public disabled = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public required = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean, reflect: true }) public opened = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean, attribute: "hide-clear-icon" })
|
||||||
|
public hideClearIcon = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean, attribute: "clear-initial-value" })
|
||||||
|
public clearInitialValue = false;
|
||||||
|
|
||||||
|
@query("vaadin-combo-box-light", true) private _comboBox!: ComboBoxLight;
|
||||||
|
|
||||||
|
@query("ha-combo-box-textfield", true) private _inputElement!: HaTextField;
|
||||||
|
|
||||||
|
@state({ type: Boolean }) private _forceBlankValue = false;
|
||||||
|
|
||||||
|
private _overlayMutationObserver?: MutationObserver;
|
||||||
|
|
||||||
|
private _bodyMutationObserver?: MutationObserver;
|
||||||
|
|
||||||
|
public async open() {
|
||||||
|
await this.updateComplete;
|
||||||
|
this._comboBox?.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async focus() {
|
||||||
|
await this.updateComplete;
|
||||||
|
await this._inputElement?.updateComplete;
|
||||||
|
this._inputElement?.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public disconnectedCallback() {
|
||||||
|
super.disconnectedCallback();
|
||||||
|
if (this._overlayMutationObserver) {
|
||||||
|
this._overlayMutationObserver.disconnect();
|
||||||
|
this._overlayMutationObserver = undefined;
|
||||||
|
}
|
||||||
|
if (this._bodyMutationObserver) {
|
||||||
|
this._bodyMutationObserver.disconnect();
|
||||||
|
this._bodyMutationObserver = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get selectedItem() {
|
||||||
|
return this._comboBox.selectedItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setInputValue(value: string) {
|
||||||
|
this._comboBox.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setTextFieldValue(value: string) {
|
||||||
|
this._inputElement.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<!-- @ts-ignore Tag definition is not included in theme folder -->
|
||||||
|
<vaadin-combo-box-light
|
||||||
|
.itemValuePath=${this.itemValuePath}
|
||||||
|
.itemIdPath=${this.itemIdPath}
|
||||||
|
.itemLabelPath=${this.itemLabelPath}
|
||||||
|
.items=${this.items}
|
||||||
|
.value=${this.value || ""}
|
||||||
|
.filteredItems=${this.filteredItems}
|
||||||
|
.dataProvider=${this.dataProvider}
|
||||||
|
.allowCustomValue=${this.allowCustomValue}
|
||||||
|
.disabled=${this.disabled}
|
||||||
|
.required=${this.required}
|
||||||
|
${comboBoxRenderer(this.renderer || this._defaultRowRenderer)}
|
||||||
|
@opened-changed=${this._openedChanged}
|
||||||
|
@filter-changed=${this._filterChanged}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
attr-for-value="value"
|
||||||
|
>
|
||||||
|
<ha-combo-box-textfield
|
||||||
|
label=${ifDefined(this.label)}
|
||||||
|
placeholder=${ifDefined(this.placeholder)}
|
||||||
|
?disabled=${this.disabled}
|
||||||
|
?required=${this.required}
|
||||||
|
validationMessage=${ifDefined(this.validationMessage)}
|
||||||
|
.errorMessage=${this.errorMessage}
|
||||||
|
class="input"
|
||||||
|
autocapitalize="none"
|
||||||
|
autocomplete="off"
|
||||||
|
.autocorrect=${false}
|
||||||
|
input-spellcheck="false"
|
||||||
|
.suffix=${html`<div
|
||||||
|
style="width: 28px;"
|
||||||
|
role="none presentation"
|
||||||
|
></div>`}
|
||||||
|
.icon=${this.icon}
|
||||||
|
.invalid=${this.invalid}
|
||||||
|
.forceBlankValue=${this._forceBlankValue}
|
||||||
|
>
|
||||||
|
<slot name="icon" slot="leadingIcon"></slot>
|
||||||
|
</ha-combo-box-textfield>
|
||||||
|
${this.value && !this.hideClearIcon
|
||||||
|
? html`<ha-svg-icon
|
||||||
|
role="button"
|
||||||
|
tabindex="-1"
|
||||||
|
aria-label=${ifDefined(this.hass?.localize("ui.common.clear"))}
|
||||||
|
class=${`clear-button ${this.label ? "" : "no-label"}`}
|
||||||
|
.path=${mdiClose}
|
||||||
|
?disabled=${this.disabled}
|
||||||
|
@click=${this._clearValue}
|
||||||
|
></ha-svg-icon>`
|
||||||
|
: ""}
|
||||||
|
<ha-svg-icon
|
||||||
|
role="button"
|
||||||
|
tabindex="-1"
|
||||||
|
aria-label=${ifDefined(this.label)}
|
||||||
|
aria-expanded=${this.opened ? "true" : "false"}
|
||||||
|
class=${`toggle-button ${this.label ? "" : "no-label"}`}
|
||||||
|
.path=${this.opened ? mdiMenuUp : mdiMenuDown}
|
||||||
|
?disabled=${this.disabled}
|
||||||
|
@click=${this._toggleOpen}
|
||||||
|
></ha-svg-icon>
|
||||||
|
</vaadin-combo-box-light>
|
||||||
|
${this._renderHelper()}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _renderHelper() {
|
||||||
|
return this.helper
|
||||||
|
? html`<ha-input-helper-text .disabled=${this.disabled}
|
||||||
|
>${this.helper}</ha-input-helper-text
|
||||||
|
>`
|
||||||
|
: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private _defaultRowRenderer: ComboBoxLitRenderer<
|
||||||
|
string | Record<string, any>
|
||||||
|
> = (item) => html`
|
||||||
|
<ha-combo-box-item type="button">
|
||||||
|
${this.itemLabelPath ? item[this.itemLabelPath] : item}
|
||||||
|
</ha-combo-box-item>
|
||||||
|
`;
|
||||||
|
|
||||||
|
private _clearValue(ev: Event) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
fireEvent(this, "value-changed", { value: undefined });
|
||||||
|
}
|
||||||
|
|
||||||
|
private _toggleOpen(ev: Event) {
|
||||||
|
if (this.opened) {
|
||||||
|
this._comboBox?.close();
|
||||||
|
ev.stopPropagation();
|
||||||
|
} else {
|
||||||
|
this._comboBox?.inputElement.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _openedChanged(ev: ComboBoxLightOpenedChangedEvent) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
const opened = ev.detail.value;
|
||||||
|
// delay this so we can handle click event for toggle button before setting _opened
|
||||||
|
setTimeout(() => {
|
||||||
|
this.opened = opened;
|
||||||
|
fireEvent(this, "opened-changed", { value: ev.detail.value });
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
if (this.clearInitialValue) {
|
||||||
|
this.setTextFieldValue("");
|
||||||
|
if (opened) {
|
||||||
|
// Wait 100ms to be sure vaddin-combo-box-light already tried to set the value
|
||||||
|
setTimeout(() => {
|
||||||
|
this._forceBlankValue = false;
|
||||||
|
}, 100);
|
||||||
|
} else {
|
||||||
|
this._forceBlankValue = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opened) {
|
||||||
|
const overlay = document.querySelector<HTMLElement>(
|
||||||
|
"vaadin-combo-box-overlay"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (overlay) {
|
||||||
|
this._removeInert(overlay);
|
||||||
|
}
|
||||||
|
this._observeBody();
|
||||||
|
} else {
|
||||||
|
this._bodyMutationObserver?.disconnect();
|
||||||
|
this._bodyMutationObserver = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _observeBody() {
|
||||||
|
if ("MutationObserver" in window && !this._bodyMutationObserver) {
|
||||||
|
this._bodyMutationObserver = new MutationObserver((mutations) => {
|
||||||
|
mutations.forEach((mutation) => {
|
||||||
|
mutation.addedNodes.forEach((node) => {
|
||||||
|
if (node.nodeName === "VAADIN-COMBO-BOX-OVERLAY") {
|
||||||
|
this._removeInert(node as HTMLElement);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mutation.removedNodes.forEach((node) => {
|
||||||
|
if (node.nodeName === "VAADIN-COMBO-BOX-OVERLAY") {
|
||||||
|
this._overlayMutationObserver?.disconnect();
|
||||||
|
this._overlayMutationObserver = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this._bodyMutationObserver.observe(document.body, {
|
||||||
|
childList: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _removeInert(overlay: HTMLElement) {
|
||||||
|
if (overlay.inert) {
|
||||||
|
overlay.inert = false;
|
||||||
|
this._overlayMutationObserver?.disconnect();
|
||||||
|
this._overlayMutationObserver = undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ("MutationObserver" in window && !this._overlayMutationObserver) {
|
||||||
|
this._overlayMutationObserver = new MutationObserver((mutations) => {
|
||||||
|
mutations.forEach((mutation) => {
|
||||||
|
if (mutation.attributeName === "inert") {
|
||||||
|
const target = mutation.target as HTMLElement;
|
||||||
|
if (target.inert) {
|
||||||
|
this._overlayMutationObserver?.disconnect();
|
||||||
|
this._overlayMutationObserver = undefined;
|
||||||
|
target.inert = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this._overlayMutationObserver.observe(overlay, {
|
||||||
|
attributes: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _filterChanged(ev: ComboBoxLightFilterChangedEvent) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
fireEvent(this, "filter-changed", { value: ev.detail.value });
|
||||||
|
}
|
||||||
|
|
||||||
|
private _valueChanged(ev: ComboBoxLightValueChangedEvent) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
if (!this.allowCustomValue) {
|
||||||
|
// @ts-ignore
|
||||||
|
this._comboBox._closeOnBlurIsPrevented = true;
|
||||||
|
}
|
||||||
|
if (!this.opened) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const newValue = ev.detail.value;
|
||||||
|
if (newValue !== this.value) {
|
||||||
|
fireEvent(this, "value-changed", { value: newValue || undefined });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
vaadin-combo-box-light {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
ha-combo-box-textfield {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
ha-combo-box-textfield > ha-icon-button {
|
||||||
|
--mdc-icon-button-size: 24px;
|
||||||
|
padding: 2px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
ha-svg-icon {
|
||||||
|
color: var(--input-dropdown-icon-color);
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.toggle-button {
|
||||||
|
right: 12px;
|
||||||
|
top: -10px;
|
||||||
|
inset-inline-start: initial;
|
||||||
|
inset-inline-end: 12px;
|
||||||
|
direction: var(--direction);
|
||||||
|
}
|
||||||
|
:host([opened]) .toggle-button {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
.toggle-button[disabled],
|
||||||
|
.clear-button[disabled] {
|
||||||
|
color: var(--disabled-text-color);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.toggle-button.no-label {
|
||||||
|
top: -3px;
|
||||||
|
}
|
||||||
|
.clear-button {
|
||||||
|
--mdc-icon-size: 20px;
|
||||||
|
top: -7px;
|
||||||
|
right: 36px;
|
||||||
|
inset-inline-start: initial;
|
||||||
|
inset-inline-end: 36px;
|
||||||
|
direction: var(--direction);
|
||||||
|
}
|
||||||
|
.clear-button.no-label {
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
ha-input-helper-text {
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-combo-box": HaComboBox;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HASSDomEvents {
|
||||||
|
"filter-changed": { value: string };
|
||||||
|
"opened-changed": { value: boolean };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -101,13 +101,14 @@ export class HaDialog extends DialogBase {
|
|||||||
}
|
}
|
||||||
.mdc-dialog__container {
|
.mdc-dialog__container {
|
||||||
align-items: var(--vertical-align-dialog, center);
|
align-items: var(--vertical-align-dialog, center);
|
||||||
padding: var(--dialog-container-padding, 0);
|
padding: var(--dialog-container-padding, var(--ha-space-0));
|
||||||
}
|
}
|
||||||
.mdc-dialog__title {
|
.mdc-dialog__title {
|
||||||
padding: var(--ha-space-4) var(--ha-space-4) 0 var(--ha-space-4);
|
padding: var(--ha-space-4) var(--ha-space-4) var(--ha-space-0)
|
||||||
|
var(--ha-space-4);
|
||||||
}
|
}
|
||||||
.mdc-dialog__title:has(span) {
|
.mdc-dialog__title:has(span) {
|
||||||
padding: var(--ha-space-3) var(--ha-space-3) 0;
|
padding: var(--ha-space-3) var(--ha-space-3) var(--ha-space-0);
|
||||||
}
|
}
|
||||||
.mdc-dialog__title::before {
|
.mdc-dialog__title::before {
|
||||||
content: unset;
|
content: unset;
|
||||||
@@ -135,7 +136,7 @@ export class HaDialog extends DialogBase {
|
|||||||
--ha-dialog-surface-background,
|
--ha-dialog-surface-background,
|
||||||
var(--mdc-theme-surface, #fff)
|
var(--mdc-theme-surface, #fff)
|
||||||
);
|
);
|
||||||
padding: var(--dialog-surface-padding, 0);
|
padding: var(--dialog-surface-padding, var(--ha-space-0));
|
||||||
}
|
}
|
||||||
:host([flexContent]) .mdc-dialog .mdc-dialog__content {
|
:host([flexContent]) .mdc-dialog .mdc-dialog__content {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -167,7 +168,7 @@ export class HaDialog extends DialogBase {
|
|||||||
}
|
}
|
||||||
.dialog-actions {
|
.dialog-actions {
|
||||||
inset-inline-start: initial !important;
|
inset-inline-start: initial !important;
|
||||||
inset-inline-end: 0 !important;
|
inset-inline-end: var(--ha-space-0) !important;
|
||||||
direction: var(--direction);
|
direction: var(--direction);
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { RenderItemFunction } from "@lit-labs/virtualizer/virtualize";
|
|
||||||
import { mdiPlus, mdiTextureBox } from "@mdi/js";
|
import { mdiPlus, mdiTextureBox } from "@mdi/js";
|
||||||
|
import type { ComboBoxLitRenderer } from "@vaadin/combo-box/lit";
|
||||||
import type { HassEntity } from "home-assistant-js-websocket";
|
import type { HassEntity } from "home-assistant-js-websocket";
|
||||||
import type { TemplateResult } from "lit";
|
import type { TemplateResult } from "lit";
|
||||||
import { LitElement, html } from "lit";
|
import { LitElement, html } from "lit";
|
||||||
@@ -303,7 +303,7 @@ export class HaFloorPicker extends LitElement {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
private _rowRenderer: RenderItemFunction<FloorComboBoxItem> = (item) => html`
|
private _rowRenderer: ComboBoxLitRenderer<FloorComboBoxItem> = (item) => html`
|
||||||
<ha-combo-box-item type="button" compact>
|
<ha-combo-box-item type="button" compact>
|
||||||
${item.icon_path
|
${item.icon_path
|
||||||
? html`
|
? html`
|
||||||
|
|||||||
@@ -393,7 +393,7 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wa-popover {
|
wa-popover {
|
||||||
--wa-space-l: 0;
|
--wa-space-l: var(--ha-space-0);
|
||||||
}
|
}
|
||||||
|
|
||||||
wa-popover::part(body) {
|
wa-popover::part(body) {
|
||||||
@@ -418,7 +418,7 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
|
|||||||
--ha-bottom-sheet-height: calc(100dvh - var(--ha-space-12));
|
--ha-bottom-sheet-height: calc(100dvh - var(--ha-space-12));
|
||||||
--ha-bottom-sheet-max-height: var(--ha-bottom-sheet-height);
|
--ha-bottom-sheet-max-height: var(--ha-bottom-sheet-height);
|
||||||
--ha-bottom-sheet-max-width: 600px;
|
--ha-bottom-sheet-max-width: 600px;
|
||||||
--ha-bottom-sheet-padding: 0;
|
--ha-bottom-sheet-padding: var(--ha-space-0);
|
||||||
--ha-bottom-sheet-surface-background: var(--card-background-color);
|
--ha-bottom-sheet-surface-background: var(--card-background-color);
|
||||||
--ha-bottom-sheet-border-radius: var(--ha-border-radius-2xl);
|
--ha-bottom-sheet-border-radius: var(--ha-border-radius-2xl);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -175,10 +175,10 @@ export class HaMdDialog extends Dialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
margin-top: var(--safe-area-inset-top, 0);
|
margin-top: var(--safe-area-inset-top, var(--ha-space-0));
|
||||||
margin-bottom: var(--safe-area-inset-bottom, 0);
|
margin-bottom: var(--safe-area-inset-bottom, var(--ha-space-0));
|
||||||
margin-left: var(--safe-area-inset-left, 0);
|
margin-left: var(--safe-area-inset-left, var(--ha-space-0));
|
||||||
margin-right: var(--safe-area-inset-right, 0);
|
margin-right: var(--safe-area-inset-right, var(--ha-space-0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,202 +0,0 @@
|
|||||||
import type { PropertyValues } from "lit";
|
|
||||||
import { css, html, LitElement, nothing } from "lit";
|
|
||||||
import { customElement, property, state } from "lit/decorators";
|
|
||||||
import memoizeOne from "memoize-one";
|
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
|
||||||
import { isTemplate } from "../../common/string/has-template";
|
|
||||||
import type { ChooseSelector, Selector } from "../../data/selector";
|
|
||||||
import type { HomeAssistant } from "../../types";
|
|
||||||
import "../ha-button-toggle-group";
|
|
||||||
import "./ha-selector";
|
|
||||||
|
|
||||||
@customElement("ha-selector-choose")
|
|
||||||
export class HaChooseSelector extends LitElement {
|
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
|
||||||
|
|
||||||
@property({ attribute: false }) public selector!: ChooseSelector;
|
|
||||||
|
|
||||||
@property() public value?: any;
|
|
||||||
|
|
||||||
@property() public label?: string;
|
|
||||||
|
|
||||||
@property() public helper?: string;
|
|
||||||
|
|
||||||
@property({ attribute: false })
|
|
||||||
public localizeValue?: (key: string) => string;
|
|
||||||
|
|
||||||
@property({ type: Boolean }) public disabled = false;
|
|
||||||
|
|
||||||
@property({ type: Boolean }) public required = true;
|
|
||||||
|
|
||||||
@state() public _activeChoice?: string;
|
|
||||||
|
|
||||||
protected willUpdate(changedProperties: PropertyValues): void {
|
|
||||||
if (
|
|
||||||
changedProperties.has("selector") &&
|
|
||||||
(!this._activeChoice ||
|
|
||||||
!(this._activeChoice in this.selector.choose.choices))
|
|
||||||
) {
|
|
||||||
this._setActiveChoice();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render() {
|
|
||||||
if (!this._activeChoice) {
|
|
||||||
return nothing;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selector = this._selector(this._activeChoice);
|
|
||||||
const value = this._value(this._activeChoice);
|
|
||||||
|
|
||||||
return html`<div class="multi-header">
|
|
||||||
<span>${this.label}${this.required ? "*" : ""}</span>
|
|
||||||
<ha-button-toggle-group
|
|
||||||
size="small"
|
|
||||||
.buttons=${this._toggleButtons(
|
|
||||||
this.selector.choose.choices,
|
|
||||||
this.selector.choose.translation_key
|
|
||||||
)}
|
|
||||||
.active=${this._activeChoice}
|
|
||||||
@value-changed=${this._choiceChanged}
|
|
||||||
></ha-button-toggle-group>
|
|
||||||
</div>
|
|
||||||
<ha-selector
|
|
||||||
.hass=${this.hass}
|
|
||||||
.selector=${selector}
|
|
||||||
.value=${value}
|
|
||||||
.disabled=${this.disabled}
|
|
||||||
.required=${this.required}
|
|
||||||
@value-changed=${this._handleValueChanged}
|
|
||||||
.helper=${this.helper}
|
|
||||||
></ha-selector>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _toggleButtons = memoizeOne(
|
|
||||||
(choices: ChooseSelector["choose"]["choices"], translationKey?: string) =>
|
|
||||||
Object.keys(choices).map((choice) => ({
|
|
||||||
label:
|
|
||||||
this.localizeValue && translationKey
|
|
||||||
? this.localizeValue(`${translationKey}.choices.${choice}`)
|
|
||||||
: choice,
|
|
||||||
value: choice,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
|
|
||||||
private _choiceChanged(ev) {
|
|
||||||
ev.stopPropagation();
|
|
||||||
const value =
|
|
||||||
typeof this.value === "object"
|
|
||||||
? this.value
|
|
||||||
: {
|
|
||||||
[this._activeChoice!]: this.value,
|
|
||||||
};
|
|
||||||
this._activeChoice = ev.detail?.value || ev.target.value;
|
|
||||||
fireEvent(this, "value-changed", {
|
|
||||||
value: {
|
|
||||||
...value,
|
|
||||||
active_choice: this._activeChoice,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _handleValueChanged(ev: CustomEvent) {
|
|
||||||
ev.stopPropagation();
|
|
||||||
const value = typeof this.value === "object" ? this.value : {};
|
|
||||||
fireEvent(this, "value-changed", {
|
|
||||||
value: {
|
|
||||||
...value,
|
|
||||||
[this._activeChoice!]: ev.detail.value,
|
|
||||||
active_choice: this._activeChoice,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _selector(choice?: string): Selector {
|
|
||||||
const choices = this.selector.choose.choices;
|
|
||||||
|
|
||||||
choice = choice || this.value?.active_choice;
|
|
||||||
|
|
||||||
if (choice && choice in choices) {
|
|
||||||
return choices[choice].selector;
|
|
||||||
}
|
|
||||||
|
|
||||||
return choices[Object.keys(choices)[0]].selector;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _value(choice?: string): any {
|
|
||||||
if (!this.value) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return typeof this.value === "object"
|
|
||||||
? this.value[choice || this.value.active_choice]
|
|
||||||
: this.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _setActiveChoice() {
|
|
||||||
if (this.value) {
|
|
||||||
if (typeof this.value === "object") {
|
|
||||||
if (this.value.active_choice in this.selector.choose.choices) {
|
|
||||||
this._activeChoice = this.value.active_choice;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const typeofValue = typeof this.value;
|
|
||||||
const selectorTypes = Object.values(this.selector.choose.choices).map(
|
|
||||||
(choice) => Object.keys(choice.selector)[0]
|
|
||||||
);
|
|
||||||
if (typeofValue === "number" && selectorTypes.includes("number")) {
|
|
||||||
this._activeChoice = Object.keys(this.selector.choose.choices)[
|
|
||||||
selectorTypes.indexOf("number")
|
|
||||||
];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
typeofValue === "string" &&
|
|
||||||
isTemplate(this.value) &&
|
|
||||||
selectorTypes.includes("template")
|
|
||||||
) {
|
|
||||||
this._activeChoice = Object.keys(this.selector.choose.choices)[
|
|
||||||
selectorTypes.indexOf("template")
|
|
||||||
];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
typeofValue === "string" &&
|
|
||||||
this.value.includes(".") &&
|
|
||||||
selectorTypes.includes("entity")
|
|
||||||
) {
|
|
||||||
this._activeChoice = Object.keys(this.selector.choose.choices)[
|
|
||||||
selectorTypes.indexOf("entity")
|
|
||||||
];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (typeofValue === "string" && selectorTypes.includes("text")) {
|
|
||||||
this._activeChoice = Object.keys(this.selector.choose.choices)[
|
|
||||||
selectorTypes.indexOf("text")
|
|
||||||
];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this._activeChoice = Object.keys(this.selector.choose.choices)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
static styles = css`
|
|
||||||
.multi-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: var(--ha-space-2);
|
|
||||||
}
|
|
||||||
ha-button-toggle-group {
|
|
||||||
display: block;
|
|
||||||
justify-self: end;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"ha-selector-choose": HaChooseSelector;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -18,7 +18,6 @@ const LOAD_ELEMENTS = {
|
|||||||
attribute: () => import("./ha-selector-attribute"),
|
attribute: () => import("./ha-selector-attribute"),
|
||||||
assist_pipeline: () => import("./ha-selector-assist-pipeline"),
|
assist_pipeline: () => import("./ha-selector-assist-pipeline"),
|
||||||
boolean: () => import("./ha-selector-boolean"),
|
boolean: () => import("./ha-selector-boolean"),
|
||||||
choose: () => import("./ha-selector-choose"),
|
|
||||||
color_rgb: () => import("./ha-selector-color-rgb"),
|
color_rgb: () => import("./ha-selector-color-rgb"),
|
||||||
condition: () => import("./ha-selector-condition"),
|
condition: () => import("./ha-selector-condition"),
|
||||||
config_entry: () => import("./ha-selector-config-entry"),
|
config_entry: () => import("./ha-selector-config-entry"),
|
||||||
|
|||||||
@@ -726,7 +726,6 @@ export class HaServiceControl extends LitElement {
|
|||||||
: undefined}
|
: undefined}
|
||||||
.placeholder=${dataField.default}
|
.placeholder=${dataField.default}
|
||||||
.localizeValue=${this._localizeValueCallback}
|
.localizeValue=${this._localizeValueCallback}
|
||||||
.required=${dataField.required}
|
|
||||||
></ha-selector>
|
></ha-selector>
|
||||||
</ha-settings-row>`
|
</ha-settings-row>`
|
||||||
: "";
|
: "";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { RenderItemFunction } from "@lit-labs/virtualizer/virtualize";
|
|
||||||
import { mdiRoomService } from "@mdi/js";
|
import { mdiRoomService } from "@mdi/js";
|
||||||
|
import type { ComboBoxLitRenderer } from "@vaadin/combo-box/lit";
|
||||||
import { html, LitElement, nothing, type TemplateResult } from "lit";
|
import { html, LitElement, nothing, type TemplateResult } from "lit";
|
||||||
import { customElement, property, query } from "lit/decorators";
|
import { customElement, property, query } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
@@ -56,9 +56,9 @@ class HaServicePicker extends LitElement {
|
|||||||
getServiceIcons(this.hass);
|
getServiceIcons(this.hass);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _rowRenderer: RenderItemFunction<ServiceComboBoxItem> = (
|
private _rowRenderer: ComboBoxLitRenderer<ServiceComboBoxItem> = (
|
||||||
item,
|
item,
|
||||||
index
|
{ index }
|
||||||
) => html`
|
) => html`
|
||||||
<ha-combo-box-item type="button" .borderTop=${index !== 0}>
|
<ha-combo-box-item type="button" .borderTop=${index !== 0}>
|
||||||
<ha-service-icon
|
<ha-service-icon
|
||||||
|
|||||||
@@ -681,7 +681,7 @@ class HaSidebar extends SubscribeMixin(LitElement) {
|
|||||||
tooltip.style.display = "block";
|
tooltip.style.display = "block";
|
||||||
tooltip.style.position = "fixed";
|
tooltip.style.position = "fixed";
|
||||||
tooltip.style.top = `${top}px`;
|
tooltip.style.top = `${top}px`;
|
||||||
tooltip.style.left = `calc(${item.offsetLeft + item.clientWidth + 8}px + var(--safe-area-inset-left, 0px))`;
|
tooltip.style.left = `calc(${item.offsetLeft + item.clientWidth + 8}px + var(--safe-area-inset-left, var(--ha-space-0)))`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _hideTooltip() {
|
private _hideTooltip() {
|
||||||
@@ -720,10 +720,14 @@ class HaSidebar extends SubscribeMixin(LitElement) {
|
|||||||
background-color: var(--sidebar-background-color);
|
background-color: var(--sidebar-background-color);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding-bottom: calc(14px + var(--safe-area-inset-bottom, 0px));
|
padding-bottom: calc(
|
||||||
|
14px + var(--safe-area-inset-bottom, var(--ha-space-0))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
.menu {
|
.menu {
|
||||||
height: calc(var(--header-height) + var(--safe-area-inset-top, 0px));
|
height: calc(
|
||||||
|
var(--header-height) + var(--safe-area-inset-top, var(--ha-space-0))
|
||||||
|
);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 0 var(--ha-space-1);
|
padding: 0 var(--ha-space-1);
|
||||||
@@ -742,16 +746,16 @@ class HaSidebar extends SubscribeMixin(LitElement) {
|
|||||||
font-size: var(--ha-font-size-xl);
|
font-size: var(--ha-font-size-xl);
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-left: calc(
|
padding-left: calc(
|
||||||
var(--ha-space-1) + var(--safe-area-inset-left, 0px)
|
var(--ha-space-1) + var(--safe-area-inset-left, var(--ha-space-0))
|
||||||
);
|
);
|
||||||
padding-inline-start: calc(
|
padding-inline-start: calc(
|
||||||
var(--ha-space-1) + var(--safe-area-inset-left, 0px)
|
var(--ha-space-1) + var(--safe-area-inset-left, var(--ha-space-0))
|
||||||
);
|
);
|
||||||
padding-inline-end: initial;
|
padding-inline-end: initial;
|
||||||
padding-top: var(--safe-area-inset-top, 0px);
|
padding-top: var(--safe-area-inset-top, var(--ha-space-0));
|
||||||
}
|
}
|
||||||
:host([expanded]) .menu {
|
:host([expanded]) .menu {
|
||||||
width: calc(256px + var(--safe-area-inset-left, 0px));
|
width: calc(256px + var(--safe-area-inset-left, var(--ha-space-0)));
|
||||||
}
|
}
|
||||||
:host([narrow][expanded]) .menu {
|
:host([narrow][expanded]) .menu {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -767,8 +771,8 @@ class HaSidebar extends SubscribeMixin(LitElement) {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
:host([narrow]) .title {
|
:host([narrow]) .title {
|
||||||
margin: 0;
|
margin: var(--ha-space-0);
|
||||||
padding: 0 var(--ha-space-4);
|
padding: var(--ha-space-0) var(--ha-space-4);
|
||||||
}
|
}
|
||||||
:host([expanded]) .title {
|
:host([expanded]) .title {
|
||||||
display: initial;
|
display: initial;
|
||||||
@@ -780,13 +784,16 @@ class HaSidebar extends SubscribeMixin(LitElement) {
|
|||||||
ha-fade-in,
|
ha-fade-in,
|
||||||
ha-md-list {
|
ha-md-list {
|
||||||
height: calc(
|
height: calc(
|
||||||
100% - var(--header-height) - var(--safe-area-inset-top, 0px) -
|
100% - var(--header-height) - var(
|
||||||
|
--safe-area-inset-top,
|
||||||
|
var(--ha-space-0)
|
||||||
|
) -
|
||||||
132px
|
132px
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-fade-in {
|
ha-fade-in {
|
||||||
padding: var(--ha-space-1) 0;
|
padding: var(--ha-space-1) var(--ha-space-0);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -796,7 +803,7 @@ class HaSidebar extends SubscribeMixin(LitElement) {
|
|||||||
ha-md-list {
|
ha-md-list {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
background: none;
|
background: none;
|
||||||
margin-left: var(--safe-area-inset-left, 0px);
|
margin-left: var(--safe-area-inset-left, var(--ha-space-0));
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-md-list-item {
|
ha-md-list-item {
|
||||||
@@ -818,7 +825,7 @@ class HaSidebar extends SubscribeMixin(LitElement) {
|
|||||||
width: 248px;
|
width: 248px;
|
||||||
}
|
}
|
||||||
:host([narrow][expanded]) ha-md-list-item {
|
:host([narrow][expanded]) ha-md-list-item {
|
||||||
width: calc(240px - var(--safe-area-inset-left, 0px));
|
width: calc(240px - var(--safe-area-inset-left, var(--ha-space-0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-md-list-item.selected {
|
ha-md-list-item.selected {
|
||||||
@@ -891,7 +898,7 @@ class HaSidebar extends SubscribeMixin(LitElement) {
|
|||||||
border-radius: var(--ha-border-radius-md);
|
border-radius: var(--ha-border-radius-md);
|
||||||
font-size: 0.65em;
|
font-size: 0.65em;
|
||||||
line-height: var(--ha-line-height-expanded);
|
line-height: var(--ha-line-height-expanded);
|
||||||
padding: 0 var(--ha-space-1);
|
padding: var(--ha-space-0) var(--ha-space-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-md-list-item.user {
|
ha-md-list-item.user {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export class HaTab extends LitElement {
|
|||||||
aria-label=${ifDefined(this.name)}
|
aria-label=${ifDefined(this.name)}
|
||||||
@keydown=${this._handleKeyDown}
|
@keydown=${this._handleKeyDown}
|
||||||
>
|
>
|
||||||
<slot name="icon"></slot>
|
${this.narrow ? html`<slot name="icon"></slot>` : ""}
|
||||||
<span class="name">${this.name}</span>
|
<span class="name">${this.name}</span>
|
||||||
<ha-ripple></ha-ripple>
|
<ha-ripple></ha-ripple>
|
||||||
</div>
|
</div>
|
||||||
@@ -50,11 +50,6 @@ export class HaTab extends LitElement {
|
|||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host(:not([narrow])) div {
|
|
||||||
flex-direction: row;
|
|
||||||
gap: var(--ha-space-2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -81,14 +76,6 @@ export class HaTab extends LitElement {
|
|||||||
padding: 0 4px;
|
padding: 0 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
::slotted([slot="icon"]) {
|
|
||||||
margin-bottom: var(--ha-space-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
:host(:not([narrow])) ::slotted([slot="icon"]) {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
div:focus-visible:before {
|
div:focus-visible:before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: block;
|
display: block;
|
||||||
|
|||||||
@@ -988,7 +988,7 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
|||||||
style=${styleMap({
|
style=${styleMap({
|
||||||
width: "var(--ha-space-12)",
|
width: "var(--ha-space-12)",
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: "0",
|
top: "var(--ha-space-0)",
|
||||||
left: rtl ? undefined : "var(--ha-space-1)",
|
left: rtl ? undefined : "var(--ha-space-1)",
|
||||||
right: rtl ? "var(--ha-space-1)" : undefined,
|
right: rtl ? "var(--ha-space-1)" : undefined,
|
||||||
transform: rtl ? "scaleX(-1)" : "",
|
transform: rtl ? "scaleX(-1)" : "",
|
||||||
@@ -1092,7 +1092,7 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
|||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
.mdc-chip-set {
|
.mdc-chip-set {
|
||||||
padding: var(--ha-space-1) 0;
|
padding: var(--ha-space-1) var(--ha-space-0);
|
||||||
gap: var(--ha-space-2);
|
gap: var(--ha-space-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -266,15 +266,15 @@ export class HaWaDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
/* Used to offset the dialog from the safe areas when space is limited */
|
/* Used to offset the dialog from the safe areas when space is limited */
|
||||||
transform: translate(
|
transform: translate(
|
||||||
calc(
|
calc(
|
||||||
var(--safe-area-offset-left, 0px) - var(
|
var(--safe-area-offset-left, var(--ha-space-0)) - var(
|
||||||
--safe-area-offset-right,
|
--safe-area-offset-right,
|
||||||
0px
|
var(--ha-space-0)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
calc(
|
calc(
|
||||||
var(--safe-area-offset-top, 0px) - var(
|
var(--safe-area-offset-top, var(--ha-space-0)) - var(
|
||||||
--safe-area-offset-bottom,
|
--safe-area-offset-bottom,
|
||||||
0px
|
var(--ha-space-0)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -285,7 +285,7 @@ export class HaWaDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
|
|
||||||
@media all and (max-width: 450px), all and (max-height: 500px) {
|
@media all and (max-width: 450px), all and (max-height: 500px) {
|
||||||
:host([type="standard"]) {
|
:host([type="standard"]) {
|
||||||
--ha-dialog-border-radius: 0;
|
--ha-dialog-border-radius: var(--ha-space-0);
|
||||||
|
|
||||||
wa-dialog {
|
wa-dialog {
|
||||||
/* Make the container fill the whole screen width and not the safe width */
|
/* Make the container fill the whole screen width and not the safe width */
|
||||||
@@ -372,7 +372,7 @@ export class HaWaDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wa-dialog::part(footer) {
|
wa-dialog::part(footer) {
|
||||||
padding: 0;
|
padding: var(--ha-space-0);
|
||||||
}
|
}
|
||||||
|
|
||||||
::slotted([slot="footer"]) {
|
::slotted([slot="footer"]) {
|
||||||
|
|||||||
@@ -1,17 +1,13 @@
|
|||||||
import { animate } from "@lit-labs/motion";
|
import { animate } from "@lit-labs/motion";
|
||||||
|
|
||||||
import {
|
import { mdiClose, mdiDelete } from "@mdi/js";
|
||||||
mdiClose,
|
|
||||||
mdiDelete,
|
|
||||||
mdiCheckboxBlankOutline,
|
|
||||||
mdiCheckboxMarkedOutline,
|
|
||||||
} from "@mdi/js";
|
|
||||||
import type { CSSResultGroup } from "lit";
|
import type { CSSResultGroup } from "lit";
|
||||||
import { css, html, LitElement, nothing } from "lit";
|
import { css, html, LitElement, nothing } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { repeat } from "lit/directives/repeat";
|
import { repeat } from "lit/directives/repeat";
|
||||||
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
|
import { computeRTLDirection } from "../../common/util/compute_rtl";
|
||||||
import { deleteImage, getIdFromUrl } from "../../data/image_upload";
|
import { deleteImage, getIdFromUrl } from "../../data/image_upload";
|
||||||
import type { MediaPlayerItem } from "../../data/media-player";
|
import type { MediaPlayerItem } from "../../data/media-player";
|
||||||
import { MediaClassBrowserSettings } from "../../data/media-player";
|
import { MediaClassBrowserSettings } from "../../data/media-player";
|
||||||
@@ -22,13 +18,12 @@ import {
|
|||||||
removeLocalMedia,
|
removeLocalMedia,
|
||||||
} from "../../data/media_source";
|
} from "../../data/media_source";
|
||||||
import { showConfirmationDialog } from "../../dialogs/generic/show-dialog-box";
|
import { showConfirmationDialog } from "../../dialogs/generic/show-dialog-box";
|
||||||
|
import { haStyleDialog, haStyleDialogFixedTop } from "../../resources/styles";
|
||||||
import type { HomeAssistant } from "../../types";
|
import type { HomeAssistant } from "../../types";
|
||||||
import "../ha-button";
|
import "../ha-button";
|
||||||
import "../ha-check-list-item";
|
import "../ha-check-list-item";
|
||||||
import "../ha-wa-dialog";
|
import "../ha-dialog";
|
||||||
import "../ha-dialog-header";
|
import "../ha-dialog-header";
|
||||||
import "../ha-dialog-footer";
|
|
||||||
import "../ha-icon-button";
|
|
||||||
import "../ha-list";
|
import "../ha-list";
|
||||||
import "../ha-spinner";
|
import "../ha-spinner";
|
||||||
import "../ha-svg-icon";
|
import "../ha-svg-icon";
|
||||||
@@ -51,24 +46,14 @@ class DialogMediaManage extends LitElement {
|
|||||||
|
|
||||||
@state() private _selected = new Set<number>();
|
@state() private _selected = new Set<number>();
|
||||||
|
|
||||||
@state() private _open = false;
|
|
||||||
|
|
||||||
@state() private _filteredChildren: MediaPlayerItem[] = [];
|
|
||||||
|
|
||||||
private _filesChanged = false;
|
private _filesChanged = false;
|
||||||
|
|
||||||
public showDialog(params: MediaManageDialogParams): void {
|
public showDialog(params: MediaManageDialogParams): void {
|
||||||
this._params = params;
|
this._params = params;
|
||||||
this._refreshMedia();
|
this._refreshMedia();
|
||||||
this._open = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public closeDialog() {
|
public closeDialog() {
|
||||||
this._open = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _dialogClosed(): void {
|
|
||||||
if (this._filesChanged && this._params!.onClose) {
|
if (this._filesChanged && this._params!.onClose) {
|
||||||
this._params!.onClose();
|
this._params!.onClose();
|
||||||
}
|
}
|
||||||
@@ -80,68 +65,88 @@ class DialogMediaManage extends LitElement {
|
|||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
}
|
}
|
||||||
|
|
||||||
protected willUpdate() {
|
|
||||||
this._filteredChildren =
|
|
||||||
this._currentItem?.children?.filter((child) => !child.can_expand) || [];
|
|
||||||
if (this._filteredChildren.length === 0 && this._selected.size !== 0) {
|
|
||||||
// When running delete all, sometimes the list can throw off a spurious
|
|
||||||
// select event that makes it think that 1 item is still selected. Clear selected
|
|
||||||
// if nothing can be selected.
|
|
||||||
this._selected = new Set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
if (!this._params) {
|
if (!this._params) {
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const children =
|
||||||
|
this._currentItem?.children?.filter((child) => !child.can_expand) || [];
|
||||||
|
|
||||||
let fileIndex = 0;
|
let fileIndex = 0;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-wa-dialog
|
<ha-dialog
|
||||||
.hass=${this.hass}
|
open
|
||||||
.open=${this._open}
|
scrimClickAction
|
||||||
?prevent-scrim-close=${this._uploading || this._deleting}
|
escapeKeyAction
|
||||||
@closed=${this._dialogClosed}
|
hideActions
|
||||||
|
flexContent
|
||||||
|
.heading=${this._params.currentItem.title}
|
||||||
|
@closed=${this.closeDialog}
|
||||||
>
|
>
|
||||||
<ha-dialog-header slot="header">
|
<ha-dialog-header slot="heading">
|
||||||
${!(this._uploading || this._deleting)
|
|
||||||
? html`<slot name="headerNavigationIcon" slot="navigationIcon">
|
|
||||||
<ha-icon-button
|
|
||||||
data-dialog="close"
|
|
||||||
.label=${this.hass?.localize("ui.common.close") ?? "Close"}
|
|
||||||
.path=${mdiClose}
|
|
||||||
></ha-icon-button
|
|
||||||
></slot>`
|
|
||||||
: nothing}
|
|
||||||
<span class="title" slot="title" id="dialog-box-title">
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.components.media-browser.file_management.title"
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
${this._selected.size === 0
|
${this._selected.size === 0
|
||||||
? html`<ha-media-upload-button
|
? html`
|
||||||
.hass=${this.hass}
|
<span slot="title">
|
||||||
.currentItem=${this._params.currentItem}
|
${this.hass.localize(
|
||||||
@uploading=${this._startUploading}
|
"ui.components.media-browser.file_management.title"
|
||||||
@media-refresh=${this._doneUploading}
|
)}
|
||||||
slot="actionItems"
|
</span>
|
||||||
></ha-media-upload-button>`
|
|
||||||
: html`<ha-button
|
<ha-media-upload-button
|
||||||
variant="danger"
|
.disabled=${this._deleting}
|
||||||
slot="actionItems"
|
.hass=${this.hass}
|
||||||
.disabled=${this._deleting}
|
.currentItem=${this._params.currentItem}
|
||||||
@click=${this._handleDelete}
|
@uploading=${this._startUploading}
|
||||||
>
|
@media-refresh=${this._doneUploading}
|
||||||
<ha-svg-icon .path=${mdiDelete} slot="start"></ha-svg-icon>
|
slot="actionItems"
|
||||||
${this.hass.localize(
|
></ha-media-upload-button>
|
||||||
`ui.components.media-browser.file_management.${
|
${this._uploading
|
||||||
this._deleting ? "deleting" : "delete"
|
? ""
|
||||||
}`,
|
: html`
|
||||||
{ count: this._selected.size }
|
<ha-icon-button
|
||||||
)}
|
.label=${this.hass.localize("ui.common.close")}
|
||||||
</ha-button>`}
|
.path=${mdiClose}
|
||||||
|
dialogAction="close"
|
||||||
|
slot="navigationIcon"
|
||||||
|
dir=${computeRTLDirection(this.hass)}
|
||||||
|
></ha-icon-button>
|
||||||
|
`}
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
<ha-button
|
||||||
|
variant="danger"
|
||||||
|
slot="navigationIcon"
|
||||||
|
.disabled=${this._deleting}
|
||||||
|
@click=${this._handleDelete}
|
||||||
|
>
|
||||||
|
<ha-svg-icon .path=${mdiDelete} slot="start"></ha-svg-icon>
|
||||||
|
${this.hass.localize(
|
||||||
|
`ui.components.media-browser.file_management.${
|
||||||
|
this._deleting ? "deleting" : "delete"
|
||||||
|
}`,
|
||||||
|
{ count: this._selected.size }
|
||||||
|
)}
|
||||||
|
</ha-button>
|
||||||
|
|
||||||
|
${this._deleting
|
||||||
|
? ""
|
||||||
|
: html`
|
||||||
|
<ha-button
|
||||||
|
slot="actionItems"
|
||||||
|
@click=${this._handleDeselectAll}
|
||||||
|
>
|
||||||
|
<ha-svg-icon
|
||||||
|
.path=${mdiClose}
|
||||||
|
slot="start"
|
||||||
|
></ha-svg-icon>
|
||||||
|
${this.hass.localize(
|
||||||
|
`ui.components.media-browser.file_management.deselect_all`
|
||||||
|
)}
|
||||||
|
</ha-button>
|
||||||
|
`}
|
||||||
|
`}
|
||||||
</ha-dialog-header>
|
</ha-dialog-header>
|
||||||
${!this._currentItem
|
${!this._currentItem
|
||||||
? html`
|
? html`
|
||||||
@@ -149,7 +154,7 @@ class DialogMediaManage extends LitElement {
|
|||||||
<ha-spinner></ha-spinner>
|
<ha-spinner></ha-spinner>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: !this._filteredChildren.length
|
: !children.length
|
||||||
? html`<div class="no-items">
|
? html`<div class="no-items">
|
||||||
<p>
|
<p>
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
@@ -165,38 +170,9 @@ class DialogMediaManage extends LitElement {
|
|||||||
: ""}
|
: ""}
|
||||||
</div>`
|
</div>`
|
||||||
: html`
|
: html`
|
||||||
<div class="buttons" slot="footer">
|
|
||||||
<ha-button
|
|
||||||
appearance="filled"
|
|
||||||
@click=${this._handleDeselectAll}
|
|
||||||
.disabled=${this._selected.size === 0}
|
|
||||||
>
|
|
||||||
<ha-svg-icon
|
|
||||||
.path=${mdiCheckboxBlankOutline}
|
|
||||||
slot="start"
|
|
||||||
></ha-svg-icon>
|
|
||||||
${this.hass.localize(
|
|
||||||
`ui.components.media-browser.file_management.deselect_all`
|
|
||||||
)}
|
|
||||||
</ha-button>
|
|
||||||
<ha-button
|
|
||||||
appearance="filled"
|
|
||||||
@click=${this._handleSelectAll}
|
|
||||||
.disabled=${this._selected.size ===
|
|
||||||
this._filteredChildren.length}
|
|
||||||
>
|
|
||||||
<ha-svg-icon
|
|
||||||
.path=${mdiCheckboxMarkedOutline}
|
|
||||||
slot="start"
|
|
||||||
></ha-svg-icon>
|
|
||||||
${this.hass.localize(
|
|
||||||
`ui.components.media-browser.file_management.select_all`
|
|
||||||
)}
|
|
||||||
</ha-button>
|
|
||||||
</div>
|
|
||||||
<ha-list multi @selected=${this._handleSelected}>
|
<ha-list multi @selected=${this._handleSelected}>
|
||||||
${repeat(
|
${repeat(
|
||||||
this._filteredChildren,
|
children,
|
||||||
(item) => item.media_content_id,
|
(item) => item.media_content_id,
|
||||||
(item) => {
|
(item) => {
|
||||||
const icon = html`
|
const icon = html`
|
||||||
@@ -244,7 +220,7 @@ class DialogMediaManage extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</ha-tip>`
|
</ha-tip>`
|
||||||
: nothing}
|
: nothing}
|
||||||
</ha-wa-dialog>
|
</ha-dialog>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,10 +244,6 @@ class DialogMediaManage extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleSelectAll() {
|
|
||||||
this._selected = new Set([...Array(this._filteredChildren.length).keys()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _handleDelete() {
|
private async _handleDelete() {
|
||||||
if (
|
if (
|
||||||
!(await showConfirmationDialog(this, {
|
!(await showConfirmationDialog(this, {
|
||||||
@@ -332,10 +304,23 @@ class DialogMediaManage extends LitElement {
|
|||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return [
|
return [
|
||||||
|
haStyleDialog,
|
||||||
|
haStyleDialogFixedTop,
|
||||||
css`
|
css`
|
||||||
ha-wa-dialog {
|
ha-dialog {
|
||||||
|
--dialog-z-index: 9;
|
||||||
--dialog-content-padding: 0;
|
--dialog-content-padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 800px) {
|
||||||
|
ha-dialog {
|
||||||
|
--mdc-dialog-max-width: 800px;
|
||||||
|
--mdc-dialog-max-height: calc(
|
||||||
|
100vh - var(--ha-space-18) - var(--safe-area-inset-y)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ha-dialog-header ha-media-upload-button,
|
ha-dialog-header ha-media-upload-button,
|
||||||
ha-dialog-header ha-button {
|
ha-dialog-header ha-button {
|
||||||
--mdc-theme-primary: var(--primary-text-color);
|
--mdc-theme-primary: var(--primary-text-color);
|
||||||
@@ -353,11 +338,7 @@ class DialogMediaManage extends LitElement {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
.buttons {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.no-items {
|
.no-items {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ export class HaTargetPickerItemGroup extends LitElement {
|
|||||||
static styles = css`
|
static styles = css`
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
--expansion-panel-content-padding: 0;
|
--expansion-panel-content-padding: var(--ha-space-0);
|
||||||
}
|
}
|
||||||
ha-expansion-panel::part(summary) {
|
ha-expansion-panel::part(summary) {
|
||||||
background-color: var(--ha-color-fill-neutral-quiet-resting);
|
background-color: var(--ha-color-fill-neutral-quiet-resting);
|
||||||
@@ -101,7 +101,7 @@ export class HaTargetPickerItemGroup extends LitElement {
|
|||||||
min-height: unset;
|
min-height: unset;
|
||||||
}
|
}
|
||||||
ha-md-list {
|
ha-md-list {
|
||||||
padding: 0;
|
padding: var(--ha-space-0);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -605,8 +605,8 @@ export class HaTargetPickerItemRow extends LitElement {
|
|||||||
buttonLinkStyle,
|
buttonLinkStyle,
|
||||||
css`
|
css`
|
||||||
:host {
|
:host {
|
||||||
--md-list-item-top-space: 0;
|
--md-list-item-top-space: var(--ha-space-0);
|
||||||
--md-list-item-bottom-space: 0;
|
--md-list-item-bottom-space: var(--ha-space-0);
|
||||||
--md-list-item-leading-space: var(--ha-space-2);
|
--md-list-item-leading-space: var(--ha-space-2);
|
||||||
--md-list-item-trailing-space: var(--ha-space-2);
|
--md-list-item-trailing-space: var(--ha-space-2);
|
||||||
--md-list-item-two-line-container-height: 56px;
|
--md-list-item-two-line-container-height: 56px;
|
||||||
|
|||||||
@@ -278,8 +278,8 @@ export class HaTargetPickerValueChip extends LitElement {
|
|||||||
direction: var(--direction);
|
direction: var(--direction);
|
||||||
}
|
}
|
||||||
.expand-btn {
|
.expand-btn {
|
||||||
margin-right: 0;
|
margin-right: var(--ha-space-0);
|
||||||
margin-inline-end: 0;
|
margin-inline-end: var(--ha-space-0);
|
||||||
margin-inline-start: initial;
|
margin-inline-start: initial;
|
||||||
}
|
}
|
||||||
.mdc-chip.area:not(.add),
|
.mdc-chip.area:not(.add),
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { RenderItemFunction } from "@lit-labs/virtualizer/virtualize";
|
import type { ComboBoxLitRenderer } from "@vaadin/combo-box/lit";
|
||||||
import type { TemplateResult } from "lit";
|
import type { TemplateResult } from "lit";
|
||||||
import { html, LitElement, nothing } from "lit";
|
import { html, LitElement, nothing } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
@@ -73,7 +73,7 @@ class HaUserPicker extends LitElement {
|
|||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|
||||||
private _rowRenderer: RenderItemFunction<UserComboBoxItem> = (item) => {
|
private _rowRenderer: ComboBoxLitRenderer<UserComboBoxItem> = (item) => {
|
||||||
const user = item.user;
|
const user = item.user;
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return html`<ha-combo-box-item type="button" compact>
|
return html`<ha-combo-box-item type="button" compact>
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
import { isComponentLoaded } from "../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../common/config/is_component_loaded";
|
||||||
import { atLeastVersion } from "../common/config/version";
|
import { atLeastVersion } from "../common/config/version";
|
||||||
import type { HomeAssistant } from "../types";
|
import type { HomeAssistant } from "../types";
|
||||||
import type { HassioAddonInfo } from "./hassio/addon";
|
|
||||||
|
|
||||||
export interface LogProvider {
|
export interface LogProvider {
|
||||||
key: string;
|
key: string;
|
||||||
name: string;
|
name: string;
|
||||||
addon?: HassioAddonInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetchErrorLog = (hass: HomeAssistant) =>
|
export const fetchErrorLog = (hass: HomeAssistant) =>
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ export type Selector =
|
|||||||
| AttributeSelector
|
| AttributeSelector
|
||||||
| BooleanSelector
|
| BooleanSelector
|
||||||
| ButtonToggleSelector
|
| ButtonToggleSelector
|
||||||
| ChooseSelector
|
|
||||||
| ColorRGBSelector
|
| ColorRGBSelector
|
||||||
| ColorTempSelector
|
| ColorTempSelector
|
||||||
| ConditionSelector
|
| ConditionSelector
|
||||||
@@ -117,13 +116,6 @@ export interface ButtonToggleSelector {
|
|||||||
} | null;
|
} | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ChooseSelector {
|
|
||||||
choose: {
|
|
||||||
choices: Record<string, { selector: Selector }>;
|
|
||||||
translation_key?: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ColorRGBSelector {
|
export interface ColorRGBSelector {
|
||||||
color_rgb: {} | null;
|
color_rgb: {} | null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ export class HaMoreInfoControlSelectContainer extends LitElement {
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
-ms-overflow-style: none; /* IE and Edge */
|
-ms-overflow-style: none; /* IE and Edge */
|
||||||
scrollbar-width: none; /* Firefox */
|
scrollbar-width: none; /* Firefox */
|
||||||
margin: -2px calc(var(--ha-space-6) * -1);
|
margin: -2px -24px;
|
||||||
padding: 2px var(--ha-space-6);
|
padding: 2px 24px;
|
||||||
}
|
}
|
||||||
.controls-scroll::-webkit-scrollbar {
|
.controls-scroll::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
|
|||||||
@@ -84,8 +84,8 @@ export class HaMoreInfoStateHeader extends LitElement {
|
|||||||
font-weight: var(--ha-font-weight-medium);
|
font-weight: var(--ha-font-weight-medium);
|
||||||
line-height: var(--ha-line-height-normal);
|
line-height: var(--ha-line-height-normal);
|
||||||
letter-spacing: 0.1px;
|
letter-spacing: 0.1px;
|
||||||
padding: var(--ha-space-1) 0;
|
padding: 4px 0;
|
||||||
margin-bottom: var(--ha-space-5);
|
margin-bottom: 20px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
|
|||||||
@@ -268,14 +268,14 @@ class DialogLightColorFavorite extends LitElement {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: var(--ha-space-6);
|
padding: 24px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
.modes {
|
.modes {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
padding: 0 var(--ha-space-6);
|
padding: 0 24px;
|
||||||
}
|
}
|
||||||
.wheel {
|
.wheel {
|
||||||
width: 30px;
|
width: 30px;
|
||||||
|
|||||||
@@ -254,14 +254,14 @@ export class HaMoreInfoLightFavoriteColors extends LitElement {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin: calc(var(--ha-space-2) * -1);
|
margin: -8px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
max-width: 250px;
|
max-width: 250px;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container > * {
|
.container > * {
|
||||||
margin: var(--ha-space-2);
|
margin: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.color {
|
.color {
|
||||||
|
|||||||
@@ -515,7 +515,7 @@ class LightRgbColorPicker extends LitElement {
|
|||||||
hr {
|
hr {
|
||||||
border-color: var(--divider-color);
|
border-color: var(--divider-color);
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
margin: var(--ha-space-4) 0;
|
margin: 16px 0;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -15,22 +15,22 @@ export const moreInfoControlStyle = css`
|
|||||||
}
|
}
|
||||||
|
|
||||||
.controls:not(:last-child) {
|
.controls:not(:last-child) {
|
||||||
margin-bottom: var(--ha-space-6);
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.controls > *:not(:last-child) {
|
.controls > *:not(:last-child) {
|
||||||
margin-bottom: var(--ha-space-6);
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.buttons {
|
.buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-bottom: var(--ha-space-3);
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.buttons > * {
|
.buttons > * {
|
||||||
margin: var(--ha-space-2);
|
margin: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-attributes {
|
ha-attributes {
|
||||||
@@ -38,6 +38,6 @@ export const moreInfoControlStyle = css`
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
ha-more-info-control-select-container + ha-attributes:not([empty]) {
|
ha-more-info-control-select-container + ha-attributes:not([empty]) {
|
||||||
margin-top: var(--ha-space-4);
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ class MoreInfoSirenAdvancedControls extends LitElement {
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: var(--ha-space-4);
|
gap: var(--ha-space-4);
|
||||||
margin-top: var(--ha-space-4);
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
ha-control-button {
|
ha-control-button {
|
||||||
--control-button-border-radius: var(--ha-border-radius-xl);
|
--control-button-border-radius: var(--ha-border-radius-xl);
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class MoreInfoViewVoiceAssistants extends LitElement {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: var(--ha-space-6);
|
padding: 24px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class MoreInfoAutomation extends LitElement {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
.actions {
|
.actions {
|
||||||
margin: var(--ha-space-2) 0;
|
margin: 8px 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -60,7 +60,7 @@ class MoreInfoAutomation extends LitElement {
|
|||||||
hr {
|
hr {
|
||||||
border-color: var(--divider-color);
|
border-color: var(--divider-color);
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
margin: var(--ha-space-4) 0;
|
margin: 16px 0;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ class MoreInfoCamera extends LitElement {
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: var(--ha-space-4);
|
padding: 16px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
gap: var(--ha-space-2);
|
gap: var(--ha-space-2);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -511,7 +511,7 @@ class MoreInfoClimate extends LitElement {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: var(--ha-space-10);
|
margin-bottom: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.current div {
|
.current div {
|
||||||
@@ -534,7 +534,7 @@ class MoreInfoClimate extends LitElement {
|
|||||||
font-size: var(--ha-font-size-m);
|
font-size: var(--ha-font-size-m);
|
||||||
line-height: var(--ha-line-height-condensed);
|
line-height: var(--ha-line-height-condensed);
|
||||||
letter-spacing: 0.4px;
|
letter-spacing: 0.4px;
|
||||||
margin-bottom: var(--ha-space-1);
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.current .value {
|
.current .value {
|
||||||
@@ -545,7 +545,7 @@ class MoreInfoClimate extends LitElement {
|
|||||||
}
|
}
|
||||||
ha-select {
|
ha-select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: var(--ha-space-2);
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container-humidity .single-row {
|
.container-humidity .single-row {
|
||||||
@@ -561,7 +561,7 @@ class MoreInfoClimate extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.single-row {
|
.single-row {
|
||||||
padding: var(--ha-space-2) 0;
|
padding: 8px 0;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export class MoreInfoConfigurator extends LitElement {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
p {
|
p {
|
||||||
margin: var(--ha-space-2) 0;
|
margin: 8px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ class MoreInfoCounter extends LitElement {
|
|||||||
|
|
||||||
static styles = css`
|
static styles = css`
|
||||||
.actions {
|
.actions {
|
||||||
margin: var(--ha-space-2) 0;
|
margin: 8px 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ class MoreInfoCover extends LitElement {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
.main-control > * {
|
.main-control > * {
|
||||||
margin: 0 var(--ha-space-2);
|
margin: 0 8px;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -72,8 +72,8 @@ class MoreInfoDatetime extends LitElement {
|
|||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
ha-date-input + ha-time-input {
|
ha-date-input + ha-time-input {
|
||||||
margin-left: var(--ha-space-1);
|
margin-left: 4px;
|
||||||
margin-inline-start: var(--ha-space-1);
|
margin-inline-start: 4px;
|
||||||
margin-inline-end: initial;
|
margin-inline-end: initial;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ class MoreInfoGroup extends LitElement {
|
|||||||
css`
|
css`
|
||||||
state-card-content {
|
state-card-content {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: var(--ha-space-2);
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ class MoreInfoHumidifier extends LitElement {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: var(--ha-space-10);
|
margin-bottom: 40px;
|
||||||
}
|
}
|
||||||
.current div {
|
.current div {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -237,7 +237,7 @@ class MoreInfoHumidifier extends LitElement {
|
|||||||
font-size: var(--ha-font-size-m);
|
font-size: var(--ha-font-size-m);
|
||||||
line-height: var(--ha-line-height-condensed);
|
line-height: var(--ha-line-height-condensed);
|
||||||
letter-spacing: 0.4px;
|
letter-spacing: 0.4px;
|
||||||
margin-bottom: var(--ha-space-1);
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
.current .value {
|
.current .value {
|
||||||
font-size: var(--ha-font-size-xl);
|
font-size: var(--ha-font-size-xl);
|
||||||
|
|||||||
@@ -84,8 +84,8 @@ class MoreInfoInputDatetime extends LitElement {
|
|||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
ha-date-input + ha-time-input {
|
ha-date-input + ha-time-input {
|
||||||
margin-left: var(--ha-space-1);
|
margin-left: 4px;
|
||||||
margin-inline-start: var(--ha-space-1);
|
margin-inline-start: 4px;
|
||||||
margin-inline-end: initial;
|
margin-inline-end: initial;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ class MoreInfoLock extends LitElement {
|
|||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
ha-control-button-group + ha-attributes:not([empty]) {
|
ha-control-button-group + ha-attributes:not([empty]) {
|
||||||
margin-top: var(--ha-space-4);
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
@keyframes pulse {
|
@keyframes pulse {
|
||||||
0% {
|
0% {
|
||||||
|
|||||||
@@ -528,11 +528,11 @@ class MoreInfoMediaPlayer extends LitElement {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--ha-space-3);
|
gap: var(--ha-space-3);
|
||||||
margin-left: var(--ha-space-2);
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.volume ha-svg-icon {
|
.volume ha-svg-icon {
|
||||||
padding: var(--ha-space-1);
|
padding: 4px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
}
|
}
|
||||||
@@ -545,17 +545,17 @@ class MoreInfoMediaPlayer extends LitElement {
|
|||||||
.badge {
|
.badge {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -10px;
|
top: -10px;
|
||||||
left: var(--ha-space-4);
|
left: 16px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
min-width: var(--ha-space-2);
|
min-width: 8px;
|
||||||
border-radius: var(--ha-border-radius-md);
|
border-radius: var(--ha-border-radius-md);
|
||||||
font-weight: var(--ha-font-weight-normal);
|
font-weight: var(--ha-font-weight-normal);
|
||||||
font-size: var(--ha-font-size-xs);
|
font-size: var(--ha-font-size-xs);
|
||||||
background-color: var(--primary-color);
|
background-color: var(--primary-color);
|
||||||
padding: 0 var(--ha-space-1);
|
padding: 0 4px;
|
||||||
color: var(--text-primary-color);
|
color: var(--text-primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,13 +572,13 @@ class MoreInfoMediaPlayer extends LitElement {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin: var(--ha-space-2) 0 var(--ha-space-2) var(--ha-space-2);
|
margin: 8px 0 8px 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-title {
|
.media-title {
|
||||||
font-size: var(--ha-font-size-xl);
|
font-size: var(--ha-font-size-xl);
|
||||||
font-weight: var(--ha-font-weight-bold);
|
font-weight: var(--ha-font-weight-bold);
|
||||||
margin-bottom: var(--ha-space-1);
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-artist {
|
.media-artist {
|
||||||
|
|||||||
@@ -72,12 +72,12 @@ class MoreInfoPerson extends LitElement {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
.actions {
|
.actions {
|
||||||
margin: var(--ha-space-2) 0;
|
margin: 8px 0;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
ha-map {
|
ha-map {
|
||||||
margin-top: var(--ha-space-4);
|
margin-top: 16px;
|
||||||
margin-bottom: var(--ha-space-4);
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -227,24 +227,24 @@ class MoreInfoScript extends LitElement {
|
|||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: var(--ha-space-4);
|
margin-bottom: 16px;
|
||||||
height: 21px;
|
height: 21px;
|
||||||
}
|
}
|
||||||
.queue.has-queue {
|
.queue.has-queue {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
.fields {
|
.fields {
|
||||||
padding: var(--ha-space-4);
|
padding: 16px;
|
||||||
border: 1px solid var(--divider-color);
|
border: 1px solid var(--divider-color);
|
||||||
border-radius: var(--ha-border-radius-md);
|
border-radius: var(--ha-border-radius-md);
|
||||||
margin-bottom: var(--ha-space-4);
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
.fields .title {
|
.fields .title {
|
||||||
font-weight: var(--ha-font-weight-bold);
|
font-weight: var(--ha-font-weight-bold);
|
||||||
}
|
}
|
||||||
ha-control-button ha-svg-icon {
|
ha-control-button ha-svg-icon {
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
margin-right: var(--ha-space-1);
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
ha-service-control {
|
ha-service-control {
|
||||||
--service-control-padding: 0;
|
--service-control-padding: 0;
|
||||||
@@ -252,7 +252,7 @@ class MoreInfoScript extends LitElement {
|
|||||||
}
|
}
|
||||||
ha-markdown {
|
ha-markdown {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0 var(--ha-space-4);
|
padding: 0 16px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ class MoreInfoSun extends LitElement {
|
|||||||
hr {
|
hr {
|
||||||
border-color: var(--divider-color);
|
border-color: var(--divider-color);
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
margin: var(--ha-space-4) 0;
|
margin: 16px 0;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ class MoreInfoTimer extends LitElement {
|
|||||||
|
|
||||||
static styles = css`
|
static styles = css`
|
||||||
.actions {
|
.actions {
|
||||||
margin: var(--ha-space-2) 0;
|
margin: 8px 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|||||||
@@ -448,14 +448,14 @@ class MoreInfoUpdate extends LitElement {
|
|||||||
hr {
|
hr {
|
||||||
border-color: var(--divider-color);
|
border-color: var(--divider-color);
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
margin: var(--ha-space-4) 0;
|
margin: 16px 0;
|
||||||
}
|
}
|
||||||
ha-expansion-panel {
|
ha-expansion-panel {
|
||||||
margin: var(--ha-space-4) 0;
|
margin: 16px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary {
|
.summary {
|
||||||
margin-bottom: var(--ha-space-4);
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.row {
|
.row {
|
||||||
@@ -473,10 +473,8 @@ class MoreInfoUpdate extends LitElement {
|
|||||||
);
|
);
|
||||||
position: sticky;
|
position: sticky;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
margin: 0 calc(var(--ha-space-6) * -1) 0 calc(var(--ha-space-6) * -1);
|
margin: 0 -24px 0 -24px;
|
||||||
margin-bottom: calc(
|
margin-bottom: calc(-1 * max(var(--safe-area-inset-bottom), 24px));
|
||||||
-1 * max(var(--safe-area-inset-bottom), var(--ha-space-6))
|
|
||||||
);
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -488,8 +486,8 @@ class MoreInfoUpdate extends LitElement {
|
|||||||
ha-md-list {
|
ha-md-list {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin-bottom: calc(var(--ha-space-4) * -1);
|
margin-bottom: -16px;
|
||||||
margin-top: calc(var(--ha-space-1) * -1);
|
margin-top: -4px;
|
||||||
--md-sys-color-surface: var(
|
--md-sys-color-surface: var(
|
||||||
--ha-dialog-surface-background,
|
--ha-dialog-surface-background,
|
||||||
var(--mdc-theme-surface, #fff)
|
var(--mdc-theme-surface, #fff)
|
||||||
@@ -497,8 +495,8 @@ class MoreInfoUpdate extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ha-md-list-item {
|
ha-md-list-item {
|
||||||
--md-list-item-leading-space: var(--ha-space-6);
|
--md-list-item-leading-space: 24px;
|
||||||
--md-list-item-trailing-space: var(--ha-space-6);
|
--md-list-item-trailing-space: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
@@ -508,7 +506,7 @@ class MoreInfoUpdate extends LitElement {
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: var(--ha-space-4);
|
padding: 16px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
gap: var(--ha-space-2);
|
gap: var(--ha-space-2);
|
||||||
}
|
}
|
||||||
@@ -522,12 +520,12 @@ class MoreInfoUpdate extends LitElement {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
mwc-linear-progress {
|
mwc-linear-progress {
|
||||||
margin-bottom: calc(var(--ha-space-2) * -1);
|
margin-bottom: -8px;
|
||||||
margin-top: var(--ha-space-1);
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
ha-markdown {
|
ha-markdown {
|
||||||
direction: ltr;
|
direction: ltr;
|
||||||
padding-bottom: var(--ha-space-4);
|
padding-bottom: 16px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
ha-markdown.hidden {
|
ha-markdown.hidden {
|
||||||
@@ -536,7 +534,7 @@ class MoreInfoUpdate extends LitElement {
|
|||||||
.loader {
|
.loader {
|
||||||
height: 80px;
|
height: 80px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding-bottom: var(--ha-space-4);
|
padding-bottom: 16px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ class MoreInfoValve extends LitElement {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
.main-control > * {
|
.main-control > * {
|
||||||
margin: 0 var(--ha-space-2);
|
margin: 0 8px;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ class MoreInfoWaterHeater extends LitElement {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: var(--ha-space-10);
|
margin-bottom: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.current div {
|
.current div {
|
||||||
@@ -237,7 +237,7 @@ class MoreInfoWaterHeater extends LitElement {
|
|||||||
font-size: var(--ha-font-size-m);
|
font-size: var(--ha-font-size-m);
|
||||||
line-height: var(--ha-line-height-condensed);
|
line-height: var(--ha-line-height-condensed);
|
||||||
letter-spacing: 0.4px;
|
letter-spacing: 0.4px;
|
||||||
margin-bottom: var(--ha-space-1);
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.current .value {
|
.current .value {
|
||||||
|
|||||||
@@ -440,13 +440,13 @@ class MoreInfoWeather extends LitElement {
|
|||||||
css`
|
css`
|
||||||
ha-svg-icon {
|
ha-svg-icon {
|
||||||
color: var(--state-icon-color);
|
color: var(--state-icon-color);
|
||||||
margin-left: var(--ha-space-2);
|
margin-left: 8px;
|
||||||
margin-inline-start: var(--ha-space-2);
|
margin-inline-start: 8px;
|
||||||
margin-inline-end: initial;
|
margin-inline-end: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section {
|
.section {
|
||||||
margin: var(--ha-space-4) 0 var(--ha-space-2) 0;
|
margin: 16px 0 8px 0;
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,14 +470,14 @@ class MoreInfoWeather extends LitElement {
|
|||||||
|
|
||||||
.main {
|
.main {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
margin-left: var(--ha-space-6);
|
margin-left: 24px;
|
||||||
margin-inline-start: var(--ha-space-6);
|
margin-inline-start: 24px;
|
||||||
margin-inline-end: initial;
|
margin-inline-end: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
.attribution {
|
.attribution {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: var(--ha-space-4);
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.time-ago,
|
.time-ago,
|
||||||
@@ -500,15 +500,15 @@ class MoreInfoWeather extends LitElement {
|
|||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: var(--ha-space-4);
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-image {
|
.icon-image {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-width: 64px;
|
min-width: 64px;
|
||||||
margin-right: var(--ha-space-4);
|
margin-right: 16px;
|
||||||
margin-inline-end: var(--ha-space-4);
|
margin-inline-end: 16px;
|
||||||
margin-inline-start: initial;
|
margin-inline-start: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -534,7 +534,7 @@ class MoreInfoWeather extends LitElement {
|
|||||||
|
|
||||||
.temp-attribute .temp {
|
.temp-attribute .temp {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-right: var(--ha-space-6);
|
margin-right: 24px;
|
||||||
direction: ltr;
|
direction: ltr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -557,8 +557,8 @@ class MoreInfoWeather extends LitElement {
|
|||||||
|
|
||||||
.name-state {
|
.name-state {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding-right: var(--ha-space-3);
|
padding-right: 12px;
|
||||||
padding-inline-end: var(--ha-space-3);
|
padding-inline-end: 12px;
|
||||||
padding-inline-start: initial;
|
padding-inline-start: initial;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
@@ -572,7 +572,7 @@ class MoreInfoWeather extends LitElement {
|
|||||||
.forecast {
|
.forecast {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
padding: var(--ha-space-4);
|
padding: 16px;
|
||||||
padding-bottom: 0px;
|
padding-bottom: 0px;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
scrollbar-color: var(--scrollbar-thumb-color) transparent;
|
scrollbar-color: var(--scrollbar-thumb-color) transparent;
|
||||||
@@ -634,8 +634,8 @@ class MoreInfoWeather extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.forecast-image-icon {
|
.forecast-image-icon {
|
||||||
padding-top: var(--ha-space-1);
|
padding-top: 4px;
|
||||||
padding-bottom: var(--ha-space-1);
|
padding-bottom: 4px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -802,7 +802,8 @@ export class MoreInfoDialog extends ScrollableFadeMixin(LitElement) {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
margin: 0 0 calc(var(--ha-space-2) * -1) 0;
|
margin: var(--ha-space-0) var(--ha-space-0)
|
||||||
|
calc(var(--ha-space-2) * -1) var(--ha-space-0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.title p {
|
.title p {
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export class MoreInfoHistoryAndLogbook extends LitElement {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
ha-more-info-history + ha-more-info-logbook {
|
ha-more-info-history + ha-more-info-logbook {
|
||||||
margin-top: var(--ha-space-4);
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ export class MoreInfoHistory extends LitElement {
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: var(--ha-space-2);
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
.header > a,
|
.header > a,
|
||||||
a:visited {
|
a:visited {
|
||||||
|
|||||||
@@ -130,8 +130,8 @@ export class MoreInfoInfo extends LitElement {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: var(--ha-space-6);
|
padding: 24px;
|
||||||
padding-bottom: max(var(--safe-area-inset-bottom), var(--ha-space-6));
|
padding-bottom: max(var(--safe-area-inset-bottom), 24px);
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-domain="camera"] .content {
|
[data-domain="camera"] .content {
|
||||||
@@ -153,7 +153,7 @@ export class MoreInfoInfo extends LitElement {
|
|||||||
ha-more-info-history,
|
ha-more-info-history,
|
||||||
ha-more-info-logbook:not(:last-child) {
|
ha-more-info-logbook:not(:last-child) {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: var(--ha-space-4);
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-alert {
|
ha-alert {
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ export class MoreInfoLogbook extends LitElement {
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: var(--ha-space-2);
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
.header > a,
|
.header > a,
|
||||||
a:visited {
|
a:visited {
|
||||||
|
|||||||
@@ -83,8 +83,7 @@ export class HaMoreInfoSettings extends LitElement {
|
|||||||
return [
|
return [
|
||||||
css`
|
css`
|
||||||
.content {
|
.content {
|
||||||
padding: var(--ha-space-2) var(--ha-space-6) var(--ha-space-6)
|
padding: 8px 24px 24px 24px;
|
||||||
var(--ha-space-6);
|
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ class MoreInfoContent extends LitElement {
|
|||||||
hui-section {
|
hui-section {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: var(--ha-space-4);
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1120,7 +1120,7 @@ export class QuickBar extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.nothing-found {
|
.nothing-found {
|
||||||
padding: var(--ha-space-4) 0;
|
padding: var(--ha-space-4) var(--ha-space-0);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -123,8 +123,8 @@ export const ScrollableFadeMixin = <T extends Constructor<LitElement>>(
|
|||||||
.fade-top,
|
.fade-top,
|
||||||
.fade-bottom {
|
.fade-bottom {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: var(--ha-space-0);
|
||||||
right: 0;
|
right: var(--ha-space-0);
|
||||||
height: var(--ha-space-4);
|
height: var(--ha-space-4);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
transition: opacity 180ms ease-in-out;
|
transition: opacity 180ms ease-in-out;
|
||||||
@@ -137,10 +137,10 @@ export const ScrollableFadeMixin = <T extends Constructor<LitElement>>(
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
.fade-top {
|
.fade-top {
|
||||||
top: 0;
|
top: var(--ha-space-0);
|
||||||
}
|
}
|
||||||
.fade-bottom {
|
.fade-bottom {
|
||||||
bottom: 0;
|
bottom: var(--ha-space-0);
|
||||||
transform: rotate(180deg);
|
transform: rotate(180deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2016,12 +2016,12 @@ class DialogAddAutomationElement
|
|||||||
--ha-bottom-sheet-height: calc(100dvh - var(--ha-space-12));
|
--ha-bottom-sheet-height: calc(100dvh - var(--ha-space-12));
|
||||||
--ha-bottom-sheet-max-height: var(--ha-bottom-sheet-height);
|
--ha-bottom-sheet-max-height: var(--ha-bottom-sheet-height);
|
||||||
--ha-bottom-sheet-max-width: 888px;
|
--ha-bottom-sheet-max-width: 888px;
|
||||||
--ha-bottom-sheet-padding: 0;
|
--ha-bottom-sheet-padding: var(--ha-space-0);
|
||||||
--ha-bottom-sheet-surface-background: var(--card-background-color);
|
--ha-bottom-sheet-surface-background: var(--card-background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-wa-dialog {
|
ha-wa-dialog {
|
||||||
--dialog-content-padding: 0;
|
--dialog-content-padding: var(--ha-space-0);
|
||||||
--ha-dialog-min-height: min(
|
--ha-dialog-min-height: min(
|
||||||
800px,
|
800px,
|
||||||
calc(
|
calc(
|
||||||
@@ -2045,7 +2045,7 @@ class DialogAddAutomationElement
|
|||||||
|
|
||||||
search-input {
|
search-input {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0 var(--ha-space-4);
|
margin: var(--ha-space-0) var(--ha-space-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-button-toggle-group {
|
ha-button-toggle-group {
|
||||||
@@ -2079,7 +2079,7 @@ class DialogAddAutomationElement
|
|||||||
.groups {
|
.groups {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
flex: 4;
|
flex: 4;
|
||||||
margin-inline-end: 0;
|
margin-inline-end: var(--ha-space-0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-automation-add-from-target.hidden {
|
ha-automation-add-from-target.hidden {
|
||||||
|
|||||||
@@ -213,8 +213,8 @@ export class HaAutomationAddItems extends LitElement {
|
|||||||
background-color: var(--ha-color-surface-default);
|
background-color: var(--ha-color-surface-default);
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: var(--ha-color-text-secondary);
|
color: var(--ha-color-text-secondary);
|
||||||
padding: 0;
|
padding: var(--ha-space-0);
|
||||||
margin: 0 var(--ha-space-4)
|
margin: var(--ha-space-0) var(--ha-space-4)
|
||||||
max(var(--safe-area-inset-bottom), var(--ha-space-3));
|
max(var(--safe-area-inset-bottom), var(--ha-space-3));
|
||||||
line-height: var(--ha-line-height-expanded);
|
line-height: var(--ha-line-height-expanded);
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -233,7 +233,7 @@ export class HaAutomationAddItems extends LitElement {
|
|||||||
--md-list-item-supporting-text-font: var(--ha-font-family-body);
|
--md-list-item-supporting-text-font: var(--ha-font-family-body);
|
||||||
--ha-md-list-item-gap: var(--ha-space-3);
|
--ha-md-list-item-gap: var(--ha-space-3);
|
||||||
gap: var(--ha-space-2);
|
gap: var(--ha-space-2);
|
||||||
padding: 0 var(--ha-space-4);
|
padding: var(--ha-space-0) var(--ha-space-4);
|
||||||
}
|
}
|
||||||
.items ha-md-list ha-md-list-item {
|
.items ha-md-list ha-md-list-item {
|
||||||
border-radius: var(--ha-border-radius-lg);
|
border-radius: var(--ha-border-radius-lg);
|
||||||
|
|||||||
@@ -327,7 +327,7 @@ export class HaAutomationAddSearch extends LitElement {
|
|||||||
style=${styleMap({
|
style=${styleMap({
|
||||||
width: "var(--ha-space-12)",
|
width: "var(--ha-space-12)",
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: "0",
|
top: "var(--ha-space-0)",
|
||||||
left: rtl ? undefined : "var(--ha-space-1)",
|
left: rtl ? undefined : "var(--ha-space-1)",
|
||||||
right: rtl ? "var(--ha-space-1)" : undefined,
|
right: rtl ? "var(--ha-space-1)" : undefined,
|
||||||
transform: rtl ? "scaleX(-1)" : "",
|
transform: rtl ? "scaleX(-1)" : "",
|
||||||
|
|||||||
@@ -256,7 +256,6 @@ export class HaPlatformCondition extends LitElement {
|
|||||||
: undefined}
|
: undefined}
|
||||||
.placeholder=${dataField.default}
|
.placeholder=${dataField.default}
|
||||||
.localizeValue=${this._localizeValueCallback}
|
.localizeValue=${this._localizeValueCallback}
|
||||||
.required=${dataField.required}
|
|
||||||
></ha-selector>
|
></ha-selector>
|
||||||
</ha-settings-row>`
|
</ha-settings-row>`
|
||||||
: nothing;
|
: nothing;
|
||||||
|
|||||||
@@ -292,7 +292,6 @@ export class HaPlatformTrigger extends LitElement {
|
|||||||
: undefined}
|
: undefined}
|
||||||
.placeholder=${dataField.default}
|
.placeholder=${dataField.default}
|
||||||
.localizeValue=${this._localizeValueCallback}
|
.localizeValue=${this._localizeValueCallback}
|
||||||
.required=${dataField.required}
|
|
||||||
></ha-selector>
|
></ha-selector>
|
||||||
</ha-settings-row>`
|
</ha-settings-row>`
|
||||||
: nothing;
|
: nothing;
|
||||||
|
|||||||
@@ -462,7 +462,7 @@ class AddIntegrationDialog extends LitElement {
|
|||||||
style=${styleMap({
|
style=${styleMap({
|
||||||
width: `${this._width}px`,
|
width: `${this._width}px`,
|
||||||
height: this._narrow
|
height: this._narrow
|
||||||
? "calc(100vh - 184px - var(--safe-area-inset-top, 0px) - var(--safe-area-inset-bottom, 0px))"
|
? "calc(100vh - 184px - var(--safe-area-inset-top, var(--ha-space-0)) - var(--safe-area-inset-bottom, var(--ha-space-0)))"
|
||||||
: "500px",
|
: "500px",
|
||||||
})}
|
})}
|
||||||
@click=${this._integrationPicked}
|
@click=${this._integrationPicked}
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ export class DialogLabsPreviewFeatureEnable
|
|||||||
|
|
||||||
static readonly styles = css`
|
static readonly styles = css`
|
||||||
ha-wa-dialog {
|
ha-wa-dialog {
|
||||||
--dialog-content-padding: 0;
|
--dialog-content-padding: var(--ha-space-0);
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
|
|||||||
@@ -1,31 +1,20 @@
|
|||||||
import {
|
import { mdiChevronDown } from "@mdi/js";
|
||||||
mdiChevronDown,
|
|
||||||
mdiChip,
|
|
||||||
mdiDns,
|
|
||||||
mdiPackageVariant,
|
|
||||||
mdiPuzzle,
|
|
||||||
mdiRadar,
|
|
||||||
mdiVolumeHigh,
|
|
||||||
} from "@mdi/js";
|
|
||||||
import type { CSSResultGroup, TemplateResult } from "lit";
|
import type { CSSResultGroup, TemplateResult } from "lit";
|
||||||
import { css, html, LitElement, nothing } from "lit";
|
import { css, html, LitElement } from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
|
||||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||||
import { atLeastVersion } from "../../../common/config/version";
|
|
||||||
import { navigate } from "../../../common/navigate";
|
import { navigate } from "../../../common/navigate";
|
||||||
import { stringCompare } from "../../../common/string/compare";
|
import { stringCompare } from "../../../common/string/compare";
|
||||||
import { extractSearchParam } from "../../../common/url/search-params";
|
import { extractSearchParam } from "../../../common/url/search-params";
|
||||||
import "../../../components/ha-button";
|
import "../../../components/ha-button";
|
||||||
import "../../../components/ha-generic-picker";
|
import "../../../components/ha-dropdown";
|
||||||
import type { HaGenericPicker } from "../../../components/ha-generic-picker";
|
import "../../../components/ha-dropdown-item";
|
||||||
import type { PickerComboBoxItem } from "../../../components/ha-picker-combo-box";
|
import type { HaDropdownItem } from "../../../components/ha-dropdown-item";
|
||||||
import "../../../components/search-input";
|
import "../../../components/search-input";
|
||||||
import type { LogProvider } from "../../../data/error_log";
|
import type { LogProvider } from "../../../data/error_log";
|
||||||
import { fetchHassioAddonsInfo } from "../../../data/hassio/addon";
|
import { fetchHassioAddonsInfo } from "../../../data/hassio/addon";
|
||||||
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
|
import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
|
||||||
import "../../../layouts/hass-subpage";
|
import "../../../layouts/hass-subpage";
|
||||||
import { mdiHomeAssistant } from "../../../resources/home-assistant-logo-svg";
|
|
||||||
import { haStyle } from "../../../resources/styles";
|
import { haStyle } from "../../../resources/styles";
|
||||||
import type { HomeAssistant, Route } from "../../../types";
|
import type { HomeAssistant, Route } from "../../../types";
|
||||||
import "./error-log-card";
|
import "./error-log-card";
|
||||||
@@ -75,8 +64,6 @@ export class HaConfigLogs extends LitElement {
|
|||||||
|
|
||||||
@query("system-log-card") private systemLog?: SystemLogCard;
|
@query("system-log-card") private systemLog?: SystemLogCard;
|
||||||
|
|
||||||
@query("ha-generic-picker") private providerPicker?: HaGenericPicker;
|
|
||||||
|
|
||||||
@state() private _selectedLogProvider = "core";
|
@state() private _selectedLogProvider = "core";
|
||||||
|
|
||||||
@state() private _logProviders = logProviders;
|
@state() private _logProviders = logProviders;
|
||||||
@@ -122,8 +109,6 @@ export class HaConfigLogs extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const selectedProvider = this._getActiveProvider(this._selectedLogProvider);
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<hass-subpage
|
<hass-subpage
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
@@ -131,39 +116,33 @@ export class HaConfigLogs extends LitElement {
|
|||||||
.header=${this.hass.localize("ui.panel.config.logs.caption")}
|
.header=${this.hass.localize("ui.panel.config.logs.caption")}
|
||||||
back-path="/config/system"
|
back-path="/config/system"
|
||||||
>
|
>
|
||||||
${isComponentLoaded(this.hass, "hassio") && this._logProviders
|
${isComponentLoaded(this.hass, "hassio")
|
||||||
? html`
|
? html`
|
||||||
<ha-generic-picker
|
<ha-dropdown
|
||||||
slot="toolbar-icon"
|
slot="toolbar-icon"
|
||||||
.hass=${this.hass}
|
@wa-select=${this._handleDropdownSelect}
|
||||||
.getItems=${this._getLogProviderItems}
|
|
||||||
value=""
|
|
||||||
.rowRenderer=${this._providerRenderer}
|
|
||||||
@value-changed=${this._handleDropdownSelect}
|
|
||||||
>
|
>
|
||||||
<ha-button
|
<ha-button slot="trigger" appearance="filled">
|
||||||
slot="field"
|
|
||||||
appearance="filled"
|
|
||||||
@click=${this._openPicker}
|
|
||||||
>
|
|
||||||
${selectedProvider?.icon
|
|
||||||
? html`<img
|
|
||||||
src=${selectedProvider.icon}
|
|
||||||
alt=${selectedProvider.primary}
|
|
||||||
slot="start"
|
|
||||||
/>`
|
|
||||||
: selectedProvider?.icon_path
|
|
||||||
? html`<ha-svg-icon
|
|
||||||
slot="start"
|
|
||||||
.path=${selectedProvider.icon_path}
|
|
||||||
></ha-svg-icon>`
|
|
||||||
: nothing}
|
|
||||||
${selectedProvider?.primary}
|
|
||||||
<ha-svg-icon slot="end" .path=${mdiChevronDown}></ha-svg-icon>
|
<ha-svg-icon slot="end" .path=${mdiChevronDown}></ha-svg-icon>
|
||||||
|
${this._logProviders.find(
|
||||||
|
(p) => p.key === this._selectedLogProvider
|
||||||
|
)!.name}
|
||||||
</ha-button>
|
</ha-button>
|
||||||
</ha-generic-picker>
|
${this._logProviders.map(
|
||||||
|
(provider) => html`
|
||||||
|
<ha-dropdown-item
|
||||||
|
.value=${provider.key}
|
||||||
|
class=${provider.key === this._selectedLogProvider
|
||||||
|
? "selected"
|
||||||
|
: ""}
|
||||||
|
>
|
||||||
|
${provider.name}
|
||||||
|
</ha-dropdown-item>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</ha-dropdown>
|
||||||
`
|
`
|
||||||
: nothing}
|
: ""}
|
||||||
${search}
|
${search}
|
||||||
<div class="content">
|
<div class="content">
|
||||||
${this._selectedLogProvider === "core" && !this._detail
|
${this._selectedLogProvider === "core" && !this._detail
|
||||||
@@ -196,13 +175,8 @@ export class HaConfigLogs extends LitElement {
|
|||||||
this._detail = !this._detail;
|
this._detail = !this._detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _openPicker(ev: Event) {
|
private _handleDropdownSelect(ev: CustomEvent<{ item: HaDropdownItem }>) {
|
||||||
ev.stopPropagation();
|
const provider = ev.detail?.item?.value;
|
||||||
this.providerPicker?.open();
|
|
||||||
}
|
|
||||||
|
|
||||||
private _handleDropdownSelect(ev: CustomEvent<{ value: string }>) {
|
|
||||||
const provider = ev.detail?.value;
|
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -249,7 +223,6 @@ export class HaConfigLogs extends LitElement {
|
|||||||
.map((addon) => ({
|
.map((addon) => ({
|
||||||
key: addon.slug,
|
key: addon.slug,
|
||||||
name: addon.name,
|
name: addon.name,
|
||||||
addon,
|
|
||||||
}))
|
}))
|
||||||
.sort((a, b) =>
|
.sort((a, b) =>
|
||||||
stringCompare(a.name, b.name, this.hass.locale.language)
|
stringCompare(a.name, b.name, this.hass.locale.language)
|
||||||
@@ -261,78 +234,6 @@ export class HaConfigLogs extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getLogProviderItems = (): PickerComboBoxItem[] =>
|
|
||||||
this._logProviders.map((provider) => ({
|
|
||||||
id: provider.key,
|
|
||||||
primary: provider.name,
|
|
||||||
icon: provider.addon
|
|
||||||
? atLeastVersion(this.hass.config.version, 0, 105) &&
|
|
||||||
provider.addon.icon
|
|
||||||
? `/api/hassio/addons/${provider.addon.slug}/icon`
|
|
||||||
: undefined
|
|
||||||
: undefined,
|
|
||||||
icon_path: provider.addon
|
|
||||||
? mdiPuzzle
|
|
||||||
: this._getProviderIconPath(provider.key),
|
|
||||||
}));
|
|
||||||
|
|
||||||
private _providerRenderer = (item: PickerComboBoxItem) => html`
|
|
||||||
<ha-combo-box-item type="button" compact>
|
|
||||||
${item.icon
|
|
||||||
? html`<img src=${item.icon} alt=${item.primary} slot="start" />`
|
|
||||||
: item.icon_path
|
|
||||||
? html`<ha-svg-icon
|
|
||||||
slot="start"
|
|
||||||
.path=${item.icon_path}
|
|
||||||
></ha-svg-icon>`
|
|
||||||
: nothing}
|
|
||||||
<span slot="headline">${item.primary}</span>
|
|
||||||
${item.secondary
|
|
||||||
? html`<span slot="supporting-text">${item.secondary}</span>`
|
|
||||||
: nothing}
|
|
||||||
</ha-combo-box-item>
|
|
||||||
`;
|
|
||||||
|
|
||||||
private _getActiveProvider = memoizeOne((selectedLogProvider: string) => {
|
|
||||||
const provider = this._logProviders.find(
|
|
||||||
(p) => p.key === selectedLogProvider
|
|
||||||
);
|
|
||||||
if (provider) {
|
|
||||||
return {
|
|
||||||
id: provider.key,
|
|
||||||
primary: provider.name,
|
|
||||||
icon: provider.addon
|
|
||||||
? atLeastVersion(this.hass.config.version, 0, 105) &&
|
|
||||||
provider.addon.icon
|
|
||||||
? `/api/hassio/addons/${provider.addon.slug}/icon`
|
|
||||||
: undefined
|
|
||||||
: undefined,
|
|
||||||
icon_path: provider.addon
|
|
||||||
? mdiPuzzle
|
|
||||||
: this._getProviderIconPath(provider.key),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
private _getProviderIconPath(providerKey: string): string | undefined {
|
|
||||||
switch (providerKey) {
|
|
||||||
case "core":
|
|
||||||
return mdiHomeAssistant;
|
|
||||||
case "supervisor":
|
|
||||||
return mdiPackageVariant;
|
|
||||||
case "host":
|
|
||||||
return mdiChip;
|
|
||||||
case "dns":
|
|
||||||
return mdiDns;
|
|
||||||
case "audio":
|
|
||||||
return mdiVolumeHigh;
|
|
||||||
case "multicast":
|
|
||||||
return mdiRadar;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
@@ -361,17 +262,8 @@ export class HaConfigLogs extends LitElement {
|
|||||||
.content {
|
.content {
|
||||||
direction: ltr;
|
direction: ltr;
|
||||||
}
|
}
|
||||||
ha-generic-picker {
|
|
||||||
--md-list-item-leading-icon-color: var(--ha-color-primary-50);
|
|
||||||
--mdc-icon-size: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
height: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media all and (max-width: 870px) {
|
@media all and (max-width: 870px) {
|
||||||
ha-generic-picker {
|
ha-dropdown {
|
||||||
max-width: 50%;
|
max-width: 50%;
|
||||||
}
|
}
|
||||||
ha-button {
|
ha-button {
|
||||||
@@ -382,6 +274,9 @@ export class HaConfigLogs extends LitElement {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ha-dropdown-item.selected {
|
||||||
|
font-weight: var(--ha-font-weight-bold);
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,11 +31,7 @@ import { formatTime } from "../../../../../common/datetime/format_time";
|
|||||||
import type { ECOption } from "../../../../../resources/echarts/echarts";
|
import type { ECOption } from "../../../../../resources/echarts/echarts";
|
||||||
import { filterXSS } from "../../../../../common/util/xss";
|
import { filterXSS } from "../../../../../common/util/xss";
|
||||||
|
|
||||||
export function getSuggestedMax(
|
export function getSuggestedMax(dayDifference: number, end: Date): number {
|
||||||
dayDifference: number,
|
|
||||||
end: Date,
|
|
||||||
detailedDailyData = false
|
|
||||||
): number {
|
|
||||||
let suggestedMax = new Date(end);
|
let suggestedMax = new Date(end);
|
||||||
|
|
||||||
// Sometimes around DST we get a time of 0:59 instead of 23:59 as expected.
|
// Sometimes around DST we get a time of 0:59 instead of 23:59 as expected.
|
||||||
@@ -44,9 +40,7 @@ export function getSuggestedMax(
|
|||||||
suggestedMax = subHours(suggestedMax, 1);
|
suggestedMax = subHours(suggestedMax, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!detailedDailyData) {
|
suggestedMax.setMinutes(0, 0, 0);
|
||||||
suggestedMax.setMinutes(0, 0, 0);
|
|
||||||
}
|
|
||||||
if (dayDifference > 35) {
|
if (dayDifference > 35) {
|
||||||
suggestedMax.setDate(1);
|
suggestedMax.setDate(1);
|
||||||
}
|
}
|
||||||
@@ -83,8 +77,7 @@ export function getCommonOptions(
|
|||||||
unit?: string,
|
unit?: string,
|
||||||
compareStart?: Date,
|
compareStart?: Date,
|
||||||
compareEnd?: Date,
|
compareEnd?: Date,
|
||||||
formatTotal?: (total: number) => string,
|
formatTotal?: (total: number) => string
|
||||||
detailedDailyData = false
|
|
||||||
): ECOption {
|
): ECOption {
|
||||||
const dayDifference = differenceInDays(end, start);
|
const dayDifference = differenceInDays(end, start);
|
||||||
|
|
||||||
@@ -96,7 +89,7 @@ export function getCommonOptions(
|
|||||||
xAxis: {
|
xAxis: {
|
||||||
type: "time",
|
type: "time",
|
||||||
min: start,
|
min: start,
|
||||||
max: getSuggestedMax(dayDifference, end, detailedDailyData),
|
max: getSuggestedMax(dayDifference, end),
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {
|
||||||
type: "value",
|
type: "value",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { endOfToday, isSameDay, isToday, startOfToday } from "date-fns";
|
import { endOfToday, isToday, startOfToday } from "date-fns";
|
||||||
import type { HassConfig, UnsubscribeFunc } from "home-assistant-js-websocket";
|
import type { HassConfig, UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
import type { PropertyValues } from "lit";
|
import type { PropertyValues } from "lit";
|
||||||
import { css, html, LitElement, nothing } from "lit";
|
import { css, html, LitElement, nothing } from "lit";
|
||||||
@@ -132,9 +132,7 @@ export class HuiPowerSourcesGraphCard
|
|||||||
config,
|
config,
|
||||||
"kW",
|
"kW",
|
||||||
compareStart,
|
compareStart,
|
||||||
compareEnd,
|
compareEnd
|
||||||
undefined,
|
|
||||||
true
|
|
||||||
),
|
),
|
||||||
legend: {
|
legend: {
|
||||||
show: this._config?.show_legend !== false,
|
show: this._config?.show_legend !== false,
|
||||||
@@ -212,17 +210,14 @@ export class HuiPowerSourcesGraphCard
|
|||||||
const { positive, negative } = this._processData(
|
const { positive, negative } = this._processData(
|
||||||
statIds[key].stats.map((id: string) => {
|
statIds[key].stats.map((id: string) => {
|
||||||
const stats = energyData.stats[id] ?? [];
|
const stats = energyData.stats[id] ?? [];
|
||||||
if (isSameDay(now, this._start) && isSameDay(now, this._end)) {
|
const currentStateWatts = getPowerFromState(this.hass.states[id]);
|
||||||
// Append current state if we are showing today
|
if (currentStateWatts !== undefined) {
|
||||||
const currentStateWatts = getPowerFromState(this.hass.states[id]);
|
// getPowerFromState returns power in W; convert to kW for this graph
|
||||||
if (currentStateWatts !== undefined) {
|
stats.push({
|
||||||
// getPowerFromState returns power in W; convert to kW for this graph
|
start: now,
|
||||||
stats.push({
|
end: now,
|
||||||
start: now,
|
mean: currentStateWatts / 1000,
|
||||||
end: now,
|
});
|
||||||
mean: currentStateWatts / 1000,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return stats;
|
return stats;
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -732,7 +732,9 @@ export class HuiAreaCard extends LitElement implements LovelaceCard {
|
|||||||
padding: 0 var(--ha-space-3) var(--ha-space-3) var(--ha-space-3);
|
padding: 0 var(--ha-space-3) var(--ha-space-3) var(--ha-space-3);
|
||||||
}
|
}
|
||||||
.container.horizontal hui-card-features {
|
.container.horizontal hui-card-features {
|
||||||
width: calc(50% - var(--column-gap, 0px) / 2 - var(--ha-space-3));
|
width: calc(
|
||||||
|
50% - var(--column-gap, var(--ha-space-0)) / 2 - var(--ha-space-3)
|
||||||
|
);
|
||||||
flex: none;
|
flex: none;
|
||||||
--feature-height: var(--ha-space-9);
|
--feature-height: var(--ha-space-9);
|
||||||
padding: 0 var(--ha-space-3);
|
padding: 0 var(--ha-space-3);
|
||||||
|
|||||||
@@ -268,7 +268,6 @@ export class HuiHistoryGraphCard extends LitElement implements LovelaceCard {
|
|||||||
now.setHours(now.getHours() - this._hoursToShow);
|
now.setHours(now.getHours() - this._hoursToShow);
|
||||||
const configUrl = `/history?${createSearchParam({
|
const configUrl = `/history?${createSearchParam({
|
||||||
entity_id: this._entityIds.join(","),
|
entity_id: this._entityIds.join(","),
|
||||||
back: "1",
|
|
||||||
start_date: now.toISOString(),
|
start_date: now.toISOString(),
|
||||||
})}`;
|
})}`;
|
||||||
|
|
||||||
|
|||||||
@@ -141,13 +141,12 @@ export class HomeOverviewViewStrategy extends ReactiveElement {
|
|||||||
);
|
);
|
||||||
const maxCommonControls = Math.max(8, favoriteEntities.length);
|
const maxCommonControls = Math.max(8, favoriteEntities.length);
|
||||||
|
|
||||||
const favoritesSection = {
|
const commonControlsSection = {
|
||||||
strategy: {
|
strategy: {
|
||||||
type: "common-controls",
|
type: "common-controls",
|
||||||
limit: maxCommonControls,
|
limit: maxCommonControls,
|
||||||
include_entities: favoriteEntities,
|
include_entities: favoriteEntities,
|
||||||
title: hass.localize("ui.panel.lovelace.strategy.home.favorites"),
|
title: hass.localize("ui.panel.lovelace.strategy.home.favorites"),
|
||||||
title_visibilty: [largeScreenCondition],
|
|
||||||
hide_empty: true,
|
hide_empty: true,
|
||||||
} satisfies CommonControlSectionStrategyConfig,
|
} satisfies CommonControlSectionStrategyConfig,
|
||||||
column_span: maxColumns,
|
column_span: maxColumns,
|
||||||
@@ -261,18 +260,10 @@ export class HomeOverviewViewStrategy extends ReactiveElement {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
// Build summary cards for mobile section (half width: columns 6)
|
// Build summary cards for mobile section (half width: columns 6)
|
||||||
const mobileSummaryCards = [
|
const mobileSummaryCards = summaryCards.map((card) => ({
|
||||||
...summaryCards.map((card) => ({
|
...card,
|
||||||
...card,
|
grid_options: { columns: 6 },
|
||||||
grid_options: { columns: 6 },
|
}));
|
||||||
})),
|
|
||||||
];
|
|
||||||
|
|
||||||
const summaryHeadingCard: LovelaceCardConfig = {
|
|
||||||
type: "heading",
|
|
||||||
heading: hass.localize("ui.panel.lovelace.strategy.home.summaries"),
|
|
||||||
heading_style: "title",
|
|
||||||
};
|
|
||||||
|
|
||||||
// Mobile summary section (visible on small screens only)
|
// Mobile summary section (visible on small screens only)
|
||||||
const mobileSummarySection: LovelaceSectionConfig | undefined =
|
const mobileSummarySection: LovelaceSectionConfig | undefined =
|
||||||
@@ -281,7 +272,7 @@ export class HomeOverviewViewStrategy extends ReactiveElement {
|
|||||||
type: "grid",
|
type: "grid",
|
||||||
column_span: maxColumns,
|
column_span: maxColumns,
|
||||||
visibility: [smallScreenCondition],
|
visibility: [smallScreenCondition],
|
||||||
cards: [summaryHeadingCard, ...mobileSummaryCards],
|
cards: mobileSummaryCards,
|
||||||
}
|
}
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
@@ -290,15 +281,25 @@ export class HomeOverviewViewStrategy extends ReactiveElement {
|
|||||||
sidebarSummaryCards.length > 0
|
sidebarSummaryCards.length > 0
|
||||||
? {
|
? {
|
||||||
type: "grid",
|
type: "grid",
|
||||||
cards: [summaryHeadingCard, ...sidebarSummaryCards],
|
cards: [
|
||||||
|
{
|
||||||
|
type: "heading",
|
||||||
|
heading: hass.localize(
|
||||||
|
"ui.panel.lovelace.strategy.home.for_you"
|
||||||
|
),
|
||||||
|
heading_style: "title",
|
||||||
|
},
|
||||||
|
...sidebarSummaryCards,
|
||||||
|
],
|
||||||
}
|
}
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const sections = (
|
const sections = (
|
||||||
[favoritesSection, mobileSummarySection, ...floorsSections] satisfies (
|
[
|
||||||
| LovelaceSectionRawConfig
|
mobileSummarySection,
|
||||||
| undefined
|
commonControlsSection,
|
||||||
)[]
|
...floorsSections,
|
||||||
|
] satisfies (LovelaceSectionRawConfig | undefined)[]
|
||||||
).filter(Boolean) as LovelaceSectionRawConfig[];
|
).filter(Boolean) as LovelaceSectionRawConfig[];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -318,7 +319,7 @@ export class HomeOverviewViewStrategy extends ReactiveElement {
|
|||||||
sections: [sidebarSection],
|
sections: [sidebarSection],
|
||||||
content_label: hass.localize("ui.panel.lovelace.strategy.home.home"),
|
content_label: hass.localize("ui.panel.lovelace.strategy.home.home"),
|
||||||
sidebar_label: hass.localize(
|
sidebar_label: hass.localize(
|
||||||
"ui.panel.lovelace.strategy.home.summaries"
|
"ui.panel.lovelace.strategy.home.for_you"
|
||||||
),
|
),
|
||||||
visibility: [largeScreenCondition],
|
visibility: [largeScreenCondition],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import type { LovelaceSectionConfig } from "../../../../data/lovelace/config/sec
|
|||||||
import { getCommonControlUsagePrediction } from "../../../../data/usage_prediction";
|
import { getCommonControlUsagePrediction } from "../../../../data/usage_prediction";
|
||||||
import type { HomeAssistant } from "../../../../types";
|
import type { HomeAssistant } from "../../../../types";
|
||||||
import type { HeadingCardConfig, TileCardConfig } from "../../cards/types";
|
import type { HeadingCardConfig, TileCardConfig } from "../../cards/types";
|
||||||
import type { Condition } from "../../common/validate-condition";
|
|
||||||
|
|
||||||
const DEFAULT_LIMIT = 8;
|
const DEFAULT_LIMIT = 8;
|
||||||
|
|
||||||
@@ -17,7 +16,6 @@ export interface CommonControlSectionStrategyConfig {
|
|||||||
exclude_entities?: string[];
|
exclude_entities?: string[];
|
||||||
include_entities?: string[];
|
include_entities?: string[];
|
||||||
hide_empty?: boolean;
|
hide_empty?: boolean;
|
||||||
title_visibilty?: Condition[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@customElement("common-controls-section-strategy")
|
@customElement("common-controls-section-strategy")
|
||||||
@@ -36,7 +34,6 @@ export class CommonControlsSectionStrategy extends ReactiveElement {
|
|||||||
type: "heading",
|
type: "heading",
|
||||||
heading: config.title,
|
heading: config.title,
|
||||||
icon: config.icon,
|
icon: config.icon,
|
||||||
visibility: config.title_visibilty,
|
|
||||||
} satisfies HeadingCardConfig);
|
} satisfies HeadingCardConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -142,10 +142,11 @@ export const haStyleDialog = css`
|
|||||||
--mdc-dialog-max-width: 600px;
|
--mdc-dialog-max-width: 600px;
|
||||||
--mdc-dialog-max-width: min(600px, 95vw);
|
--mdc-dialog-max-width: min(600px, 95vw);
|
||||||
--justify-action-buttons: space-between;
|
--justify-action-buttons: space-between;
|
||||||
--dialog-container-padding: var(--safe-area-inset-top, 0)
|
--dialog-container-padding: var(--safe-area-inset-top, var(--ha-space-0))
|
||||||
var(--safe-area-inset-right, 0) var(--safe-area-inset-bottom, 0)
|
var(--safe-area-inset-right, var(--ha-space-0))
|
||||||
var(--safe-area-inset-left, 0);
|
var(--safe-area-inset-bottom, var(--ha-space-0))
|
||||||
--dialog-surface-padding: 0px;
|
var(--safe-area-inset-left, var(--ha-space-0));
|
||||||
|
--dialog-surface-padding: var(--ha-space-0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-dialog .form {
|
ha-dialog .form {
|
||||||
@@ -165,10 +166,11 @@ export const haStyleDialog = css`
|
|||||||
--mdc-dialog-min-height: 100svh;
|
--mdc-dialog-min-height: 100svh;
|
||||||
--mdc-dialog-max-height: 100vh;
|
--mdc-dialog-max-height: 100vh;
|
||||||
--mdc-dialog-max-height: 100svh;
|
--mdc-dialog-max-height: 100svh;
|
||||||
--dialog-container-padding: 0px;
|
--dialog-container-padding: var(--ha-space-0);
|
||||||
--dialog-surface-padding: var(--safe-area-inset-top, 0)
|
--dialog-surface-padding: var(--safe-area-inset-top, var(--ha-space-0))
|
||||||
var(--safe-area-inset-right, 0) var(--safe-area-inset-bottom, 0)
|
var(--safe-area-inset-right, var(--ha-space-0))
|
||||||
var(--safe-area-inset-left, 0);
|
var(--safe-area-inset-bottom, var(--ha-space-0))
|
||||||
|
var(--safe-area-inset-left, var(--ha-space-0));
|
||||||
--vertical-align-dialog: flex-end;
|
--vertical-align-dialog: flex-end;
|
||||||
--ha-dialog-border-radius: var(--ha-border-radius-square);
|
--ha-dialog-border-radius: var(--ha-border-radius-square);
|
||||||
}
|
}
|
||||||
@@ -186,13 +188,13 @@ export const haStyleDialogFixedTop = css`
|
|||||||
--mdc-dialog-max-height: calc(
|
--mdc-dialog-max-height: calc(
|
||||||
100vh - var(--dialog-surface-margin-top) - var(--ha-space-2) - var(
|
100vh - var(--dialog-surface-margin-top) - var(--ha-space-2) - var(
|
||||||
--safe-area-inset-y,
|
--safe-area-inset-y,
|
||||||
0px
|
var(--ha-space-0)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
--mdc-dialog-max-height: calc(
|
--mdc-dialog-max-height: calc(
|
||||||
100svh - var(--dialog-surface-margin-top) - var(--ha-space-2) - var(
|
100svh - var(--dialog-surface-margin-top) - var(--ha-space-2) - var(
|
||||||
--safe-area-inset-y,
|
--safe-area-inset-y,
|
||||||
0px
|
var(--ha-space-0)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -200,7 +202,7 @@ export const haStyleDialogFixedTop = css`
|
|||||||
@media all and (max-width: 450px), all and (max-height: 500px) {
|
@media all and (max-width: 450px), all and (max-height: 500px) {
|
||||||
ha-dialog {
|
ha-dialog {
|
||||||
/* When in fullscreen, dialog should be attached to top */
|
/* When in fullscreen, dialog should be attached to top */
|
||||||
--dialog-surface-margin-top: 0px;
|
--dialog-surface-margin-top: var(--ha-space-0);
|
||||||
--mdc-dialog-min-height: 100vh;
|
--mdc-dialog-min-height: 100vh;
|
||||||
--mdc-dialog-min-height: 100svh;
|
--mdc-dialog-min-height: 100svh;
|
||||||
--mdc-dialog-max-height: 100vh;
|
--mdc-dialog-max-height: 100vh;
|
||||||
|
|||||||
@@ -339,6 +339,12 @@ export const colorStyles = css`
|
|||||||
--ha-assist-chip-filled-container-color: rgba(var(--rgb-primary-text-color), 0.15);
|
--ha-assist-chip-filled-container-color: rgba(var(--rgb-primary-text-color), 0.15);
|
||||||
--ha-assist-chip-active-container-color: rgba(var(--rgb-primary-color), 0.15);
|
--ha-assist-chip-active-container-color: rgba(var(--rgb-primary-color), 0.15);
|
||||||
--chip-background-color: rgba(var(--rgb-primary-text-color), 0.15);
|
--chip-background-color: rgba(var(--rgb-primary-text-color), 0.15);
|
||||||
|
|
||||||
|
/* Vaadin */
|
||||||
|
--material-body-text-color: var(--primary-text-color);
|
||||||
|
--material-background-color: var(--card-background-color);
|
||||||
|
--material-secondary-background-color: var(--secondary-background-color);
|
||||||
|
--material-secondary-text-color: var(--secondary-text-color);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export const coreStyles = css`
|
|||||||
--ha-border-radius-square: 0;
|
--ha-border-radius-square: 0;
|
||||||
|
|
||||||
/* Spacing */
|
/* Spacing */
|
||||||
|
--ha-space-0: 0px;
|
||||||
--ha-space-1: 4px;
|
--ha-space-1: 4px;
|
||||||
--ha-space-2: 8px;
|
--ha-space-2: 8px;
|
||||||
--ha-space-3: 12px;
|
--ha-space-3: 12px;
|
||||||
|
|||||||
@@ -36,6 +36,12 @@ export const typographyStyles = css`
|
|||||||
--ha-font-smoothing: antialiased;
|
--ha-font-smoothing: antialiased;
|
||||||
--ha-moz-osx-font-smoothing: grayscale;
|
--ha-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
|
/* Vaadin typography */
|
||||||
|
--material-h6-font-size: var(--ha-font-size-m);
|
||||||
|
--material-small-font-size: var(--ha-font-size-xs);
|
||||||
|
--material-caption-font-size: var(--ha-font-size-2xs);
|
||||||
|
--material-button-font-size: var(--ha-font-size-xs);
|
||||||
|
|
||||||
/* Add font to lists since default does not handle non-latin characters */
|
/* Add font to lists since default does not handle non-latin characters */
|
||||||
--md-list-item-label-text-font: var(--ha-font-family-body);
|
--md-list-item-label-text-font: var(--ha-font-family-body);
|
||||||
--md-list-item-supporting-text-font: var(--ha-font-family-body);
|
--md-list-item-supporting-text-font: var(--ha-font-family-body);
|
||||||
|
|||||||
@@ -1105,7 +1105,6 @@
|
|||||||
"delete": "Delete {count}",
|
"delete": "Delete {count}",
|
||||||
"deleting": "Deleting {count}",
|
"deleting": "Deleting {count}",
|
||||||
"deselect_all": "Deselect all",
|
"deselect_all": "Deselect all",
|
||||||
"select_all": "[%key:ui::components::subpage-data-table::select_all%]",
|
|
||||||
"tip_media_storage": "[%key:ui::panel::config::tips::media_storage%]",
|
"tip_media_storage": "[%key:ui::panel::config::tips::media_storage%]",
|
||||||
"tip_storage_panel": "storage"
|
"tip_storage_panel": "storage"
|
||||||
},
|
},
|
||||||
@@ -4304,7 +4303,7 @@
|
|||||||
"entity": "Entity with timestamp",
|
"entity": "Entity with timestamp",
|
||||||
"offset_by": "offset by {offset}",
|
"offset_by": "offset by {offset}",
|
||||||
"mode": "Mode",
|
"mode": "Mode",
|
||||||
"weekday": "Days of the Week",
|
"weekday": "Weekdays",
|
||||||
"weekdays": {
|
"weekdays": {
|
||||||
"mon": "[%key:ui::weekdays::monday%]",
|
"mon": "[%key:ui::weekdays::monday%]",
|
||||||
"tue": "[%key:ui::weekdays::tuesday%]",
|
"tue": "[%key:ui::weekdays::tuesday%]",
|
||||||
|
|||||||
@@ -76,60 +76,6 @@
|
|||||||
],
|
],
|
||||||
"@lit-labs/observers/resize-controller": [
|
"@lit-labs/observers/resize-controller": [
|
||||||
"./node_modules/@lit-labs/observers/resize-controller.js"
|
"./node_modules/@lit-labs/observers/resize-controller.js"
|
||||||
],
|
|
||||||
"@formatjs/intl-durationformat/should-polyfill": [
|
|
||||||
"./node_modules/@formatjs/intl-durationformat/should-polyfill.js"
|
|
||||||
],
|
|
||||||
"@formatjs/intl-durationformat/polyfill-force": [
|
|
||||||
"./node_modules/@formatjs/intl-durationformat/polyfill-force.js"
|
|
||||||
],
|
|
||||||
"@formatjs/intl-datetimeformat/should-polyfill": [
|
|
||||||
"./node_modules/@formatjs/intl-datetimeformat/should-polyfill.js"
|
|
||||||
],
|
|
||||||
"@formatjs/intl-datetimeformat/polyfill-force": [
|
|
||||||
"./node_modules/@formatjs/intl-datetimeformat/polyfill-force.js"
|
|
||||||
],
|
|
||||||
"@formatjs/intl-displaynames/should-polyfill": [
|
|
||||||
"./node_modules/@formatjs/intl-displaynames/should-polyfill.js"
|
|
||||||
],
|
|
||||||
"@formatjs/intl-displaynames/polyfill-force": [
|
|
||||||
"./node_modules/@formatjs/intl-displaynames/polyfill-force.js"
|
|
||||||
],
|
|
||||||
"@formatjs/intl-getcanonicallocales/should-polyfill": [
|
|
||||||
"./node_modules/@formatjs/intl-getcanonicallocales/should-polyfill.js"
|
|
||||||
],
|
|
||||||
"@formatjs/intl-getcanonicallocales/polyfill-force": [
|
|
||||||
"./node_modules/@formatjs/intl-getcanonicallocales/polyfill-force.js"
|
|
||||||
],
|
|
||||||
"@formatjs/intl-listformat/should-polyfill": [
|
|
||||||
"./node_modules/@formatjs/intl-listformat/should-polyfill.js"
|
|
||||||
],
|
|
||||||
"@formatjs/intl-listformat/polyfill-force": [
|
|
||||||
"./node_modules/@formatjs/intl-listformat/polyfill-force.js"
|
|
||||||
],
|
|
||||||
"@formatjs/intl-locale/should-polyfill": [
|
|
||||||
"./node_modules/@formatjs/intl-locale/should-polyfill.js"
|
|
||||||
],
|
|
||||||
"@formatjs/intl-locale/polyfill-force": [
|
|
||||||
"./node_modules/@formatjs/intl-locale/polyfill-force.js"
|
|
||||||
],
|
|
||||||
"@formatjs/intl-numberformat/should-polyfill": [
|
|
||||||
"./node_modules/@formatjs/intl-numberformat/should-polyfill.js"
|
|
||||||
],
|
|
||||||
"@formatjs/intl-numberformat/polyfill-force": [
|
|
||||||
"./node_modules/@formatjs/intl-numberformat/polyfill-force.js"
|
|
||||||
],
|
|
||||||
"@formatjs/intl-pluralrules/should-polyfill": [
|
|
||||||
"./node_modules/@formatjs/intl-pluralrules/should-polyfill.js"
|
|
||||||
],
|
|
||||||
"@formatjs/intl-pluralrules/polyfill-force": [
|
|
||||||
"./node_modules/@formatjs/intl-pluralrules/polyfill-force.js"
|
|
||||||
],
|
|
||||||
"@formatjs/intl-relativetimeformat/should-polyfill": [
|
|
||||||
"./node_modules/@formatjs/intl-relativetimeformat/should-polyfill.js"
|
|
||||||
],
|
|
||||||
"@formatjs/intl-relativetimeformat/polyfill-force": [
|
|
||||||
"./node_modules/@formatjs/intl-relativetimeformat/polyfill-force.js"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user