1
0
mirror of https://github.com/home-assistant/frontend.git synced 2026-04-02 00:27:49 +01:00

Fix data-table content bottom margin (#29805)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Matthias Alphart
2026-03-02 17:02:31 +01:00
committed by GitHub
parent 1991a9e493
commit 2701015eda
3 changed files with 68 additions and 36 deletions

View File

@@ -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)
);
}

View File

@@ -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(

View File

@@ -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`
<a href=${page.path} @click=${this._tabClicked}>
@@ -135,7 +145,6 @@ class HassTabsSubpage extends LitElement {
this.narrow,
this.localizeFunc || this.hass.localize
);
const showTabs = tabs.length > 1;
return html`
<div class="toolbar ${classMap({ narrow: this.narrow })}">
<slot name="toolbar">
@@ -160,12 +169,12 @@ class HassTabsSubpage extends LitElement {
@click=${this._backTapped}
></ha-icon-button-arrow-prev>
`}
${this.narrow || !showTabs
${this.narrow || !this.showTabs
? html`<div class="main-title">
<slot name="header">${!showTabs ? tabs[0] : ""}</slot>
<slot name="header">${!this.showTabs ? tabs[0] : ""}</slot>
</div>`
: ""}
${showTabs && !this.narrow
${this.showTabs && !this.narrow
? html`<div id="tabbar">${tabs}</div>`
: ""}
<div id="toolbar-icon">
@@ -173,13 +182,11 @@ class HassTabsSubpage extends LitElement {
</div>
</div>
</slot>
${showTabs && this.narrow
${this.showTabs && this.narrow
? html`<div id="tabbar" class="bottom-bar">${tabs}</div>`
: ""}
</div>
<div
class=${classMap({ container: true, tabs: showTabs && this.narrow })}
>
<div class="container">
${this.pane
? html`<div class="pane">
<div class="shadow-container"></div>
@@ -188,15 +195,12 @@ class HassTabsSubpage extends LitElement {
</div>
</div>`
: nothing}
<div
class="content ha-scrollbar ${classMap({ tabs: showTabs })}"
@scroll=${this._saveScrollPos}
>
<div class="content ha-scrollbar" @scroll=${this._saveScrollPos}>
<slot></slot>
${this.hasFab ? html`<div class="fab-bottom-space"></div>` : nothing}
</div>
</div>
<div id="fab" class=${classMap({ tabs: showTabs })}>
<div id="fab">
<slot name="fab"></slot>
</div>
`;
@@ -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] {