A different take on designing a Lovelace UI

Yes, I started over again last month based on the last update of mattias. Suggest/advise you to do the same, since a lot changed (and became much better)

I tried to change to verticla-stack as matt did. But something wierd is happening.
The sidebar has no styles, the buttons appear not on the bottom and the cards from “wohnzimmer” are gone.


ui-lovelace.yaml

      - type: vertical-stack
        view_layout:
          grid-area: sidebar
        cards:
          - type: custom:button-card
            entity: sensor.template_sidebar
            template: sidebar_template
          - type: grid
            cards:
              - type: button
                icon: mdi:lightning-bolt
                tap_action: !include popup/sidebar_batterie.yaml
                hold_action:
                  action: none

              - type: button
                icon: mdi:information-outline
                tap_action: !include popup/sidebar_information.yaml
                hold_action:
                  action: none

              - type: button
                icon: mdi:arrow-up-bold-circle-outline
                tap_action: !include popup/sidebar_update.yaml
                hold_action:
                  action: none

template.yaml

template:
  ####################################################
  #                                                  #
  #                     TEMPLATE                     #
  #                                                  #
  ####################################################

  sensor:
    - unique_id: sidebar
      state: template
      attributes:
        time: >
          {% set hours = now().strftime('%H') %}
          {% set minutes = now().strftime('%M') %}
          <span class="time">
            {{ hours }}<span class="time-colon">:</span>{{ minutes }}
          </span>
        date: |
          <font color='#6a7377'><b>
          {%- if strptime(states('sensor.date'), '%Y-%m-%d').day != null %}
          {%- set days = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag'] %}
          {%- set months = ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 
          'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'] %}
            {{- days[now().weekday()] }}<br>
            {{- strptime(states('sensor.date'), '%Y-%m-%d').day }} {{ months[now().month-1] }}
          {%- endif -%}
          </b></font>
        greet: |
          <b>
          {% set time = now().hour %}
          {% if time <= 1 %} Gute Nacht {{'\U0001F611'}}
          {% elif time <= 3 %} Gute Nacht {{'\U0001F62A'}}
          {% elif time <= 5 %} Gute Nacht {{'\U0001F634'}}
          {% elif time <= 7 %} Guten Morgen {{'\U0001F4A9'}}
          {% elif time <= 9 %} Guten Morgen {{'\u2615\uFE0F'}}
          {% elif time <= 10 %} Guten Morgen {{'\U0001F642'}}
          {% elif time <= 13 %} Guten Tag {{'\U0001F60A'}}
          {% elif time <= 15 %} Guten Tag {{'\U0001F60E'}}
          {% elif time <= 17 %} Guten Tag {{'\U0001F44B\U0001F3FB'}}
          {% elif time <= 19 %} Guten Abend {{'\U0001F44B\U0001F3FB'}}
          {% elif time <= 22 %} Guten Abend {{'\U0001F60C'}}
          {% elif time <= 23 %} Guten Abend {{'\U0001F974'}}
          {% else %} Guten Abend {{'\U0001F974'}}
          {% endif %}
          </b>
        active: |
          <b>
          {% set lights = [
            states.light.wohnzimmer_licht, 
            states.light.kueche_licht, 
            states.light.kueche_licht_speis, 
            states.light.kueche_licht_spuele,
            states.light.schlafzimmer_licht, 
            states.light.wohnzimmer_licht_tv, 
            states.switch.garage_licht
          ] %}

          {% set switches = [
            states.switch.werkstatt_makitaladegeraet, 
            states.switch.kueche_licht, 
            states.media_player.wohnzimmer_tv
          ] %}

          {% set lights_on = lights | selectattr('state','eq','on') | list %}
          {% set lights_name = lights | selectattr('state','eq','on') | map(attribute='name') | join(', ') %}

          {% set switches_on = switches | selectattr('state','eq','on') | list %} 
          {% set switches_name = switches | selectattr('state','eq','on') | map(attribute='name') | join(', ') %}

          {% if (lights_on | length == 0) and (switches_on | length > 0) %} 
          {{ switches_name | regex_replace(',([^,]*)

button-card-templates.yaml

sidebar_template:
  show_state: false
  show_icon: false
  tap_action:
    action: none
  name: |
    [[[
      if (entity) {
        let attributes = '';
        for (const [key, value] of Object.entries(entity.attributes)) {
          value != false ? attributes += `<p>${value}</p>` : null;
        }
        return attributes;
      }
    ]]]
  extra_styles: |
    #card {
      padding: 0;
    }
    #container {
      display: flex !important;
    }
    #name {
      padding: 1.8vw 2.5vw 0 var(--custom-layout-card-padding);
      white-space: normal;
      text-align: left;
    }
    .time {
      font-family: SF Text;
      font-size: var(--sidebar-time-font-size);
      font-weight: 200;
      line-height: var(--sidebar-time-line-height);
      letter-spacing: -0.05vw;
      margin-left: -0.3vw;
      color: rgba(255, 255, 255, 0.8);
    }
    .time-colon {
      position: relative;
      top: -.09em;
    }
    p {
      font-family: SF Display;
      font-size: var(--sidebar-font-size);
      line-height: var(--sidebar-line-height);
      font-weight: 300;
      letter-spacing: 0.06vw;
      color: #6a7377;
    }

    p > b {
      color: rgba(255, 255, 255, 0.8);
    }
    /* portrait */
    @media screen and (max-width: 1200px) {
      .time {
        font-size: calc(var(--sidebar-time-font-size) * 1.4 );
        line-height: calc(var(--sidebar-time-line-height) * 1.4 );
      }
      p {
        font-size: calc(var(--sidebar-font-size) * 1.4 );
        line-height: calc(var(--sidebar-line-height) * 1.4 );
      }
    }
    /* phone */
    @media screen and (max-width: 800px) {
      .time {
        font-size: calc(var(--sidebar-time-font-size) * 2.6 );
      }
      p {
        font-size: calc(var(--sidebar-font-size) * 2.6 );
        line-height: calc(var(--sidebar-line-height) * 2.6 );
        letter-spacing: 0.16vw;
      }
      #name {
        padding: 0 0 0 1vw;
      }
    }

