Label and templates support (#134)
* Label and templates support * Fix blank card with fixed width * Fix some layouts
This commit is contained in:
parent
21c60bb033
commit
56a8fac0fa
97
README.md
97
README.md
|
@ -21,6 +21,7 @@ Lovelace Button card for your entities.
|
||||||
- custom color (optional), or based on light rgb value
|
- custom color (optional), or based on light rgb value
|
||||||
- custom state definition with customizable color, icon and style (optional)
|
- custom state definition with customizable color, icon and style (optional)
|
||||||
- [custom size of the icon, width and height](#Play-with-width-height-and-icon-size) (optional)
|
- [custom size of the icon, width and height](#Play-with-width-height-and-icon-size) (optional)
|
||||||
|
- Support for [templates](#templates) in some fields
|
||||||
- custom icon (optional)
|
- custom icon (optional)
|
||||||
- custom css style (optional)
|
- custom css style (optional)
|
||||||
- multiple [layout](#Layout) support
|
- multiple [layout](#Layout) support
|
||||||
|
@ -52,10 +53,13 @@ Lovelace Button card for your entities.
|
||||||
| `tap_action` | object | optional | See [Action](#Action) | Define the type of action on click, if undefined, toggle will be used. |
|
| `tap_action` | object | optional | See [Action](#Action) | Define the type of action on click, if undefined, toggle will be used. |
|
||||||
| `hold_action` | object | optional | See [Action](#Action) | Define the type of action on hold, if undefined, nothing happens. |
|
| `hold_action` | object | optional | See [Action](#Action) | Define the type of action on hold, if undefined, nothing happens. |
|
||||||
| `name` | string | optional | `Air conditioner` | Define an optional text to show below the icon |
|
| `name` | string | optional | `Air conditioner` | Define an optional text to show below the icon |
|
||||||
|
| `label` | string | optional | Any string that you want | Display a label below the card. See [Layouts](#layout) for more information. |
|
||||||
|
| `label_template` | string | optional | `states['light.mylight'].attributes.brightness` | See [templates](#templates). Any javascript code which returns a string. Overrides `label` |
|
||||||
| `show_name` | boolean | `true` | `true` \| `false` | Wether to show the name or not. Will pick entity_id's name by default, unless redefined in the `name` property or in any state `name` property |
|
| `show_name` | boolean | `true` | `true` \| `false` | Wether to show the name or not. Will pick entity_id's name by default, unless redefined in the `name` property or in any state `name` property |
|
||||||
| `show_state` | boolean | `false` | `true` \| `false` | Show the state on the card. defaults to false if not set |
|
| `show_state` | boolean | `false` | `true` \| `false` | Show the state on the card. defaults to false if not set |
|
||||||
| `show_icon` | boolean | `true` | `true` \| `false` | Wether to show the icon or not. Unless redefined in `icon`, uses the default entity icon from hass |
|
| `show_icon` | boolean | `true` | `true` \| `false` | Wether to show the icon or not. Unless redefined in `icon`, uses the default entity icon from hass |
|
||||||
| `show_units` | boolean | `true` | `true` \| `false` | Display or hide the units of a sensor, if any. |
|
| `show_units` | boolean | `true` | `true` \| `false` | Display or hide the units of a sensor, if any. |
|
||||||
|
| `show_label` | boolean | `false` | `true` \| `false` | Display or hide the `label`/`label_template`
|
||||||
| `show_entity_picture` | boolean | `false` | `true` \| `false` | Replace the icon by the entity picture (if any) or the custom picture (if any). Falls back to using the icon if both are undefined |
|
| `show_entity_picture` | boolean | `false` | `true` \| `false` | Replace the icon by the entity picture (if any) or the custom picture (if any). Falls back to using the icon if both are undefined |
|
||||||
| `entity_picture` | string | optional | Can be any of `/local/*` file or a URL | Will override the icon/the default entity_picture with your own image. Best is to use a square image. You can also define one per state |
|
| `entity_picture` | string | optional | Can be any of `/local/*` file or a URL | Will override the icon/the default entity_picture with your own image. Best is to use a square image. You can also define one per state |
|
||||||
| `units` | string | optional | `Kb/s`, `lux`, ... | Override or define the units to display after the state of the entity. If omitted, it's using the entity's units |
|
| `units` | string | optional | `Kb/s`, `lux`, ... | Override or define the units to display after the state of the entity. If omitted, it's using the entity's units |
|
||||||
|
@ -89,9 +93,13 @@ Lovelace Button card for your entities.
|
||||||
| `spin` | boolean | `false` | `true` \| `false` | Should the icon spin for this state? |
|
| `spin` | boolean | `false` | `true` \| `false` | Should the icon spin for this state? |
|
||||||
| `entity_picture` | string | optional | Can be any of `/local/*` file or a URL | Will override the icon/the default entity_picture with your own image for this state. Best is to use a square image |
|
| `entity_picture` | string | optional | Can be any of `/local/*` file or a URL | Will override the icon/the default entity_picture with your own image for this state. Best is to use a square image |
|
||||||
| `entity_picture_style` | object list | optional | `- border-radius: 50%`, `- filter: grayscale(100%)`, ... | Style applied to the entity picture for this state |
|
| `entity_picture_style` | object list | optional | `- border-radius: 50%`, `- filter: grayscale(100%)`, ... | Style applied to the entity picture for this state |
|
||||||
|
| `label` | string | optional | Any string that you want | Display a label below the card. See [Layouts](#layout) for more information. |
|
||||||
|
| `label_template` | string | optional | `states['light.mylight'].attributes.brightness` | See [templates](#templates). Any javascript code which returns a string. Overrides `label` |
|
||||||
|
|
||||||
### Available operators
|
### Available operators
|
||||||
|
|
||||||
|
The order of your elements in the `state` object matters. The first one which is `true` will match.
|
||||||
|
|
||||||
| Operator | `value` example | Description |
|
| Operator | `value` example | Description |
|
||||||
| :-------: | --------------- | -------------------------------------------------------------------------------------------------------- |
|
| :-------: | --------------- | -------------------------------------------------------------------------------------------------------- |
|
||||||
| `<` | `5` | Current state is inferior to `value` |
|
| `<` | `5` | Current state is inferior to `value` |
|
||||||
|
@ -101,6 +109,7 @@ Lovelace Button card for your entities.
|
||||||
| `>` | `12` | Current state is superior to `value` |
|
| `>` | `12` | Current state is superior to `value` |
|
||||||
| `!=` | `'normal'` | Current state is not equal (`!=` javascript) to `value` |
|
| `!=` | `'normal'` | Current state is not equal (`!=` javascript) to `value` |
|
||||||
| `regex` | `'^norm.*$'` | `value` regex applied to current state does match |
|
| `regex` | `'^norm.*$'` | `value` regex applied to current state does match |
|
||||||
|
| `template` | `return states['input_select.light_mode'].state === 'night_mode'` | See [here](#state-templates) for examples. `value` needs to be a javascript expression which returns a boolean. If the boolean is true, it will match this state |
|
||||||
| `default` | N/A | If nothing matches, this is used |
|
| `default` | N/A | If nothing matches, this is used |
|
||||||
|
|
||||||
### Layout
|
### Layout
|
||||||
|
@ -111,15 +120,29 @@ It is fully compatible with every `show_*` option. Make sure you set `show_state
|
||||||
|
|
||||||
Multiple values are possible, see the image below for examples:
|
Multiple values are possible, see the image below for examples:
|
||||||
* `vertical` (default value if nothing is provided): Everything is centered vertically on top of each other
|
* `vertical` (default value if nothing is provided): Everything is centered vertically on top of each other
|
||||||
* `icon_name_state`: Everything is aligned horizontally, name and state are concatenated
|
* `icon_name_state`: Everything is aligned horizontally, name and state are concatenated, label is centered below
|
||||||
* `name_state`: Icon sits on top of name and state concatenated on one line
|
* `name_state`: Icon sits on top of name and state concatenated on one line, label below
|
||||||
* `icon_name`: Icon and name are horizontally aligned, state is centered below
|
* `icon_name`: Icon and name are horizontally aligned, state and label are centered below
|
||||||
* `icon_state`: Icon and state are horizontally aligned, name is centered below
|
* `icon_state`: Icon and state are horizontally aligned, name and label are centered below
|
||||||
* `icon_name_state2nd`: Icon, name and state are horizontally aligned, name is above state
|
* `icon_label`: Icon and label are horizontally aligned, name and state are centered below
|
||||||
* `icon_state_name2nd`: Icon, name and state are horizontally aligned, state is above name
|
* `icon_name_state2nd`: Icon, name and state are horizontally aligned, name is above state, label below name and state
|
||||||
|
* `icon_state_name2nd`: Icon, name and state are horizontally aligned, state is above name, label below name and state
|
||||||
|
|
||||||
![layout_image](examples/layout.png)
|
![layout_image](examples/layout.png)
|
||||||
|
|
||||||
|
### Templates
|
||||||
|
|
||||||
|
`label_template` supports templating.
|
||||||
|
It will be interpreted as javascript code and the code should return a value.
|
||||||
|
|
||||||
|
Inside the javascript code, you'll have access to those variables:
|
||||||
|
* `entity`: The current entity object, if the entity is defined in the card
|
||||||
|
* `states`: An object with all the states of all the entities (equivalent to `hass.states`)
|
||||||
|
* `user`: The user object (equivalent to `hass.user`)
|
||||||
|
* `hass`: The complete `hass` object
|
||||||
|
|
||||||
|
See [here](#playing-with-label-templates) for some examples.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Manual Installation
|
### Manual Installation
|
||||||
|
@ -466,6 +489,68 @@ If you specify a width for the card, it has to be in `px`. All the cards without
|
||||||
style:
|
style:
|
||||||
- height: 300px
|
- height: 300px
|
||||||
```
|
```
|
||||||
|
### Templates Support
|
||||||
|
|
||||||
|
#### Playing with label templates
|
||||||
|
|
||||||
|
![label_template](examples/labels.png)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- type: "custom:button-card"
|
||||||
|
color_type: icon
|
||||||
|
entity: light.test_light
|
||||||
|
label_template: >
|
||||||
|
var bri = states['light.test_light'].attributes.brightness;
|
||||||
|
return 'Brightness: ' + (bri ? bri : '0') + '%';
|
||||||
|
show_label: true
|
||||||
|
size: 15%
|
||||||
|
style:
|
||||||
|
- height: 100px
|
||||||
|
- type: "custom:button-card"
|
||||||
|
color_type: icon
|
||||||
|
entity: light.test_light
|
||||||
|
layout: icon_label
|
||||||
|
label_template: >
|
||||||
|
return 'Other State: ' + states['switch.skylight'].state;
|
||||||
|
show_label: true
|
||||||
|
show_name: false
|
||||||
|
style:
|
||||||
|
- height: 100px
|
||||||
|
```
|
||||||
|
|
||||||
|
#### State Templates
|
||||||
|
|
||||||
|
The javascript code inside `value` needs to return `true` of `false`.
|
||||||
|
|
||||||
|
Example with `template`:
|
||||||
|
```yaml
|
||||||
|
- type: "custom:button-card"
|
||||||
|
color_type: icon
|
||||||
|
entity: switch.skylight
|
||||||
|
show_state: true
|
||||||
|
show_label: true
|
||||||
|
state:
|
||||||
|
- operator: template
|
||||||
|
value: >
|
||||||
|
return states['light.test_light'].attributes
|
||||||
|
&& (states['light.test_light'].attributes.brightness <= 100)
|
||||||
|
icon: mdi:alert
|
||||||
|
- operator: default
|
||||||
|
icon: mdi:lightbulb
|
||||||
|
- type: "custom:button-card"
|
||||||
|
color_type: icon
|
||||||
|
entity: light.test_light
|
||||||
|
show_label: true
|
||||||
|
state:
|
||||||
|
- operator: template
|
||||||
|
value: >
|
||||||
|
return states['input_select.light_mode'].state === 'night_mode'
|
||||||
|
icon: mdi:weather-night
|
||||||
|
label: Night Mode
|
||||||
|
- operator: default
|
||||||
|
icon: mdi:white-balance-sunny
|
||||||
|
label: Day Mode
|
||||||
|
```
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
|
|
|
@ -3336,8 +3336,8 @@ function applyBrightnessToColor(color, brightness) {
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
// Check if config or Entity changed
|
// Check if config or Entity changed
|
||||||
function hasConfigOrEntityChanged(element, changedProps) {
|
function hasConfigOrEntityChanged(element, changedProps, forceUpdate) {
|
||||||
if (changedProps.has('config')) {
|
if (changedProps.has('config') || forceUpdate) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (element.config.entity) {
|
if (element.config.entity) {
|
||||||
|
@ -3711,8 +3711,9 @@ const styles = css`
|
||||||
}
|
}
|
||||||
.img-cell {
|
.img-cell {
|
||||||
grid-area: i;
|
grid-area: i;
|
||||||
min-height: 0;
|
height: 100%;
|
||||||
min-width: 0;
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
|
@ -3736,64 +3737,164 @@ const styles = css`
|
||||||
/* margin: auto; */
|
/* margin: auto; */
|
||||||
}
|
}
|
||||||
|
|
||||||
.container.vertical {
|
.label {
|
||||||
grid-template-areas: "i" "n" "s";
|
grid-area: l;
|
||||||
grid-template-columns: 1fr;
|
max-width: 100%;
|
||||||
grid-template-rows: 1fr min-content min-content;
|
align-self: center;
|
||||||
|
justify-self: center;
|
||||||
}
|
}
|
||||||
.container.vertical.no-icon {
|
|
||||||
grid-template-areas: "n" "s";
|
.container.vertical {
|
||||||
|
grid-template-areas: "i" "n" "s" "l";
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
grid-template-rows: 1fr 1fr;
|
grid-template-rows: 1fr min-content min-content min-content;
|
||||||
|
}
|
||||||
|
/* Vertical No Icon */
|
||||||
|
.container.vertical.no-icon {
|
||||||
|
grid-template-areas: "n" "s" "l";
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: 1fr min-content 1fr;
|
||||||
}
|
}
|
||||||
.container.vertical.no-icon .state {
|
.container.vertical.no-icon .state {
|
||||||
align-self: start;
|
align-self: center;
|
||||||
}
|
}
|
||||||
.container.vertical.no-icon .name {
|
.container.vertical.no-icon .name {
|
||||||
align-self: end;
|
align-self: end;
|
||||||
}
|
}
|
||||||
|
.container.vertical.no-icon .label {
|
||||||
|
align-self: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Vertical No Icon No Name */
|
||||||
.container.vertical.no-icon.no-name {
|
.container.vertical.no-icon.no-name {
|
||||||
|
grid-template-areas: "s" "l";
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: 1fr 1fr;
|
||||||
|
}
|
||||||
|
.container.vertical.no-icon.no-name .state {
|
||||||
|
align-self: end;
|
||||||
|
}
|
||||||
|
.container.vertical.no-icon.no-name .label {
|
||||||
|
align-self: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Vertical No Icon No State */
|
||||||
|
.container.vertical.no-icon.no-state {
|
||||||
|
grid-template-areas: "n" "l";
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: 1fr 1fr;
|
||||||
|
}
|
||||||
|
.container.vertical.no-icon.no-state .name {
|
||||||
|
align-self: end;
|
||||||
|
}
|
||||||
|
.container.vertical.no-icon.no-state .label {
|
||||||
|
align-self: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Vertical No Icon No Label */
|
||||||
|
.container.vertical.no-icon.no-label {
|
||||||
|
grid-template-areas: "n" "s";
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: 1fr 1fr;
|
||||||
|
}
|
||||||
|
.container.vertical.no-icon.no-label .name {
|
||||||
|
align-self: end;
|
||||||
|
}
|
||||||
|
.container.vertical.no-icon.no-label .state {
|
||||||
|
align-self: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Vertical No Icon No Label No Name */
|
||||||
|
.container.vertical.no-icon.no-label.no-name {
|
||||||
grid-template-areas: "s";
|
grid-template-areas: "s";
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
grid-template-rows: 1fr;
|
grid-template-rows: 1fr;
|
||||||
}
|
}
|
||||||
.container.vertical.no-icon.no-name .state {
|
.container.vertical.no-icon.no-label.no-name .state {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
.container.vertical.no-icon.no-state {
|
/* Vertical No Icon No Label No State */
|
||||||
|
.container.vertical.no-icon.no-label.no-state {
|
||||||
grid-template-areas: "n";
|
grid-template-areas: "n";
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
grid-template-rows: 1fr;
|
grid-template-rows: 1fr;
|
||||||
}
|
}
|
||||||
.container.vertical.no-icon.no-state .name {
|
.container.vertical.no-icon.no-label.no-state .name {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Vertical No Icon No Name No State */
|
||||||
|
.container.vertical.no-icon.no-name.no-state {
|
||||||
|
grid-template-areas: "l";
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
}
|
||||||
|
.container.vertical.no-icon.no-name.no-state .label {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container.icon_name_state {
|
.container.icon_name_state {
|
||||||
grid-template-areas: "i n";
|
grid-template-areas: "i n" "l l";
|
||||||
grid-template-columns: 40% 1fr;
|
grid-template-columns: 40% 1fr;
|
||||||
grid-template-rows: 1fr;
|
grid-template-rows: 1fr min-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container.icon_name {
|
.container.icon_name {
|
||||||
grid-template-areas: "i n" "s s";
|
grid-template-areas: "i n" "s s" "l l";
|
||||||
grid-template-columns: 40% 1fr;
|
grid-template-columns: 40% 1fr;
|
||||||
grid-template-rows: 1fr min-content;
|
grid-template-rows: 1fr min-content min-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container.icon_state {
|
.container.icon_state {
|
||||||
grid-template-areas: "i s" "n n";
|
grid-template-areas: "i s" "n n" "l l";
|
||||||
grid-template-columns: 40% 1fr;
|
grid-template-columns: 40% 1fr;
|
||||||
grid-template-rows: 1fr min-content;
|
grid-template-rows: 1fr min-content min-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container.name_state {
|
.container.name_state {
|
||||||
grid-template-areas: "i" "n";
|
grid-template-areas: "i" "n" "l";
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
grid-template-rows: 1fr min-content;
|
grid-template-rows: 1fr min-content min-content;
|
||||||
|
}
|
||||||
|
.container.name_state.no-icon {
|
||||||
|
grid-template-areas: "n" "l";
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: 1fr 1fr;
|
||||||
|
}
|
||||||
|
.container.name_state.no-icon .name {
|
||||||
|
align-self: end
|
||||||
|
}
|
||||||
|
.container.name_state.no-icon .label {
|
||||||
|
align-self: start
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container.name_state.no-icon.no-label {
|
||||||
|
grid-template-areas: "n";
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
}
|
||||||
|
.container.name_state.no-icon.no-label .name {
|
||||||
|
align-self: center
|
||||||
|
}
|
||||||
|
|
||||||
|
/* icon_name_state2nd default */
|
||||||
.container.icon_name_state2nd {
|
.container.icon_name_state2nd {
|
||||||
|
grid-template-areas: "i n" "i s" "i l";
|
||||||
|
grid-template-columns: 40% 1fr;
|
||||||
|
grid-template-rows: 1fr min-content 1fr;
|
||||||
|
}
|
||||||
|
.container.icon_name_state2nd .name {
|
||||||
|
align-self: end;
|
||||||
|
}
|
||||||
|
.container.icon_name_state2nd .state {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
.container.icon_name_state2nd .label {
|
||||||
|
align-self: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* icon_name_state2nd No Label */
|
||||||
|
.container.icon_name_state2nd.no-label {
|
||||||
grid-template-areas: "i n" "i s";
|
grid-template-areas: "i n" "i s";
|
||||||
grid-template-columns: 40% 1fr;
|
grid-template-columns: 40% 1fr;
|
||||||
grid-template-rows: 1fr 1fr;
|
grid-template-rows: 1fr 1fr;
|
||||||
|
@ -3805,7 +3906,24 @@ const styles = css`
|
||||||
align-self: start;
|
align-self: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* icon_state_name2nd Default */
|
||||||
.container.icon_state_name2nd {
|
.container.icon_state_name2nd {
|
||||||
|
grid-template-areas: "i s" "i n" "i l";
|
||||||
|
grid-template-columns: 40% 1fr;
|
||||||
|
grid-template-rows: 1fr min-content 1fr;
|
||||||
|
}
|
||||||
|
.container.icon_state_name2nd .state {
|
||||||
|
align-self: end;
|
||||||
|
}
|
||||||
|
.container.icon_state_name2nd .name {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
.container.icon_state_name2nd .state {
|
||||||
|
align-self: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* icon_state_name2nd No Label */
|
||||||
|
.container.icon_state_name2nd.no-label {
|
||||||
grid-template-areas: "i s" "i n";
|
grid-template-areas: "i s" "i n";
|
||||||
grid-template-columns: 40% 1fr;
|
grid-template-columns: 40% 1fr;
|
||||||
grid-template-rows: 1fr 1fr;
|
grid-template-rows: 1fr 1fr;
|
||||||
|
@ -3816,6 +3934,12 @@ const styles = css`
|
||||||
.container.icon_state_name2nd .name {
|
.container.icon_state_name2nd .name {
|
||||||
align-self: start;
|
align-self: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container.icon_label {
|
||||||
|
grid-template-areas: "i l" "n n" "s s";
|
||||||
|
grid-template-columns: 40% 1fr;
|
||||||
|
grid-template-rows: 1fr min-content min-content;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
let ButtonCard = class ButtonCard extends LitElement {
|
let ButtonCard = class ButtonCard extends LitElement {
|
||||||
|
@ -3829,7 +3953,12 @@ let ButtonCard = class ButtonCard extends LitElement {
|
||||||
return this._cardHtml();
|
return this._cardHtml();
|
||||||
}
|
}
|
||||||
shouldUpdate(changedProps) {
|
shouldUpdate(changedProps) {
|
||||||
return hasConfigOrEntityChanged(this, changedProps);
|
const state = this.config.entity ? this.hass.states[this.config.entity] : undefined;
|
||||||
|
const configState = this._getMatchingConfigState(state);
|
||||||
|
const forceUpdate = this.config.show_label && (configState && configState.label_template || this.config.label_template) || this.config.state && this.config.state.find(elt => {
|
||||||
|
return elt.operator === 'template';
|
||||||
|
}) ? true : false;
|
||||||
|
return hasConfigOrEntityChanged(this, changedProps, forceUpdate);
|
||||||
}
|
}
|
||||||
_getMatchingConfigState(state) {
|
_getMatchingConfigState(state) {
|
||||||
if (!state || !this.config.state) {
|
if (!state || !this.config.state) {
|
||||||
|
@ -3858,6 +3987,10 @@ let ButtonCard = class ButtonCard extends LitElement {
|
||||||
const matches = state.state.match(elt.value) ? true : false;
|
const matches = state.state.match(elt.value) ? true : false;
|
||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
|
case 'template':
|
||||||
|
{
|
||||||
|
return new Function('states', 'entity', 'user', 'hass', `'use strict'; ${elt.value}`).call(this, this.hass.states, state, this.hass.user, this.hass);
|
||||||
|
}
|
||||||
case 'default':
|
case 'default':
|
||||||
def = elt;
|
def = elt;
|
||||||
return false;
|
return false;
|
||||||
|
@ -4018,6 +4151,28 @@ let ButtonCard = class ButtonCard extends LitElement {
|
||||||
}
|
}
|
||||||
return units;
|
return units;
|
||||||
}
|
}
|
||||||
|
_buildLabel(state, configState) {
|
||||||
|
if (!this.config.show_label) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
let label;
|
||||||
|
let matchingLabelTemplate;
|
||||||
|
if (configState && configState.label_template) {
|
||||||
|
matchingLabelTemplate = configState.label_template;
|
||||||
|
} else {
|
||||||
|
matchingLabelTemplate = this.config.label_template;
|
||||||
|
}
|
||||||
|
if (!matchingLabelTemplate) {
|
||||||
|
if (configState && configState.label) {
|
||||||
|
label = configState.label;
|
||||||
|
} else {
|
||||||
|
label = this.config.label;
|
||||||
|
}
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
/* eslint no-new-func: 0 */
|
||||||
|
return new Function('states', 'entity', 'user', 'hass', `'use strict'; ${matchingLabelTemplate}`).call(this, this.hass.states, state, this.hass.user, this.hass);
|
||||||
|
}
|
||||||
_isClickable(state) {
|
_isClickable(state) {
|
||||||
let clickable = true;
|
let clickable = true;
|
||||||
if (this.config.tap_action.action === 'toggle' && this.config.hold_action.action === 'none' || this.config.hold_action.action === 'toggle' && this.config.tap_action.action === 'none') {
|
if (this.config.tap_action.action === 'toggle' && this.config.hold_action.action === 'none' || this.config.hold_action.action === 'toggle' && this.config.tap_action.action === 'none') {
|
||||||
|
@ -4045,11 +4200,11 @@ let ButtonCard = class ButtonCard extends LitElement {
|
||||||
_rotate(configState) {
|
_rotate(configState) {
|
||||||
return configState && configState.spin ? true : false;
|
return configState && configState.spin ? true : false;
|
||||||
}
|
}
|
||||||
_blankCardColoredHtml(state) {
|
_blankCardColoredHtml(state, cardStyle) {
|
||||||
const color = this._buildCssColorAttribute(state, undefined);
|
const color = this._buildCssColorAttribute(state, undefined);
|
||||||
const fontColor = getFontColorBasedOnBackgroundColor(color);
|
const fontColor = getFontColorBasedOnBackgroundColor(color);
|
||||||
return html`
|
return html`
|
||||||
<ha-card class="disabled">
|
<ha-card class="disabled" style=${styleMap(cardStyle)}>
|
||||||
<div style="color: ${fontColor}; background-color: ${color};"></div>
|
<div style="color: ${fontColor}; background-color: ${color};"></div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`;
|
`;
|
||||||
|
@ -4061,9 +4216,13 @@ let ButtonCard = class ButtonCard extends LitElement {
|
||||||
let buttonColor = color;
|
let buttonColor = color;
|
||||||
let cardStyle = {};
|
let cardStyle = {};
|
||||||
const configCardStyle = this._buildStyle(state, configState);
|
const configCardStyle = this._buildStyle(state, configState);
|
||||||
|
if (configCardStyle.width) {
|
||||||
|
this.style.setProperty('flex', '0 0 auto');
|
||||||
|
this.style.setProperty('max-width', 'fit-content');
|
||||||
|
}
|
||||||
switch (this.config.color_type) {
|
switch (this.config.color_type) {
|
||||||
case 'blank-card':
|
case 'blank-card':
|
||||||
return this._blankCardColoredHtml(state);
|
return this._blankCardColoredHtml(state, configCardStyle);
|
||||||
case 'card':
|
case 'card':
|
||||||
case 'label-card':
|
case 'label-card':
|
||||||
{
|
{
|
||||||
|
@ -4078,10 +4237,6 @@ let ButtonCard = class ButtonCard extends LitElement {
|
||||||
cardStyle = configCardStyle;
|
cardStyle = configCardStyle;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (configCardStyle.width) {
|
|
||||||
this.style.setProperty('flex', '0 0 auto');
|
|
||||||
this.style.setProperty('max-width', 'fit-content');
|
|
||||||
}
|
|
||||||
return html`
|
return html`
|
||||||
<ha-card class="button-card-main ${this._isClickable(state) ? '' : 'disabled'}" style=${styleMap(cardStyle)} @ha-click="${this._handleTap}" @ha-hold="${this._handleHold}" .longpress="${longPress()}" .config="${this.config}">
|
<ha-card class="button-card-main ${this._isClickable(state) ? '' : 'disabled'}" style=${styleMap(cardStyle)} @ha-click="${this._handleTap}" @ha-hold="${this._handleHold}" .longpress="${longPress()}" .config="${this.config}">
|
||||||
${this._buttonContent(state, configState, buttonColor)}
|
${this._buttonContent(state, configState, buttonColor)}
|
||||||
|
@ -4104,14 +4259,17 @@ let ButtonCard = class ButtonCard extends LitElement {
|
||||||
_gridHtml(state, configState, containerClass, color, name, stateString) {
|
_gridHtml(state, configState, containerClass, color, name, stateString) {
|
||||||
const iconTemplate = this._getIconHtml(state, configState, color);
|
const iconTemplate = this._getIconHtml(state, configState, color);
|
||||||
const itemClass = ['container', containerClass];
|
const itemClass = ['container', containerClass];
|
||||||
|
const label = this._buildLabel(state, configState);
|
||||||
if (!iconTemplate) itemClass.push('no-icon');
|
if (!iconTemplate) itemClass.push('no-icon');
|
||||||
if (!name) itemClass.push('no-name');
|
if (!name) itemClass.push('no-name');
|
||||||
if (!stateString) itemClass.push('no-state');
|
if (!stateString) itemClass.push('no-state');
|
||||||
|
if (!label) itemClass.push('no-label');
|
||||||
return html`
|
return html`
|
||||||
<div class=${itemClass.join(' ')}>
|
<div class=${itemClass.join(' ')}>
|
||||||
${iconTemplate ? iconTemplate : ''}
|
${iconTemplate ? iconTemplate : ''}
|
||||||
${name ? html`<div class="name">${name}</div>` : ''}
|
${name ? html`<div class="name">${name}</div>` : ''}
|
||||||
${stateString ? html`<div class="state">${stateString}</div>` : ''}
|
${stateString ? html`<div class="state">${stateString}</div>` : ''}
|
||||||
|
${label ? html`<div class="label">${label}</div>` : ''}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -4142,7 +4300,7 @@ let ButtonCard = class ButtonCard extends LitElement {
|
||||||
if (!config) {
|
if (!config) {
|
||||||
throw new Error('Invalid configuration');
|
throw new Error('Invalid configuration');
|
||||||
}
|
}
|
||||||
this.config = Object.assign({ tap_action: { action: 'toggle' }, hold_action: { action: 'none' }, layout: 'vertical', size: '40%', color_type: 'icon', show_name: true, show_state: false, show_icon: true, show_units: true, show_entity_picture: false }, config);
|
this.config = Object.assign({ tap_action: { action: 'toggle' }, hold_action: { action: 'none' }, layout: 'vertical', size: '40%', color_type: 'icon', show_name: true, show_state: false, show_icon: true, show_units: true, show_label: false, show_entity_picture: false }, config);
|
||||||
this.config.default_color = 'var(--primary-text-color)';
|
this.config.default_color = 'var(--primary-text-color)';
|
||||||
if (this.config.color_type !== 'icon') {
|
if (this.config.color_type !== 'icon') {
|
||||||
this.config.color_off = 'var(--paper-card-background-color)';
|
this.config.color_off = 'var(--paper-card-background-color)';
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 7.8 KiB |
|
@ -48,7 +48,17 @@ class ButtonCard extends LitElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||||
return hasConfigOrEntityChanged(this, changedProps);
|
const state = this.config!.entity ? this.hass!.states[this.config!.entity] : undefined;
|
||||||
|
const configState = this._getMatchingConfigState(state);
|
||||||
|
const forceUpdate = (this.config!.show_label
|
||||||
|
&& (configState
|
||||||
|
&& configState.label_template
|
||||||
|
|| this.config!.label_template)
|
||||||
|
)
|
||||||
|
|| this.config!.state
|
||||||
|
&& this.config!.state.find((elt) => { return elt.operator === 'template'; })
|
||||||
|
? true : false;
|
||||||
|
return hasConfigOrEntityChanged(this, changedProps, forceUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getMatchingConfigState(state: HassEntity | undefined): StateConfig | undefined {
|
private _getMatchingConfigState(state: HassEntity | undefined): StateConfig | undefined {
|
||||||
|
@ -77,6 +87,11 @@ class ButtonCard extends LitElement {
|
||||||
const matches = state.state.match(elt.value) ? true : false;
|
const matches = state.state.match(elt.value) ? true : false;
|
||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
|
case 'template': {
|
||||||
|
return new Function('states', 'entity', 'user', 'hass',
|
||||||
|
`'use strict'; ${elt.value}`)
|
||||||
|
.call(this, this.hass!.states, state, this.hass!.user, this.hass);
|
||||||
|
}
|
||||||
case 'default':
|
case 'default':
|
||||||
def = elt;
|
def = elt;
|
||||||
return false;
|
return false;
|
||||||
|
@ -266,6 +281,36 @@ class ButtonCard extends LitElement {
|
||||||
return units;
|
return units;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _buildLabel(
|
||||||
|
state: HassEntity | undefined,
|
||||||
|
configState: StateConfig | undefined,
|
||||||
|
): string | undefined {
|
||||||
|
if (!this.config!.show_label) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
let label: string | undefined;
|
||||||
|
let matchingLabelTemplate: string | undefined;
|
||||||
|
|
||||||
|
if (configState && configState.label_template) {
|
||||||
|
matchingLabelTemplate = configState.label_template;
|
||||||
|
} else {
|
||||||
|
matchingLabelTemplate = this.config!.label_template;
|
||||||
|
}
|
||||||
|
if (!matchingLabelTemplate) {
|
||||||
|
if (configState && configState.label) {
|
||||||
|
label = configState.label;
|
||||||
|
} else {
|
||||||
|
label = this.config!.label;
|
||||||
|
}
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eslint no-new-func: 0 */
|
||||||
|
return new Function('states', 'entity', 'user', 'hass',
|
||||||
|
`'use strict'; ${matchingLabelTemplate}`)
|
||||||
|
.call(this, this.hass!.states, state, this.hass!.user, this.hass);
|
||||||
|
}
|
||||||
|
|
||||||
private _isClickable(state: HassEntity | undefined): boolean {
|
private _isClickable(state: HassEntity | undefined): boolean {
|
||||||
let clickable = true;
|
let clickable = true;
|
||||||
if (this.config!.tap_action!.action === 'toggle' && this.config!.hold_action!.action === 'none'
|
if (this.config!.tap_action!.action === 'toggle' && this.config!.hold_action!.action === 'none'
|
||||||
|
@ -297,11 +342,14 @@ class ButtonCard extends LitElement {
|
||||||
return configState && configState.spin ? true : false;
|
return configState && configState.spin ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _blankCardColoredHtml(state: HassEntity | undefined): TemplateResult {
|
private _blankCardColoredHtml(
|
||||||
|
state: HassEntity | undefined,
|
||||||
|
cardStyle: StyleInfo,
|
||||||
|
): TemplateResult {
|
||||||
const color = this._buildCssColorAttribute(state, undefined);
|
const color = this._buildCssColorAttribute(state, undefined);
|
||||||
const fontColor = getFontColorBasedOnBackgroundColor(color);
|
const fontColor = getFontColorBasedOnBackgroundColor(color);
|
||||||
return html`
|
return html`
|
||||||
<ha-card class="disabled">
|
<ha-card class="disabled" style=${styleMap(cardStyle)}>
|
||||||
<div style="color: ${fontColor}; background-color: ${color};"></div>
|
<div style="color: ${fontColor}; background-color: ${color};"></div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
`;
|
`;
|
||||||
|
@ -315,9 +363,13 @@ class ButtonCard extends LitElement {
|
||||||
let cardStyle: StyleInfo = {};
|
let cardStyle: StyleInfo = {};
|
||||||
const configCardStyle = this._buildStyle(state, configState);
|
const configCardStyle = this._buildStyle(state, configState);
|
||||||
|
|
||||||
|
if (configCardStyle.width) {
|
||||||
|
this.style.setProperty('flex', '0 0 auto');
|
||||||
|
this.style.setProperty('max-width', 'fit-content');
|
||||||
|
}
|
||||||
switch (this.config!.color_type) {
|
switch (this.config!.color_type) {
|
||||||
case 'blank-card':
|
case 'blank-card':
|
||||||
return this._blankCardColoredHtml(state);
|
return this._blankCardColoredHtml(state, configCardStyle);
|
||||||
case 'card':
|
case 'card':
|
||||||
case 'label-card': {
|
case 'label-card': {
|
||||||
const fontColor = getFontColorBasedOnBackgroundColor(color);
|
const fontColor = getFontColorBasedOnBackgroundColor(color);
|
||||||
|
@ -331,10 +383,6 @@ class ButtonCard extends LitElement {
|
||||||
cardStyle = configCardStyle;
|
cardStyle = configCardStyle;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (configCardStyle.width) {
|
|
||||||
this.style.setProperty('flex', '0 0 auto');
|
|
||||||
this.style.setProperty('max-width', 'fit-content');
|
|
||||||
}
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-card class="button-card-main ${this._isClickable(state) ? '' : 'disabled'}" style=${styleMap(cardStyle)} @ha-click="${this._handleTap}" @ha-hold="${this._handleHold}" .longpress="${longPress()}" .config="${this.config}">
|
<ha-card class="button-card-main ${this._isClickable(state) ? '' : 'disabled'}" style=${styleMap(cardStyle)} @ha-click="${this._handleTap}" @ha-hold="${this._handleHold}" .longpress="${longPress()}" .config="${this.config}">
|
||||||
|
@ -374,15 +422,18 @@ class ButtonCard extends LitElement {
|
||||||
): TemplateResult {
|
): TemplateResult {
|
||||||
const iconTemplate = this._getIconHtml(state, configState, color);
|
const iconTemplate = this._getIconHtml(state, configState, color);
|
||||||
const itemClass: string[] = ['container', containerClass];
|
const itemClass: string[] = ['container', containerClass];
|
||||||
|
const label = this._buildLabel(state, configState);
|
||||||
if (!iconTemplate) itemClass.push('no-icon');
|
if (!iconTemplate) itemClass.push('no-icon');
|
||||||
if (!name) itemClass.push('no-name');
|
if (!name) itemClass.push('no-name');
|
||||||
if (!stateString) itemClass.push('no-state');
|
if (!stateString) itemClass.push('no-state');
|
||||||
|
if (!label) itemClass.push('no-label');
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class=${itemClass.join(' ')}>
|
<div class=${itemClass.join(' ')}>
|
||||||
${iconTemplate ? iconTemplate : ''}
|
${iconTemplate ? iconTemplate : ''}
|
||||||
${name ? html`<div class="name">${name}</div>` : ''}
|
${name ? html`<div class="name">${name}</div>` : ''}
|
||||||
${stateString ? html`<div class="state">${stateString}</div>` : ''}
|
${stateString ? html`<div class="state">${stateString}</div>` : ''}
|
||||||
|
${label ? html`<div class="label">${label}</div>` : ''}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -435,6 +486,7 @@ class ButtonCard extends LitElement {
|
||||||
show_state: false,
|
show_state: false,
|
||||||
show_icon: true,
|
show_icon: true,
|
||||||
show_units: true,
|
show_units: true,
|
||||||
|
show_label: false,
|
||||||
show_entity_picture: false,
|
show_entity_picture: false,
|
||||||
...config,
|
...config,
|
||||||
};
|
};
|
||||||
|
|
|
@ -61,8 +61,9 @@ export function applyBrightnessToColor(
|
||||||
export function hasConfigOrEntityChanged(
|
export function hasConfigOrEntityChanged(
|
||||||
element: any,
|
element: any,
|
||||||
changedProps: PropertyValues,
|
changedProps: PropertyValues,
|
||||||
|
forceUpdate: Boolean,
|
||||||
): boolean {
|
): boolean {
|
||||||
if (changedProps.has('config')) {
|
if (changedProps.has('config') || forceUpdate) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
166
src/styles.ts
166
src/styles.ts
|
@ -79,8 +79,9 @@ export const styles = css`
|
||||||
}
|
}
|
||||||
.img-cell {
|
.img-cell {
|
||||||
grid-area: i;
|
grid-area: i;
|
||||||
min-height: 0;
|
height: 100%;
|
||||||
min-width: 0;
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
|
@ -104,64 +105,164 @@ export const styles = css`
|
||||||
/* margin: auto; */
|
/* margin: auto; */
|
||||||
}
|
}
|
||||||
|
|
||||||
.container.vertical {
|
.label {
|
||||||
grid-template-areas: "i" "n" "s";
|
grid-area: l;
|
||||||
grid-template-columns: 1fr;
|
max-width: 100%;
|
||||||
grid-template-rows: 1fr min-content min-content;
|
align-self: center;
|
||||||
|
justify-self: center;
|
||||||
}
|
}
|
||||||
.container.vertical.no-icon {
|
|
||||||
grid-template-areas: "n" "s";
|
.container.vertical {
|
||||||
|
grid-template-areas: "i" "n" "s" "l";
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
grid-template-rows: 1fr 1fr;
|
grid-template-rows: 1fr min-content min-content min-content;
|
||||||
|
}
|
||||||
|
/* Vertical No Icon */
|
||||||
|
.container.vertical.no-icon {
|
||||||
|
grid-template-areas: "n" "s" "l";
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: 1fr min-content 1fr;
|
||||||
}
|
}
|
||||||
.container.vertical.no-icon .state {
|
.container.vertical.no-icon .state {
|
||||||
align-self: start;
|
align-self: center;
|
||||||
}
|
}
|
||||||
.container.vertical.no-icon .name {
|
.container.vertical.no-icon .name {
|
||||||
align-self: end;
|
align-self: end;
|
||||||
}
|
}
|
||||||
|
.container.vertical.no-icon .label {
|
||||||
|
align-self: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Vertical No Icon No Name */
|
||||||
.container.vertical.no-icon.no-name {
|
.container.vertical.no-icon.no-name {
|
||||||
|
grid-template-areas: "s" "l";
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: 1fr 1fr;
|
||||||
|
}
|
||||||
|
.container.vertical.no-icon.no-name .state {
|
||||||
|
align-self: end;
|
||||||
|
}
|
||||||
|
.container.vertical.no-icon.no-name .label {
|
||||||
|
align-self: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Vertical No Icon No State */
|
||||||
|
.container.vertical.no-icon.no-state {
|
||||||
|
grid-template-areas: "n" "l";
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: 1fr 1fr;
|
||||||
|
}
|
||||||
|
.container.vertical.no-icon.no-state .name {
|
||||||
|
align-self: end;
|
||||||
|
}
|
||||||
|
.container.vertical.no-icon.no-state .label {
|
||||||
|
align-self: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Vertical No Icon No Label */
|
||||||
|
.container.vertical.no-icon.no-label {
|
||||||
|
grid-template-areas: "n" "s";
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: 1fr 1fr;
|
||||||
|
}
|
||||||
|
.container.vertical.no-icon.no-label .name {
|
||||||
|
align-self: end;
|
||||||
|
}
|
||||||
|
.container.vertical.no-icon.no-label .state {
|
||||||
|
align-self: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Vertical No Icon No Label No Name */
|
||||||
|
.container.vertical.no-icon.no-label.no-name {
|
||||||
grid-template-areas: "s";
|
grid-template-areas: "s";
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
grid-template-rows: 1fr;
|
grid-template-rows: 1fr;
|
||||||
}
|
}
|
||||||
.container.vertical.no-icon.no-name .state {
|
.container.vertical.no-icon.no-label.no-name .state {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
.container.vertical.no-icon.no-state {
|
/* Vertical No Icon No Label No State */
|
||||||
|
.container.vertical.no-icon.no-label.no-state {
|
||||||
grid-template-areas: "n";
|
grid-template-areas: "n";
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
grid-template-rows: 1fr;
|
grid-template-rows: 1fr;
|
||||||
}
|
}
|
||||||
.container.vertical.no-icon.no-state .name {
|
.container.vertical.no-icon.no-label.no-state .name {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Vertical No Icon No Name No State */
|
||||||
|
.container.vertical.no-icon.no-name.no-state {
|
||||||
|
grid-template-areas: "l";
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
}
|
||||||
|
.container.vertical.no-icon.no-name.no-state .label {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container.icon_name_state {
|
.container.icon_name_state {
|
||||||
grid-template-areas: "i n";
|
grid-template-areas: "i n" "l l";
|
||||||
grid-template-columns: 40% 1fr;
|
grid-template-columns: 40% 1fr;
|
||||||
grid-template-rows: 1fr;
|
grid-template-rows: 1fr min-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container.icon_name {
|
.container.icon_name {
|
||||||
grid-template-areas: "i n" "s s";
|
grid-template-areas: "i n" "s s" "l l";
|
||||||
grid-template-columns: 40% 1fr;
|
grid-template-columns: 40% 1fr;
|
||||||
grid-template-rows: 1fr min-content;
|
grid-template-rows: 1fr min-content min-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container.icon_state {
|
.container.icon_state {
|
||||||
grid-template-areas: "i s" "n n";
|
grid-template-areas: "i s" "n n" "l l";
|
||||||
grid-template-columns: 40% 1fr;
|
grid-template-columns: 40% 1fr;
|
||||||
grid-template-rows: 1fr min-content;
|
grid-template-rows: 1fr min-content min-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container.name_state {
|
.container.name_state {
|
||||||
grid-template-areas: "i" "n";
|
grid-template-areas: "i" "n" "l";
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
grid-template-rows: 1fr min-content;
|
grid-template-rows: 1fr min-content min-content;
|
||||||
|
}
|
||||||
|
.container.name_state.no-icon {
|
||||||
|
grid-template-areas: "n" "l";
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: 1fr 1fr;
|
||||||
|
}
|
||||||
|
.container.name_state.no-icon .name {
|
||||||
|
align-self: end
|
||||||
|
}
|
||||||
|
.container.name_state.no-icon .label {
|
||||||
|
align-self: start
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container.name_state.no-icon.no-label {
|
||||||
|
grid-template-areas: "n";
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
}
|
||||||
|
.container.name_state.no-icon.no-label .name {
|
||||||
|
align-self: center
|
||||||
|
}
|
||||||
|
|
||||||
|
/* icon_name_state2nd default */
|
||||||
.container.icon_name_state2nd {
|
.container.icon_name_state2nd {
|
||||||
|
grid-template-areas: "i n" "i s" "i l";
|
||||||
|
grid-template-columns: 40% 1fr;
|
||||||
|
grid-template-rows: 1fr min-content 1fr;
|
||||||
|
}
|
||||||
|
.container.icon_name_state2nd .name {
|
||||||
|
align-self: end;
|
||||||
|
}
|
||||||
|
.container.icon_name_state2nd .state {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
.container.icon_name_state2nd .label {
|
||||||
|
align-self: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* icon_name_state2nd No Label */
|
||||||
|
.container.icon_name_state2nd.no-label {
|
||||||
grid-template-areas: "i n" "i s";
|
grid-template-areas: "i n" "i s";
|
||||||
grid-template-columns: 40% 1fr;
|
grid-template-columns: 40% 1fr;
|
||||||
grid-template-rows: 1fr 1fr;
|
grid-template-rows: 1fr 1fr;
|
||||||
|
@ -173,7 +274,24 @@ export const styles = css`
|
||||||
align-self: start;
|
align-self: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* icon_state_name2nd Default */
|
||||||
.container.icon_state_name2nd {
|
.container.icon_state_name2nd {
|
||||||
|
grid-template-areas: "i s" "i n" "i l";
|
||||||
|
grid-template-columns: 40% 1fr;
|
||||||
|
grid-template-rows: 1fr min-content 1fr;
|
||||||
|
}
|
||||||
|
.container.icon_state_name2nd .state {
|
||||||
|
align-self: end;
|
||||||
|
}
|
||||||
|
.container.icon_state_name2nd .name {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
.container.icon_state_name2nd .state {
|
||||||
|
align-self: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* icon_state_name2nd No Label */
|
||||||
|
.container.icon_state_name2nd.no-label {
|
||||||
grid-template-areas: "i s" "i n";
|
grid-template-areas: "i s" "i n";
|
||||||
grid-template-columns: 40% 1fr;
|
grid-template-columns: 40% 1fr;
|
||||||
grid-template-rows: 1fr 1fr;
|
grid-template-rows: 1fr 1fr;
|
||||||
|
@ -184,6 +302,12 @@ export const styles = css`
|
||||||
.container.icon_state_name2nd .name {
|
.container.icon_state_name2nd .name {
|
||||||
align-self: start;
|
align-self: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container.icon_label {
|
||||||
|
grid-template-areas: "i l" "n n" "s s";
|
||||||
|
grid-template-columns: 40% 1fr;
|
||||||
|
grid-template-rows: 1fr min-content min-content;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default styles;
|
export default styles;
|
||||||
|
|
18
src/types.ts
18
src/types.ts
|
@ -23,12 +23,15 @@ export interface ButtonCardConfig {
|
||||||
show_icon?: boolean;
|
show_icon?: boolean;
|
||||||
show_units?: boolean;
|
show_units?: boolean;
|
||||||
show_entity_picture?: boolean;
|
show_entity_picture?: boolean;
|
||||||
|
show_label?: boolean;
|
||||||
|
label?: string;
|
||||||
|
label_template?: string;
|
||||||
entity_picture?: string;
|
entity_picture?: string;
|
||||||
units?: string;
|
units?: string;
|
||||||
style?: CssStyleConfig[];
|
style?: CssStyleConfig[];
|
||||||
state?: StateConfig[];
|
state?: StateConfig[];
|
||||||
confirmation?: string;
|
confirmation?: string;
|
||||||
layout: 'vertical' | 'icon_name_state' | 'name_state' | 'icon_name' | 'icon_state' | 'icon_name_state2nd' | 'icon_state_name2nd';
|
layout: Layout;
|
||||||
entity_picture_style?: CssStyleConfig[];
|
entity_picture_style?: CssStyleConfig[];
|
||||||
|
|
||||||
default_color: string;
|
default_color: string;
|
||||||
|
@ -36,8 +39,17 @@ export interface ButtonCardConfig {
|
||||||
color_off: string;
|
color_off: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type Layout = 'vertical'
|
||||||
|
| 'icon_name_state'
|
||||||
|
| 'name_state'
|
||||||
|
| 'icon_name'
|
||||||
|
| 'icon_state'
|
||||||
|
| 'icon_name_state2nd'
|
||||||
|
| 'icon_state_name2nd'
|
||||||
|
| 'icon_label';
|
||||||
|
|
||||||
export interface StateConfig {
|
export interface StateConfig {
|
||||||
operator?: '<' | '<=' | '==' | '>=' | '>' | '!=' | 'regex' | 'default';
|
operator?: '<' | '<=' | '==' | '>=' | '>' | '!=' | 'regex' | 'template' | 'default';
|
||||||
value?: any;
|
value?: any;
|
||||||
name?: string;
|
name?: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
|
@ -46,6 +58,8 @@ export interface StateConfig {
|
||||||
entity_picture_style?: CssStyleConfig[];
|
entity_picture_style?: CssStyleConfig[];
|
||||||
entity_picture?: string;
|
entity_picture?: string;
|
||||||
spin?: boolean;
|
spin?: boolean;
|
||||||
|
label?: string;
|
||||||
|
label_template?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CssStyleConfig {
|
export interface CssStyleConfig {
|
||||||
|
|
Loading…
Reference in New Issue