Initial commit
This commit is contained in:
commit
2f3cf2b508
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
q-card.js binary
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
node_modules/
|
21
LICENSE.txt
Normal file
21
LICENSE.txt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Thomas Lovén
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
105
README.md
Normal file
105
README.md
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
q-card
|
||||||
|
=================
|
||||||
|
|
||||||
|
<!--[](https://github.com/custom-components/hacs)-->
|
||||||
|
|
||||||
|
**EXPERIMENTAL**
|
||||||
|
|
||||||
|
Use the same lovelace card in multiple places (but only one at a time).
|
||||||
|
|
||||||
|
For installation instructions [see this guide](https://github.com/thomasloven/hass-config/wiki/Lovelace-Plugins).
|
||||||
|
|
||||||
|
Install `q-card.js` as a `module`. Ignore all other files in this repo.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
resources:
|
||||||
|
- url: /local/q-card.js
|
||||||
|
type: module
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
1. Define q-cards in `ui-lovelace.yaml`
|
||||||
|
|
||||||
|
* Either globally:
|
||||||
|
```yaml
|
||||||
|
title: My awesome lovelace configuration
|
||||||
|
resources:
|
||||||
|
- url: /local/q-card.js
|
||||||
|
type: module
|
||||||
|
q_cards:
|
||||||
|
card1:
|
||||||
|
type: entities
|
||||||
|
entities:
|
||||||
|
- light.bed_light
|
||||||
|
- light.kitchen_lights
|
||||||
|
- light.ceiling_lights
|
||||||
|
views:
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
* Or locally in a view
|
||||||
|
```yaml
|
||||||
|
views:
|
||||||
|
- title: My first view
|
||||||
|
q_cards:
|
||||||
|
card2:
|
||||||
|
type: glance
|
||||||
|
entities:
|
||||||
|
- light.bed_light
|
||||||
|
- light.kitchen_lights
|
||||||
|
- light.ceiling_lights
|
||||||
|
cards:
|
||||||
|
...
|
||||||
|
```
|
||||||
|
> Note: Local cards takes precedence.
|
||||||
|
|
||||||
|
2. Use the card:
|
||||||
|
```yaml
|
||||||
|
views:
|
||||||
|
- title: One view
|
||||||
|
cards:
|
||||||
|
- type: q-card
|
||||||
|
card: card1
|
||||||
|
- title: Another view
|
||||||
|
cards:
|
||||||
|
- type: q-card
|
||||||
|
card: card1
|
||||||
|
```
|
||||||
|
|
||||||
|
The same card will now show up in both views.
|
||||||
|
|
||||||
|
So what? You can already do this with:
|
||||||
|
|
||||||
|
- [decluttering-card](https://github.com/custom-cards/decluttering-card)
|
||||||
|
- [lovelace_gen](https://github.com/thomasloven/hass-lovelace_gen)
|
||||||
|
- [YAML node anchors](https://github.com/thomasloven/hass-config/wiki/Misc-tricks#node-anchors)
|
||||||
|
|
||||||
|
What's the difference?
|
||||||
|
|
||||||
|
Well, the difference is that the **SAME** card will show up in both views.
|
||||||
|
It's not an equal card - it's actually the *very same* card being moved over from one view to another.
|
||||||
|
|
||||||
|
This has two main advantages (besides simplifying your configuration as the alternatives mentioned above do):
|
||||||
|
|
||||||
|
- Memory
|
||||||
|
|
||||||
|
By only creating and loading a card once you can preserve some RAM and performance. This could also be a great advantage e.g. for [state-switch](https://github.com/thomasloven/lovelace-state-switch) and similar cards.
|
||||||
|
|
||||||
|
- Persistance.
|
||||||
|
|
||||||
|
Say you have a card with a [fold-entity-row](https://github.com/thomasloven/lovelace-fold-entity-row) in it. Now, you can unfold that in one view, and when you move to another view, it's still unfolded.
|
||||||
|
|
||||||
|
This also means you can only have the same q-card visible once in the same browser window.
|
||||||
|
|
||||||
|
# FAQ
|
||||||
|
|
||||||
|
### What's Q for in the name?
|
||||||
|
Quantum. You know how quantum teleportation works and how quantum particles can be in two different places at the same time*.
|
||||||
|
|
||||||
|
This is nothing like that.
|
||||||
|
|
||||||
|
\* They can't _really_...
|
||||||
|
|
||||||
|
---
|
||||||
|
<a href="https://www.buymeacoffee.com/uqD6KHCdJ" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/white_img.png" alt="Buy Me A Coffee" style="height: auto !important;width: auto !important;" ></a>
|
4078
package-lock.json
generated
Normal file
4078
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
25
package.json
Normal file
25
package.json
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "q-card",
|
||||||
|
"private": true,
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"scripts": {
|
||||||
|
"build": "webpack",
|
||||||
|
"watch": "webpack --watch --mode=development",
|
||||||
|
"update-card-tools": "npm uninstall card-tools && npm install thomasloven/lovelace-card-tools"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "github.com:thomasloven/lovelace-q-card"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "Thomas Lovén",
|
||||||
|
"license": "MIT",
|
||||||
|
"devDependencies": {
|
||||||
|
"webpack": "^4.41.5",
|
||||||
|
"webpack-cli": "^3.3.10"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"card-tools": "github:thomasloven/lovelace-card-tools"
|
||||||
|
}
|
||||||
|
}
|
1
q-card.js
Normal file
1
q-card.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
!function(e){var t={};function o(n){if(t[n])return t[n].exports;var r=t[n]={i:n,l:!1,exports:{}};return e[n].call(r.exports,r,r.exports,o),r.l=!0,r.exports}o.m=e,o.c=t,o.d=function(e,t,n){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,t){if(1&t&&(e=o(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)o.d(n,r,function(t){return e[t]}.bind(null,r));return n},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,"a",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p="",o(o.s=0)}([function(e,t,o){"use strict";o.r(t);const n=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view"));n.prototype.html,n.prototype.css;function r(){var e,t=document.querySelector("hc-main");return t?((e=t._lovelaceConfig).current_view=t._lovelacePath,e):(t=(t=(t=(t=(t=(t=(t=(t=(t=document.querySelector("home-assistant"))&&t.shadowRoot)&&t.querySelector("home-assistant-main"))&&t.shadowRoot)&&t.querySelector("app-drawer-layout partial-panel-resolver"))&&t.shadowRoot||t)&&t.querySelector("ha-panel-lovelace"))&&t.shadowRoot)&&t.querySelector("hui-root"))?((e=t.lovelace).current_view=t.___curView,e):null}function s(e,t,o=null){if((e=new Event(e,{bubbles:!0,cancelable:!1,composed:!0})).detail=t||{},o)o.dispatchEvent(e);else{var n=function(){var e=document.querySelector("hc-main");return e=e?(e=(e=(e=e&&e.shadowRoot)&&e.querySelector("hc-lovelace"))&&e.shadowRoot)&&e.querySelector("hui-view"):(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=document.querySelector("home-assistant"))&&e.shadowRoot)&&e.querySelector("home-assistant-main"))&&e.shadowRoot)&&e.querySelector("app-drawer-layout partial-panel-resolver"))&&e.shadowRoot||e)&&e.querySelector("ha-panel-lovelace"))&&e.shadowRoot)&&e.querySelector("hui-root"))&&e.shadowRoot)&&e.querySelector("ha-app-layout #view"))&&e.firstElementChild}();n&&n.dispatchEvent(e)}}function a(e,t){const o=document.createElement("hui-error-card");return o.setConfig({type:"error",error:e,origConfig:t}),o}function i(e,t){if(!t||"object"!=typeof t||!t.type)return a(`No ${e} type configured`,t);let o=t.type;if(o=o.startsWith("custom:")?o.substr("custom:".length):`hui-${o}-${e}`,customElements.get(o))return function(e,t){const o=document.createElement(e);try{o.setConfig(t)}catch(e){return a(e,t)}return o}(o,t);const n=a(`Custom element doesn't exist: ${o}.`,t);n.style.display="None";const r=setTimeout(()=>{n.style.display=""},2e3);return customElements.whenDefined(o).then(()=>{clearTimeout(r),s("ll-rebuild",{},n)}),n}function c(e){return i("card",e)}customElements.get("q-card")||customElements.define("q-card",class extends n{setConfig(e){this.name=e.card,this.localname=`__local_${r().current_view}_${e.card}`,window.qCards||(window.qCards={});const t=r().config.q_cards,o=r().config.views[r().current_view].q_cards;t&&t[this.name]&&!window.qCards[this.name]&&(window.qCards[this.name]=c(t[this.name])),o&&o[this.name]&&!window.qCards[this.localname]&&(window.qCards[this.localname]=c(o[this.name])),window.addEventListener("location-changed",()=>this.update()),this.update()}connectedCallback(){this.update()}update(){window.setTimeout(()=>{window.qCards&&0!==Object.keys(window.qCards).length&&(!this.shadowRoot.firstElementChild&&this.offsetParent&&this.shadowRoot.appendChild(window.qCards[this.localname]||window.qCards[this.name]),this.shadowRoot.firstElementChild&&(this.shadowRoot.firstElementChild.hass=this._hass))},1)}set hass(e){this._hass=e,this.update()}})}]);
|
48
src/main.js
Normal file
48
src/main.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { LitElement } from "card-tools/src/lit-element";
|
||||||
|
import {lovelace} from "card-tools/src/hass";
|
||||||
|
import {createCard} from "card-tools/src/lovelace-element";
|
||||||
|
|
||||||
|
class QCard extends LitElement {
|
||||||
|
|
||||||
|
setConfig(config) {
|
||||||
|
this.name = config.card;
|
||||||
|
this.localname = `__local_${lovelace().current_view}_${config.card}`;
|
||||||
|
if(!window.qCards)
|
||||||
|
window.qCards = {};
|
||||||
|
|
||||||
|
const globals = lovelace().config.q_cards;
|
||||||
|
const locals = lovelace().config.views[lovelace().current_view].q_cards;
|
||||||
|
|
||||||
|
if(globals && globals[this.name] && !window.qCards[this.name]) {
|
||||||
|
window.qCards[this.name] = createCard(globals[this.name]);
|
||||||
|
}
|
||||||
|
if(locals && locals[this.name] && !window.qCards[this.localname]) {
|
||||||
|
window.qCards[this.localname] = createCard(locals[this.name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("location-changed", () => this.update());
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
window.setTimeout(() => {
|
||||||
|
if(!window.qCards || Object.keys(window.qCards).length === 0) return;
|
||||||
|
if(!this.shadowRoot.firstElementChild && this.offsetParent)
|
||||||
|
this.shadowRoot.appendChild(window.qCards[this.localname]
|
||||||
|
|| window.qCards[this.name]);
|
||||||
|
if(this.shadowRoot.firstElementChild) this.shadowRoot.firstElementChild.hass = this._hass;
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
set hass(hass) {
|
||||||
|
this._hass = hass;
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!customElements.get("q-card"))
|
||||||
|
customElements.define("q-card", QCard);
|
10
webpack.config.js
Normal file
10
webpack.config.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: './src/main.js',
|
||||||
|
mode: 'production',
|
||||||
|
output: {
|
||||||
|
filename: 'q-card.js',
|
||||||
|
path: path.resolve(__dirname)
|
||||||
|
}
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user