A different take on designing a Lovelace UI

This is my code.
Widget Calendar
i use a date sensor

          - type: custom:button-card
            entity: calendar.lavoro
            template: 
              - base
              - widget_calendar

button_card_template.yaml
  widget_calendar:
    aspect_ratio: 1/1
    show_icon: false
    show_name: false
    show_state: false
    show_label: false
    tap_action:
      action: more-info  
    styles:
      grid:
        - grid-template-areas: |     
            "giorno"
            "numero"
            "testo"
            "eventi"
        - grid-template-columns: 1fr
        - grid-template-rows: min-content min-content min-content 1fr
        - gap: 0%
        - overflow: hidden
      card:
        - color: >
            [[[
              if (states['sun.sun'].state == 'below_horizon'){
                return 'rgba(0, 0, 0, 0.6)';
              } else
                return 'rgba(255, 255, 255, 0.8)';
            ]]]         
        - background-color: >
            [[[
              if (states['sun.sun'].state == 'below_horizon'){
                return '#1c1c1e';
              } else
                return 'rgba(255, 255, 255, 0.8)';
            ]]]          
      custom_fields:
        giorno:
          - place-self: start
          - color: '#ff3b2f'
          - text-transform: uppercase 
          - font-weight: 500
        numero:
          - place-self: start
          - color: >
              [[[
                if (states['sun.sun'].state == 'below_horizon'){
                  return 'rgba(255, 255, 255, 0.8)';
                } else
                  return 'rgba(0, 0, 0, 0.6)';
              ]]]             
          - font-weight: 500
          - margin-top: -10px
        testo:
          - place-self: start
          - text-transform: uppercase 
          - color: '#8e8e90'         
        eventi:
          - place-self: start
          - border-left: 3px blue solid
          - padding-left: 3px                         
          - color: >          
              [[[
                if (states['sun.sun'].state == 'below_horizon'){
                  return 'rgba(255, 255, 255, 0.8)';
                } else
                  return 'rgba(0, 0, 0, 0.6)';
              ]]]           
    custom_fields:
      giorno: >
        [[[ return `${states['sensor.pretty_date'].attributes.week_day}` ]]]
      numero: >
        [[[ return `${states['sensor.pretty_date'].attributes.day}` ]]]
      testo: >
        [[[
          if (states['sun.sun'].state == 'below_horizon'){
            return "Domani";
          } else
            return " ";
        ]]]        
      eventi: '[[[ return entity.attributes.message ]]]'  
    extra_styles: |
      [[[
        return `
          #giorno {
            font-size: 1.3vw;
          }           
          #numero {
            font-size: 4.5vw;
          }     
          #testo {
            font-size: 1.1vw;
          }   
          #eventi {
            font-size: 1vw;
          }                              
          /* portrait */
          @media screen and (max-width: 1200px) {
            #numero {
              font-size: 4.5vw;
            }
            #giorno {
              font-size: 1.3vw;
            }      
            #testo {
              font-size: 1.1vw;
            }   
            #eventi {
              font-size: 1.1vw;
            }               
          }
          /* phone */
          @media screen and (max-width: 800px) {
            #giorno {
              font-size: 3.5vw;
            }              
            #numero {
              font-size: 12vw;
            }    
            #testo {
              font-size: 3vw;
            }   
            #eventi {
              font-size: 2.8vw;
            }    
          }
        `
      ]]]           

Widget Weather
I use a sensor for min and max temperatures
I use this icon animated.

              - type: custom:button-card
                entity: weather.openweathermap
                name: Campobasso
                template:
                  - base 
                  - widget_weather
                variables:
                  temp_min: sensor.min_temperatura
                  temp_max: sensor.max_temperatura

