321 lines
10 KiB
TypeScript
321 lines
10 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
/* eslint-disable @typescript-eslint/camelcase */
|
|
import {
|
|
LitElement,
|
|
html,
|
|
customElement,
|
|
property,
|
|
TemplateResult,
|
|
CSSResult,
|
|
css,
|
|
internalProperty,
|
|
} from 'lit-element';
|
|
import { HomeAssistant, fireEvent, LovelaceCardEditor, ActionConfig } from 'custom-card-helpers';
|
|
|
|
import { BoilerplateCardConfig } from './types';
|
|
|
|
const options = {
|
|
required: {
|
|
icon: 'tune',
|
|
name: 'Required',
|
|
secondary: 'Required options for this card to function',
|
|
show: true,
|
|
},
|
|
actions: {
|
|
icon: 'gesture-tap-hold',
|
|
name: 'Actions',
|
|
secondary: 'Perform actions based on tapping/clicking',
|
|
show: false,
|
|
options: {
|
|
tap: {
|
|
icon: 'gesture-tap',
|
|
name: 'Tap',
|
|
secondary: 'Set the action to perform on tap',
|
|
show: false,
|
|
},
|
|
hold: {
|
|
icon: 'gesture-tap-hold',
|
|
name: 'Hold',
|
|
secondary: 'Set the action to perform on hold',
|
|
show: false,
|
|
},
|
|
double_tap: {
|
|
icon: 'gesture-double-tap',
|
|
name: 'Double Tap',
|
|
secondary: 'Set the action to perform on double tap',
|
|
show: false,
|
|
},
|
|
},
|
|
},
|
|
appearance: {
|
|
icon: 'palette',
|
|
name: 'Appearance',
|
|
secondary: 'Customize the name, icon, etc',
|
|
show: false,
|
|
},
|
|
};
|
|
|
|
@customElement('boilerplate-card-editor')
|
|
export class BoilerplateCardEditor extends LitElement implements LovelaceCardEditor {
|
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
|
@internalProperty() private _config?: BoilerplateCardConfig;
|
|
@internalProperty() private _toggle?: boolean;
|
|
@internalProperty() private _helpers?: any;
|
|
private _initialized = false;
|
|
|
|
public setConfig(config: BoilerplateCardConfig): void {
|
|
this._config = config;
|
|
|
|
this.loadCardHelpers();
|
|
}
|
|
|
|
protected shouldUpdate(): boolean {
|
|
if (!this._initialized) {
|
|
this._initialize();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
get _name(): string {
|
|
return this._config?.name || '';
|
|
}
|
|
|
|
get _entity(): string {
|
|
return this._config?.entity || '';
|
|
}
|
|
|
|
get _show_warning(): boolean {
|
|
return this._config?.show_warning || false;
|
|
}
|
|
|
|
get _show_error(): boolean {
|
|
return this._config?.show_error || false;
|
|
}
|
|
|
|
get _tap_action(): ActionConfig {
|
|
return this._config?.tap_action || { action: 'more-info' };
|
|
}
|
|
|
|
get _hold_action(): ActionConfig {
|
|
return this._config?.hold_action || { action: 'none' };
|
|
}
|
|
|
|
get _double_tap_action(): ActionConfig {
|
|
return this._config?.double_tap_action || { action: 'none' };
|
|
}
|
|
|
|
protected render(): TemplateResult | void {
|
|
if (!this.hass || !this._helpers) {
|
|
return html``;
|
|
}
|
|
|
|
// The climate more-info has ha-switch and paper-dropdown-menu elements that are lazy loaded unless explicitly done here
|
|
this._helpers.importMoreInfoControl('climate');
|
|
|
|
// You can restrict on domain type
|
|
const entities = Object.keys(this.hass.states).filter(eid => eid.substr(0, eid.indexOf('.')) === 'sun');
|
|
|
|
return html`
|
|
<div class="card-config">
|
|
<div class="option" @click=${this._toggleOption} .option=${'required'}>
|
|
<div class="row">
|
|
<ha-icon .icon=${`mdi:${options.required.icon}`}></ha-icon>
|
|
<div class="title">${options.required.name}</div>
|
|
</div>
|
|
<div class="secondary">${options.required.secondary}</div>
|
|
</div>
|
|
${options.required.show
|
|
? html`
|
|
<div class="values">
|
|
<paper-dropdown-menu
|
|
label="Entity (Required)"
|
|
@value-changed=${this._valueChanged}
|
|
.configValue=${'entity'}
|
|
>
|
|
<paper-listbox slot="dropdown-content" .selected=${entities.indexOf(this._entity)}>
|
|
${entities.map(entity => {
|
|
return html`
|
|
<paper-item>${entity}</paper-item>
|
|
`;
|
|
})}
|
|
</paper-listbox>
|
|
</paper-dropdown-menu>
|
|
</div>
|
|
`
|
|
: ''}
|
|
<div class="option" @click=${this._toggleOption} .option=${'actions'}>
|
|
<div class="row">
|
|
<ha-icon .icon=${`mdi:${options.actions.icon}`}></ha-icon>
|
|
<div class="title">${options.actions.name}</div>
|
|
</div>
|
|
<div class="secondary">${options.actions.secondary}</div>
|
|
</div>
|
|
${options.actions.show
|
|
? html`
|
|
<div class="values">
|
|
<div class="option" @click=${this._toggleAction} .option=${'tap'}>
|
|
<div class="row">
|
|
<ha-icon .icon=${`mdi:${options.actions.options.tap.icon}`}></ha-icon>
|
|
<div class="title">${options.actions.options.tap.name}</div>
|
|
</div>
|
|
<div class="secondary">${options.actions.options.tap.secondary}</div>
|
|
</div>
|
|
${options.actions.options.tap.show
|
|
? html`
|
|
<div class="values">
|
|
<paper-item>Action Editors Coming Soon</paper-item>
|
|
</div>
|
|
`
|
|
: ''}
|
|
<div class="option" @click=${this._toggleAction} .option=${'hold'}>
|
|
<div class="row">
|
|
<ha-icon .icon=${`mdi:${options.actions.options.hold.icon}`}></ha-icon>
|
|
<div class="title">${options.actions.options.hold.name}</div>
|
|
</div>
|
|
<div class="secondary">${options.actions.options.hold.secondary}</div>
|
|
</div>
|
|
${options.actions.options.hold.show
|
|
? html`
|
|
<div class="values">
|
|
<paper-item>Action Editors Coming Soon</paper-item>
|
|
</div>
|
|
`
|
|
: ''}
|
|
<div class="option" @click=${this._toggleAction} .option=${'double_tap'}>
|
|
<div class="row">
|
|
<ha-icon .icon=${`mdi:${options.actions.options.double_tap.icon}`}></ha-icon>
|
|
<div class="title">${options.actions.options.double_tap.name}</div>
|
|
</div>
|
|
<div class="secondary">${options.actions.options.double_tap.secondary}</div>
|
|
</div>
|
|
${options.actions.options.double_tap.show
|
|
? html`
|
|
<div class="values">
|
|
<paper-item>Action Editors Coming Soon</paper-item>
|
|
</div>
|
|
`
|
|
: ''}
|
|
</div>
|
|
`
|
|
: ''}
|
|
<div class="option" @click=${this._toggleOption} .option=${'appearance'}>
|
|
<div class="row">
|
|
<ha-icon .icon=${`mdi:${options.appearance.icon}`}></ha-icon>
|
|
<div class="title">${options.appearance.name}</div>
|
|
</div>
|
|
<div class="secondary">${options.appearance.secondary}</div>
|
|
</div>
|
|
${options.appearance.show
|
|
? html`
|
|
<div class="values">
|
|
<paper-input
|
|
label="Name (Optional)"
|
|
.value=${this._name}
|
|
.configValue=${'name'}
|
|
@value-changed=${this._valueChanged}
|
|
></paper-input>
|
|
<br />
|
|
<ha-formfield .label=${`Toggle warning ${this._show_warning ? 'off' : 'on'}`}>
|
|
<ha-switch
|
|
.checked=${this._show_warning !== false}
|
|
.configValue=${'show_warning'}
|
|
@change=${this._valueChanged}
|
|
></ha-switch>
|
|
</ha-formfield>
|
|
<ha-formfield .label=${`Toggle error ${this._show_error ? 'off' : 'on'}`}>
|
|
<ha-switch
|
|
.checked=${this._show_error !== false}
|
|
.configValue=${'show_error'}
|
|
@change=${this._valueChanged}
|
|
></ha-switch>
|
|
</ha-formfield>
|
|
</div>
|
|
`
|
|
: ''}
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
private _initialize(): void {
|
|
if (this.hass === undefined) return;
|
|
if (this._config === undefined) return;
|
|
if (this._helpers === undefined) return;
|
|
this._initialized = true;
|
|
}
|
|
|
|
private async loadCardHelpers(): Promise<void> {
|
|
this._helpers = await (window as any).loadCardHelpers();
|
|
}
|
|
|
|
private _toggleAction(ev): void {
|
|
this._toggleThing(ev, options.actions.options);
|
|
}
|
|
|
|
private _toggleOption(ev): void {
|
|
this._toggleThing(ev, options);
|
|
}
|
|
|
|
private _toggleThing(ev, optionList): void {
|
|
const show = !optionList[ev.target.option].show;
|
|
for (const [key] of Object.entries(optionList)) {
|
|
optionList[key].show = false;
|
|
}
|
|
optionList[ev.target.option].show = show;
|
|
this._toggle = !this._toggle;
|
|
}
|
|
|
|
private _valueChanged(ev): void {
|
|
if (!this._config || !this.hass) {
|
|
return;
|
|
}
|
|
const target = ev.target;
|
|
if (this[`_${target.configValue}`] === target.value) {
|
|
return;
|
|
}
|
|
if (target.configValue) {
|
|
if (target.value === '') {
|
|
delete this._config[target.configValue];
|
|
} else {
|
|
this._config = {
|
|
...this._config,
|
|
[target.configValue]: target.checked !== undefined ? target.checked : target.value,
|
|
};
|
|
}
|
|
}
|
|
fireEvent(this, 'config-changed', { config: this._config });
|
|
}
|
|
|
|
static get styles(): CSSResult {
|
|
return css`
|
|
.option {
|
|
padding: 4px 0px;
|
|
cursor: pointer;
|
|
}
|
|
.row {
|
|
display: flex;
|
|
margin-bottom: -14px;
|
|
pointer-events: none;
|
|
}
|
|
.title {
|
|
padding-left: 16px;
|
|
margin-top: -6px;
|
|
pointer-events: none;
|
|
}
|
|
.secondary {
|
|
padding-left: 40px;
|
|
color: var(--secondary-text-color);
|
|
pointer-events: none;
|
|
}
|
|
.values {
|
|
padding-left: 16px;
|
|
background: var(--secondary-background-color);
|
|
display: grid;
|
|
}
|
|
ha-formfield {
|
|
padding-bottom: 8px;
|
|
}
|
|
`;
|
|
}
|
|
}
|