diff --git a/src/components/data-table/ha-data-table.ts b/src/components/data-table/ha-data-table.ts index 0846c1eb5d..3e350edf8a 100644 --- a/src/components/data-table/ha-data-table.ts +++ b/src/components/data-table/ha-data-table.ts @@ -118,8 +118,6 @@ export class HaDataTable extends LitElement { @property({ type: Boolean }) public clickable = false; - @property({ attribute: "has-fab", type: Boolean }) public hasFab = false; - /** * Add an extra row at the bottom of the data table * @type {TemplateResult} @@ -519,7 +517,6 @@ export class HaDataTable extends LitElement { this._filteredData, localize, this.appendRow, - this.hasFab, this.groupColumn, this.groupOrder, this._collapsedGroups, @@ -716,14 +713,13 @@ export class HaDataTable extends LitElement { data: DataTableRowData[], localize: LocalizeFunc, appendRow, - hasFab: boolean, groupColumn: string | undefined, groupOrder: string[] | undefined, collapsedGroups: string[], sortColumn: string | undefined, sortDirection: SortingDirection ) => { - if (appendRow || hasFab || groupColumn) { + if (appendRow || groupColumn) { let items = [...data]; if (groupColumn) { @@ -813,13 +809,11 @@ export class HaDataTable extends LitElement { items.push({ append: true, selectable: false, content: appendRow }); } - if (hasFab) { - items.push({ empty: true }); - } + items.push({ empty: true }); return items; } - return data; + return [...data, { empty: true }]; } ); @@ -871,7 +865,6 @@ export class HaDataTable extends LitElement { this._filteredData, this.localizeFunc || this.hass.localize, this.appendRow, - this.hasFab, this.groupColumn, this.groupOrder, this._collapsedGroups, @@ -1089,11 +1082,8 @@ export class HaDataTable extends LitElement { } .mdc-data-table__row.empty-row { - height: max( - var( - --data-table-empty-row-height, - var(--data-table-row-height, 52px) - ), + height: var( + --data-table-empty-row-height, var(--safe-area-inset-bottom, 0px) ); } diff --git a/src/layouts/hass-tabs-subpage-data-table.ts b/src/layouts/hass-tabs-subpage-data-table.ts index 76f494ba9f..27fec4832e 100644 --- a/src/layouts/hass-tabs-subpage-data-table.ts +++ b/src/layouts/hass-tabs-subpage-data-table.ts @@ -12,10 +12,11 @@ import { mdiUnfoldLessHorizontal, mdiUnfoldMoreHorizontal, } from "@mdi/js"; -import type { TemplateResult } from "lit"; +import type { TemplateResult, PropertyValues } from "lit"; import { LitElement, css, html, nothing } from "lit"; import { customElement, property, query, state } from "lit/decorators"; import { classMap } from "lit/directives/class-map"; +import { canShowPage } from "../common/config/can_show_page"; import { fireEvent } from "../common/dom/fire_event"; import type { LocalizeFunc } from "../common/translations/localize"; import "../components/chips/ha-assist-chip"; @@ -83,7 +84,15 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) { * Do we need to add padding for a fab. * @type {Boolean} */ - @property({ attribute: "has-fab", type: Boolean }) public hasFab = false; + @property({ attribute: "has-fab", type: Boolean, reflect: true }) + public hasFab = false; + + /** + * Show tabs on top or at bottom (narrow) of the page. + * @type {Boolean} + */ + @property({ attribute: "show-tabs", type: Boolean, reflect: true }) + public showTabs = false; /** * Add an extra row at the bottom of the data table @@ -200,7 +209,19 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) { this._dataTable.clearSelection(); } - protected willUpdate() { + protected willUpdate(changedProperties: PropertyValues) { + if ( + changedProperties.has("tabs") || + (changedProperties.has("hass") && + (this.hass?.config.components !== + changedProperties.get("hass")?.config.components || + this.hass?.userData?.showAdvanced !== + changedProperties.get("hass")?.userData?.showAdvanced)) + ) { + this.showTabs = + this.tabs.filter((page) => canShowPage(this.hass, page)).length > 1; + } + if (this.hasUpdated) { return; } @@ -491,7 +512,6 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) { .noDataText=${this.noDataText} .filter=${this.filter} .selectable=${this._selectMode} - .hasFab=${this.hasFab} .id=${this.id} .clickable=${this.clickable} .appendRow=${this.appendRow} @@ -713,6 +733,7 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) { width: 100%; height: 100%; --data-table-border-width: 0; + --data-table-empty-row-height: var(--safe-area-inset-bottom, 0px); } :host(:not([narrow])) ha-data-table, .pane { @@ -725,6 +746,23 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) { ); display: block; } + /* Last content row should keep the same padding above the fab as the fab + has to the bottom (16px standard fab bottom padding) + the safe-area inset. */ + :host([has-fab]) ha-data-table { + --data-table-empty-row-height: calc( + 48px + 16px * 2 + var(--safe-area-inset-bottom, 0px) + ); + } + /* In narrow view with tabs shown at the bottom, the tab bar already + accounts for safe-area-inset-bottom. No extra empty-row height is needed. */ + :host([narrow][show-tabs]:not([has-fab])) ha-data-table { + --data-table-empty-row-height: 0px; + } + /* Reserve space for fab + doubled narrow-mode bottom padding (28px * 2) + when using narrow layout with bottom tabs. */ + :host([narrow][show-tabs][has-fab]) ha-data-table { + --data-table-empty-row-height: calc(48px + 28px * 2); + } .pane-content { height: calc( diff --git a/src/layouts/hass-tabs-subpage.ts b/src/layouts/hass-tabs-subpage.ts index 88aba938f6..c917604d33 100644 --- a/src/layouts/hass-tabs-subpage.ts +++ b/src/layouts/hass-tabs-subpage.ts @@ -37,7 +37,7 @@ export interface PageNavigation { } @customElement("hass-tabs-subpage") -class HassTabsSubpage extends LitElement { +export class HassTabsSubpage extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public localizeFunc?: LocalizeFunc; @@ -65,6 +65,14 @@ class HassTabsSubpage extends LitElement { */ @property({ type: Boolean, attribute: "has-fab" }) public hasFab = false; + /** + * Whether tabs are shown (2 or more tabs visible). + * When both, show-tabs and narrow are true, tabs are shown as bottom bar. + * @type {Boolean} + */ + @property({ type: Boolean, attribute: "show-tabs", reflect: true }) + public showTabs = false; + @state() private _activeTab?: PageNavigation; // @ts-ignore @@ -83,6 +91,7 @@ class HassTabsSubpage extends LitElement { const shownTabs = tabs.filter((page) => canShowPage(this.hass, page)); if (shownTabs.length < 2) { + this.showTabs = false; if (shownTabs.length === 1) { const page = shownTabs[0]; return [ @@ -92,6 +101,7 @@ class HassTabsSubpage extends LitElement { return [""]; } + this.showTabs = true; return shownTabs.map( (page) => html` @@ -135,7 +145,6 @@ class HassTabsSubpage extends LitElement { this.narrow, this.localizeFunc || this.hass.localize ); - const showTabs = tabs.length > 1; return html`
@@ -160,12 +169,12 @@ class HassTabsSubpage extends LitElement { @click=${this._backTapped} > `} - ${this.narrow || !showTabs + ${this.narrow || !this.showTabs ? html`
- ${!showTabs ? tabs[0] : ""} + ${!this.showTabs ? tabs[0] : ""}
` : ""} - ${showTabs && !this.narrow + ${this.showTabs && !this.narrow ? html`
${tabs}
` : ""}
@@ -173,13 +182,11 @@ class HassTabsSubpage extends LitElement {
- ${showTabs && this.narrow + ${this.showTabs && this.narrow ? html`
${tabs}
` : ""} -
+
${this.pane ? html`
@@ -188,15 +195,12 @@ class HassTabsSubpage extends LitElement {
` : nothing} -
+
${this.hasFab ? html`
` : nothing}
-
+
`; @@ -373,7 +377,7 @@ class HassTabsSubpage extends LitElement { margin-left: var(--safe-area-inset-left); margin-inline-start: var(--safe-area-inset-left); } - :host([narrow]) .content.tabs { + :host([narrow][show-tabs]) .content { /* Bottom bar reuses header height */ margin-bottom: calc( var(--header-height, 0px) + var(--safe-area-inset-bottom, 0px) @@ -384,7 +388,7 @@ class HassTabsSubpage extends LitElement { height: calc(64px + var(--safe-area-inset-bottom, 0px)); } - :host([narrow]) .content.tabs .fab-bottom-space { + :host([narrow][show-tabs]) .content .fab-bottom-space { height: calc(80px + var(--safe-area-inset-bottom, 0px)); } @@ -400,7 +404,7 @@ class HassTabsSubpage extends LitElement { justify-content: flex-end; gap: var(--ha-space-2); } - :host([narrow]) #fab.tabs { + :host([narrow][show-tabs]) #fab { bottom: calc(84px + var(--safe-area-inset-bottom, 0px)); } #fab[is-wide] {