In ui-lovelace.yaml somewhere between line 3 and 45 the theme describes the grid layout it uses for several screen sizes
You should change the grid-template-columns, grid-template-rows and grid-template-areas to accommodate your situation.

1 Like

I have tried a few things here as well, but can’t seem to find the correct configuration that we need
@Mattias_Persson could you maybe shine some light on this?

@JacobPantuso @Tismo
There is no one size fits all for this dashboard, Mattais pretty much provides his config, which is made of a framework (the themes.yaml an the button-card-templates.yaml) and an example for the ui-lovelace.yaml as well as all accompanying sensors/templates you could use.

But it’s up to you to make this fitting for your situation.
There is no video to set this up because there is no one size fits all approach, you don’t have the same sensors, same devices, same needs as I would have.
And even if that were the case you would still need to change/edit/fix a lot of things so it would be better to just try and work from the provided code, understand the code, and be able to actually make the necessary changes yourself and contribute to the project.

So as for global steps… There are multiple ways to go about it but the way that worked for me was:

  • Backup my complete Home Assisstant setup, everything as a snapshot but also config backups
  • Then you have two options:
    • Start fresh (throw everything you have away and start with Mattias’ setup)
    • Edit your own config to incorporate all of Mattias’ edits
  • Change your used theme to the “tablet” theme (thats the name of the theme)
  • Check all the errors you get in lovelace and start fixing them one by one, but most importantly: Try to understand the code structure

The code structure:

  • themes.yaml (the tablet theme) pretty much contains all the general CSS code, in other words: how thing look, which colors they have, the font used, the sizes and so on
  • button-card-templates.yaml contains the sidebar and the buttons that are used on the dashboard, as the name implies these are templates, as such they describe how a button is layed out, how the buttons look, how they react, but importantly: they do not contain (in most cases) the sensors themselves
  • lovelace-ui.yaml contains the sensors and layout of the dahboard

So if we look at lovelace-ui.yaml it shows a button for a lamp, this button uses a template from the button-card-templates which contains the information on which icon is used, what the text is etc, and the themes.yaml contains information on the style of this button, which color it is, which font etc

@Se7enair
Did you replace the themes.yaml with the updated version?

Also your mini graphs are “floating” in the buttons, might want to check my setup
ui-lovelace.yaml

              - type: custom:button-card
                entity: sensor.lumi_lumi_weather_temperature
                name: Temperatuur
                custom_fields:
                  graph:
                    card:
                      entities:
                        - sensor.lumi_lumi_weather_temperature
                template:
                  - temperature
                  - icon_temp

button-card-templates:

