A different take on designing a Lovelace UI

Download icon as SVG

If you paste that into button-card it will look like this.

1

Rather than fixing it in code we can have a consistent viewbox for all the icons we create or download.

  • Create an empty svg
<svg viewBox="0 0 50 50"></svg>
  • Open both icon and empty svg in illustrator

  • Copy over the icon to the empty svg

  • Resize the icon to fit artboard

Now, there’s a lot of paths so let’s make it into one with Compound Path with keyboard shortcut cmd + 8 (ctrl + 8)

So of course that didn’t work as you picked a complex icon :joy:

Undo that and select everything again and go Pathfinder > Exclude

4

Lets try Compound Path again, we got one path

Save as svg and upload to nano

Now we got an SVG file of the icon in:

  • One single path
  • In our viewbox
  • A lot less code

You don’t have to make it into one shape, we can split it into more paths so you can color and animate separate parts.

In lovelace it looks like this, you can fine tune the size and position.

8

custom_fields:
  icon_cube3d: >
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><path d="M47.6 8.1v-.4h-.3L19.2 1c-.1 0-.3 0-.4.1L2.6 12.6l-.1.1v29c0 .2.2.5.4.5l28 6.7h.4l16.1-11.6a.76.76 0 0 0 .2-.4V8.1c0 .1 0 0 0 0zm-28.5-6h.4l12.4 3-7 5-5.4-1.3v-.1h-.4L12.3 7l6.8-4.9zm-2.7 29.6h0V37l-.9-.2-.2.8 1 .2v6.8L3.5 41.4V28.1l12.9 3.1v.5zm0-14.4h0v12.9L11 28.8h.4v-1.3h-.8v1.2L3.5 27V13.7l7.2 1.7v.3h.8v-.1l5 1.2v.5zm-5-2.7v-.1H11l-6.8-1.6 6.8-5h.4l7.3 1.7v.4h.8v-.2l4.3 1-4.3 3.1h-.8v.6l-1.9 1.4-5.4-1.3zm7.2 1.7l-.4-.1.2-.2.2.3zM30.4 35h0v12.9l-12.9-3.1V31.9l.3-.2-.1-.1 12.7 3v.4zm0-1.5L19 30.8l.1-.1.5.1.2-.8-.3-.1v-.3h-.8v.4l-.4.3.3.4-1.1-.3V17.5l.3-.2-.1-.1 1 .2v.4h.8v-.2l7.6 1.8 3.3.8v13.3zm.7-14.5l-.3.2L19 16.4l.1-.1.5.1.2-.8-.6-.2-.1.4-.2-.2 6.2-4.4 7.6 1.8v.3h.8v-.1l4.3 1-4.3 3.1h-.8v.6l-.9.6-.5-.1-.2.6zm7.4 23.2h0l-.1.3-6.9 5v-6.2l.5.1.2-.8-.7-.2v-5.3l.3-.2-.3-.5v-.1l.9-.6h.1v-.1l.4.5.5-.4-.2-.3h.4V33l5-3.6v12.8zm0-14.1l-6.7 4.8-.4-.1V20l.9-.6h.1v-.1l6.1-4.4v13.2zm-5-16V12H33l-6.8-1.6L33 5.5h.4l12.4 3-7 5-5.3-1.4zm13 24.3h0l-.1.3-6.9 5v-6.2l.5.1.2-.8-.7-.2v-6.1l7-5v12.9zm0-14.4h0l-.1.3-6.9 5v-6.2l.5.1.2-.8-.7-.2v-6.1l7-5V22zM34.9 34.4l-1.3-.3.2-.8 1.3.3-.2.8zm7.6 1.8l-1.3-.3.2-.8 1.3.3-.2.8zm2.6.7l-1.3-.3.2-.8 1.3.3-.2.8zm-18.9-5.4l1.3.3-.2.8-1.3-.3.2-.8zm3.6 1.7l-1.3-.3.2-.8 1.3.3-.2.8zm-6.2-2.3l1.3.3-.2.8-1.3-.3.2-.8zm-2.5-.6l1.3.3-.2.8-1.3-.3.2-.8zM37.4 35l-1.3-.3.2-.8 1.3.3-.2.8zM8.7 38.2l-.5-.6 1-.7.5.6-1 .7zm4.1-2.9l-.5-.6 1-.7.5.6-1 .7zM4.7 41l-.5-.6 1-.7.5.6-1 .7zm10.1-7.2l-.5-.6 1-.7.5.6-1 .7zm-8.1 5.8l-.4-.6 1-.7.5.6-1.1.7zM19.5 4.7h-.8V3.4h.8v1.3zm0 2.7h-.8V6h.8v1.4zM18.7 27h.8v1.3h-.8V27zm0-2.6h.8v1.3h-.8v-1.3zm.8-11.8h-.8v-1.3h.8v1.3zm-.8 6.5h.8v1.3h-.8v-1.3zm0 2.6h.8V23h-.8v-1.3zm8 16.9l-.4-.6 1-.7.5.6-1.1.7zM19.2 43l.5.6-1 .7-.5-.6 1-.7zm1.5-.1l-.5-.6 1-.7.5.6-1 .7zm2-1.4l-.5-.6 1-.7.5.6-1 .7zm6.1-4.3l-.5-.6 1-.7.5.6-1 .7zm4.7-13.4h-.8v-1.3h.8v1.3zm0-2.6h-.8v-1.3h.8v1.3zm0 5.2h-.8v-1.3h.8v1.3zm0 2.6h-.8v-1.3h.8V29zm0 2.6h-.8v-1.3h.8v1.3zm-.8-22.2h.8v1.3h-.8V9.4zm0-2.6h.8v1.3h-.8V6.8zm.8 9.1h-.8v-1.3h.8v1.3zM19.2 38.4l-1.3-.3.2-.8 1.3.3-.2.8zm2.5.6l-1.3-.3.2-.8 1.3.3-.2.8zm11.7 2l1.3.3-.3.7-1.3-.3.3-.7zm3.6 1.7l-1.3-.3.2-.8 1.3.3-.2.8zm-12.7-3.1l-1.3-.3.2-.8 1.3.3-.1.5.9-.7.4.6v-.1l1.3.3-.2.8-1.3-.3.1-.5-.9.7-.4-.6v.1zm5.1 1.2l-1.3-.3.2-.8 1.3.3-.2.8zM13 36.1l1.3.3-.2.8-1.3-.3.2-.8zm-2.4-24.3h.8v1.3h-.8v-1.3zm0 5.3h.8v1.3h-.8v-1.3zm0-7.9h.8v1.3h-.8V9.2zm.8 24.9h-.8v-1.3h.8v1.3zm-.8-9.2h.8v1.3h-.8v-1.3zm.8 6.6h-.8v-1.3h.8v1.3zm-.7 5.2l-.5-.6.3-.2v-.4h.7v.1l.2.2h.2v.2h-.1l-.1.5-.5-.1-.2.3zm10.4-20.8l1.3.3-.2.8-1.3-.3.2-.8zm2.5.6l1.3.3-.2.8-1.3-.3.2-.8zm21.5 6l-1.3-.3.2-.8 1.3.3-.2.8zm-2.6-.6l-1.3-.3.2-.8 1.3.3-.2.8zm-16.3-4.8l1.3.3-.2.8-1.3-.3.2-.8zm2.5.7l1.3.3-.2.8-1.3-.3.2-.8zm8.7 2.9l-1.3-.3.2-.8 1.3.3-.2.8zm-2.5-.7l-1.3-.3.2-.8 1.3.3-.2.8zm-20.1-.6l-.5-.6 1-.7.5.6-1 .7zm-7.5 4.5l.5.6-1 .7-.5-.6 1-.7zm2-1.5l.5.6-1 .7-.5-.6 1-.7zm-4 2.9l.5.6-1 .7-.6-.6 1.1-.7zm7.5-4.4l-.5-.6 1-.7.5.6-1 .7zm-1.5.1l.4.6-1 .7h.6v1.3h-.8v-1.3h.1l-.4-.6 1.1-.7h-.7v-1.3h.8l-.1 1.3z"/></svg>
styles:
  custom_fields:
    icon_cube3d:
      [fill: green, top: 7%, left: 10%, width: 3.5vw, position: absolute]