button_card_template.yaml
  widget_weather:
    variables:
      temp_min: ''
      temp_max: ''
    aspect_ratio: 1/1
    show_icon: false
    show_entity_picture: true
    show_name: true
    show_state: true
    show_label: true 
    tap_action:
      action: more-info      
    styles:
      grid:
        - grid-template-areas: |
            "n"        
            "temp"
            "i"
            "s"
            "l"
        - grid-template-columns: 1fr
        - grid-template-rows: min-content repeat(2, 1fr) repeat(2, min-content)
        - gap: 0%
      card:
        - color: rgba(255, 255, 255, 0.8)        
        - background: >
            [[[
              if (states['sun.sun'].state == 'below_horizon'){
                return 'linear-gradient(to top, rgba(53,59,83,1) 0%, rgba(10,14,34,1) 100%)';
              } else
                return 'linear-gradient(to top, rgba(123,168,197,1) 0%, rgba(61,132,176,1) 100%)';
            ]]]                        
      name:
        - place-self: start
        - text-transform: uppercase 
        - font-weight: 500   
      img_cell:
        - justify-content: start
      icon:
        - width: 20%
      label:
        - place-self: start
        - margin-left: -5px
      custom_fields:
        temp:
          - place-self: start
          - margin-top: -10px
    label: >   
      [[[
        return `<ha-icon
          icon="mdi:arrow-up-thin"
          style="width: 20px; height: 20px; margin-right: -5px;">
          </ha-icon><span>: ${states[variables.temp_max].state}°</span>
                <ha-icon
          icon="mdi:arrow-down-thin"
          style="width: 20px; height: 20px; margin-right: -5px;">
          </ha-icon><span>: ${states[variables.temp_min].state}°</span>          
        `
      ]]]
    custom_fields:
      temp: >
        [[[ return entity.attributes.temperature + "°"; ]]]     
    entity_picture: >
      [[[
        if ((entity.state == 'sunny') && (states['sun.sun'].state == 'above_horizon'))
          return "/local/weather/clear-day.svg";
          if ((entity.state == 'sunny') || (entity.state == 'clear-night') && (states['sun.sun'].state == 'below_horizon'))
            return "/local/weather/clear-night.svg";   
              if (entity.state == 'fog')
                return "/local/weather/fog.svg";     
                  if ((entity.state == 'partlycloudy') && (states['sun.sun'].state == 'above_horizon'))
                    return "/local/weather/partly-cloudy-day.svg";                      
                      if ((entity.state == 'partlycloudy') && (states['sun.sun'].state == 'below_horizon'))
                        return "/local/weather/partly-cloudy-night.svg";    
                          if (entity.state == 'rainy')
                            return "/local/weather/rain.svg";                  
                              if (entity.state == 'sleet')
                                return "/local/weather/sleet.svg";         
                                  if (entity.state == 'snow')
                                    return "/local/weather/snow.svg";  
                                      if (entity.state == 'cloudy')
                                        return "/local/weather/cloudy.svg";    
        else (entity.state == 'wind')
          return "/local/weather/wind.svg";                        
      ]]]
    extra_styles: |
      [[[
        return `
          #name {
            font-size: 1.3vw;
          }
          #temp {
            font-size: 4.5vw;
          }
          #state {
            font-size: 1.1vw;
          }  
          #label {
            font-size: 1.1vw;
          }                    
          /* portrait */
          @media screen and (max-width: 1200px) {
            #name {
              font-size: 1.3vw;
            }
            #temp {
              font-size: 4.5vw;
            }
            #state {
              font-size: 1.1vw;
            }  
            #label {
              font-size: 1.1vw;
            }  
          }
          /* phone */
          @media screen and (max-width: 800px) {
            #name {
              font-size: 3.5vw;
            }              
            #temp {
              font-size: 12vw;
            }    
            #state {
              font-size: 3.5vw;
            }   
            #label {
              font-size: 3.5vw;
            }                        
          }
          @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);
            }
          }
        `
      ]]]

Widget Battery

          - type: custom:button-card
            template: 
              - base
              - widget_phone
            variables:
              entity_phone: sensor.ipex_battery_level
              entity_picture_iphone: /local/apple/i12.png
              entity_watch: sensor.apple_watch_di_giuseppe_battery_state
              entity_picture_watch: /local/apple/watch.png
              entity_ipad: sensor.icompare_battery_level
              entity_picture_ipad: /local/apple/ipad.png
              entity_other: sensor.ipex6s_battery_level
              entity_picture_other: /local/apple/6s.png

