Sidebar iteration (#3392)

* Remove hover effect

* Reuse render panel func

* Show notification badge on the right in expanded mode
This commit is contained in:
Paulus Schoutsen 2019-07-19 15:51:37 -07:00 committed by GitHub
parent a7077dbcb4
commit 3d0c994b9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -31,8 +31,6 @@ import { classMap } from "lit-html/directives/class-map";
const SHOW_AFTER_SPACER = ["config", "developer-tools"]; const SHOW_AFTER_SPACER = ["config", "developer-tools"];
const computeUrl = (urlPath) => `/${urlPath}`;
const SUPPORT_SCROLL_IF_NEEDED = "scrollIntoViewIfNeeded" in document.body; const SUPPORT_SCROLL_IF_NEEDED = "scrollIntoViewIfNeeded" in document.body;
const SORT_VALUE = { const SORT_VALUE = {
@ -91,22 +89,6 @@ const computePanels = (hass: HomeAssistant): [PanelInfo[], PanelInfo[]] => {
return [beforeSpacer, afterSpacer]; return [beforeSpacer, afterSpacer];
}; };
const renderPanel = (hass, panel) => html`
<a
aria-role="option"
href="${computeUrl(panel.url_path)}"
data-panel="${panel.url_path}"
tabindex="-1"
>
<paper-icon-item>
<ha-icon slot="item-icon" .icon="${panel.icon}"></ha-icon>
<span class="item-text">
${hass.localize(`panel.${panel.title}`) || panel.title}
</span>
</paper-icon-item>
</a>
`;
/* /*
* @appliesMixin LocalizeMixin * @appliesMixin LocalizeMixin
*/ */
@ -116,13 +98,10 @@ 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;
@ -156,22 +135,27 @@ class HaSidebar extends LitElement {
<span class="title">Home Assistant</span> <span class="title">Home Assistant</span>
</div> </div>
<paper-listbox attr-for-selected="data-panel" .selected=${hass.panelUrl}> <paper-listbox attr-for-selected="data-panel" .selected=${hass.panelUrl}>
<a ${this._renderPanel(
aria-role="option" this._defaultPage,
href="${computeUrl(this._defaultPage)}" "hass:apps",
data-panel=${this._defaultPage} hass.localize("panel.states")
tabindex="-1" )}
> ${beforeSpacer.map((panel) =>
<paper-icon-item> this._renderPanel(
<ha-icon slot="item-icon" icon="hass:apps"></ha-icon> panel.url_path,
<span class="item-text">${hass.localize("panel.states")}</span> panel.icon,
</paper-icon-item> hass.localize(`panel.${panel.title}`) || panel.title
</a> )
)}
${beforeSpacer.map((panel) => renderPanel(hass, panel))}
<div class="spacer" disabled></div> <div class="spacer" disabled></div>
${afterSpacer.map((panel) => renderPanel(hass, panel))} ${afterSpacer.map((panel) =>
this._renderPanel(
panel.url_path,
panel.icon,
hass.localize(`panel.${panel.title}`) || panel.title
)
)}
${this._externalConfig && this._externalConfig.hasSettingsScreen ${this._externalConfig && this._externalConfig.hasSettingsScreen
? html` ? html`
<a <a
@ -203,7 +187,7 @@ class HaSidebar extends LitElement {
@click=${this._handleShowNotificationDrawer} @click=${this._handleShowNotificationDrawer}
> >
<ha-icon slot="item-icon" icon="hass:bell"></ha-icon> <ha-icon slot="item-icon" icon="hass:bell"></ha-icon>
${notificationCount > 0 ${!this.expanded && notificationCount > 0
? html` ? html`
<span class="notification-badge" slot="item-icon"> <span class="notification-badge" slot="item-icon">
${notificationCount} ${notificationCount}
@ -213,6 +197,11 @@ class HaSidebar extends LitElement {
<span class="item-text"> <span class="item-text">
${hass.localize("ui.notification_drawer.title")} ${hass.localize("ui.notification_drawer.title")}
</span> </span>
${this.expanded
? html`
<span class="notification-badge">${notificationCount}</span>
`
: ""}
</paper-icon-item> </paper-icon-item>
<a <a
@ -242,7 +231,6 @@ 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") ||
@ -275,21 +263,6 @@ 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._expand();
});
this.addEventListener("mouseleave", () => {
this._contract();
});
subscribeNotifications(this.hass.connection, (notifications) => { subscribeNotifications(this.hass.connection, (notifications) => {
this._notifications = notifications; this._notifications = notifications;
}); });
@ -297,9 +270,8 @@ class HaSidebar extends LitElement {
protected updated(changedProps) { protected updated(changedProps) {
super.updated(changedProps); super.updated(changedProps);
if (changedProps.has("alwaysExpand") && this.alwaysExpand) { if (changedProps.has("alwaysExpand")) {
this.expanded = true; this.expanded = this.alwaysExpand;
this.expandedWidth = true;
} }
if (!SUPPORT_SCROLL_IF_NEEDED || !changedProps.has("hass")) { if (!SUPPORT_SCROLL_IF_NEEDED || !changedProps.has("hass")) {
return; return;
@ -314,33 +286,6 @@ 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() {
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() {
fireEvent(this, "hass-show-notifications"); fireEvent(this, "hass-show-notifications");
} }
@ -356,6 +301,22 @@ class HaSidebar extends LitElement {
fireEvent(this, "hass-toggle-menu"); fireEvent(this, "hass-toggle-menu");
} }
private _renderPanel(urlPath, icon, title) {
return html`
<a
aria-role="option"
href="${`/${urlPath}`}"
data-panel="${urlPath}"
tabindex="-1"
>
<paper-icon-item>
<ha-icon slot="item-icon" .icon="${icon}"></ha-icon>
<span class="item-text">${title}</span>
</paper-icon-item>
</a>
`;
}
static get styles(): CSSResult { static get styles(): CSSResult {
return css` return css`
:host { :host {
@ -371,12 +332,8 @@ class HaSidebar extends LitElement {
var(--primary-background-color) var(--primary-background-color)
); );
width: 64px; width: 64px;
transition: width 0.2s ease-in;
will-change: width;
contain: strict;
transition-delay: 0.2s;
} }
:host([expandedwidth]) { :host([expanded]) {
width: 256px; width: 256px;
} }
@ -512,6 +469,9 @@ class HaSidebar extends LitElement {
.notifications { .notifications {
cursor: pointer; cursor: pointer;
} }
.notifications .item-text {
flex: 1;
}
.profile { .profile {
} }
.profile paper-icon-item { .profile paper-icon-item {
@ -522,19 +482,22 @@ class HaSidebar extends LitElement {
} }
.notification-badge { .notification-badge {
position: absolute; min-width: 20px;
font-weight: 400; box-sizing: border-box;
bottom: 14px;
left: 26px;
border-radius: 50%; border-radius: 50%;
font-weight: 400;
background-color: var(--primary-color); background-color: var(--primary-color);
height: 20px;
line-height: 20px; line-height: 20px;
text-align: center; text-align: center;
padding: 0px 6px; padding: 0px 6px;
font-size: 0.65em;
color: var(--text-primary-color); color: var(--text-primary-color);
} }
ha-icon + .notification-badge {
position: absolute;
bottom: 14px;
left: 26px;
font-size: 0.65em;
}
.spacer { .spacer {
flex: 1; flex: 1;