temperature:
  template:
    - base
  show_state: false
  custom_fields:
    circle: >
      [[[ {
      const temperature = Math.round(entity.state);
      return `<svg viewBox="0 0 50 50"><circle cx="25" cy="25" r="20.5" stroke="#313638" stroke-width="1.5" fill="#FFFFFF08" style="
      transform: rotate(-90deg); transform-origin: 50% 50%;" />
      <text x="50%" y="54%" fill="#8d8e90" font-size="14" text-anchor="middle" alignment-baseline="middle" dominant-baseline="middle" dominant-baseline="middle">${temperature}°</text></svg>`; } ]]]
    graph:
      card:
        type: "custom:mini-graph-card"
        line_color: "#3182b7"
        line_width: 4
        font_size: 75
        show:
          name: false
          icon: false
          state: false
          legend: false
          labels: false
  styles:
    name: [top: 57%, left: 0%, width: 100%, position: absolute]
    custom_fields:
      graph: [bottom: 0%, left: 0%, width: 100%, position: absolute]
      circle:
        - display: initial
        - width: 90%
        - letter-spacing: 0.03vw
        - margin: -6% -6% 0 0
        - justify-self: end
        - opacity: 1
      icon:
        - width: 67%
        - fill: "#9da0a2"
5 Likes

Forgot to reload themes :shushing_face: :confounded:
It working now

I adopt your code for the mini-graph. Is looking better when on mobile!

The last thing now is the window which is not correct resizing when on another device. Will looking for a nicer icon.
Somebody know a nice icon for windows?

hi there, i successfully implemented matt’s beauty of Dashboard :smiley:

i decided to implement some custom:swipe-card’s for single buttons. Somehow im running into problems on mobile. If i open the App for the first time the sizing is not working (pic 2). After switching to another Dashboard and going back it looks like it should.(pic 1) :confused:

Also i am trying to change the icon of one of the bottom sidebar buttons depending on the state (if automation is on or off). I copied the change color for update from theme and could change the color but i cant get the icon to change. Any ideas?

Thanks in advance !
Greetings

Hy Mathias
I started to develop my lovelace with a menu in the sidebar.
I have a yam file for each lovelace panel and one sidebar.yaml file for the menu which is called by each file.
Now, I would like to change the item menu style according to the current dashboard. Do you have any idea for a condition on the current lovelace ? Or maybe my way is not the best and I need to change the grid and have a conditional card like you mentioned it ?
Thanks for your help

Could anybody tell me, where i can specify “state_color: true” if im using mdi:icons?

hi @Mattias_Persson So that the weather card takes up more space in height. Do I have to put together a grid and customize it?
Thanks

The weather card is not designed with a square layout in mind. Can you conceptualize how you would fill that space without stretching the card?

You could make your own with button card [example]
or add the weather card to the sidebar

Use the icon: config variable instead (not custom field). if you must use <ha-icon> you can add a css variable

custom_fields:
  icon: |
    <ha-icon icon="hue:play-bar" style="color:var(--button-card-light-color);"></ha-icon>
1 Like

You can use this template by @Mariusthvdb for current view as a condition in sidebar yaml

[[[ return window.location.pathname.split('lovelace/')[1]; ]]]
1 Like

I don’t know about the first one but changing icons in type: button is potentially bugged

1 Like

I’m using this layout

swipe-card
→ horizontal-stack → conditional
→ grid

some people tried (which I didn’t test)

swipe-card
→ grid
→ grid

which cut off the bottom part and the reason I added height: 100%

working example

      - type: grid
        title: Media
        view_layout:
          grid-area: media
        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: media_player.vardagsrum
                    name: Vardagsrum
                    template:
                      - media
                      - icon_apple_tv

                  - type: custom:button-card
                    name: Sovrum
                    entity: media_player.sovrum
                    template:
                      - media
                      - icon_apple_tv

                  - type: custom:button-card
                    entity: media_player.spotify
                    name: Spotify
                    template:
                      - media
                      - icon_spotify

                  - type: custom:button-card
                    entity: media_player.kok
                    name: Nest Mini
                    template:
                      - media
                      - icon_nest_mini

              - type: grid
                columns: 2
                cards:

                  - type: custom:button-card
                    entity: media_player.vardagsrum
                    name: Vardagsrum
                    template:
                      - media
                      - icon_apple_tv

                  - type: custom:button-card
                    name: Sovrum
                    entity: media_player.sovrum
                    template:
                      - media
                      - icon_apple_tv

                  - type: custom:button-card
                    entity: media_player.spotify
                    name: Spotify
                    template:
                      - media
                      - icon_spotify

                  - type: custom:button-card
                    entity: media_player.kok
                    name: Nest Mini
                    template:
                      - media
                      - icon_nest_mini
1 Like

Do you have this line? extra_styles fix

There’s this basic guide at least. You’re welcome to make a video :wink:

Have you tried putting custom:thermostat-dark-card by itself and not inside custom:button-card?

I bet my templates are messing with your bottom right icons. Can you post how you’ve set those up?

Yeah, and to add to that I don’t think that markdown is inherently bad but styling it is a nightmare.

The nice thing about button card is that if one doesn’t want to convert all jinja templates to javascript, incorporating existing template sensors works fine too.

1 Like