From 82a3b9d80f0b1c0976df2492a0bc7c711d01864c Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Wed, 3 Apr 2024 11:27:30 +0200 Subject: [PATCH] Use tree for nested floor instead of icon (#20363) --- src/components/ha-area-floor-picker.ts | 76 ++++++++++++--------- src/components/ha-filter-floor-areas.ts | 87 +++++++++++++++---------- src/components/ha-tree-indicator.ts | 36 ++++++++++ 3 files changed, 136 insertions(+), 63 deletions(-) create mode 100644 src/components/ha-tree-indicator.ts diff --git a/src/components/ha-area-floor-picker.ts b/src/components/ha-area-floor-picker.ts index d19756d6eb..12a032bdec 100644 --- a/src/components/ha-area-floor-picker.ts +++ b/src/components/ha-area-floor-picker.ts @@ -1,8 +1,9 @@ -import { mdiSubdirectoryArrowRight, mdiTextureBox } from "@mdi/js"; +import { mdiTextureBox } from "@mdi/js"; import { ComboBoxLitRenderer } from "@vaadin/combo-box/lit"; import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket"; import { LitElement, PropertyValues, TemplateResult, html, nothing } from "lit"; import { customElement, property, query, state } from "lit/decorators"; +import { styleMap } from "lit/directives/style-map"; import memoizeOne from "memoize-one"; import { fireEvent } from "../common/dom/fire_event"; import { computeDomain } from "../common/entity/compute_domain"; @@ -11,6 +12,7 @@ import { ScorableTextItem, fuzzyFilterSort, } from "../common/string/filter/sequence-matching"; +import { computeRTL } from "../common/util/compute_rtl"; import { AreaRegistryEntry } from "../data/area_registry"; import { DeviceEntityDisplayLookup, @@ -32,6 +34,7 @@ import "./ha-floor-icon"; import "./ha-icon-button"; import "./ha-list-item"; import "./ha-svg-icon"; +import "./ha-tree-indicator"; type ScorableAreaFloorEntry = ScorableTextItem & FloorAreaEntry; @@ -41,35 +44,11 @@ interface FloorAreaEntry { icon: string | null; strings: string[]; type: "floor" | "area"; - hasFloor?: boolean; level: number | null; + hasFloor?: boolean; + lastArea?: boolean; } -const rowRenderer: ComboBoxLitRenderer = (item) => - html` - ${item.type === "area" && item.hasFloor - ? html`` - : nothing} - ${item.type === "floor" - ? html`` - : item.icon - ? html`` - : html``} - ${item.name} - `; - @customElement("ha-area-floor-picker") export class HaAreaFloorPicker extends SubscribeMixin(LitElement) { @property({ attribute: false }) public hass!: HomeAssistant; @@ -158,6 +137,44 @@ export class HaAreaFloorPicker extends SubscribeMixin(LitElement) { await this.comboBox?.focus(); } + private _rowRenderer: ComboBoxLitRenderer = (item) => { + const rtl = computeRTL(this.hass); + return html` + + ${item.type === "area" && item.hasFloor + ? html`` + : nothing} + ${item.type === "floor" + ? html`` + : item.icon + ? html`` + : html``} + ${item.name} + + `; + }; + private _getAreas = memoizeOne( ( floors: FloorRegistryEntry[], @@ -371,7 +388,7 @@ export class HaAreaFloorPicker extends SubscribeMixin(LitElement) { }); } output.push( - ...floorAreas.map((area) => ({ + ...floorAreas.map((area, index, array) => ({ id: area.area_id, type: "area" as const, name: area.name, @@ -379,6 +396,7 @@ export class HaAreaFloorPicker extends SubscribeMixin(LitElement) { strings: [area.area_id, ...area.aliases, area.name], hasFloor: true, level: null, + lastArea: index === array.length - 1, })) ); }); @@ -452,7 +470,7 @@ export class HaAreaFloorPicker extends SubscribeMixin(LitElement) { .placeholder=${this.placeholder ? this.hass.areas[this.placeholder]?.name : undefined} - .renderer=${rowRenderer} + .renderer=${this._rowRenderer} @filter-changed=${this._filterChanged} @opened-changed=${this._openedChanged} @value-changed=${this._areaChanged} diff --git a/src/components/ha-filter-floor-areas.ts b/src/components/ha-filter-floor-areas.ts index d52db44f02..8810c9d6d2 100644 --- a/src/components/ha-filter-floor-areas.ts +++ b/src/components/ha-filter-floor-areas.ts @@ -1,15 +1,13 @@ import "@material/mwc-menu/mwc-menu-surface"; -import { - mdiFilterVariantRemove, - mdiSubdirectoryArrowRight, - mdiTextureBox, -} from "@mdi/js"; +import { mdiFilterVariantRemove, mdiTextureBox } from "@mdi/js"; import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { CSSResultGroup, LitElement, css, html, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { repeat } from "lit/directives/repeat"; import memoizeOne from "memoize-one"; import { fireEvent } from "../common/dom/fire_event"; +import { computeRTL } from "../common/util/compute_rtl"; import { FloorRegistryEntry, getFloorAreaLookup, @@ -23,6 +21,7 @@ import "./ha-check-list-item"; import "./ha-floor-icon"; import "./ha-icon"; import "./ha-svg-icon"; +import "./ha-tree-indicator"; @customElement("ha-filter-floor-areas") export class HaFilterFloorAreas extends SubscribeMixin(LitElement) { @@ -90,8 +89,10 @@ export class HaFilterFloorAreas extends SubscribeMixin(LitElement) { ${repeat( floor.areas, - (area) => area.area_id, - (area) => this._renderArea(area) + (area, index) => + `${area.area_id}${index === floor.areas.length - 1 ? "___last" : ""}`, + (area, index) => + this._renderArea(area, index === floor.areas.length - 1) )} ` )} @@ -107,30 +108,37 @@ export class HaFilterFloorAreas extends SubscribeMixin(LitElement) { `; } - private _renderArea(area) { - return html` - ${area.floor_id - ? html`` - : nothing} - ${area.icon - ? html`` - : html``} - ${area.name} - `; + private _renderArea(area, last: boolean = false) { + const hasFloor = !!area.floor_id; + return html` + + ${hasFloor + ? html` + + ` + : nothing} + ${area.icon + ? html`` + : html``} + ${area.name} + + `; } private _handleItemClick(ev) { @@ -305,9 +313,20 @@ export class HaFilterFloorAreas extends SubscribeMixin(LitElement) { --mdc-list-item-graphic-margin: 16px; } .floor { - padding-left: 38px; - padding-inline-start: 38px; - --mdc-list-item-graphic-margin: 32px; + padding-left: 48px; + padding-inline-start: 48px; + padding-inline-end: 16px; + } + ha-tree-indicator { + width: 56px; + position: absolute; + top: 0px; + left: 0px; + } + .rtl ha-tree-indicator { + right: 0px; + left: initial; + transform: scaleX(-1); } .subdir { margin-inline-end: 8px; diff --git a/src/components/ha-tree-indicator.ts b/src/components/ha-tree-indicator.ts new file mode 100644 index 0000000000..5912d7650c --- /dev/null +++ b/src/components/ha-tree-indicator.ts @@ -0,0 +1,36 @@ +import { LitElement, TemplateResult, css, html } from "lit"; +import { customElement, property } from "lit/decorators"; + +@customElement("ha-tree-indicator") +export class HaTreeIndicator extends LitElement { + @property({ type: Boolean, reflect: true }) + public end?: boolean = false; + + protected render(): TemplateResult { + return html` + + + + + `; + } + + static styles = css` + :host { + display: block; + width: 48px; + height: 48px; + } + line { + stroke: var(--divider-color); + stroke-width: 2; + stroke-dasharray: 2; + } + `; +} + +declare global { + interface HTMLElementTagNameMap { + "ha-tree-indicator": HaTreeIndicator; + } +}