A different take on designing a Lovelace UI

Hello, does someone have an idea for my problem? I use Mattias’ template for my activity (Harmony Hub). Can anyone help me that only the current activity is triggered and displayed as switched on.

Code:

          - type: custom:button-card
            entity: remote.harmonyhub
            name: Panasonic TV
            style:
              top: 35%
              left: 52.5%
              width: 10%
            action:
              - service: remote.turn_on
                entity_id: remote.harmonyhub
                data:
                   activity: "Fernsehen"
            custom_fields:
              icon_tv: &icon_tv >
                [[[ const state = entity.state === 'on' ? 'animate' : null; 
                const style = '<style>@keyframes animate_on{from{transform: scaleY(0);}to{transform: scaleY(1);}}.animate_on{animation: animate_on 1s; transform-origin: -100% 46%; animation-fill-mode: forwards;}@keyframes animate_off{from{transform: scaleY(1);}to{transform: scaleY(0);}}.animate_off{animation: animate_off 1s; transform-origin: -100% 46%; animation-fill-mode: forwards;}</style>';
                const path = '<path d="M46 9.2v27.5H4.1V9.2H46m2.4-2.4H1.6v32.3h46.7c.1 0 .1-32.3.1-32.3zM11.9 43.2h26.3c.6 0 1.1-.4 1.1-1v-.3c0-.6-.4-1.1-1-1.1H11.9c-.6 0-1.1.4-1.1 1v.3a1.11 1.11 0 0 0 1.1 1.1z"/>';
                const gradient = '<linearGradient id="A" gradientUnits="userSpaceOnUse" x1="5.401" y1="34.714" x2="43.817" y2="11.74"><stop offset="0" stop-color="#64acb7"/><stop offset="1" stop-color="#7fdbe9"/></linearGradient>';
                if (entity.state === 'off'){ return `<svg viewBox="0 0 50 50"> ${style} ${gradient} <path class="animate_off" d="M2.9,8h44.3v29.9H2.9V8z" fill="url(#A)"/> ${path} </svg>`; }
                if (entity.state === 'on'){ return `<svg viewBox="0 0 50 50"> ${style} ${gradient} <path d="M2.9,8h44.3v29.9H2.9V8z" fill="#20262890"/><path class="animate_on" d="M2.9,8h44.3v29.9H2.9V8z" fill="url(#A)"/> ${path} </svg>`; }
                if (entity.state === 'on'){ return `<svg viewBox="0 0 50 50"> ${gradient} <path d="M2.9,8h44.3v29.9H2.9V8z" fill="url(#A)"/> ${path} </svg>`; }
                else if (entity.state==='off') { return `<svg viewBox="0 0 50 50"> ${path} </svg>`; } ]]]
            styles: &icon_tv_styles
              custom_fields:
                icon_tv:
                  [fill: "[[[ return entity.state === 'on' ? '#616161' : '#9da0a2'; ]]]", 
                  top: 11%, left: 4.5%, width: 3.05vw, position: absolute]
            template: base

Currently it shows as soon as I e.g. turn on the TV as well, because it triggers the “entity: remote.harmonyhub” …

Hello :slight_smile:
I am really excited about your configuration.

Unfortunately, I don’t know how to use them. I have already integrated my devices. Unfortunately, I can’t get my Apple TV 4K integrated. And I can’t get the user interface right.

Can you help me through Teamviewer? I would pay for it too.

Best regards

Luas

my fullykiosk browser and wallpanel both are crashing while loading lovelace ui, if i have some buttons it loads fine, is there anyone facing the same problem??

I just start with home assistant 2 weeks ago en last week installed it on a NUC with proxmox.
Busy integrating all my devices of fibaro hc2 (use it as zwave controller)
HACS / node red and things like viewing panel already done, automation come also but my fibaro does the job so no hurry

This design of Lovelace is one word AWESOME!

I must learn a lot but this is a nice goal to jump into the learn curve make this happen for me.
Any advice to start for learning this ? Or just begin with the picture elements card / panel mode and work from there?

Sorry if it’s been mentioned above (700+ posts is a lot to sift through), but has anyone done any work to make @Mattias_Persson work reusable? It’s great, but even as a developer it’s going to take me weeks to sift through this to pull out the relevant bits.

1 Like

Hello,

I am just about to install the template.
I have now noticed that I can not switch the lights via a click.

In the base file it says:

tap_action:
    action: toggle

But it seems to have no function, is it still with someone so? All other functions like hold_action work.

Got it, when i remove the complete

ui_sound

Part… it works!

I don’t disagree… but

Where is the fun in that! …I have truely enjoyed learning many aspects of coding and HTML design from the work @Mattias_Persson has done. Making it more accessible would, in my opinion, would stifle the creativity that this community has developed from his example. He has given a great gift to the community and inspiration to other.

