Add some animated transitions
This commit is contained in:
parent
fddaed38c3
commit
1dfa8aa5d4
10
README.md
10
README.md
@ -24,6 +24,8 @@ resources:
|
|||||||
type: custom:state-switch
|
type: custom:state-switch
|
||||||
entity: <entity>
|
entity: <entity>
|
||||||
default: <default>
|
default: <default>
|
||||||
|
transition: <transition>
|
||||||
|
transition_time: <transition_time>
|
||||||
states:
|
states:
|
||||||
<state 1>:
|
<state 1>:
|
||||||
<card 1>
|
<card 1>
|
||||||
@ -41,6 +43,8 @@ If the state of `<entity>` doesn't match any `<state>`, the `<card>` for the `<d
|
|||||||
- `<default>` State to use as default fallback
|
- `<default>` State to use as default fallback
|
||||||
- `<state N>` The state to match
|
- `<state N>` The state to match
|
||||||
- `<card N>` Lovelace card configuration
|
- `<card N>` Lovelace card configuration
|
||||||
|
- `<transition>` Animated transition to use (`slide-left`, `slide-right`, `swap-left`, `swap_right` or `flip`). Default: `none`
|
||||||
|
- `<transition_time>` The time for an animated transition in ms. Default: 500
|
||||||
|
|
||||||
## State matching
|
## State matching
|
||||||
|
|
||||||
@ -205,6 +209,12 @@ states:
|
|||||||
content: "Really small"
|
content: "Really small"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Transitions
|
||||||
|
The switch from one card to another can be animated by setting the `<transition>` option.
|
||||||
|
The speed of the transition is set by `<transition_time>` (milliseconds). Note that some animations do two things, and thus take two times `<transition_time>` to complete.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## A few tips
|
## A few tips
|
||||||
|
|
||||||
- To replace more than one card at a time, use e.g. [`vertical-stack`](https://www.home-assistant.io/lovelace/vertical-stack/), [`horizontal-stack`](https://www.home-assistant.io/lovelace/horizontal-stack/) or [`layout-card`](https://github.com/thomasloven/lovelace-layout-card).
|
- To replace more than one card at a time, use e.g. [`vertical-stack`](https://www.home-assistant.io/lovelace/vertical-stack/), [`horizontal-stack`](https://www.home-assistant.io/lovelace/horizontal-stack/) or [`layout-card`](https://github.com/thomasloven/lovelace-layout-card).
|
||||||
|
153
src/main.js
153
src/main.js
@ -1,7 +1,8 @@
|
|||||||
import { LitElement, html } from "card-tools/src/lit-element";
|
import { LitElement, html, css } from "card-tools/src/lit-element";
|
||||||
import { hass } from "card-tools/src/hass";
|
import { hass } from "card-tools/src/hass";
|
||||||
import { createCard } from "card-tools/src/lovelace-element";
|
import { createCard } from "card-tools/src/lovelace-element";
|
||||||
import { deviceID } from "card-tools/src/deviceID";
|
import { deviceID } from "card-tools/src/deviceID";
|
||||||
|
import {fireEvent} from "card-tools/src/event.js";
|
||||||
|
|
||||||
class StateSwitch extends LitElement {
|
class StateSwitch extends LitElement {
|
||||||
|
|
||||||
@ -72,13 +73,35 @@ class StateSwitch extends LitElement {
|
|||||||
|
|
||||||
if(!changedProperties.has("state")) {
|
if(!changedProperties.has("state")) {
|
||||||
this.update_state();
|
this.update_state();
|
||||||
|
} else {
|
||||||
|
const oldState = changedProperties.get("state");
|
||||||
|
if(this.cards[oldState]) {
|
||||||
|
this.cards[oldState].classList.remove("visible");
|
||||||
|
this.cards[oldState].classList.add("out");
|
||||||
|
window.setTimeout(() => {
|
||||||
|
this.cards[oldState].classList.remove("out");
|
||||||
|
}, this._config.transition_time || 500);
|
||||||
|
}
|
||||||
|
if(this.cards[this.state]) {
|
||||||
|
this.cards[this.state].classList.add("visible");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<div id="root">
|
<div
|
||||||
${this.cards[this.state]}
|
id="root"
|
||||||
|
class="${this._config.transition}"
|
||||||
|
style="
|
||||||
|
transition-duration: ${this._config.transition_time || 500}ms;
|
||||||
|
transition-delay: ${this._config.transition_time || 500}ms;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
${Object.keys(this.cards).map((k) =>
|
||||||
|
html`
|
||||||
|
${this.cards[k]}
|
||||||
|
`)}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -92,6 +115,130 @@ class StateSwitch extends LitElement {
|
|||||||
return sz;
|
return sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
:host {
|
||||||
|
perspective: 1000px;
|
||||||
|
}
|
||||||
|
#root {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
#root * {
|
||||||
|
display: none;
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 1;
|
||||||
|
}
|
||||||
|
#root .visible {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#root.slide-right *,
|
||||||
|
#root.slide-left * {
|
||||||
|
display: block;
|
||||||
|
opacity: 0;
|
||||||
|
height: 0;
|
||||||
|
transition-property: transform;
|
||||||
|
transition-timing-function: linear;
|
||||||
|
transition-duration: inherit;
|
||||||
|
transform: translate(-110%);
|
||||||
|
}
|
||||||
|
#root.slide-left * {
|
||||||
|
transform: translate(110%);
|
||||||
|
}
|
||||||
|
#root.slide-right .visible,
|
||||||
|
#root.slide-left .visible {
|
||||||
|
opacity: 1;
|
||||||
|
height: auto;
|
||||||
|
transform: translate(0%);
|
||||||
|
}
|
||||||
|
#root.slide-right .out,
|
||||||
|
#root.slide-left .out {
|
||||||
|
opacity: 1;
|
||||||
|
height: auto;
|
||||||
|
transform: translate(110%);
|
||||||
|
}
|
||||||
|
#root.slide-left .out {
|
||||||
|
transform: translate(-110%);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#root.swap-right *,
|
||||||
|
#root.swap-left * {
|
||||||
|
display: block;
|
||||||
|
opacity: 0;
|
||||||
|
height: 0;
|
||||||
|
transition-property: transform;
|
||||||
|
transition-timing-function: linear;
|
||||||
|
transition-duration: inherit;
|
||||||
|
transform: translate(110%);
|
||||||
|
}
|
||||||
|
#root.swap-left *{
|
||||||
|
transform: translate(-110%);
|
||||||
|
}
|
||||||
|
#root.swap-right .visible,
|
||||||
|
#root.swap-left .visible {
|
||||||
|
opacity: 1;
|
||||||
|
height: auto;
|
||||||
|
transition-delay: inherit;
|
||||||
|
transform: translate(0%);
|
||||||
|
}
|
||||||
|
#root.swap-right .out,
|
||||||
|
#root.swap-left .out {
|
||||||
|
opacity: 1;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#root.flip {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
}
|
||||||
|
#root.flip * {
|
||||||
|
display: block;
|
||||||
|
opacity: 0;
|
||||||
|
height: 0;
|
||||||
|
transform: rotateY(-180deg);
|
||||||
|
transition-property: transform;
|
||||||
|
transition-timing-function: linear;
|
||||||
|
transition-duration: inherit;
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
#root.flip .visible {
|
||||||
|
opacity: 1;
|
||||||
|
height: auto;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
transform: rotateY(0deg);
|
||||||
|
}
|
||||||
|
#root.flip .out {
|
||||||
|
opacity: 1;
|
||||||
|
height: auto;
|
||||||
|
transform: rotateY(180deg);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("state-switch", StateSwitch);
|
customElements.define("state-switch", StateSwitch);
|
||||||
|
|
||||||
|
// Monkey patch hui-view to avoid scroll bars in columns
|
||||||
|
customElements.whenDefined("hui-view").then( () => {
|
||||||
|
const HuiView = customElements.get("hui-view").prototype;
|
||||||
|
const oldRenderStyles = HuiView.renderStyles;
|
||||||
|
HuiView.renderStyles = function() {
|
||||||
|
let original = oldRenderStyles();
|
||||||
|
original.strings = [original.strings[0] + `
|
||||||
|
<style>
|
||||||
|
.column {
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
`];
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
fireEvent('ll-rebuild', {});
|
||||||
|
});
|
||||||
|
120
state-switch.js
120
state-switch.js
@ -1,5 +1,117 @@
|
|||||||
!function(e){var t={};function s(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,s),o.l=!0,o.exports}s.m=e,s.c=t,s.d=function(e,t,r){s.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},s.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},s.t=function(e,t){if(1&t&&(e=s(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(s.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)s.d(r,o,function(t){return e[t]}.bind(null,o));return r},s.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return s.d(t,"a",t),t},s.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},s.p="",s(s.s=0)}([function(e,t,s){"use strict";s.r(t);const r=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view")),o=r.prototype.html;r.prototype.css;function a(){return document.querySelector("home-assistant").hass}const i="custom:";function n(e,t){const s=document.createElement("hui-error-card");return s.setConfig({type:"error",error:e,origConfig:t}),s}function c(e,t){if(!t||"object"!=typeof t||!t.type)return n(`No ${e} type configured`,t);let s=t.type;if(s=s.startsWith(i)?s.substr(i.length):`hui-${s}-${e}`,customElements.get(s))return function(e,t){const s=document.createElement(e);try{s.setConfig(t)}catch(e){return n(e,t)}return s}(s,t);const r=n(`Custom element doesn't exist: ${s}.`,t);r.style.display="None";const o=setTimeout(()=>{r.style.display=""},2e3);return customElements.whenDefined(s).then(()=>{clearTimeout(o),function(e,t,s=null){if((e=new Event(e,{bubbles:!0,cancelable:!1,composed:!0})).detail=t||{},s)s.dispatchEvent(e);else{var r=document.querySelector("home-assistant");(r=(r=(r=(r=(r=(r=(r=(r=(r=(r=(r=r&&r.shadowRoot)&&r.querySelector("home-assistant-main"))&&r.shadowRoot)&&r.querySelector("app-drawer-layout partial-panel-resolver"))&&r.shadowRoot||r)&&r.querySelector("ha-panel-lovelace"))&&r.shadowRoot)&&r.querySelector("hui-root"))&&r.shadowRoot)&&r.querySelector("ha-app-layout #view"))&&r.firstElementChild)&&r.dispatchEvent(e)}}("ll-rebuild",{},r)}),r}function u(e){return c("card",e)}let d=function(){if(window.fully&&"function"==typeof fully.getDeviceId)return fully.getDeviceId();if(!localStorage["lovelace-player-device-id"]){const e=()=>Math.floor(1e5*(1+Math.random())).toString(16).substring(1);localStorage["lovelace-player-device-id"]=`${e()}${e()}-${e()}${e()}`}return localStorage["lovelace-player-device-id"]}();customElements.define("state-switch",class extends r{static get properties(){return{hass:{},state:{}}}setConfig(e){this._config=e,this.state=void 0,this.cards={};for(let t in e.states)this.cards[t]=u(e.states[t]),this.cards[t].hass=a();if("hash"===e.entity&&window.addEventListener("location-changed",()=>this.updated(new Map)),"mediaquery"===e.entity)for(const e in this.cards)window.matchMedia(e).addEventListener("change",this.update_state.bind(this))}update_state(){let e=void 0;switch(this._config.entity){case"user":e=this.hass&&this.hass.user&&this.hass.user.name||void 0;break;case"group":e=this.hass&&this.hass.user&&this.hass.user.is_admin?"admin":"user";case"deviceID":case"browser":e=d;break;case"hash":e=location.hash.substr(1);break;case"mediaquery":for(const t in this.cards)if(window.matchMedia(t).matches){e=t;break}break;default:e=this.hass.states[this._config.entity],e=e?e.state:void 0}void 0!==e&&this.cards.hasOwnProperty(e)||(e=this._config.default),this.state=e}updated(e){if(e.has("hass"))for(let e in this.cards)this.cards[e].hass=this.hass;e.has("state")||this.update_state()}render(){return o`
|
!function(t){var e={};function i(s){if(e[s])return e[s].exports;var r=e[s]={i:s,l:!1,exports:{}};return t[s].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.m=t,i.c=e,i.d=function(t,e,s){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:s})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,e){if(1&e&&(t=i(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var s=Object.create(null);if(i.r(s),Object.defineProperty(s,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)i.d(s,r,function(e){return t[e]}.bind(null,r));return s},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=0)}([function(t,e,i){"use strict";i.r(e);const s=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view")),r=s.prototype.html,o=s.prototype.css;function a(){return document.querySelector("home-assistant").hass}function n(t,e,i=null){if((t=new Event(t,{bubbles:!0,cancelable:!1,composed:!0})).detail=e||{},i)i.dispatchEvent(t);else{var s=document.querySelector("home-assistant");(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=s&&s.shadowRoot)&&s.querySelector("home-assistant-main"))&&s.shadowRoot)&&s.querySelector("app-drawer-layout partial-panel-resolver"))&&s.shadowRoot||s)&&s.querySelector("ha-panel-lovelace"))&&s.shadowRoot)&&s.querySelector("hui-root"))&&s.shadowRoot)&&s.querySelector("ha-app-layout #view"))&&s.firstElementChild)&&s.dispatchEvent(t)}}const l="custom:";function c(t,e){const i=document.createElement("hui-error-card");return i.setConfig({type:"error",error:t,origConfig:e}),i}function d(t,e){if(!e||"object"!=typeof e||!e.type)return c(`No ${t} type configured`,e);let i=e.type;if(i=i.startsWith(l)?i.substr(l.length):`hui-${i}-${t}`,customElements.get(i))return function(t,e){const i=document.createElement(t);try{i.setConfig(e)}catch(t){return c(t,e)}return i}(i,e);const s=c(`Custom element doesn't exist: ${i}.`,e);s.style.display="None";const r=setTimeout(()=>{s.style.display=""},2e3);return customElements.whenDefined(i).then(()=>{clearTimeout(r),n("ll-rebuild",{},s)}),s}function u(t){return d("card",t)}let h=function(){if(window.fully&&"function"==typeof fully.getDeviceId)return fully.getDeviceId();if(!localStorage["lovelace-player-device-id"]){const t=()=>Math.floor(1e5*(1+Math.random())).toString(16).substring(1);localStorage["lovelace-player-device-id"]=`${t()}${t()}-${t()}${t()}`}return localStorage["lovelace-player-device-id"]}();customElements.define("state-switch",class extends s{static get properties(){return{hass:{},state:{}}}setConfig(t){this._config=t,this.state=void 0,this.cards={};for(let e in t.states)this.cards[e]=u(t.states[e]),this.cards[e].hass=a();if("hash"===t.entity&&window.addEventListener("location-changed",()=>this.updated(new Map)),"mediaquery"===t.entity)for(const t in this.cards)window.matchMedia(t).addEventListener("change",this.update_state.bind(this))}update_state(){let t=void 0;switch(this._config.entity){case"user":t=this.hass&&this.hass.user&&this.hass.user.name||void 0;break;case"group":t=this.hass&&this.hass.user&&this.hass.user.is_admin?"admin":"user";case"deviceID":case"browser":t=h;break;case"hash":t=location.hash.substr(1);break;case"mediaquery":for(const e in this.cards)if(window.matchMedia(e).matches){t=e;break}break;default:t=this.hass.states[this._config.entity],t=t?t.state:void 0}void 0!==t&&this.cards.hasOwnProperty(t)||(t=this._config.default),this.state=t}updated(t){if(t.has("hass"))for(let t in this.cards)this.cards[t].hass=this.hass;if(t.has("state")){const e=t.get("state");this.cards[e]&&(this.cards[e].classList.remove("visible"),this.cards[e].classList.add("out"),window.setTimeout(()=>{this.cards[e].classList.remove("out")},this._config.transition_time||500)),this.cards[this.state]&&this.cards[this.state].classList.add("visible")}else this.update_state()}render(){return r`
|
||||||
<div id="root">
|
<div
|
||||||
${this.cards[this.state]}
|
id="root"
|
||||||
|
class="${this._config.transition}"
|
||||||
|
style="
|
||||||
|
transition-duration: ${this._config.transition_time||500}ms;
|
||||||
|
transition-delay: ${this._config.transition_time||500}ms;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
${Object.keys(this.cards).map(t=>r`
|
||||||
|
${this.cards[t]}
|
||||||
|
`)}
|
||||||
</div>
|
</div>
|
||||||
`}getCardSize(){let e=1;for(let t in this.cards)this.cards[t]&&this.cards[t].getCardSize&&(e=Math.max(e,this.cards[t].getCardSize()));return e}})}]);
|
`}getCardSize(){let t=1;for(let e in this.cards)this.cards[e]&&this.cards[e].getCardSize&&(t=Math.max(t,this.cards[e].getCardSize()));return t}static get styles(){return o`
|
||||||
|
:host {
|
||||||
|
perspective: 1000px;
|
||||||
|
}
|
||||||
|
#root {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
#root * {
|
||||||
|
display: none;
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 1;
|
||||||
|
}
|
||||||
|
#root .visible {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#root.slide-right *,
|
||||||
|
#root.slide-left * {
|
||||||
|
display: block;
|
||||||
|
opacity: 0;
|
||||||
|
height: 0;
|
||||||
|
transition-property: transform;
|
||||||
|
transition-timing-function: linear;
|
||||||
|
transition-duration: inherit;
|
||||||
|
transform: translate(-110%);
|
||||||
|
}
|
||||||
|
#root.slide-left * {
|
||||||
|
transform: translate(110%);
|
||||||
|
}
|
||||||
|
#root.slide-right .visible,
|
||||||
|
#root.slide-left .visible {
|
||||||
|
opacity: 1;
|
||||||
|
height: auto;
|
||||||
|
transform: translate(0%);
|
||||||
|
}
|
||||||
|
#root.slide-right .out,
|
||||||
|
#root.slide-left .out {
|
||||||
|
opacity: 1;
|
||||||
|
height: auto;
|
||||||
|
transform: translate(110%);
|
||||||
|
}
|
||||||
|
#root.slide-left .out {
|
||||||
|
transform: translate(-110%);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#root.swap-right *,
|
||||||
|
#root.swap-left * {
|
||||||
|
display: block;
|
||||||
|
opacity: 0;
|
||||||
|
height: 0;
|
||||||
|
transition-property: transform;
|
||||||
|
transition-timing-function: linear;
|
||||||
|
transition-duration: inherit;
|
||||||
|
transform: translate(110%);
|
||||||
|
}
|
||||||
|
#root.swap-left *{
|
||||||
|
transform: translate(-110%);
|
||||||
|
}
|
||||||
|
#root.swap-right .visible,
|
||||||
|
#root.swap-left .visible {
|
||||||
|
opacity: 1;
|
||||||
|
height: auto;
|
||||||
|
transition-delay: inherit;
|
||||||
|
transform: translate(0%);
|
||||||
|
}
|
||||||
|
#root.swap-right .out,
|
||||||
|
#root.swap-left .out {
|
||||||
|
opacity: 1;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#root.flip {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
}
|
||||||
|
#root.flip * {
|
||||||
|
display: block;
|
||||||
|
opacity: 0;
|
||||||
|
height: 0;
|
||||||
|
transform: rotateY(-180deg);
|
||||||
|
transition-property: transform;
|
||||||
|
transition-timing-function: linear;
|
||||||
|
transition-duration: inherit;
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
#root.flip .visible {
|
||||||
|
opacity: 1;
|
||||||
|
height: auto;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
transform: rotateY(0deg);
|
||||||
|
}
|
||||||
|
#root.flip .out {
|
||||||
|
opacity: 1;
|
||||||
|
height: auto;
|
||||||
|
transform: rotateY(180deg);
|
||||||
|
}
|
||||||
|
`}}),customElements.whenDefined("hui-view").then(()=>{const t=customElements.get("hui-view").prototype,e=t.renderStyles;t.renderStyles=function(){let t=e();return t.strings=[t.strings[0]+"\n <style>\n .column {\n overflow-y: hidden;\n }\n </style>\n "],t},n("ll-rebuild",{})})}]);
|
Loading…
x
Reference in New Issue
Block a user