Thanks.
If anyone has any idea about how to implement a multi-storey grid layout I’ll be grateful to learn!
Thanks.
If anyone has any idea about how to implement a multi-storey grid layout I’ll be grateful to learn!
Thanks. It helps a lot. Is it possible to make the conditional_media have media_player.media_next_track,too?
Hi @RoRoW
I like your temp card. can you please share “climate and icon_temperature” template. And also probably climate_livingroom.yaml?
Beautiful work. I’m basically stealing your design but not your code, trying to piece things together in a way that makes sense to my less technically inclined brain. First and foremost, thanks for sharing.
Mini question if you have the time: Could you point me to the style/card mod code you’re using to style the popup windows? I’m trying to increase the border radius for the entire popup card, but I’m having a hard time accessing the right tags.
Thanks!
-J
I’m using this UI for a while now and just starting to use the latest one ( August). Is it far to say that the issue with the custom swipe card cutting off the last bit of the cards isnt fix yet?
Or do i miss something?
I can only replicate when placing swipe card outside of layout card
card-mod-more-info-yaml:
sure
The climate tempate is based on “base_2” template and on “additional_values” template:
base_2:
#################################################
# #
# BASE_2 #
# #
#################################################
base_2:
variables:
state: >
[[[ return entity === undefined || entity.state; ]]]
timeout: >
[[[ return entity === undefined || Date.now() - Date.parse(entity.last_changed); ]]]
aspect_ratio: 1/1
show_state: true
show_icon: false
state_display: >
[[[ if (variables.state === true) return 'unknown'; ]]]
tap_action:
animation_card: |
[[[
const animation_speed_ms = 900;
const animation = `card_bounce ${animation_speed_ms}ms cubic-bezier(0.22, 1, 0.36, 1)`;
this.shadowRoot.getElementById("card").style.animation = animation;
window.setTimeout(() => {
this.shadowRoot.getElementById("card").style.animation = "none";
}, animation_speed_ms)
]]]
action: toggle
haptic: medium
styles:
grid:
- grid-template-areas: |
"icon values"
"n n"
"s s"
- grid-template-columns: repeat(2, 1fr)
- grid-template-rows: auto repeat(2, min-content)
- gap: 2%
- align-items: start
name:
- justify-self: start
- line-height: 105%
state:
- justify-self: start
- line-height: 105%
card:
- font-family: Sf Display
- border-radius: var(--custom-button-card-border-radius)
- -webkit-tap-highlight-color: rgba(0,0,0,0)
- transition: none
- padding: 8%
- --mdc-ripple-color: >
[[[
return (variables.state === 'on' || variables.state === 'home') ?
'rgb(0, 0, 0)' :
'rgba(255, 255, 255, 0.3)';
]]]
- color: >
[[[
return (variables.state === 'on' || variables.state === 'home') ?
'rgba(0, 0, 0, 0.6)' :
'rgba(255, 255, 255, 0.3)';
]]]
- background-color: >
[[[
return (variables.state === 'on' || variables.state === 'home') ?
'rgba(255, 255, 255, 0.8)' :
'rgba(115, 115, 115, 0.2)';
]]]
extra_styles: |
#name, #state {
font-size: 1.1vw;
letter-spacing: 0.05vw;
}
/* portrait */
@media screen and (max-width: 1200px) {
#name, #state {
font-size: 2vw;
letter-spacing: 0.05vw;
}
}
/* phone */
@media screen and (max-width: 800px) {
#name, #state {
font-size: 3.1vw;
letter-spacing: 0.12vw;
}
}
@keyframes card_bounce {
0% {
transform: scale(1);
}
15% {
transform: scale(0.9);
}
25% {
transform: scale(1);
}
30% {
transform: scale(0.98);
}
100% {
transform: scale(1);
}
}
additional_values:
#################################################
# #
# ADIDITIONAL VALUES #
# #
#################################################
additional_values:
custom_fields:
values: >
[[[
if ( variables.state != 'problem' && variables.state != 'unavailable' ) {
const value1 = variables.value_1;
const value2 = variables.value_2;
const value3 = variables.value_3;
return `
<svg viewBox="0 0 50 50">
<text x="5%" y="28%" fill="#8d8e90" font-size="12" text-anchor="start" alignment-baseline="middle" dominant-baseline="middle">${value1}</text>
<text x="5%" y="62%" fill="#8d8e90" font-size="12" text-anchor="start" alignment-baseline="middle" dominant-baseline="middle">${value2}</text>
</svg>
`;
} else if( variables.state === 'problem'){
const string1 = entity.attributes.problem;
if ( string1.includes('unavailable')) {
return `
<svg viewBox="0 0 50 50">
<path fill="#855151" d="M19.817 18.932L1.068.183c-.244-.244-.64-.244-.884 0s-.244.64 0 .884l1.935 1.935c-.621.286-1.231.596-1.819.952-.142.086-.245.227-.284.39a.62.62 0 0 0 .08.476l1.671 2.655a15.05 15.05 0 0 1 3.224-1.6l.995.995c-1.27.389-2.469.942-3.554 1.661l1.33 2.112c1.275-.852 2.745-1.414 4.315-1.682l1.1 1.1c-1.745.144-3.372.711-4.75 1.639l1.334 2.117C6.969 12.988 8.428 12.5 10 12.5c.644 0 1.265.09 1.86.244l7.072 7.072c.122.122.282.184.442.184a.63.63 0 0 0 .442-.182c.244-.245.244-.64 0-.885zm.165-14.587a.62.62 0 0 0-.284-.391C16.787 2.185 13.433 1.25 10 1.25a18.77 18.77 0 0 0-5.322.776l3.135 3.135C8.528 5.056 9.258 5 10 5c3.04 0 5.866.915 8.232 2.475l1.671-2.654a.62.62 0 0 0 .079-.476zM10 6.25l-1.057.041 2.574 2.574c1.727.235 3.334.851 4.721 1.78l1.33-2.114A13.66 13.66 0 0 0 10 6.25zm3.189 4.287l1.911 1.911.471-.749c-.73-.491-1.534-.876-2.382-1.162zM10 13.749a6.2 6.2 0 0 0-3.569 1.132l3.039 4.826a.63.63 0 0 0 .53.291c.215 0 .415-.11.529-.291l3.039-4.826A6.19 6.19 0 0 0 10 13.749z"/>
</svg>
`;
}else if( string1.includes('moisture low')){
return `
<svg viewBox="0 0 50 50">
<path d="M15.341 12.328a7.68 7.68 0 0 1-7.67 7.67A7.68 7.68 0 0 1 0 12.328a7.68 7.68 0 0 1 1.788-4.922L7.67 0l5.882 7.406c1.153 1.377 1.788 3.124 1.788 4.922z" fill="#4abbf0"/><path d="M15.341 12.328a7.68 7.68 0 0 1-7.67 7.67V0l5.882 7.406c1.153 1.377 1.788 3.124 1.788 4.922z" fill="#009be5"/><path d="M18.131 10.529a5.24 5.24 0 0 1-5.23 5.23 5.24 5.24 0 0 1-5.23-5.23c0-1.226.433-2.417 1.219-3.356l4.011-5.05 4.011 5.05c.786.939 1.219 2.13 1.219 3.356z" fill="#78d5f9"/><path d="M18.131 10.529a5.24 5.24 0 0 1-5.23 5.23V2.123l4.011 5.05c.786.939 1.219 2.13 1.219 3.356z" fill="#4abbf0"/>
</svg>
`;
}
}
]]]
styles:
card:
- font-size: 0.8vw;
custom_fields:
values:
- display: initial
- width: 95%
- letter-spacing: 0.03vw
- margin: -6% -6% 0 0
- justify-self: end
- opacity: 1
climate:
#################################################
# #
# CLIMATE #
# #
#################################################
climate:
show_state: false
show_icon: true
template:
- base_2
- additional_values
state:
- value: 'problem'
styles:
card: [box-shadow: '0px 0px 10px 2px #FFCCCC']
- value: 'ok'
styles:
card: [box-shadow: '0px 0px 10px 2px #E5FFCC']
variables:
value_1: >
[[[ return entity === undefined || Math.round((Math.abs(entity.attributes.pressure) > 999 ? Math.sign(entity.attributes.pressure)*((Math.abs(entity.attributes.pressure)/1000).toFixed(1)) + 'k' : Math.sign(entity.attributes.pressure)*Math.abs(entity.attributes.pressure))) + ' hPa'; ]]]
value_2: >
[[[ return entity === undefined || Math.round(entity.attributes.humidity) + '%'; ]]]
climate_livingroom.yaml only shows the current sensor values of an aqara temperature and humidity sensor. I use grafana for temperatuer and humdity graph:
action: fire-dom-event
browser_mod:
command: popup
title: Wohnzimmer
style:
.: |
:host .content {
width: calc(385px + 770px);
max-width: 90vw;
max-height: 95vw;
}
card:
type: custom:layout-card
layout_type: custom:grid-layout
layout:
grid-template-columns: repeat(2, 1fr)
grid-template-rows: 1fr
grid-template-areas: |
"info graph"
mediaquery:
#phone
"(max-width: 800px)":
grid-template-columns: 1fr
grid-template-rows: repeat(2, 1fr)
grid-template-areas: |
"info"
"graph"
cards:
- type: entities
view_layout:
grid-area: info
show_header_toggle: false
style: &border |
ha-card {
border-radius: 0;
animation: ha-card 1s forwards;
}
@keyframes ha-card {
0%, 100% {
border-right: 1.5px solid rgba(0, 0, 0, 0.2);
}
}
/* phone */
@media screen and (max-width: 800px) {
ha-card {
border-bottom: 1.5px solid rgba(0, 0, 0, 0.2);
padding-right: 0;
animation: none;
}
}
entities:
- entity: sensor.aqara_temp_1_temperature
secondary_info: last-updated
- entity: sensor.aqara_temp_1_humidity
secondary_info: last-updated
- entity: sensor.aqara_temp_1_pressure
secondary_info: last-updated
- type: divider
- entity: sensor.aqara_temp_1_battery
- entity: sensor.aqara_temp_1_linkquality
############# Grafana Graph #########################
#- break
- type: custom:hui-element
view_layout:
grid-area: graph
card_type: iframe
url: #link to grafana graf here
card_mod:
style: |
ha-card {
border-radius: 1em;
} action: fire-dom-event
browser_mod:
command: popup
title: Wohnzimmer
style:
.: |
:host .content {
width: calc(385px + 770px);
max-width: 90vw;
max-height: 95vw;
}
card:
type: custom:layout-card
layout_type: custom:grid-layout
layout:
grid-template-columns: repeat(2, 1fr)
grid-template-rows: 1fr
grid-template-areas: |
"info graph"
mediaquery:
#phone
"(max-width: 800px)":
grid-template-columns: 1fr
grid-template-rows: repeat(2, 1fr)
grid-template-areas: |
"info"
"graph"
cards:
- type: entities
view_layout:
grid-area: info
show_header_toggle: false
style: &border |
ha-card {
border-radius: 0;
animation: ha-card 1s forwards;
}
@keyframes ha-card {
0%, 100% {
border-right: 1.5px solid rgba(0, 0, 0, 0.2);
}
}
/* phone */
@media screen and (max-width: 800px) {
ha-card {
border-bottom: 1.5px solid rgba(0, 0, 0, 0.2);
padding-right: 0;
animation: none;
}
}
entities:
- entity: sensor.aqara_temp_1_temperature
secondary_info: last-updated
- entity: sensor.aqara_temp_1_humidity
secondary_info: last-updated
- entity: sensor.aqara_temp_1_pressure
secondary_info: last-updated
- type: divider
- entity: sensor.aqara_temp_1_battery
- entity: sensor.aqara_temp_1_linkquality
############# Grafana Graph #########################
- type: custom:hui-element
view_layout:
grid-area: graph
card_type: iframe
url: #link to grafana graph here
card_mod:
style: |
ha-card {
border-radius: 1em;
}
Thanks so much!
Heavy use of card-mod to style the theme itself then – not something I’ve explored much. Fun times ahead!
Much appreciated!
-J
thanks a lot. icon_temperature template is missing here, could you share that too.
Here you go:
icon_temperature:
show_state: true
custom_fields:
icon: >
[[[
if (entity.state != 'unavailable')
{
var temp_color ="'#9da0a2";
if (entity.state >= '-10' && entity.state < 0) {
temp_color = "#0302FC";
} else if(entity.state >= '0' && entity.state < 12) {
temp_color = "#2A00D5";
} else if(entity.state >= '12' && entity.state < 22) {
temp_color = "#63009E";
} else if(entity.state >= '22' && entity.state < 30) {
temp_color = "#A1015D";
} else if(entity.state >= '30' && entity.state < 35) {
temp_color = "#D80027";
} else if(entity.state >= '35' && entity.state < 40) {
temp_color = "#FE0002";
}
return `<svg viewBox="-949 951 100 125"><style>@keyframes animate{0%{transform: scale(0.85);}20%{transform: scale(1.1);}40%{transform: scale(0.95);}60%{transform: scale(1.03);}80%{transform: scale(0.97);}100%{transform: scale(1);}}.animate{animation: animate 0.8s; transform-origin: center;}</style>
<path fill="#9da0a2" d="M-895.9,1020.1v-56.7c0-5.5-4.5-10-10-10c-5.5,0-10,4.5-10,10v56.7c-3.7,3-6,7.6-6,12.4c0,8.8,7.2,16,16,16 c8.8,0,15.9-7.2,15.9-16C-890,1027.7-892.2,1023.1-895.9,1020.1z M-905.9,1045.1c-6.9,0-12.5-5.6-12.5-12.5c0-4.4,2.3-8.4,6-10.7 v-58.4c0-3.6,2.9-6.6,6.6-6.6c3.6,0,6.6,2.9,6.6,6.6v58.4c3.6,2.3,6,6.3,6,10.7C-893.4,1039.5-899,1045.1-905.9,1045.1z"/>
<path fill="${temp_color}" d="M-902.8,1024v-22.9c0-1.7-1.4-3.1-3.1-3.1c-1.7,0-3.1,1.4-3.1,3.1v22.9c-3.5,1.3-6,4.6-6,8.5c0,5,4.1,9.1,9.1,9.1 c5,0,9.1-4.1,9.1-9.1C-896.8,1028.6-899.3,1025.3-902.8,1024z"/>
<rect fill="#9da0a2" x="-892.4" y="963.6" width="16.3" height="3.4"/>
<rect fill="#9da0a2" x="-892.4" y="974.9" width="7.7" height="3.4"/>
<rect fill="#9da0a2" x="-892.4" y="986.3" width="16.3" height="3.4"/>
<rect fill="#9da0a2" x="-892.4" y="997.6" width="7.7" height="3.4"/>
<rect fill="#9da0a2"v x="-892.4" y="1008.9" width="16.3" height="3.4"/>
</svg>`;
} ]]]
It’s a quite lazy implementation, but it works
thanks. looks very nice
I noticed that top right corner where i have icon and humidity percentage, the text is slightly higher than the icon. do you how can i align them? i am using following code
additional_values:
custom_fields:
temp: >
[[[
return `<text>${variables.temp}°C</text>`
]]]
values: >
[[[
const value1 = variables.value_1;
const value2 = variables.value_2;
return `
<ha-icon icon="mdi:radiator" style="width: 20px; height: 20px;"></ha-icon><span> ${value1}</span>
<br>
<ha-icon icon="mdi:water-percent" style="width: 20px; height: 20px;"></ha-icon><span> ${value2}</span>
`
]]]
Hey @Mattias_Persson! Awesome design on the UI and clean code on the backend! You inspired me to redo my entire HA install and use your basecode. I even created a fork of it here (still working on the README). I changed several things and added some functionality but I am not a CSS expert by any stretch.
I am having trouble with these icons going haywire
.This is happening in the latest version of Brave Browser v1.29.76. It does not happen in Edge or Chrome. I did some developer analysis and saw that this line is affecting the size. flex: auto;
hui-grid-card {
display: flex;
flex: auto;
align-items: flex-end;
}
I rolled back the Brave version and the problem went away. Wondering if you or anyone else has seen this issue?
I was able to fix it in this change. Not sure if it was the “right” way though. Hopefully, this helps anybody else that comes across this problem.
Same problem here. Your fix kinda solves it, sometimes. Firefox looks good though.
Hmm hard to say. Can’t really help you here… I would try with something like text-align: center;
But I’m not really a CSS expert.
That was fast! Thx, it works.