26 Likes

Listen Mattias, this is soooo nice of you to spend all the effort and time to help a rookie like I am, really appreciated. It looks not only great but now I know how it works and that is most important!

Really, really appreciated and big help! Thanks a lot!

1 Like

We contribute and learn from each other. :slightly_smiling_face:

9 Likes

Hi Mattias,
I manage to customize icons doing the following:

  1. download icons in .svg format

  2. modify icon in Inkscape as need it and save it with a different name

  3. open the original icon in a text editor and copy the viewBox=“0 0 24 24” and <path d=" …" and paste it in yaml

  4. open the modified icon in a text editor and copy the viewBox=“0 0 24 24” and <path d=" …" and paste it in yaml

  5. the modified yaml looks like this:

custom_fields:
              icon_ceiling_light: >
                [[[ const state = entity.state === 'on' ? 'animate' : null;
                return `<svg viewBox="0 0 24 24"><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>
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M8,9H11V4H13V9H16L20,17H4L8,9M14,18A2,2 0 0,1 12,20A2,2 0 0,1 10,18H14Z" /></svg>
                <path class="${state}" fill="var(--button-card-light-color-no-temperature)"  d="m 8,9 c 8,0 0.7559689,0 8,0 l 4,8 H 4 L 8,9"/></svg>`; ]]]

            styles:
              custom_fields:
                icon_ceiling_light:
                  [fill: grey, top: 7%, left: 4.5%, width: 4.5vw, position: absolute]

