Just finished my first custom layout card. Don’t ask me how I did it, but somehow, it seems I got it working…
The card is very similar to the grid card, except that in portrait mode, all the columns collapse into one. This simple change enables layouts that look nice in both portrait and landscape modes (and thus also in desktop mode).
Here is a little example of how it looks on my phone:
The custom card is based on the built in grid card and uses the same config entries. So, it is possible to replace any grid card simply by exchanging ‘type:grid’ with ‘type: custom:smart-grid’. To edit the card content with the graphical editor, it’s also possible to temporarily switch it back to ‘type: grid’ and use the grid card’s graphical editor.
Here is the source if you are interested :
smart-grid.js
import {
LitElement,
html,
css,
} from "https://unpkg.com/[email protected]/lit-element.js?module";
class AspectRatioColumnsLayout extends LitElement
{
async setConfig( config )
{
if ( !config || !config.cards || !Array.isArray(config.cards) )
throw new Error( "Invalid configuration" );
if ( config.columns )
this.style.setProperty( "--max-cols", String(config.columns) );
else
this.style.removeProperty( "--max-cols" );
if ( config.square )
this.setAttribute( "square", "" );
else
this.removeAttribute( "square" );
window.loadCardHelpers().then( (cardHelpers) => {
this.elements = config.cards.map( (cardConfig) => { return cardHelpers.createCardElement( cardConfig ); } );
} ).then( this.requestUpdate() );
//console.log( [this] );
}
static get properties()
{
return {
elements: {type: Array, attribute: false},
hass: {type: Object, attribute: false}
};
}
updated( changedProps )
{
super.updated( changedProps );
//console.log( changedProps );
if ( !this.elements ) return;
//if ( changedProps.has("hass") )
this.elements.forEach( (e) => { e.hass = this.hass; } );
}
render()
{
if( !this.elements ) return html``;
return html`<style>
@media (max-aspect-ratio: 11/10)
{
#root { grid-template-columns: 1fr !important; }
}
/* #root div { background: #9ff; } */
#root
{
display: grid;
grid-template-columns: repeat( var(--max-cols,2), minmax(0, 1fr) );
grid-gap: var(--grid-card-gap, 8px);
}
:host([square]) #root {
grid-auto-rows: 1fr;
}
:host([square]) #root::before {
content: "";
width: 0;
padding-bottom: 100%;
grid-row: 1 / 1;
grid-column: 1 / 1;
}
:host([square]) #root > *:not([hidden]) {
grid-row: 1 / 1;
grid-column: 1 / 1;
}
:host([square]) #root > *:not([hidden]) ~ *:not([hidden]) {
grid-row: unset;
grid-column: unset;
}
</style> <div id="root">${this.elements.map((card) => html`<div>${card}</div>`)}</div>`;
}
}
customElements.define("smart-grid", AspectRatioColumnsLayout );