* Add layout, show_units and units options

* Refactor

* Adding 2 new layout options

* Update documentation for layout
This commit is contained in:
Jérôme W 2019-04-23 09:13:54 +02:00 committed by GitHub
parent 06e000c10e
commit 0cb256ee46
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 187 additions and 30 deletions

View File

@ -23,6 +23,8 @@ Lovelace Button card for your entities.
- custom size (optional)
- custom icon (optional)
- custom css style (optional)
- multiple [layout](#Layout) support
- units can be redefined or hidden
- 2 color types
- `icon` : apply color settings to the icon only
- `card` : apply color settings to the card only
@ -58,9 +60,12 @@ If you don't have a standard home-assistant card with long-press enabled in your
| `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_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. |
| `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 |
| `style` | object list | optional | `- text-transform: none` | Define a list of css attribute and their value to apply to the card |
| `state` | object list | optional | See [State](#State) | State to use for the color, icon and style of the button. Multiple states can be defined |
| `confirmation` | string | optional | Free-form text | Show a confirmation popup on tap with defined text |
| `layout` | string | optional | See [Layout](#Layout) | The layout of the button can be modified using this option |
### Action
@ -99,6 +104,23 @@ If you don't have a standard home-assistant card with long-press enabled in your
| `regex` | `'^norm.*$'` | `value` regex applied to current state does match |
| `default` | N/A | If nothing matches, this is used |
### Layout
This option enables you to modify the layout of the card.
It is fully compatible with every `show_*` option. Make sure you set `show_state: true` if you want to show the state
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
* `icon_name_state`: Everything is aligned horizontally, name and state are concatenated
* `name_state`: Icon sits on top of name and state concatenated on one line
* `icon_name`: Icon and name are horizontally aligned, state is centered below
* `icon_state`: Icon and state are horizontally aligned, name is centered below
* `icon_name_state2nd`: Icon, name and state are horizontally aligned, name is above state
* `icon_state_name2nd`: Icon, name and state are horizontally aligned, state is above name
![layout_image](examples/layout.png)
## Installation
### Manual Installation

View File

@ -138,6 +138,28 @@ export default function domainIcon(domain, state) {
letter-spacing: normal;
width: 100%;
}
div.divTable{
display: table;
overflow: auto;
table-layout: fixed;
width: 100%;
}
div.divTableBody {
display: table-row-group;
}
div.divTableRow {
display: table-row;
}
.divTableCell {
display: table-cell;
vertical-align: middle;
}
div {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
min-width: 100%;
}
div.button-card-background-color {
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
@ -215,7 +237,6 @@ export default function domainIcon(domain, state) {
case 'blank-card':
return this.blankCardColoredHtml(state, this.config, configState);
case 'label-card':
return this.labelCardColoredHtml(state, this.config, configState);
case 'card':
return this.cardColoredHtml(state, this.config, configState);
case 'icon':
@ -378,6 +399,9 @@ export default function domainIcon(domain, state) {
}
buildName(state, configState) {
if (this.config.show_name === false) {
return null;
}
let name = null;
if (configState && configState.name) {
name = configState.name;
@ -392,6 +416,50 @@ export default function domainIcon(domain, state) {
return name;
}
buildStateString(state) {
let stateString = null;
if (this.config.show_state && state && state.state) {
const units = this.buildUnits(state);
if (units) {
stateString = state.state + " " + units;
} else {
stateString = state.state
}
}
return stateString;
}
buildUnits(state) {
let units = null;
if (state) {
if (this.config.show_units) {
if (state.attributes && state.attributes.unit_of_measurement && !this.config.units) {
units = state.attributes.unit_of_measurement;
} else {
units = this.config.units ? this.config.units : null;
}
}
}
return units;
}
buildNameStateConcat(name, stateString) {
if (!name && !stateString) {
return null;
}
let nameStateString = null
if (stateString !== null) {
if (name) {
nameStateString = name + ": " + stateString;
} else {
nameStateString = stateString;
}
} else {
nameStateString = name;
}
return nameStateString;
}
isClickable(state, config) {
let clickable = true;
if (config.tap_action.action == 'toggle') {
@ -418,6 +486,99 @@ export default function domainIcon(domain, state) {
return configState && configState.spin ? 'rotating' : '';
}
buttonContent(state, configState, color) {
const icon = this.buildIcon(state, this.config, configState);
const name = this.buildName(state, configState);
const stateString = this.buildStateString(state);
const nameStateString = this.buildNameStateConcat(name, stateString);
switch (this.config.layout) {
case 'icon_name_state':
return html`
<div class="divTable">
<div class="divTableBody">
<div class="divTableRow">
<div class="divTableCell" style="width: ${this.config.size}; height: auto;">
${this.config.show_icon && icon ? html`<ha-icon style="color: ${color ? color : "inherit"}; width: auto; height: auto; max-width: ${this.config.size};" icon="${icon}" class="${this.rotate(configState)}"></ha-icon>` : ''}
</div>
${nameStateString ? html`<div class="divTableCell">${nameStateString}</div>` : ''}
</div>
</div>
</div>
`;
case 'icon_name':
return html`
<div class="divTable">
<div class="divTableBody">
<div class="divTableRow">
<div class="divTableCell" style="width: ${this.config.size}; height: auto;">
${this.config.show_icon && icon ? html`<ha-icon style="color: ${color ? color : "inherit"}; width: auto; height: auto; max-width: ${this.config.size};" icon="${icon}" class="${this.rotate(configState)}"></ha-icon>` : ''}
</div>
${name ? html`<div class="divTableCell">${name}</div>` : ''}
</div>
</div>
</div>
${stateString != null ? html`<div>${stateString}</div>` : ''}
`;
case 'icon_state':
return html`
<div class="divTable">
<div class="divTableBody">
<div class="divTableRow">
<div class="divTableCell" style="width: ${this.config.size}; height: auto;">
${this.config.show_icon && icon ? html`<ha-icon style="color: ${color ? color : "inherit"}; width: auto; height: auto; max-width: ${this.config.size};" icon="${icon}" class="${this.rotate(configState)}"></ha-icon>` : ''}
</div>
${stateString != null ? html`<div class="divTableCell">${stateString}</div>` : ''}
</div>
</div>
</div>
${name ? html`<div>${name}</div>` : ''}
`;
case 'icon_state_name2nd':
return html`
<div class="divTable">
<div class="divTableBody">
<div class="divTableRow">
<div class="divTableCell" style="width: ${this.config.size}; height: auto;">
${this.config.show_icon && icon ? html`<ha-icon style="color: ${color ? color : "inherit"}; width: auto; height: auto; max-width: ${this.config.size};" icon="${icon}" class="${this.rotate(configState)}"></ha-icon>` : ''}
</div>
${stateString != null && name ? html`<div class="divTableCell">${stateString}<br/>${name}</div>` : ''}
${!stateString && name ? html`<div class="divTableCell">${name}</div>` : ''}
${stateString && !name ? html`<div class="divTableCell">${stateString}</div>` : ''}
</div>
</div>
</div>
`;
case 'icon_name_state2nd':
return html`
<div class="divTable">
<div class="divTableBody">
<div class="divTableRow">
<div class="divTableCell" style="width: ${this.config.size}; height: auto;">
${this.config.show_icon && icon ? html`<ha-icon style="color: ${color ? color : "inherit"}; width: auto; height: auto; max-width: ${this.config.size};" icon="${icon}" class="${this.rotate(configState)}"></ha-icon>` : ''}
</div>
${stateString != null && name ? html`<div class="divTableCell">${name}<br/>${stateString}</div>` : ''}
${!stateString && name ? html`<div class="divTableCell">${name}</div>` : ''}
${stateString && !name ? html`<div class="divTableCell">${stateString}</div>` : ''}
</div>
</div>
</div>
`;
case 'name_state':
return html`
${this.config.show_icon && icon ? html`<ha-icon style="color: ${color ? color : "inherit"}; width: ${this.config.size}; height: auto;" icon="${icon}" class="${this.rotate(configState)}"></ha-icon>` : ''}
${nameStateString ? html`<div>${nameStateString}</div>` : ''}
`;
case 'vertical':
default:
return html`
${this.config.show_icon && icon ? html`<ha-icon style="color: ${color ? color : "inherit"}; width: ${this.config.size}; height: auto;" icon="${icon}" class="${this.rotate(configState)}"></ha-icon>` : ''}
${name ? html`<div>${name}</div>` : ''}
${stateString ? html`<div>${stateString}</div>` : ''}
`;
}
}
blankCardColoredHtml(state, config, configState) {
const color = this.buildCssColorAttribute(state, config);
const fontColor = this.getFontColorBasedOnBackgroundColor(color);
@ -428,38 +589,15 @@ export default function domainIcon(domain, state) {
`;
}
labelCardColoredHtml(state, config, configState) {
const color = this.buildCssColorAttribute(state, config, configState);
const fontColor = this.getFontColorBasedOnBackgroundColor(color);
const icon = this.buildIcon(state, config, configState);
const style = this.buildStyle(state, config, configState);
const name = this.buildName(state, configState);
return html`
<ha-card class="${this.isClickable(state, config) ? '' : "disabled"}" @ha-click="${ev => this._handleTap(state, config, false)}" @ha-hold="${ev => this._handleTap(state, config, true)}">
<div class="button-card-background-color" style="color: ${fontColor}; background-color: ${color};">
<div class="button-card-main" style="${style}">
${config.show_icon && icon ? html`<ha-icon style="width: ${config.size}; height: auto;" icon="${icon}" class="${this.rotate(configState)}"></ha-icon>` : ''}
${config.show_name && name ? html`<div>${name}</div>` : ''}
</div>
</div>
<mwc-ripple></mwc-ripple>
</ha-card>
`;
}
cardColoredHtml(state, config, configState) {
const color = this.buildCssColorAttribute(state, config, configState);
const fontColor = this.getFontColorBasedOnBackgroundColor(color);
const icon = this.buildIcon(state, config, configState);
const style = this.buildStyle(state, config, configState);
const name = this.buildName(state, configState);
return html`
<ha-card class="${this.isClickable(state, config) ? '' : "disabled"}" @ha-click="${ev => this._handleTap(state, config, false)}" @ha-hold="${ev => this._handleTap(state, config, true)}">
<div class="button-card-background-color" style="color: ${fontColor}; background-color: ${color};">
<div class="button-card-main" style="${style}">
${config.show_icon && icon ? html`<ha-icon style="width: ${config.size}; height: auto;" icon="${icon}" class="${this.rotate(configState)}"></ha-icon>` : ''}
${config.show_name && name ? html`<div>${name}</div>` : ''}
${config.show_state ? html`<div>${state.state} ${state.attributes.unit_of_measurement ? state.attributes.unit_of_measurement : ''}</div>` : ''}
${this.buttonContent(state, configState, null)}
</div>
</div>
<mwc-ripple></mwc-ripple>
@ -469,15 +607,11 @@ export default function domainIcon(domain, state) {
iconColoredHtml(state, config, configState) {
const color = this.buildCssColorAttribute(state, config, configState);
const icon = this.buildIcon(state, config, configState);
const style = this.buildStyle(state, config, configState);
const name = this.buildName(state, configState);
return html`
<ha-card class="${this.isClickable(state, config) ? '' : "disabled"}" @ha-click="${ev => this._handleTap(state, config, false)}" @ha-hold="${ev => this._handleTap(state, config, true)}">
<div class="button-card-main" style="${style}">
${config.show_icon && icon ? html`<ha-icon style="color: ${color}; width: ${config.size}; height: auto;" icon="${icon}" class="${this.rotate(configState)}"></ha-icon>` : ''}
${config.show_name && name ? html`<div>${name}</div>` : ''}
${config.show_state ? html`<div>${state.state} ${state.attributes.unit_of_measurement ? state.attributes.unit_of_measurement : ''}</div>` : ''}
${this.buttonContent(state, configState, color)}
</div>
<mwc-ripple></mwc-ripple>
</ha-card>
@ -493,6 +627,7 @@ export default function domainIcon(domain, state) {
show_name: true,
show_state: false,
show_icon: true,
show_units: true,
...config
};
this.config.color_off = 'var(--paper-item-icon-color)';

BIN
examples/layout.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB