diff --git a/README.md b/README.md index 7651844..85dc390 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/button-card.js b/button-card.js index a71b5bc..4b4ddd7 100644 --- a/button-card.js +++ b/button-card.js @@ -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` +
+
+
+
+ ${this.config.show_icon && icon ? html`` : ''} +
+ ${nameStateString ? html`
${nameStateString}
` : ''} +
+
+
+ `; + case 'icon_name': + return html` +
+
+
+
+ ${this.config.show_icon && icon ? html`` : ''} +
+ ${name ? html`
${name}
` : ''} +
+
+
+ ${stateString != null ? html`
${stateString}
` : ''} + `; + case 'icon_state': + return html` +
+
+
+
+ ${this.config.show_icon && icon ? html`` : ''} +
+ ${stateString != null ? html`
${stateString}
` : ''} +
+
+
+ ${name ? html`
${name}
` : ''} + `; + case 'icon_state_name2nd': + return html` +
+
+
+
+ ${this.config.show_icon && icon ? html`` : ''} +
+ ${stateString != null && name ? html`
${stateString}
${name}
` : ''} + ${!stateString && name ? html`
${name}
` : ''} + ${stateString && !name ? html`
${stateString}
` : ''} +
+
+
+ `; + case 'icon_name_state2nd': + return html` +
+
+
+
+ ${this.config.show_icon && icon ? html`` : ''} +
+ ${stateString != null && name ? html`
${name}
${stateString}
` : ''} + ${!stateString && name ? html`
${name}
` : ''} + ${stateString && !name ? html`
${stateString}
` : ''} +
+
+
+ `; + case 'name_state': + return html` + ${this.config.show_icon && icon ? html`` : ''} + ${nameStateString ? html`
${nameStateString}
` : ''} + `; + case 'vertical': + default: + return html` + ${this.config.show_icon && icon ? html`` : ''} + ${name ? html`
${name}
` : ''} + ${stateString ? html`
${stateString}
` : ''} + `; + } + } + 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` - -
-
- ${config.show_icon && icon ? html`` : ''} - ${config.show_name && name ? html`
${name}
` : ''} -
-
- -
- `; - } - 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`
- ${config.show_icon && icon ? html`` : ''} - ${config.show_name && name ? html`
${name}
` : ''} - ${config.show_state ? html`
${state.state} ${state.attributes.unit_of_measurement ? state.attributes.unit_of_measurement : ''}
` : ''} + ${this.buttonContent(state, configState, null)}
@@ -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`
- ${config.show_icon && icon ? html`` : ''} - ${config.show_name && name ? html`
${name}
` : ''} - ${config.show_state ? html`
${state.state} ${state.attributes.unit_of_measurement ? state.attributes.unit_of_measurement : ''}
` : ''} + ${this.buttonContent(state, configState, color)}
@@ -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)'; diff --git a/examples/layout.png b/examples/layout.png new file mode 100644 index 0000000..20940f6 Binary files /dev/null and b/examples/layout.png differ