the new icon animates the same as the icon in your design
image
image

15 Likes

I will release some animated SVG today. Thanks for the great help.

Here is a little video of my Lovelace. Here the video: https://imgur.com/xnF4aJf

11 Likes

WOW, great. Do you share your complete Config?

Mattias certainly had a lot of influence on this design. I would like to thank him again at this point. I will therefore share as many of the codes as possible.

1 Like

I know and I have had my Config only with Mattias help getting to work.

How do you blur the background behind the pop-ups?

Look Post#2

A different take on designing a Lovelace UI?

1 Like

fire hd 10 + fully kiosk browser without blur effect

Fully uses android webview (chrome) and backdrop-filter is pretty new for android, I would say late 2019 as I remember it started to work after an os update. caniuse.com is a good way to check browser support.

That’s amazing. I’d really love those SVGs especially the blinds I’ve been looking for a good one but could never find one.

@Mattias_Persson Wow! This is amazing!! Great job. Hopefully this gets the attention of the Lovelace UI devs and maybe, just maybe one day this will inspire lovelace…oh who am I kidding. lol

Anyways…I’ve managed to “borrow” the hue, tv and speaker icons. Wondering if you have plans to create the SVGs for climate, garage doors, security cameras?

Also, is it possible to to keep an animation repeating such as when the music is playing I’d like to have the woofer keep animating.

Thanks again for the inspiration!!

Can you post the paths here, so if anyone want them they can use them?

Going through the YAML was harder than I thought to extract the icons.

I don’t have any of that so no.

It depends. Does ha know if music is playing? If yes you can set the animation-iteration-count: infinite like the fan svg loops.

I was actually researching the same idea and there’s no readily available way to capture if music is playing on macos. I’d have to write a program to listen for system audio all the time and count bpm so the animation matches. Honestly, I don’t know where to start or if this really is a good idea at all.

1 Like

