Add name position option. Refactor types

This commit is contained in:
2020-05-09 20:24:37 +03:00
parent 491e571aab
commit 4488b303d2
7 changed files with 133 additions and 56 deletions
+2 -1
View File
@@ -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"]
} }
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;