From a9f406ed8fd4b873825def74774df6dc672f8639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Wiedemann?= Date: Sat, 23 Apr 2022 07:41:53 +0000 Subject: [PATCH] feat: support actions on the title with `title_actions` Fix #323 --- .devcontainer/ui-lovelace.yaml | 9 ++++ README.md | 7 +-- src/apexcharts-card.ts | 87 +++++++++++++++++++++++++++++++--- src/styles.ts | 6 +++ src/types-config-ti.ts | 1 + src/types-config.ts | 1 + 6 files changed, 101 insertions(+), 10 deletions(-) diff --git a/.devcontainer/ui-lovelace.yaml b/.devcontainer/ui-lovelace.yaml index 192f9f6..1cd3456 100644 --- a/.devcontainer/ui-lovelace.yaml +++ b/.devcontainer/ui-lovelace.yaml @@ -1326,6 +1326,15 @@ views: header: show: true title: Test Stats + title_actions: + tap_action: + action: more-info + entity: sensor.random_0_1000 + confirmation: + text: test + hold_action: + action: more-info + entity: sensor.random_0_1000 all_series_config: stroke_width: 1 series: diff --git a/README.md b/README.md index 4496b3f..438838b 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ However, some things might be broken :grin: - [Main Options](#main-options) - [`series` Options](#series-options) - [series' `show` Options](#series-show-options) - - [`header_actions` options](#header_actions-options) + - [`header_actions` or `title_actions` options](#header_actions-or-title_actions-options) - [`*_action` options](#_action-options) - [`confirmation` options](#confirmation-options) - [`statistics` options](#statistics-options) @@ -184,7 +184,7 @@ The card stricly validates all the options available (but not for the `apex_conf | `color_threshold` | object | | v1.6.0 | See [experimental](#experimental-features) | | `yaxis_id` | string | | v1.9.0 | The identification name of the y-axis which this serie should be associated to. See [yaxis](#yaxis-options-multi-y-axis) | | `show` | object | | v1.3.0 | See [serie's show options](#series-show-options) | -| `header_actions` | object | | v1.10.0 | See [header_actions](#header_actions-options) | +| `header_actions` | object | | v1.10.0 | See [header_actions](#header_actions-or-title_actions-options) | ### series' `show` Options @@ -202,7 +202,7 @@ The card stricly validates all the options available (but not for the `apex_conf | `in_brush` | boolean | `false` | v1.8.0 | See [brush](#brush-experimental-feature) | | `offset_in_name` | boolean | `true` | v1.8.0 | If `true`, appends the offset information to the name of the serie. If `false`, it doesn't | -### `header_actions` options +### `header_actions` or `title_actions` options | Name | Type | Default | Since | Description | @@ -284,6 +284,7 @@ series: | ---- | :--: | :-----: | :---: | ----------- | | `show` | boolean | `false` | v1.0.0 | Show or hide the header | | `title` | string | | v1.1.0 | The title of the chart you want to display | +| `title_actions` | object | NEXT_VERSION | Actions to perform while taping the title of the chart. See [title_actions](#header_actions-or-title_actions-options) | | `floating` | boolean | `false` | v1.0.0 | Makes the header float above the graph. Positionning will be supported later | | `show_states` | boolean | `false` | v1.1.0 | Show or hide the states in the header | | `colorize_states` | boolean | `false` | v1.1.0 | Colorize the states based on the color of the serie | diff --git a/src/apexcharts-card.ts b/src/apexcharts-card.ts index 4bc4c5f..c3539a4 100644 --- a/src/apexcharts-card.ts +++ b/src/apexcharts-card.ts @@ -609,14 +609,65 @@ class ChartsCard extends LitElement { }; return html` `; } + private _renderTitle(): TemplateResult { + const classes = + this._config?.header?.disable_actions || + !this._config?.header?.title_actions || + (this._config?.header?.title_actions?.tap_action?.action === 'none' && + (!this._config?.header?.title_actions?.hold_action?.action || + this._config?.header?.title_actions?.hold_action?.action === 'none') && + (!this._config?.header?.title_actions?.double_tap_action?.action || + this._config?.header?.title_actions?.double_tap_action?.action === 'none')) + ? 'disabled' + : 'actions'; + + return html`
{ + this._handleTitleAction(ev); + }} + .actionHandler=${actionHandler({ + hasDoubleClick: + this._config?.header?.title_actions?.double_tap_action?.action && + this._config?.header?.title_actions.double_tap_action.action !== 'none', + hasHold: + this._config?.header?.title_actions?.hold_action?.action && + this._config?.header?.title_actions?.hold_action.action !== 'none', + })} + @focus="${(ev) => { + this.handleRippleFocus(ev, 'title'); + }}" + @blur="${(ev) => { + this.handleRippleBlur(ev, 'title'); + }}" + @mousedown="${(ev) => { + this.handleRippleActivate(ev, 'title'); + }}" + @mouseup="${(ev) => { + this.handleRippleDeactivate(ev, 'title'); + }}" + @touchstart="${(ev) => { + this.handleRippleActivate(ev, 'title'); + }}" + @touchend="${(ev) => { + this.handleRippleDeactivate(ev, 'title'); + }}" + @touchcancel="${(ev) => { + this.handleRippleDeactivate(ev, 'title'); + }}" + > + ${this._config?.header?.title} + +
`; + } + private _renderStates(): TemplateResult { return html`
@@ -1432,24 +1483,46 @@ class ChartsCard extends LitElement { return; } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + private _handleTitleAction(ev: any) { + if (ev.detail?.action) { + const configDup: ActionsConfig = this._config?.header?.title_actions + ? JSON.parse(JSON.stringify(this._config?.header?.title_actions)) + : {}; + + switch (ev.detail.action) { + case 'tap': + case 'hold': + case 'double_tap': + configDup.entity = configDup[`${ev.detail.action}_action`]?.entity; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + handleAction(this, this._hass!, configDup, ev.detail.action); + break; + default: + break; + } + } + return; + } + // backward compatibility @eventOptions({ passive: true }) - private handleRippleActivate(evt: Event, index: number): void { + private handleRippleActivate(evt: Event, index: number | string): void { const r = this.shadowRoot?.getElementById(`ripple-${index}`) as Ripple; r && typeof r.startFocus === 'function' && r.startPress(evt); } - private handleRippleDeactivate(_, index: number): void { + private handleRippleDeactivate(_, index: number | string): void { const r = this.shadowRoot?.getElementById(`ripple-${index}`) as Ripple; r && typeof r.startFocus === 'function' && r.endPress(); } - private handleRippleFocus(_, index: number): void { + private handleRippleFocus(_, index: number | string): void { const r = this.shadowRoot?.getElementById(`ripple-${index}`) as Ripple; r && typeof r.startFocus === 'function' && r.startFocus(); } - private handleRippleBlur(_, index: number): void { + private handleRippleBlur(_, index: number | string): void { const r = this.shadowRoot?.getElementById(`ripple-${index}`) as Ripple; r && typeof r.startFocus === 'function' && r.endFocus(); } diff --git a/src/styles.ts b/src/styles.ts index 94cd022..3231082 100644 --- a/src/styles.ts +++ b/src/styles.ts @@ -68,10 +68,16 @@ export const stylesApex: CSSResultGroup = css` position: relative; } + #header__title { + position: relative; + } + + #header__title.actions, #states__state.actions { cursor: pointer; } + #header__title.disabled, #states__state.disabled { pointer-events: none; } diff --git a/src/types-config-ti.ts b/src/types-config-ti.ts index 9eb302a..3916bba 100644 --- a/src/types-config-ti.ts +++ b/src/types-config-ti.ts @@ -139,6 +139,7 @@ export const ChartCardHeaderExternalConfig = t.iface([], { "colorize_states": t.opt("boolean"), "standard_format": t.opt("boolean"), "disable_actions": t.opt("boolean"), + "title_actions": t.opt("ActionsConfig"), }); export const ChartCardColorThreshold = t.iface([], { diff --git a/src/types-config.ts b/src/types-config.ts index 9bc7b13..5a76db7 100644 --- a/src/types-config.ts +++ b/src/types-config.ts @@ -139,6 +139,7 @@ export interface ChartCardHeaderExternalConfig { colorize_states?: boolean; standard_format?: boolean; disable_actions?: boolean; + title_actions?: ActionsConfig; } export interface ChartCardColorThreshold {