Use 0.98 jinja template subscriptions. Also style entity rows and glance entities
This commit is contained in:
parent
60a6d80116
commit
27ebb26c26
63
README.md
63
README.md
@ -59,7 +59,7 @@ entities:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
You can also use [templates](https://github.com/thomasloven/hass-config/wiki/Mod-plugin-templates) to change the styles dynamically.
|
You can also use [templating](https://www.home-assistant.io/docs/configuration/templating/) to change the styles dynamically.
|
||||||
|
|
||||||
**Example** \
|
**Example** \
|
||||||
Make an `entity-button` card green when the light is on
|
Make an `entity-button` card green when the light is on
|
||||||
@ -69,7 +69,7 @@ type: entity-button
|
|||||||
entity: light.bed_light
|
entity: light.bed_light
|
||||||
style: |
|
style: |
|
||||||
ha-card {
|
ha-card {
|
||||||
background: [[ if(light.bed_light == "on", "green", "") ]];
|
background: {% if is_state('light.bed_light', 'on') %} green {% endif %};
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -100,9 +100,43 @@ style: |
|
|||||||
## More examples
|
## More examples
|
||||||
More examples are available [here](https://github.com/thomasloven/lovelace-card-mod/blob/master/src/example.yaml).
|
More examples are available [here](https://github.com/thomasloven/lovelace-card-mod/blob/master/src/example.yaml).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
## Styling entity and glance cards
|
||||||
|
|
||||||
|
To make things easier, rows in `entities` cards and buttons in `glance` cards can be styled individually.
|
||||||
|
For those, the styles will be applied to the shadowRoot of the element, so a good starting point (rather than `ha-card`) would be `:host`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
type: entities
|
||||||
|
entities:
|
||||||
|
- light.bed_light
|
||||||
|
- entity: light.kitchen_lights
|
||||||
|
style: |
|
||||||
|
:host {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
- entity: input_number.value
|
||||||
|
style: |
|
||||||
|
:host {
|
||||||
|
--paper-item-icon-color:
|
||||||
|
{% if states(config.entity)|int < 50 %}
|
||||||
|
blue
|
||||||
|
{% else %}
|
||||||
|
red
|
||||||
|
{% endif %}
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Templating
|
||||||
|
Jinja templates have access to a few special variables. Those are:
|
||||||
|
|
||||||
|
- `config` - an object containing the card, entity row or glance button configuration
|
||||||
|
- `user` - the username of the currently logged in user
|
||||||
|
- `browser` - the deviceID of the current browser (see [browser_mod](https://github.com/thomasloven/hass-browser_mod).
|
||||||
|
- `hash` - the hash part of the current URL.
|
||||||
|
|
||||||
## Advanced usage
|
## Advanced usage
|
||||||
|
|
||||||
When exploring the cards using the element inspector, you might run into something called a `shadow-root` and notice that you can't apply styles to anything inside that.
|
When exploring the cards using the element inspector, you might run into something called a `shadow-root` and notice that you can't apply styles to anything inside that.
|
||||||
@ -147,6 +181,29 @@ entity: alarm_control_panel.alarm
|
|||||||
|
|
||||||
# FAQ
|
# FAQ
|
||||||
|
|
||||||
|
### How do I convert my old card-modder configuration to card-mod?
|
||||||
|
For cards, you just have to wrap everything in `ha-card {}` and format it as CSS.
|
||||||
|
|
||||||
|
So, you go from:
|
||||||
|
```yaml
|
||||||
|
style:
|
||||||
|
"--ha-card-background": rgba(200, 0, 0, 0.5)
|
||||||
|
color: white
|
||||||
|
```
|
||||||
|
|
||||||
|
to
|
||||||
|
```yaml
|
||||||
|
style: |
|
||||||
|
ha-card {
|
||||||
|
--ha-card-background: rgba(200, 0, 0, 0.5);
|
||||||
|
color: white
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For rows in an entities card, you replace `ha-card` with `:host` as described above.
|
||||||
|
|
||||||
|
Note that some cards can't be modded with card-mod. See below.
|
||||||
|
|
||||||
### Why won't this work for some cards?
|
### Why won't this work for some cards?
|
||||||
The cards this doesn't work for often are not really *cards* at all, but change how other cards work. Examples include: `conditional`, `entity-filter`, `horizontal-stack` and `vertical-stack` as well as some custom cards, like `layout-card`, `auto-entities` and `state-switch` among others.
|
The cards this doesn't work for often are not really *cards* at all, but change how other cards work. Examples include: `conditional`, `entity-filter`, `horizontal-stack` and `vertical-stack` as well as some custom cards, like `layout-card`, `auto-entities` and `state-switch` among others.
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
249
src/example.yaml
249
src/example.yaml
@ -1,15 +1,13 @@
|
|||||||
title: card-mod
|
title: card-mod
|
||||||
cards:
|
cards:
|
||||||
|
# Style the card, but use special styles for the header
|
||||||
- type: entities
|
- type: entities
|
||||||
title: Default
|
title: Simple configuration
|
||||||
entities:
|
|
||||||
- light.bed_light
|
|
||||||
- light.ceiling_lights
|
|
||||||
- light.kitchen_lights
|
|
||||||
|
|
||||||
- type: entities
|
|
||||||
style: |
|
style: |
|
||||||
ha-card {
|
ha-card {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
.card-header {
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
entities:
|
entities:
|
||||||
@ -17,41 +15,55 @@ cards:
|
|||||||
- light.ceiling_lights
|
- light.ceiling_lights
|
||||||
- light.kitchen_lights
|
- light.kitchen_lights
|
||||||
|
|
||||||
- type: glance
|
# Style an entities card row separately
|
||||||
title: Glance card
|
- type: entities
|
||||||
|
title: Styled rows
|
||||||
|
entities:
|
||||||
|
- light.bed_light
|
||||||
|
- entity: light.ceiling_lights
|
||||||
|
style: |
|
||||||
|
:host {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
- type: section
|
||||||
|
label: A section label
|
||||||
|
style: |
|
||||||
|
:host {
|
||||||
|
--primary-color: red;
|
||||||
|
}
|
||||||
|
- entity: light.kitchen_lights
|
||||||
|
|
||||||
|
|
||||||
|
# Styles that update to state changes using jinja2 templating
|
||||||
|
- type: entities
|
||||||
|
title: Dynamic styles
|
||||||
style: |
|
style: |
|
||||||
ha-card {
|
ha-card {
|
||||||
font-variant: small-caps;
|
background: url(http://place{{ states("input_select.background") }}.com/g/600/400);
|
||||||
}
|
--primary-text-color: rgb(250,250,250);
|
||||||
.card-header {
|
--paper-listbox-background-color: black;
|
||||||
font-size: 16px;
|
text-shadow: 1px 1px 0 #000;
|
||||||
}
|
}
|
||||||
entities:
|
entities:
|
||||||
|
- input_select.background
|
||||||
- light.bed_light
|
- light.bed_light
|
||||||
- light.ceiling_lights
|
- light.ceiling_lights
|
||||||
- light.kitchen_lights
|
- light.kitchen_lights
|
||||||
|
|
||||||
|
# Using the "config" special variable for templates
|
||||||
- type: entity-button
|
- type: entity-button
|
||||||
entity: light.bed_light
|
entity: light.bed_light
|
||||||
style: |
|
style: |
|
||||||
ha-card {
|
ha-card {
|
||||||
background: [[ if(light.bed_light == "on", "green", "") ]];
|
background:
|
||||||
}
|
{% if is_state(config.entity, 'on') %}
|
||||||
|
green
|
||||||
- type: entity-button
|
{% endif %}
|
||||||
entity: light.bed_light
|
;
|
||||||
style: |
|
|
||||||
@keyframes blink {
|
|
||||||
50% {
|
|
||||||
background: red;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ha-card {
|
|
||||||
animation: blink 2s linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
# Advanced css selectors can be used
|
||||||
- type: entities
|
- type: entities
|
||||||
title: Styled
|
title: Advanced CSS rules
|
||||||
style: |
|
style: |
|
||||||
ha-card {
|
ha-card {
|
||||||
background: rgba(0,50,0,0.5);
|
background: rgba(0,50,0,0.5);
|
||||||
@ -66,29 +78,48 @@ cards:
|
|||||||
- light.kitchen_lights
|
- light.kitchen_lights
|
||||||
- light.bed_light
|
- light.bed_light
|
||||||
|
|
||||||
|
# Cards can be made transparent by removing background and box-shadow
|
||||||
- type: entities
|
- type: entities
|
||||||
title: Dynamic styles
|
title: Transparent card
|
||||||
|
show_header_toggle: false
|
||||||
style: |
|
style: |
|
||||||
ha-card {
|
ha-card {
|
||||||
background: url(http://place[[ input_select.background.state ]].com/g/600/400);
|
background: none;
|
||||||
--primary-text-color: rgb(250,250,250);
|
box-shadow: none;
|
||||||
color: [[ if(light.bed_light == "on", "rgb(250,250,250)", "red") ]];
|
}
|
||||||
--paper-listbox-background-color: black;
|
entities:
|
||||||
text-shadow: 1px 1px 0 #000;
|
- type: custom:text-divider-row
|
||||||
|
text: blah
|
||||||
|
|
||||||
|
# Entities in glance cards can also be styled individually
|
||||||
|
- type: glance
|
||||||
|
title: Glance card
|
||||||
|
style: |
|
||||||
|
ha-card {
|
||||||
|
font-variant: small-caps;
|
||||||
|
}
|
||||||
|
.card-header {
|
||||||
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
entities:
|
entities:
|
||||||
- input_select.background
|
|
||||||
- light.bed_light
|
- light.bed_light
|
||||||
- light.ceiling_lights
|
- entity: light.ceiling_lights
|
||||||
|
style: |
|
||||||
|
:host {
|
||||||
|
font-variant: none;
|
||||||
|
}
|
||||||
- light.kitchen_lights
|
- light.kitchen_lights
|
||||||
|
|
||||||
|
# Adjustable picture elements position
|
||||||
|
# This could be much more useful with, say, an x and y value taken from sensor values
|
||||||
|
# that e.g. contain your robot vacuum cleaner location...
|
||||||
- type: vertical-stack
|
- type: vertical-stack
|
||||||
cards:
|
cards:
|
||||||
- type: picture-elements
|
- type: picture-elements
|
||||||
style: |
|
style: |
|
||||||
ha-card {
|
ha-card {
|
||||||
--top: [[ input_number.y_pos.state ]]%;
|
--top: {{ states("input_number.y_pos") }}%;
|
||||||
--left: [[ input_number.x_pos.state ]]%;
|
--left: {{ states("input_number.x_pos") }}%;
|
||||||
}
|
}
|
||||||
title: Dynamic styling of elements
|
title: Dynamic styling of elements
|
||||||
image: "http://placekitten.com/g/800/600"
|
image: "http://placekitten.com/g/800/600"
|
||||||
@ -103,6 +134,7 @@ cards:
|
|||||||
- input_number.x_pos
|
- input_number.x_pos
|
||||||
- input_number.y_pos
|
- input_number.y_pos
|
||||||
|
|
||||||
|
# Some animations
|
||||||
- type: horizontal-stack
|
- type: horizontal-stack
|
||||||
cards:
|
cards:
|
||||||
- type: entity-button
|
- type: entity-button
|
||||||
@ -114,7 +146,7 @@ cards:
|
|||||||
}
|
}
|
||||||
@keyframes blink {
|
@keyframes blink {
|
||||||
50% {
|
50% {
|
||||||
filter: invert(100%);
|
background: red;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
- type: entity-button
|
- type: entity-button
|
||||||
@ -160,100 +192,7 @@ cards:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Keyframes are inherited into picture-elements elements as well...
|
||||||
|
|
||||||
- type: horizontal-stack
|
|
||||||
cards:
|
|
||||||
- type: entity-button
|
|
||||||
entity: light.bed_light
|
|
||||||
name: swing
|
|
||||||
style: |
|
|
||||||
ha-card {
|
|
||||||
animation: swing 1s linear infinite alternate;
|
|
||||||
}
|
|
||||||
@keyframes swing {
|
|
||||||
0% {
|
|
||||||
-webkit-transform: rotate(5deg);
|
|
||||||
transform: rotate(5deg);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
-webkit-transform: rotate(-5deg);
|
|
||||||
transform: rotate(-5deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- type: entity-button
|
|
||||||
entity: light.bed_light
|
|
||||||
name: swell
|
|
||||||
style: |
|
|
||||||
ha-card {
|
|
||||||
animation: pulse 3s linear infinite alternate;
|
|
||||||
}
|
|
||||||
@keyframes blinka {
|
|
||||||
50% { background: white; }
|
|
||||||
100% { background: blue; }
|
|
||||||
}
|
|
||||||
@keyframes pulse {
|
|
||||||
0% {
|
|
||||||
-webkit-transform: scaleX(1);
|
|
||||||
transform: scaleX(1);
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
-webkit-transform: scale3d(1.15,1.15,1.15);
|
|
||||||
transform: scale3d(1.15,1.15,1.15);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
-webkit-transform: scaleX(1);
|
|
||||||
transform: scaleX(1);
|
|
||||||
}
|
|
||||||
- type: entity-button
|
|
||||||
entity: light.bed_light
|
|
||||||
name: flip
|
|
||||||
style: |
|
|
||||||
ha-card {
|
|
||||||
animation: flip 5s linear infinite
|
|
||||||
}
|
|
||||||
@keyframes blinka {
|
|
||||||
50% { background: white; }
|
|
||||||
100% { background: red; }
|
|
||||||
}
|
|
||||||
@keyframes flip {
|
|
||||||
0% {
|
|
||||||
-webkit-animation-timing-function: ease-out;
|
|
||||||
-webkit-transform: perspective(400px) scaleX(1) translateZ(0) rotateY(-1turn);
|
|
||||||
animation-timing-function: ease-out;
|
|
||||||
transform: perspective(400px) scaleX(1) translateZ(0) rotateY(-1turn)
|
|
||||||
}
|
|
||||||
|
|
||||||
40% {
|
|
||||||
-webkit-animation-timing-function: ease-out;
|
|
||||||
-webkit-transform: perspective(400px) scaleX(1) translateZ(150px) rotateY(-190deg);
|
|
||||||
animation-timing-function: ease-out;
|
|
||||||
transform: perspective(400px) scaleX(1) translateZ(150px) rotateY(-190deg)
|
|
||||||
}
|
|
||||||
|
|
||||||
50% {
|
|
||||||
-webkit-animation-timing-function: ease-in;
|
|
||||||
-webkit-transform: perspective(400px) scaleX(1) translateZ(150px) rotateY(-170deg);
|
|
||||||
animation-timing-function: ease-in;
|
|
||||||
transform: perspective(400px) scaleX(1) translateZ(150px) rotateY(-170deg)
|
|
||||||
}
|
|
||||||
|
|
||||||
80% {
|
|
||||||
-webkit-animation-timing-function: ease-in;
|
|
||||||
-webkit-transform: perspective(400px) scale3d(.95,.95,.95) translateZ(0) rotateY(0deg);
|
|
||||||
animation-timing-function: ease-in;
|
|
||||||
transform: perspective(400px) scale3d(.95,.95,.95) translateZ(0) rotateY(0deg)
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
-webkit-animation-timing-function: ease-in;
|
|
||||||
-webkit-transform: perspective(400px) scaleX(1) translateZ(0) rotateY(0deg);
|
|
||||||
animation-timing-function: ease-in;
|
|
||||||
transform: perspective(400px) scaleX(1) translateZ(0) rotateY(0deg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- type: picture-elements
|
- type: picture-elements
|
||||||
style: |
|
style: |
|
||||||
@keyframes dvd {
|
@keyframes dvd {
|
||||||
@ -288,6 +227,9 @@ cards:
|
|||||||
animation: dvd 10s linear infinite
|
animation: dvd 10s linear infinite
|
||||||
left: 0%
|
left: 0%
|
||||||
top: 50%
|
top: 50%
|
||||||
|
|
||||||
|
# An example of going into shadowroots of stuff
|
||||||
|
# Not for the faint of heart
|
||||||
- type: alarm-panel
|
- type: alarm-panel
|
||||||
card_icon: mdi:bell
|
card_icon: mdi:bell
|
||||||
name: Alarm Panel
|
name: Alarm Panel
|
||||||
@ -311,3 +253,44 @@ cards:
|
|||||||
--mdc-theme-primary: green;
|
--mdc-theme-primary: green;
|
||||||
}
|
}
|
||||||
entity: alarm_control_panel.alarm
|
entity: alarm_control_panel.alarm
|
||||||
|
|
||||||
|
# By placing a stack in an entities card as a row, it can be modded as well.
|
||||||
|
- type: entities
|
||||||
|
style: |
|
||||||
|
ha-card {
|
||||||
|
--ha-card-background: red;
|
||||||
|
box-shadow: none;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.card-content {
|
||||||
|
padding: 0
|
||||||
|
}
|
||||||
|
entities:
|
||||||
|
- type: custom:hui-horizontal-stack-card
|
||||||
|
cards:
|
||||||
|
- type: entities
|
||||||
|
entities:
|
||||||
|
- light.bed_light
|
||||||
|
- light.kitchen_lights
|
||||||
|
- light.ceiling_lights
|
||||||
|
- type: glance
|
||||||
|
entities:
|
||||||
|
- light.bed_light
|
||||||
|
- light.kitchen_lights
|
||||||
|
- light.ceiling_lights
|
||||||
|
|
||||||
|
# Automatically styled entity rows
|
||||||
|
# Makes use of config variable
|
||||||
|
- type: custom:auto-entities
|
||||||
|
filter:
|
||||||
|
include:
|
||||||
|
- domain: light
|
||||||
|
options:
|
||||||
|
style: |
|
||||||
|
:host {
|
||||||
|
color: {% if is_state(config.entity, 'on') %} green {% endif %};
|
||||||
|
}
|
||||||
|
card:
|
||||||
|
type: entities
|
||||||
|
title: Auto-entities
|
||||||
|
|
||||||
|
251
src/main.js
251
src/main.js
@ -1,6 +1,78 @@
|
|||||||
import {html, css} from "/card-tools/lit-element.js";
|
import {html, css} from "/card-tools/lit-element.js";
|
||||||
import {fireEvent} from "/card-tools/event.js";
|
import {fireEvent} from "/card-tools/event.js";
|
||||||
import {parseTemplate} from "/card-tools/templates.js";
|
import {subscribeRenderTemplate} from "/card-tools/templates.js";
|
||||||
|
|
||||||
|
const applyStyle = async function(root, style, params, debug) {
|
||||||
|
|
||||||
|
const debugPrint = function(str){
|
||||||
|
if(!debug) return;
|
||||||
|
if(typeof str === "string")
|
||||||
|
console.log(' '.repeat(2*(debug-1)) + str);
|
||||||
|
else
|
||||||
|
console.log(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!root || !style) return;
|
||||||
|
|
||||||
|
if(root.updateComplete)
|
||||||
|
await root.updateComplete;
|
||||||
|
|
||||||
|
if(typeof style === "string") {
|
||||||
|
const oldStyleEl = root.querySelector(".card-mod-style");
|
||||||
|
if(oldStyleEl)
|
||||||
|
{
|
||||||
|
// Remove old styles and cancel template subscriptions
|
||||||
|
if(oldStyleEl.cancelSubscription)
|
||||||
|
{
|
||||||
|
await oldStyleEl.cancelSubscription;
|
||||||
|
}
|
||||||
|
root.removeChild(oldStyleEl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new style tag to the root element
|
||||||
|
const styleEl = document.createElement('style');
|
||||||
|
styleEl.classList = "card-mod-style";
|
||||||
|
styleEl.cancelSubscription = subscribeRenderTemplate(
|
||||||
|
null,
|
||||||
|
(result) => {
|
||||||
|
styleEl.innerHTML = result;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
template: style,
|
||||||
|
variables: params.variables,
|
||||||
|
entity_ids: params.entity_ids,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
root.appendChild(styleEl);
|
||||||
|
debugPrint("Applied styles to:");
|
||||||
|
debugPrint(root);
|
||||||
|
} else {
|
||||||
|
Object.keys(style).forEach((k) => {
|
||||||
|
if(k === ".") {
|
||||||
|
debugPrint(`Stepping into root of ${root.tagName}`)
|
||||||
|
return applyStyle(root, style[k], params, debug?debug+1:0);
|
||||||
|
} else if(k === "$") {
|
||||||
|
debugPrint(`Stepping into ShadowRoot of ${root.tagName}`)
|
||||||
|
return applyStyle(root.shadowRoot, style[k], params, debug?debug+1:0);
|
||||||
|
} else {
|
||||||
|
debugPrint(`Searching for: "${k}". ${root.querySelectorAll(k).length} matches.`);
|
||||||
|
root.querySelectorAll(`${k}`).forEach((el) => {
|
||||||
|
debugPrint(`Stepping into ${el.tagName}`)
|
||||||
|
applyStyle(el, style[k], params, debug?debug+1:0);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const find_entity_ids = function(data) {
|
||||||
|
if(typeof(data) === "string") {
|
||||||
|
return data.includes("config.entity");
|
||||||
|
}
|
||||||
|
return Object.values(data).some(find_entity_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
customElements.whenDefined('ha-card').then(() => {
|
customElements.whenDefined('ha-card').then(() => {
|
||||||
const HaCard = customElements.get('ha-card');
|
const HaCard = customElements.get('ha-card');
|
||||||
@ -19,63 +91,6 @@ customElements.whenDefined('ha-card').then(() => {
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const applyStyle = function(root, style, debug) {
|
|
||||||
|
|
||||||
const debugPrint = function(str){
|
|
||||||
if(!debug) return;
|
|
||||||
if(typeof str === "string")
|
|
||||||
console.log(' '.repeat(2*(debug-1)) + str);
|
|
||||||
else
|
|
||||||
console.log(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!root || !style) return;
|
|
||||||
|
|
||||||
if(typeof style === "string") {
|
|
||||||
// Remove old styles if we're updating
|
|
||||||
if(root.querySelector(".card-mod-style"))
|
|
||||||
root.removeChild(root.querySelector(".card-mod-style"));
|
|
||||||
|
|
||||||
// Add new style tag to the root element
|
|
||||||
const styleEl = document.createElement('style');
|
|
||||||
styleEl.classList = "card-mod-style";
|
|
||||||
styleEl.innerHTML = parseTemplate(style);
|
|
||||||
root.appendChild(styleEl);
|
|
||||||
if(debug) {
|
|
||||||
debugPrint("Applied styles to:")
|
|
||||||
console.log(root);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Object.keys(style).forEach((k) => {
|
|
||||||
if(k === ".") {
|
|
||||||
debugPrint(`Stepping into root of ${root.tagName}`)
|
|
||||||
return applyStyle(root, style[k], debug?debug+1:0);
|
|
||||||
} else if(k === "$") {
|
|
||||||
debugPrint(`Stepping into ShadowRoot of ${root.tagName}`)
|
|
||||||
return applyStyle(root.shadowRoot, style[k], debug?debug+1:0);
|
|
||||||
} else {
|
|
||||||
debugPrint(`Searching for: "${k}". ${root.querySelectorAll(k).length} matches.`);
|
|
||||||
root.querySelectorAll(`${k}`).forEach((el) => {
|
|
||||||
debugPrint(`Stepping into ${el.tagName}`)
|
|
||||||
applyStyle(el, style[k], debug?debug+1:0);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HaCard.prototype.updated = function(_) {
|
|
||||||
// Apply styles after updates, if specified
|
|
||||||
const config = findConfig(this);
|
|
||||||
if(config && config.style) {
|
|
||||||
if(config.debug_cardmod)
|
|
||||||
console.log("--- APPLYING STYLES START ---");
|
|
||||||
applyStyle(this, config.style, config.debug_cardmod ? 1 : 0);
|
|
||||||
if(config.debug_cardmod)
|
|
||||||
console.log("--- APPLYING STYLES END ---");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HaCard.prototype.firstUpdated = function() {
|
HaCard.prototype.firstUpdated = function() {
|
||||||
// Move the header inside the slot instead of in the shadowDOM
|
// Move the header inside the slot instead of in the shadowDOM
|
||||||
@ -85,22 +100,114 @@ customElements.whenDefined('ha-card').then(() => {
|
|||||||
{
|
{
|
||||||
this.insertBefore(header, this.children[0]);
|
this.insertBefore(header, this.children[0]);
|
||||||
}
|
}
|
||||||
// Listen for changes to hass or the location and update
|
|
||||||
document.querySelector("home-assistant").provideHass(this);
|
const config = findConfig(this);
|
||||||
window.addEventListener("location-changed", () => this._requestUpdate());
|
if(!config || !config.style) return;
|
||||||
|
|
||||||
|
let entity_ids = config.entity_ids;
|
||||||
|
if(!entity_ids && find_entity_ids(config.style))
|
||||||
|
entity_ids = [config.entity];
|
||||||
|
|
||||||
|
const apply = () => {
|
||||||
|
applyStyle(this, config.style, {
|
||||||
|
variables: {config},
|
||||||
|
entity_ids
|
||||||
|
}, !!config.debug_cardmod);
|
||||||
}
|
}
|
||||||
Object.defineProperty(HaCard.prototype, 'hass', {
|
|
||||||
get() {
|
apply();
|
||||||
return this._hass;
|
window.addEventListener("location-changed", () => apply());
|
||||||
},
|
}
|
||||||
set(value) {
|
|
||||||
if(value !== this._hass) {
|
fireEvent('ll-rebuild', {});
|
||||||
const oldval = this._hass;
|
});
|
||||||
this._hass = value;
|
|
||||||
this._requestUpdate('hass', oldval);
|
|
||||||
|
customElements.whenDefined('hui-entities-card').then(() => {
|
||||||
|
const EntitiesCard = customElements.get('hui-entities-card');
|
||||||
|
|
||||||
|
const oldRenderEntity = EntitiesCard.prototype.renderEntity;
|
||||||
|
EntitiesCard.prototype.renderEntity = function(config) {
|
||||||
|
|
||||||
|
const retval = oldRenderEntity.bind(this)(config);
|
||||||
|
|
||||||
|
if(!config.style) return retval;
|
||||||
|
if(!retval.values) return retval;
|
||||||
|
const row = retval.values[0];
|
||||||
|
if(!row || !row.updateComplete) return retval;
|
||||||
|
|
||||||
|
let entity_ids = config.entity_ids;
|
||||||
|
if (!entity_ids && find_entity_ids(config.style))
|
||||||
|
entity_ids = [config.entity];
|
||||||
|
|
||||||
|
const apply = () => {
|
||||||
|
applyStyle(row.shadowRoot, config.style, {
|
||||||
|
variables: {config},
|
||||||
|
entity_ids
|
||||||
|
}, !!config.debug_cardmod);
|
||||||
|
}
|
||||||
|
|
||||||
|
row.updateComplete.then(apply);
|
||||||
|
window.addEventListener("location-changed", apply);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
fireEvent('ll-rebuild', {});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
customElements.whenDefined('hui-glance-card').then(() => {
|
||||||
|
const GlanceCard = customElements.get('hui-glance-card');
|
||||||
|
|
||||||
|
GlanceCard.prototype.firstUpdated = function () {
|
||||||
|
const entities = this.shadowRoot.querySelectorAll("ha-card div.entity");
|
||||||
|
entities.forEach((e) => {
|
||||||
|
const root = e.attachShadow({mode: "open"});
|
||||||
|
[...e.children].forEach((el) => root.appendChild(el));
|
||||||
|
const styletag = document.createElement("style");
|
||||||
|
root.appendChild(styletag);
|
||||||
|
styletag.innerHTML = `
|
||||||
|
:host {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0 4px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
width: var(--glance-column-width, 20%);
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.name {
|
||||||
|
min-height: var(--paper-font-body1_-_line-height, 20px);
|
||||||
|
}
|
||||||
|
state-badge {
|
||||||
|
margin: 8px 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const config = e.entityConf;
|
||||||
|
if(!config.style) return;
|
||||||
|
let entity_ids = config.entity_ids;
|
||||||
|
if (!entity_ids && find_entity_ids(config.style))
|
||||||
|
entity_ids = [config.entity];
|
||||||
|
|
||||||
|
const apply = () => {
|
||||||
|
applyStyle(root, config.style, {
|
||||||
|
variables: {config},
|
||||||
|
entity_ids
|
||||||
|
}, !!config.debug_cardmod);
|
||||||
|
}
|
||||||
|
|
||||||
|
apply();
|
||||||
|
window.addEventListener("location-changed", apply);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
fireEvent('ll-rebuild', {});
|
fireEvent('ll-rebuild', {});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user