A different take on designing a Lovelace UI

hi, is it possible to have another dashboard beside this one? Because the tablet theme breaks the other dashboard… thanks

Yes try this.

Maybe this question is already asked, but couldn’t find the solution in this thread.

The person cards are working, howeve within the circle the display of the time home are not updating, only on refresh of the whole browser the information is updated.

I would expect that these times are updating automatically, but maybe my expectation is wrong.

- platform: template
    sensors:
      appletv_kueche_progress:
        friendly_name: "Apple TV Kueche Player Prozent"
        value_template: >
              {{ 100 / state_attr('media_player.kueche','media_duration') * (state_attr('media_player.kueche', 'media_position')) }}  

Thanks! That fixed the error. For some reason my conditional card is no longer changing though, and just stuck at “Recently Added.” Probably something off in my own code, but I’ll keep working through it.

Thanks again!

1 Like

Check out the select.conditional_media entity and see if that is reporting correctly. The options should match the media player friendly names that are listed as conditions in the ui-lovelace.yaml media section.

If it doesn’t, your problem is in packages/tv_media.yaml

1 Like

You rock! That was exactly what I needed, and found that my PS5 sensor was named incorrectly in tv_media.yaml. Quick fix. Thanks for pointing me in the right direction!

2 Likes

I cannot figure out how to change colors of svg icons. As it is right now the icons i have copied from this thread, where pictures show different colors from what i get… I can see that colors are often set via variables, but where should i find these values? Is it in themes.yaml, because i cannot find them there.

My icons:
image

Original according to this forum:
image

and icon.yaml includes this code

icon_pendant:
    styles:
      custom_fields:
        icon:
          - width: 100%
          - margin-left: -9%
          - margin-top: -9%
    custom_fields:
      icon: >
        [[[
          let state = variables.state_on && variables.timeout < 2000 ? 'on' : null;
          return `
            <svg stroke-miterlimit="10" style="fill-rule:nonzero;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:vectornator="http://vectornator.io" xmlns:xlink="http://www.w3.org/1999/xlink">
              <defs><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="178.015" id="Filter" width="15.7685" x="244.46" y="22.1442"><feDropShadow dx="0" dy="0" flood-color="#000" flood-opacity=".797297" in="SourceGraphic" result="Shadow" stdDeviation=".680957"/></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="74.3896" id="Filter_2" width="49.2588" x="228.474" y="164.53"><feDropShadow dx="0" dy="0" flood-color="#000" flood-opacity=".333" in="SourceGraphic" result="Shadow" stdDeviation=".775166"/></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="185.846" id="Filter_3" width="342.386" x="79.1407" y="201.683"><feDropShadow dx="0" dy="0" flood-color="#000" flood-opacity=".333" in="SourceGraphic" result="Shadow" stdDeviation=".387597"/></filter></defs><g  id="Layer-1" vectornator:layerName="Layer 1">
              <path class="${state}" d="M252.33 30.0149 252.357 192.288" fill="blue" fill-rule="evenodd" filter="url(#Filter)" stroke="#a0a0a0" stroke-linecap="butt" stroke-linejoin="miter" stroke-width="13.0176" vectornator:shadowAngle="-.656674" vectornator:shadowColor="#000000" vectornator:shadowOffset="0" vectornator:shadowOpacity=".797297" vectornator:shadowRadius="1.36191"/>
              <path class="${state}" d="M238.28 166.081H267.926C272.486 166.081 276.182 169.886 276.182 174.581V228.869C276.182 233.564 272.486 237.369 267.926 237.369H238.28C233.72 237.369 230.024 233.564 230.024 228.869V174.581C230.024 169.886 233.72 166.081 238.28 166.081z" fill="var(--light-outside)" fill-rule="evenodd" filter="url(#Filter_2)" stroke="none" vectornator:shadowAngle="1.5708" vectornator:shadowColor="#000000" vectornator:shadowOffset="0" vectornator:shadowOpacity=".333" vectornator:shadowRadius="1.55033"/>
              <path class="${state}" d="M79.9394 336.998C78.8314 299.922 117.197 257.306 137.523 241.656 168.633 217.703 202.906 202.458 249.98 202.458 297.053 202.458 338.512 219.467 369.361 243.775 400.209 268.084 420.752 302.038 420.752 336.83 420.752 382.245 405.423 385.678 366.584 386.494 341.306 387.025 298.558 386.577 251.484 386.577 204.411 386.577 171.104 386.31 135.623 385.764 96.7806 385.167 81.331 383.565 79.9394 336.998z" fill="var(--light-outside)" fill-rule="evenodd" filter="url(#Filter_3)" stroke="none" vectornator:shadowAngle="1.5708" vectornator:shadowColor="#000000" vectornator:shadowOffset="0" vectornator:shadowOpacity=".333" vectornator:shadowRadius=".775194"/>
              <path class="${state}" fill="var(--light-color)" d="M210.899 409.227C212.783 397.014 216.042 397.813 226.03 397.757 235.634 397.704 245.046 397.781 256.452 397.685 267.382 397.594 270.76 397.868 281.548 398.215 290.703 398.51 295.585 397.897 297.041 408.195 298.497 418.493 295.761 440.415 282.097 449.059 268.434 457.704 234.111 456.602 222.094 445.669 210.076 434.737 209.367 419.164 210.899 409.227z" fill="#ffdc00" fill-rule="evenodd" opacity="1" stroke="none"/>
              </g>
              
              <style>
                @keyframes on {
                  0% {
                    color: #26abff
                    background-color: '#26abff';
                  }
                  23% {
                    transform: rotateZ(-10deg);
                    animation-timing-function: ease-in-out;
                  }
                 
                  56% {
                    transform: rotateZ(10deg);
                    animation-timing-function: ease-in-out;
                  }
                  70% {
                    transform: rotateZ(-2deg);
                    animation-timing-function: ease-in-out;
                  }
                  85% {
                    transform: rotateZ(2deg);
                    animation-timing-function: ease-in-out;
                  }
                  100% {
                    transform: rotateZ(0deg);
                  }
                }
                .on {
                  animation: on 1.7s;
                  transform-origin: top;
                  background-color: '#26abff';
                  animation-fill-mode: forwards;
                  animation-delay: -0.1s;
                }
                
              </style>
            </svg>
            
          `; 
        ]]]

