From 89630a5c7f96163b4d6b2c077927963bffd0d55b Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 27 Jan 2019 23:23:07 -0800 Subject: [PATCH] Convert ha-sidebar to TS/Lit --- src/components/ha-sidebar.js | 341 -------------------------- src/components/ha-sidebar.ts | 379 +++++++++++++++++++++++++++++ src/layouts/home-assistant-main.js | 1 - src/polymer-types.ts | 1 + 4 files changed, 380 insertions(+), 342 deletions(-) delete mode 100644 src/components/ha-sidebar.js create mode 100644 src/components/ha-sidebar.ts diff --git a/src/components/ha-sidebar.js b/src/components/ha-sidebar.js deleted file mode 100644 index a3d87db4c7..0000000000 --- a/src/components/ha-sidebar.js +++ /dev/null @@ -1,341 +0,0 @@ -import "@polymer/app-layout/app-toolbar/app-toolbar"; -import "@polymer/iron-flex-layout/iron-flex-layout-classes"; -import "@polymer/paper-icon-button/paper-icon-button"; -import "@polymer/paper-item/paper-icon-item"; -import "@polymer/paper-item/paper-item"; -import "@polymer/paper-listbox/paper-listbox"; -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; -import "./ha-icon"; - -import "../util/hass-translation"; -import LocalizeMixin from "../mixins/localize-mixin"; -import isComponentLoaded from "../common/config/is_component_loaded"; - -/* - * @appliesMixin LocalizeMixin - */ -class HaSidebar extends LocalizeMixin(PolymerElement) { - static get template() { - return html` - - - -
Home Assistant
- -
- - - - - - [[localize('panel.states')]] - - - - - - - - -
-
- -
[[localize('ui.sidebar.developer_tools')]]
- - -
-`; - } - - static get properties() { - return { - hass: { - type: Object, - }, - menuShown: { - type: Boolean, - }, - menuSelected: { - type: String, - }, - narrow: Boolean, - panels: { - type: Array, - computed: "computePanels(hass)", - }, - defaultPage: String, - _initials: { - type: String, - computed: "_computeUserInitials(hass.user.name)", - }, - }; - } - - _computeUserInitials(name) { - if (!name) return "user"; - return ( - name - .trim() - // Split by space and take first 3 words - .split(" ") - .slice(0, 3) - // Of each word, take first letter - .map((s) => s.substr(0, 1)) - .join("") - ); - } - - _computeBadgeClass(initials) { - return `profile-badge ${initials.length > 2 ? "long" : ""}`; - } - - _mqttLoaded(hass) { - return isComponentLoaded(hass, "mqtt"); - } - - _computeUserName(user) { - return user && (user.name || "Unnamed User"); - } - - _computePanelName(localize, panel) { - return localize(`panel.${panel.title}`) || panel.title; - } - - computePanels(hass) { - var panels = hass.panels; - var sortValue = { - map: 1, - logbook: 2, - history: 3, - }; - var result = []; - - Object.keys(panels).forEach(function(key) { - if (panels[key].title) { - result.push(panels[key]); - } - }); - - result.sort(function(a, b) { - var aBuiltIn = a.component_name in sortValue; - var bBuiltIn = b.component_name in sortValue; - - if (aBuiltIn && bBuiltIn) { - return sortValue[a.component_name] - sortValue[b.component_name]; - } - if (aBuiltIn) { - return -1; - } - if (bBuiltIn) { - return 1; - } - // both not built in, sort by title - if (a.title < b.title) { - return -1; - } - if (a.title > b.title) { - return 1; - } - return 0; - }); - - return result; - } - - _computeUrl(urlPath) { - return `/${urlPath}`; - } - - _handleLogOut() { - this.fire("hass-logout"); - } -} - -customElements.define("ha-sidebar", HaSidebar); diff --git a/src/components/ha-sidebar.ts b/src/components/ha-sidebar.ts new file mode 100644 index 0000000000..202576d044 --- /dev/null +++ b/src/components/ha-sidebar.ts @@ -0,0 +1,379 @@ +import { + LitElement, + html, + CSSResult, + css, + PropertyDeclarations, + PropertyValues, +} from "lit-element"; +import { classMap } from "lit-html/directives/class-map"; +import "@polymer/app-layout/app-toolbar/app-toolbar"; +import "@polymer/paper-icon-button/paper-icon-button"; +import "@polymer/paper-item/paper-icon-item"; +import "@polymer/paper-item/paper-item"; +import "@polymer/paper-listbox/paper-listbox"; +import "./ha-icon"; + +import isComponentLoaded from "../common/config/is_component_loaded"; +import { HomeAssistant, Panel } from "../types"; +import { fireEvent } from "../common/dom/fire_event"; + +const computeInitials = (name: string) => { + if (!name) { + return "user"; + } + return ( + name + .trim() + // Split by space and take first 3 words + .split(" ") + .slice(0, 3) + // Of each word, take first letter + .map((s) => s.substr(0, 1)) + .join("") + ); +}; + +const computeUrl = (urlPath) => `/${urlPath}`; + +const computePanels = (hass: HomeAssistant) => { + const panels = hass.panels; + const sortValue = { + map: 1, + logbook: 2, + history: 3, + }; + const result: Panel[] = []; + + Object.keys(panels).forEach((key) => { + if (panels[key].title) { + result.push(panels[key]); + } + }); + + result.sort((a, b) => { + const aBuiltIn = a.component_name in sortValue; + const bBuiltIn = b.component_name in sortValue; + + if (aBuiltIn && bBuiltIn) { + return sortValue[a.component_name] - sortValue[b.component_name]; + } + if (aBuiltIn) { + return -1; + } + if (bBuiltIn) { + return 1; + } + // both not built in, sort by title + if (a.title! < b.title!) { + return -1; + } + if (a.title! > b.title!) { + return 1; + } + return 0; + }); + + return result; +}; + +/* + * @appliesMixin LocalizeMixin + */ +class HaSidebar extends LitElement { + public hass?: HomeAssistant; + public defaultPage?: string; + + protected render() { + const hass = this.hass; + + if (!hass) { + return html``; + } + + const initials = hass.user ? computeInitials(hass.user.name) : ""; + + return html` + +
Home Assistant
+ ${hass.user + ? html` + 2, + })}" + > + + ${initials} + + ` + : ""} +
+ + + + + + ${hass.localize("panel.states")} + + + + ${computePanels(hass).map( + (panel) => html` + + + + ${hass.localize(`panel.${panel.title}`) || panel.title} + + + ` + )} + ${!hass.user + ? html` + + + ${hass.localize("ui.sidebar.log_out")} + + ` + : html``} + + +
+
+ +
+ ${hass.localize("ui.sidebar.developer_tools")} +
+ +
+ + + + + + + + + + + + + ${isComponentLoaded(hass, "mqtt") + ? html` + + + + ` + : html``} + + + +
+
+ `; + } + + static get properties(): PropertyDeclarations { + return { + hass: {}, + defaultPage: {}, + }; + } + + protected shouldUpdate(changedProps: PropertyValues): boolean { + if (!this.hass || !changedProps.has("hass")) { + return false; + } + const oldHass = changedProps.get("hass") as HomeAssistant; + if (!oldHass) { + return true; + } + const hass = this.hass; + return ( + hass.panels !== oldHass.panels || + hass.panelUrl !== oldHass.panelUrl || + hass.config.components !== oldHass.config.components || + hass.user !== oldHass.user || + hass.localize !== oldHass.localize + ); + } + + private _handleLogOut() { + fireEvent(this, "hass-logout"); + } + + static get styles(): CSSResult { + return css` + :host { + height: 100%; + display: block; + overflow: auto; + -ms-user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + border-right: 1px solid var(--divider-color); + background-color: var( + --sidebar-background-color, + var(--primary-background-color) + ); + } + + app-toolbar { + font-weight: 400; + color: var(--primary-text-color); + border-bottom: 1px solid var(--divider-color); + background-color: var(--primary-background-color); + } + + app-toolbar a { + color: var(--primary-text-color); + } + + paper-listbox { + padding: 0; + } + + paper-listbox > a { + color: var(--sidebar-text-color); + font-weight: 500; + font-size: 14px; + text-decoration: none; + } + + paper-icon-item { + margin: 8px; + padding-left: 9px; + border-radius: 4px; + --paper-item-min-height: 40px; + } + + a ha-icon { + color: var(--sidebar-icon-color); + } + + .iron-selected paper-icon-item:before { + border-radius: 4px; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + pointer-events: none; + content: ""; + background-color: var(--sidebar-selected-icon-color); + opacity: 0.12; + transition: opacity 15ms linear; + will-change: opacity; + } + + .iron-selected paper-icon-item[pressed]:before { + opacity: 0.37; + } + + paper-icon-item span { + color: var(--sidebar-text-color); + font-weight: 500; + font-size: 14px; + } + + a.iron-selected paper-icon-item ha-icon { + color: var(--sidebar-selected-icon-color); + } + + a.iron-selected .item-text { + color: var(--sidebar-selected-text-color); + } + + paper-icon-item.logout { + margin-top: 16px; + } + + .divider { + height: 1px; + background-color: var(--divider-color); + margin: 4px 0; + } + + .subheader { + color: var(--sidebar-text-color); + font-weight: 500; + font-size: 14px; + padding: 16px; + } + + .dev-tools { + display: flex; + flex-direction: row; + justify-content: space-between; + padding: 0 8px; + } + + .dev-tools a { + color: var(--sidebar-icon-color); + } + + .profile-badge { + /* for ripple */ + position: relative; + box-sizing: border-box; + width: 40px; + line-height: 40px; + border-radius: 50%; + text-align: center; + background-color: var(--light-primary-color); + text-decoration: none; + color: var(--primary-text-color); + } + + .profile-badge.long { + font-size: 80%; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-sidebar": HaSidebar; + } +} + +customElements.define("ha-sidebar", HaSidebar); diff --git a/src/layouts/home-assistant-main.js b/src/layouts/home-assistant-main.js index 4f99bf5958..768b3968d8 100644 --- a/src/layouts/home-assistant-main.js +++ b/src/layouts/home-assistant-main.js @@ -61,7 +61,6 @@ class HomeAssistantMain extends NavigateMixin(EventsMixin(PolymerElement)) { persistent="[[dockedSidebar]]" > diff --git a/src/polymer-types.ts b/src/polymer-types.ts index 9ebb6e1bcf..693c2db105 100644 --- a/src/polymer-types.ts +++ b/src/polymer-types.ts @@ -4,6 +4,7 @@ export {}; declare global { // for fire event interface HASSDomEvents { + "hass-logout": undefined; "iron-resize": undefined; "config-refresh": undefined; "ha-refresh-cloud-status": undefined;