diff --git a/src/panels/lovelace/cards/hui-horizontal-stack-card.ts b/src/panels/lovelace/cards/hui-horizontal-stack-card.ts index e1427fbe1d..93d46f3e2c 100644 --- a/src/panels/lovelace/cards/hui-horizontal-stack-card.ts +++ b/src/panels/lovelace/cards/hui-horizontal-stack-card.ts @@ -1,4 +1,4 @@ -import { html, TemplateResult } from "lit-element"; +import { CSSResult, css } from "lit-element"; import { computeCardSize } from "../common/compute-card-size"; import { HuiStackCard } from "./hui-stack-card"; @@ -17,9 +17,10 @@ class HuiHorizontalStackCard extends HuiStackCard { return totalSize; } - protected renderStyle(): TemplateResult { - return html` - - `; + `, + ]; } } diff --git a/src/panels/lovelace/cards/hui-stack-card.ts b/src/panels/lovelace/cards/hui-stack-card.ts index bcd165470c..3d0a1b5fa7 100644 --- a/src/panels/lovelace/cards/hui-stack-card.ts +++ b/src/panels/lovelace/cards/hui-stack-card.ts @@ -1,18 +1,34 @@ -import { html, LitElement, TemplateResult, CSSResult, css } from "lit-element"; +import { + html, + LitElement, + TemplateResult, + CSSResult, + css, + property, +} from "lit-element"; import { createCardElement } from "../create-element/create-card-element"; -import { LovelaceCard } from "../types"; +import { LovelaceCard, LovelaceCardEditor } from "../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; import { HomeAssistant } from "../../../types"; import { StackCardConfig } from "./types"; export abstract class HuiStackCard extends LitElement implements LovelaceCard { - static get properties() { - return { - _config: {}, - }; + public static async getConfigElement(): Promise { + await import( + /* webpackChunkName: "hui-stack-card-editor" */ "../editor/config-elements/hui-stack-card-editor" + ); + return document.createElement("hui-stack-card-editor"); } + public static getStubConfig(): object { + return { cards: [] }; + } + + @property() protected _cards?: LovelaceCard[]; + @property() private _config?: StackCardConfig; + private _hass?: HomeAssistant; + set hass(hass: HomeAssistant) { this._hass = hass; @@ -24,9 +40,6 @@ export abstract class HuiStackCard extends LitElement implements LovelaceCard { element.hass = this._hass; } } - protected _cards?: LovelaceCard[]; - private _config?: StackCardConfig; - private _hass?: HomeAssistant; public abstract getCardSize(): number; @@ -42,12 +55,11 @@ export abstract class HuiStackCard extends LitElement implements LovelaceCard { } protected render(): TemplateResult { - if (!this._config) { + if (!this._config || !this._cards) { return html``; } return html` - ${this.renderStyle()} ${this._config.title ? html` ${this._config.title} @@ -57,9 +69,7 @@ export abstract class HuiStackCard extends LitElement implements LovelaceCard { `; } - protected abstract renderStyle(): TemplateResult; - - static get styles(): CSSResult { + static get sharedStyles(): CSSResult { return css` .card-header { color: var(--ha-card-header-color, --primary-text-color); diff --git a/src/panels/lovelace/cards/hui-vertical-stack-card.ts b/src/panels/lovelace/cards/hui-vertical-stack-card.ts index a36c37ea6b..c4107ef721 100644 --- a/src/panels/lovelace/cards/hui-vertical-stack-card.ts +++ b/src/panels/lovelace/cards/hui-vertical-stack-card.ts @@ -1,4 +1,4 @@ -import { html, TemplateResult } from "lit-element"; +import { CSSResult, css } from "lit-element"; import { computeCardSize } from "../common/compute-card-size"; import { HuiStackCard } from "./hui-stack-card"; @@ -18,9 +18,10 @@ class HuiVerticalStackCard extends HuiStackCard { return totalSize; } - protected renderStyle(): TemplateResult { - return html` - - `; + `, + ]; } } diff --git a/src/panels/lovelace/cards/types.ts b/src/panels/lovelace/cards/types.ts index a80103fcf9..3ad79336b0 100644 --- a/src/panels/lovelace/cards/types.ts +++ b/src/panels/lovelace/cards/types.ts @@ -243,6 +243,7 @@ export interface ShoppingListCardConfig extends LovelaceCardConfig { export interface StackCardConfig extends LovelaceCardConfig { cards: LovelaceCardConfig[]; + title?: string; } export interface ThermostatCardConfig extends LovelaceCardConfig { diff --git a/src/panels/lovelace/components/hui-card-options.ts b/src/panels/lovelace/components/hui-card-options.ts index 1223354fdd..f594d313c5 100644 --- a/src/panels/lovelace/components/hui-card-options.ts +++ b/src/panels/lovelace/components/hui-card-options.ts @@ -93,6 +93,10 @@ export class HuiCardOptions extends LitElement { static get styles(): CSSResult { return css` + :host(:hover) { + outline: 2px solid var(--primary-color); + } + ha-card { border-top-right-radius: 0; border-top-left-radius: 0; diff --git a/src/panels/lovelace/editor/config-elements/hui-stack-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-stack-card-editor.ts new file mode 100644 index 0000000000..ee9d8e7392 --- /dev/null +++ b/src/panels/lovelace/editor/config-elements/hui-stack-card-editor.ts @@ -0,0 +1,201 @@ +import { + html, + LitElement, + TemplateResult, + customElement, + property, + CSSResult, + css, +} from "lit-element"; +import "@polymer/paper-tabs"; + +import { struct } from "../../common/structs/struct"; +import { HomeAssistant } from "../../../../types"; +import { LovelaceCardEditor } from "../../types"; +import { StackCardConfig } from "../../cards/types"; +import { fireEvent } from "../../../../common/dom/fire_event"; + +const cardConfigStruct = struct({ + type: "string", + cards: ["any"], + title: "string?", +}); + +@customElement("hui-stack-card-editor") +export class HuiStackCardEditor extends LitElement + implements LovelaceCardEditor { + @property() public hass?: HomeAssistant; + @property() private _config?: StackCardConfig; + @property() private _selectedCard: number = 0; + + public setConfig(config: StackCardConfig): void { + this._config = cardConfigStruct(config); + } + + protected render(): TemplateResult { + if (!this.hass || !this._config) { + return html``; + } + const selected = this._selectedCard!; + const numcards = this._config.cards.length; + + return html` + + + + ${this._config.cards.map((_card, i) => { + return html` + + ${i + 1} + + `; + })} + + + + + + + + + + ${ + selected < numcards + ? html` + + + + + + + + + + ` + : html` + + ` + } + + + `; + } + + private _handleSelectedCard(ev) { + this._selectedCard = + ev.target.id === "add-card" + ? this._config!.cards.length + : parseInt(ev.target.selected, 10); + } + + private _handleConfigChanged(ev) { + ev.stopPropagation(); + if (!this._config) { + return; + } + this._config.cards[this._selectedCard] = ev.detail.config; + fireEvent(this, "config-changed", { config: this._config }); + } + + private _handleCardPicked(ev) { + ev.stopPropagation(); + if (!this._config) { + return; + } + const config = ev.detail.config; + this._config.cards.push(config); + fireEvent(this, "config-changed", { config: this._config }); + } + + private _handleDeleteCard() { + if (!this._config) { + return; + } + this._config.cards.splice(this._selectedCard, 1); + this._selectedCard = Math.max(0, this._selectedCard - 1); + fireEvent(this, "config-changed", { config: this._config }); + } + + private _handleMove(ev) { + if (!this._config) { + return; + } + const source = this._selectedCard; + const target = ev.target.id === "move-before" ? source - 1 : source + 1; + const card = this._config.cards.splice(this._selectedCard, 1)[0]; + this._config.cards.splice(target, 0, card); + this._selectedCard = target; + fireEvent(this, "config-changed", { config: this._config }); + } + + static get styles(): CSSResult { + return css` + .toolbar { + display: flex; + --paper-tabs-selection-bar-color: var(--primary-color); + --paper-tab-ink: var(--primary-color); + } + paper-tabs { + display: flex; + font-size: 14px; + flex-grow: 1; + } + #add-card { + max-width: 32px; + padding: 0; + } + + #card-options { + display: flex; + justify-content: flex-end; + width: 100%; + } + + #editor { + border: 1px solid var(--divider-color); + padding: 12px; + } + @media (max-width: 450px) { + #editor { + margin: 0 -12px; + } + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-stack-card-editor": HuiStackCardEditor; + } +}