diff --git a/src/common/entity/domain_icon.ts b/src/common/entity/domain_icon.ts index 0bb2535a77..9d36310a2e 100644 --- a/src/common/entity/domain_icon.ts +++ b/src/common/entity/domain_icon.ts @@ -8,7 +8,7 @@ import { DEFAULT_DOMAIN_ICON } from "../const"; const fixedIcons = { alert: "hass:alert", alexa: "hass:amazon-alexa", - automation: "hass:playlist-play", + automation: "hass:robot", calendar: "hass:calendar", camera: "hass:video", climate: "hass:thermostat", @@ -36,8 +36,8 @@ const fixedIcons = { plant: "hass:flower", proximity: "hass:apple-safari", remote: "hass:remote", - scene: "hass:google-pages", - script: "hass:file-document", + scene: "hass:palette", + script: "hass:script-text", sensor: "hass:eye", simple_alarm: "hass:bell", sun: "hass:white-balance-sunny", @@ -48,7 +48,7 @@ const fixedIcons = { water_heater: "hass:thermometer", weather: "hass:weather-cloudy", weblink: "hass:open-in-new", - zone: "hass:map-marker", + zone: "hass:map-marker-radius", }; export const domainIcon = (domain: string, state?: string): string => { diff --git a/src/components/ha-menu-button.ts b/src/components/ha-menu-button.ts index 1086ca8c87..7f64e34432 100644 --- a/src/components/ha-menu-button.ts +++ b/src/components/ha-menu-button.ts @@ -135,7 +135,7 @@ class HaMenuButton extends LitElement { top: 5px; right: 2px; border-radius: 50%; - border: 2px solid var(--primary-color); + border: 2px solid var(--app-header-background-color); } `; } diff --git a/src/layouts/hass-loading-screen.ts b/src/layouts/hass-loading-screen.ts index c75db2dfe9..e0670fa4ee 100644 --- a/src/layouts/hass-loading-screen.ts +++ b/src/layouts/hass-loading-screen.ts @@ -50,6 +50,11 @@ class HassLoadingScreen extends LitElement { return [ haStyle, css` + :host { + display: block; + height: 100%; + background-color: var(--primary-background-color); + } .content { height: calc(100% - 64px); display: flex; diff --git a/src/layouts/hass-subpage.ts b/src/layouts/hass-subpage.ts index 34ad70f212..39c539d7ee 100644 --- a/src/layouts/hass-subpage.ts +++ b/src/layouts/hass-subpage.ts @@ -59,6 +59,7 @@ class HassSubpage extends LitElement { background-color: var(--app-header-background-color); font-weight: 400; color: var(--app-header-text-color, white); + border-bottom: var(--app-header-border-bottom, none); } ha-menu-button, diff --git a/src/layouts/hass-tabs-subpage.ts b/src/layouts/hass-tabs-subpage.ts new file mode 100644 index 0000000000..4a51d61785 --- /dev/null +++ b/src/layouts/hass-tabs-subpage.ts @@ -0,0 +1,239 @@ +import { + LitElement, + property, + TemplateResult, + html, + customElement, + css, + CSSResult, + PropertyValues, +} from "lit-element"; +import "../components/ha-menu-button"; +import "../components/ha-paper-icon-button-arrow-prev"; +import { classMap } from "lit-html/directives/class-map"; +import { Route, HomeAssistant } from "../types"; +import { navigate } from "../common/navigate"; +import "@material/mwc-ripple"; +import { isComponentLoaded } from "../common/config/is_component_loaded"; + +export interface PageNavigation { + path: string; + translationKey?: string; + component?: string; + name?: string; + core?: boolean; + exportOnly?: boolean; + icon?: string; + info?: any; +} + +@customElement("hass-tabs-subpage") +class HassTabsSubpage extends LitElement { + @property() public hass!: HomeAssistant; + @property({ type: String, attribute: "back-path" }) public backPath?: string; + @property() public backCallback?: () => void; + @property({ type: Boolean }) public hassio = false; + @property({ type: Boolean }) public showAdvanced = false; + @property() public route!: Route; + @property() public tabs!: PageNavigation[]; + @property({ type: Boolean, reflect: true }) public narrow = false; + @property() private _activeTab: number = -1; + + protected updated(changedProperties: PropertyValues) { + super.updated(changedProperties); + if (changedProperties.has("route")) { + this._activeTab = this.tabs.findIndex((tab) => + this.route.prefix.includes(tab.path) + ); + } + } + + protected render(): TemplateResult { + return html` +
+ +
+ ${this.tabs.map((page, index) => + (!page.component || + page.core || + isComponentLoaded(this.hass, page.component)) && + (!page.exportOnly || this.showAdvanced) + ? html` +
+ ${this.narrow + ? html` + + ` + : ""} + ${!this.narrow || index === this._activeTab + ? html` + ${page.translationKey + ? this.hass.localize(page.translationKey) + : name} + ` + : ""} + +
+ ` + : "" + )} +
+ +
+ +
+
+
+ +
+ `; + } + + private _tabTapped(ev: MouseEvent): void { + navigate(this, (ev.currentTarget as any).path, true); + } + + private _backTapped(): void { + if (this.backPath) { + navigate(this, this.backPath); + return; + } + if (this.backCallback) { + this.backCallback(); + return; + } + history.back(); + } + + static get styles(): CSSResult { + return css` + :host { + display: block; + height: 100%; + background-color: var(--primary-background-color); + } + + .toolbar { + display: flex; + align-items: center; + font-size: 20px; + height: 64px; + background-color: var(--sidebar-background-color); + font-weight: 400; + color: var(--sidebar-text-color); + border-bottom: 1px solid var(--divider-color); + padding: 0 16px; + box-sizing: border-box; + } + + :host([narrow]) .toolbar { + background-color: var(--primary-background-color); + border-bottom: none; + } + + #tabbar { + display: flex; + font-size: 14px; + } + + #tabbar.bottom-bar { + position: absolute; + bottom: 0; + left: 0; + padding: 0 16px; + box-sizing: border-box; + background-color: var(--sidebar-background-color); + border-top: 1px solid var(--divider-color); + justify-content: space-between; + z-index: 1; + font-size: 12px; + width: 100%; + } + + #tabbar:not(.bottom-bar) { + margin: auto; + left: 50%; + position: absolute; + transform: translate(-50%, 0); + } + + .tab { + padding: 0 32px; + display: flex; + flex-direction: column; + text-align: center; + align-items: center; + justify-content: center; + height: 64px; + cursor: pointer; + } + + .name { + white-space: nowrap; + } + + .tab.active { + color: var(--primary-color); + } + + #tabbar:not(.bottom-bar) .tab.active { + border-bottom: 2px solid var(--primary-color); + } + + .bottom-bar .tab { + padding: 0 16px; + width: 20%; + min-width: 0; + } + + ha-menu-button, + ha-paper-icon-button-arrow-prev, + ::slotted([slot="toolbar-icon"]) { + pointer-events: auto; + color: var(--sidebar-icon-color); + } + + [main-title] { + margin: 0 0 0 24px; + line-height: 20px; + flex-grow: 1; + } + + .content { + position: relative; + width: 100%; + height: calc(100% - 64px); + overflow-y: auto; + overflow: auto; + -webkit-overflow-scrolling: touch; + } + + #toolbar-icon { + position: absolute; + right: 16px; + } + + :host([narrow]) .content { + height: calc(100% - 128px); + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "hass-tabs-subpage": HassTabsSubpage; + } +} diff --git a/src/panels/config/areas/ha-config-areas.ts b/src/panels/config/areas/ha-config-areas.ts index 348bc6656c..7c3cf09932 100644 --- a/src/panels/config/areas/ha-config-areas.ts +++ b/src/panels/config/areas/ha-config-areas.ts @@ -10,7 +10,7 @@ import { import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item-body"; -import { HomeAssistant } from "../../../types"; +import { HomeAssistant, Route } from "../../../types"; import { AreaRegistryEntry, updateAreaRegistryEntry, @@ -20,7 +20,7 @@ import { } from "../../../data/area_registry"; import "../../../components/ha-card"; import "../../../components/ha-fab"; -import "../../../layouts/hass-subpage"; +import "../../../layouts/hass-tabs-subpage"; import "../../../layouts/hass-loading-screen"; import "../ha-config-section"; import { @@ -30,11 +30,14 @@ import { import { classMap } from "lit-html/directives/class-map"; import { computeRTL } from "../../../common/util/compute_rtl"; import { UnsubscribeFunc } from "home-assistant-js-websocket"; +import { configSections } from "../ha-panel-config"; @customElement("ha-config-areas") export class HaConfigAreas extends LitElement { @property() public hass!: HomeAssistant; @property() public isWide?: boolean; + @property() public narrow!: boolean; + @property() public route!: Route; @property() private _areas?: AreaRegistryEntry[]; private _unsubAreas?: UnsubscribeFunc; @@ -52,9 +55,12 @@ export class HaConfigAreas extends LitElement { `; } return html` - @@ -95,10 +101,11 @@ export class HaConfigAreas extends LitElement { : html``} - + - - - -
- ${this.automation - ? computeStateName(this.automation) - : this.hass.localize( - "ui.panel.config.automation.editor.default_name" - )} -
- ${this.creatingNew - ? "" - : html` - - `} -
-
- -
- ${this._errors + this._backTapped()} + .tabs=${configSections.automation} + > + ${this.creatingNew + ? "" + : html` + + `} + ${this._errors + ? html` +
${this._errors}
+ ` + : ""} +
+ ${this._config ? html` -
${this._errors}
+ + ${this._config.alias} + + ${this.hass.localize( + "ui.panel.config.automation.editor.introduction" + )} + + +
+ + + +
+
+
+ + + + ${this.hass.localize( + "ui.panel.config.automation.editor.triggers.header" + )} + + +

+ ${this.hass.localize( + "ui.panel.config.automation.editor.triggers.introduction" + )} +

+ + ${this.hass.localize( + "ui.panel.config.automation.editor.triggers.learn_more" + )} + +
+ +
+ + + + ${this.hass.localize( + "ui.panel.config.automation.editor.conditions.header" + )} + + +

+ ${this.hass.localize( + "ui.panel.config.automation.editor.conditions.introduction" + )} +

+ + ${this.hass.localize( + "ui.panel.config.automation.editor.conditions.learn_more" + )} + +
+ +
+ + + + ${this.hass.localize( + "ui.panel.config.automation.editor.actions.header" + )} + + +

+ ${this.hass.localize( + "ui.panel.config.automation.editor.actions.introduction" + )} +

+ + ${this.hass.localize( + "ui.panel.config.automation.editor.actions.learn_more" + )} + +
+ +
` : ""} -
- ${this._config - ? html` - - ${this._config.alias} - - ${this.hass.localize( - "ui.panel.config.automation.editor.introduction" - )} - - -
- - - -
-
-
- - - - ${this.hass.localize( - "ui.panel.config.automation.editor.triggers.header" - )} - - -

- ${this.hass.localize( - "ui.panel.config.automation.editor.triggers.introduction" - )} -

- - ${this.hass.localize( - "ui.panel.config.automation.editor.triggers.learn_more" - )} - -
- -
- - - - ${this.hass.localize( - "ui.panel.config.automation.editor.conditions.header" - )} - - -

- ${this.hass.localize( - "ui.panel.config.automation.editor.conditions.introduction" - )} -

- - ${this.hass.localize( - "ui.panel.config.automation.editor.conditions.learn_more" - )} - -
- -
- - - - ${this.hass.localize( - "ui.panel.config.automation.editor.actions.header" - )} - - -

- ${this.hass.localize( - "ui.panel.config.automation.editor.actions.introduction" - )} -

- - ${this.hass.localize( - "ui.panel.config.automation.editor.actions.learn_more" - )} - -
- -
- ` - : ""} -
- +
`; } @@ -409,7 +402,10 @@ export class HaAutomationEditor extends LitElement { bottom: 24px; right: 24px; } - + ha-fab[narrow] { + bottom: 84px; + margin-bottom: -140px; + } ha-fab[dirty] { margin-bottom: 0; } diff --git a/src/panels/config/automation/ha-automation-picker.ts b/src/panels/config/automation/ha-automation-picker.ts index d50cc496ad..608956c487 100644 --- a/src/panels/config/automation/ha-automation-picker.ts +++ b/src/panels/config/automation/ha-automation-picker.ts @@ -11,7 +11,7 @@ import { ifDefined } from "lit-html/directives/if-defined"; import "@polymer/paper-icon-button/paper-icon-button"; import "@polymer/paper-item/paper-item-body"; import "@polymer/paper-tooltip/paper-tooltip"; -import "../../../layouts/hass-subpage"; +import "../../../layouts/hass-tabs-subpage"; import "../../../components/ha-card"; import "../../../components/ha-fab"; @@ -22,7 +22,7 @@ import "../ha-config-section"; import { computeStateName } from "../../../common/entity/compute_state_name"; import { computeRTL } from "../../../common/util/compute_rtl"; import { haStyle } from "../../../resources/styles"; -import { HomeAssistant } from "../../../types"; +import { HomeAssistant, Route } from "../../../types"; import { AutomationEntity, showAutomationEditor, @@ -32,18 +32,24 @@ import format_date_time from "../../../common/datetime/format_date_time"; import { fireEvent } from "../../../common/dom/fire_event"; import { showThingtalkDialog } from "./show-dialog-thingtalk"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; +import { configSections } from "../ha-panel-config"; @customElement("ha-automation-picker") class HaAutomationPicker extends LitElement { @property() public hass!: HomeAssistant; @property() public isWide!: boolean; + @property() public narrow!: boolean; + @property() public route!: Route; @property() public automations!: AutomationEntity[]; protected render(): TemplateResult { return html` -
@@ -150,6 +156,7 @@ class HaAutomationPicker extends LitElement {
-
+ `; } @@ -221,7 +228,9 @@ class HaAutomationPicker extends LitElement { bottom: 24px; right: 24px; } - + ha-fab[narrow] { + bottom: 84px; + } ha-fab[rtl] { right: auto; left: 16px; diff --git a/src/panels/config/automation/ha-config-automation.js b/src/panels/config/automation/ha-config-automation.js index ec685ae329..d3052b9640 100644 --- a/src/panels/config/automation/ha-config-automation.js +++ b/src/panels/config/automation/ha-config-automation.js @@ -33,6 +33,8 @@ class HaConfigAutomation extends PolymerElement { hass="[[hass]]" automations="[[automations]]" is-wide="[[isWide]]" + narrow="[[narrow]]" + route="[[route]]" > @@ -41,6 +43,8 @@ class HaConfigAutomation extends PolymerElement { hass="[[hass]]" automation="[[automation]]" is-wide="[[isWide]]" + narrow="[[narrow]]" + route="[[route]]" creating-new="[[_creatingNew]]" > @@ -52,6 +56,7 @@ class HaConfigAutomation extends PolymerElement { hass: Object, route: Object, isWide: Boolean, + narrow: Boolean, _routeData: Object, _routeMatches: Boolean, _creatingNew: Boolean, diff --git a/src/panels/config/cloud/account/cloud-account.js b/src/panels/config/cloud/account/cloud-account.js index 2bc95e8f32..19f37a5aff 100644 --- a/src/panels/config/cloud/account/cloud-account.js +++ b/src/panels/config/cloud/account/cloud-account.js @@ -63,10 +63,7 @@ class CloudAccount extends EventsMixin(LocalizeMixin(PolymerElement)) { color: var(--primary-color); } - +
- +
-
-
+ `; } @@ -52,10 +58,16 @@ class HaConfigCore extends LocalizeMixin(PolymerElement) { return { hass: Object, isWide: Boolean, + narrow: Boolean, showAdvanced: Boolean, + route: Object, }; } + _computeTabs() { + return configSections.general; + } + computeClasses(isWide) { return isWide ? "content" : "content narrow"; } diff --git a/src/panels/config/customize/ha-config-customize.js b/src/panels/config/customize/ha-config-customize.js index b5d622fc4b..abd812191f 100644 --- a/src/panels/config/customize/ha-config-customize.js +++ b/src/panels/config/customize/ha-config-customize.js @@ -1,10 +1,8 @@ -import "@polymer/app-layout/app-header-layout/app-header-layout"; -import "@polymer/app-layout/app-header/app-header"; -import "@polymer/app-layout/app-toolbar/app-toolbar"; import "@polymer/paper-icon-button/paper-icon-button"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; +import "../../../layouts/hass-tabs-subpage"; import "../../../resources/ha-style"; import "../../../components/ha-paper-icon-button-arrow-prev"; @@ -17,6 +15,8 @@ import { computeStateDomain } from "../../../common/entity/compute_state_domain" import { sortStatesByName } from "../../../common/entity/states_sort_by_name"; import LocalizeMixin from "../../../mixins/localize-mixin"; +import { configSections } from "../ha-panel-config"; + /* * @appliesMixin LocalizeMixin */ @@ -29,19 +29,14 @@ class HaConfigCustomize extends LocalizeMixin(PolymerElement) { } - - - - -
- [[localize('ui.panel.config.customize.caption')]] -
-
-
- +
@@ -59,7 +54,7 @@ class HaConfigCustomize extends LocalizeMixin(PolymerElement) {
-
+ `; } @@ -67,7 +62,9 @@ class HaConfigCustomize extends LocalizeMixin(PolymerElement) { return { hass: Object, isWide: Boolean, - + narrow: Boolean, + route: Object, + showAdvanced: Boolean, entities: { type: Array, computed: "computeEntities(hass)", @@ -95,6 +92,10 @@ class HaConfigCustomize extends LocalizeMixin(PolymerElement) { history.back(); } + _computeTabs() { + return configSections.general; + } + computeEntities(hass) { return Object.keys(hass.states) .map((key) => hass.states[key]) diff --git a/src/panels/config/dashboard/ha-config-dashboard.ts b/src/panels/config/dashboard/ha-config-dashboard.ts index 95e4256a7b..5114a62631 100644 --- a/src/panels/config/dashboard/ha-config-dashboard.ts +++ b/src/panels/config/dashboard/ha-config-dashboard.ts @@ -15,7 +15,7 @@ import "../../../components/ha-menu-button"; import { haStyle } from "../../../resources/styles"; import { HomeAssistant } from "../../../types"; -import { CloudStatus, CloudStatusLoggedIn } from "../../../data/cloud"; +import { CloudStatus } from "../../../data/cloud"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import "../../../components/ha-card"; @@ -23,6 +23,7 @@ import "../../../components/ha-icon-next"; import "../ha-config-section"; import "./ha-config-navigation"; +import { configSections } from "../ha-panel-config"; @customElement("ha-config-dashboard") class HaConfigDashboard extends LitElement { @@ -41,7 +42,6 @@ class HaConfigDashboard extends LitElement { .hass=${this.hass} .narrow=${this.narrow} > -
${this.hass.localize("panel.config")}
@@ -57,68 +57,33 @@ class HaConfigDashboard extends LitElement { ${this.cloudStatus && isComponentLoaded(this.hass, "cloud") ? html` - - - - ${this.hass.localize("ui.panel.config.cloud.caption")} - ${this.cloudStatus.logged_in - ? html` -
- ${this.hass.localize( - "ui.panel.config.cloud.description_login", - "email", - (this.cloudStatus as CloudStatusLoggedIn) - .email - )} -
- ` - : html` -
- ${this.hass.localize( - "ui.panel.config.cloud.description_features" - )} -
- `} -
- -
-
+
` : ""} - - - - - - - - + ${Object.values(configSections).map( + (section) => html` + + + + ` + )} ${!this.showAdvanced ? html`
@@ -142,9 +107,15 @@ class HaConfigDashboard extends LitElement { return [ haStyle, css` + app-header { + --app-header-background-color: var(--primary-background-color); + } ha-config-navigation:last-child { margin-bottom: 24px; } + ha-config-section { + margin-top: -20px; + } ha-card { overflow: hidden; } diff --git a/src/panels/config/dashboard/ha-config-navigation.ts b/src/panels/config/dashboard/ha-config-navigation.ts index 0d55475475..3af4194ac9 100644 --- a/src/panels/config/dashboard/ha-config-navigation.ts +++ b/src/panels/config/dashboard/ha-config-navigation.ts @@ -1,6 +1,6 @@ import "@polymer/iron-icon/iron-icon"; import "@polymer/paper-item/paper-item-body"; -import "@polymer/paper-item/paper-item"; +import "@polymer/paper-item/paper-icon-item"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; @@ -17,70 +17,65 @@ import { } from "lit-element"; import { HomeAssistant } from "../../../types"; import { CloudStatus, CloudStatusLoggedIn } from "../../../data/cloud"; - -export interface ConfigPageNavigation { - page: string; - core?: boolean; - advanced?: boolean; - info?: any; -} +import { PageNavigation } from "../../../layouts/hass-tabs-subpage"; @customElement("ha-config-navigation") class HaConfigNavigation extends LitElement { @property() public hass!: HomeAssistant; @property() public showAdvanced!: boolean; - @property() public pages!: ConfigPageNavigation[]; - @property() public curPage!: string; + @property() public pages!: PageNavigation[]; protected render(): TemplateResult { return html` - - ${this.pages.map(({ page, core, advanced, info }) => - (core || isComponentLoaded(this.hass, page)) && - (!advanced || this.showAdvanced) - ? html` - - - - ${this.hass.localize(`ui.panel.config.${page}.caption`)} - ${page === "cloud" && (info as CloudStatus) - ? info.logged_in - ? html` -
- ${this.hass.localize( - "ui.panel.config.cloud.description_login", - "email", - (info as CloudStatusLoggedIn).email - )} -
- ` - : html` -
- ${this.hass.localize( - "ui.panel.config.cloud.description_features" - )} -
- ` + ${this.pages.map((page) => + (!page.component || + page.core || + isComponentLoaded(this.hass, page.component)) && + (!page.exportOnly || this.showAdvanced) + ? html` +
+ + + + ${this.hass.localize( + `ui.panel.config.${page.component}.caption` + )} + ${page.component === "cloud" && (page.info as CloudStatus) + ? page.info.logged_in + ? html` +
+ ${this.hass.localize( + "ui.panel.config.cloud.description_login", + "email", + (page.info as CloudStatusLoggedIn).email + )} +
+ ` : html`
${this.hass.localize( - `ui.panel.config.${page}.description` + "ui.panel.config.cloud.description_features" )}
- `} -
- - -
- ` - : "" - )} -
+ ` + : html` +
+ ${this.hass.localize( + `ui.panel.config.${page.component}.description` + )} +
+ `} + + + + + ` + : "" + )} `; } @@ -93,6 +88,10 @@ class HaConfigNavigation extends LitElement { display: block; outline: 0; } + ha-icon, + ha-icon-next { + color: var(--secondary-text-color); + } .iron-selected paper-item::before, a:not(.iron-selected):focus::before { position: absolute; @@ -105,10 +104,6 @@ class HaConfigNavigation extends LitElement { transition: opacity 15ms linear; will-change: opacity; } - .iron-selected paper-item::before { - background-color: var(--sidebar-selected-icon-color); - opacity: 0.12; - } a:not(.iron-selected):focus::before { background-color: currentColor; opacity: var(--dark-divider-opacity); @@ -117,12 +112,6 @@ class HaConfigNavigation extends LitElement { .iron-selected:focus paper-item::before { opacity: 0.2; } - .iron-selected paper-item[pressed]::before { - opacity: 0.37; - } - paper-listbox { - padding: 0; - } `; } } diff --git a/src/panels/config/devices/ha-config-device-page.ts b/src/panels/config/devices/ha-config-device-page.ts index 2bc8d4fb0d..336d4642ff 100644 --- a/src/panels/config/devices/ha-config-device-page.ts +++ b/src/panels/config/devices/ha-config-device-page.ts @@ -9,7 +9,7 @@ import { import memoizeOne from "memoize-one"; -import "../../../layouts/hass-subpage"; +import "../../../layouts/hass-tabs-subpage"; import "../../../layouts/hass-error-screen"; import "../ha-config-section"; @@ -18,7 +18,7 @@ import "./device-detail/ha-device-triggers-card"; import "./device-detail/ha-device-conditions-card"; import "./device-detail/ha-device-actions-card"; import "./device-detail/ha-device-entities-card"; -import { HomeAssistant } from "../../../types"; +import { HomeAssistant, Route } from "../../../types"; import { ConfigEntry } from "../../../data/config_entries"; import { EntityRegistryEntry, @@ -45,6 +45,7 @@ import { import { compare } from "../../../common/string/compare"; import { computeStateName } from "../../../common/entity/compute_state_name"; import { createValidEntityId } from "../../../common/entity/valid_entity_id"; +import { configSections } from "../ha-panel-config"; export interface EntityRegistryStateEntry extends EntityRegistryEntry { stateName?: string; @@ -60,6 +61,7 @@ export class HaConfigDevicePage extends LitElement { @property() public deviceId!: string; @property() public narrow!: boolean; @property() public showAdvanced!: boolean; + @property() public route!: Route; @property() private _triggers: DeviceTrigger[] = []; @property() private _conditions: DeviceCondition[] = []; @property() private _actions: DeviceAction[] = []; @@ -133,7 +135,12 @@ export class HaConfigDevicePage extends LitElement { const entities = this._entities(this.deviceId, this.entities); return html` - + - + `; } diff --git a/src/panels/config/devices/ha-config-devices-dashboard.ts b/src/panels/config/devices/ha-config-devices-dashboard.ts index ef2f32d684..e60b990e92 100644 --- a/src/panels/config/devices/ha-config-devices-dashboard.ts +++ b/src/panels/config/devices/ha-config-devices-dashboard.ts @@ -1,4 +1,4 @@ -import "../../../layouts/hass-subpage"; +import "../../../layouts/hass-tabs-subpage"; import "./ha-devices-data-table"; import { @@ -10,11 +10,12 @@ import { CSSResult, css, } from "lit-element"; -import { HomeAssistant } from "../../../types"; +import { HomeAssistant, Route } from "../../../types"; import { DeviceRegistryEntry } from "../../../data/device_registry"; import { EntityRegistryEntry } from "../../../data/entity_registry"; import { ConfigEntry } from "../../../data/config_entries"; import { AreaRegistryEntry } from "../../../data/area_registry"; +import { configSections } from "../ha-panel-config"; @customElement("ha-config-devices-dashboard") export class HaConfigDeviceDashboard extends LitElement { @@ -26,12 +27,16 @@ export class HaConfigDeviceDashboard extends LitElement { @property() public entities!: EntityRegistryEntry[]; @property() public areas!: AreaRegistryEntry[]; @property() public domain!: string; + @property() public route!: Route; protected render(): TemplateResult { return html` -
-
+ `; } diff --git a/src/panels/config/devices/ha-config-devices.ts b/src/panels/config/devices/ha-config-devices.ts index 0f0a78fcd6..2db8938019 100644 --- a/src/panels/config/devices/ha-config-devices.ts +++ b/src/panels/config/devices/ha-config-devices.ts @@ -100,6 +100,7 @@ class HaConfigDevices extends HassRouterPage { pageEl.narrow = this.narrow; pageEl.isWide = this.isWide; pageEl.showAdvanced = this.showAdvanced; + pageEl.route = this.routeTail; } private _loadData() { diff --git a/src/panels/config/entities/entity-registry-settings.ts b/src/panels/config/entities/entity-registry-settings.ts index 547838c8fb..0e4fcb95a8 100644 --- a/src/panels/config/entities/entity-registry-settings.ts +++ b/src/panels/config/entities/entity-registry-settings.ts @@ -1,32 +1,29 @@ +import "@polymer/paper-input/paper-input"; +import { HassEntity } from "home-assistant-js-websocket"; import { - LitElement, - html, css, CSSResult, - TemplateResult, - property, customElement, + html, + LitElement, + property, PropertyValues, + TemplateResult, } from "lit-element"; -import "@polymer/paper-input/paper-input"; - -import "../../../components/ha-switch"; - -import { PolymerChangedEvent } from "../../../polymer-types"; -import { HomeAssistant } from "../../../types"; -import { HassEntity } from "home-assistant-js-websocket"; -// tslint:disable-next-line: no-duplicate-imports -import { HaSwitch } from "../../../components/ha-switch"; - +import { fireEvent } from "../../../common/dom/fire_event"; import { computeDomain } from "../../../common/entity/compute_domain"; import { computeStateName } from "../../../common/entity/compute_state_name"; +import "../../../components/ha-switch"; +// tslint:disable-next-line: no-duplicate-imports +import { HaSwitch } from "../../../components/ha-switch"; import { - updateEntityRegistryEntry, - removeEntityRegistryEntry, EntityRegistryEntry, + removeEntityRegistryEntry, + updateEntityRegistryEntry, } from "../../../data/entity_registry"; import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box"; -import { fireEvent } from "../../../common/dom/fire_event"; +import { PolymerChangedEvent } from "../../../polymer-types"; +import { HomeAssistant } from "../../../types"; @customElement("entity-registry-settings") export class EntityRegistrySettings extends LitElement { diff --git a/src/panels/config/entities/ha-config-entities.ts b/src/panels/config/entities/ha-config-entities.ts index 00a95df4da..f16cfd5fb2 100644 --- a/src/panels/config/entities/ha-config-entities.ts +++ b/src/panels/config/entities/ha-config-entities.ts @@ -1,59 +1,59 @@ -import { - LitElement, - TemplateResult, - html, - css, - CSSResult, - property, - query, - customElement, -} from "lit-element"; -import { styleMap } from "lit-html/directives/style-map"; - import "@polymer/paper-checkbox/paper-checkbox"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-listbox/paper-listbox"; import "@polymer/paper-tooltip/paper-tooltip"; - -import { HomeAssistant } from "../../../types"; +import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { - EntityRegistryEntry, - computeEntityRegistryName, - subscribeEntityRegistry, - removeEntityRegistryEntry, - updateEntityRegistryEntry, -} from "../../../data/entity_registry"; -import "../../../layouts/hass-subpage"; -import "../../../layouts/hass-loading-screen"; -import "../../../components/data-table/ha-data-table"; -import "../../../components/ha-icon"; + css, + CSSResult, + customElement, + html, + LitElement, + property, + query, + TemplateResult, +} from "lit-element"; +import { styleMap } from "lit-html/directives/style-map"; +import memoize from "memoize-one"; +import { computeDomain } from "../../../common/entity/compute_domain"; import { domainIcon } from "../../../common/entity/domain_icon"; import { stateIcon } from "../../../common/entity/state_icon"; -import { computeDomain } from "../../../common/entity/compute_domain"; -import { - showEntityRegistryDetailDialog, - loadEntityRegistryDetailDialog, -} from "./show-dialog-entity-registry-detail"; -import { UnsubscribeFunc } from "home-assistant-js-websocket"; -import memoize from "memoize-one"; +import "../../../components/data-table/ha-data-table"; // tslint:disable-next-line import { DataTableColumnContainer, + DataTableColumnData, + HaDataTable, RowClickedEvent, SelectionChangedEvent, - HaDataTable, - DataTableColumnData, } from "../../../components/data-table/ha-data-table"; +import "../../../components/ha-icon"; +import { + computeEntityRegistryName, + EntityRegistryEntry, + removeEntityRegistryEntry, + subscribeEntityRegistry, + updateEntityRegistryEntry, +} from "../../../data/entity_registry"; import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box"; +import "../../../layouts/hass-loading-screen"; +import "../../../layouts/hass-tabs-subpage"; import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; +import { HomeAssistant, Route } from "../../../types"; import { DialogEntityRegistryDetail } from "./dialog-entity-registry-detail"; +import { + loadEntityRegistryDetailDialog, + showEntityRegistryDetailDialog, +} from "./show-dialog-entity-registry-detail"; +import { configSections } from "../ha-panel-config"; @customElement("ha-config-entities") export class HaConfigEntities extends SubscribeMixin(LitElement) { @property() public hass!: HomeAssistant; @property() public isWide!: boolean; @property() public narrow!: boolean; + @property() public route!: Route; @property() private _entities?: EntityRegistryEntry[]; @property() private _showDisabled = false; @property() private _showUnavailable = true; @@ -224,9 +224,12 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { `; } return html` -
@@ -367,7 +370,7 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
-
+ `; } @@ -490,6 +493,10 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { static get styles(): CSSResult { return css` + hass-loading-screen { + --app-header-background-color: var(--sidebar-background-color); + --app-header-text-color: var(--sidebar-text-color); + } a { color: var(--primary-color); } diff --git a/src/panels/config/ha-config-router.ts b/src/panels/config/ha-config-router.ts deleted file mode 100644 index dd883f0d0a..0000000000 --- a/src/panels/config/ha-config-router.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { property, customElement } from "lit-element"; -import "../../layouts/hass-loading-screen"; -import { HomeAssistant } from "../../types"; -import { CloudStatus } from "../../data/cloud"; -import { HassRouterPage, RouterOptions } from "../../layouts/hass-router-page"; -import { PolymerElement } from "@polymer/polymer"; - -declare global { - // for fire event - interface HASSDomEvents { - "ha-refresh-cloud-status": undefined; - } -} - -@customElement("ha-config-router") -class HaConfigRouter extends HassRouterPage { - @property() public hass!: HomeAssistant; - @property() public narrow!: boolean; - @property() public wideSidebar: boolean = false; - @property() public wide: boolean = false; - @property() public isWide: boolean = false; - @property() public showAdvanced: boolean = false; - @property() public cloudStatus?: CloudStatus; - - protected routerOptions: RouterOptions = { - defaultPage: "dashboard", - cacheAll: true, - preloadAll: true, - routes: { - areas: { - tag: "ha-config-areas", - load: () => - import( - /* webpackChunkName: "panel-config-areas" */ "./areas/ha-config-areas" - ), - }, - automation: { - tag: "ha-config-automation", - load: () => - import( - /* webpackChunkName: "panel-config-automation" */ "./automation/ha-config-automation" - ), - }, - cloud: { - tag: "ha-config-cloud", - load: () => - import( - /* webpackChunkName: "panel-config-cloud" */ "./cloud/ha-config-cloud" - ), - }, - core: { - tag: "ha-config-core", - load: () => - import( - /* webpackChunkName: "panel-config-core" */ "./core/ha-config-core" - ), - }, - devices: { - tag: "ha-config-devices", - load: () => - import( - /* webpackChunkName: "panel-config-devices" */ "./devices/ha-config-devices" - ), - }, - server_control: { - tag: "ha-config-server-control", - load: () => - import( - /* webpackChunkName: "panel-config-server-control" */ "./server_control/ha-config-server-control" - ), - }, - customize: { - tag: "ha-config-customize", - load: () => - import( - /* webpackChunkName: "panel-config-customize" */ "./customize/ha-config-customize" - ), - }, - dashboard: { - tag: "ha-config-dashboard", - load: () => - import( - /* webpackChunkName: "panel-config-dashboard" */ "./dashboard/ha-config-dashboard" - ), - }, - entities: { - tag: "ha-config-entities", - load: () => - import( - /* webpackChunkName: "panel-config-entities" */ "./entities/ha-config-entities" - ), - }, - integrations: { - tag: "ha-config-integrations", - load: () => - import( - /* webpackChunkName: "panel-config-integrations" */ "./integrations/ha-config-integrations" - ), - }, - person: { - tag: "ha-config-person", - load: () => - import( - /* webpackChunkName: "panel-config-person" */ "./person/ha-config-person" - ), - }, - script: { - tag: "ha-config-script", - load: () => - import( - /* webpackChunkName: "panel-config-script" */ "./script/ha-config-script" - ), - }, - scene: { - tag: "ha-config-scene", - load: () => - import( - /* webpackChunkName: "panel-config-scene" */ "./scene/ha-config-scene" - ), - }, - users: { - tag: "ha-config-users", - load: () => - import( - /* webpackChunkName: "panel-config-users" */ "./users/ha-config-users" - ), - }, - zone: { - tag: "ha-config-zone", - load: () => - import( - /* webpackChunkName: "panel-config-zone" */ "./zone/ha-config-zone" - ), - }, - zha: { - tag: "zha-config-dashboard-router", - load: () => - import( - /* webpackChunkName: "panel-config-zha" */ "./zha/zha-config-dashboard-router" - ), - }, - zwave: { - tag: "ha-config-zwave", - load: () => - import( - /* webpackChunkName: "panel-config-zwave" */ "./zwave/ha-config-zwave" - ), - }, - }, - }; - protected updatePageEl(el) { - if ("setProperties" in el) { - // As long as we have Polymer panels - (el as PolymerElement).setProperties({ - route: this.routeTail, - hass: this.hass, - showAdvanced: this.showAdvanced, - isWide: this.isWide, - narrow: this.narrow, - cloudStatus: this.cloudStatus, - }); - } else { - el.route = this.routeTail; - el.hass = this.hass; - el.showAdvanced = this.showAdvanced; - el.isWide = this.isWide; - el.narrow = this.narrow; - el.cloudStatus = this.cloudStatus; - } - } -} - -declare global { - interface HTMLElementTagNameMap { - "ha-config-router": HaConfigRouter; - } -} diff --git a/src/panels/config/ha-config-section.ts b/src/panels/config/ha-config-section.ts index 802bd65128..2e4e70db3c 100644 --- a/src/panels/config/ha-config-section.ts +++ b/src/panels/config/ha-config-section.ts @@ -1,18 +1,59 @@ -import { customElement } from "lit-element"; +import { customElement, LitElement, html, css, property } from "lit-element"; +import { classMap } from "lit-html/directives/class-map"; @customElement("ha-config-section") -export class HaConfigSection extends HTMLElement { - constructor() { - super(); - this.attachShadow({ mode: "open" }); - this.shadowRoot!.innerHTML = ` - -
-
-
-
-
-
-
+ + .narrow.content { + max-width: 640px; + } + .narrow .together { + margin-top: 20px; + } + .narrow .intro { + padding-bottom: 20px; + margin-right: 0; + max-width: 500px; + } `; } } diff --git a/src/panels/config/ha-panel-config.ts b/src/panels/config/ha-panel-config.ts index d0b763ddc7..f5c31b369a 100644 --- a/src/panels/config/ha-panel-config.ts +++ b/src/panels/config/ha-panel-config.ts @@ -1,12 +1,4 @@ -import { - property, - PropertyValues, - customElement, - LitElement, - html, - CSSResult, - css, -} from "lit-element"; +import { property, PropertyValues, customElement } from "lit-element"; import "@polymer/paper-item/paper-item-body"; import "@polymer/paper-item/paper-item"; import "../../layouts/hass-loading-screen"; @@ -18,9 +10,9 @@ import { getOptimisticFrontendUserDataCollection, CoreFrontendUserData, } from "../../data/frontend"; -import "./ha-config-router"; -import "./dashboard/ha-config-navigation"; -import { classMap } from "lit-html/directives/class-map"; +import { HassRouterPage, RouterOptions } from "../../layouts/hass-router-page"; +import { PolymerElement } from "@polymer/polymer"; +import { PageNavigation } from "../../layouts/hass-tabs-subpage"; declare global { // for fire event @@ -29,14 +21,252 @@ declare global { } } -const NO_SIDEBAR_PAGES = ["zone"]; +export const configSections: { [name: string]: PageNavigation[] } = { + integrations: [ + { + component: "integrations", + path: "/config/integrations", + translationKey: "ui.panel.config.integrations.caption", + icon: "hass:puzzle", + core: true, + }, + { + component: "devices", + path: "/config/devices", + translationKey: "ui.panel.config.devices.caption", + icon: "hass:devices", + core: true, + }, + { + component: "entities", + path: "/config/entities", + translationKey: "ui.panel.config.entities.caption", + icon: "hass:shape", + core: true, + }, + { + component: "areas", + path: "/config/areas", + translationKey: "ui.panel.config.areas.caption", + icon: "hass:sofa", + core: true, + }, + ], + automation: [ + { + component: "automation", + path: "/config/automation", + translationKey: "ui.panel.config.automation.caption", + icon: "hass:robot", + }, + { + component: "scene", + path: "/config/scene", + translationKey: "ui.panel.config.scene.caption", + icon: "hass:palette", + }, + { + component: "script", + path: "/config/script", + translationKey: "ui.panel.config.script.caption", + icon: "hass:script-text", + }, + ], + persons: [ + { + component: "person", + path: "/config/person", + translationKey: "ui.panel.config.person.caption", + icon: "hass:account", + }, + { + component: "zone", + path: "/config/zone", + translationKey: "ui.panel.config.zone.caption", + icon: "hass:map-marker-radius", + core: true, + }, + { + component: "users", + path: "/config/users", + translationKey: "ui.panel.config.users.caption", + icon: "hass:account-badge-horizontal", + core: true, + }, + ], + general: [ + { + component: "core", + path: "/config/core", + translationKey: "ui.panel.config.core.caption", + icon: "hass:home-assistant", + core: true, + }, + { + component: "server_control", + path: "/config/server_control", + translationKey: "ui.panel.config.server_control.caption", + icon: "hass:server", + core: true, + }, + { + component: "customize", + path: "/config/customize", + translationKey: "ui.panel.config.customize.caption", + icon: "hass:pencil", + core: true, + exportOnly: true, + }, + ], + other: [ + { + component: "zha", + path: "/config/zha", + translationKey: "ui.panel.config.zha.caption", + icon: "hass:zigbee", + }, + { + component: "zwave", + path: "/config/zwave", + translationKey: "ui.panel.config.zwave.caption", + icon: "hass:z-wave", + }, + ], +}; @customElement("ha-panel-config") -class HaPanelConfig extends LitElement { +class HaPanelConfig extends HassRouterPage { @property() public hass!: HomeAssistant; @property() public narrow!: boolean; @property() public route!: Route; + protected routerOptions: RouterOptions = { + defaultPage: "dashboard", + cacheAll: true, + preloadAll: true, + routes: { + areas: { + tag: "ha-config-areas", + load: () => + import( + /* webpackChunkName: "panel-config-areas" */ "./areas/ha-config-areas" + ), + }, + automation: { + tag: "ha-config-automation", + load: () => + import( + /* webpackChunkName: "panel-config-automation" */ "./automation/ha-config-automation" + ), + }, + cloud: { + tag: "ha-config-cloud", + load: () => + import( + /* webpackChunkName: "panel-config-cloud" */ "./cloud/ha-config-cloud" + ), + }, + core: { + tag: "ha-config-core", + load: () => + import( + /* webpackChunkName: "panel-config-core" */ "./core/ha-config-core" + ), + }, + devices: { + tag: "ha-config-devices", + load: () => + import( + /* webpackChunkName: "panel-config-devices" */ "./devices/ha-config-devices" + ), + }, + server_control: { + tag: "ha-config-server-control", + load: () => + import( + /* webpackChunkName: "panel-config-server-control" */ "./server_control/ha-config-server-control" + ), + }, + customize: { + tag: "ha-config-customize", + load: () => + import( + /* webpackChunkName: "panel-config-customize" */ "./customize/ha-config-customize" + ), + }, + dashboard: { + tag: "ha-config-dashboard", + load: () => + import( + /* webpackChunkName: "panel-config-dashboard" */ "./dashboard/ha-config-dashboard" + ), + }, + entities: { + tag: "ha-config-entities", + load: () => + import( + /* webpackChunkName: "panel-config-entities" */ "./entities/ha-config-entities" + ), + }, + integrations: { + tag: "ha-config-integrations", + load: () => + import( + /* webpackChunkName: "panel-config-integrations" */ "./integrations/ha-config-integrations" + ), + }, + person: { + tag: "ha-config-person", + load: () => + import( + /* webpackChunkName: "panel-config-person" */ "./person/ha-config-person" + ), + }, + script: { + tag: "ha-config-script", + load: () => + import( + /* webpackChunkName: "panel-config-script" */ "./script/ha-config-script" + ), + }, + scene: { + tag: "ha-config-scene", + load: () => + import( + /* webpackChunkName: "panel-config-scene" */ "./scene/ha-config-scene" + ), + }, + users: { + tag: "ha-config-users", + load: () => + import( + /* webpackChunkName: "panel-config-users" */ "./users/ha-config-users" + ), + }, + zone: { + tag: "ha-config-zone", + load: () => + import( + /* webpackChunkName: "panel-config-zone" */ "./zone/ha-config-zone" + ), + }, + zha: { + tag: "zha-config-dashboard-router", + load: () => + import( + /* webpackChunkName: "panel-config-zha" */ "./zha/zha-config-dashboard-router" + ), + }, + zwave: { + tag: "ha-config-zwave", + load: () => + import( + /* webpackChunkName: "panel-config-zwave" */ "./zwave/ha-config-zwave" + ), + }, + }, + }; + @property() private _wideSidebar: boolean = false; @property() private _wide: boolean = false; @property() private _coreUserData?: CoreFrontendUserData; @@ -85,64 +315,42 @@ class HaPanelConfig extends LitElement { this.addEventListener("ha-refresh-cloud-status", () => this._updateCloudStatus() ); + this.style.setProperty( + "--app-header-background-color", + "var(--sidebar-background-color)" + ); + this.style.setProperty( + "--app-header-text-color", + "var(--sidebar-text-color)" + ); + this.style.setProperty( + "--app-header-border-bottom", + "1px solid var(--divider-color)" + ); } - protected render() { - const dividerPos = this.route.path.indexOf("/", 1); - const curPage = - dividerPos === -1 - ? this.route.path.substr(1) - : this.route.path.substr(1, dividerPos - 1); - + protected updatePageEl(el) { const isWide = this.hass.dockedSidebar === "docked" ? this._wideSidebar : this._wide; - const showSidebar = isWide && !NO_SIDEBAR_PAGES.includes(curPage); - return html` - ${showSidebar - ? html` - - ` - : ""} - - `; + if ("setProperties" in el) { + // As long as we have Polymer panels + (el as PolymerElement).setProperties({ + route: this.routeTail, + hass: this.hass, + showAdvanced: this._showAdvanced, + isWide, + narrow: this.narrow, + cloudStatus: this._cloudStatus, + }); + } else { + el.route = this.routeTail; + el.hass = this.hass; + el.showAdvanced = this._showAdvanced; + el.isWide = isWide; + el.narrow = this.narrow; + el.cloudStatus = this._cloudStatus; + } } private async _updateCloudStatus() { @@ -152,54 +360,6 @@ class HaPanelConfig extends LitElement { setTimeout(() => this._updateCloudStatus(), 5000); } } - - static get styles(): CSSResult { - return css` - :host { - display: block; - height: 100%; - background-color: var(--primary-background-color); - } - - a { - text-decoration: none; - color: var(--primary-text-color); - } - - .side-bar { - border-right: 1px solid var(--divider-color); - background: white; - width: 320px; - float: left; - box-sizing: border-box; - position: fixed; - } - - .toolbar { - display: flex; - align-items: center; - font-size: 20px; - height: 64px; - padding: 0 16px 0 16px; - pointer-events: none; - background-color: var(--primary-background-color); - font-weight: 400; - color: var(--primary-text-color); - border-bottom: 1px solid var(--divider-color); - } - - .wide-config { - float: right; - width: calc(100% - 320px); - height: 100%; - } - - .navigation { - height: calc(100vh - 64px); - overflow: auto; - } - `; - } } declare global { diff --git a/src/panels/config/integrations/ha-config-entries-dashboard.ts b/src/panels/config/integrations/ha-config-entries-dashboard.ts index 2c55f68544..6aa95b96e5 100644 --- a/src/panels/config/integrations/ha-config-entries-dashboard.ts +++ b/src/panels/config/integrations/ha-config-entries-dashboard.ts @@ -12,7 +12,7 @@ import "../../../components/ha-card"; import "../../../components/ha-icon-next"; import "../../../components/ha-fab"; import "../../../components/entity/ha-state-icon"; -import "../../../layouts/hass-subpage"; +import "../../../layouts/hass-tabs-subpage"; import "../../../resources/ha-style"; import "../../../components/ha-icon"; @@ -38,18 +38,21 @@ import { css, CSSResult, } from "lit-element"; -import { HomeAssistant } from "../../../types"; +import { HomeAssistant, Route } from "../../../types"; import { ConfigEntry, deleteConfigEntry } from "../../../data/config_entries"; import { fireEvent } from "../../../common/dom/fire_event"; import { EntityRegistryEntry } from "../../../data/entity_registry"; import { DataEntryFlowProgress } from "../../../data/data_entry_flow"; import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box"; +import { configSections } from "../ha-panel-config"; @customElement("ha-config-entries-dashboard") export class HaConfigManagerDashboard extends LitElement { @property() public hass!: HomeAssistant; @property() public showAdvanced!: boolean; @property() public isWide!: boolean; + @property() public narrow!: boolean; + @property() public route!: Route; @property() private configEntries!: ConfigEntry[]; @@ -72,9 +75,12 @@ export class HaConfigManagerDashboard extends LitElement { protected render(): TemplateResult { return html` - - + `; } @@ -361,7 +368,9 @@ export class HaConfigManagerDashboard extends LitElement { right: 16px; z-index: 1; } - + ha-fab[narrow] { + bottom: 84px; + } ha-fab[rtl] { right: auto; left: 16px; diff --git a/src/panels/config/integrations/ha-config-integrations.ts b/src/panels/config/integrations/ha-config-integrations.ts index e3abd2f4fe..511f4e6390 100644 --- a/src/panels/config/integrations/ha-config-integrations.ts +++ b/src/panels/config/integrations/ha-config-integrations.ts @@ -104,7 +104,7 @@ class HaConfigIntegrations extends HassRouterPage { pageEl.narrow = this.narrow; pageEl.isWide = this.isWide; pageEl.showAdvanced = this.showAdvanced; - + pageEl.route = this.routeTail; if (this._currentPage === "dashboard") { pageEl.configEntriesInProgress = this._configEntriesInProgress; return; diff --git a/src/panels/config/person/ha-config-person.ts b/src/panels/config/person/ha-config-person.ts index b2b30089b0..59aa055f0a 100644 --- a/src/panels/config/person/ha-config-person.ts +++ b/src/panels/config/person/ha-config-person.ts @@ -9,7 +9,7 @@ import { import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item-body"; -import { HomeAssistant } from "../../../types"; +import { HomeAssistant, Route } from "../../../types"; import { Person, fetchPersons, @@ -19,7 +19,7 @@ import { } from "../../../data/person"; import "../../../components/ha-card"; import "../../../components/ha-fab"; -import "../../../layouts/hass-subpage"; +import "../../../layouts/hass-tabs-subpage"; import "../../../layouts/hass-loading-screen"; import { compare } from "../../../common/string/compare"; import "../ha-config-section"; @@ -28,10 +28,13 @@ import { loadPersonDetailDialog, } from "./show-dialog-person-detail"; import { User, fetchUsers } from "../../../data/user"; +import { configSections } from "../ha-panel-config"; class HaConfigPerson extends LitElement { @property() public hass?: HomeAssistant; @property() public isWide?: boolean; + @property() public narrow?: boolean; + @property() public route!: Route; @property() private _storageItems?: Person[]; @property() private _configItems?: Person[]; private _usersLoad?: Promise; @@ -48,9 +51,12 @@ class HaConfigPerson extends LitElement { } const hass = this.hass; return html` - - +
@@ -72,8 +77,7 @@ class HaSceneDashboard extends LitElement { ` : this.scenes.map( (scene) => html` - -
+ ` )} - - + `; } @@ -152,13 +154,11 @@ class HaSceneDashboard extends LitElement { css` :host { display: block; - } - - hass-subpage { - min-height: 100vh; + height: 100%; } ha-card { + padding-bottom: 8px; margin-bottom: 56px; } @@ -173,6 +173,10 @@ class HaSceneDashboard extends LitElement { color: var(--primary-text-color); } + .actions { + display: flex; + } + ha-entity-toggle { margin-right: 16px; } @@ -188,7 +192,9 @@ class HaSceneDashboard extends LitElement { bottom: 24px; right: 24px; } - + ha-fab[narrow] { + bottom: 84px; + } ha-fab[rtl] { right: auto; left: 16px; diff --git a/src/panels/config/scene/ha-scene-editor.ts b/src/panels/config/scene/ha-scene-editor.ts index 295e5192a1..d1b10ff3f5 100644 --- a/src/panels/config/scene/ha-scene-editor.ts +++ b/src/panels/config/scene/ha-scene-editor.ts @@ -26,7 +26,7 @@ import "../../../layouts/ha-app-layout"; import { computeStateName } from "../../../common/entity/compute_state_name"; import { haStyle } from "../../../resources/styles"; -import { HomeAssistant } from "../../../types"; +import { HomeAssistant, Route } from "../../../types"; import { navigate } from "../../../common/navigate"; import { computeRTL } from "../../../common/util/compute_rtl"; import { @@ -55,6 +55,7 @@ import memoizeOne from "memoize-one"; import { computeDomain } from "../../../common/entity/compute_domain"; import { HassEvent } from "home-assistant-js-websocket"; import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box"; +import { configSections } from "../ha-panel-config"; interface DeviceEntities { id: string; @@ -69,7 +70,9 @@ interface DeviceEntitiesLookup { @customElement("ha-scene-editor") export class HaSceneEditor extends SubscribeMixin(LitElement) { @property() public hass!: HomeAssistant; - @property() public isWide?: boolean; + @property() public narrow!: boolean; + @property() public isWide!: boolean; + @property() public route!: Route; @property() public scene?: SceneEntity; @property() public creatingNew?: boolean; @property() public showAdvanced!: boolean; @@ -157,39 +160,36 @@ export class HaSceneEditor extends SubscribeMixin(LitElement) { this._deviceRegistryEntries ); return html` - - - - -
- ${this.scene - ? computeStateName(this.scene) - : this.hass.localize( - "ui.panel.config.scene.editor.default_name" - )} -
- ${this.creatingNew - ? "" - : html` - - `} -
-
+ this._backTapped()} + .tabs=${configSections.automation} + > -
- ${this._errors - ? html` -
${this._errors}
- ` - : ""} + ${ + this.creatingNew + ? "" + : html` + + ` + } + + ${ + this._errors + ? html` +
${this._errors}
+ ` + : "" + }
- ${this.scene - ? computeStateName(this.scene) - : this.hass.localize( - "ui.panel.config.scene.editor.default_name" - )} + ${ + this.scene + ? computeStateName(this.scene) + : this.hass.localize( + "ui.panel.config.scene.editor.default_name" + ) + }
${this.hass.localize( @@ -291,87 +293,88 @@ export class HaSceneEditor extends SubscribeMixin(LitElement) { - ${this.showAdvanced - ? html` - -
- ${this.hass.localize( - "ui.panel.config.scene.editor.entities.header" - )} -
-
- ${this.hass.localize( - "ui.panel.config.scene.editor.entities.introduction" - )} -
- ${entities.length - ? html` - - ${entities.map((entityId) => { - const stateObj = this.hass.states[entityId]; - if (!stateObj) { - return html``; - } - return html` - - - - ${computeStateName(stateObj)} - - - - `; - })} - - ` - : ""} - - -
+ ${ + this.showAdvanced + ? html` + +
${this.hass.localize( - "ui.panel.config.scene.editor.entities.device_entities" + "ui.panel.config.scene.editor.entities.header" )} -
- -
- ` - : ""} +
+ ${this.hass.localize( + "ui.panel.config.scene.editor.entities.introduction" + )} +
+ ${entities.length + ? html` + + ${entities.map((entityId) => { + const stateObj = this.hass.states[entityId]; + if (!stateObj) { + return html``; + } + return html` + + + + ${computeStateName(stateObj)} + + + + `; + })} + + ` + : ""} + + +
+ ${this.hass.localize( + "ui.panel.config.scene.editor.entities.device_entities" + )} + +
+
+ + ` + : "" + }
-
@@ -42,6 +44,8 @@ class HaConfigScript extends PolymerElement { hass="[[hass]]" script="[[script]]" is-wide="[[isWide]]" + narrow="[[narrow]]" + route="[[route]]" creating-new="[[_creatingNew]]" > @@ -53,6 +57,7 @@ class HaConfigScript extends PolymerElement { hass: Object, route: Object, isWide: Boolean, + narrow: Boolean, _routeData: Object, _routeMatches: Boolean, _creatingNew: Boolean, diff --git a/src/panels/config/script/ha-script-editor.ts b/src/panels/config/script/ha-script-editor.ts index bf527d6b3b..3dcd615c03 100644 --- a/src/panels/config/script/ha-script-editor.ts +++ b/src/panels/config/script/ha-script-editor.ts @@ -11,7 +11,6 @@ import { TemplateResult, } from "lit-element"; import { classMap } from "lit-html/directives/class-map"; -import { computeStateName } from "../../../common/entity/compute_state_name"; import { navigate } from "../../../common/navigate"; import { computeRTL } from "../../../common/util/compute_rtl"; import "../../../components/ha-fab"; @@ -25,14 +24,17 @@ import { import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box"; import "../../../layouts/ha-app-layout"; import { haStyle } from "../../../resources/styles"; -import { HomeAssistant } from "../../../types"; +import { HomeAssistant, Route } from "../../../types"; import "../automation/action/ha-automation-action"; import { computeObjectId } from "../../../common/entity/compute_object_id"; +import { configSections } from "../ha-panel-config"; export class HaScriptEditor extends LitElement { @property() public hass!: HomeAssistant; @property() public script!: ScriptEntity; @property() public isWide?: boolean; + @property() public narrow!: boolean; + @property() public route!: Route; @property() public creatingNew?: boolean; @property() private _config?: ScriptConfig; @property() private _dirty?: boolean; @@ -40,32 +42,25 @@ export class HaScriptEditor extends LitElement { protected render(): TemplateResult { return html` - - - - -
- ${this.script - ? computeStateName(this.script) - : this.hass.localize( - "ui.panel.config.script.editor.default_name" - )} -
- ${this.creatingNew - ? "" - : html` - - `} -
-
+ this._backTapped()} + .tabs=${configSections.automation} + > + ${this.creatingNew + ? "" + : html` + + `}
${this._errors @@ -134,9 +129,9 @@ export class HaScriptEditor extends LitElement {
-
+ `; } @@ -301,7 +296,10 @@ export class HaScriptEditor extends LitElement { bottom: 24px; right: 24px; } - + ha-fab[narrow] { + bottom: 84px; + margin-bottom: -140px; + } ha-fab[dirty] { margin-bottom: 0; } diff --git a/src/panels/config/script/ha-script-picker.ts b/src/panels/config/script/ha-script-picker.ts index 82dbaee3a6..836cf63f1a 100644 --- a/src/panels/config/script/ha-script-picker.ts +++ b/src/panels/config/script/ha-script-picker.ts @@ -11,7 +11,7 @@ import "@polymer/paper-icon-button/paper-icon-button"; import "@polymer/paper-item/paper-item-body"; import { HassEntity } from "home-assistant-js-websocket"; -import "../../../layouts/hass-subpage"; +import "../../../layouts/hass-tabs-subpage"; import { computeRTL } from "../../../common/util/compute_rtl"; @@ -22,21 +22,27 @@ import "../ha-config-section"; import { computeStateName } from "../../../common/entity/compute_state_name"; import { haStyle } from "../../../resources/styles"; -import { HomeAssistant } from "../../../types"; +import { HomeAssistant, Route } from "../../../types"; import { triggerScript } from "../../../data/script"; import { showToast } from "../../../util/toast"; +import { configSections } from "../ha-panel-config"; @customElement("ha-script-picker") class HaScriptPicker extends LitElement { @property() public hass!: HomeAssistant; @property() public scripts!: HassEntity[]; @property() public isWide!: boolean; + @property() public narrow!: boolean; + @property() public route!: Route; protected render(): TemplateResult { return html` -
@@ -99,8 +105,8 @@ class HaScriptPicker extends LitElement { - + `; } @@ -169,7 +175,9 @@ class HaScriptPicker extends LitElement { bottom: 24px; right: 24px; } - + ha-fab[narrow] { + bottom: 84px; + } ha-fab[rtl] { right: auto; left: 16px; diff --git a/src/panels/config/server_control/ha-config-server-control.js b/src/panels/config/server_control/ha-config-server-control.js index 21c9162b87..ef93fe8fd6 100644 --- a/src/panels/config/server_control/ha-config-server-control.js +++ b/src/panels/config/server_control/ha-config-server-control.js @@ -4,12 +4,13 @@ import "@polymer/paper-icon-button/paper-icon-button"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; -import "../../../layouts/hass-subpage"; +import "../../../layouts/hass-tabs-subpage"; import "../../../resources/ha-style"; import "./ha-config-section-server-control"; import LocalizeMixin from "../../../mixins/localize-mixin"; +import { configSections } from "../ha-panel-config"; /* * @appliesMixin LocalizeMixin @@ -33,9 +34,13 @@ class HaConfigServerControl extends LocalizeMixin(PolymerElement) { } -
-
+ `; } @@ -52,10 +57,16 @@ class HaConfigServerControl extends LocalizeMixin(PolymerElement) { return { hass: Object, isWide: Boolean, + narrow: Boolean, + route: Object, showAdvanced: Boolean, }; } + _computeTabs() { + return configSections.general; + } + computeClasses(isWide) { return isWide ? "content" : "content narrow"; } diff --git a/src/panels/config/users/ha-config-user-picker.js b/src/panels/config/users/ha-config-user-picker.js index babfea2436..c7a78b581e 100644 --- a/src/panels/config/users/ha-config-user-picker.js +++ b/src/panels/config/users/ha-config-user-picker.js @@ -3,7 +3,7 @@ import "@polymer/paper-item/paper-item-body"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; -import "../../../layouts/hass-subpage"; +import "../../../layouts/hass-tabs-subpage"; import "../../../components/ha-icon-next"; import "../../../components/ha-card"; import "../../../components/ha-fab"; @@ -13,6 +13,7 @@ import NavigateMixin from "../../../mixins/navigate-mixin"; import { EventsMixin } from "../../../mixins/events-mixin"; import { computeRTL } from "../../../common/util/compute_rtl"; +import { configSections } from "../ha-panel-config"; let registeredDialog = false; @@ -41,6 +42,9 @@ class HaUserPicker extends EventsMixin( right: auto; left: 16px; } + ha-fab[narrow] { + bottom: 84px; + } ha-fab[rtl][is-wide] { bottom: 24px; right: auto; @@ -58,9 +62,12 @@ class HaUserPicker extends EventsMixin( } - `; @@ -47,6 +51,7 @@ class HaConfigUsers extends NavigateMixin(PolymerElement) { return { hass: Object, isWide: Boolean, + narrow: Boolean, route: { type: Object, observer: "_checkRoute", diff --git a/src/panels/config/users/ha-user-editor.ts b/src/panels/config/users/ha-user-editor.ts index 207cde707c..2aa50c413c 100644 --- a/src/panels/config/users/ha-user-editor.ts +++ b/src/panels/config/users/ha-user-editor.ts @@ -10,10 +10,10 @@ import { import { until } from "lit-html/directives/until"; import "@material/mwc-button"; -import "../../../layouts/hass-subpage"; +import "../../../layouts/hass-tabs-subpage"; import { haStyle } from "../../../resources/styles"; import "../../../components/ha-card"; -import { HomeAssistant } from "../../../types"; +import { HomeAssistant, Route } from "../../../types"; import { fireEvent } from "../../../common/dom/fire_event"; import { navigate } from "../../../common/navigate"; import { @@ -29,6 +29,7 @@ import { showConfirmationDialog, showPromptDialog, } from "../../../dialogs/generic/show-dialog-box"; +import { configSections } from "../ha-panel-config"; declare global { interface HASSDomEvents { @@ -42,6 +43,8 @@ const GROUPS = [SYSTEM_GROUP_ID_USER, SYSTEM_GROUP_ID_ADMIN]; class HaUserEditor extends LitElement { @property() public hass?: HomeAssistant; @property() public user?: User; + @property() public narrow?: boolean; + @property() public route!: Route; protected render(): TemplateResult { const hass = this.hass; @@ -51,8 +54,11 @@ class HaUserEditor extends LitElement { } return html` - @@ -130,7 +136,7 @@ class HaUserEditor extends LitElement { : ""} - + `; } @@ -225,7 +231,7 @@ class HaUserEditor extends LitElement { } ha-card { max-width: 600px; - margin: 0 auto 16px; + margin: 16px auto 16px; } hass-subpage ha-card:first-of-type { direction: ltr; diff --git a/src/panels/config/zone/ha-config-zone.ts b/src/panels/config/zone/ha-config-zone.ts index 8554d5433e..96ff793607 100644 --- a/src/panels/config/zone/ha-config-zone.ts +++ b/src/panels/config/zone/ha-config-zone.ts @@ -16,10 +16,10 @@ import "@polymer/paper-tooltip/paper-tooltip"; import "../../../components/map/ha-locations-editor"; -import { HomeAssistant } from "../../../types"; +import { HomeAssistant, Route } from "../../../types"; import "../../../components/ha-card"; import "../../../components/ha-fab"; -import "../../../layouts/hass-subpage"; +import "../../../layouts/hass-tabs-subpage"; import "../../../layouts/hass-loading-screen"; import { compare } from "../../../common/string/compare"; import "../ha-config-section"; @@ -42,12 +42,14 @@ import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket"; import memoizeOne from "memoize-one"; import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; import { subscribeEntityRegistry } from "../../../data/entity_registry"; +import { configSections } from "../ha-panel-config"; @customElement("ha-config-zone") export class HaConfigZone extends SubscribeMixin(LitElement) { @property() public hass!: HomeAssistant; @property() public isWide?: boolean; @property() public narrow?: boolean; + @property() public route!: Route; @property() private _storageItems?: Zone[]; @property() private _stateItems?: HassEntity[]; @property() private _activeEntry: string = ""; @@ -179,7 +181,13 @@ export class HaConfigZone extends SubscribeMixin(LitElement) { `; return html` - + ${this.narrow ? html` @@ -206,10 +214,11 @@ export class HaConfigZone extends SubscribeMixin(LitElement) { ` : ""} - +