Skip to content

Commit

Permalink
v1.15: Fix layout on new HA: use local hui-generic-entity-row
Browse files Browse the repository at this point in the history
  • Loading branch information
rianadon committed Dec 20, 2021
1 parent 1847b42 commit 937eadc
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 14 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ Either `entity` or `entities` must be supplied. Use `entity` if you'd like to em

| Name | Type | Requirement | Description | Default |
|----------------|---------|--------------|------------------------------------------------------------------------------------------------------------|-------------------|
| icon | string | **Optional** | Customize the icon to shown next to the timer | - |
| icon | string | **Optional** | Customize the icon to show next to the timer | - |
| image | string | **Optional** | Customize the image url to show in place of the icon | - |
| state_color | boolean | **Optional** | Change the icon's color if the timer is active | - |
| active_icon | boolean | **Optional** | Override `icon` when timer is active | - |
| text_width | string | **Optional** | Space alotted for the time remaining (i.e. right offset of bar) | `3.5em` |
| bar_width | boolean | **Optional** | Width of progress bar (decrease if the entity name is cut off) | `calc(70% - 7em)` |
Expand All @@ -95,6 +97,8 @@ Either `entity` or `entities` must be supplied. Use `entity` if you'd like to em

† the primary color is taken from your theme using `var(--mdc-theme-primary, #6200ee);`