And ui-lovelace.yaml

          - type: custom:button-card
            entity: light.yeelight_ceiling10_0x7654218
            name: Belysning
            template:
              - loader
              - base
              - icon_pendant
1 Like

I dont know where light-outside is set, it could be custom from @Quinnod34 or something that was removed by @Mattias_Persson between now and when that code was written. in short I just fixed it by setting the fill to the same value that I have set as the fill on other icons.

before fixing mine looked like yours after the fix it looks like so (this is an RGB light and set to orange)
Screen Shot 2023-01-11 at 9.30.12 pm

  icon_pendant:
    styles:
      custom_fields:
        icon:
          - width: 100%
          - margin-left: -9%
          - margin-top: -9%
    custom_fields:
      icon: >
        [[[
          let state = variables.state_on && variables.timeout < 2000 ? 'on' : null;
          return `
            <svg stroke-miterlimit="10" style="fill-rule:nonzero;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" xmlns:vectornator="http://vectornator.io" xmlns:xlink="http://www.w3.org/1999/xlink">
              <defs><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="178.015" id="Filter" width="15.7685" x="244.46" y="22.1442"><feDropShadow dx="0" dy="0" flood-color="#000" flood-opacity=".797297" in="SourceGraphic" result="Shadow" stdDeviation=".680957"/></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="74.3896" id="Filter_2" width="49.2588" x="228.474" y="164.53"><feDropShadow dx="0" dy="0" flood-color="#000" flood-opacity=".333" in="SourceGraphic" result="Shadow" stdDeviation=".775166"/></filter><filter color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse" height="185.846" id="Filter_3" width="342.386" x="79.1407" y="201.683"><feDropShadow dx="0" dy="0" flood-color="#000" flood-opacity=".333" in="SourceGraphic" result="Shadow" stdDeviation=".387597"/></filter></defs><g  id="Layer-1" vectornator:layerName="Layer 1">
              <path class="${state}" d="M252.33 30.0149 252.357 192.288" fill="blue" fill-rule="evenodd" filter="url(#Filter)" stroke="#a0a0a0" stroke-linecap="butt" stroke-linejoin="miter" stroke-width="13.0176" vectornator:shadowAngle="-.656674" vectornator:shadowColor="#000000" vectornator:shadowOffset="0" vectornator:shadowOpacity=".797297" vectornator:shadowRadius="1.36191"/>
              <path class="${state}" d="M238.28 166.081H267.926C272.486 166.081 276.182 169.886 276.182 174.581V228.869C276.182 233.564 272.486 237.369 267.926 237.369H238.28C233.72 237.369 230.024 233.564 230.024 228.869V174.581C230.024 169.886 233.72 166.081 238.28 166.081z" fill="#9da0a2" fill-rule="evenodd" filter="url(#Filter_2)" stroke="none" vectornator:shadowAngle="1.5708" vectornator:shadowColor="#000000" vectornator:shadowOffset="0" vectornator:shadowOpacity=".333" vectornator:shadowRadius="1.55033"/>
              <path class="${state}" d="M79.9394 336.998C78.8314 299.922 117.197 257.306 137.523 241.656 168.633 217.703 202.906 202.458 249.98 202.458 297.053 202.458 338.512 219.467 369.361 243.775 400.209 268.084 420.752 302.038 420.752 336.83 420.752 382.245 405.423 385.678 366.584 386.494 341.306 387.025 298.558 386.577 251.484 386.577 204.411 386.577 171.104 386.31 135.623 385.764 96.7806 385.167 81.331 383.565 79.9394 336.998z" fill="#9da0a2" fill-rule="evenodd" filter="url(#Filter_3)" stroke="none" vectornator:shadowAngle="1.5708" vectornator:shadowColor="#000000" vectornator:shadowOffset="0" vectornator:shadowOpacity=".333" vectornator:shadowRadius=".775194"/>
              <path class="${state}" fill="var(--light-color)" d="M210.899 409.227C212.783 397.014 216.042 397.813 226.03 397.757 235.634 397.704 245.046 397.781 256.452 397.685 267.382 397.594 270.76 397.868 281.548 398.215 290.703 398.51 295.585 397.897 297.041 408.195 298.497 418.493 295.761 440.415 282.097 449.059 268.434 457.704 234.111 456.602 222.094 445.669 210.076 434.737 209.367 419.164 210.899 409.227z" fill="#ffdc00" fill-rule="evenodd" opacity="1" stroke="none"/>
              </g>
              
              <style>
                @keyframes on {
                  0% {
                    color: #26abff
                    background-color: '#26abff';
                  }
                  23% {
                    transform: rotateZ(-10deg);
                    animation-timing-function: ease-in-out;
                  }
                  56% {
                    transform: rotateZ(10deg);
                    animation-timing-function: ease-in-out;
                  }
                  70% {
                    transform: rotateZ(-2deg);
                    animation-timing-function: ease-in-out;
                  }
                  85% {
                    transform: rotateZ(2deg);
                    animation-timing-function: ease-in-out;
                  }
                  100% {
                    transform: rotateZ(0deg);
                  }
                }
                .on {
                  animation: on 1.7s;
                  transform-origin: top;
                  background-color: '#26abff';
                  animation-fill-mode: forwards;
                  animation-delay: -0.1s;
                }
                
              </style>
            </svg>
            
          `; 
        ]]]

