From c15629b81bf52bab00b9b1299e7bd0225c495658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Sat, 10 Aug 2019 21:14:35 +0200 Subject: [PATCH] Various changes to card editor. (#3265) * Various changes to card editor. * Avoid crashing on bad yaml when creating a new card * Address review comments * Revert interface change * Avoid config loops. Nicer error behavior. --- .../editor/card-editor/hui-card-editor.ts | 281 ++++++++++ .../editor/card-editor/hui-card-picker.ts | 12 +- .../card-editor/hui-dialog-edit-card.ts | 235 +++++++-- .../card-editor/hui-dialog-pick-card.ts | 88 ---- .../editor/card-editor/hui-edit-card.ts | 493 ------------------ 5 files changed, 491 insertions(+), 618 deletions(-) create mode 100644 src/panels/lovelace/editor/card-editor/hui-card-editor.ts delete mode 100644 src/panels/lovelace/editor/card-editor/hui-dialog-pick-card.ts delete mode 100644 src/panels/lovelace/editor/card-editor/hui-edit-card.ts diff --git a/src/panels/lovelace/editor/card-editor/hui-card-editor.ts b/src/panels/lovelace/editor/card-editor/hui-card-editor.ts new file mode 100644 index 0000000000..5e10eafeb6 --- /dev/null +++ b/src/panels/lovelace/editor/card-editor/hui-card-editor.ts @@ -0,0 +1,281 @@ +import { + html, + css, + LitElement, + TemplateResult, + CSSResult, + customElement, + property, +} from "lit-element"; + +import yaml from "js-yaml"; + +import "@material/mwc-button"; +import { HomeAssistant } from "../../../../types"; +import { LovelaceCardConfig } from "../../../../data/lovelace"; +import { LovelaceCardEditor } from "../../types"; +import { getCardElementTag } from "../../common/get-card-element-tag"; + +import "../../components/hui-yaml-editor"; +// This is not a duplicate import, one is for types, one is for element. +// tslint:disable-next-line +import { HuiYamlEditor } from "../../components/hui-yaml-editor"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import { EntityConfig } from "../../entity-rows/types"; + +declare global { + interface HASSDomEvents { + "entities-changed": { + entities: EntityConfig[]; + }; + "config-changed": { + config: LovelaceCardConfig; + error?: string; + }; + } +} + +export interface UIConfigChangedEvent extends Event { + detail: { + config: LovelaceCardConfig; + }; +} + +@customElement("hui-card-editor") +export class HuiCardEditor extends LitElement { + @property() public hass?: HomeAssistant; + + @property() private _yaml?: string; + @property() private _config?: LovelaceCardConfig; + @property() private _configElement?: LovelaceCardEditor; + @property() private _configElType?: string; + @property() private _GUImode: boolean = true; + // Error: Configuration broken - do not save + @property() private _error?: string; + // Warning: GUI editor can't handle configuration - ok to save + @property() private _warning?: string; + @property() private _loading: boolean = false; + + public get yaml(): string { + return this._yaml || ""; + } + public set yaml(_yaml: string) { + this._yaml = _yaml; + try { + this._config = yaml.safeLoad(this.yaml); + this._updateConfigElement(); + setTimeout(() => { + if (this._yamlEditor) { + this._yamlEditor.codemirror.refresh(); + } + }, 1); + this._error = undefined; + } catch (err) { + this._error = err.message; + } + fireEvent(this, "config-changed", { + config: this.value!, + error: this._error, + }); + } + + public get value(): LovelaceCardConfig | undefined { + return this._config; + } + public set value(config: LovelaceCardConfig | undefined) { + if (JSON.stringify(config) !== JSON.stringify(this._config || {})) { + this.yaml = yaml.safeDump(config); + } + } + + public get hasError(): boolean { + return this._error !== undefined; + } + + private get _yamlEditor(): HuiYamlEditor { + return this.shadowRoot!.querySelector("hui-yaml-editor")!; + } + + public toggleMode() { + this._GUImode = !this._GUImode; + } + + protected render(): TemplateResult { + return html` +
+ ${this._GUImode + ? html` +
+ ${this._loading + ? html` + + ` + : this._configElement} +
+ ` + : html` +
+ +
+ `} + ${this._error + ? html` +
+ ${this._error} +
+ ` + : ""} + ${this._warning + ? html` +
+ ${this._warning} +
+ ` + : ""} +
+ + + +
+
+ `; + } + + protected updated(changedProperties) { + super.updated(changedProperties); + + if (changedProperties.has("_GUImode")) { + if (this._GUImode === false) { + // Refresh code editor when switching to yaml mode + this._yamlEditor.codemirror.refresh(); + this._yamlEditor.codemirror.focus(); + } + fireEvent(this as HTMLElement, "iron-resize"); + } + } + + private _handleUIConfigChanged(ev: UIConfigChangedEvent) { + ev.stopPropagation(); + const config = ev.detail.config; + this.value = config; + } + private _handleYAMLChanged(ev) { + ev.stopPropagation(); + const newYaml = ev.detail.value; + if (newYaml !== this.yaml) { + this.yaml = newYaml; + } + } + + private async _updateConfigElement(): Promise { + if (!this.value) { + return; + } + + const cardType = this.value.type; + let configElement = this._configElement; + try { + this._error = undefined; + this._warning = undefined; + + if (this._configElType !== cardType) { + // If the card type has changed, we need to load a new GUI editor + if (!this.value.type) { + throw new Error("No card type defined"); + } + + const tag = getCardElementTag(cardType); + + // Check if the card type exists + const elClass = customElements.get(tag); + if (!elClass) { + throw new Error(`Unknown card type encountered: ${cardType}.`); + } + + this._loading = true; + // Check if a GUI editor exists + if (elClass && elClass.getConfigElement) { + configElement = await elClass.getConfigElement(); + } else { + configElement = undefined; + throw Error(`WARNING: No GUI editor available for: ${cardType}`); + } + + this._configElement = configElement; + this._configElType = cardType; + } + + // Setup GUI editor and check that it can handle the current config + try { + this._configElement!.setConfig(this.value); + } catch (err) { + throw Error(`WARNING: ${err.message}`); + } + + // Perform final setup + this._configElement!.hass = this.hass; + this._configElement!.addEventListener("config-changed", (ev) => + this._handleUIConfigChanged(ev as UIConfigChangedEvent) + ); + + return; + } catch (err) { + if (err.message.startsWith("WARNING:")) { + this._warning = err.message.substr(8); + } else { + this._error = err; + } + this._GUImode = false; + } finally { + this._loading = false; + fireEvent(this, "iron-resize"); + } + } + + static get styles(): CSSResult { + return css` + :host { + display: flex; + } + .wrapper { + width: 100%; + } + .gui-editor, + .yaml-editor { + padding: 8px 0px; + } + .error { + color: #ef5350; + } + .warning { + color: #ffa726; + } + .buttons { + text-align: right; + padding: 8px 0px; + } + paper-spinner { + display: block; + margin: auto; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-card-editor": HuiCardEditor; + } +} diff --git a/src/panels/lovelace/editor/card-editor/hui-card-picker.ts b/src/panels/lovelace/editor/card-editor/hui-card-picker.ts index 6caebb4255..33422e952d 100644 --- a/src/panels/lovelace/editor/card-editor/hui-card-picker.ts +++ b/src/panels/lovelace/editor/card-editor/hui-card-picker.ts @@ -12,6 +12,7 @@ import { HomeAssistant } from "../../../../types"; import { LovelaceCardConfig } from "../../../../data/lovelace"; import { getCardElementTag } from "../../common/get-card-element-tag"; import { CardPickTarget } from "../types"; +import { fireEvent } from "../../../../common/dom/fire_event"; const cards = [ { name: "Alarm panel", type: "alarm-panel" }, @@ -60,6 +61,9 @@ export class HuiCardPicker extends LitElement { `; })} +
+ MANUAL CARD +
`; } @@ -85,6 +89,12 @@ export class HuiCardPicker extends LitElement { ]; } + private _manualPicked(): void { + fireEvent(this, "config-changed", { + config: { type: "" }, + }); + } + private _cardPicked(ev: Event): void { const type = (ev.currentTarget! as CardPickTarget).type; const tag = getCardElementTag(type); @@ -97,7 +107,7 @@ export class HuiCardPicker extends LitElement { config = { ...config, ...cardConfig }; } - this.cardPicked!(config); + fireEvent(this, "config-changed", { config }); } } diff --git a/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts b/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts index c0a058aeca..4ef5ea2eee 100644 --- a/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts +++ b/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts @@ -1,7 +1,9 @@ import { + css, html, LitElement, TemplateResult, + CSSResultArray, customElement, property, } from "lit-element"; @@ -9,11 +11,17 @@ import { import { HomeAssistant } from "../../../../types"; import { HASSDomEvent } from "../../../../common/dom/fire_event"; import { LovelaceCardConfig } from "../../../../data/lovelace"; -import "./hui-edit-card"; -import "./hui-dialog-pick-card"; +import "./hui-card-editor"; +// tslint:disable-next-line +import { HuiCardEditor } from "./hui-card-editor"; +import "./hui-card-preview"; +import "./hui-card-picker"; import { EditCardDialogParams } from "./show-edit-card-dialog"; import { addCard, replaceCard } from "../config-util"; +import "../../../../components/dialog/ha-paper-dialog"; +import { haStyleDialog } from "../../../../resources/styles"; + declare global { // for fire event interface HASSDomEvents { @@ -33,72 +41,227 @@ export class HuiDialogEditCard extends LitElement { @property() private _cardConfig?: LovelaceCardConfig; - @property() private _newCard?: boolean; - - constructor() { - super(); - this._cardPicked = this._cardPicked.bind(this); - this._cancel = this._cancel.bind(this); - this._save = this._save.bind(this); - } + @property() private _saving: boolean = false; + @property() private _error?: string; public async showDialog(params: EditCardDialogParams): Promise { this._params = params; const [view, card] = params.path; - this._newCard = card !== undefined ? false : true; this._cardConfig = card !== undefined ? params.lovelace.config.views[view].cards![card] : undefined; } + private get _cardEditorEl(): HuiCardEditor | null { + return this.shadowRoot!.querySelector("hui-card-editor"); + } + protected render(): TemplateResult | void { if (!this._params) { return html``; } - if (!this._cardConfig) { - // Card picker - return html` - - `; - } + return html` - - + +

+ ${this.hass!.localize("ui.panel.lovelace.editor.edit_card.header")} +

+ + ${this._cardConfig === undefined + ? html` + + ` + : html` +
+
+ +
+
+ + ${this._error + ? html` + + ` + : ``} +
+
+ `} +
+
+ + ${this.hass!.localize("ui.common.cancel")} + + + ${this._saving + ? html` + + ` + : this.hass!.localize("ui.common.save")} + +
+
`; } - private _cardPicked(cardConf: LovelaceCardConfig): void { - this._cardConfig = cardConf; + static get styles(): CSSResultArray { + return [ + haStyleDialog, + css` + :host { + --code-mirror-max-height: calc(100vh - 176px); + } + + @media all and (max-width: 450px), all and (max-height: 500px) { + /* overrule the ha-style-dialog max-height on small screens */ + ha-paper-dialog { + max-height: 100%; + height: 100%; + } + } + + @media all and (min-width: 660px) { + ha-paper-dialog { + width: 845px; + } + } + + ha-paper-dialog { + max-width: 845px; + } + + .center { + margin-left: auto; + margin-right: auto; + } + + .content { + display: flex; + flex-direction: column; + margin: 0 -10px; + } + .content hui-card-preview { + margin: 4px auto; + max-width: 390px; + } + .content .element-editor { + margin: 0 10px; + } + + @media (min-width: 1200px) { + ha-paper-dialog { + max-width: none; + width: 1000px; + } + + .content { + flex-direction: row; + } + .content > * { + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; + min-width: 0; + } + .content hui-card-preview { + padding: 8px 0; + margin: auto 10px; + max-width: 500px; + } + } + + mwc-button paper-spinner { + width: 14px; + height: 14px; + margin-right: 20px; + } + .hidden { + display: none; + } + .element-editor { + margin-bottom: 8px; + } + .blur { + filter: blur(2px) grayscale(100%); + } + .element-preview { + position: relative; + } + .element-preview paper-spinner { + top: 50%; + left: 50%; + position: absolute; + z-index: 10; + } + hui-card-preview { + padding-top: 8px; + margin-bottom: 4px; + display: block; + width: 100%; + } + `, + ]; } - private _cancel(): void { + private _handleConfigChanged(ev) { + this._cardConfig = ev.detail.config; + this._error = ev.detail.error; + } + + private _close(): void { this._params = undefined; this._cardConfig = undefined; + this._error = undefined; } - private async _save(cardConf: LovelaceCardConfig): Promise { + private get _canSave(): boolean { + if (this._saving) { + return false; + } + if (this._cardConfig === undefined) { + return false; + } + if (this._cardEditorEl && this._cardEditorEl.hasError) { + return false; + } + return true; + } + + private async _save(): Promise { const lovelace = this._params!.lovelace; + this._saving = true; await lovelace.saveConfig( this._params!.path.length === 1 - ? addCard(lovelace.config, this._params!.path as [number], cardConf) + ? addCard( + lovelace.config, + this._params!.path as [number], + this._cardConfig! + ) : replaceCard( lovelace.config, this._params!.path as [number, number], - cardConf + this._cardConfig! ) ); + this._saving = false; + this._close(); } } diff --git a/src/panels/lovelace/editor/card-editor/hui-dialog-pick-card.ts b/src/panels/lovelace/editor/card-editor/hui-dialog-pick-card.ts deleted file mode 100644 index 49d80a6fd7..0000000000 --- a/src/panels/lovelace/editor/card-editor/hui-dialog-pick-card.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { - html, - css, - LitElement, - TemplateResult, - CSSResult, - customElement, -} from "lit-element"; -import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable"; - -import "../../../../components/dialog/ha-paper-dialog"; - -import { haStyleDialog } from "../../../../resources/styles"; - -import "./hui-card-picker"; -import { HomeAssistant } from "../../../../types"; -import { LovelaceCardConfig } from "../../../../data/lovelace"; - -@customElement("hui-dialog-pick-card") -export class HuiDialogPickCard extends LitElement { - public hass?: HomeAssistant; - public cardPicked?: (cardConf: LovelaceCardConfig) => void; - public closeDialog?: () => void; - - protected render(): TemplateResult | void { - return html` - -

- ${this.hass!.localize("ui.panel.lovelace.editor.edit_card.header")} -

- - - -
- MANUAL CARD -
-
- `; - } - - private _openedChanged(ev): void { - if (!ev.detail.value) { - this.closeDialog!(); - } - } - - private _skipPick() { - this.cardPicked!({ type: "" }); - } - - static get styles(): CSSResult[] { - return [ - haStyleDialog, - css` - @media all and (max-width: 450px), all and (max-height: 500px) { - /* overrule the ha-style-dialog max-height on small screens */ - ha-paper-dialog { - max-height: 100%; - height: 100%; - } - } - - @media all and (min-width: 660px) { - ha-paper-dialog { - width: 650px; - } - } - - ha-paper-dialog { - max-width: 650px; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hui-dialog-pick-card": HuiDialogPickCard; - } -} diff --git a/src/panels/lovelace/editor/card-editor/hui-edit-card.ts b/src/panels/lovelace/editor/card-editor/hui-edit-card.ts deleted file mode 100644 index efe7ce09ac..0000000000 --- a/src/panels/lovelace/editor/card-editor/hui-edit-card.ts +++ /dev/null @@ -1,493 +0,0 @@ -import { - html, - css, - LitElement, - PropertyValues, - TemplateResult, - CSSResult, - customElement, - property, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; -import yaml from "js-yaml"; - -import { haStyleDialog } from "../../../../resources/styles"; - -import "@polymer/paper-spinner/paper-spinner"; -import "@polymer/paper-dialog/paper-dialog"; -import "../../../../components/dialog/ha-paper-dialog"; -// This is not a duplicate import, one is for types, one is for element. -// tslint:disable-next-line -import { HaPaperDialog } from "../../../../components/dialog/ha-paper-dialog"; -import "@material/mwc-button"; -import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable"; -import { HomeAssistant } from "../../../../types"; -import { LovelaceCardConfig } from "../../../../data/lovelace"; -import { fireEvent } from "../../../../common/dom/fire_event"; - -import "../../components/hui-yaml-editor"; -// This is not a duplicate import, one is for types, one is for element. -// tslint:disable-next-line -import { HuiYamlEditor } from "../../components/hui-yaml-editor"; -import "./hui-card-preview"; -// This is not a duplicate import, one is for types, one is for element. -// tslint:disable-next-line -import { HuiCardPreview } from "./hui-card-preview"; -import { LovelaceCardEditor, Lovelace } from "../../types"; -import { ConfigError } from "../types"; -import { EntityConfig } from "../../entity-rows/types"; -import { getCardElementTag } from "../../common/get-card-element-tag"; -import { afterNextRender } from "../../../../common/util/render-status"; - -declare global { - interface HASSDomEvents { - "entities-changed": { - entities: EntityConfig[]; - }; - "config-changed": { - config: LovelaceCardConfig; - }; - } -} - -@customElement("hui-edit-card") -export class HuiEditCard extends LitElement { - @property() public hass?: HomeAssistant; - - @property() public cardConfig?: LovelaceCardConfig; - - public lovelace?: Lovelace; - - public closeDialog?: () => void; - - public saveCard?: (cardConf: LovelaceCardConfig) => Promise; - - public newCard?: boolean; - - @property() private _configElement?: LovelaceCardEditor | null; - - @property() private _uiEditor?: boolean; - - @property() private _cardConfig?: LovelaceCardConfig; - - @property() private _configState?: string; - - @property() private _loading?: boolean; - - @property() private _saving: boolean; - - @property() private _errorMsg?: TemplateResult; - - private get _dialog(): HaPaperDialog { - return this.shadowRoot!.querySelector("ha-paper-dialog")!; - } - - private get _previewEl(): HuiCardPreview { - return this.shadowRoot!.querySelector("hui-card-preview")!; - } - - // tslint:disable-next-line - private __cardYaml: string | undefined; - - private get _cardYaml(): string | undefined { - if (!this.__cardYaml) { - this.__cardYaml = yaml.safeDump(this._cardConfig); - } - return this.__cardYaml; - } - - private set _cardYaml(yml: string | undefined) { - this.__cardYaml = yml; - } - - public constructor() { - super(); - this._saving = false; - } - - protected updated(changedProperties: PropertyValues): void { - super.updated(changedProperties); - - if (!changedProperties.has("cardConfig")) { - return; - } - - this._cardConfig = undefined; - this._cardYaml = undefined; - this._configState = "OK"; - this._uiEditor = true; - this._errorMsg = undefined; - this._configElement = undefined; - - this._loading = true; - this._loadConfigElement(this.cardConfig!); - } - - protected render(): TemplateResult | void { - let content; - let preview; - if (this._configElement !== undefined) { - content = html` -
- ${this._uiEditor - ? this._configElement - : html` - - `} -
- `; - - preview = html` - - `; - } - - return html` - -

- ${this.hass!.localize("ui.panel.lovelace.editor.edit_card.header")} -

- - - ${this._errorMsg - ? html` -
${this._errorMsg}
- ` - : ""} -
${content}${preview}
-
- ${!this._loading - ? html` -
- ${this.hass!.localize( - "ui.panel.lovelace.editor.edit_card.toggle_editor" - )} - ${this.hass!.localize("ui.common.cancel")} - - - ${this.hass!.localize("ui.common.save")} - -
- ` - : ""} -
- `; - } - - private async _loadedDialog(): Promise { - await this.updateComplete; - this._loading = false; - this._resizeDialog(); - if (!this._uiEditor) { - afterNextRender(() => { - this.yamlEditor.codemirror.refresh(); - this._resizeDialog(); - this.yamlEditor.codemirror.focus(); - }); - } - } - - private async _resizeDialog(): Promise { - await this.updateComplete; - fireEvent(this._dialog as HTMLElement, "iron-resize"); - } - - private async _save(): Promise { - if (!this._isConfigValid()) { - alert("Your config is not valid, please fix your config before saving."); - return; - } - - if (!this._isConfigChanged()) { - this.closeDialog!(); - return; - } - - this._saving = true; - - try { - await this.saveCard!(this._cardConfig!); - this._cardYaml = undefined; - this.closeDialog!(); - } catch (err) { - alert(`Saving failed: ${err.message}`); - } finally { - this._saving = false; - } - } - - private _handleYamlChanged(ev: CustomEvent): void { - try { - this._cardConfig = yaml.safeLoad(ev.detail.value); - this._updatePreview(this._cardConfig!); - this._configState = "OK"; - } catch (err) { - this._configState = "YAML_ERROR"; - this._setPreviewError({ - type: "YAML Error", - message: err, - }); - } - } - - private _handleUIConfigChanged(value: LovelaceCardConfig): void { - this._cardConfig = value; - this._updatePreview(value); - } - - private async _updatePreview(config: LovelaceCardConfig): Promise { - await this.updateComplete; - - if (!this._previewEl) { - return; - } - - this._previewEl.config = config; - - if (this._loading) { - this._loadedDialog(); - } else { - this._resizeDialog(); - } - } - - private _setPreviewError(error: ConfigError): void { - if (!this._previewEl) { - return; - } - this._previewEl.error = error; - - this._resizeDialog(); - } - - private async _toggleEditor(): Promise { - this._cardYaml = undefined; - if (this._uiEditor) { - this._uiEditor = false; - } else if (this._configElement) { - const success = await this._loadConfigElement(this._cardConfig!); - if (!success) { - this._loadedDialog(); - } else { - this._uiEditor = true; - this._configElement.setConfig(this._cardConfig!); - } - } - this._resizeDialog(); - } - - private _isConfigValid(): boolean { - if (!this._cardConfig) { - return false; - } - if (this._configState === "OK") { - return true; - } else { - return false; - } - } - - private _isConfigChanged(): boolean { - if (this.newCard) { - return true; - } - return JSON.stringify(this._cardConfig) !== JSON.stringify(this.cardConfig); - } - - private async _loadConfigElement(conf: LovelaceCardConfig): Promise { - if (!conf) { - return false; - } - - this._errorMsg = undefined; - this._loading = true; - this._configElement = undefined; - - const tag = getCardElementTag(conf.type); - - const elClass = customElements.get(tag); - let configElement; - - this._cardConfig = conf; - - if (elClass && elClass.getConfigElement) { - configElement = await elClass.getConfigElement(); - } else { - this._updatePreview(conf); - this._uiEditor = false; - this._configElement = null; - return false; - } - - try { - configElement.setConfig(conf); - } catch (err) { - this._errorMsg = html` - Your config is not supported by the UI editor:
${err.message}
Falling back to YAML editor. - `; - this._updatePreview(conf); - this._uiEditor = false; - this._configElement = null; - return false; - } - - configElement.hass = this.hass; - configElement.addEventListener("config-changed", (ev) => - this._handleUIConfigChanged(ev.detail.config) - ); - this._configElement = configElement; - await this.updateComplete; - this._updatePreview(conf); - return true; - } - - private _openedChanged(ev): void { - if (!ev.detail.value) { - this.closeDialog!(); - } - } - - private get yamlEditor(): HuiYamlEditor { - return this.shadowRoot!.querySelector("hui-yaml-editor")!; - } - - static get styles(): CSSResult[] { - return [ - haStyleDialog, - css` - :host { - --code-mirror-max-height: calc(100vh - 176px); - } - - @media all and (max-width: 450px), all and (max-height: 500px) { - /* overrule the ha-style-dialog max-height on small screens */ - ha-paper-dialog { - max-height: 100%; - height: 100%; - } - } - - @media all and (min-width: 660px) { - ha-paper-dialog { - width: 845px; - } - } - - ha-paper-dialog { - max-width: 845px; - } - - .center { - margin-left: auto; - margin-right: auto; - } - - .content { - display: flex; - flex-direction: column; - margin: 0 -10px; - } - .content hui-card-preview { - margin-top: 16px; - margin: 0 auto; - max-width: 390px; - } - .content .element-editor { - margin: 0 10px; - } - - @media (min-width: 1200px) { - ha-paper-dialog { - max-width: none; - width: 1000px; - } - - .content { - flex-direction: row; - } - .content > * { - flex-basis: 0; - flex-grow: 1; - flex-shrink: 1; - min-width: 0; - } - .content hui-card-preview { - padding-top: 0; - margin: 0 10px; - max-width: 490px; - } - } - - .margin-bot { - margin-bottom: 24px; - } - mwc-button paper-spinner { - width: 14px; - height: 14px; - margin-right: 20px; - } - paper-spinner { - display: none; - } - paper-spinner[active] { - display: block; - } - .hidden { - display: none; - } - .element-editor { - margin-bottom: 8px; - } - .error { - color: #ef5350; - border-bottom: 1px solid #ef5350; - } - hui-card-preview { - padding-top: 8px; - margin-bottom: 4px; - display: block; - } - .toggle-button { - margin-right: auto; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hui-edit-card": HuiEditCard; - } -}