Use mwc-drawer (#10335

* Use mwc-drawer

* Update home-assistant-main.ts

* Implement top-app-bar

* Update home-assistant-main.ts

* update hui-root

* WIP

tabs don't work yet

* migrate most panels

* fixed

* notifications-drawer

* developer tools

* lovelace

* Update hui-root.ts

* Update hui-root.ts

* Update notification-drawer.ts

* fix dev tools

* Update ha-panel-developer-tools.ts
This commit is contained in:
Bram Kragten 2023-03-29 17:46:34 +02:00 committed by GitHub
parent f19fdeacba
commit f5a4affdec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 1061 additions and 1112 deletions

View File

@ -50,20 +50,7 @@ class HassioMarkdownDialog extends LitElement {
haStyleDialog, haStyleDialog,
hassioStyle, hassioStyle,
css` css`
app-toolbar {
margin: 0;
padding: 0 16px;
color: var(--primary-text-color);
background-color: var(--secondary-background-color);
}
app-toolbar [main-title] {
margin-left: 16px;
}
@media all and (max-width: 450px), all and (max-height: 500px) { @media all and (max-width: 450px), all and (max-height: 500px) {
app-toolbar {
color: var(--text-primary-color);
background-color: var(--primary-color);
}
ha-markdown { ha-markdown {
padding: 16px; padding: 16px;
} }

View File

@ -597,10 +597,6 @@ export class DialogHassioNetwork
margin-left: 8px; margin-left: 8px;
} }
:host([rtl]) app-toolbar {
direction: rtl;
text-align: right;
}
.container { .container {
padding: 0 8px 4px; padding: 0 8px 4px;
} }

View File

@ -71,6 +71,7 @@
"@material/mwc-tab-bar": "0.27.0", "@material/mwc-tab-bar": "0.27.0",
"@material/mwc-textarea": "0.27.0", "@material/mwc-textarea": "0.27.0",
"@material/mwc-textfield": "0.27.0", "@material/mwc-textfield": "0.27.0",
"@material/mwc-top-app-bar": "0.27.0",
"@material/mwc-top-app-bar-fixed": "0.27.0", "@material/mwc-top-app-bar-fixed": "0.27.0",
"@material/top-app-bar": "=14.0.0-canary.53b3cad2f.0", "@material/top-app-bar": "=14.0.0-canary.53b3cad2f.0",
"@material/web": "=1.0.0-pre.4", "@material/web": "=1.0.0-pre.4",

View File

@ -0,0 +1,22 @@
import { DrawerBase } from "@material/mwc-drawer/mwc-drawer-base";
import { styles } from "@material/mwc-drawer/mwc-drawer.css";
import { css } from "lit";
import { customElement } from "lit/decorators";
@customElement("ha-drawer")
export class HaDrawer extends DrawerBase {
static override styles = [
styles,
css`
.mdc-drawer {
top: 0;
}
`,
];
}
declare global {
interface HTMLElementTagNameMap {
"ha-drawer": HaDrawer;
}
}

View File

@ -32,6 +32,9 @@ export class HaHeaderBar extends LitElement {
return [ return [
unsafeCSS(topAppBarStyles), unsafeCSS(topAppBarStyles),
css` css`
.mdc-top-app-bar__row {
height: var(--header-bar-height, 64px);
}
.mdc-top-app-bar { .mdc-top-app-bar {
position: static; position: static;
color: var(--mdc-theme-on-primary, #fff); color: var(--mdc-theme-on-primary, #fff);

View File

@ -846,17 +846,9 @@ class HaSidebar extends SubscribeMixin(LitElement) {
-ms-user-select: none; -ms-user-select: none;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
border-right: 1px solid var(--divider-color);
background-color: var(--sidebar-background-color); background-color: var(--sidebar-background-color);
width: 56px; width: 100%;
} box-sizing: border-box;
:host([expanded]) {
width: 256px;
width: calc(256px + env(safe-area-inset-left));
}
:host([rtl]) {
border-right: 0;
border-left: 1px solid var(--divider-color);
} }
.menu { .menu {
height: var(--header-height); height: var(--header-height);
@ -1070,8 +1062,8 @@ class HaSidebar extends SubscribeMixin(LitElement) {
.notification-badge, .notification-badge,
.configuration-badge { .configuration-badge {
left: calc(var(--app-drawer-width) - 42px);
position: absolute; position: absolute;
left: calc(var(--app-drawer-width, 248px) - 42px);
min-width: 20px; min-width: 20px;
box-sizing: border-box; box-sizing: border-box;
border-radius: 50%; border-radius: 50%;

View File

@ -0,0 +1,34 @@
import { TopAppBarFixedBase } from "@material/mwc-top-app-bar-fixed/mwc-top-app-bar-fixed-base";
import { styles } from "@material/mwc-top-app-bar/mwc-top-app-bar.css";
import { css } from "lit";
import { customElement } from "lit/decorators";
@customElement("ha-top-app-bar-fixed")
export class HaTopAppBarFixed extends TopAppBarFixedBase {
static override styles = [
styles,
css`
.mdc-top-app-bar__row {
height: var(--header-height);
}
.mdc-top-app-bar--fixed-adjust {
padding-top: var(--header-height);
}
.mdc-top-app-bar {
--mdc-typography-headline6-font-weight: 400;
color: var(--app-header-text-color, var(--mdc-theme-on-primary, #fff));
background-color: var(
--app-header-background-color,
var(--mdc-theme-primary)
);
border-bottom: var(--app-header-border-bottom);
}
`,
];
}
declare global {
interface HTMLElementTagNameMap {
"ha-top-app-bar-fixed": HaTopAppBarFixed;
}
}

View File

@ -0,0 +1,34 @@
import { TopAppBarBase } from "@material/mwc-top-app-bar/mwc-top-app-bar-base";
import { styles } from "@material/mwc-top-app-bar/mwc-top-app-bar.css";
import { css } from "lit";
import { customElement } from "lit/decorators";
@customElement("ha-top-app-bar")
export class HaTopAppBar extends TopAppBarBase {
static override styles = [
styles,
css`
.mdc-top-app-bar__row {
height: var(--header-height);
}
.mdc-top-app-bar--fixed-adjust {
padding-top: var(--header-height);
}
.mdc-top-app-bar {
--mdc-typography-headline6-font-weight: 400;
color: var(--app-header-text-color, var(--mdc-theme-on-primary, #fff));
background-color: var(
--app-header-background-color,
var(--mdc-theme-primary)
);
border-bottom: var(--app-header-border-bottom);
}
`,
];
}
declare global {
interface HTMLElementTagNameMap {
"ha-top-app-bar": HaTopAppBar;
}
}

View File

@ -1,207 +0,0 @@
import "@material/mwc-button";
import "@polymer/app-layout/app-drawer/app-drawer";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import { computeDomain } from "../../common/entity/compute_domain";
import "../../components/ha-icon-button-prev";
import { subscribeNotifications } from "../../data/persistent_notification";
import { EventsMixin } from "../../mixins/events-mixin";
import LocalizeMixin from "../../mixins/localize-mixin";
import "./notification-item";
/*
* @appliesMixin EventsMixin
* @appliesMixin LocalizeMixin
*/
export class HuiNotificationDrawer extends EventsMixin(
LocalizeMixin(PolymerElement)
) {
static get template() {
return html`
<style>
app-toolbar {
color: var(--primary-text-color);
border-bottom: 1px solid var(--divider-color);
background-color: var(--primary-background-color);
height: var(--header-height);
box-sizing: border-box;
}
div[main-title] {
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
}
.notifications {
overflow-y: auto;
padding-top: 16px;
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
padding-bottom: env(safe-area-inset-bottom);
height: calc(100% - 1px - var(--header-height));
box-sizing: border-box;
background-color: var(--primary-background-color);
color: var(--primary-text-color);
}
.notification {
padding: 0 16px 16px;
}
.notification-actions {
padding: 0 16px 16px;
text-align: center;
}
.empty {
padding: 16px;
text-align: center;
}
</style>
<app-drawer id="drawer" opened="{{open}}" disable-swipe align="start">
<app-toolbar>
<div main-title>[[localize('ui.notification_drawer.title')]]</div>
<ha-icon-button-prev hass="[[hass]]" on-click="_closeDrawer"
label="[[localize('ui.notification_drawer.close')]]">
</ha-icon-button-prev>
</app-toolbar>
<div class="notifications">
<template is="dom-if" if="[[!_empty(notifications)]]">
<dom-repeat items="[[notifications]]">
<template>
<div class="notification">
<notification-item hass="[[hass]]" notification="[[item]]"></notification-item>
</div>
</template>
</dom-repeat>
<template is="dom-if" if="[[_moreThanOne(notifications)]]">
<div class="notification-actions">
<mwc-button raised on-click="_dismissAll">
[[localize('ui.notification_drawer.dismiss_all')]]
</mwc-button>
</div>
</template>
</template>
<template is="dom-if" if="[[_empty(notifications)]]">
<div class="empty">[[localize('ui.notification_drawer.empty')]]<div>
</template>
</div>
</app-drawer>
`;
}
static get properties() {
return {
hass: Object,
open: {
type: Boolean,
observer: "_openChanged",
},
notifications: {
type: Array,
computed: "_computeNotifications(open, hass, _notificationsBackend)",
observer: "_notificationsChanged",
},
_notificationsBackend: {
type: Array,
value: [],
},
};
}
ready() {
super.ready();
window.addEventListener("location-changed", () => {
// close drawer when we navigate away.
if (this.open) {
this.open = false;
}
});
}
_closeDrawer(ev) {
ev.stopPropagation();
this.open = false;
}
_dismissAll() {
this.notifications.forEach((notification) => {
this.hass.callService("persistent_notification", "dismiss", {
notification_id: notification.notification_id,
});
});
this.open = false;
}
_empty(notifications) {
return notifications.length === 0;
}
_moreThanOne(notifications) {
return notifications.length > 1;
}
_openChanged(open) {
if (open) {
// Render closed then animate open
this._unsubNotifications = subscribeNotifications(
this.hass.connection,
(notifications) => {
this._notificationsBackend = notifications;
}
);
} else if (this._unsubNotifications) {
this._unsubNotifications();
this._unsubNotifications = undefined;
}
}
_notificationsChanged(newNotifications, oldNotifications) {
// automatically close drawer when last notification has been dismissed
if (
this.open &&
oldNotifications.length > 0 &&
newNotifications.length === 0
) {
this.open = false;
}
}
_computeNotifications(open, hass, notificationsBackend) {
if (!open) {
return [];
}
const configuratorEntities = Object.keys(hass.states)
.filter((entityId) => computeDomain(entityId) === "configurator")
.map((entityId) => hass.states[entityId]);
const notifications = notificationsBackend.concat(configuratorEntities);
notifications.sort((n1, n2) => {
const d1 = new Date(n1.created_at);
const d2 = new Date(n2.created_at);
if (d1 < d2) {
return 1;
}
if (d1 > d2) {
return -1;
}
return 0;
});
return notifications;
}
showDialog({ narrow }) {
this.style.setProperty(
"--app-drawer-width",
narrow ? window.innerWidth + "px" : "500px"
);
this.$.drawer.open();
}
}
customElements.define("notification-drawer", HuiNotificationDrawer);

View File

@ -0,0 +1,190 @@
import "@material/mwc-button";
import { UnsubscribeFunc } from "home-assistant-js-websocket";
import { LitElement, html, css, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import { computeDomain } from "../../common/entity/compute_domain";
import "../../components/ha-icon-button-prev";
import {
PersistentNotification,
subscribeNotifications,
} from "../../data/persistent_notification";
import { HomeAssistant } from "../../types";
import "./notification-item";
import "../../components/ha-header-bar";
import "../../components/ha-drawer";
@customElement("notification-drawer")
export class HuiNotificationDrawer extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@state() private _notifications: PersistentNotification[] = [];
@state() private _open = false;
private _unsubNotifications?: UnsubscribeFunc;
connectedCallback() {
super.connectedCallback();
window.addEventListener("location-changed", this.closeDialog);
}
disconnectedCallback() {
super.disconnectedCallback();
window.addEventListener("location-changed", this.closeDialog);
}
showDialog({ narrow }) {
this._unsubNotifications = subscribeNotifications(
this.hass.connection,
(notifications) => {
if (this._notifications.length && !notifications.length) {
this.closeDialog();
return;
}
this._notifications = notifications;
}
);
this.style.setProperty(
"--mdc-drawer-width",
narrow ? window.innerWidth + "px" : "500px"
);
this._open = true;
}
closeDialog = () => {
if (this._unsubNotifications) {
this._unsubNotifications();
this._unsubNotifications = undefined;
}
this._notifications = [];
this._open = false;
fireEvent(this, "dialog-closed", { dialog: this.localName });
};
protected render() {
if (!this._open) {
return nothing;
}
const configuratorEntities = Object.keys(this.hass.states)
.filter((entityId) => computeDomain(entityId) === "configurator")
.map((entityId) => this.hass.states[entityId]);
// @ts-ignore
const notifications = this._notifications.concat(configuratorEntities);
notifications.sort((n1, n2) => {
const d1 = new Date(n1.created_at);
const d2 = new Date(n2.created_at);
if (d1 < d2) {
return 1;
}
if (d1 > d2) {
return -1;
}
return 0;
});
return html`
<ha-drawer
type="modal"
.open=${this._open}
@MDCDrawer:closed=${this._closeDrawer}
>
<ha-header-bar>
<div slot="title">
${this.hass.localize("ui.notification_drawer.title")}
</div>
<ha-icon-button-prev
slot="actionItems"
.hass=${this.hass}
@click=${this._closeDrawer}
.label=${this.hass.localize("ui.notification_drawer.close")}
>
</ha-icon-button-prev>
</ha-header-bar>
<div class="notifications">
${notifications.length
? html`${notifications.map(
(notification) => html`<div class="notification">
<notification-item
.hass=${this.hass}
.notification=${notification}
></notification-item>
</div>`
)}
${this._notifications.length > 1
? html`<div class="notification-actions">
<mwc-button raised @click=${this._dismissAll}>
${this.hass.localize(
"ui.notification_drawer.dismiss_all"
)}
</mwc-button>
</div>`
: ""}`
: html` <div class="empty">
${this.hass.localize("ui.notification_drawer.empty")}
<div></div>
</div>`}
</div>
</ha-drawer>
`;
}
private _closeDrawer(ev) {
ev.stopPropagation();
this.closeDialog();
}
private _dismissAll() {
this._notifications.forEach((notification) => {
this.hass.callService("persistent_notification", "dismiss", {
notification_id: notification.notification_id,
});
});
this.closeDialog();
}
static styles = css`
ha-header-bar {
--mdc-theme-on-primary: var(--primary-text-color);
--mdc-theme-primary: var(--primary-background-color);
border-bottom: 1px solid var(--divider-color);
display: block;
--header-bar-height: var(--header-height);
}
.notifications {
overflow-y: auto;
padding-top: 16px;
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
padding-bottom: env(safe-area-inset-bottom);
height: calc(100% - 1px - var(--header-height));
box-sizing: border-box;
background-color: var(--primary-background-color);
color: var(--primary-text-color);
}
.notification {
padding: 0 16px 16px;
}
.notification-actions {
padding: 0 16px 16px;
text-align: center;
}
.empty {
padding: 16px;
text-align: center;
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"notification-drawer": HuiNotificationDrawer;
}
}

View File

@ -9,7 +9,7 @@ export const showNotificationDrawer = (
dialogParams: NotificationDrawerParams dialogParams: NotificationDrawerParams
): void => { ): void => {
fireEvent(element, "show-dialog", { fireEvent(element, "show-dialog", {
dialogTag: "notification-drawer" as any, // Not in TS yet dialogTag: "notification-drawer",
dialogImport: () => import("./notification-drawer"), dialogImport: () => import("./notification-drawer"),
dialogParams, dialogParams,
}); });

View File

@ -30,7 +30,6 @@ import {
import { debounce } from "../../common/util/debounce"; import { debounce } from "../../common/util/debounce";
import "../../components/ha-chip"; import "../../components/ha-chip";
import "../../components/ha-circular-progress"; import "../../components/ha-circular-progress";
import "../../components/ha-header-bar";
import "../../components/ha-icon-button"; import "../../components/ha-icon-button";
import "../../components/ha-list-item"; import "../../components/ha-list-item";
import "../../components/ha-textfield"; import "../../components/ha-textfield";

View File

@ -1,5 +1,8 @@
<meta name='viewport' content='width=device-width, user-scalable=no, viewport-fit=cover, initial-scale=1'> <meta name='viewport' content='width=device-width, user-scalable=no, viewport-fit=cover, initial-scale=1'>
<style> <style>
html {
overflow: hidden;
}
body { body {
font-family: Roboto, sans-serif; font-family: Roboto, sans-serif;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;

View File

@ -1,4 +1,3 @@
import "@polymer/app-layout/app-toolbar/app-toolbar";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import "../components/ha-circular-progress"; import "../components/ha-circular-progress";

View File

@ -1,8 +1,4 @@
/* eslint-disable lit/prefer-static-styles */ /* eslint-disable lit/prefer-static-styles */
import "@polymer/app-layout/app-drawer-layout/app-drawer-layout";
import type { AppDrawerLayoutElement } from "@polymer/app-layout/app-drawer-layout/app-drawer-layout";
import "@polymer/app-layout/app-drawer/app-drawer";
import type { AppDrawerElement } from "@polymer/app-layout/app-drawer/app-drawer";
import { import {
css, css,
CSSResultGroup, CSSResultGroup,
@ -11,6 +7,7 @@ import {
PropertyValues, PropertyValues,
TemplateResult, TemplateResult,
} from "lit"; } from "lit";
import "@material/mwc-drawer/mwc-drawer";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import { fireEvent, HASSDomEvent } from "../common/dom/fire_event"; import { fireEvent, HASSDomEvent } from "../common/dom/fire_event";
import { listenMediaQuery } from "../common/dom/media_query"; import { listenMediaQuery } from "../common/dom/media_query";
@ -19,8 +16,6 @@ import { showNotificationDrawer } from "../dialogs/notifications/show-notificati
import type { HomeAssistant, Route } from "../types"; import type { HomeAssistant, Route } from "../types";
import "./partial-panel-resolver"; import "./partial-panel-resolver";
const NON_SWIPABLE_PANELS = ["map"];
declare global { declare global {
// for fire event // for fire event
interface HASSDomEvents { interface HASSDomEvents {
@ -49,6 +44,8 @@ export class HomeAssistantMain extends LitElement {
@state() private _externalSidebar = false; @state() private _externalSidebar = false;
@state() private _drawerOpen = false;
constructor() { constructor() {
super(); super();
listenMediaQuery("(max-width: 870px)", (matches) => { listenMediaQuery("(max-width: 870px)", (matches) => {
@ -57,54 +54,28 @@ export class HomeAssistantMain extends LitElement {
} }
protected render(): TemplateResult { protected render(): TemplateResult {
const hass = this.hass;
const sidebarNarrow = this._sidebarNarrow || this._externalSidebar; const sidebarNarrow = this._sidebarNarrow || this._externalSidebar;
const disableSwipe =
this._sidebarEditMode ||
!sidebarNarrow ||
NON_SWIPABLE_PANELS.indexOf(hass.panelUrl) !== -1 ||
this._externalSidebar;
// Style block in render because of the mixin that is not supported
return html` return html`
<style> <mwc-drawer
app-drawer { .type=${sidebarNarrow ? "modal" : ""}
--app-drawer-content-container: { .open=${sidebarNarrow ? this._drawerOpen : undefined}
background-color: var(--primary-background-color, #fff); @MDCDrawer:closed=${this._drawerClosed}
}
}
</style>
<app-drawer-layout
fullbleed
.forceNarrow=${sidebarNarrow}
responsive-width="0"
> >
<app-drawer <ha-sidebar
id="drawer" .hass=${this.hass}
align="start" .narrow=${sidebarNarrow}
slot="drawer" .route=${this.route}
.disableSwipe=${disableSwipe} .editMode=${this._sidebarEditMode}
.swipeOpen=${!disableSwipe} .alwaysExpand=${sidebarNarrow || this.hass.dockedSidebar === "docked"}
.persistent=${!this.narrow && ></ha-sidebar>
this.hass.dockedSidebar !== "always_hidden"}
@app-drawer-transitioned=${this._drawerTransitioned}
>
<ha-sidebar
.hass=${hass}
.narrow=${sidebarNarrow}
.route=${this.route}
.editMode=${this._sidebarEditMode}
.alwaysExpand=${sidebarNarrow ||
this.hass.dockedSidebar === "docked"}
></ha-sidebar>
</app-drawer>
<partial-panel-resolver <partial-panel-resolver
.narrow=${this.narrow} .narrow=${this.narrow}
.hass=${hass} .hass=${this.hass}
.route=${this.route} .route=${this.route}
slot="appContent"
></partial-panel-resolver> ></partial-panel-resolver>
</app-drawer-layout> </mwc-drawer>
`; `;
} }
@ -126,12 +97,11 @@ export class HomeAssistantMain extends LitElement {
if (this._sidebarEditMode) { if (this._sidebarEditMode) {
if (this._sidebarNarrow) { if (this._sidebarNarrow) {
this.drawer.open(); this._drawerOpen = true;
} else { } else {
fireEvent(this, "hass-dock-sidebar", { fireEvent(this, "hass-dock-sidebar", {
dock: "docked", dock: "docked",
}); });
setTimeout(() => this.appLayout.resetLayout());
} }
} }
} }
@ -148,16 +118,11 @@ export class HomeAssistantMain extends LitElement {
return; return;
} }
if (this._sidebarNarrow) { if (this._sidebarNarrow) {
if (this.drawer.opened) { this._drawerOpen = !this._drawerOpen;
this.drawer.close();
} else {
this.drawer.open();
}
} else { } else {
fireEvent(this, "hass-dock-sidebar", { fireEvent(this, "hass-dock-sidebar", {
dock: this.hass.dockedSidebar === "auto" ? "docked" : "auto", dock: this.hass.dockedSidebar === "auto" ? "docked" : "auto",
}); });
setTimeout(() => this.appLayout.resetLayout());
} }
}); });
@ -168,6 +133,12 @@ export class HomeAssistantMain extends LitElement {
}); });
} }
public willUpdate(changedProps: PropertyValues) {
if (changedProps.has("route") && this._sidebarNarrow) {
this._drawerOpen = false;
}
}
protected updated(changedProps: PropertyValues) { protected updated(changedProps: PropertyValues) {
super.updated(changedProps); super.updated(changedProps);
@ -176,40 +147,15 @@ export class HomeAssistantMain extends LitElement {
"expanded", "expanded",
this.narrow || this.hass.dockedSidebar !== "auto" this.narrow || this.hass.dockedSidebar !== "auto"
); );
if (changedProps.has("route") && this._sidebarNarrow) {
this.drawer.close();
}
if (!changedProps.has("hass")) {
return;
}
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
// Make app-drawer adjust to a potential LTR/RTL change
if (oldHass && oldHass.language !== this.hass!.language) {
this.drawer._resetPosition();
}
}
private _drawerTransitioned(ev: CustomEvent) {
const drawer = ev.currentTarget as AppDrawerElement;
if (!drawer.opened) {
this._sidebarEditMode = false;
}
} }
private get _sidebarNarrow() { private get _sidebarNarrow() {
return this.narrow || this.hass.dockedSidebar === "always_hidden"; return this.narrow || this.hass.dockedSidebar === "always_hidden";
} }
private get drawer(): AppDrawerElement { private _drawerClosed() {
return this.shadowRoot!.querySelector("app-drawer")!; this._drawerOpen = false;
} this._sidebarEditMode = false;
private get appLayout(): AppDrawerLayoutElement {
return this.shadowRoot!.querySelector("app-drawer-layout")!;
} }
static get styles(): CSSResultGroup { static get styles(): CSSResultGroup {
@ -218,16 +164,21 @@ export class HomeAssistantMain extends LitElement {
color: var(--primary-text-color); color: var(--primary-text-color);
/* remove the grey tap highlights in iOS on the fullscreen touch targets */ /* remove the grey tap highlights in iOS on the fullscreen touch targets */
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
--app-drawer-width: 56px; --mdc-drawer-width: 56px;
} }
:host([expanded]) { :host([expanded]) {
--app-drawer-width: calc(256px + env(safe-area-inset-left)); --mdc-drawer-width: calc(256px + env(safe-area-inset-left));
} }
partial-panel-resolver, partial-panel-resolver,
ha-sidebar { ha-sidebar {
/* allow a light tap highlight on the actual interface elements */ /* allow a light tap highlight on the actual interface elements */
-webkit-tap-highlight-color: rgba(0, 0, 0, 0.1); -webkit-tap-highlight-color: rgba(0, 0, 0, 0.1);
} }
@media (min-width: 870px) {
partial-panel-resolver {
--mdc-top-app-bar-width: calc(100% - var(--mdc-drawer-width));
}
}
`; `;
} }
} }

View File

@ -1,8 +1,6 @@
import "@material/mwc-checkbox"; import "@material/mwc-checkbox";
import "@material/mwc-formfield"; import "@material/mwc-formfield";
import { mdiRefresh } from "@mdi/js"; import { mdiRefresh } from "@mdi/js";
import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import { import {
css, css,
CSSResultGroup, CSSResultGroup,
@ -25,10 +23,10 @@ import {
fetchCalendarEvents, fetchCalendarEvents,
getCalendars, getCalendars,
} from "../../data/calendar"; } from "../../data/calendar";
import "../../layouts/ha-app-layout";
import { haStyle } from "../../resources/styles"; import { haStyle } from "../../resources/styles";
import type { CalendarViewChanged, HomeAssistant } from "../../types"; import type { CalendarViewChanged, HomeAssistant } from "../../types";
import "./ha-full-calendar"; import "./ha-full-calendar";
import "../../components/ha-top-app-bar-fixed";
@customElement("ha-panel-calendar") @customElement("ha-panel-calendar")
class PanelCalendar extends LitElement { class PanelCalendar extends LitElement {
@ -59,21 +57,19 @@ class PanelCalendar extends LitElement {
protected render(): TemplateResult { protected render(): TemplateResult {
return html` return html`
<ha-app-layout> <ha-top-app-bar-fixed>
<app-header fixed slot="header"> <ha-menu-button
<app-toolbar> slot="navigationIcon"
<ha-menu-button .hass=${this.hass}
.hass=${this.hass} .narrow=${this.narrow}
.narrow=${this.narrow} ></ha-menu-button>
></ha-menu-button> <div slot="title">${this.hass.localize("panel.calendar")}</div>
<div main-title>${this.hass.localize("panel.calendar")}</div> <ha-icon-button
<ha-icon-button slot="actionItems"
.path=${mdiRefresh} .path=${mdiRefresh}
.label=${this.hass.localize("ui.common.refresh")} .label=${this.hass.localize("ui.common.refresh")}
@click=${this._handleRefresh} @click=${this._handleRefresh}
></ha-icon-button> ></ha-icon-button>
</app-toolbar>
</app-header>
<div class="content"> <div class="content">
<div class="calendar-list"> <div class="calendar-list">
<div class="calendar-list-header"> <div class="calendar-list-header">
@ -108,7 +104,7 @@ class PanelCalendar extends LitElement {
@view-changed=${this._handleViewChanged} @view-changed=${this._handleViewChanged}
></ha-full-calendar> ></ha-full-calendar>
</div> </div>
</ha-app-layout> </ha-top-app-bar-fixed>
`; `;
} }

View File

@ -14,8 +14,6 @@ import {
mdiStopCircleOutline, mdiStopCircleOutline,
mdiTransitConnection, mdiTransitConnection,
} from "@mdi/js"; } from "@mdi/js";
import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { UnsubscribeFunc } from "home-assistant-js-websocket";
import { import {
css, css,
@ -54,7 +52,6 @@ import {
showAlertDialog, showAlertDialog,
showConfirmationDialog, showConfirmationDialog,
} from "../../../dialogs/generic/show-dialog-box"; } from "../../../dialogs/generic/show-dialog-box";
import "../../../layouts/ha-app-layout";
import "../../../layouts/hass-subpage"; import "../../../layouts/hass-subpage";
import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin"; import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin";
import { haStyle } from "../../../resources/styles"; import { haStyle } from "../../../resources/styles";

View File

@ -5,7 +5,6 @@ import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../../../common/dom/fire_event"; import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/ha-alert"; import "../../../../components/ha-alert";
import { createCloseHeading } from "../../../../components/ha-dialog"; import { createCloseHeading } from "../../../../components/ha-dialog";
import "../../../../components/ha-header-bar";
import { HassDialog } from "../../../../dialogs/make-dialog-manager"; import { HassDialog } from "../../../../dialogs/make-dialog-manager";
import { haStyleDialog } from "../../../../resources/styles"; import { haStyleDialog } from "../../../../resources/styles";
import { HomeAssistant } from "../../../../types"; import { HomeAssistant } from "../../../../types";

View File

@ -6,8 +6,6 @@ import {
mdiPower, mdiPower,
mdiUpdate, mdiUpdate,
} from "@mdi/js"; } from "@mdi/js";
import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import { HassEntities, UnsubscribeFunc } from "home-assistant-js-websocket"; import { HassEntities, UnsubscribeFunc } from "home-assistant-js-websocket";
import { import {
css, css,
@ -28,6 +26,7 @@ import "../../../components/ha-list-item";
import "../../../components/ha-menu-button"; import "../../../components/ha-menu-button";
import "../../../components/ha-svg-icon"; import "../../../components/ha-svg-icon";
import "../../../components/ha-tip"; import "../../../components/ha-tip";
import "../../../components/ha-top-app-bar-fixed";
import { CloudStatus } from "../../../data/cloud"; import { CloudStatus } from "../../../data/cloud";
import { import {
RepairsIssue, RepairsIssue,
@ -41,7 +40,6 @@ import {
} from "../../../data/update"; } from "../../../data/update";
import { showQuickBar } from "../../../dialogs/quick-bar/show-dialog-quick-bar"; import { showQuickBar } from "../../../dialogs/quick-bar/show-dialog-quick-bar";
import { showRestartDialog } from "../../../dialogs/restart/show-dialog-restart"; import { showRestartDialog } from "../../../dialogs/restart/show-dialog-restart";
import "../../../layouts/ha-app-layout";
import { PageNavigation } from "../../../layouts/hass-tabs-subpage"; import { PageNavigation } from "../../../layouts/hass-tabs-subpage";
import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
import { haStyle } from "../../../resources/styles"; import { haStyle } from "../../../resources/styles";
@ -182,43 +180,43 @@ class HaConfigDashboard extends SubscribeMixin(LitElement) {
this._repairsIssues; this._repairsIssues;
return html` return html`
<ha-app-layout> <ha-top-app-bar-fixed>
<app-header fixed slot="header"> <ha-menu-button
<app-toolbar> slot="navigationIcon"
<ha-menu-button .hass=${this.hass}
.hass=${this.hass} .narrow=${this.narrow}
.narrow=${this.narrow} ></ha-menu-button>
></ha-menu-button> <div slot="title">${this.hass.localize("panel.config")}</div>
<div main-title>${this.hass.localize("panel.config")}</div>
<ha-icon-button
.label=${this.hass.localize("ui.dialogs.quick-bar.title")}
.path=${mdiMagnify}
@click=${this._showQuickBar}
></ha-icon-button>
<ha-button-menu
corner="BOTTOM_START"
@action=${this._handleMenuAction}
>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-list-item graphic="icon"> <ha-icon-button
${this.hass.localize("ui.panel.config.updates.check_updates")} slot="actionItems"
<ha-svg-icon slot="graphic" .path=${mdiUpdate}></ha-svg-icon> .label=${this.hass.localize("ui.dialogs.quick-bar.title")}
</ha-list-item> .path=${mdiMagnify}
@click=${this._showQuickBar}
></ha-icon-button>
<ha-button-menu
slot="actionItems"
corner="BOTTOM_START"
@action=${this._handleMenuAction}
>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-list-item graphic="icon"> <ha-list-item graphic="icon">
${this.hass.localize( ${this.hass.localize("ui.panel.config.updates.check_updates")}
"ui.panel.config.system_dashboard.restart_homeassistant" <ha-svg-icon slot="graphic" .path=${mdiUpdate}></ha-svg-icon>
)} </ha-list-item>
<ha-svg-icon slot="graphic" .path=${mdiPower}></ha-svg-icon>
</ha-list-item> <ha-list-item graphic="icon">
</ha-button-menu> ${this.hass.localize(
</app-toolbar> "ui.panel.config.system_dashboard.restart_homeassistant"
</app-header> )}
<ha-svg-icon slot="graphic" .path=${mdiPower}></ha-svg-icon>
</ha-list-item>
</ha-button-menu>
<ha-config-section <ha-config-section
.narrow=${this.narrow} .narrow=${this.narrow}
@ -292,7 +290,7 @@ class HaConfigDashboard extends SubscribeMixin(LitElement) {
</ha-card> </ha-card>
<ha-tip .hass=${this.hass}>${this._tip}</ha-tip> <ha-tip .hass=${this.hass}>${this._tip}</ha-tip>
</ha-config-section> </ha-config-section>
</ha-app-layout> </ha-top-app-bar-fixed>
`; `;
} }

View File

@ -10,7 +10,6 @@ import "../../../components/ha-card";
import "../../../components/ha-circular-progress"; import "../../../components/ha-circular-progress";
import "../../../components/ha-expansion-panel"; import "../../../components/ha-expansion-panel";
import "../../../components/ha-formfield"; import "../../../components/ha-formfield";
import "../../../components/ha-header-bar";
import "../../../components/ha-icon-button"; import "../../../components/ha-icon-button";
import "../../../components/ha-radio"; import "../../../components/ha-radio";
import "../../../components/ha-settings-row"; import "../../../components/ha-settings-row";

View File

@ -14,7 +14,6 @@ import "../../../components/ha-card";
import "../../../components/ha-circular-progress"; import "../../../components/ha-circular-progress";
import "../../../components/ha-expansion-panel"; import "../../../components/ha-expansion-panel";
import "../../../components/ha-formfield"; import "../../../components/ha-formfield";
import "../../../components/ha-header-bar";
import "../../../components/ha-icon-button"; import "../../../components/ha-icon-button";
import "../../../components/ha-radio"; import "../../../components/ha-radio";
import { extractApiErrorMessage } from "../../../data/hassio/common"; import { extractApiErrorMessage } from "../../../data/hassio/common";
@ -549,12 +548,6 @@ export class HassioNetwork extends LitElement {
static get styles(): CSSResultGroup { static get styles(): CSSResultGroup {
return [ return [
css` css`
ha-header-bar {
--mdc-theme-on-primary: var(--primary-text-color);
--mdc-theme-primary: var(--mdc-theme-surface);
flex-shrink: 0;
}
mwc-tab-bar { mwc-tab-bar {
border-bottom: 1px solid border-bottom: 1px solid
var(--mdc-dialog-scroll-divider-color, rgba(0, 0, 0, 0.12)); var(--mdc-dialog-scroll-divider-color, rgba(0, 0, 0, 0.12));
@ -573,11 +566,6 @@ export class HassioNetwork extends LitElement {
mwc-button.scan { mwc-button.scan {
margin-left: 8px; margin-left: 8px;
} }
:host([rtl]) app-toolbar {
direction: rtl;
text-align: right;
}
ha-expansion-panel { ha-expansion-panel {
--expansion-panel-summary-padding: 0 16px; --expansion-panel-summary-padding: 0 16px;
margin: 4px 0; margin: 4px 0;

View File

@ -9,8 +9,6 @@ import {
mdiPlay, mdiPlay,
mdiTransitConnection, mdiTransitConnection,
} from "@mdi/js"; } from "@mdi/js";
import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import { import {
css, css,
CSSResultGroup, CSSResultGroup,
@ -54,7 +52,6 @@ import {
triggerScript, triggerScript,
} from "../../../data/script"; } from "../../../data/script";
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box"; import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
import "../../../layouts/ha-app-layout";
import "../../../layouts/hass-subpage"; import "../../../layouts/hass-subpage";
import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin"; import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin";
import { haStyle } from "../../../resources/styles"; import { haStyle } from "../../../resources/styles";

View File

@ -1,12 +1,9 @@
import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import "@polymer/paper-tabs/paper-tab"; import "@polymer/paper-tabs/paper-tab";
import "@polymer/paper-tabs/paper-tabs";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import { navigate } from "../../common/navigate"; import { navigate } from "../../common/navigate";
import "../../components/ha-menu-button"; import "../../components/ha-menu-button";
import "../../components/ha-tabs";
import "../../layouts/ha-app-layout";
import { haStyle } from "../../resources/styles"; import { haStyle } from "../../resources/styles";
import { HomeAssistant, Route } from "../../types"; import { HomeAssistant, Route } from "../../types";
import "./developer-tools-router"; import "./developer-tools-router";
@ -27,57 +24,54 @@ class PanelDeveloperTools extends LitElement {
protected render(): TemplateResult { protected render(): TemplateResult {
const page = this._page; const page = this._page;
return html` return html`
<ha-app-layout> <div class="header">
<app-header fixed slot="header"> <div class="toolbar">
<app-toolbar> <ha-menu-button
<ha-menu-button slot="navigationIcon"
.hass=${this.hass} .hass=${this.hass}
.narrow=${this.narrow} .narrow=${this.narrow}
></ha-menu-button> ></ha-menu-button>
<div main-title>${this.hass.localize("panel.developer_tools")}</div> <div class="main-title">
</app-toolbar> ${this.hass.localize("panel.developer_tools")}
<ha-tabs </div>
scrollable </div>
attr-for-selected="page-name" <paper-tabs
.selected=${page} scrollable
@iron-activate=${this.handlePageSelected} attr-for-selected="page-name"
> .selected=${page}
<paper-tab page-name="yaml"> @iron-activate=${this.handlePageSelected}
${this.hass.localize("ui.panel.developer-tools.tabs.yaml.title")} >
</paper-tab> <paper-tab page-name="yaml">
<paper-tab page-name="state"> ${this.hass.localize("ui.panel.developer-tools.tabs.yaml.title")}
${this.hass.localize( </paper-tab>
"ui.panel.developer-tools.tabs.states.title" <paper-tab page-name="state">
)} ${this.hass.localize("ui.panel.developer-tools.tabs.states.title")}
</paper-tab> </paper-tab>
<paper-tab page-name="service"> <paper-tab page-name="service">
${this.hass.localize( ${this.hass.localize(
"ui.panel.developer-tools.tabs.services.title" "ui.panel.developer-tools.tabs.services.title"
)} )}
</paper-tab> </paper-tab>
<paper-tab page-name="template"> <paper-tab page-name="template">
${this.hass.localize( ${this.hass.localize(
"ui.panel.developer-tools.tabs.templates.title" "ui.panel.developer-tools.tabs.templates.title"
)} )}
</paper-tab> </paper-tab>
<paper-tab page-name="event"> <paper-tab page-name="event">
${this.hass.localize( ${this.hass.localize("ui.panel.developer-tools.tabs.events.title")}
"ui.panel.developer-tools.tabs.events.title" </paper-tab>
)} <paper-tab page-name="statistics">
</paper-tab> ${this.hass.localize(
<paper-tab page-name="statistics"> "ui.panel.developer-tools.tabs.statistics.title"
${this.hass.localize( )}
"ui.panel.developer-tools.tabs.statistics.title" </paper-tab>
)} </paper-tabs>
</paper-tab> </div>
</ha-tabs> <developer-tools-router
</app-header> .route=${this.route}
<developer-tools-router .narrow=${this.narrow}
.route=${this.route} .hass=${this.hass}
.narrow=${this.narrow} ></developer-tools-router>
.hass=${this.hass}
></developer-tools-router>
</ha-app-layout>
`; `;
} }
@ -99,14 +93,36 @@ class PanelDeveloperTools extends LitElement {
haStyle, haStyle,
css` css`
:host { :host {
display: block;
height: 100%;
color: var(--primary-text-color); color: var(--primary-text-color);
--paper-card-header-color: var(--primary-text-color); --paper-card-header-color: var(--primary-text-color);
} }
.header {
background-color: var(--app-header-background-color);
color: var(--app-header-text-color, white);
border-bottom: var(--app-header-border-bottom, none);
}
.toolbar {
height: var(--header-height);
display: flex;
align-items: center;
font-size: 20px;
padding: 0 16px;
font-weight: 400;
box-sizing: border-box;
}
.main-title {
margin: 0 0 0 24px;
line-height: 20px;
flex-grow: 1;
}
developer-tools-router { developer-tools-router {
display: block; display: block;
height: calc(100vh - 104px); height: calc(100% - var(--header-height) - 48px);
overflow: auto;
} }
ha-tabs { paper-tabs {
margin-left: max(env(safe-area-inset-left), 24px); margin-left: max(env(safe-area-inset-left), 24px);
margin-right: max(env(safe-area-inset-right), 24px); margin-right: max(env(safe-area-inset-right), 24px);
--paper-tabs-selection-bar-color: var( --paper-tabs-selection-bar-color: var(

View File

@ -1,5 +1,3 @@
import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import { import {
css, css,
CSSResultGroup, CSSResultGroup,
@ -11,12 +9,12 @@ import {
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import "../../components/ha-menu-button"; import "../../components/ha-menu-button";
import { LovelaceConfig } from "../../data/lovelace"; import { LovelaceConfig } from "../../data/lovelace";
import "../../layouts/ha-app-layout";
import { haStyle } from "../../resources/styles"; import { haStyle } from "../../resources/styles";
import { HomeAssistant } from "../../types"; import { HomeAssistant } from "../../types";
import "../lovelace/components/hui-energy-period-selector"; import "../lovelace/components/hui-energy-period-selector";
import { Lovelace } from "../lovelace/types"; import { Lovelace } from "../lovelace/types";
import "../lovelace/views/hui-view"; import "../lovelace/views/hui-view";
import "../../components/ha-top-app-bar-fixed";
const ENERGY_LOVELACE_CONFIG: LovelaceConfig = { const ENERGY_LOVELACE_CONFIG: LovelaceConfig = {
views: [ views: [
@ -62,24 +60,23 @@ class PanelEnergy extends LitElement {
protected render(): TemplateResult { protected render(): TemplateResult {
return html` return html`
<ha-app-layout> <ha-top-app-bar-fixed>
<app-header fixed slot="header"> <ha-menu-button
<app-toolbar> slot="navigationIcon"
<ha-menu-button .hass=${this.hass}
.hass=${this.hass} .narrow=${this.narrow}
.narrow=${this.narrow} ></ha-menu-button>
></ha-menu-button> <div slot="title">${this.hass.localize("panel.energy")}</div>
<div main-title>${this.hass.localize("panel.energy")}</div> ${this.narrow
${this.narrow ? ""
? "" : html`
: html` <hui-energy-period-selector
<hui-energy-period-selector slot="actionItems"
.hass=${this.hass} .hass=${this.hass}
collectionKey="energy_dashboard" collectionKey="energy_dashboard"
></hui-energy-period-selector> .narrow=${false}
`} ></hui-energy-period-selector>
</app-toolbar> `}
</app-header>
<hui-view <hui-view
.hass=${this.hass} .hass=${this.hass}
.narrow=${this.narrow} .narrow=${this.narrow}
@ -87,7 +84,7 @@ class PanelEnergy extends LitElement {
.index=${this._viewIndex} .index=${this._viewIndex}
@reload-energy-panel=${this._reloadView} @reload-energy-panel=${this._reloadView}
></hui-view> ></hui-view>
</ha-app-layout> </ha-top-app-bar-fixed>
`; `;
} }
@ -119,10 +116,6 @@ class PanelEnergy extends LitElement {
return [ return [
haStyle, haStyle,
css` css`
app-toolbar {
display: flex;
justify-content: space-between;
}
hui-energy-period-selector { hui-energy-period-selector {
width: 100%; width: 100%;
padding-left: 16px; padding-left: 16px;

View File

@ -1,6 +1,4 @@
import { mdiFilterRemove, mdiRefresh } from "@mdi/js"; import { mdiFilterRemove, mdiRefresh } from "@mdi/js";
import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import { import {
addDays, addDays,
differenceInHours, differenceInHours,
@ -54,10 +52,11 @@ import {
HistoryResult, HistoryResult,
subscribeHistory, subscribeHistory,
} from "../../data/history"; } from "../../data/history";
import "../../layouts/ha-app-layout";
import { SubscribeMixin } from "../../mixins/subscribe-mixin"; import { SubscribeMixin } from "../../mixins/subscribe-mixin";
import { haStyle } from "../../resources/styles"; import { haStyle } from "../../resources/styles";
import { HomeAssistant } from "../../types"; import { HomeAssistant } from "../../types";
import "../../components/ha-top-app-bar-fixed";
import "../../components/ha-icon-button-arrow-prev";
class HaPanelHistory extends SubscribeMixin(LitElement) { class HaPanelHistory extends SubscribeMixin(LitElement) {
@property({ attribute: false }) hass!: HomeAssistant; @property({ attribute: false }) hass!: HomeAssistant;
@ -137,40 +136,40 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
protected render() { protected render() {
return html` return html`
<ha-app-layout> <ha-top-app-bar-fixed>
<app-header slot="header" fixed> ${this._showBack
<app-toolbar> ? html`
${this._showBack <ha-icon-button-arrow-prev
? html` slot="navigationIcon"
<ha-icon-button-arrow-prev @click=${this._goBack}
@click=${this._goBack} ></ha-icon-button-arrow-prev>
></ha-icon-button-arrow-prev> `
` : html`
: html` <ha-menu-button
<ha-menu-button slot="navigationIcon"
.hass=${this.hass} .hass=${this.hass}
.narrow=${this.narrow} .narrow=${this.narrow}
></ha-menu-button> ></ha-menu-button>
`} `}
<div main-title>${this.hass.localize("panel.history")}</div> <div slot="title">${this.hass.localize("panel.history")}</div>
${this._targetPickerValue ${this._targetPickerValue
? html` ? html`
<ha-icon-button <ha-icon-button
@click=${this._removeAll} slot="actionItems"
.disabled=${this._isLoading} @click=${this._removeAll}
.path=${mdiFilterRemove} .disabled=${this._isLoading}
.label=${this.hass.localize("ui.panel.history.remove_all")} .path=${mdiFilterRemove}
></ha-icon-button> .label=${this.hass.localize("ui.panel.history.remove_all")}
` ></ha-icon-button>
: ""} `
<ha-icon-button : ""}
@click=${this._getHistory} <ha-icon-button
.disabled=${this._isLoading || !this._targetPickerValue} slot="actionItems"
.path=${mdiRefresh} @click=${this._getHistory}
.label=${this.hass.localize("ui.common.refresh")} .disabled=${this._isLoading || !this._targetPickerValue}
></ha-icon-button> .path=${mdiRefresh}
</app-toolbar> .label=${this.hass.localize("ui.common.refresh")}
</app-header> ></ha-icon-button>
<div class="flex content"> <div class="flex content">
<div class="filters"> <div class="filters">
@ -210,7 +209,7 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
</state-history-charts> </state-history-charts>
`} `}
</div> </div>
</ha-app-layout> </ha-top-app-bar-fixed>
`; `;
} }

View File

@ -1,6 +1,4 @@
import { mdiRefresh } from "@mdi/js"; import { mdiRefresh } from "@mdi/js";
import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import { import {
addDays, addDays,
endOfToday, endOfToday,
@ -24,9 +22,10 @@ import "../../components/entity/ha-entity-picker";
import "../../components/ha-date-range-picker"; import "../../components/ha-date-range-picker";
import type { DateRangePickerRanges } from "../../components/ha-date-range-picker"; import type { DateRangePickerRanges } from "../../components/ha-date-range-picker";
import "../../components/ha-icon-button"; import "../../components/ha-icon-button";
import "../../components/ha-icon-button-arrow-prev";
import "../../components/ha-menu-button"; import "../../components/ha-menu-button";
import "../../components/ha-top-app-bar-fixed";
import { filterLogbookCompatibleEntities } from "../../data/logbook"; import { filterLogbookCompatibleEntities } from "../../data/logbook";
import "../../layouts/ha-app-layout";
import { haStyle } from "../../resources/styles"; import { haStyle } from "../../resources/styles";
import { HomeAssistant } from "../../types"; import { HomeAssistant } from "../../types";
import "./ha-logbook"; import "./ha-logbook";
@ -64,29 +63,28 @@ export class HaPanelLogbook extends LitElement {
protected render() { protected render() {
return html` return html`
<ha-app-layout> <ha-top-app-bar-fixed>
<app-header slot="header" fixed> ${this._showBack
<app-toolbar> ? html`
${this._showBack <ha-icon-button-arrow-prev
? html` slot="navigationIcon"
<ha-icon-button-arrow-prev @click=${this._goBack}
@click=${this._goBack} ></ha-icon-button-arrow-prev>
></ha-icon-button-arrow-prev> `
` : html`
: html` <ha-menu-button
<ha-menu-button slot="navigationIcon"
.hass=${this.hass} .hass=${this.hass}
.narrow=${this.narrow} .narrow=${this.narrow}
></ha-menu-button> ></ha-menu-button>
`} `}
<div main-title>${this.hass.localize("panel.logbook")}</div> <div slot="title">${this.hass.localize("panel.logbook")}</div>
<ha-icon-button <ha-icon-button
@click=${this._refreshLogbook} slot="actionItems"
.path=${mdiRefresh} @click=${this._refreshLogbook}
.label=${this.hass!.localize("ui.common.refresh")} .path=${mdiRefresh}
></ha-icon-button> .label=${this.hass!.localize("ui.common.refresh")}
</app-toolbar> ></ha-icon-button>
</app-header>
<div class="filters"> <div class="filters">
<ha-date-range-picker <ha-date-range-picker
@ -114,7 +112,7 @@ export class HaPanelLogbook extends LitElement {
.entityIds=${this._entityIds} .entityIds=${this._entityIds}
virtualize virtualize
></ha-logbook> ></ha-logbook>
</ha-app-layout> </ha-top-app-bar-fixed>
`; `;
} }

View File

@ -44,7 +44,7 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) {
@property() public collectionKey?: string; @property() public collectionKey?: string;
@property({ type: Boolean, reflect: true }) public narrow = false; @property({ type: Boolean, reflect: true }) public narrow?;
@state() _startDate?: Date; @state() _startDate?: Date;
@ -56,7 +56,9 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) {
public connectedCallback() { public connectedCallback() {
super.connectedCallback(); super.connectedCallback();
toggleAttribute(this, "narrow", this.offsetWidth < 600); if (this.narrow !== false) {
toggleAttribute(this, "narrow", this.offsetWidth < 600);
}
} }
public hassSubscribe(): UnsubscribeFunc[] { public hassSubscribe(): UnsubscribeFunc[] {

View File

@ -1,8 +1,6 @@
import { undoDepth } from "@codemirror/commands"; import { undoDepth } from "@codemirror/commands";
import "@material/mwc-button"; import "@material/mwc-button";
import { mdiClose } from "@mdi/js"; import { mdiClose } from "@mdi/js";
import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import { dump, load } from "js-yaml"; import { dump, load } from "js-yaml";
import { import {
css, css,
@ -25,11 +23,11 @@ import {
showAlertDialog, showAlertDialog,
showConfirmationDialog, showConfirmationDialog,
} from "../../dialogs/generic/show-dialog-box"; } from "../../dialogs/generic/show-dialog-box";
import "../../layouts/ha-app-layout";
import { haStyle } from "../../resources/styles"; import { haStyle } from "../../resources/styles";
import type { HomeAssistant } from "../../types"; import type { HomeAssistant } from "../../types";
import { showToast } from "../../util/toast"; import { showToast } from "../../util/toast";
import type { Lovelace } from "./types"; import type { Lovelace } from "./types";
import "../../components/ha-top-app-bar-fixed";
const lovelaceStruct = type({ const lovelaceStruct = type({
title: optional(string()), title: optional(string()),
@ -50,43 +48,38 @@ class LovelaceFullConfigEditor extends LitElement {
protected render(): TemplateResult | void { protected render(): TemplateResult | void {
return html` return html`
<ha-app-layout> <ha-top-app-bar-fixed>
<app-header slot="header"> <ha-icon-button
<app-toolbar> slot="navigationIcon"
<ha-icon-button .path=${mdiClose}
.path=${mdiClose} @click=${this._closeEditor}
@click=${this._closeEditor} .label=${this.hass!.localize("ui.common.close")}
.label=${this.hass!.localize("ui.common.close")} ></ha-icon-button>
></ha-icon-button> <div slot="title">
<div main-title> ${this.hass!.localize("ui.panel.lovelace.editor.raw_editor.header")}
${this.hass!.localize( </div>
"ui.panel.lovelace.editor.raw_editor.header" <div
)} slot="actionItems"
</div> class="save-button
<div
class="save-button
${classMap({ ${classMap({
saved: this._saving! === false || this._changed === true, saved: this._saving! === false || this._changed === true,
})}" })}"
> >
${this._changed ${this._changed
? this.hass!.localize( ? this.hass!.localize(
"ui.panel.lovelace.editor.raw_editor.unsaved_changes" "ui.panel.lovelace.editor.raw_editor.unsaved_changes"
) )
: this.hass!.localize( : this.hass!.localize("ui.panel.lovelace.editor.raw_editor.saved")}
"ui.panel.lovelace.editor.raw_editor.saved" </div>
)} <mwc-button
</div> raised
<mwc-button slot="actionItems"
raised @click=${this._handleSave}
@click=${this._handleSave} .disabled=${!this._changed}
.disabled=${!this._changed} >${this.hass!.localize(
>${this.hass!.localize( "ui.panel.lovelace.editor.raw_editor.save"
"ui.panel.lovelace.editor.raw_editor.save" )}</mwc-button
)}</mwc-button >
>
</app-toolbar>
</app-header>
<div class="content"> <div class="content">
<ha-code-editor <ha-code-editor
mode="yaml" mode="yaml"
@ -100,7 +93,7 @@ class LovelaceFullConfigEditor extends LitElement {
> >
</ha-code-editor> </ha-code-editor>
</div> </div>
</ha-app-layout> </ha-top-app-bar-fixed>
`; `;
} }
@ -142,15 +135,11 @@ class LovelaceFullConfigEditor extends LitElement {
css` css`
:host { :host {
--code-mirror-height: 100%; --code-mirror-height: 100%;
} --app-header-background-color: var(
--app-header-edit-background-color,
ha-app-layout { #455a64
height: 100vh; );
} --app-header-text-color: var(--app-header-edit-text-color, #fff);
app-toolbar {
background-color: var(--app-header-edit-background-color, #455a64);
color: var(--app-header-edit-text-color, #fff);
} }
mwc-button[disabled] { mwc-button[disabled] {
@ -158,14 +147,14 @@ class LovelaceFullConfigEditor extends LitElement {
border-radius: 4px; border-radius: 4px;
} }
.comments {
font-size: 16px;
}
.content { .content {
height: calc(100vh - var(--header-height)); height: calc(100vh - var(--header-height));
} }
.comments {
font-size: 16px;
}
.save-button { .save-button {
opacity: 0; opacity: 0;
font-size: 14px; font-size: 14px;

View File

@ -16,9 +16,6 @@ import {
mdiShape, mdiShape,
mdiViewDashboard, mdiViewDashboard,
} from "@mdi/js"; } from "@mdi/js";
import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-scroll-effects/effects/waterfall";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import "@polymer/paper-tabs/paper-tab"; import "@polymer/paper-tabs/paper-tab";
import "@polymer/paper-tabs/paper-tabs"; import "@polymer/paper-tabs/paper-tabs";
import { import {
@ -35,7 +32,6 @@ import { ifDefined } from "lit/directives/if-defined";
import memoizeOne from "memoize-one"; import memoizeOne from "memoize-one";
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 scrollToTarget from "../../common/dom/scroll-to-target";
import { shouldHandleRequestSelectedEvent } from "../../common/mwc/handle-request-selected-event"; import { shouldHandleRequestSelectedEvent } from "../../common/mwc/handle-request-selected-event";
import { navigate } from "../../common/navigate"; import { navigate } from "../../common/navigate";
import { constructUrlCurrentPath } from "../../common/url/construct-url"; import { constructUrlCurrentPath } from "../../common/url/construct-url";
@ -66,8 +62,6 @@ import {
} from "../../dialogs/generic/show-dialog-box"; } from "../../dialogs/generic/show-dialog-box";
import { showQuickBar } from "../../dialogs/quick-bar/show-dialog-quick-bar"; import { showQuickBar } from "../../dialogs/quick-bar/show-dialog-quick-bar";
import { showVoiceCommandDialog } from "../../dialogs/voice-command-dialog/show-ha-voice-command-dialog"; import { showVoiceCommandDialog } from "../../dialogs/voice-command-dialog/show-ha-voice-command-dialog";
import "../../layouts/ha-app-layout";
import type { haAppLayout } from "../../layouts/ha-app-layout";
import { haStyle } from "../../resources/styles"; import { haStyle } from "../../resources/styles";
import type { HomeAssistant } from "../../types"; import type { HomeAssistant } from "../../types";
import { documentationUrl } from "../../util/documentation-url"; import { documentationUrl } from "../../util/documentation-url";
@ -93,7 +87,7 @@ class HUIRoot extends LitElement {
@state() private _curView?: number | "hass-unused-entities"; @state() private _curView?: number | "hass-unused-entities";
@query("ha-app-layout", true) private _appLayout!: haAppLayout; @query("#view", true) _view!: HTMLDivElement;
private _viewCache?: { [viewId: string]: HUIView }; private _viewCache?: { [viewId: string]: HUIView };
@ -121,20 +115,20 @@ class HUIRoot extends LitElement {
typeof this._curView === "number" ? views[this._curView] : undefined; typeof this._curView === "number" ? views[this._curView] : undefined;
return html` return html`
<ha-app-layout <div
class=${classMap({ class=" ${classMap({
"edit-mode": this._editMode, "edit-mode": this._editMode,
})} })}"
id="layout"
> >
<app-header slot="header" effects="waterfall" fixed condenses> <div class="header">
${this._editMode <div class="toolbar">
? html` ${this._editMode
<app-toolbar class="edit-mode"> ? html`
<div main-title> <div class="main-title">
${this.config.title || ${this.config.title ||
this.hass!.localize("ui.panel.lovelace.editor.header")} this.hass!.localize("ui.panel.lovelace.editor.header")}
<ha-icon-button <ha-icon-button
slot="actionItems"
.label=${this.hass!.localize( .label=${this.hass!.localize(
"ui.panel.lovelace.editor.edit_lovelace.edit_title" "ui.panel.lovelace.editor.edit_lovelace.edit_title"
)} )}
@ -143,114 +137,118 @@ class HUIRoot extends LitElement {
@click=${this._editLovelace} @click=${this._editLovelace}
></ha-icon-button> ></ha-icon-button>
</div> </div>
<mwc-button <div class="action-items">
outlined <mwc-button
class="exit-edit-mode" outlined
.label=${this.hass!.localize( class="exit-edit-mode"
"ui.panel.lovelace.menu.exit_edit_mode"
)}
@click=${this._editModeDisable}
></mwc-button>
<a
href=${documentationUrl(this.hass, "/dashboards/")}
rel="noreferrer"
class="menu-link"
target="_blank"
>
<ha-icon-button
.label=${this.hass!.localize( .label=${this.hass!.localize(
"ui.panel.lovelace.menu.help" "ui.panel.lovelace.menu.exit_edit_mode"
)} )}
.path=${mdiHelpCircle} @click=${this._editModeDisable}
></ha-icon-button> ></mwc-button>
</a> <a
<ha-button-menu corner="BOTTOM_START"> href=${documentationUrl(this.hass, "/dashboards/")}
<ha-icon-button rel="noreferrer"
slot="trigger" class="menu-link"
.label=${this.hass!.localize( target="_blank"
"ui.panel.lovelace.editor.menu.open"
)}
.path=${mdiDotsVertical}
></ha-icon-button>
${__DEMO__ /* No unused entities available in the demo */
? ""
: html`
<mwc-list-item
graphic="icon"
@request-selected=${this._handleUnusedEntities}
>
<ha-svg-icon
slot="graphic"
.path=${mdiFormatListBulletedTriangle}
>
</ha-svg-icon>
${this.hass!.localize(
"ui.panel.lovelace.unused_entities.title"
)}
</mwc-list-item>
`}
<mwc-list-item
graphic="icon"
@request-selected=${this._handleRawEditor}
> >
<ha-svg-icon <ha-icon-button
slot="graphic" .label=${this.hass!.localize(
.path=${mdiCodeBraces} "ui.panel.lovelace.menu.help"
></ha-svg-icon> )}
${this.hass!.localize( .path=${mdiHelpCircle}
"ui.panel.lovelace.editor.menu.raw_editor" ></ha-icon-button>
)} </a>
</mwc-list-item> <ha-button-menu corner="BOTTOM_START">
${__DEMO__ /* No config available in the demo */ <ha-icon-button
? "" slot="trigger"
: html`<mwc-list-item .label=${this.hass!.localize(
graphic="icon" "ui.panel.lovelace.editor.menu.open"
@request-selected=${this._handleManageDashboards} )}
> .path=${mdiDotsVertical}
<ha-svg-icon ></ha-icon-button>
slot="graphic" ${__DEMO__ /* No unused entities available in the demo */
.path=${mdiViewDashboard} ? ""
></ha-svg-icon> : html`
${this.hass!.localize( <mwc-list-item
"ui.panel.lovelace.editor.menu.manage_dashboards" graphic="icon"
)} @request-selected=${this._handleUnusedEntities}
</mwc-list-item> >
${this.hass.userData?.showAdvanced <ha-svg-icon
? html`<mwc-list-item slot="graphic"
graphic="icon" .path=${mdiFormatListBulletedTriangle}
@request-selected=${this._handleManageResources}
> >
<ha-svg-icon </ha-svg-icon>
slot="graphic" ${this.hass!.localize(
.path=${mdiFileMultiple} "ui.panel.lovelace.unused_entities.title"
></ha-svg-icon> )}
${this.hass!.localize( </mwc-list-item>
"ui.panel.lovelace.editor.menu.manage_resources" `}
)} <mwc-list-item
</mwc-list-item>` graphic="icon"
: ""} `} @request-selected=${this._handleRawEditor}
</ha-button-menu> >
</app-toolbar> <ha-svg-icon
` slot="graphic"
: html` .path=${mdiCodeBraces}
<app-toolbar> ></ha-svg-icon>
${this.hass!.localize(
"ui.panel.lovelace.editor.menu.raw_editor"
)}
</mwc-list-item>
${__DEMO__ /* No config available in the demo */
? ""
: html`<mwc-list-item
graphic="icon"
@request-selected=${this._handleManageDashboards}
>
<ha-svg-icon
slot="graphic"
.path=${mdiViewDashboard}
></ha-svg-icon>
${this.hass!.localize(
"ui.panel.lovelace.editor.menu.manage_dashboards"
)}
</mwc-list-item>
${this.hass.userData?.showAdvanced
? html`<mwc-list-item
graphic="icon"
@request-selected=${this
._handleManageResources}
>
<ha-svg-icon
slot="graphic"
.path=${mdiFileMultiple}
></ha-svg-icon>
${this.hass!.localize(
"ui.panel.lovelace.editor.menu.manage_resources"
)}
</mwc-list-item>`
: ""} `}
</ha-button-menu>
</div>
`
: html`
${curViewConfig?.subview ${curViewConfig?.subview
? html` ? html`
<ha-icon-button-arrow-prev <ha-icon-button-arrow-prev
slot="navigationIcon"
@click=${this._goBack} @click=${this._goBack}
></ha-icon-button-arrow-prev> ></ha-icon-button-arrow-prev>
` `
: html` : html`
<ha-menu-button <ha-menu-button
slot="navigationIcon"
.hass=${this.hass} .hass=${this.hass}
.narrow=${this.narrow} .narrow=${this.narrow}
></ha-menu-button> ></ha-menu-button>
`} `}
${curViewConfig?.subview ${curViewConfig?.subview
? html`<div main-title>${curViewConfig.title}</div>` ? html`<div class="main-title">${curViewConfig.title}</div>`
: views.filter((view) => !view.subview).length > 1 : views.filter((view) => !view.subview).length > 1
? html` ? html`
<ha-tabs <ha-tabs
slot="title"
scrollable scrollable
.selected=${this._curView} .selected=${this._curView}
@iron-activate=${this._handleViewSelected} @iron-activate=${this._handleViewSelected}
@ -286,265 +284,271 @@ class HUIRoot extends LitElement {
)} )}
</ha-tabs> </ha-tabs>
` `
: html`<div main-title>${this.config.title}</div>`} : html`<div class="main-title">${this.config.title}</div>`}
${!this.narrow <div class="action-items">
? html` ${!this.narrow
<ha-icon-button
.label=${this.hass!.localize(
"ui.panel.lovelace.menu.search"
)}
.path=${mdiMagnify}
@click=${this._showQuickBar}
></ha-icon-button>
`
: ""}
${!this.narrow &&
this._conversation(this.hass.config.components)
? html`
<ha-icon-button
.label=${this.hass!.localize(
"ui.panel.lovelace.menu.assist"
)}
.path=${mdiCommentProcessingOutline}
@click=${this._showVoiceCommandDialog}
></ha-icon-button>
`
: ""}
${this._showButtonMenu
? html`
<ha-button-menu corner="BOTTOM_START">
<ha-icon-button
slot="trigger"
.label=${this.hass!.localize(
"ui.panel.lovelace.editor.menu.open"
)}
.path=${mdiDotsVertical}
></ha-icon-button>
${this.narrow
? html`
<mwc-list-item
graphic="icon"
@request-selected=${this._handleShowQuickBar}
>
${this.hass!.localize(
"ui.panel.lovelace.menu.search"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiMagnify}
></ha-svg-icon>
</mwc-list-item>
`
: ""}
${this.narrow &&
this._conversation(this.hass.config.components)
? html`
<mwc-list-item
graphic="icon"
@request-selected=${this
._handleShowVoiceCommandDialog}
>
${this.hass!.localize(
"ui.panel.lovelace.menu.assist"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiCommentProcessingOutline}
></ha-svg-icon>
</mwc-list-item>
`
: ""}
${this._yamlMode
? html`
<mwc-list-item
graphic="icon"
@request-selected=${this._handleRefresh}
>
${this.hass!.localize("ui.common.refresh")}
<ha-svg-icon
slot="graphic"
.path=${mdiRefresh}
></ha-svg-icon>
</mwc-list-item>
<mwc-list-item
graphic="icon"
@request-selected=${this
._handleUnusedEntities}
>
${this.hass!.localize(
"ui.panel.lovelace.unused_entities.title"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiShape}
></ha-svg-icon>
</mwc-list-item>
`
: ""}
${(
this.hass.panels.lovelace
?.config as LovelacePanelConfig
)?.mode === "yaml"
? html`
<mwc-list-item
graphic="icon"
@request-selected=${this
._handleReloadResources}
>
${this.hass!.localize(
"ui.panel.lovelace.menu.reload_resources"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiRefresh}
></ha-svg-icon>
</mwc-list-item>
`
: ""}
${this.hass!.user?.is_admin &&
!this.hass!.config.safe_mode
? html`
<mwc-list-item
graphic="icon"
@request-selected=${this
._handleEnableEditMode}
>
${this.hass!.localize(
"ui.panel.lovelace.menu.configure_ui"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiPencil}
></ha-svg-icon>
</mwc-list-item>
`
: ""}
${this._editMode
? html`
<a
href=${documentationUrl(
this.hass,
"/lovelace/"
)}
rel="noreferrer"
class="menu-link"
target="_blank"
>
<mwc-list-item graphic="icon">
${this.hass!.localize(
"ui.panel.lovelace.menu.help"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiHelp}
></ha-svg-icon>
</mwc-list-item>
</a>
`
: ""}
</ha-button-menu>
`
: ""}
</app-toolbar>
`}
${this._editMode
? html`
<div sticky>
<paper-tabs
scrollable
.selected=${this._curView}
@iron-activate=${this._handleViewSelected}
dir=${computeRTLDirection(this.hass!)}
>
${views.map(
(view) => html`
<paper-tab
aria-label=${ifDefined(view.title)}
class=${classMap({
"hide-tab": Boolean(
!this._editMode &&
view.visible !== undefined &&
((Array.isArray(view.visible) &&
!view.visible.some(
(e) => e.user === this.hass!.user?.id
)) ||
view.visible === false)
),
})}
>
${this._editMode
? html`
<ha-icon-button-arrow-prev
.hass=${this.hass}
.label=${this.hass!.localize(
"ui.panel.lovelace.editor.edit_view.move_left"
)}
class="edit-icon view"
@click=${this._moveViewLeft}
?disabled=${this._curView === 0}
></ha-icon-button-arrow-prev>
`
: ""}
${view.icon
? html`
<ha-icon
class=${classMap({
"child-view-icon": Boolean(view.subview),
})}
title=${ifDefined(view.title)}
.icon=${view.icon}
></ha-icon>
`
: view.title || "Unnamed view"}
${this._editMode
? html`
<ha-svg-icon
title=${this.hass!.localize(
"ui.panel.lovelace.editor.edit_view.edit"
)}
class="edit-icon view"
.path=${mdiPencil}
@click=${this._editView}
></ha-svg-icon>
<ha-icon-button-arrow-next
.hass=${this.hass}
.label=${this.hass!.localize(
"ui.panel.lovelace.editor.edit_view.move_right"
)}
class="edit-icon view"
@click=${this._moveViewRight}
?disabled=${(this._curView! as number) + 1 ===
views.length}
></ha-icon-button-arrow-next>
`
: ""}
</paper-tab>
`
)}
${this._editMode
? html` ? html`
<ha-icon-button <ha-icon-button
id="add-view" slot="actionItems"
@click=${this._addView}
.label=${this.hass!.localize( .label=${this.hass!.localize(
"ui.panel.lovelace.editor.edit_view.add" "ui.panel.lovelace.menu.search"
)} )}
.path=${mdiPlus} .path=${mdiMagnify}
@click=${this._showQuickBar}
></ha-icon-button> ></ha-icon-button>
` `
: ""} : ""}
</paper-tabs> ${!this.narrow &&
</div> this._conversation(this.hass.config.components)
? html`
<ha-icon-button
slot="actionItems"
.label=${this.hass!.localize(
"ui.panel.lovelace.menu.assist"
)}
.path=${mdiCommentProcessingOutline}
@click=${this._showVoiceCommandDialog}
></ha-icon-button>
`
: ""}
${this._showButtonMenu
? html`
<ha-button-menu
corner="BOTTOM_START"
slot="actionItems"
>
<ha-icon-button
slot="trigger"
.label=${this.hass!.localize(
"ui.panel.lovelace.editor.menu.open"
)}
.path=${mdiDotsVertical}
></ha-icon-button>
${this.narrow
? html`
<mwc-list-item
graphic="icon"
@request-selected=${this
._handleShowQuickBar}
>
${this.hass!.localize(
"ui.panel.lovelace.menu.search"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiMagnify}
></ha-svg-icon>
</mwc-list-item>
`
: ""}
${this.narrow &&
this._conversation(this.hass.config.components)
? html`
<mwc-list-item
graphic="icon"
@request-selected=${this
._handleShowVoiceCommandDialog}
>
${this.hass!.localize(
"ui.panel.lovelace.menu.assist"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiCommentProcessingOutline}
></ha-svg-icon>
</mwc-list-item>
`
: ""}
${this._yamlMode
? html`
<mwc-list-item
graphic="icon"
@request-selected=${this._handleRefresh}
>
${this.hass!.localize("ui.common.refresh")}
<ha-svg-icon
slot="graphic"
.path=${mdiRefresh}
></ha-svg-icon>
</mwc-list-item>
<mwc-list-item
graphic="icon"
@request-selected=${this
._handleUnusedEntities}
>
${this.hass!.localize(
"ui.panel.lovelace.unused_entities.title"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiShape}
></ha-svg-icon>
</mwc-list-item>
`
: ""}
${(
this.hass.panels.lovelace
?.config as LovelacePanelConfig
)?.mode === "yaml"
? html`
<mwc-list-item
graphic="icon"
@request-selected=${this
._handleReloadResources}
>
${this.hass!.localize(
"ui.panel.lovelace.menu.reload_resources"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiRefresh}
></ha-svg-icon>
</mwc-list-item>
`
: ""}
${this.hass!.user?.is_admin &&
!this.hass!.config.safe_mode
? html`
<mwc-list-item
graphic="icon"
@request-selected=${this
._handleEnableEditMode}
>
${this.hass!.localize(
"ui.panel.lovelace.menu.configure_ui"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiPencil}
></ha-svg-icon>
</mwc-list-item>
`
: ""}
${this._editMode
? html`
<a
href=${documentationUrl(
this.hass,
"/lovelace/"
)}
rel="noreferrer"
class="menu-link"
target="_blank"
>
<mwc-list-item graphic="icon">
${this.hass!.localize(
"ui.panel.lovelace.menu.help"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiHelp}
></ha-svg-icon>
</mwc-list-item>
</a>
`
: ""}
</ha-button-menu>
`
: ""}
</div>
`}
</div>
${this._editMode
? html`
<paper-tabs
scrollable
.selected=${this._curView}
@iron-activate=${this._handleViewSelected}
dir=${computeRTLDirection(this.hass!)}
>
${views.map(
(view) => html`
<paper-tab
aria-label=${ifDefined(view.title)}
class=${classMap({
"hide-tab": Boolean(
!this._editMode &&
view.visible !== undefined &&
((Array.isArray(view.visible) &&
!view.visible.some(
(e) => e.user === this.hass!.user?.id
)) ||
view.visible === false)
),
})}
>
${this._editMode
? html`
<ha-icon-button-arrow-prev
.hass=${this.hass}
.label=${this.hass!.localize(
"ui.panel.lovelace.editor.edit_view.move_left"
)}
class="edit-icon view"
@click=${this._moveViewLeft}
?disabled=${this._curView === 0}
></ha-icon-button-arrow-prev>
`
: ""}
${view.icon
? html`
<ha-icon
class=${classMap({
"child-view-icon": Boolean(view.subview),
})}
title=${ifDefined(view.title)}
.icon=${view.icon}
></ha-icon>
`
: view.title || "Unnamed view"}
${this._editMode
? html`
<ha-svg-icon
title=${this.hass!.localize(
"ui.panel.lovelace.editor.edit_view.edit"
)}
class="edit-icon view"
.path=${mdiPencil}
@click=${this._editView}
></ha-svg-icon>
<ha-icon-button-arrow-next
.hass=${this.hass}
.label=${this.hass!.localize(
"ui.panel.lovelace.editor.edit_view.move_right"
)}
class="edit-icon view"
@click=${this._moveViewRight}
?disabled=${(this._curView! as number) + 1 ===
views.length}
></ha-icon-button-arrow-next>
`
: ""}
</paper-tab>
`
)}
${this._editMode
? html`
<ha-icon-button
id="add-view"
@click=${this._addView}
.label=${this.hass!.localize(
"ui.panel.lovelace.editor.edit_view.add"
)}
.path=${mdiPlus}
></ha-icon-button>
`
: ""}
</paper-tabs>
` `
: ""} : ""}
</app-header> </div>
<div id="view" @ll-rebuild=${this._debouncedConfigChanged}></div> <div id="view" @ll-rebuild=${this._debouncedConfigChanged}></div>
</ha-app-layout> </div>
`; `;
} }
@ -668,10 +672,6 @@ class HUIRoot extends LitElement {
return this.lovelace!.editMode; return this.lovelace!.editMode;
} }
private get _layout(): any {
return this.shadowRoot!.getElementById("layout");
}
private get _viewRoot(): HTMLDivElement { private get _viewRoot(): HTMLDivElement {
return this.shadowRoot!.getElementById("view") as HTMLDivElement; return this.shadowRoot!.getElementById("view") as HTMLDivElement;
} }
@ -862,7 +862,7 @@ class HUIRoot extends LitElement {
const path = this.config.views[viewIndex].path || viewIndex; const path = this.config.views[viewIndex].path || viewIndex;
this._navigateToView(path); this._navigateToView(path);
} }
scrollToTarget(this, this._layout.header.scrollTarget); this._view.scrollTo(0, 0);
} }
private _selectView(viewIndex: HUIRoot["_curView"], force: boolean): void { private _selectView(viewIndex: HUIRoot["_curView"], force: boolean): void {
@ -920,12 +920,9 @@ class HUIRoot extends LitElement {
const configBackground = viewConfig.background || this.config.background; const configBackground = viewConfig.background || this.config.background;
if (configBackground) { if (configBackground) {
this._appLayout.style.setProperty( this.style.setProperty("--lovelace-background", configBackground);
"--lovelace-background",
configBackground
);
} else { } else {
this._appLayout.style.removeProperty("--lovelace-background"); this.style.removeProperty("--lovelace-background");
} }
root.appendChild(view); root.appendChild(view);
@ -942,20 +939,43 @@ class HUIRoot extends LitElement {
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
} }
.header {
ha-app-layout { background-color: var(--app-header-background-color);
min-height: 100%; color: var(--app-header-text-color, white);
border-bottom: var(--app-header-border-bottom, none);
position: fixed;
top: 0;
width: var(--mdc-top-app-bar-width, 100%);
z-index: 2;
}
.edit-mode .header {
background-color: var(--app-header-edit-background-color, #455a64);
color: var(--app-header-edit-text-color, white);
}
.toolbar {
height: var(--header-height);
display: flex;
align-items: center;
font-size: 20px;
padding: 0 16px;
font-weight: 400;
box-sizing: border-box;
}
.main-title {
margin: 0 0 0 24px;
line-height: 20px;
flex-grow: 1;
}
.action-items {
white-space: nowrap;
display: flex;
align-items: center;
} }
ha-tabs { ha-tabs {
width: 100%; width: 100%;
height: 100%; height: 100%;
margin-left: 4px; margin-left: 4px;
} }
paper-tabs {
margin-left: 12px;
margin-left: max(env(safe-area-inset-left), 12px);
margin-right: env(safe-area-inset-right);
}
ha-tabs, ha-tabs,
paper-tabs { paper-tabs {
--paper-tabs-selection-bar-color: var( --paper-tabs-selection-bar-color: var(
@ -964,15 +984,13 @@ class HUIRoot extends LitElement {
); );
text-transform: uppercase; text-transform: uppercase;
} }
.edit-mode app-header,
.edit-mode app-toolbar {
background-color: var(--app-header-edit-background-color, #455a64);
color: var(--app-header-edit-text-color, #fff);
}
.edit-mode div[main-title] { .edit-mode div[main-title] {
pointer-events: auto; pointer-events: auto;
} }
.edit-mode paper-tabs {
background-color: var(--app-header-edit-background-color, #455a64);
color: var(--app-header-edit-text-color, #fff);
}
paper-tab.iron-selected .edit-icon { paper-tab.iron-selected .edit-icon {
display: inline-flex; display: inline-flex;
} }
@ -995,14 +1013,15 @@ class HUIRoot extends LitElement {
background-color: var(--accent-color); background-color: var(--accent-color);
border-radius: 4px; border-radius: 4px;
} }
app-toolbar a { a {
color: var(--text-primary-color, white); color: var(--text-primary-color, white);
} }
mwc-button.warning:not([disabled]) { mwc-button.warning:not([disabled]) {
color: var(--error-color); color: var(--error-color);
} }
#view { #view {
min-height: calc( margin-top: var(--header-height);
height: calc(
100vh - var(--header-height) - env(safe-area-inset-top) - 100vh - var(--header-height) - env(safe-area-inset-top) -
env(safe-area-inset-bottom) env(safe-area-inset-bottom)
); );
@ -1015,15 +1034,17 @@ class HUIRoot extends LitElement {
*/ */
position: relative; position: relative;
display: flex; display: flex;
overflow: auto;
} }
/** /**
* In edit mode we have the tab bar on a new line * * In edit mode we have the tab bar on a new line *
*/ */
.edit-mode #view { .edit-mode #view {
min-height: calc( height: calc(
100vh - var(--header-height) - 48px - env(safe-area-inset-top) - 100vh - var(--header-height) - 48px - env(safe-area-inset-top) -
env(safe-area-inset-bottom) env(safe-area-inset-bottom)
); );
margin-top: calc(var(--header-height) + 48px);
} }
#view > * { #view > * {
/** /**

View File

@ -1,13 +1,12 @@
import { mdiPencil } from "@mdi/js"; import { mdiPencil } from "@mdi/js";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit"; import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
import { customElement, property } from "lit/decorators"; import { customElement, property } from "lit/decorators";
import { computeStateDomain } from "../../common/entity/compute_state_domain"; import { computeStateDomain } from "../../common/entity/compute_state_domain";
import { navigate } from "../../common/navigate"; import { navigate } from "../../common/navigate";
import "../../components/ha-menu-button";
import "../../components/ha-icon-button"; import "../../components/ha-icon-button";
import "../../components/ha-menu-button";
import "../../components/ha-top-app-bar-fixed";
import "../../components/map/ha-map"; import "../../components/map/ha-map";
import "../../layouts/ha-app-layout";
import { haStyle } from "../../resources/styles"; import { haStyle } from "../../resources/styles";
import { HomeAssistant } from "../../types"; import { HomeAssistant } from "../../types";
@ -21,30 +20,28 @@ class HaPanelMap extends LitElement {
protected render() { protected render() {
return html` return html`
<ha-app-layout> <ha-top-app-bar-fixed>
<app-header fixed slot="header"> <ha-menu-button
<app-toolbar> slot="navigationIcon"
<ha-menu-button .hass=${this.hass}
.hass=${this.hass} .narrow=${this.narrow}
.narrow=${this.narrow} ></ha-menu-button>
></ha-menu-button> <div slot="title">${this.hass.localize("panel.map")}</div>
<div main-title>${this.hass.localize("panel.map")}</div> ${!__DEMO__ && this.hass.user?.is_admin
${!__DEMO__ && this.hass.user?.is_admin ? html` <ha-icon-button
? html` <ha-icon-button slot="actionItems"
.label=${this.hass!.localize("ui.panel.map.edit_zones")} .label=${this.hass!.localize("ui.panel.map.edit_zones")}
.path=${mdiPencil} .path=${mdiPencil}
@click=${this._openZonesEditor} @click=${this._openZonesEditor}
></ha-icon-button>` ></ha-icon-button>`
: ""} : ""}
</app-toolbar>
</app-header>
<ha-map <ha-map
.hass=${this.hass} .hass=${this.hass}
.entities=${this._entities} .entities=${this._entities}
autoFit autoFit
interactiveZones interactiveZones
></ha-map> ></ha-map>
</ha-app-layout> </ha-top-app-bar-fixed>
`; `;
} }

View File

@ -1,6 +1,4 @@
import { mdiArrowLeft } from "@mdi/js"; import { mdiArrowLeft } from "@mdi/js";
import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import "@material/mwc-button"; import "@material/mwc-button";
import { import {
css, css,
@ -33,7 +31,6 @@ import {
ResolvedMediaSource, ResolvedMediaSource,
resolveMediaSource, resolveMediaSource,
} from "../../data/media_source"; } from "../../data/media_source";
import "../../layouts/ha-app-layout";
import { haStyle } from "../../resources/styles"; import { haStyle } from "../../resources/styles";
import type { HomeAssistant, Route } from "../../types"; import type { HomeAssistant, Route } from "../../types";
import "./ha-bar-media-player"; import "./ha-bar-media-player";
@ -44,6 +41,7 @@ import {
getEntityIdFromCameraMediaSource, getEntityIdFromCameraMediaSource,
isCameraMediaSource, isCameraMediaSource,
} from "../../data/camera"; } from "../../data/camera";
import "../../components/ha-top-app-bar-fixed";
const createMediaPanelUrl = (entityId: string, items: MediaPlayerItemId[]) => { const createMediaPanelUrl = (entityId: string, items: MediaPlayerItemId[]) => {
let path = `/media-browser/${entityId}`; let path = `/media-browser/${entityId}`;
@ -82,36 +80,35 @@ class PanelMediaBrowser extends LitElement {
protected render(): TemplateResult { protected render(): TemplateResult {
return html` return html`
<ha-app-layout> <ha-top-app-bar-fixed>
<app-header fixed slot="header"> ${this._navigateIds.length > 1
<app-toolbar> ? html`
${this._navigateIds.length > 1 <ha-icon-button-arrow-prev
? html` slot="navigationIcon"
<ha-icon-button-arrow-prev .path=${mdiArrowLeft}
.path=${mdiArrowLeft} @click=${this._goBack}
@click=${this._goBack} ></ha-icon-button-arrow-prev>
></ha-icon-button-arrow-prev> `
` : html`
: html` <ha-menu-button
<ha-menu-button slot="navigationIcon"
.hass=${this.hass} .hass=${this.hass}
.narrow=${this.narrow} .narrow=${this.narrow}
></ha-menu-button> ></ha-menu-button>
`} `}
<div main-title> <div slot="title">
${!this._currentItem ${!this._currentItem
? this.hass.localize( ? this.hass.localize(
"ui.components.media-browser.media-player-browser" "ui.components.media-browser.media-player-browser"
) )
: this._currentItem.title} : this._currentItem.title}
</div> </div>
<ha-media-manage-button <ha-media-manage-button
.hass=${this.hass} slot="actionItems"
.currentItem=${this._currentItem} .hass=${this.hass}
@media-refresh=${this._refreshMedia} .currentItem=${this._currentItem}
></ha-media-manage-button> @media-refresh=${this._refreshMedia}
</app-toolbar> ></ha-media-manage-button>
</app-header>
<ha-media-player-browse <ha-media-player-browse
.hass=${this.hass} .hass=${this.hass}
.entityId=${this._entityId} .entityId=${this._entityId}
@ -119,7 +116,7 @@ class PanelMediaBrowser extends LitElement {
@media-picked=${this._mediaPicked} @media-picked=${this._mediaPicked}
@media-browsed=${this._mediaBrowsed} @media-browsed=${this._mediaBrowsed}
></ha-media-player-browse> ></ha-media-player-browse>
</ha-app-layout> </ha-top-app-bar-fixed>
<ha-bar-media-player <ha-bar-media-player
.hass=${this.hass} .hass=${this.hass}
.entityId=${this._entityId} .entityId=${this._entityId}
@ -275,7 +272,7 @@ class PanelMediaBrowser extends LitElement {
return [ return [
haStyle, haStyle,
css` css`
app-toolbar { ha-media-manage-button {
--mdc-theme-primary: var(--app-header-text-color); --mdc-theme-primary: var(--app-header-text-color);
} }

View File

@ -1,6 +1,4 @@
import "@material/mwc-button"; import "@material/mwc-button";
import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { UnsubscribeFunc } from "home-assistant-js-websocket";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
@ -14,7 +12,6 @@ import {
} from "../../data/frontend"; } from "../../data/frontend";
import { RefreshToken } from "../../data/refresh_token"; import { RefreshToken } from "../../data/refresh_token";
import { showConfirmationDialog } from "../../dialogs/generic/show-dialog-box"; import { showConfirmationDialog } from "../../dialogs/generic/show-dialog-box";
import "../../layouts/ha-app-layout";
import { haStyle } from "../../resources/styles"; import { haStyle } from "../../resources/styles";
import { HomeAssistant } from "../../types"; import { HomeAssistant } from "../../types";
import "./ha-advanced-mode-row"; import "./ha-advanced-mode-row";
@ -33,6 +30,7 @@ import "./ha-push-notifications-row";
import "./ha-refresh-tokens-card"; import "./ha-refresh-tokens-card";
import "./ha-set-suspend-row"; import "./ha-set-suspend-row";
import "./ha-set-vibrate-row"; import "./ha-set-vibrate-row";
import "../../components/ha-top-app-bar-fixed";
@customElement("ha-panel-profile") @customElement("ha-panel-profile")
class HaPanelProfile extends LitElement { class HaPanelProfile extends LitElement {
@ -67,16 +65,13 @@ class HaPanelProfile extends LitElement {
protected render(): TemplateResult { protected render(): TemplateResult {
return html` return html`
<ha-app-layout> <ha-top-app-bar-fixed>
<app-header slot="header" fixed> <ha-menu-button
<app-toolbar> slot="navigationIcon"
<ha-menu-button .hass=${this.hass}
.hass=${this.hass} .narrow=${this.narrow}
.narrow=${this.narrow} ></ha-menu-button>
></ha-menu-button> <div slot="title">${this.hass.localize("panel.profile")}</div>
<div main-title>${this.hass.localize("panel.profile")}</div>
</app-toolbar>
</app-header>
<div class="content"> <div class="content">
<ha-card .header=${this.hass.user!.name}> <ha-card .header=${this.hass.user!.name}>
@ -205,7 +200,7 @@ class HaPanelProfile extends LitElement {
@hass-refresh-tokens=${this._refreshRefreshTokens} @hass-refresh-tokens=${this._refreshRefreshTokens}
></ha-long-lived-access-tokens-card> ></ha-long-lived-access-tokens-card>
</div> </div>
</ha-app-layout> </ha-top-app-bar-fixed>
`; `;
} }

View File

@ -1,6 +1,4 @@
import { mdiMicrophone } from "@mdi/js"; import { mdiMicrophone } from "@mdi/js";
import "@polymer/app-layout/app-header/app-header";
import "@polymer/app-layout/app-toolbar/app-toolbar";
import { import {
css, css,
CSSResultGroup, CSSResultGroup,
@ -14,8 +12,8 @@ import memoizeOne from "memoize-one";
import { isComponentLoaded } from "../../common/config/is_component_loaded"; import { isComponentLoaded } from "../../common/config/is_component_loaded";
import "../../components/ha-icon-button"; import "../../components/ha-icon-button";
import "../../components/ha-menu-button"; import "../../components/ha-menu-button";
import "../../components/ha-top-app-bar-fixed";
import { showVoiceCommandDialog } from "../../dialogs/voice-command-dialog/show-ha-voice-command-dialog"; import { showVoiceCommandDialog } from "../../dialogs/voice-command-dialog/show-ha-voice-command-dialog";
import "../../layouts/ha-app-layout";
import { haStyle } from "../../resources/styles"; import { haStyle } from "../../resources/styles";
import { HomeAssistant } from "../../types"; import { HomeAssistant } from "../../types";
import { HuiErrorCard } from "../lovelace/cards/hui-error-card"; import { HuiErrorCard } from "../lovelace/cards/hui-error-card";
@ -51,31 +49,29 @@ class PanelShoppingList extends LitElement {
protected render(): TemplateResult { protected render(): TemplateResult {
return html` return html`
<ha-app-layout> <ha-top-app-bar-fixed>
<app-header fixed slot="header"> <ha-menu-button
<app-toolbar> slot="navigationIcon"
<ha-menu-button .hass=${this.hass}
.hass=${this.hass} .narrow=${this.narrow}
.narrow=${this.narrow} ></ha-menu-button>
></ha-menu-button> <div slot="title">${this.hass.localize("panel.shopping_list")}</div>
<div main-title>${this.hass.localize("panel.shopping_list")}</div> ${this._conversation(this.hass.config.components)
${this._conversation(this.hass.config.components) ? html`
? html` <ha-icon-button
<ha-icon-button slot="actionItems"
.label=${this.hass!.localize( .label=${this.hass!.localize(
"ui.panel.shopping_list.start_conversation" "ui.panel.shopping_list.start_conversation"
)} )}
.path=${mdiMicrophone} .path=${mdiMicrophone}
@click=${this._showVoiceCommandDialog} @click=${this._showVoiceCommandDialog}
></ha-icon-button> ></ha-icon-button>
` `
: ""} : ""}
</app-toolbar>
</app-header>
<div id="columns"> <div id="columns">
<div class="column">${this._card}</div> <div class="column">${this._card}</div>
</div> </div>
</ha-app-layout> </ha-top-app-bar-fixed>
`; `;
} }
@ -87,21 +83,6 @@ class PanelShoppingList extends LitElement {
return [ return [
haStyle, haStyle,
css` css`
:host {
display: block;
height: 100%;
}
app-header {
--mdc-theme-primary: var(--app-header-text-color);
}
:host([narrow]) app-toolbar mwc-button {
width: 65px;
}
.heading {
overflow: hidden;
white-space: nowrap;
margin-top: 4px;
}
#columns { #columns {
display: flex; display: flex;
flex-direction: row; flex-direction: row;

View File

@ -175,24 +175,6 @@ export const haStyle = css`
line-height: var(--paper-font-body1_-_line-height); line-height: var(--paper-font-body1_-_line-height);
} }
app-header-layout,
ha-app-layout {
background-color: var(--primary-background-color);
}
app-header,
app-toolbar {
background-color: var(--app-header-background-color);
font-weight: 400;
color: var(--app-header-text-color, white);
}
app-toolbar {
height: var(--header-height);
border-bottom: var(--app-header-border-bottom);
box-sizing: border-box;
}
app-header div[sticky] { app-header div[sticky] {
height: 48px; height: 48px;
} }

View File

@ -2732,7 +2732,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@material/mwc-top-app-bar@npm:^0.27.0": "@material/mwc-top-app-bar@npm:0.27.0, @material/mwc-top-app-bar@npm:^0.27.0":
version: 0.27.0 version: 0.27.0
resolution: "@material/mwc-top-app-bar@npm:0.27.0" resolution: "@material/mwc-top-app-bar@npm:0.27.0"
dependencies: dependencies:
@ -9451,6 +9451,7 @@ __metadata:
"@material/mwc-tab-bar": 0.27.0 "@material/mwc-tab-bar": 0.27.0
"@material/mwc-textarea": 0.27.0 "@material/mwc-textarea": 0.27.0
"@material/mwc-textfield": 0.27.0 "@material/mwc-textfield": 0.27.0
"@material/mwc-top-app-bar": 0.27.0
"@material/mwc-top-app-bar-fixed": 0.27.0 "@material/mwc-top-app-bar-fixed": 0.27.0
"@material/top-app-bar": =14.0.0-canary.53b3cad2f.0 "@material/top-app-bar": =14.0.0-canary.53b3cad2f.0
"@material/web": =1.0.0-pre.4 "@material/web": =1.0.0-pre.4