mirror of
https://github.com/GeorgeSG/lovelace-time-picker-card.git
synced 2026-09-06 02:18:44 +00:00
Extract time-unit component. Refactor styles. Refactor error partial.
This commit is contained in:
@@ -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`<div class="time-unit">
|
||||
${this.renderStepChanger(Direction.UP)}
|
||||
<input
|
||||
class="time-input"
|
||||
type="number"
|
||||
placeholder="MM"
|
||||
min="0"
|
||||
max="60"
|
||||
.value="${this.unit.toString()}"
|
||||
@change=${this.onInputChange}
|
||||
/>
|
||||
${this.renderStepChanger(Direction.DOWN)}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
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`
|
||||
<div class="time-picker-icon" @click=${() => this.onStepChangerClick(direction)}>
|
||||
<ha-icon .icon="mdi:arrow-${direction}"></ha-icon>
|
||||
<mwc-ripple id="ripple"></mwc-ripple>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -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)',
|
||||
};
|
||||
|
||||
+10
-45
@@ -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<void>): TemplateResult {
|
||||
const onInputChange = ({ target: { value } }: { target: HTMLInputElement }): void => {
|
||||
unit.setStringValue(value);
|
||||
serviceFn();
|
||||
};
|
||||
|
||||
return html`
|
||||
<div class="time-unit">
|
||||
${Partial.stepChanger(Direction.UP, unit, serviceFn)}
|
||||
<input
|
||||
class="time-input"
|
||||
type="number"
|
||||
placeholder="MM"
|
||||
min="0"
|
||||
max="60"
|
||||
.value="${unit.toString()}"
|
||||
@change=${onInputChange}
|
||||
/>
|
||||
${Partial.stepChanger(Direction.DOWN, unit, serviceFn)}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private static stepChanger(
|
||||
direction: Direction,
|
||||
unit: TimeUnit,
|
||||
serviceFn: () => Promise<void>
|
||||
): TemplateResult {
|
||||
const onIconClick = (): void => {
|
||||
unit.stepUpdate(direction);
|
||||
serviceFn();
|
||||
};
|
||||
|
||||
return html`
|
||||
<div class="time-picker-icon" @click=${onIconClick}>
|
||||
<ha-icon .icon="mdi:arrow-${direction}"></ha-icon>
|
||||
<mwc-ripple id="ripple"></mwc-ripple>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static error(error: string, origConfig: TimePickerCardConfig): TemplateResult {
|
||||
const config = { error, origConfig };
|
||||
return html`<hui-error-card ._config="${config}"></hui-error-card>`;
|
||||
const errorCard = document.createElement('hui-error-card') as LovelaceCard;
|
||||
errorCard.setConfig({
|
||||
type: 'error',
|
||||
error,
|
||||
origConfig,
|
||||
});
|
||||
|
||||
return html`${errorCard}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
`;
|
||||
+30
-13
@@ -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`
|
||||
<ha-card class="time-picker-ha-card">
|
||||
${Partial.unit(this.hour, this.serviceFn.bind(this))}
|
||||
<time-unit .unit=${this.hour} @update=${this.serviceFn.bind(this)}></time-unit>
|
||||
<div class="time-separator">:</div>
|
||||
${Partial.unit(this.minute, this.serviceFn.bind(this))}
|
||||
<time-unit .unit=${this.minute} @update=${this.serviceFn.bind(this)}></time-unit>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user