From fdc9c5bd22db274b28a98f43ca6bc1cffda1a4a3 Mon Sep 17 00:00:00 2001 From: Georgi Gardev Date: Tue, 5 May 2020 02:47:04 +0300 Subject: [PATCH] Extract time-unit component. Refactor styles. Refactor error partial. --- src/components/time-unit.ts | 109 ++++++++++++++++++++++++++++++++++++ src/const.ts | 4 ++ src/partials.ts | 55 ++++-------------- src/styles.ts | 60 -------------------- src/time-picker-card.ts | 43 +++++++++----- src/types.ts | 4 +- 6 files changed, 156 insertions(+), 119 deletions(-) create mode 100644 src/components/time-unit.ts delete mode 100644 src/styles.ts diff --git a/src/components/time-unit.ts b/src/components/time-unit.ts new file mode 100644 index 0000000..77b5407 --- /dev/null +++ b/src/components/time-unit.ts @@ -0,0 +1,109 @@ +import { + css, + CSSResult, + customElement, + html, + LitElement, + property, + TemplateResult, +} from 'lit-element'; +import { TimeUnit } from '../models'; +import { Direction } from '../types'; + +@customElement('time-unit') +export class TimeUnitComponent extends LitElement { + @property() private unit?: TimeUnit; + + render(): TemplateResult { + if (!this.unit) { + throw new Error('Missing unit in time-unit. This should never happen :)'); + } + + return html`
+ ${this.renderStepChanger(Direction.UP)} + + ${this.renderStepChanger(Direction.DOWN)} +
`; + } + + onInputChange({ target: { value } }: { target: HTMLInputElement }): void { + this.unit!.setStringValue(value); + this.emitUpdate(); + } + + onStepChangerClick(direction: Direction): void { + this.unit!.stepUpdate(direction); + this.emitUpdate(); + } + + private emitUpdate(): void { + const event = new CustomEvent('update'); + this.dispatchEvent(event); + } + + private renderStepChanger(direction: Direction): TemplateResult { + return html` +
this.onStepChangerClick(direction)}> + + +
+ `; + } + + static get styles(): CSSResult { + return css` + .time-unit { + display: flex; + flex-direction: column; + align-items: center; + padding: 0 8px; + } + + .time-picker-icon { + width: 30px; + padding: 8px; + text-align: center; + cursor: pointer; + } + + .time-input { + width: 30px; + padding: 8px 8px 6px; + background: var(--time-picker-card-background-color); + border: 0; + border-bottom: 2px solid var(--time-picker-card-background-color); + color: var(--text-color, #fff); + text-align: center; + font-size: 1em; + -moz-appearance: textfield; + + transition: border-color 0.2s ease-in-out; + } + + .time-input:focus { + outline: none; + } + + .time-input:invalid { + box-shadow: none; + outline: none; + border: 0; + border-bottom: 2px solid red; + } + + .time-input::-webkit-inner-spin-button, + .time-input::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; + } + `; + } +} diff --git a/src/const.ts b/src/const.ts index 54dd41d..7cfc5f0 100644 --- a/src/const.ts +++ b/src/const.ts @@ -1,3 +1,7 @@ import * as pkg from '../package.json'; export const CARD_VERSION = pkg.version; + +export const STYLE_VARIABLES = { + '--time-picker-card-background-color': 'rgb(37, 47, 68)', +}; diff --git a/src/partials.ts b/src/partials.ts index c4e6254..48c49da 100644 --- a/src/partials.ts +++ b/src/partials.ts @@ -1,51 +1,16 @@ import { html, TemplateResult } from 'lit-element'; -import { TimePickerCardConfig, Direction } from './types'; -import { TimeUnit } from './models'; +import { TimePickerCardConfig } from './types'; +import { LovelaceCard } from 'custom-card-helpers'; export class Partial { - static unit(unit: TimeUnit, serviceFn: () => Promise): TemplateResult { - const onInputChange = ({ target: { value } }: { target: HTMLInputElement }): void => { - unit.setStringValue(value); - serviceFn(); - }; - - return html` -
- ${Partial.stepChanger(Direction.UP, unit, serviceFn)} - - ${Partial.stepChanger(Direction.DOWN, unit, serviceFn)} -
- `; - } - - private static stepChanger( - direction: Direction, - unit: TimeUnit, - serviceFn: () => Promise - ): TemplateResult { - const onIconClick = (): void => { - unit.stepUpdate(direction); - serviceFn(); - }; - - return html` -
- - -
- `; - } - static error(error: string, origConfig: TimePickerCardConfig): TemplateResult { - const config = { error, origConfig }; - return html``; + const errorCard = document.createElement('hui-error-card') as LovelaceCard; + errorCard.setConfig({ + type: 'error', + error, + origConfig, + }); + + return html`${errorCard}`; } } diff --git a/src/styles.ts b/src/styles.ts deleted file mode 100644 index 72287de..0000000 --- a/src/styles.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { css } from 'lit-element'; - -export const styleVariables = { - '--time-picker-card-background-color': 'rgb(37, 47, 68)', -}; - -export const styles = css` - .time-picker-ha-card { - padding: 16px; - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - } - - .time-unit { - display: flex; - flex-direction: column; - align-items: center; - padding: 0 8px; - } - - .time-picker-icon { - width: 30px; - padding: 8px; - text-align: center; - cursor: pointer; - } - - .time-input { - width: 30px; - padding: 8px; - background: var(--time-picker-card-background-color); - border: 0; - color: var(--text-color, #fff); - text-align: center; - font-size: 1em; - } - - input[type='number']::-webkit-inner-spin-button, - input[type='number']::-webkit-outer-spin-button { - -webkit-appearance: none; - margin: 0; - } - - input[type='number'] { - -moz-appearance: textfield; - } - - input[type='number']:focus { - outline: none; - } - - input[type='number']:invalid { - box-shadow: none; - outline: none; - border: 0; - border-bottom: 2px solid red; - } -`; diff --git a/src/time-picker-card.ts b/src/time-picker-card.ts index d40c539..bb80da7 100644 --- a/src/time-picker-card.ts +++ b/src/time-picker-card.ts @@ -1,10 +1,18 @@ import { HomeAssistant } from 'custom-card-helpers'; import { HassEntity } from 'home-assistant-js-websocket'; -import { CSSResult, customElement, html, LitElement, property, TemplateResult } from 'lit-element'; -import { CARD_VERSION } from './const'; +import { + css, + CSSResult, + customElement, + html, + LitElement, + property, + TemplateResult, +} from 'lit-element'; +import './components/time-unit'; +import { CARD_VERSION, STYLE_VARIABLES } from './const'; import { Hour, Minute } from './models'; import { Partial } from './partials'; -import { styles, styleVariables } from './styles'; import { TimePickerCardConfig } from './types'; console.info( @@ -20,6 +28,14 @@ export class TimePickerCard extends LitElement { @property() private hour?: Hour; @property() private minute?: Minute; + connectedCallback(): void { + super.connectedCallback(); + + Object.entries(STYLE_VARIABLES).forEach(([variable, value]) => + this.style.setProperty(variable, value) + ); + } + private get entity(): HassEntity | undefined { if (!this.config) { return; @@ -44,15 +60,14 @@ export class TimePickerCard extends LitElement { ); } - this.setStyleVarialbes(); this.hour = new Hour(this.entity?.attributes.hour ?? 0, this.config.hour_step); this.minute = new Minute(this.entity?.attributes.minute ?? 0, this.config.minute_step); return html` - ${Partial.unit(this.hour, this.serviceFn.bind(this))} +
:
- ${Partial.unit(this.minute, this.serviceFn.bind(this))} +
`; } @@ -86,13 +101,15 @@ export class TimePickerCard extends LitElement { }); } - private setStyleVarialbes(): void { - Object.entries(styleVariables).forEach(([variable, value]) => - this.style.setProperty(variable, value) - ); - } - static get styles(): CSSResult { - return styles; + return css` + .time-picker-ha-card { + padding: 16px; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + } + `; } } diff --git a/src/types.ts b/src/types.ts index ce98d78..6046c9e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,6 @@ -export interface TimePickerCardConfig { +import { LovelaceCardConfig } from 'custom-card-helpers'; + +export interface TimePickerCardConfig extends LovelaceCardConfig { entity: string; hour_step?: number; minute_step?: number;