You can also use [actions](https://www.home-assistant.io/lovelace/actions/) with this card.

</details>

### Card options
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lovelace-timer-bar-card",
"version": "1.14.0",
"version": "1.15.0",
"description": "Progress bar display for Home Assistant timers",
"keywords": [
"home-assistant",
Expand Down
58 changes: 58 additions & 0 deletions src/ha-action-handler-directive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* Minimum code from Home Assistant to create the action handler used in hui-generic-entity-row. */

import { noChange } from "lit";
import {
AttributePart,
directive,
Directive,
DirectiveParameters,
} from "lit/directive.js";

interface ActionHandler extends HTMLElement {
holdTime: number;
bind(element: Element, options?: ActionHandlerOptions): void;
}
interface ActionHandlerElement extends HTMLElement {
actionHandler?: {
options: ActionHandlerOptions;
start?: (ev: Event) => void;
end?: (ev: Event) => void;
handleEnter?: (ev: KeyboardEvent) => void;
};
}

type ActionHandlerOptions = any;

const getActionHandler = (): ActionHandler => {
const body = document.body;
if (body.querySelector("action-handler")) {
return body.querySelector("action-handler") as ActionHandler;
}

const actionhandler = document.createElement("action-handler");
body.appendChild(actionhandler);

return actionhandler as ActionHandler;
};

export const actionHandlerBind = (
element: ActionHandlerElement,
options?: ActionHandlerOptions
) => {
const actionhandler: ActionHandler = getActionHandler();
if (!actionhandler) {
return;
}
actionhandler.bind(element, options);
};

export const actionHandler = directive(
class extends Directive {
update(part: AttributePart, [options]: DirectiveParameters<this>) {
actionHandlerBind(part.element as ActionHandlerElement, options);
return noChange;
}

render(_options?: ActionHandlerOptions) {}
}
);
79 changes: 79 additions & 0 deletions src/ha-generic-entity-row.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/* Simplified version of the hui-generic-entity-row.
* This element acts as a stable base to create the timer entity row.
*/

import { css, html, TemplateResult } from "lit";
import { ActionHandlerEvent, HomeAssistant, handleAction, hasAction } from "custom-card-helpers";
import { actionHandler } from "./ha-action-handler-directive";
import { TimerBarEntityConfig } from "./types";

const computeObjectId = (entityId: string): string =>
entityId.substr(entityId.indexOf(".") + 1);

const computeStateName = (stateObj: any): string =>
stateObj.attributes.friendly_name === undefined
? computeObjectId(stateObj.entity_id).replace(/_/g, " ")
: stateObj.attributes.friendly_name || "";

export function genericEntityRow(children: TemplateResult, hass?: HomeAssistant, config?: TimerBarEntityConfig): TemplateResult {
if (!hass || !config) return html``;
const stateObj = config.entity ? hass.states[config.entity] : undefined;
if (!stateObj) return html`<hui-warning>Entity ${config.entity} not found</hui-warning>`;

const name = config.name || computeStateName(stateObj);

const _handleAction = (ev: ActionHandlerEvent) => {
handleAction(ev.target as any, hass!, config!, ev.detail.action!);
}

return html`<div class="generic-entity-row">
<state-badge
class="pointer"
.hass=${hass}
.stateObj=${stateObj}
.overrideIcon=${config.icon}
.overrideImage=${config.image}
.stateColor=${config.state_color}
@action=${_handleAction}
.actionHandler=${actionHandler({
hasHold: hasAction(config!.hold_action),
hasDoubleClick: hasAction(config!.double_tap_action),
})}
tabindex="0"
></state-badge>
<div
class="info pointer"
@action=${_handleAction}
.actionHandler=${actionHandler({
hasHold: hasAction(config!.hold_action),
hasDoubleClick: hasAction(config!.double_tap_action),
})}
.title=${name}
>
${name}
</div>
${children}
</div>`;
}

export const genericEntityRowStyles = css`
.generic-entity-row {
display: flex;
align-items: center;
flex-direction: row;
}
.info {
margin-left: 16px;
margin-right: 8px;
flex: 1 1 30%;
}
.info,
.info > * {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
state-badge {
flex: 0 0 40px;
}
`;
4 changes: 2 additions & 2 deletions src/timer-bar-card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import { version } from '../package.json';
window.customElements.define('timer-bar-entity-row', TimerBarEntityRow);
console.info(
`%c TIMER-BAR-CARD %c Version ${version} `,
'font-weight: bold; background: #aeb',
'font-weight: bold; background: #ddd',
'font-weight: bold; color: #000; background: #aeb',
'font-weight: bold; color: #000; background: #ddd',
);

@customElement('timer-bar-card')
Expand Down
19 changes: 9 additions & 10 deletions src/timer-bar-entity-row.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { styleMap } from 'lit/directives/style-map.js';
import { HomeAssistant, hasConfigOrEntityChanged, secondsToDuration, computeStateDisplay } from 'custom-card-helpers';
import { findDuration, formatStartTime, timerTimeRemaining, timerTimePercent, findMode, stateMode, autoMode, tryDurationToSeconds } from './helpers';
import { TimerBarEntityConfig, HassEntity, Translations, TimerBarConfig, Mode } from './types';
import { genericEntityRow, genericEntityRowStyles } from './ha-generic-entity-row';

export function fillConfig(config: TimerBarEntityConfig) {
return {
Expand Down Expand Up @@ -111,7 +112,7 @@ export class TimerBarEntityRow extends LitElement {

case 'pause':
return this._renderRow(activeConfig, html`
<div class="status" style=${this._statusStyle()} @click=${this._handleClick}>
<div class="status pointer" style=${this._statusStyle()} @click=${this._handleClick}>
${localize(this.hass!, state.state, state, this.config.translations)}
</div>
<div class="text-content" style=${this._textStyle()}>
Expand All @@ -121,7 +122,7 @@ export class TimerBarEntityRow extends LitElement {

case 'waiting':
return this._renderRow(this.modConfig, html`
<div class="status" style=${this._statusStyle(true)} @click=${this._handleClick}>
<div class="status pointer" style=${this._statusStyle(true)} @click=${this._handleClick}>
${localize(this.hass!, "scheduled_for", undefined, this.config.translations)} ${formatStartTime(state)}
</div>
`);
Expand All @@ -138,9 +139,7 @@ export class TimerBarEntityRow extends LitElement {
private _renderRow(config: TimerBarConfig, contents: TemplateResult) {
if (this.modConfig.full_row) return html`<div class="flex">${contents}</div>${this._renderDebug()}`;
return html`
<hui-generic-entity-row .hass=${this.hass} .config=${config}>
${contents}
</hui-generic-entity-row>
${genericEntityRow(contents, this.hass, config)}
${this._renderDebug()}
`;
}
Expand All @@ -154,7 +153,7 @@ export class TimerBarEntityRow extends LitElement {
const containerStyle = styleMap({ width: this._bar_width, direction: this.modConfig.bar_direction });
const bgStyle = this._barStyle('100%', this.modConfig.bar_background!);
const fgStyle = this._barStyle(percent+"%", this.modConfig.bar_foreground!);
return html`<div class="bar-container" style=${containerStyle} @click=${this._handleClick}>
return html`<div class="bar-container pointer" style=${containerStyle} @click=${this._handleClick}>
<div class="bar" style=${bgStyle}>
<div style=${fgStyle}>
</div>
Expand Down Expand Up @@ -256,22 +255,22 @@ export class TimerBarEntityRow extends LitElement {
}

static get styles(): CSSResultGroup {
return css`
return [css`
:host {
display: flex;
flex-direction: column;
justify-content: center;
}
.pointer { cursor: pointer; }
.flex { display: flex; height: 40px; align-items: center; justify-content: flex-end; }
.bar-container {
cursor: pointer;
min-height: 1.5em;
display: flex;
flex-shrink: 0;
align-items: center;
}
.bar { margin-top: 2px; }
.status { cursor: pointer; line-height: 1.5em; flex-shrink: 0; }
.status { line-height: 1.5em; flex-shrink: 0; }
.text-content { text-align: right; text-align: end; overflow: hidden; }
code {
display: block;
Expand All @@ -281,7 +280,7 @@ export class TimerBarEntityRow extends LitElement {
font-size: 0.9em;
word-break: break-all;
}
`;
`, genericEntityRowStyles];
}

private get modConfig(): TimerBarEntityConfig {
Expand Down
4 changes: 4 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export declare type HassEntity = {
interface styleConfig {
icon?: string;
active_icon?: string;
image?: string;
state_color?: boolean;

bar_width?: string;
bar_height?: string;
Expand Down Expand Up @@ -60,6 +62,8 @@ export interface TimerBarEntityConfig extends styleConfig {

modifications?: modsConfig[];
translations?: Translations;
hold_action?: any;
double_tap_action?: any;
}

export interface TimerBarConfig extends TimerBarEntityConfig {
Expand Down

0 comments on commit 937eadc

Please sign in to comment.