LafferAndré Regardless of my request, can you share the camera code?
Not quite. Here is a snapshot of my panel. I am using one big custom:button-card, because I cannot figure out how to style a grid-card. BUT I want to be able to click on a link or particular area and offer a popup. If I could style the grid-card and make the custom:button cards transparent, all would be right in my world.
Well, I don’t know how you’d make 2 separate grids group like that, but you could have both grid gaps match. But again, it would apply to everything… if this is not what you’re looking for then someone else has to pitch in, I’m afraid
lovelace.yaml
grid-gap: 1vw
themes.yaml
grid-card-gap: 1vw
@Laffer Thanks again for the answer. But it gives something general unfortunately.
Can you share the code of your camera?
Here you go:
action: fire-dom-event
browser_mod:
command: popup
title: Weather
style:
hui-vertical-stack-card:
$hui-history-graph-card$ : |
.content {
padding: 0.2em 1.7em 1.2em 1.7em !important;
}
$: |
button-card {
align-self: center;
padding: 0.2em 0 2.3em 0;
}
$hui-map-card:
$: |
mwc-icon-button {
color: var(--primary-color);
}
ha-card {
border-radius: 0;
animation: border 1s forwards;
}
@keyframes border {
0%, 100% {
border-top: 2px solid #1a1a1a;
}
}
$ha-map$: |
#map {
background-color: #191919 !important;
}
.leaflet-control-attribution {
display: none;
}
.leaflet-bar a {
background-color: rgba(47, 51, 51, 0.9) !important;
color: #9da0a2 !important;
}
a.leaflet-control-zoom-in {
border-bottom: 1px solid #181818 !important;
}
.leaflet-pane.leaflet-tile-pane {
filter: contrast(85%);
}
card:
type: vertical-stack
cards:
- type: entities
card_mod:
class: content
entities:
- entity: weather.openweathermap
secondary_info: last-changed
name: Your place
- type: custom:apexcharts-card
layout: minimal
locale: 'no' #no? #se
graph_span: 12h
show:
loading: false
apex_config:
plotOptions:
area:
fillTo: end
grid:
padding:
top: -15
fill:
type: gradient
gradient:
type: vertical
opacityFrom: 0.8
opacityTo: 0
stops:
- 0
- 99
- 100
stroke:
width: 4
tooltip:
style:
fontSize: 14px
x:
format: dddd HH:mm
chart:
height: 140px
offsetY: -20px
xaxis:
crosshairs:
show: false
series:
- entity: sensor.openweathermap_temperature
name: Temp
color: '#385581'
type: area
fill_raw: last
group_by:
func: avg
duration: 1h
- color_type: blank-card
type: custom:button-card
- type: iframe
url: https://embed.windy.com/embed2.html?lat=58.905&lon=7.789&detailLat=59.886&detailLon=9.360&width=650&height=450&zoom=7&level=surface&overlay=wind&product=ecmwf&menu=&message=&marker=&calendar=now&pressure=&type=map&location=coordinates&detail=&metricWind=default&metricTemp=default&radarRange=-1
aspect_ratio: 75%
It’s basically a copy of Mattias’s Conditional Media card - just flipped.
…I think you can remove ‘- type: horizontal-stack’ and everything beneath if you don’t want that option.
- type: grid
title: Cameras
view_layout:
grid-area: cameras
columns: 1
cards:
- type: custom:swipe-card
start_card: 1
parameters:
roundLengths: true
effect: coverflow
speed: 650
spaceBetween: 20
threshold: 7
coverflowEffect:
rotate: 80
depth: 300
cards:
- type: grid
columns: 2
cards:
- type: custom:button-card
entity: camera.inngangen
name: " "
template:
- camera
- icon_unifi_cam
tap_action:
!include popup/camera_single.yaml
- type: custom:button-card
entity: camera.ringeklokke
name: " "
template:
- camera
- icon_unifi_cam
tap_action:
!include popup/camera_single.yaml
- type: custom:button-card
entity: camera.stua
name: " "
template:
- camera
- icon_unifi_cam
tap_action:
!include popup/camera_single.yaml
- type: custom:button-card
entity: camera.verandaen
name: " "
template:
- camera
- icon_unifi_cam
tap_action:
!include popup/camera_single.yaml
- type: horizontal-stack
cards:
- type: conditional
conditions:
- entity: input_select.conditional_camera
state: Driveway
card:
type: custom:button-card
entity: camera.inngangen
tap_action:
action: none
template:
- conditional_camera
- type: conditional
conditions:
- entity: input_select.conditional_camera
state: Doorbell
card:
type: custom:button-card
entity: camera.ringeklokke
template:
- conditional_camera
- type: conditional
conditions:
- entity: input_select.conditional_camera
state: Living-room
card:
type: custom:button-card
entity: camera.stua
template:
- conditional_camera
- type: conditional
conditions:
- entity: input_select.conditional_camera
state: Terrace
card:
type: custom:button-card
entity: camera.verandaen
template:
- conditional_camera
Thanks, Template Camera can you share? And Icon_unifi_cam - I will be happy to share what is connected to your code …
Thank you
The UniFi cam icon is not really used there, yet. And it’s too messy atm.
It’s getting there, tho… I can share it once I’m done.
base_camera:
tap_action:
action: >
[[[
return !(variables.state === 'off' || variables.state === 'standby') ? 'call-service' : 'none';
]]]
service: media_player.media_play_pause
service_data:
entity_id: >
[[[ return entity === undefined || entity.entity_id; ]]]
double_tap_action:
action: call-service
service: >
[[[ return variables.state === 'off' || variables.state === 'standby' ? 'media_player.turn_on' : 'media_player.turn_off'; ]]]
service_data:
entity_id: >
[[[ return entity === undefined || entity.entity_id; ]]]
styles:
card:
- color: >
[[[
let entity_picture = entity === undefined || entity.attributes.entity_picture;
if (variables.state === 'off' || variables.state === 'standby' ||
variables.state === 'unknown' || variables.state === 'unavailable' || entity === undefined) {
return 'rgba(255, 255, 255, 0.3)';
}
return (variables.state != 'off' && variables.state != 'standby') && (entity_picture == null) ? 'rgba(0, 0, 0, 0.6)' : '#efefef';
]]]
- text-shadow: >
[[[
let entity_picture = entity === undefined ? null : entity.attributes.entity_picture;
return entity_picture == null ? 'none' : '1px 1px 5px rgba(18, 22, 23, 0.9)';
]]]
camera:
template:
- base
- base_camera
state_display: >
[[[ if (variables.state == 'idle' || variables.state == 'recording') return ' '; ]]]
styles:
custom_fields:
icon:
- width: 70%
- fill: '#9da0a2'
- opacity: >
[[[
let entity_picture = entity === undefined ? null : entity.attributes.entity_picture;
if (entity.state !== 'unavailable' && entity.state !== 'standby') {
return entity_picture == null ? 1 : 0;
}
]]]
card:
#- align-self: middle
- background-color: none
- background-size: cover #137% 101%
- background-position: center
- background-repeat: no-repeat
- background-image: >
[[[
let entity_picture = entity === undefined || entity.attributes.entity_picture;
if (variables.state === 'off' || variables.state === 'standby' ||
variables.state === 'unknown' || variables.state === 'unavailable' || entity === undefined) {
return 'linear-gradient(0deg, rgba(115, 115, 115, 0.2) 0%, rgba(115, 115, 115, 0.2) 100%)';
}
return (variables.state != 'off' && variables.state != 'standby') && (entity_picture == null) ?
'linear-gradient(0deg, rgba(255, 255, 255, 0.8) 0%, rgba(255, 255, 255, 0.8) 100%)' :
'linear-gradient(0deg, rgba(0,0,0,.1) 0%, rgba(0,0,0,0) 100%), url(' + entity_picture + ')';
]]]
conditional_camera:
template:
- camera
- base_camera
state_display: >
[[[
if (entity.attributes.online === 'false') {
return 'No cameras online';
}
return entity.attributes.online === 'true' && variables.state === 'recording' ? 'No title' : entity.attributes.last_tripped_time;
]]]
custom_fields:
blur: >
[[[
if (entity.attributes.entity_picture !== undefined) return '<div></div>';
]]]
overlay: >
[[[
if (entity && entity.attributes.entity_picture === undefined && entity.state !== 'unavailable' && entity.state !== 'standby') return '<div></div>';
]]]
media_image: >
<div></div>
play_pause: >
[[[
let style = `
<style>
.scale-up {
animation: scale-up 1s forwards;
cubic-bezier(.05, .5, .3, 1);
transform-origin: center center;
}
@keyframes scale-up {
0% {
opacity: 0;
transform: scale(0);
}
20% {
transform: scale(1);
}
30% {
opacity: 1;
}
80% {
opacity: 1;
}
100% {
opacity: 0;
}
}
</style>
`;
if (variables.state === 'paused' && variables.timeout < 2000) {
return `
<svg viewBox="0 0 166 166">${style}
<path class="scale-up" d="M0 0h59.9v166H0zm106.1 0H166v166h-59.9z"/>
</svg>
`;
}
if (variables.state === 'playing' && variables.timeout < 2000) {
return `
<svg viewBox="0 0 166 166">${style}
<path class="scale-up" d="M0 0l166 83L0 166z"/>
</svg>
`;
}
]]]
styles:
name:
- z-index: 3
- margin-bottom: -1%
state:
- z-index: 3
card:
- background-color: rgba(115, 115, 115, 0.2)
- padding: 5%
- border-radius: calc(var(--custom-button-card-border-radius) / 2)
- backdrop-filter: blur(0) #fix chrome bug
- -webkit-clip-path: inset(0) #fix safari bug
custom_fields:
blur:
- z-index: 2
- top: 75%
- left: 0%
- width: 100%
- height: 25.5%
- position: absolute
- background-color: rgba(0, 0, 0, 0.2)
- backdrop-filter: blur(0.4em)
- -webkit-backdrop-filter: blur(0.4em)
overlay:
- z-index: 2
- opacity: 1
- top: 75.5%
- left: 0%
- width: 100%
- height: 26%
- position: absolute
- background-color: rgba(255, 255, 255, 0.8)
media_image:
- z-index: 1
- top: 0
- left: 0
- width: 100%
- height: 100%
- position: absolute
- background-size: cover
- background-position: center
- background-repeat: no-repeat
- background-image: >
[[[
return entity.attributes.entity_picture === undefined ? 'none' : `url(${entity.attributes.entity_picture})`;
]]]
play_pause:
- z-index: 3
- top: 0
- right: 0
- bottom: 0
- left: 0
- margin: auto
- width: 21%
- height: 21%
- position: absolute
- fill: '#dedede'
- overflow: visible
- filter: >
[[[
let entity_picture = entity === undefined || entity.attributes.entity_picture;
return entity_picture == null ? 'none' : 'drop-shadow(0 0 1.3vw rgba(0,0,0,0.7))';
]]]
icon:
- z-index: 3
- width: 29%
- fill: >
[[[
return variables.state === 'off' || variables.state === 'standby' ||
variables.state === 'unknown' || variables.state === 'unavailable' || entity === undefined ?
'#9da0a2' :
'rgba(255, 255, 255, 0.8)';
]]]
Awesome work. How can i load a scene.xyz on the buttons? only works for entities? thx
In order to apply card-mod to a layout-card, you need to wrap it in a mod-card and apply the style you want for the grid to the mod-card. It won’t work without the mod-card, I’m afraid.
Hello , i also try to add kodi instead of plex.
the sensor you meantion above where is it located ?
i get this error when i try to copy your card :
ButtonCardJSTemplateError: TypeError: data[1] is undefined in ‘const data = JSON.parse(states[entity.entity_id].attributes.data); return `${data[1].title} (${dat…’
Well I think I know what my problem is… I just don’t know the solution. It seems my button-cards inside the grid are being forced to remain square. Unless I have a grid of 2x2 or 3x3 I’m going to have “off screen” issues. Is there a way to build this with a top row of 2 cells (each with a 2x2 grid of buttons inside) and a bottom row of 3 cells (each with a 2x2 grid of buttons)? I read something about setting square to false but I can’t seem to find the right spot to do it.
HI André,
can you share your Code with the Ccamera Button?
THank You
Hi,
Can someone offer some advice please.
I’m wanting to use a icon other than the ones in the custom button card file.
Is it a case of adding an new icon to the custom button card? The icon is a mdi icon and I would like the base template behind it also?
type: grid
title: Backyard
columns: 2
square: false
cards:
Can somebody tell me where the distance of the sidebar icons is defined ?
(Icons should be at the top and close to the time)
Does anybody know where in the code the HA side menu and top bar are switch off?
Thanks.
Yeah the problem isn’t the grid. The problem is that the custom:button-card wants to be square. I can make my grids “non square” but if the button cards inside the grids want to be square, that doesn’t solve my problem.
The only solution I’ve found so far (which is less than perfect) is to add the aspect_ratio attribute to the custom:button-card. Then I have to tweak the aspect ratio for each display device.
I was wondering if someone could explain this piece of code in the button_card_templates.yaml under the base template:
extra_styles: |
[[[
if (entity) {
let hs = entity.attributes.hs_color === undefined,
h = hs || entity.attributes.hs_color[0],
s = hs || entity.attributes.hs_color[1],
l_min = 28,
l_max = 48,
l_calc = entity.attributes.brightness / 2.54 * (l_max - l_min) / 100 + l_min;
var light_color = entity.attributes.color_mode === 'color_temp'
? `hsl(204, 58%, ${l_calc}%);`
: `hsl(${h}, ${s}%, ${l_calc}%);`;
}
return `
svg {
--light-color:
${ variables.state_on && entity.attributes.brightness !== undefined
? light_color
: variables.state_on && entity.attributes.brightness === undefined
? 'var(--state-icon-active-color);'
: 'var(--state-icon-color);'
}
}
The way I read this is that the top part of the code sets the light_color if the entity uses a colored light. However, in my situation, I am using this on a dimmable switch (not a color changing light) and, as a result, hs_color is “null” according to developer tools / templates – I am assuming that translates to “undefined” in javascript.
Anyway, what is actually being returned is
--light-color: hsl(true, true%, 32.01574803149606%);
Which means entity.attributes.color_mode === ‘color_temp’ is false.
Now this is where I get confused. Since this is not a color_temp light and brightness is NOT undefined, why are we taking the light_color from above and not the --state-icon-active-color instead?
I guess I just need clarification on how to get my dimmable switch (which only has brightness levels) to use the --state-icon-active-color and not a HSL calculation.