mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-27 11:16:35 +00:00
Sidebar improvements (#3325)
* Do not contract sidebar when undocking sidebar * Do not hide text until fully contracted * Cancel hover expanding on tablets * Open notifications on the left * Set property before opening * Fix check for support scroll if needed
This commit is contained in:
parent
8c1aff7505
commit
d7371ace6a
@ -116,10 +116,13 @@ class HaSidebar extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Boolean }) public alwaysExpand = false;
|
@property({ type: Boolean }) public alwaysExpand = false;
|
||||||
@property({ type: Boolean, reflect: true }) public expanded = false;
|
@property({ type: Boolean, reflect: true }) public expanded = false;
|
||||||
|
@property({ type: Boolean, reflect: true }) public expandedWidth = false;
|
||||||
@property() public _defaultPage?: string =
|
@property() public _defaultPage?: string =
|
||||||
localStorage.defaultPage || DEFAULT_PANEL;
|
localStorage.defaultPage || DEFAULT_PANEL;
|
||||||
@property() private _externalConfig?: ExternalConfig;
|
@property() private _externalConfig?: ExternalConfig;
|
||||||
@property() private _notifications?: PersistentNotification[];
|
@property() private _notifications?: PersistentNotification[];
|
||||||
|
private _expandTimeout?: number;
|
||||||
|
private _contractTimeout?: number;
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
const hass = this.hass;
|
const hass = this.hass;
|
||||||
@ -239,6 +242,7 @@ class HaSidebar extends LitElement {
|
|||||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||||
if (
|
if (
|
||||||
changedProps.has("expanded") ||
|
changedProps.has("expanded") ||
|
||||||
|
changedProps.has("expandedWidth") ||
|
||||||
changedProps.has("narrow") ||
|
changedProps.has("narrow") ||
|
||||||
changedProps.has("alwaysExpand") ||
|
changedProps.has("alwaysExpand") ||
|
||||||
changedProps.has("_externalConfig") ||
|
changedProps.has("_externalConfig") ||
|
||||||
@ -271,8 +275,17 @@ class HaSidebar extends LitElement {
|
|||||||
this._externalConfig = conf;
|
this._externalConfig = conf;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// On tablets, there is no hover. So we receive click and mouseenter at the
|
||||||
|
// same time. In that case, we're going to cancel expanding, because it is
|
||||||
|
// going to require another tap outside the sidebar to trigger mouseleave
|
||||||
|
this.addEventListener("click", () => {
|
||||||
|
if (this._expandTimeout) {
|
||||||
|
clearTimeout(this._expandTimeout);
|
||||||
|
this._expandTimeout = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
this.addEventListener("mouseenter", () => {
|
this.addEventListener("mouseenter", () => {
|
||||||
this.expanded = true;
|
this._expand();
|
||||||
});
|
});
|
||||||
this.addEventListener("mouseleave", () => {
|
this.addEventListener("mouseleave", () => {
|
||||||
this._contract();
|
this._contract();
|
||||||
@ -284,10 +297,11 @@ class HaSidebar extends LitElement {
|
|||||||
|
|
||||||
protected updated(changedProps) {
|
protected updated(changedProps) {
|
||||||
super.updated(changedProps);
|
super.updated(changedProps);
|
||||||
if (changedProps.has("alwaysExpand")) {
|
if (changedProps.has("alwaysExpand") && this.alwaysExpand) {
|
||||||
this.expanded = this.alwaysExpand;
|
this.expanded = true;
|
||||||
|
this.expandedWidth = true;
|
||||||
}
|
}
|
||||||
if (SUPPORT_SCROLL_IF_NEEDED || !changedProps.has("hass")) {
|
if (!SUPPORT_SCROLL_IF_NEEDED || !changedProps.has("hass")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||||
@ -299,8 +313,31 @@ class HaSidebar extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _expand() {
|
||||||
|
// We debounce it one frame, because on tablets, the mouse-enter and
|
||||||
|
// click event fire at the same time.
|
||||||
|
this._expandTimeout = window.setTimeout(() => {
|
||||||
|
this.expanded = true;
|
||||||
|
this.expandedWidth = true;
|
||||||
|
}, 0);
|
||||||
|
if (this._contractTimeout) {
|
||||||
|
clearTimeout(this._contractTimeout);
|
||||||
|
this._contractTimeout = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private _contract() {
|
private _contract() {
|
||||||
this.expanded = this.alwaysExpand || false;
|
if (this._expandTimeout) {
|
||||||
|
clearTimeout(this._expandTimeout);
|
||||||
|
this._expandTimeout = undefined;
|
||||||
|
}
|
||||||
|
if (this.alwaysExpand) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.expandedWidth = false;
|
||||||
|
this._contractTimeout = window.setTimeout(() => {
|
||||||
|
this.expanded = this.alwaysExpand || false;
|
||||||
|
}, 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleShowNotificationDrawer() {
|
private _handleShowNotificationDrawer() {
|
||||||
@ -338,7 +375,7 @@ class HaSidebar extends LitElement {
|
|||||||
contain: strict;
|
contain: strict;
|
||||||
transition-delay: 0.2s;
|
transition-delay: 0.2s;
|
||||||
}
|
}
|
||||||
:host([expanded]) {
|
:host([expandedwidth]) {
|
||||||
width: 256px;
|
width: 256px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import "@polymer/app-layout/app-drawer/app-drawer";
|
||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import "@polymer/paper-icon-button/paper-icon-button";
|
import "@polymer/paper-icon-button/paper-icon-button";
|
||||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||||
@ -6,11 +7,10 @@ import { html } from "@polymer/polymer/lib/utils/html-tag";
|
|||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
|
||||||
import "./notification-item";
|
import "./notification-item";
|
||||||
import "../../components/ha-paper-icon-button-next";
|
import "../../components/ha-paper-icon-button-prev";
|
||||||
|
|
||||||
import { EventsMixin } from "../../mixins/events-mixin";
|
import { EventsMixin } from "../../mixins/events-mixin";
|
||||||
import LocalizeMixin from "../../mixins/localize-mixin";
|
import LocalizeMixin from "../../mixins/localize-mixin";
|
||||||
import { computeRTL } from "../../common/util/compute_rtl";
|
|
||||||
import { subscribeNotifications } from "../../data/persistent_notification";
|
import { subscribeNotifications } from "../../data/persistent_notification";
|
||||||
import computeDomain from "../../common/entity/compute_domain";
|
import computeDomain from "../../common/entity/compute_domain";
|
||||||
/*
|
/*
|
||||||
@ -23,86 +23,12 @@ export class HuiNotificationDrawer extends EventsMixin(
|
|||||||
static get template() {
|
static get template() {
|
||||||
return html`
|
return html`
|
||||||
<style include="paper-material-styles">
|
<style include="paper-material-styles">
|
||||||
:host {
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([hidden]) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
align-items: stretch;
|
|
||||||
background: var(--sidebar-background-color, var(--primary-background-color));
|
|
||||||
bottom: 0;
|
|
||||||
box-shadow: var(--paper-material-elevation-1_-_box-shadow);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow-y: hidden;
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
transition: right .2s ease-in;
|
|
||||||
width: 500px;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([rtl]) .container {
|
|
||||||
transition: left .2s ease-in !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host(:not(narrow)) .container {
|
|
||||||
right: -500px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([rtl]:not(narrow)) .container {
|
|
||||||
left: -500px;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([narrow]) .container {
|
|
||||||
right: -100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([rtl][narrow]) .container {
|
|
||||||
left: -100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host(.open) .container,
|
|
||||||
:host(.open[narrow]) .container {
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([rtl].open) .container,
|
|
||||||
:host([rtl].open[narrow]) .container {
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
app-toolbar {
|
app-toolbar {
|
||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
border-bottom: 1px solid var(--divider-color);
|
border-bottom: 1px solid var(--divider-color);
|
||||||
background-color: var(--primary-background-color);
|
background-color: var(--primary-background-color);
|
||||||
min-height: 64px;
|
min-height: 64px;
|
||||||
width: calc(100% - 32px);
|
width: calc(100% - 32px);
|
||||||
z-index: 11;
|
|
||||||
}
|
|
||||||
|
|
||||||
.overlay {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host(.open) .overlay {
|
|
||||||
bottom: 0;
|
|
||||||
display: block;
|
|
||||||
left: 0;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
z-index: 5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.notifications {
|
.notifications {
|
||||||
@ -119,11 +45,10 @@ export class HuiNotificationDrawer extends EventsMixin(
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="overlay" on-click="_closeDrawer"></div>
|
<app-drawer id='drawer' opened="{{open}}">
|
||||||
<div class="container">
|
|
||||||
<app-toolbar>
|
<app-toolbar>
|
||||||
<div main-title>[[localize('ui.notification_drawer.title')]]</div>
|
<div main-title>[[localize('ui.notification_drawer.title')]]</div>
|
||||||
<ha-paper-icon-button-next on-click="_closeDrawer"></paper-icon-button>
|
<ha-paper-icon-button-prev on-click="_closeDrawer"></paper-icon-button>
|
||||||
</app-toolbar>
|
</app-toolbar>
|
||||||
<div class="notifications">
|
<div class="notifications">
|
||||||
<template is="dom-if" if="[[!_empty(notifications)]]">
|
<template is="dom-if" if="[[!_empty(notifications)]]">
|
||||||
@ -139,27 +64,17 @@ export class HuiNotificationDrawer extends EventsMixin(
|
|||||||
<div class="empty">[[localize('ui.notification_drawer.empty')]]<div>
|
<div class="empty">[[localize('ui.notification_drawer.empty')]]<div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</app-drawer>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
hass: Object,
|
hass: Object,
|
||||||
narrow: {
|
|
||||||
type: Boolean,
|
|
||||||
reflectToAttribute: true,
|
|
||||||
},
|
|
||||||
open: {
|
open: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
notify: true,
|
|
||||||
observer: "_openChanged",
|
observer: "_openChanged",
|
||||||
},
|
},
|
||||||
hidden: {
|
|
||||||
type: Boolean,
|
|
||||||
value: true,
|
|
||||||
reflectToAttribute: true,
|
|
||||||
},
|
|
||||||
notifications: {
|
notifications: {
|
||||||
type: Array,
|
type: Array,
|
||||||
computed: "_computeNotifications(open, hass, _notificationsBackend)",
|
computed: "_computeNotifications(open, hass, _notificationsBackend)",
|
||||||
@ -168,11 +83,6 @@ export class HuiNotificationDrawer extends EventsMixin(
|
|||||||
type: Array,
|
type: Array,
|
||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
rtl: {
|
|
||||||
type: Boolean,
|
|
||||||
reflectToAttribute: true,
|
|
||||||
computed: "_computeRTL(hass)",
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,36 +106,20 @@ export class HuiNotificationDrawer extends EventsMixin(
|
|||||||
}
|
}
|
||||||
|
|
||||||
_openChanged(open) {
|
_openChanged(open) {
|
||||||
clearTimeout(this._openTimer);
|
|
||||||
if (open) {
|
if (open) {
|
||||||
// Render closed then animate open
|
// Render closed then animate open
|
||||||
this.hidden = false;
|
|
||||||
this._openTimer = setTimeout(() => {
|
|
||||||
this.classList.add("open");
|
|
||||||
}, 50);
|
|
||||||
this._unsubNotifications = subscribeNotifications(
|
this._unsubNotifications = subscribeNotifications(
|
||||||
this.hass.connection,
|
this.hass.connection,
|
||||||
(notifications) => {
|
(notifications) => {
|
||||||
this._notificationsBackend = notifications;
|
this._notificationsBackend = notifications;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
} else if (this._unsubNotifications) {
|
||||||
// Animate closed then hide
|
this._unsubNotifications();
|
||||||
this.classList.remove("open");
|
this._unsubNotifications = undefined;
|
||||||
this._openTimer = setTimeout(() => {
|
|
||||||
this.hidden = true;
|
|
||||||
}, 250);
|
|
||||||
if (this._unsubNotifications) {
|
|
||||||
this._unsubNotifications();
|
|
||||||
this._unsubNotifications = undefined;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_computeRTL(hass) {
|
|
||||||
return computeRTL(hass);
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeNotifications(open, hass, notificationsBackend) {
|
_computeNotifications(open, hass, notificationsBackend) {
|
||||||
if (!open) {
|
if (!open) {
|
||||||
return [];
|
return [];
|
||||||
@ -239,8 +133,11 @@ export class HuiNotificationDrawer extends EventsMixin(
|
|||||||
}
|
}
|
||||||
|
|
||||||
showDialog({ narrow }) {
|
showDialog({ narrow }) {
|
||||||
this.open = true;
|
this.style.setProperty(
|
||||||
this.narrow = narrow;
|
"--app-drawer-width",
|
||||||
|
narrow ? window.innerWidth + "px" : "500px"
|
||||||
|
);
|
||||||
|
this.$.drawer.open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
customElements.define("notification-drawer", HuiNotificationDrawer);
|
customElements.define("notification-drawer", HuiNotificationDrawer);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user