mirror of
https://github.com/GeorgeSG/lovelace-time-picker-card.git
synced 2026-11-05 12:18:45 +00:00
Add name position option. Refactor types
This commit is contained in:
@@ -13,7 +13,8 @@
|
|||||||
"rules": {
|
"rules": {
|
||||||
"@typescript-eslint/camelcase": 0,
|
"@typescript-eslint/camelcase": 0,
|
||||||
"@typescript-eslint/no-non-null-assertion": 0,
|
"@typescript-eslint/no-non-null-assertion": 0,
|
||||||
"@typescript-eslint/explicit-function-return-type": [1, { "allowExpressions": true }]
|
"@typescript-eslint/explicit-function-return-type": [1, { "allowExpressions": true }],
|
||||||
|
"@typescript-eslint/no-namespace": 0
|
||||||
},
|
},
|
||||||
"ignorePatterns": ["dist/", "node_modules/", "*.js"]
|
"ignorePatterns": ["dist/", "node_modules/", "*.js"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from 'lit-element';
|
} from 'lit-element';
|
||||||
import { ClassInfo, classMap } from 'lit-html/directives/class-map';
|
import { ClassInfo, classMap } from 'lit-html/directives/class-map';
|
||||||
import { Period, LayoutHourMode } from '../types';
|
import { Layout, Period } from '../types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders a Time Period selector with an input for a value and two arrows for step-chaning
|
* Renders a Time Period selector with an input for a value and two arrows for step-chaning
|
||||||
@@ -19,7 +19,7 @@ export class TimePeriodComponent extends LitElement {
|
|||||||
static readonly EVENT_TOGGLE = 'toggle';
|
static readonly EVENT_TOGGLE = 'toggle';
|
||||||
|
|
||||||
@property() private period!: Period;
|
@property() private period!: Period;
|
||||||
@property() private mode!: LayoutHourMode;
|
@property() private mode!: Layout.HourMode;
|
||||||
|
|
||||||
private get amClass(): ClassInfo {
|
private get amClass(): ClassInfo {
|
||||||
return { 'time-period': true, active: this.period === Period.AM };
|
return { 'time-period': true, active: this.period === Period.AM };
|
||||||
|
|||||||
+3
-1
@@ -1,4 +1,5 @@
|
|||||||
import * as pkg from '../package.json';
|
import * as pkg from '../package.json';
|
||||||
|
import { Layout } from './types';
|
||||||
|
|
||||||
export const CARD_VERSION = pkg.version;
|
export const CARD_VERSION = pkg.version;
|
||||||
export const CARD_SIZE = 3;
|
export const CARD_SIZE = 3;
|
||||||
@@ -9,4 +10,5 @@ export const ENTITY_DOMAIN = 'input_datetime';
|
|||||||
export const DEFAULT_HOUR_STEP = 1;
|
export const DEFAULT_HOUR_STEP = 1;
|
||||||
export const DEFAULT_MINUTE_STEP = 5;
|
export const DEFAULT_MINUTE_STEP = 5;
|
||||||
export const DEFAULT_LAYOUT_HOUR_MODE = 'double';
|
export const DEFAULT_LAYOUT_HOUR_MODE = 'double';
|
||||||
export const DEFAULT_LAYOUT_ALIGN = 'center';
|
export const DEFAULT_LAYOUT_ALIGN_CONTROLS = Layout.AlignControls.CENTER;
|
||||||
|
export const DEFAULT_LAYOUT_NAME = Layout.Name.HEADER;
|
||||||
|
|||||||
+46
-24
@@ -13,14 +13,14 @@ import {
|
|||||||
DEFAULT_HOUR_STEP,
|
DEFAULT_HOUR_STEP,
|
||||||
DEFAULT_MINUTE_STEP,
|
DEFAULT_MINUTE_STEP,
|
||||||
ENTITY_DOMAIN,
|
ENTITY_DOMAIN,
|
||||||
DEFAULT_LAYOUT_ALIGN,
|
DEFAULT_LAYOUT_ALIGN_CONTROLS,
|
||||||
|
DEFAULT_LAYOUT_NAME,
|
||||||
} from './const';
|
} from './const';
|
||||||
import { HourMode, LayoutHourMode, TimePickerCardConfig } from './types';
|
import { TimePickerCardConfig, Layout, HourMode } from './types';
|
||||||
|
|
||||||
@customElement('time-picker-card-editor')
|
@customElement('time-picker-card-editor')
|
||||||
export class TimePickerCardEditor extends LitElement implements LovelaceCardEditor {
|
export class TimePickerCardEditor extends LitElement implements LovelaceCardEditor {
|
||||||
private static readonly NUMBER_PROPERTIES = ['hour_step', 'minute_step', 'hour_mode'];
|
private static readonly NUMBER_PROPERTIES = ['hour_step', 'minute_step', 'hour_mode'];
|
||||||
private static readonly LAYOUT_ALIGN_VALUES = ['left', 'center', 'right'];
|
|
||||||
private static readonly CONFIG_CHANGED_EVENT = 'config-changed';
|
private static readonly CONFIG_CHANGED_EVENT = 'config-changed';
|
||||||
|
|
||||||
@property({ type: Object }) hass!: HomeAssistant;
|
@property({ type: Object }) hass!: HomeAssistant;
|
||||||
@@ -53,14 +53,14 @@ export class TimePickerCardEditor extends LitElement implements LovelaceCardEdit
|
|||||||
${this.datetimeEntities.map((entity) => html`<paper-item>${entity}</paper-item>`)}
|
${this.datetimeEntities.map((entity) => html`<paper-item>${entity}</paper-item>`)}
|
||||||
</paper-listbox>
|
</paper-listbox>
|
||||||
</paper-dropdown-menu>
|
</paper-dropdown-menu>
|
||||||
|
<paper-input
|
||||||
|
label="Name (Optional)"
|
||||||
|
.configValue=${'name'}
|
||||||
|
.value=${this.config.name}
|
||||||
|
.placeholder=${this.entity?.attributes.friendly_name}
|
||||||
|
@value-changed=${this.onValueChange}
|
||||||
|
></paper-input>
|
||||||
<div class="side-by-side">
|
<div class="side-by-side">
|
||||||
<paper-input
|
|
||||||
label="Name (Optional)"
|
|
||||||
.configValue=${'name'}
|
|
||||||
.value=${this.config.name}
|
|
||||||
.placeholder=${this.entity?.attributes.friendly_name}
|
|
||||||
@value-changed=${this.onValueChange}
|
|
||||||
></paper-input>
|
|
||||||
<ha-switch
|
<ha-switch
|
||||||
style="margin-left: 10px"
|
style="margin-left: 10px"
|
||||||
.checked="${!Boolean(this.config.hide?.name)}"
|
.checked="${!Boolean(this.config.hide?.name)}"
|
||||||
@@ -69,6 +69,20 @@ export class TimePickerCardEditor extends LitElement implements LovelaceCardEdit
|
|||||||
>
|
>
|
||||||
Show name?
|
Show name?
|
||||||
</ha-switch>
|
</ha-switch>
|
||||||
|
<paper-dropdown-menu
|
||||||
|
style="width: 100%"
|
||||||
|
label="Name Position (Optional)"
|
||||||
|
@value-changed=${this.onLayoutNameChange}
|
||||||
|
>
|
||||||
|
<paper-listbox
|
||||||
|
slot="dropdown-content"
|
||||||
|
.selected=${Object.values(Layout.Name).indexOf(
|
||||||
|
this.config.layout?.name ?? DEFAULT_LAYOUT_NAME
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
${Object.values(Layout.Name).map((name) => html`<paper-item>${name}</paper-item>`)}
|
||||||
|
</paper-listbox>
|
||||||
|
</paper-dropdown-menu>
|
||||||
</div>
|
</div>
|
||||||
<div class="side-by-side">
|
<div class="side-by-side">
|
||||||
<paper-input
|
<paper-input
|
||||||
@@ -105,18 +119,16 @@ export class TimePickerCardEditor extends LitElement implements LovelaceCardEdit
|
|||||||
<div class="side-by-side">
|
<div class="side-by-side">
|
||||||
<paper-dropdown-menu
|
<paper-dropdown-menu
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
label="Align (Optional)"
|
label="Align Controls (Optional)"
|
||||||
@value-changed=${this.onLayoutAlignChange}
|
@value-changed=${this.onLayoutAlignChange}
|
||||||
>
|
>
|
||||||
<paper-listbox
|
<paper-listbox
|
||||||
slot="dropdown-content"
|
slot="dropdown-content"
|
||||||
.selected=${TimePickerCardEditor.LAYOUT_ALIGN_VALUES.indexOf(
|
.selected=${Object.values(Layout.AlignControls).indexOf(
|
||||||
this.config.layout?.align ?? DEFAULT_LAYOUT_ALIGN
|
this.config.layout?.align_controls ?? DEFAULT_LAYOUT_ALIGN_CONTROLS
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
${TimePickerCardEditor.LAYOUT_ALIGN_VALUES.map(
|
${Object.values(Layout.AlignControls).map((a) => html`<paper-item>${a}</paper-item>`)}
|
||||||
(align) => html`<paper-item>${align}</paper-item>`
|
|
||||||
)}
|
|
||||||
</paper-listbox>
|
</paper-listbox>
|
||||||
</paper-dropdown-menu>
|
</paper-dropdown-menu>
|
||||||
</div>
|
</div>
|
||||||
@@ -134,20 +146,30 @@ export class TimePickerCardEditor extends LitElement implements LovelaceCardEdit
|
|||||||
this.dispatch(newConfig);
|
this.dispatch(newConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onHourModeLayoutChange({ target: { checked } }): void {
|
|
||||||
const hourModeLayout: LayoutHourMode = checked ? 'single' : 'double';
|
|
||||||
|
|
||||||
const newConfig = { ...this.config, layout: { hour_mode: hourModeLayout } };
|
|
||||||
this.dispatch(newConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
private onHideNameChange({ target: { checked } }): void {
|
private onHideNameChange({ target: { checked } }): void {
|
||||||
const newConfig = { ...this.config, hide: { name: !checked } };
|
const newConfig = { ...this.config, hide: { name: !checked } };
|
||||||
this.dispatch(newConfig);
|
this.dispatch(newConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onLayoutAlignChange({ detail: { value } }: CustomEvent): void {
|
private onLayoutAlignChange({ detail: { value } }: CustomEvent): void {
|
||||||
const newConfig = { ...this.config, layout: { align: value } };
|
const layout = { ...this.config.layout, align_controls: value };
|
||||||
|
const newConfig = { ...this.config, layout };
|
||||||
|
this.dispatch(newConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
private onLayoutNameChange({ detail: { value } }: CustomEvent): void {
|
||||||
|
const layout = { ...this.config.layout, name: value };
|
||||||
|
const newConfig = { ...this.config, layout };
|
||||||
|
this.dispatch(newConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
private onHourModeLayoutChange({ target: { checked } }): void {
|
||||||
|
const hourModeLayout: Layout.HourMode = checked ? 'single' : 'double';
|
||||||
|
|
||||||
|
const newConfig = {
|
||||||
|
...this.config,
|
||||||
|
layout: { ...this.config.layout, hour_mode: hourModeLayout },
|
||||||
|
};
|
||||||
this.dispatch(newConfig);
|
this.dispatch(newConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-2
@@ -1,6 +1,7 @@
|
|||||||
import { html, TemplateResult } from 'lit-element';
|
import { html, TemplateResult } from 'lit-element';
|
||||||
import { TimePickerCardConfig } from './types';
|
import { TimePickerCardConfig } from './types';
|
||||||
import { LovelaceCard } from 'custom-card-helpers';
|
import { LovelaceCard } from 'custom-card-helpers';
|
||||||
|
import { HassEntity } from 'home-assistant-js-websocket';
|
||||||
|
|
||||||
export class Partial {
|
export class Partial {
|
||||||
static error(error: string, origConfig: TimePickerCardConfig): TemplateResult {
|
static error(error: string, origConfig: TimePickerCardConfig): TemplateResult {
|
||||||
@@ -14,11 +15,16 @@ export class Partial {
|
|||||||
return html`${errorCard}`;
|
return html`${errorCard}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static header(title: string, icon?: string): TemplateResult | null {
|
static headerName(title: string): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<div class="time-picker-header">
|
<div class="time-picker-header">
|
||||||
${icon ? html`<ha-icon class="icon" icon=${icon}></ha-icon>` : ''}${title}
|
${title}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static nestedName(name: string, entity: HassEntity): TemplateResult {
|
||||||
|
return html`<state-badge .stateObj=${entity}></state-badge>
|
||||||
|
<div class="entity-name-inside">${name}</div>`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+55
-22
@@ -15,12 +15,12 @@ import {
|
|||||||
CARD_VERSION,
|
CARD_VERSION,
|
||||||
DEFAULT_LAYOUT_HOUR_MODE,
|
DEFAULT_LAYOUT_HOUR_MODE,
|
||||||
ENTITY_DOMAIN,
|
ENTITY_DOMAIN,
|
||||||
DEFAULT_LAYOUT_ALIGN,
|
DEFAULT_LAYOUT_ALIGN_CONTROLS,
|
||||||
} from './const';
|
} from './const';
|
||||||
import { Hour } from './models/hour';
|
import { Hour } from './models/hour';
|
||||||
import { Minute } from './models/minute';
|
import { Minute } from './models/minute';
|
||||||
import { Partial } from './partials';
|
import { Partial } from './partials';
|
||||||
import { Period, TimePickerCardConfig, LayoutAlign } from './types';
|
import { Period, TimePickerCardConfig, Layout } from './types';
|
||||||
|
|
||||||
import './components/time-period.component';
|
import './components/time-period.component';
|
||||||
import './components/time-unit.component';
|
import './components/time-unit.component';
|
||||||
@@ -51,8 +51,20 @@ export class TimePickerCard extends LitElement implements LovelaceCard {
|
|||||||
return this.hass.states[this.config.entity];
|
return this.hass.states[this.config.entity];
|
||||||
}
|
}
|
||||||
|
|
||||||
private get shouldShowName(): boolean {
|
private get hasNameInHeader(): boolean {
|
||||||
return Boolean(this.config.hide?.name) === false && Boolean(this.name);
|
return (
|
||||||
|
Boolean(this.name) &&
|
||||||
|
Boolean(this.config.hide?.name) === false &&
|
||||||
|
this.config.layout?.name !== Layout.Name.INSIDE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private get hasNameInside(): boolean {
|
||||||
|
return (
|
||||||
|
Boolean(this.name) &&
|
||||||
|
Boolean(this.config.hide?.name) === false &&
|
||||||
|
this.config.layout?.name === Layout.Name.INSIDE
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private get name(): string | undefined {
|
private get name(): string | undefined {
|
||||||
@@ -63,15 +75,21 @@ export class TimePickerCard extends LitElement implements LovelaceCard {
|
|||||||
return this.config.hour_mode === 12;
|
return this.config.hour_mode === 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
private get layoutAlign(): LayoutAlign {
|
private get layoutAlign(): Layout.AlignControls {
|
||||||
return this.config.layout?.align ?? DEFAULT_LAYOUT_ALIGN;
|
return this.config.layout?.align_controls ?? DEFAULT_LAYOUT_ALIGN_CONTROLS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private get rowClass(): ClassInfo {
|
||||||
|
return {
|
||||||
|
'time-picker-row': true,
|
||||||
|
'with-header-name': this.hasNameInHeader,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private get contentClass(): ClassInfo {
|
private get contentClass(): ClassInfo {
|
||||||
return {
|
return {
|
||||||
'time-picker-content': true,
|
'time-picker-content': true,
|
||||||
[`layout-${this.layoutAlign}`]: true,
|
[`layout-${this.layoutAlign}`]: true,
|
||||||
'with-name': this.shouldShowName,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,19 +116,23 @@ export class TimePickerCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-card>
|
<ha-card>
|
||||||
${this.shouldShowName ? Partial.header(this.name!) : ''}
|
${this.hasNameInHeader ? Partial.headerName(this.name!) : ''}
|
||||||
<div class=${classMap(this.contentClass)}>
|
<div class=${classMap(this.rowClass)}>
|
||||||
<time-unit .unit=${this.hour} @update=${this.callHassService}></time-unit>
|
${this.hasNameInside ? Partial.nestedName(this.name!, this.entity) : ''}
|
||||||
<div class="time-separator">:</div>
|
|
||||||
<time-unit .unit=${this.minute} @update=${this.callHassService}></time-unit>
|
|
||||||
|
|
||||||
${this.shouldShowPeriod
|
<div class=${classMap(this.contentClass)}>
|
||||||
? html`<time-period
|
<time-unit .unit=${this.hour} @update=${this.callHassService}></time-unit>
|
||||||
.period=${this.period}
|
<div class="time-separator">:</div>
|
||||||
.mode=${this.config.layout?.hour_mode ?? DEFAULT_LAYOUT_HOUR_MODE}
|
<time-unit .unit=${this.minute} @update=${this.callHassService}></time-unit>
|
||||||
@toggle=${this.onPeriodToggle}
|
|
||||||
></time-period>`
|
${this.shouldShowPeriod
|
||||||
: ''}
|
? html`<time-period
|
||||||
|
.period=${this.period}
|
||||||
|
.mode=${this.config.layout?.hour_mode ?? DEFAULT_LAYOUT_HOUR_MODE}
|
||||||
|
@toggle=${this.onPeriodToggle}
|
||||||
|
></time-period>`
|
||||||
|
: ''}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`;
|
`;
|
||||||
@@ -176,17 +198,24 @@ export class TimePickerCard extends LitElement implements LovelaceCard {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.time-picker-content {
|
.time-picker-row {
|
||||||
padding: 16px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.time-picker-content.with-name {
|
.time-picker-row.with-header-name {
|
||||||
padding: 8px 16px 16px;
|
padding: 8px 16px 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.time-picker-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
flex: 1 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
.time-picker-content.layout-left {
|
.time-picker-content.layout-left {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
@@ -198,6 +227,10 @@ export class TimePickerCard extends LitElement implements LovelaceCard {
|
|||||||
.time-picker-content.layout-right {
|
.time-picker-content.layout-right {
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.entity-name-inside {
|
||||||
|
margin-left: 16px;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+17
-4
@@ -13,12 +13,25 @@ export interface TimePickerCardConfig extends LovelaceCardConfig {
|
|||||||
export type HourMode = 12 | 24 | undefined;
|
export type HourMode = 12 | 24 | undefined;
|
||||||
|
|
||||||
export interface TimePickerLayoutConfig {
|
export interface TimePickerLayoutConfig {
|
||||||
align?: LayoutAlign;
|
align_controls?: Layout.AlignControls;
|
||||||
hour_mode?: LayoutHourMode;
|
name?: Layout.Name;
|
||||||
|
hour_mode?: Layout.HourMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LayoutHourMode = 'single' | 'double';
|
export namespace Layout {
|
||||||
export type LayoutAlign = 'left' | 'center' | 'right';
|
export type HourMode = 'single' | 'double';
|
||||||
|
|
||||||
|
export enum AlignControls {
|
||||||
|
LEFT = 'left',
|
||||||
|
CENTER = 'center',
|
||||||
|
RIGHT = 'right',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum Name {
|
||||||
|
HEADER = 'header',
|
||||||
|
INSIDE = 'inside',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface TimePickerHideConfig {
|
export interface TimePickerHideConfig {
|
||||||
name?: boolean;
|
name?: boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user