In saying all this, it would be great to reproduce simply with some documentation to help, but @Mattias is always very responsive, as are others in this post.

For everyone having issues with kiosk-mode not working ( race condition ), I’ve created a dirty fix, using setInterval. Here’s the code ( replace the file in /config/www/community/kiosk-mode/kiosk-mode.js ): https://pastebin.com/9CsnvAd6

2 Likes

Thanks, I’ll test it

EDIT: @xyboox seems to be working for me as well, have you talked to maykar about it?

I have been running this UI for a few months now and am happy with it. I have decided to try a 3D view of my home over in the right section which I think will look better with a white background. I’m going to keep the left menu section with a black background. I now need to generate a graphic to replace background.png but with a white look.

When I load background.png 6K in my image editor it is a really small image that has blocky black toned squares. In my browser this background image looks very smooth and not blocky at all. My question is what makes the small blocky image background.png end us nice and smooth in the browser?

(and does anyone have a white themed background.png they can share?)

Thanks!

gradient backgrounds are a problem because with all color variations the image becomes several mb. if you try to compress it you will see obvious artifacts. one solution is to make the image so small that the browser scales the image and as a side effect it loads quickly.

Thanks Mattias. I have Pixelmator Pro installed on my Mac. Do you have any tips on how to create a small image like that with white tones? Am I drawing each individual square myself or is there a tool that can do it?

Take any image and resize it

@Mattias_Persson how do you create a space between cards? trying to figure that out with my own theme.

Hey guys, anyone noticed that lately hass_uptime sensor is always reporting “0 seconds ago”? Or is it just for me?

They are manually positioned.

Remove unit_of_measurement and update template.

1 Like

oh… nice one! Thanks!

Hi! May I know what might be the problem with this one? Thank you in advance!

ui-lovelace.yaml