Perfect! That worked. I use a media_player entity so it knows when the music is playing: Here’s the code snippet I modified. Thanks for your help!

                                  custom_fields:
                                    icon_sonos: >
                                      [[[ if (entity.state === 'playing') {
                                      return '<svg viewBox="0 0 50 50">
                                      <style>
                                      @keyframes animate{
                                      35%{transform: scale(0.8); animation-timing-function: cubic-bezier(0, 0.55, 0.45, 1);}
                                      36%{transform: translateY(0%);}
                                      49%{transform: scale(1.25);}
                                      63%{transform: scale(0.85); animation-timing-function: cubic-bezier(0, 0.55, 0.45, 1);}
                                      77%{transform: scale(1.15); animation-timing-function: cubic-bezier(0, 0.55, 0.45, 1);}
                                      95%{transform: scale(1);}}.animate{animation: animate 1s; transform-origin: center; animation-iteration-count: infinite;}
                                      @keyframes rubber{0%{transform: scale(1);}40%{transform: scale(1);}
                                      49%{transform: scale(0.95);}
                                      63%{transform: scale(1);}
                                      77%{transform: scale(0.95);}
                                      100%{transform: scale(1);}}.rubber{animation: rubber 1s; transform-origin: center;animation-iteration-count: infinite;}
                                      </style>
                                      <g class="rubber"><path fill="#686868" d="M35.8 46.9H14.2c-1.1 0-2-1-2-2.3V6.7c0-1.3.9-2.3 2-2.3h21.5c1.1 0 2 1 2 2.3v37.9c0 1.2-.9 2.3-1.9 2.3z"/><path fill="#2a2a2a" d="M39.2 1H10.8C9.4 1 8.3 2.1 8.2 3.5v42.9a2.65 2.65 0 0 0 2.6 2.6h28.3c1.4 0 2.5-1.2 2.6-2.6V3.5c0-1.4-1.1-2.5-2.5-2.5zM25 7c1.3 0 2.4 1.1 2.4 2.4s-1.1 2.4-2.4 2.4-2.4-1.1-2.4-2.4C22.5 8 23.6 7 25 7zm10.2 35.5l-.4 1.9s-.2.6-.6.6H15.8c-.4 0-.6-.6-.6-.6s-.1-1.1-.4-1.9.6-.9.6-.9h19.3c0-.1.8-.1.5.9z"/> </g> <path class="animate" fill="#e5dd00" d="M25 15.7c-6.2 0-11.3 5.1-11.3 11.3S18.8 38.3 25 38.3 36.3 33.2 36.3 27c-.1-6.3-5.1-11.3-11.3-11.3zm0 14.5a3.33 3.33 0 0 1-3.3-3.3 3.33 3.33 0 0 1 3.3-3.3 3.33 3.33 0 0 1 3.3 3.3c-.1 1.9-1.5 3.3-3.3 3.3z"/></svg>'; }
                                      else { return '<svg viewBox="0 0 50 50"><path fill="#9da0a2" d="M25 18.6c-4.6 0-8.4 3.8-8.4 8.4s3.8 8.4 8.4 8.4 8.4-3.8 8.4-8.4-3.7-8.4-8.4-8.4zm0 11.7a3.33 3.33 0 0 1-3.3-3.3 3.33 3.33 0 0 1 3.3-3.3 3.33 3.33 0 0 1 3.3 3.3c0 1.8-1.4 3.3-3.3 3.3zM39.2 1H10.9C9.4 1 8.3 2.1 8.3 3.6v42.9a2.65 2.65 0 0 0 2.6 2.6h28.3a2.65 2.65 0 0 0 2.6-2.6v-43C41.7 2 40.5.9 39.2 1zM25 7c1.3 0 2.4 1.1 2.4 2.4s-1.1 2.4-2.4 2.4-2.4-1.1-2.4-2.4S23.7 7 25 7zm10.3 35.5l-.4 1.9s-.2.6-.6.6H15.8c-.4 0-.6-.6-.6-.6l-.4-1.9c-.2-.9.6-.9.6-.9h19.3s.9.1.6.9zM25 38.2c-6.2 0-11.3-5.1-11.3-11.3a11.29 11.29 0 1 1 22.6 0c.1 6.3-5 11.3-11.3 11.3z"/></svg>'; } ]]]
5 Likes

I try to add the temp from my thermostat as info on the button, any idea how to do this?

Yes, what have you tried so far?

I made a template for thermostat with the thermostat-popup-card.
For the button, I don’t know what I have to put in the custom_fields section.
I don’t know the entity.attributes I have tu use for the Temperature.

custom_fields:
info: >
[[[ if (entity.state === ‘on’ && entity.attributes.brightness) {
const brightness = Math.round(entity.attributes.brightness / 2.54);
const radius = 20.5; const circumference = radius * 2 * Math.PI;
return <svg viewBox="0 0 50 50"><circle cx="25" cy="25" r="${radius}" stroke="#b2b2b2" stroke-width="1.5" fill="none" style=" transform: rotate(-90deg); transform-origin: 50% 50%; stroke-dasharray: ${circumference}; stroke-dashoffset: ${circumference - brightness / 100 * circumference};" /> <text x="50%" y="54%" fill="#8d8e90" font-size="14" text-anchor="middle" alignment-baseline="middle">${brightness}<tspan font-size="10">%</tspan></text></svg>; } ]]]