the variables for light-color is set in button_card_templates/extra_styles.yaml

gold star on the question lots of details and all the info that I needed to help

4 Likes

That did the trick, thank you!

1 Like

How can i add lightning-bolt icon for when charger on for person.

Any ideas or help ?

icon

Code block:

custom_fields:
  circle: |
    [[[
      let battery = states['sensor.orcun_xiaomi_battery_level'];
      if (entity && battery) {
        let stroke = variables.state === 'home' ? '#b2b2b2' : 'none',
        fill = variables.state !== 'home' ? 'rgba(255,255,255,0.04)' : 'none';
        let sarj = states['binary_sensor.orcun_xiaomi_is_charging'].state;
        if (sarj === "on") {
          return `
            <svg viewBox="0 0 50 50">
              <circle cx="25" cy="25" r="20.5" stroke="${stroke}" stroke-width="1.5" fill="${fill}" />
              <text x="50%" y="54%" fill="#ff0000" font-size="14" text-anchor="middle" alignment-baseline="middle" dominant-baseline="middle">${battery.state}</tspan></text>
            </svg>
          `;
        } else {
          return `
            <svg viewBox="0 0 50 50">
              <circle cx="25" cy="25" r="20.5" stroke="${stroke}" stroke-width="1.5" fill="${fill}" />
              <text x="50%" y="54%" fill="#8d8e90" font-size="14" text-anchor="middle" alignment-baseline="middle" dominant-baseline="middle">${battery.state}<tspan font-size="10">%</tspan></text>
            </svg>
          `;
1 Like

hi @orcunkutlu

I think this might be what you are after.

<ha-icon icon="mdi:flash"></ha-icon> 
1 Like

Hi mason,

It’s not work in svg tag.
Maybe its working but its not visible.

My modified code just changing fill color #8d8e90 to #ff0000 when charger on.

this should show a lightning-bolt in place of the circle when binary_sensor.orcun_xiaomi_is_charging is on

custom_fields:
  circle: |
    [[[
      let battery = states['sensor.orcun_xiaomi_battery_level'];
      if (entity && battery) {
        let stroke = variables.state === 'home' ? '#b2b2b2' : 'none',
        fill = variables.state !== 'home' ? 'rgba(255,255,255,0.04)' : 'none';
        let sarj = states['binary_sensor.orcun_xiaomi_is_charging'].state;
        if (sarj === "on") {
          return `
           <ha-icon icon="mdi:flash"></ha-icon>
          `;
        } else {
          return `
            <svg viewBox="0 0 50 50">
              <circle cx="25" cy="25" r="20.5" stroke="${stroke}" stroke-width="1.5" fill="${fill}" />
              <text x="50%" y="54%" fill="#8d8e90" font-size="14" text-anchor="middle" alignment-baseline="middle" dominant-baseline="middle">${battery.state}<tspan font-size="10">%</tspan></text>
            </svg>
          `;

if you would like the icon inside of the circle, you could use this guid, to get the path for the flash icon then use that in the SVG path along with the circle

1 Like

I made a progress bar, but haven’t done much testing with it. It’s set up specifically for plex, other players might have different attribute names for media_position, media_duration and media_position_updated_at. Also, I’m not sure how other players report position, but with plex media_position is only updated when media is paused or started. If that’s not the case with other players, then the paused state (mediaPosition / mediaDuration * 100) would be fine for the playing state.

EDIT: V2 - the original version of this would fail when 2 players were active. Whichever player wasn’t displayed on browser refresh would fail to update the progress bar. This version fixes that.

EDIT V3 - moved to a separate template to leave media.yaml untouched. Code moved to gist

5 Likes

okay thank you, i will test it, can you give your variable “var(–progress-width);” i think its missing or ?

That’s defined in the javascript. This section of the js specifically

let mediaPositionUpdatedAt = entity.attributes.media_position_updated_at;
let mediaPosition = entity.attributes.media_position;
let mediaDuration = entity.attributes.media_duration;
let percentage = entity.state === 'playing'
  ? (((Date.now() / 1000) - (new Date(mediaPositionUpdatedAt).getTime() / 1000) + mediaPosition) / mediaDuration * 100)
  : entity.state === 'paused'
    ? (mediaPosition / mediaDuration * 100)
    : 0;
document.documentElement.style.setProperty('--progress-width', percentage.toFixed(1) + '%');

okay i tested your code, in my browser the progressbar ist not width enough and not aligned left, and on my phone its the same behaviour, but a little bit different.

that’s crazy i liked your code because it’s very slim and is only defined once, but with this code you can set the margin for each device yourself, that’s how i got success, not nice but i can access my devices ( tablet, iphone, browser) react and define individual margins

/* * * * * * * * * * * * * * * * * *
                             *                                 *
                             *              Tablet             *
                             *  #1920 x 1200 Pixel = Tablet    *
                             * * * * * * * * * * * * * * * * * */
                            @media screen and (max-device-height: 1200px) and (max-device-width: 1920px){
                           
                              #container {
                                text-align: left !important;
                              }
                              
                              #progress {
                                position: absolute;
                                width: 110%;
                                margin: -12% -4% 0 0;
                                display: initial;
                                opacity: 1;
                                justify-self: end;
                              }
                              
                              #name, #state {
                                font-size: 1.32vw;
                                letter-spacing: -0.02vw;
                             
                              }
                              
                              #state::first-letter {
                                text-transform: uppercase;
                              }
                            }
                            /* * * * * * * * * * * * * * * * * *
                             *                                 *
                             *              BROWSER            *
                             *  #1920 x 1080 Pixel = Laptop    *
                             * * * * * * * * * * * * * * * * * */
                            @media screen and (device-height: 1080px) and (device-width: 1920px){
                           
                              #container {
                                text-align: left !important;
                              }
                              
                              #progress {
                                position: absolute;
                                width: 110%;
                                margin: -9.5% -4% 0 0;
                                display: initial;
                                opacity: 1;
                                justify-self: end;
                              }
                              
                              #name, #state {
                                font-size: 1.32vw;
                                letter-spacing: -0.02vw;
                             
                              }
                              
                              #state::first-letter {
                                text-transform: uppercase;
                              }
                            }
                            #2532 x 1170 Pixel = Iphone
                            #1920 x 1200 Pixel = Tablet
                            #1920 x 1080 Pixel = Laptop
                            /* * * * * * * * * * * * * * * * * *
                             *                                 *
                             *              portrait           *
                             *                                 *
                             * * * * * * * * * * * * * * * * * */
                            /* portrait */ 
                            @media screen and (max-height: 1200px) {
                              #name, #state {
                                font-size: 2vw;
                              }
                              #progress {
                                font-size: 2vw;
                                margin: -13% 0 0 5%;
                                position: absolute;
                                width: 108%;
                                display: initial;
                                opacity: 1;
                                justify-self: end;
                              }
                              
                            }
                            /* * * * * * * * * * * * * * * * * *
                             *                                 *
                             *              IPHONE             *
                             *                                 *
                             * * * * * * * * * * * * * * * * * */
                            /* phone */
                            @media screen and (max-width: 800px) {
                              #name, #state {
                                font-size: 3vw;
                              }
                              #progress {
                                font-size: 2vw;
                                margin: -13% -10% 0 0;
                                position: absolute;
                                width: 120%!important;
                                display: initial;
                                opacity: 1;
                                justify-self: end;
                              }
                            }
                            
                            /* tilt */
                            #ripple, .js-tilt-glare {
                              clip-path: inset(0 round var(--custom-button-card-border-radius));
                              overflow: hidden;
                            }
                            .js-tilt-glare {
                              z-index: 1;
                            }
                            .js-tilt-glare-inner {
                              background-color: rgba(0,0,0,0.9);
                            }
                            #container {
                              transform: translateZ(${variables.tilt_options.parallax});
                            }
                            #card {
                              transform-style: preserve-3d;
                              overflow: visible;
                            }

It sounds like you might need a hard refresh in your browser, or maybe you have conflicting styles for #progress.

It will always be the same at any size
image

you are right, i had a old styles in my button_card_templates. now its align perfect.

But i had no progress bar? have you a idea why?

Unbenannt1