button_card_templates:
  base:
    aspect_ratio: 1/1
    show_state: true
    show_icon: false
    state:
      - value: 'on'
        styles:
          card: [background-color: 'rgba(255, 255, 255, 0.8)']
          name: [color: 'rgba(0, 0, 0, 0.6)']
          state: [color: 'rgba(0, 0, 0, 0.6)']
    tap_action:
      ui_sound: |
        [[[ if (entity.state === 'off' && states['switch.fullykiosk_screensaver'].state === 'off') {
        hass.callService('media_player', 'play_media', {entity_id: 'media_player.tablet', media_content_id: '/local/sound/on.m4a', media_content_type: 'music'}); }
        else if (entity.state === 'on' && states['switch.fullykiosk_screensaver'].state === 'off') {
        hass.callService('media_player', 'play_media', {entity_id: 'media_player.tablet', media_content_id: '/local/sound/off.m4a', media_content_type: 'music'}); } ]]]
      action: toggle
      haptic: light
    styles:
      name:
        [top: 57.7%, left: 11%, line-height: 2vw, position: absolute]
      state:
        [top: 74%, left: 11%, line-height: 2vw, position: absolute]
      card:
        [font-family: Sf Display, letter-spacing: 0.05vw, font-weight: 400, color: 'rgba(255, 255, 255, 0.3)', font-size: 1.34vw, 
        background-color: 'rgba(115, 115, 115, 0.2)', border-radius: 0.8vw, box-shadow: none, transition: none]
      custom_fields:
        circle:
          [top: 8.5%, left: 56.2%, width: 3.5vw, position: absolute, letter-spacing: 0.03vw]

  loader:
    custom_fields:
      loader: >
        [[[ if (states[entity.entity_id.replace(entity.entity_id.split('.')[0], 'input_boolean')].state === 'on') { 
        return '<img src="/local/loader.svg" width="100%">'; } ]]]
    styles:
      custom_fields:
        loader:
          [filter: "[[[ return entity.state === 'off' ? 'invert(1)' : 'none'; ]]]", 
           top: 3%, left: 60%, width: 3.7vw, position: absolute, opacity: 0.6]

  icon_action:
  color: '#9da0a2'
  styles:
    card:
      [background: '#FFFFFF10', border-radius: 0.6em, box-shadow: none, 
      transition: none, width: 4em, height: 3.7em]


          - type: custom:button-card
            entity: switch.3f_bedroom_remote_itechie_power
            show_icon: false
            show_name: false
            style:
              top: 50.9%
              left: 41.31%
              width: 10%
            tap_action:
              action: toggle
            hold_action: !include popup/popup_3f_tv_remote.yaml
            custom_fields:
              icon_tv: &icon_tv >
                [[[ if (entity.state === 'on') { return '<svg viewBox="0 0 50 50"> <style>@keyframes animate{50%{transform: translateY(0);}100%{transform: translateY(-45%);}}.animate{animation: animate 2s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;}</style>
                <g style="clip-path: url(#mask);"><g class="animate"><path fill="#00aa9e" d="M49.2 38.9l-75.6-25.1v7.4l75.6 25.2z"/><path fill="#f3c202" d="M49.2 46.4l-75.6-25.2v7.5l75.6 25.1z"/><path fill="#326db3" d="M49.2 53.8l-75.6-25.1V51l75.6 25.1zm0-22.3L-26.4 6.4v7.4l75.6 25.1z"/></g></g>
                <defs><clipPath id="mask"><path d="M47.5 33.2c-.5-2.2-3.9-3.5-9.1-3.9-3.8-.3-7.5.6-11.1 1.9l-.6.2v-5.7l-5.7.8-4.6 1.6L6 31.9h-.1c-1.9.7-3.8 2.2-3.7 4.2.1 2.1 4.7 2.6 8.2 3.2 3.3.6 6.2.2 8.9-.7l7.3 4.8L33 41l10.7-4h.1c2.8-1 4-2.5 3.7-3.8zm-31.3 2l-3.6 1.3c-2.2.8-4.1-1.1-2.1-1.9l1.7-.6 7.2-2.7v2.8l-3.2 1.1zm22.5-1.1l-1.9.7-10.2 3.7V36l6.5-2.4 3.8-1.3c4-.9 5.6.5 1.8 1.8z"/></clipPath></defs><path fill="#de0029" d="M26.7 14.6v28.7l-7.3-2.5V7.1l9.3 2.6c6 1.7 9.6 5 9.6 10.7-.1 6.7-3 9.4-8.7 7.6V14.9c-.1-1.6-2.9-1.7-2.9-.3h0z"/></svg>'; }
                else { return '<svg viewBox="0 0 50 50"><path fill="#9da0a2" d="M43.8 37h-.1l-10.6 4-4.2 1.6v-4.9l8-2.9 1.9-.7c3.8-1.3 2.2-2.7-1.8-1.9l-3.8 1.3-4.3 1.6v-4.5c3.1-1 6.3-1.6 9.5-1.4 5.3.4 8.7 1.6 9.1 3.9.3 1.4-.9 2.9-3.7 3.9zm-26.7-2.1l-.9.3-3.6 1.3c-2.2.8-4.1-1.1-2.1-1.9l1.7-.6 5-1.9v-4.2l-.6.2L6 31.9h-.1c-1.9.7-3.8 2.2-3.7 4.2.1 2.1 4.7 2.6 8.2 3.2 2.4.4 4.6.3 6.7-.1v-4.3zm12.4-20V28c5.7 1.7 8.7-.9 8.7-7.6.1-5.7-3.6-9-9.6-10.7l-9.3-2.6v33.8l7.2 2.5.1.1V14.6c.1-1.4 2.9-1.3 2.9.3z"/></svg>'; } ]]]
            styles: &icon_tv_styles
              custom_fields:
                icon_tv:
                  [fill: "[[[ return entity.state === 'on' ? '#616161' : '#9da0a2'; ]]]", 
                  top: 20%, left: 10.7%, width: 3.5vw]
            template: ['base', 'loader']

No issues encountered if template is commented except for the image in pink box (left)

button_card_templates:
  base:
    aspect_ratio: 1/1
    show_state: true
    show_icon: false
    state:
      - value: 'on'
        styles:
          card: [background-color: 'rgba(255, 255, 255, 0.8)']
          name: [color: 'rgba(0, 0, 0, 0.6)']
          state: [color: 'rgba(0, 0, 0, 0.6)']
    tap_action:
      ui_sound: |
        [[[ if (entity.state === 'off' && states['switch.fullykiosk_screensaver'].state === 'off') {
        hass.callService('media_player', 'play_media', {entity_id: 'media_player.tablet', media_content_id: '/local/sound/on.m4a', media_content_type: 'music'}); }
        else if (entity.state === 'on' && states['switch.fullykiosk_screensaver'].state === 'off') {
        hass.callService('media_player', 'play_media', {entity_id: 'media_player.tablet', media_content_id: '/local/sound/off.m4a', media_content_type: 'music'}); } ]]]
      action: toggle
      haptic: light
    styles:
      name:
        [top: 57.7%, left: 11%, line-height: 2vw, position: absolute]
      state:
        [top: 74%, left: 11%, line-height: 2vw, position: absolute]
      card:
        [font-family: Sf Display, letter-spacing: 0.05vw, font-weight: 400, color: 'rgba(255, 255, 255, 0.3)', font-size: 1.34vw, 
        background-color: 'rgba(115, 115, 115, 0.2)', border-radius: 0.8vw, box-shadow: none, transition: none]
      custom_fields:
        circle:
          [top: 8.5%, left: 56.2%, width: 3.5vw, position: absolute, letter-spacing: 0.03vw]

  loader:
    custom_fields:
      loader: >
        [[[ if (states[entity.entity_id.replace(entity.entity_id.split('.')[0], 'input_boolean')].state === 'on') { 
        return '<img src="/local/loader.svg" width="100%">'; } ]]]
    styles:
      custom_fields:
        loader:
          [filter: "[[[ return entity.state === 'off' ? 'invert(1)' : 'none'; ]]]", 
           top: 3%, left: 60%, width: 3.7vw, position: absolute, opacity: 0.6]

  icon_action:
  color: '#9da0a2'
  styles:
    card:
      [background: '#FFFFFF10', border-radius: 0.6em, box-shadow: none, 
      transition: none, width: 4em, height: 3.7em]


          - type: custom:button-card
            entity: switch.3f_bedroom_remote_itechie_power
            show_icon: false
            show_name: false
            style:
              top: 50.9%
              left: 41.31%
              width: 10%
            tap_action:
              action: toggle
            hold_action: !include popup/popup_3f_tv_remote.yaml
            custom_fields:
              icon_tv: &icon_tv >
                [[[ if (entity.state === 'on') { return '<svg viewBox="0 0 50 50"> <style>@keyframes animate{50%{transform: translateY(0);}100%{transform: translateY(-45%);}}.animate{animation: animate 2s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;}</style>
                <g style="clip-path: url(#mask);"><g class="animate"><path fill="#00aa9e" d="M49.2 38.9l-75.6-25.1v7.4l75.6 25.2z"/><path fill="#f3c202" d="M49.2 46.4l-75.6-25.2v7.5l75.6 25.1z"/><path fill="#326db3" d="M49.2 53.8l-75.6-25.1V51l75.6 25.1zm0-22.3L-26.4 6.4v7.4l75.6 25.1z"/></g></g>
                <defs><clipPath id="mask"><path d="M47.5 33.2c-.5-2.2-3.9-3.5-9.1-3.9-3.8-.3-7.5.6-11.1 1.9l-.6.2v-5.7l-5.7.8-4.6 1.6L6 31.9h-.1c-1.9.7-3.8 2.2-3.7 4.2.1 2.1 4.7 2.6 8.2 3.2 3.3.6 6.2.2 8.9-.7l7.3 4.8L33 41l10.7-4h.1c2.8-1 4-2.5 3.7-3.8zm-31.3 2l-3.6 1.3c-2.2.8-4.1-1.1-2.1-1.9l1.7-.6 7.2-2.7v2.8l-3.2 1.1zm22.5-1.1l-1.9.7-10.2 3.7V36l6.5-2.4 3.8-1.3c4-.9 5.6.5 1.8 1.8z"/></clipPath></defs><path fill="#de0029" d="M26.7 14.6v28.7l-7.3-2.5V7.1l9.3 2.6c6 1.7 9.6 5 9.6 10.7-.1 6.7-3 9.4-8.7 7.6V14.9c-.1-1.6-2.9-1.7-2.9-.3h0z"/></svg>'; }
                else { return '<svg viewBox="0 0 50 50"><path fill="#9da0a2" d="M43.8 37h-.1l-10.6 4-4.2 1.6v-4.9l8-2.9 1.9-.7c3.8-1.3 2.2-2.7-1.8-1.9l-3.8 1.3-4.3 1.6v-4.5c3.1-1 6.3-1.6 9.5-1.4 5.3.4 8.7 1.6 9.1 3.9.3 1.4-.9 2.9-3.7 3.9zm-26.7-2.1l-.9.3-3.6 1.3c-2.2.8-4.1-1.1-2.1-1.9l1.7-.6 5-1.9v-4.2l-.6.2L6 31.9h-.1c-1.9.7-3.8 2.2-3.7 4.2.1 2.1 4.7 2.6 8.2 3.2 2.4.4 4.6.3 6.7-.1v-4.3zm12.4-20V28c5.7 1.7 8.7-.9 8.7-7.6.1-5.7-3.6-9-9.6-10.7l-9.3-2.6v33.8l7.2 2.5.1.1V14.6c.1-1.4 2.9-1.3 2.9.3z"/></svg>'; } ]]]
            styles: &icon_tv_styles
              custom_fields:
                icon_tv:
                  [fill: "[[[ return entity.state === 'on' ? '#616161' : '#9da0a2'; ]]]", 
                  top: 20%, left: 10.7%, width: 3.5vw]
            **# template: ['base', 'loader']**