2020-01-28 21:48:21 +01:00
|
|
|
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";
|
2020-02-28 21:58:50 +01:00
|
|
|
import memoizeOne from "memoize-one";
|
2020-01-28 21:48:21 +01:00
|
|
|
|
|
|
|
export interface PageNavigation {
|
|
|
|
path: string;
|
|
|
|
translationKey?: string;
|
|
|
|
component?: string;
|
|
|
|
name?: string;
|
|
|
|
core?: boolean;
|
2020-02-28 21:58:50 +01:00
|
|
|
advancedOnly?: boolean;
|
2020-01-28 21:48:21 +01:00
|
|
|
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() public route!: Route;
|
|
|
|
@property() public tabs!: PageNavigation[];
|
|
|
|
@property({ type: Boolean, reflect: true }) public narrow = false;
|
2020-03-17 20:44:07 +01:00
|
|
|
@property() private _activeTab?: PageNavigation;
|
2020-01-28 21:48:21 +01:00
|
|
|
|
2020-02-28 21:58:50 +01:00
|
|
|
private _getTabs = memoizeOne(
|
|
|
|
(
|
|
|
|
tabs: PageNavigation[],
|
2020-03-17 20:44:07 +01:00
|
|
|
activeTab: PageNavigation | undefined,
|
2020-02-28 21:58:50 +01:00
|
|
|
showAdvanced: boolean | undefined,
|
|
|
|
_components,
|
|
|
|
_language
|
|
|
|
) => {
|
|
|
|
const shownTabs = tabs.filter(
|
|
|
|
(page) =>
|
|
|
|
(!page.component ||
|
|
|
|
page.core ||
|
|
|
|
isComponentLoaded(this.hass, page.component)) &&
|
|
|
|
(!page.advancedOnly || showAdvanced)
|
|
|
|
);
|
|
|
|
|
|
|
|
return shownTabs.map(
|
2020-03-17 20:44:07 +01:00
|
|
|
(page) =>
|
|
|
|
html`
|
|
|
|
<div
|
|
|
|
class="tab ${classMap({
|
|
|
|
active: page === activeTab,
|
|
|
|
})}"
|
|
|
|
@click=${this._tabTapped}
|
|
|
|
.path=${page.path}
|
|
|
|
>
|
|
|
|
${this.narrow
|
|
|
|
? html`
|
|
|
|
<ha-icon .icon=${page.icon}></ha-icon>
|
|
|
|
`
|
|
|
|
: ""}
|
|
|
|
${!this.narrow || page === activeTab
|
|
|
|
? html`
|
|
|
|
<span class="name"
|
|
|
|
>${page.translationKey
|
|
|
|
? this.hass.localize(page.translationKey)
|
|
|
|
: name}</span
|
|
|
|
>
|
|
|
|
`
|
|
|
|
: ""}
|
|
|
|
<mwc-ripple></mwc-ripple>
|
|
|
|
</div>
|
|
|
|
`
|
2020-02-28 21:58:50 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2020-01-28 21:48:21 +01:00
|
|
|
protected updated(changedProperties: PropertyValues) {
|
|
|
|
super.updated(changedProperties);
|
|
|
|
if (changedProperties.has("route")) {
|
2020-03-17 20:44:07 +01:00
|
|
|
this._activeTab = this.tabs.find((tab) =>
|
2020-01-28 21:48:21 +01:00
|
|
|
this.route.prefix.includes(tab.path)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected render(): TemplateResult {
|
2020-02-28 21:58:50 +01:00
|
|
|
const tabs = this._getTabs(
|
|
|
|
this.tabs,
|
|
|
|
this._activeTab,
|
|
|
|
this.hass.userData?.showAdvanced,
|
|
|
|
this.hass.config.components,
|
|
|
|
this.hass.language
|
|
|
|
);
|
|
|
|
|
2020-01-28 21:48:21 +01:00
|
|
|
return html`
|
|
|
|
<div class="toolbar">
|
|
|
|
<ha-paper-icon-button-arrow-prev
|
|
|
|
aria-label="Back"
|
|
|
|
.hassio=${this.hassio}
|
|
|
|
@click=${this._backTapped}
|
|
|
|
></ha-paper-icon-button-arrow-prev>
|
2020-02-13 19:53:48 +01:00
|
|
|
${this.narrow
|
|
|
|
? html`
|
|
|
|
<div main-title><slot name="header"></slot></div>
|
|
|
|
`
|
|
|
|
: ""}
|
2020-02-28 21:58:50 +01:00
|
|
|
${tabs.length > 1 || !this.narrow
|
|
|
|
? html`
|
|
|
|
<div id="tabbar" class=${classMap({ "bottom-bar": this.narrow })}>
|
|
|
|
${tabs}
|
|
|
|
</div>
|
|
|
|
`
|
|
|
|
: ""}
|
2020-01-28 21:48:21 +01:00
|
|
|
<div id="toolbar-icon">
|
|
|
|
<slot name="toolbar-icon"></slot>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="content">
|
|
|
|
<slot></slot>
|
|
|
|
</div>
|
|
|
|
`;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2020-01-28 22:44:21 +01:00
|
|
|
height: 65px;
|
2020-01-28 21:48:21 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
#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%;
|
2020-01-28 22:44:21 +01:00
|
|
|
height: calc(100% - 65px);
|
2020-01-28 21:48:21 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|