mirror of
https://github.com/home-assistant/frontend.git
synced 2025-11-08 18:39:40 +00:00
Always show compact header for dashboards (#26706)
This commit is contained in:
@@ -148,6 +148,10 @@ export class HaDialog extends DialogBase {
|
||||
white-space: nowrap;
|
||||
display: block;
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
margin-right: 12px;
|
||||
margin-inline-end: 12px;
|
||||
margin-inline-start: initial;
|
||||
}
|
||||
.header_button {
|
||||
text-decoration: none;
|
||||
|
||||
106
src/dialogs/dialog-list-items/dialog-list-items.ts
Normal file
106
src/dialogs/dialog-list-items/dialog-list-items.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { createCloseHeading } from "../../components/ha-dialog";
|
||||
import "../../components/ha-icon";
|
||||
import "../../components/ha-md-list";
|
||||
import "../../components/ha-md-list-item";
|
||||
import "../../components/ha-svg-icon";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import type { HassDialog } from "../make-dialog-manager";
|
||||
import type { ListItemsDialogParams } from "./show-list-items-dialog";
|
||||
|
||||
@customElement("dialog-list-items")
|
||||
export class ListItemsDialog
|
||||
extends LitElement
|
||||
implements HassDialog<ListItemsDialogParams>
|
||||
{
|
||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||
|
||||
@state() private _params?: ListItemsDialogParams;
|
||||
|
||||
public async showDialog(params: ListItemsDialogParams): Promise<void> {
|
||||
this._params = params;
|
||||
}
|
||||
|
||||
private _dialogClosed(): void {
|
||||
this._params = undefined;
|
||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||
}
|
||||
|
||||
private _itemClicked(ev: CustomEvent): void {
|
||||
const item = (ev.currentTarget as any).item;
|
||||
if (!item) return;
|
||||
item.action();
|
||||
this._dialogClosed();
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this._params || !this.hass) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
return html`
|
||||
<ha-dialog
|
||||
open
|
||||
.heading=${createCloseHeading(this.hass, this._params.title ?? " ")}
|
||||
@closed=${this._dialogClosed}
|
||||
hideActions
|
||||
>
|
||||
<div class="container">
|
||||
<ha-md-list>
|
||||
${this._params.items.map(
|
||||
(item) => html`
|
||||
<ha-md-list-item
|
||||
type="button"
|
||||
@click=${this._itemClicked}
|
||||
.item=${item}
|
||||
>
|
||||
${item.iconPath
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
.path=${item.iconPath}
|
||||
slot="start"
|
||||
class="item-icon"
|
||||
></ha-svg-icon>
|
||||
`
|
||||
: item.icon
|
||||
? html`
|
||||
<ha-icon
|
||||
icon=${item.icon}
|
||||
slot="start"
|
||||
class="item-icon"
|
||||
></ha-icon>
|
||||
`
|
||||
: nothing}
|
||||
<span class="headline">${item.label}</span>
|
||||
${item.description
|
||||
? html`
|
||||
<span class="supporting-text">${item.description}</span>
|
||||
`
|
||||
: nothing}
|
||||
</ha-md-list-item>
|
||||
`
|
||||
)}
|
||||
</ha-md-list>
|
||||
</div>
|
||||
</ha-dialog>
|
||||
`;
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
ha-dialog {
|
||||
/* Place above other dialogs */
|
||||
--dialog-z-index: 104;
|
||||
--dialog-content-padding: 0;
|
||||
--md-list-item-leading-space: 24px;
|
||||
--md-list-item-trailing-space: 24px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"dialog-list-items": ListItemsDialog;
|
||||
}
|
||||
}
|
||||
24
src/dialogs/dialog-list-items/show-list-items-dialog.ts
Normal file
24
src/dialogs/dialog-list-items/show-list-items-dialog.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
|
||||
interface ListItem {
|
||||
icon?: string;
|
||||
iconPath?: string;
|
||||
label: string;
|
||||
description?: string;
|
||||
action: () => any;
|
||||
}
|
||||
|
||||
export interface ListItemsDialogParams {
|
||||
title?: string;
|
||||
items: ListItem[];
|
||||
}
|
||||
|
||||
export const showListItemsDialog = (
|
||||
element: HTMLElement,
|
||||
params: ListItemsDialogParams
|
||||
) =>
|
||||
fireEvent(element, "show-dialog", {
|
||||
dialogTag: "dialog-list-items",
|
||||
dialogImport: () => import("./dialog-list-items"),
|
||||
dialogParams: params,
|
||||
});
|
||||
@@ -46,6 +46,7 @@ import "../../components/ha-list-item";
|
||||
import "../../components/ha-menu-button";
|
||||
import "../../components/ha-svg-icon";
|
||||
import "../../components/sl-tab-group";
|
||||
import { createAreaRegistryEntry } from "../../data/area_registry";
|
||||
import type { LovelacePanelConfig } from "../../data/lovelace";
|
||||
import type { LovelaceConfig } from "../../data/lovelace/config/types";
|
||||
import { isStrategyDashboard } from "../../data/lovelace/config/types";
|
||||
@@ -57,6 +58,7 @@ import {
|
||||
} from "../../data/lovelace/dashboard";
|
||||
import { getPanelTitle } from "../../data/panel";
|
||||
import { createPerson } from "../../data/person";
|
||||
import { showListItemsDialog } from "../../dialogs/dialog-list-items/show-list-items-dialog";
|
||||
import {
|
||||
showAlertDialog,
|
||||
showConfirmationDialog,
|
||||
@@ -71,6 +73,8 @@ import { showVoiceCommandDialog } from "../../dialogs/voice-command-dialog/show-
|
||||
import { haStyle } from "../../resources/styles";
|
||||
import type { HomeAssistant, PanelInfo } from "../../types";
|
||||
import { documentationUrl } from "../../util/documentation-url";
|
||||
import { showToast } from "../../util/toast";
|
||||
import { showAreaRegistryDetailDialog } from "../config/areas/show-dialog-area-registry-detail";
|
||||
import { showNewAutomationDialog } from "../config/automation/show-dialog-new-automation";
|
||||
import { showAddIntegrationDialog } from "../config/integrations/show-add-integration-dialog";
|
||||
import { showDashboardDetailDialog } from "../config/lovelace/dashboards/show-dialog-lovelace-dashboard-detail";
|
||||
@@ -86,9 +90,6 @@ import "./views/hui-view";
|
||||
import type { HUIView } from "./views/hui-view";
|
||||
import "./views/hui-view-background";
|
||||
import "./views/hui-view-container";
|
||||
import { showAreaRegistryDetailDialog } from "../config/areas/show-dialog-area-registry-detail";
|
||||
import { createAreaRegistryEntry } from "../../data/area_registry";
|
||||
import { showToast } from "../../util/toast";
|
||||
|
||||
interface ActionItem {
|
||||
icon: string;
|
||||
@@ -105,6 +106,7 @@ interface ActionItem {
|
||||
interface SubActionItem {
|
||||
icon: string;
|
||||
key: LocalizeKeys;
|
||||
overflowAction?: any;
|
||||
action?: any;
|
||||
visible: boolean | undefined;
|
||||
}
|
||||
@@ -208,31 +210,35 @@ class HUIRoot extends LitElement {
|
||||
icon: mdiPlus,
|
||||
key: "ui.panel.lovelace.menu.add",
|
||||
visible: !this._editMode && this.hass.user?.is_admin,
|
||||
overflow: false,
|
||||
overflow: this.narrow,
|
||||
subItems: [
|
||||
{
|
||||
icon: mdiDevices,
|
||||
key: "ui.panel.lovelace.menu.add_device",
|
||||
visible: true,
|
||||
action: this._handleAddDevice,
|
||||
action: this._addDevice,
|
||||
overflowAction: this._handleAddDevice,
|
||||
},
|
||||
{
|
||||
icon: mdiRobot,
|
||||
key: "ui.panel.lovelace.menu.create_automation",
|
||||
visible: true,
|
||||
action: this._handleACreateAutomation,
|
||||
action: this._createAutomation,
|
||||
overflowAction: this._handleCreateAutomation,
|
||||
},
|
||||
{
|
||||
icon: mdiSofa,
|
||||
key: "ui.panel.lovelace.menu.add_area",
|
||||
visible: true,
|
||||
action: this._handleAddArea,
|
||||
action: this._addArea,
|
||||
overflowAction: this._handleAddArea,
|
||||
},
|
||||
{
|
||||
icon: mdiAccount,
|
||||
key: "ui.panel.lovelace.menu.add_person",
|
||||
visible: true,
|
||||
action: this._handleInvitePerson,
|
||||
action: this._addPerson,
|
||||
overflowAction: this._handleAddPerson,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -242,7 +248,7 @@ class HUIRoot extends LitElement {
|
||||
buttonAction: this._showQuickBar,
|
||||
overflowAction: this._handleShowQuickBar,
|
||||
visible: !this._editMode,
|
||||
overflow: false,
|
||||
overflow: this.narrow,
|
||||
suffix: this.hass.enableShortcuts ? "(E)" : undefined,
|
||||
},
|
||||
{
|
||||
@@ -252,7 +258,7 @@ class HUIRoot extends LitElement {
|
||||
overflowAction: this._handleShowVoiceCommandDialog,
|
||||
visible:
|
||||
!this._editMode && this._conversation(this.hass.config.components),
|
||||
overflow: false,
|
||||
overflow: this.narrow,
|
||||
suffix: this.hass.enableShortcuts ? "(A)" : undefined,
|
||||
},
|
||||
{
|
||||
@@ -321,7 +327,7 @@ class HUIRoot extends LitElement {
|
||||
<ha-list-item
|
||||
graphic="icon"
|
||||
.key=${subItem.key}
|
||||
@request-selected=${subItem.action}
|
||||
@request-selected=${subItem.overflowAction}
|
||||
>
|
||||
${this.hass!.localize(subItem.key)}
|
||||
<ha-svg-icon
|
||||
@@ -347,26 +353,37 @@ class HUIRoot extends LitElement {
|
||||
if (overflowItems.length && !overflowCanPromote) {
|
||||
const listItems: TemplateResult[] = [];
|
||||
overflowItems.forEach((i) => {
|
||||
const title = [this.hass!.localize(i.key), i.suffix].join(" ");
|
||||
const action = i.subItems
|
||||
? () => {
|
||||
showListItemsDialog(this, {
|
||||
title: title,
|
||||
items: i.subItems!.map((si) => ({
|
||||
iconPath: si.icon,
|
||||
label: this.hass!.localize(si.key),
|
||||
action: si.action,
|
||||
})),
|
||||
});
|
||||
}
|
||||
: i.overflowAction;
|
||||
|
||||
listItems.push(
|
||||
html`<ha-list-item
|
||||
graphic="icon"
|
||||
@request-selected=${i.overflowAction}
|
||||
>
|
||||
${[this.hass!.localize(i.key), i.suffix].join(" ")}
|
||||
html`<ha-list-item graphic="icon" @request-selected=${action}>
|
||||
${title}
|
||||
<ha-svg-icon slot="graphic" .path=${i.icon}></ha-svg-icon>
|
||||
</ha-list-item>`
|
||||
);
|
||||
});
|
||||
result.push(
|
||||
html`<ha-button-menu slot="actionItems">
|
||||
result.push(html`
|
||||
<ha-button-menu slot="actionItems">
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass!.localize("ui.panel.lovelace.editor.menu.open")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
${listItems}
|
||||
</ha-button-menu>`
|
||||
);
|
||||
</ha-button-menu>
|
||||
`);
|
||||
}
|
||||
return html`${result}`;
|
||||
}
|
||||
@@ -458,8 +475,6 @@ class HUIRoot extends LitElement {
|
||||
|
||||
const isSubview = curViewConfig?.subview;
|
||||
const hasTabViews = views.filter((view) => !view.subview).length > 1;
|
||||
const showTabBar =
|
||||
this._editMode || (!isSubview && hasTabViews && this.narrow);
|
||||
|
||||
return html`
|
||||
<div
|
||||
@@ -504,35 +519,35 @@ class HUIRoot extends LitElement {
|
||||
`}
|
||||
${isSubview
|
||||
? html`<div class="main-title">${curViewConfig.title}</div>`
|
||||
: hasTabViews && !showTabBar
|
||||
: hasTabViews
|
||||
? tabs
|
||||
: html`
|
||||
<div class="main-title">
|
||||
${curViewConfig?.title ?? dashboardTitle}
|
||||
${views[0]?.title ?? dashboardTitle}
|
||||
</div>
|
||||
`}
|
||||
<div class="action-items">${this._renderActionItems()}</div>
|
||||
`}
|
||||
</div>
|
||||
${showTabBar
|
||||
? html`<div class="tab-bar">
|
||||
${tabs}
|
||||
${this._editMode
|
||||
? html`<ha-icon-button
|
||||
slot="nav"
|
||||
id="add-view"
|
||||
@click=${this._addView}
|
||||
.label=${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.edit_view.add"
|
||||
)}
|
||||
.path=${mdiPlus}
|
||||
></ha-icon-button>`
|
||||
: nothing}
|
||||
</div>`
|
||||
${this._editMode
|
||||
? html`
|
||||
<div class="tab-bar">
|
||||
${tabs}
|
||||
<ha-icon-button
|
||||
slot="nav"
|
||||
id="add-view"
|
||||
@click=${this._addView}
|
||||
.label=${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.edit_view.add"
|
||||
)}
|
||||
.path=${mdiPlus}
|
||||
></ha-icon-button>
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
<hui-view-container
|
||||
class=${showTabBar ? "has-tab-bar" : ""}
|
||||
class=${this._editMode ? "has-tab-bar" : ""}
|
||||
.hass=${this.hass}
|
||||
.theme=${curViewConfig?.theme}
|
||||
id="view"
|
||||
@@ -788,36 +803,47 @@ class HUIRoot extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
private async _handleAddDevice(
|
||||
ev: CustomEvent<RequestSelectedDetail>
|
||||
): Promise<void> {
|
||||
private _handleAddDevice(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
this._addDevice();
|
||||
}
|
||||
|
||||
private _addDevice = async () => {
|
||||
await this.hass.loadFragmentTranslation("config");
|
||||
showAddIntegrationDialog(this);
|
||||
}
|
||||
};
|
||||
|
||||
private async _handleACreateAutomation(
|
||||
private _handleCreateAutomation(
|
||||
ev: CustomEvent<RequestSelectedDetail>
|
||||
): Promise<void> {
|
||||
): void {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
this._createAutomation();
|
||||
}
|
||||
|
||||
private _createAutomation = async () => {
|
||||
await this.hass.loadFragmentTranslation("config");
|
||||
showNewAutomationDialog(this, { mode: "automation" });
|
||||
}
|
||||
};
|
||||
|
||||
private async _handleAddArea(
|
||||
ev: CustomEvent<RequestSelectedDetail>
|
||||
): Promise<void> {
|
||||
private _handleAddArea(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
this._addArea();
|
||||
}
|
||||
|
||||
private _addArea = async () => {
|
||||
await this.hass.loadFragmentTranslation("config");
|
||||
showAreaRegistryDetailDialog(this, {
|
||||
createEntry: async (values) => {
|
||||
const area = await createAreaRegistryEntry(this.hass, values);
|
||||
if (isStrategyDashboard(this.lovelace!.rawConfig)) {
|
||||
fireEvent(this, "config-refresh");
|
||||
}
|
||||
showToast(this, {
|
||||
message: this.hass.localize(
|
||||
"ui.panel.lovelace.menu.add_area_success"
|
||||
@@ -831,14 +857,16 @@ class HUIRoot extends LitElement {
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private async _handleInvitePerson(
|
||||
ev: CustomEvent<RequestSelectedDetail>
|
||||
): Promise<void> {
|
||||
private _handleAddPerson(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
this._addPerson();
|
||||
}
|
||||
|
||||
private _addPerson = async () => {
|
||||
await this.hass.loadFragmentTranslation("config");
|
||||
showPersonDetailDialog(this, {
|
||||
users: [],
|
||||
@@ -859,7 +887,7 @@ class HUIRoot extends LitElement {
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private _handleRawEditor(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
|
||||
Reference in New Issue
Block a user