├── README.md ├── VERSION └── column-card.js /README.md: -------------------------------------------------------------------------------- 1 | # THIS IS DEPRECATED 2 | # USE [layout card](https://github.com/thomasloven/lovelace-layout-card) INSTEAD 3 | 4 | --- 5 | 6 | # column-card 7 | 8 | A lovelace card which contains other cards and display them as if they were not inside a card at all. 9 | 10 | ## Why? 11 | 12 | Lovelace automatically puts your cards in nice columns, the number of which are determined by the screen width: 13 | ![example-original](https://user-images.githubusercontent.com/1299821/43414537-552140c4-9433-11e8-802c-640193b1cd12.png) 14 | 15 | A known trick to get a header bar to a view is to make the view a panel, and add the header via a `vertial-stacḱ` card. But then you lose the columns. The best you can get is a `horizontal-stack`, but that doesn't adjust to the screen width. 16 | 17 | Enter `column-card`. A card which takes other cards and display them in columns: 18 | ![example-after](https://user-images.githubusercontent.com/1299821/43414653-b9276cd8-9433-11e8-8c66-33002aee3561.png) 19 | 20 | ## Options 21 | 22 | | Name | Type | Default | Description 23 | | ---- | ---- | ------- | ----------- 24 | | type | string | **Required** | `custom:column-card` 25 | | cards | list | **Required** | List of cards 26 | 27 | ## Installation 28 | 29 | 1. Copy `column-card.js` to `/www/column-card.js` 30 | 2. Add `column-card` as a resource in `ui-lovelace.yaml` 31 | 32 | ```yaml 33 | resources: 34 | - url: /local/column-card.js 35 | type: js 36 | ``` 37 | 38 | 39 | ## Example configuration 40 | 41 | ```yaml 42 | views: 43 | title: My view 44 | panel: true 45 | cards: 46 | - type: vertical-stack 47 | cards: 48 | - type: glance 49 | title: Header of the view 50 | entities: 51 | - ... 52 | - type: custom:column-card 53 | cards: 54 | - type: entities 55 | title: Card1 56 | entities: 57 | - ... 58 | - type: entities 59 | title: Card2 60 | entities: 61 | - ... 62 | - type: entities 63 | title: Card3 64 | entities: 65 | - ... 66 | ``` 67 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.0.1 2 | -------------------------------------------------------------------------------- /column-card.js: -------------------------------------------------------------------------------- 1 | class ColumnCard extends HTMLElement { 2 | constructor() { 3 | super(); 4 | // Make use of shadowRoot to avoid conflicts when reusing 5 | this.attachShadow({ mode: 'open' }); 6 | this.shadowRoot.innerHTML = ` 7 | 27 | `; 28 | 29 | this.cols = document.createElement('div'); 30 | this.cols.setAttribute("id", "columns"); 31 | this.shadowRoot.appendChild(this.cols); 32 | 33 | this.columns = 0; 34 | this._cards = []; 35 | } 36 | 37 | setConfig(config) { 38 | this.config = config; 39 | if (!config || !config.cards || !Array.isArray(config.cards)) { 40 | throw new Error('Card config incorrect'); 41 | } 42 | 43 | // The cards are created here in order to allow finding their height later 44 | // hui-view.js recreated the cards whenever the number of columns change, but that didn't work for me. 45 | // There might be some bad side effects of this, but I haven't encountered any so far. 46 | // Heads up, though... 47 | this._cards = config.cards.map((item) => { 48 | let element; 49 | if (item.type.startsWith("custom:")){ 50 | element = document.createElement(`${item.type.substr("custom:".length)}`); 51 | } else { 52 | element = document.createElement(`hui-${item.type}-card`); 53 | } 54 | element.setConfig(item); 55 | if(this.hass) 56 | element.hass = this.hass; 57 | return element; 58 | }); 59 | 60 | window.addEventListener('resize', (event) => {this._updateColumns()}); 61 | window.setTimeout((event) => {this._updateColumns()}, 10); 62 | } 63 | 64 | _updateColumns() { 65 | let numcols = Math.max(1,Math.floor(this.cols.clientWidth/300)); 66 | if(numcols != this.columns) { 67 | this.columns = numcols 68 | this._createColumns(); 69 | } 70 | } 71 | 72 | _createColumns() { 73 | // This code is copied more or less verbatim from hui-view.js in home-assistant. 74 | // https://github.com/home-assistant/home-assistant-polymer/blob/master/src/panels/lovelace/hui-view.js 75 | // The credit for anything good you find here goes to the home-assistant team. 76 | const root = this.cols; 77 | // Remove old columns 78 | while (root.lastChild) { 79 | root.removeChild(root.lastChild); 80 | } 81 | 82 | // Prepare a number of new columns 83 | let columns = []; 84 | const columnEntityCount = []; 85 | for(let i = 0; i < this.columns; i++) { 86 | columns.push([]); 87 | columnEntityCount.push(0); 88 | } 89 | 90 | function getColumnIndex(size) { 91 | // Find the shortest column 92 | let minIndex = 0; 93 | for (let i = 0; i < columnEntityCount.length; i++) { 94 | if (columnEntityCount[i] < 5) { 95 | minIndex = i; 96 | break; 97 | } 98 | if (columnEntityCount[i] < columnEntityCount[minIndex]) { 99 | minIndex = i; 100 | } 101 | } 102 | columnEntityCount[minIndex] += size; 103 | return minIndex; 104 | } 105 | 106 | // Go through each card and find which column to place it in (the shortest one) 107 | this._cards.forEach((el) => { 108 | this.appendChild(el); 109 | const cardSize = typeof el.getCardSize === 'function' ? el.getCardSize() : 1; 110 | columns[getColumnIndex(cardSize)].push(el); 111 | }); 112 | 113 | this.columnEntityCount = columnEntityCount 114 | 115 | // Remove any empty columns 116 | columns = columns.filter(val => val.length > 0); 117 | 118 | // Actually place the cards in the columns 119 | columns.forEach((column) => { 120 | const columnEl = document.createElement('div'); 121 | columnEl.classList.add('column'); 122 | column.forEach(el => columnEl.appendChild(el)); 123 | root.appendChild(columnEl); 124 | }); 125 | } 126 | 127 | set hass(hass) { 128 | // console.log(hass); 129 | this._cards.forEach(item => { 130 | item.hass = hass; 131 | }); 132 | } 133 | 134 | getCardSize() { 135 | return Math.max(this.columnEntityCount); 136 | } 137 | } 138 | customElements.define('column-card', ColumnCard); 139 | --------------------------------------------------------------------------------