button_card_template.yaml
  widget_custom_fields:
    show_icon: false
    show_state: false
    show_name: false
    show_entity_picture: true
    tap_action:
      action: none  
    styles:
      # icon:
      #   - height: 50%      
      custom_fields:
        circle:
          - top: 0%
          - left: 25%
          - width: 50%
          - position: absolute   
    custom_fields:                 
      circle: >
        [[[                       
          if (entity.state >= 20) { 
            let input = entity.state,
              radius = 20.5,
              color = 'green',
              circumference = radius * 2 * Math.PI,
              dasharray = circumference,
              dashoffset = circumference - input / 100 * circumference;
            return `
              <svg viewBox="0 0 50 50">
                <circle cx="25" cy="25" r="${radius}" stroke="gray" stroke-opacity="50%" stroke-width="4.5" fill="none" />
                  <circle cx="25" cy="25" r="${radius}" stroke="${color}" stroke-dashoffset="${dashoffset}" stroke-dasharray="${dasharray}" stroke-linecap="round" stroke-width="4.5" fill="none" style="transform: rotate(-90deg); transform-origin: 50% 50%;" />
              </svg>
            `;                    
          } else {   
            let input = entity.state,
              radius = 20.5,
              color = 'red',
              circumference = radius * 2 * Math.PI,
              dasharray = circumference,
              dashoffset = circumference - input / 100 * circumference;
            return `
              <svg viewBox="0 0 50 50">
                <circle cx="25" cy="25" r="${radius}" stroke="gray" stroke-opacity="50%" stroke-width="4.5" fill="none" />
                  <circle cx="25" cy="25" r="${radius}" stroke="${color}" stroke-dashoffset="${dashoffset}" stroke-dasharray="${dasharray}" stroke-linecap="round" stroke-width="4.5" fill="none" fill-opacity="0.3" style="transform: rotate(-90deg); transform-origin: 50% 50%;" />
              </svg>
            `;
          } 
        ]]]        

  widget_phone:
    variables:
      entity_phone: ''
      entity_picture_iphone: ''
      entity_watch: ''
      entity_picture_watch: ''
      entity_ipad: ''
      entity_picture_ipad: ''
      entity_other: ''
      entity_picture_other: ''
    aspect_ratio: 1/1
    show_icon: false
    show_name: false
    show_state: false
    show_label: false  
    styles:
      grid:
        - grid-template-areas: |     
            "phone watch"
            "ipad other"
        - grid-template-columns: repeat(2, 1fr)
        - grid-template-rows: repeat(2, 1fr)
        - gap: 0%
      card:
        - padding: 5%
        - color: >
            [[[
              if (states['sun.sun'].state == 'below_horizon'){
                return 'rgba(0, 0, 0, 0.6)';
              } else
                return 'rgba(255, 255, 255, 0.3)';
            ]]]         
      custom_fields:
        phone:
          - align-self: start
          - justify-self: center
          - width: 200%    
        watch:
          - align-self: start
          - justify-self: center
          - width: 200%           
        ipad:
          - align-self: end
          - justify-self: center
          - width: 200%     
        other:
          - align-self: end
          - justify-self: center
          - width: 200%                 
    custom_fields:
      phone: 
        card:  
          type: custom:button-card
          entity: '[[[ return variables.entity_phone ]]]'
          template: widget_custom_fields
          icon: phu:apple-iphone
          entity_picture: '[[[ return variables.entity_picture_iphone ]]]'
      watch: 
        card:  
          type: custom:button-card
          entity: '[[[ return variables.entity_watch ]]]' 
          template: widget_custom_fields
          icon: phu:apple-ipad-pro  
          entity_picture: '[[[ return variables.entity_picture_watch ]]]'             
      ipad: 
        card:  
          type: custom:button-card
          entity: '[[[ return variables.entity_ipad ]]]' 
          template: widget_custom_fields
          icon: phu:apple-ipad-pro  
          entity_picture: '[[[ return variables.entity_picture_ipad ]]]'         
      other: 
        card:  
          type: custom:button-card
          entity: '[[[ return variables.entity_other ]]]'
          template: widget_custom_fields
          icon: phu:apple-iphone 
          entity_picture: '[[[ return variables.entity_picture_other ]]]'  
7 Likes