├── README.md ├── configuration.yaml ├── configuration ├── themes.yaml └── themes │ ├── desktop │ ├── desktop.yaml │ ├── desktop_dark.yaml │ └── desktop_light.yaml │ └── mobile │ ├── mobile.yaml │ ├── mobile_dark.yaml │ └── mobile_light.yaml ├── lovelace ├── button_card_templates │ └── button_card_templates.yaml ├── resources │ └── resources.yaml └── views │ ├── 01_home.yaml │ ├── 02_temperature.yaml │ ├── 03_consommation.yaml │ └── 04_localisation.yaml ├── screenshots ├── anatomy.png ├── binary_sensor-1.png ├── binary_sensor-2.png ├── cards.png ├── chips.png ├── chips_icon.png ├── chips_localisation_present.png ├── chips_return.png ├── chips_temperature.png ├── cover_buttons.png ├── entity_graph.png ├── generic.png ├── light.png ├── light_slider.png ├── media.png ├── outlet.png ├── person.png ├── playstation.png ├── power_consumption.png ├── thermostat.png ├── title.png └── water-heater.png ├── ui-lovelace.yaml └── www └── community ├── button-card ├── button-card.js └── button-card.js.gz ├── ha-slider-card ├── slider-card.js └── slider-card.js.gz ├── lovelace-auto-entities ├── auto-entities.js ├── auto-entities.js.gz ├── rollup.config.js └── rollup.config.js.gz ├── lovelace-card-mod ├── card-mod.js ├── card-mod.js.gz ├── rollup.config.js └── rollup.config.js.gz ├── lovelace-state-switch ├── state-switch.js ├── state-switch.js.gz ├── webpack.config.js └── webpack.config.js.gz ├── mini-graph-card ├── mini-graph-card-bundle.js └── mini-graph-card-bundle.js.gz ├── mini-media-player ├── mini-media-player-bundle.js └── mini-media-player-bundle.js.gz ├── swipe-card ├── swipe-card.js └── swipe-card.js.gz └── vertical-stack-in-card ├── vertical-stack-in-card.js └── vertical-stack-in-card.js.gz /README.md: -------------------------------------------------------------------------------- 1 | # My Home Assistant 2 | At the top of each page we find the [chips](#chips) which allow me to quickly visualize the important information of the page. 3 | Then [title](#title) to separate the different sections 4 | and [cards](#cards) to represent and interact with devices, sensors, etc … 5 | I used the custom component [button-card](https://github.com/custom-cards/button-card) for all these cards. 6 | I drew a lot of inspiration from [7ahang’s work](https://www.behance.net/gallery/88433905/Redesign-Smart-Home) that I found on Behance. 7 | 8 | 9 | 10 | 11 | 12 | 13 | ## Table of Contents 14 | - [Installation](#installation) 15 | - [Design system](#design-system) 16 | - [Chips](#chips) 17 | - [Scene](#scene) 18 | - [Title](#title) 19 | - [Cards](#cards) 20 | 21 | # Installation 22 | 1. Add **button_card_templates** in **ui-lovelace.yaml** file. 23 | ```yaml 24 | button_card_templates: !include lovelace/button_card_templates/button_card_templates.yaml 25 | ``` 26 | 4. Add **resources** in your **configuration.yaml** file. You will need at least [button-card](https://github.com/custom-cards/button-card) 27 | ```yaml 28 | lovelace: 29 | mode: yaml 30 | resources: !include lovelace/resources/resources.yaml 31 | ``` 32 | 3. Add **themes** in your **configuration.yaml** file 33 | ```yaml 34 | frontend: 35 | themes: !include configuration/themes.yaml 36 | ``` 37 | 38 | 39 | # Design system 40 | ## Colors 41 | I tried to set up a consistency between the colors used to represent the entities. 42 | 43 | 44 | 45 | 46 | 47 | 48 | 53 | 54 | 59 | 60 | 61 | 67 | 72 | 73 | 74 | 80 | 87 | 88 | 89 | 95 | 100 | 101 |
Color Type
49 | 50 | ![orange](https://user-images.githubusercontent.com/12232620/127771417-73385ee2-8c31-47a4-8438-472826184ea1.png) 51 | 52 | 55 | 💡 Light 56 | 57 | ⚡ Electricity 58 |
62 | 63 | ![red](https://user-images.githubusercontent.com/12232620/127771470-38b1eba2-fc8a-41a8-a1fa-5fa249619af6.png) 64 | 65 | 66 | 68 | 69 | 🔥 Heating 70 | 71 |
75 | 76 | ![Blue](https://user-images.githubusercontent.com/12232620/127771485-615cf15e-d7fe-4528-8ccb-db3c307c3428.png) 77 | 78 | 79 | 81 | 82 | ☑️ On/off devices 83 | 84 | 🏠 Home 85 | 86 |
90 | 91 | ![green](https://user-images.githubusercontent.com/12232620/127771492-1abcd92b-8261-45e6-bdfb-d7987dcb6c76.png) 92 | 93 | 94 | 96 | 97 | 🌲 Exterior 98 | 99 |
102 | 103 | 104 | # Chips 105 | ![Chips](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/chips.png) 106 |
Code template 107 | 108 | 109 | 110 | 111 | 112 | 143 | 144 |
Template
113 | 114 | ```yaml 115 | chips: 116 | tap_action: 117 | action: more-info 118 | show_icon: false 119 | show_name: false 120 | show_state: false 121 | show_label: true 122 | size: 80% 123 | styles: 124 | img_cell: 125 | - width: 24px 126 | card: 127 | - border-radius: 18px 128 | - box-shadow: var(--box-shadow) 129 | - height: 36px 130 | - width: auto 131 | - padding-left: 6px 132 | - padding-right: 6px 133 | grid: 134 | - grid-template-areas: '"l"' 135 | label: 136 | - justify-self: center 137 | - padding: 0px 6px 138 | - font-weight: bold 139 | - font-size: 14px 140 | ``` 141 | 142 |
145 |
146 | 147 | ## Temperature 148 | ![Chips - Temperature](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/chips_temperature.png) 149 |
Code 150 | 151 | 152 | 153 | 154 | 155 | 156 | 164 | 203 | 204 |
Example Template
157 | 158 | ```yaml 159 | - template: chips_temperature 160 | type: 'custom:button-card' 161 | ``` 162 | 163 | 165 | 166 | ```yaml 167 | chips_temperature: 168 | template: chips 169 | tap_action: 170 | action: navigate 171 | navigation_path: /lovelace/temperature 172 | label: | 173 | [[[ 174 | var inter = states['sensor.fibaro_multisensor_salon_temperature'].state; 175 | var exter = states['sensor.fibaro_multisensor_balcon_temperature'].state; 176 | var icon = '☀️'; 177 | if (states['sensor.dark_sky_icon'].state == 'clear-day'){ 178 | var icon = '☀️'; 179 | } else if(states['sensor.dark_sky_icon'].state == 'clear-night'){ 180 | var icon = '🌙'; 181 | } else if(states['sensor.dark_sky_icon'].state == 'rain'){ 182 | var icon = '🌧️'; 183 | } else if(states['sensor.dark_sky_icon'].state == 'snow'){ 184 | var icon = '❄️'; 185 | } else if(states['sensor.dark_sky_icon'].state == 'sleet'){ 186 | var icon = '❄️'; 187 | } else if(states['sensor.dark_sky_icon'].state == 'wind'){ 188 | var icon = '🌫️'; 189 | } else if(states['sensor.dark_sky_icon'].state == 'fog'){ 190 | var icon = '🌫️'; 191 | } else if(states['sensor.dark_sky_icon'].state == 'cloudy'){ 192 | var icon = '☁️'; 193 | } else if(states['sensor.dark_sky_icon'].state == 'partly-cloudy-day'){ 194 | var icon = '⛅️'; 195 | } else if(states['sensor.dark_sky_icon'].state == 'partly-cloudy-night'){ 196 | var icon = '⛅'; 197 | } 198 | return icon + ' ' + exter + '° / ' + inter + '°' ; 199 | ]]] 200 | ``` 201 | 202 |
205 |
206 | 207 | ## Electric consumption 208 | ![Chips - Consommation](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/power_consumption.png) 209 |
Code 210 | 211 | 212 | 213 | 214 | 215 | 216 | 224 | 240 | 242 |
Example Template
217 | 218 | ```yaml 219 | - template: chips_power_consumption 220 | type: 'custom:button-card' 221 | ``` 222 | 223 | 225 | 226 | ```yaml 227 | chips_power_consumption: 228 | template: chips 229 | tap_action: 230 | action: navigate 231 | navigation_path: /lovelace/consommation 232 | label: | 233 | [[[ 234 | var price = states['sensor.atome_price_conso_today'].state; 235 | return '⚡ ' + price + '€' ; 236 | ]]] 237 | ``` 238 | 239 | 241 |
243 |
244 | 245 | ## Presence counter 246 | ![Chips - Present](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/chips_localisation_present.png) 247 |
Code 248 | 249 | 250 | 251 | 252 | 253 | 254 | 262 | 278 | 279 |
Example Template
255 | 256 | ```yaml 257 | - template: chips_localisation_present 258 | type: 'custom:button-card' 259 | ``` 260 | 261 | 263 | 264 | ```yaml 265 | chips_localisation_present: 266 | tap_action: 267 | action: navigate 268 | navigation_path: /lovelace/localisation 269 | label: | 270 | [[[ 271 | var personnes_presentes = states['sensor.people_count_present'].state; 272 | return '🏠 ' + personnes_presentes; 273 | ]]] 274 | template: chips 275 | ``` 276 | 277 |
280 |
281 | 282 | ## Return button 283 | ![Chips - return](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/chips_return.png) 284 | 285 |
Code 286 | 287 | 288 | 289 | 290 | 291 | 292 | 300 | 317 | 318 |
Example Template
293 | 294 | ```yaml 295 | - template: chips_return 296 | type: 'custom:button-card 297 | ``` 298 | 299 | 301 | 302 | ```yaml 303 | chips_return: 304 | template: chips 305 | show_icon: true 306 | icon: 'mdi:arrow-left' 307 | size: 80% 308 | styles: 309 | grid: 310 | - grid-template-areas: '"i"' 311 | tap_action: 312 | action: navigate 313 | navigation_path: /lovelace/home 314 | ``` 315 | 316 |
319 |
320 | 321 | # Scene 322 | ![Scene](https://user-images.githubusercontent.com/12232620/127768397-24ab76fc-b037-4fc5-a2ef-45e96285cd46.gif) 323 |
Code 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 342 | 379 | 407 | 408 |
Example Template Template Blue
332 | 333 | ```yaml 334 | - entity: sensor.present 335 | template: scene_blue 336 | variables: 337 | state: "Present" 338 | type: 'custom:button-card' 339 | ``` 340 | 341 | 343 | 344 | ```yaml 345 | scene: 346 | size: 20px 347 | show_label: true 348 | label: | 349 | [[[ return (entity.attributes.value )]]] 350 | styles: 351 | card: 352 | - border-radius: var(--border-radius) 353 | - box-shadow: var(--box-shadow) 354 | - padding: 10px 0px 8px 0px 355 | grid: 356 | - grid-template-areas: '"i" "n" "l"' 357 | name: 358 | - margin-top: 10px 359 | - justify-self: center 360 | - font-weight: bold 361 | - font-size: 14px 362 | label: 363 | - justify-self: center 364 | - align-self: start 365 | - font-weight: bolder 366 | - font-size: 12px 367 | - filter: opacity(40%) 368 | icon: 369 | - color: 'rgba(var(--color-theme),0.2)' 370 | img_cell: 371 | - background-color: 'rgba(var(--color-theme),0.05)' 372 | - border-radius: 50% 373 | - place-self: center 374 | - width: 42px 375 | - height: 42px 376 | ``` 377 | 378 | 380 | 381 | ```yaml 382 | scene_blue: 383 | variables: 384 | state: "default" 385 | template: 386 | - scene 387 | state: 388 | - operator: template 389 | value: > 390 | [[[ 391 | return states['input_select.localisation_thomas'].state == variables.state 392 | ]]] 393 | styles: 394 | icon: 395 | - color: 'rgba(var(--color-blue),1)' 396 | img_cell: 397 | - background-color: 'rgba(var(--color-blue), 0.2)' 398 | card: 399 | - background-color: 'rgba(var(--color-background-blue), var(--opacity-bg))' 400 | name: 401 | - color: 'rgba(var(--color-blue-text),1)' 402 | label: 403 | - color: 'rgba(var(--color-blue-text),1)' 404 | ``` 405 | 406 |
409 |
410 | 411 | # Title 412 | ![Title](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/title.png) 413 |
Code 414 | 415 | 416 | 417 | 418 | 419 | 420 | 431 | 465 | 466 |
Example Template
421 | 422 | ```yaml 423 | - template: title 424 | name: Title 425 | label: 'Subtitle' 426 | type: 'custom:button-card' 427 | 428 | ``` 429 | 430 | 432 | 433 | ```yaml 434 | title: 435 | tap_action: 436 | action: none 437 | show_icon: false 438 | show_label: true 439 | show_name: true 440 | styles: 441 | card: 442 | - background-color: rgba(0,0,0,0) 443 | - box-shadow: none 444 | - height: auto 445 | - width: auto 446 | - margin-top: 12px 447 | - margin-left: 24px 448 | - margin-bottom: 0px 449 | grid: 450 | - grid-template-areas: '"n" "l"' 451 | - grid-template-columns: 1fr 452 | - grid-template-rows: min-content min-content 453 | name: 454 | - justify-self: start 455 | - font-weight: bold 456 | - font-size: '1.5rem' 457 | label: 458 | - justify-self: start 459 | - font-weight: bold 460 | - font-size: '1rem' 461 | - opacity: '0.4' 462 | ``` 463 | 464 |
467 |
468 | 469 | # Cards 470 | ![Cards](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/cards.png) 471 | 472 | ### Anatomy 473 | ![Anatomy](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/anatomy.png) 474 | 1. **Dot** : Visible when the device is unavailable. Also used on the entity **person** 475 | 2. **Icon** : Icon that represents the device 476 | 3. **Primary line** : Main information 477 | 4. **Secondary line** : Secondary information 478 | 5. **Optionnal part** : Possibility to display buttons to launch actions related to the device. Or display a graph to view the history of a sensor 479 | 480 | 481 | ## Light 482 | 483 | ![Light](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/light.png) 484 |
Code 485 | 486 | 487 | 488 | 489 | 490 | 491 | 503 | 529 | 530 |
Example Template
492 | 493 | ```yaml 494 | - entity: light.example 495 | name: Lumière 496 | template: 497 | - icon_info_bg 498 | - light 499 | type: 'custom:button-card' 500 | ``` 501 | 502 | 504 | 505 | ```yaml 506 | light: 507 | tap_action: 508 | action: toggle 509 | hold_action: 510 | action: more-info 511 | label: >- 512 | [[[ if (entity.state !='unavailable'){ 513 | if (entity.state =='off'){ 514 | var bri = Math.round(entity.attributes.brightness / 2.55); 515 | return 'Off'; 516 | }else{ 517 | var bri = Math.round(entity.attributes.brightness / 2.55); 518 | return (bri ? bri : '0') + '%'; 519 | } 520 | }else{ 521 | return "Indisponible"; 522 | } 523 | ]]] 524 | template: 525 | - yellow 526 | ``` 527 | 528 |
531 |
532 | 533 | ## Light slider 534 | 535 | ![Light-slider](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/light_slider.png) 536 |
Code 537 | 538 | 539 | 540 | 541 | 542 | 543 | 556 | 615 | 616 |
Example Template
544 | 545 | ```yaml 546 | - entity: light.exemple 547 | template: 548 | - light_slider 549 | variables: 550 | entity: "light.exemple" 551 | name: "Light" 552 | type: 'custom:button-card' 553 | ``` 554 | 555 | 557 | 558 | ```yaml 559 | light_slider: 560 | variables: 561 | name: "Default name" 562 | show_icon: false 563 | show_name: false 564 | show_label: false 565 | styles: 566 | card: 567 | - border-radius: var(--border-radius) 568 | - box-shadow: var(--box-shadow) 569 | - padding: 12px 570 | grid: 571 | - grid-template-areas: '"item1" "item2"' 572 | - grid-template-columns: 1fr 573 | - grid-template-rows: min-content min-content 574 | - row-gap: 12px 575 | state: 576 | - operator: template 577 | value: > 578 | [[[ 579 | return entity.state == 'on' 580 | ]]] 581 | styles: 582 | card: 583 | - background-color: 'rgba(var(--color-background-yellow),var(--opacity-bg))' 584 | custom_fields: 585 | item1: 586 | card: 587 | entity: '[[[ return variables.entity ]]]' 588 | name: '[[[ return variables.name ]]]' 589 | template: 590 | - icon_info 591 | - light 592 | type: 'custom:button-card' 593 | item2: 594 | card: 595 | type: 'custom:slider-card' 596 | entity: '[[[ return variables.entity ]]]' 597 | radius: 14px 598 | height: 42px 599 | mainSliderColor: rgba(var(--color-yellow),1) 600 | secondarySliderColor: rgba(var(--color-yellow),0.2) 601 | mainSliderColorOff: rgba(var(--color-theme),0.05) 602 | secondarySliderColorOff: rgba(var(--color-theme),0.05) 603 | thumbHorizontalPadding: '0px' 604 | thumbVerticalPadding: '0px' 605 | thumbWidth: 0px 606 | card_mod: 607 | style: | 608 | ha-card { 609 | border-radius: 14px; 610 | box-shadow: none; 611 | } 612 | ``` 613 | 614 |
617 |
618 | 619 | ## Outlet 620 | ![Prise](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/outlet.png) 621 |
Code 622 | 623 | 624 | 625 | 626 | 627 | 628 | 646 | 663 | 664 |
Example Template
629 | 630 | ```yaml 631 | - entity: switch.exemple 632 | name: Prise 633 | template: 634 | - icon_info_bg 635 | - outlet 636 | label: |- 637 | [[[ if (entity.state =='on') 638 | var etat = "On • " + states["sensor.exemple"].state + "W"; 639 | else 640 | var etat = "Off"; 641 | return etat ; ]]] 642 | type: 'custom:button-card' 643 | ``` 644 | 645 | 647 | 648 | ```yaml 649 | outlet: 650 | tap_action: 651 | action: more-info 652 | label: |- 653 | [[[ if (entity.state =='on') 654 | var etat = "On"; 655 | else 656 | var etat = "Off"; 657 | return etat ; ]]] 658 | template: 659 | - yellow 660 | ``` 661 | 662 |
665 |
666 | 667 | ## Binary sensor 668 | ![Mouvements](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/binary_sensor-1.png) ![Fenêtres](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/binary_sensor-2.png) 669 |
Code 670 | 671 | 672 | 673 | 674 | 675 | 676 | 689 | 699 | 700 |
Example Template
677 | 678 | ```yaml 679 | - entity: binary_sensor.example 680 | name: Mouvement 681 | icon: 'mdi:run' 682 | template: 683 | - icon_info_bg 684 | - binary_sensor 685 | type: 'custom:button-card' 686 | ``` 687 | 688 | 690 | 691 | ```yaml 692 | binary_sensor: 693 | show_last_changed: true 694 | template: 695 | - blue 696 | ``` 697 | 698 |
701 |
702 | 703 | 704 | ## Cover 705 | ![Volets](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/cover_buttons.png) 706 |
Code 707 | 708 | 709 | 710 | 711 | 712 | 713 | 724 | 790 | 791 |
Example Template
714 | 715 | ```yaml 716 | - template: cover_buttons 717 | variables: 718 | entity: "cover.example" 719 | name: "Volets" 720 | type: 'custom:button-card' 721 | ``` 722 | 723 | 725 | 726 | ```yaml 727 | cover_buttons: 728 | variables: 729 | entity: "cover.fibaro_cover_balcon" 730 | name: "Default name" 731 | styles: 732 | card: 733 | - border-radius: var(--border-radius) 734 | - box-shadow: var(--box-shadow) 735 | - padding: 12px 736 | grid: 737 | - grid-template-areas: '"item1" "item2"' 738 | - grid-template-columns: 1fr 739 | - grid-template-rows: min-content min-content 740 | - row-gap: 12px 741 | custom_fields: 742 | item1: 743 | card: 744 | entity: '[[[ return variables.entity ]]]' 745 | name: '[[[ return variables.name ]]]' 746 | tap_action: 747 | action: more-info 748 | template: 749 | - icon_info 750 | - cover 751 | type: 'custom:button-card' 752 | item2: 753 | card: 754 | template: list_items 755 | type: 'custom:button-card' 756 | custom_fields: 757 | item1: 758 | card: 759 | icon: 'mdi:arrow-down' 760 | tap_action: 761 | action: call-service 762 | service: cover.close_cover 763 | service_data: 764 | entity_id: '[[[ return variables.entity ]]]' 765 | type: 'custom:button-card' 766 | template: widget_icon 767 | item2: 768 | card: 769 | icon: 'mdi:pause' 770 | tap_action: 771 | action: call-service 772 | service: cover.stop_cover 773 | service_data: 774 | entity_id: '[[[ return variables.entity ]]]' 775 | type: 'custom:button-card' 776 | template: widget_icon 777 | item3: 778 | card: 779 | icon: 'mdi:arrow-up' 780 | tap_action: 781 | action: call-service 782 | service: cover.open_cover 783 | service_data: 784 | entity_id: '[[[ return variables.entity ]]]' 785 | type: 'custom:button-card' 786 | template: widget_icon 787 | ``` 788 | 789 |
792 |
793 | 794 | ## Thermostat 795 | ![Thermostat](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/thermostat.png) 796 |
Code 797 | 798 | 799 | 800 | 801 | 802 | 803 | 814 | 854 | 855 |
Example Template
804 | 805 | ```yaml 806 | - entity: climate.example 807 | template: 808 | - icon_info_bg 809 | - thermostat 810 | type: 'custom:button-card' 811 | ``` 812 | 813 | 815 | 816 | ```yaml 817 | thermostat: 818 | hold_action: 819 | action: more-info 820 | entity: input_boolean.radiateur_arret_force 821 | label: >- 822 | [[[ 823 | if (entity.state =='off'){ 824 | return 'Off' ; 825 | }else{ 826 | if (states['light.qubino'].state == 'on'){ 827 | var etat = "Chauffe"; 828 | }else{ 829 | var etat = "Inactif"; 830 | } 831 | return (entity.attributes.temperature ) + '°' + ' • ' + etat ; 832 | } 833 | ]]] 834 | state: 835 | - operator: template 836 | value: > 837 | [[[ 838 | return states['light.qubino'].state == 'on' 839 | ]]] 840 | styles: 841 | icon: 842 | - color: 'rgba(var(--color-red),1)' 843 | img_cell: 844 | - background-color: 'rgba(var(--color-red),0.2)' 845 | card: 846 | - background-color: 'rgba(var(--color-background-red),var(--opacity-bg))' 847 | name: 848 | - color: 'rgba(var(--color-red-text),1)' 849 | label: 850 | - color: 'rgba(var(--color-red-text),1)' 851 | ``` 852 | 853 |
856 |
857 | 858 | ## Water heater 859 | ![Chauffe-eau](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/water-heater.png) 860 |
Code 861 | 862 | 863 | 864 | 865 | 866 | 867 | 879 | 921 | 922 |
Example Template
868 | 869 | ```yaml 870 | - entity: switch.example 871 | name: Chauffe eau 872 | template: 873 | - icon_info_bg 874 | - water_heater 875 | type: 'custom:button-card' 876 | ``` 877 | 878 | 880 | 881 | ```yaml 882 | water_heater: 883 | icon: 'mdi:waves' 884 | tap_action: 885 | action: more-info 886 | hold_action: 887 | action: more-info 888 | label: >- 889 | [[[ 890 | if (entity.state == 'off'){ 891 | return 'Arrêt forcé'; 892 | }else{ 893 | if (states["sensor.shelly_prise_salon_conso"].state > 0){ 894 | var etat = "Chauffe • " + states["sensor.shelly_prise_salon_conso"].state + "W"; 895 | }else{ 896 | var etat = "Inactif"; 897 | } 898 | return etat ; 899 | } 900 | ]]] 901 | state: 902 | - operator: template 903 | value: > 904 | [[[ 905 | return (states['sensor.shelly_prise_salon_conso'].state > 0) 906 | ]]] 907 | styles: 908 | icon: 909 | - color: 'rgba(var(--color-red),1)' 910 | img_cell: 911 | - background-color: 'rgba(var(--color-red),0.2)' 912 | card: 913 | - background-color: 'rgba(var(--color-background-red),var(--opacity-bg))' 914 | name: 915 | - color: 'rgba(var(--color-red-text),1)' 916 | label: 917 | - color: 'rgba(var(--color-red-text),1)' 918 | ``` 919 | 920 |
923 |
924 | 925 | ## Media player 926 | ![Enceintes](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/media.png) 927 |
Code 928 | 929 | 930 | 931 | 932 | 933 | 934 | 946 | 1019 | 1020 |
Example Template
935 | 936 | ```yaml 937 | - entity: media_player.example 938 | name: Enceintes 939 | template: 940 | - icon_info_bg 941 | - media 942 | type: 'custom:button-card' 943 | ``` 944 | 945 | 947 | 948 | ```yaml 949 | media: 950 | label: >- 951 | [[[ if (entity.state =='off'){ 952 | return "Off"; 953 | }else{ 954 | return entity.state; 955 | } 956 | ]]] 957 | icon: | 958 | [[[ 959 | var application = entity.attributes.app_name; 960 | var icon = 'mdi:speaker'; 961 | if (application == 'Oto music'){ 962 | var icon = 'mdi:music-circle'; 963 | } else if(application == 'Spotify'){ 964 | var icon = 'mdi:spotify'; 965 | } else if(application == 'Google Podcasts'){ 966 | var icon = 'mdi:google-podcast'; 967 | } else if(application == 'Plex'){ 968 | var icon = 'mdi:plex'; 969 | } 970 | return icon ; 971 | ]]] 972 | styles: 973 | label: 974 | - opacity: '0.6' 975 | icon: 976 | - color: 'rgba(var(--color-theme),0.2)' 977 | img_cell: 978 | - background-color: 'rgba(var(--color-theme),0.05)' 979 | card: 980 | - background-blend-mode: multiply 981 | - background: > 982 | [[[ 983 | var image = entity.attributes.entity_picture_local; 984 | var bg = entity.attributes.entity_picture_local; 985 | if (image == null){ 986 | var bg = ''; 987 | } else{ 988 | var bg = 'center / cover url(' + image + ') rgba(0, 0, 0, 0.15)'; 989 | } 990 | return bg; 991 | ]]] 992 | state: 993 | - operator: template 994 | value: > 995 | [[[ 996 | return entity.state !='off' 997 | ]]] 998 | name: > 999 | [[[ 1000 | return entity.attributes.media_title; 1001 | ]]] 1002 | label: > 1003 | [[[ 1004 | return entity.attributes.media_album_name; 1005 | ]]] 1006 | styles: 1007 | label: 1008 | - color: white 1009 | - filter: opacity(100%) 1010 | img_cell: 1011 | - background-color: 'rgba(var(--color-theme),0.0)' 1012 | icon: 1013 | - color: white 1014 | name: 1015 | - color: white 1016 | ``` 1017 | 1018 |
1021 |
1022 | 1023 | ## Playstation 1024 | ![Playstation](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/playstation.png) 1025 |
Code 1026 | 1027 | 1028 | 1029 | 1030 | 1031 | 1032 | 1043 | 1107 | 1108 |
Example Template
1033 | 1034 | ```yaml 1035 | - entity: media_player.example 1036 | template: 1037 | - icon_info_bg 1038 | - ps4 1039 | type: 'custom:button-card' 1040 | ``` 1041 | 1042 | 1044 | 1045 | ```yaml 1046 | ps4: 1047 | label: >- 1048 | [[[ if (entity.state =='unknown'){ 1049 | return "Off"; 1050 | }else if (entity.state =='standby'){ 1051 | return "En veille"; 1052 | }else{ 1053 | return "On"; 1054 | } 1055 | ]]] 1056 | styles: 1057 | icon: 1058 | - color: 'rgba(var(--color-theme),0.2)' 1059 | img_cell: 1060 | - background-color: 'rgba(var(--color-theme),0.05)' 1061 | state: 1062 | - value: 'idle' 1063 | styles: 1064 | icon: 1065 | - color: 'rgba(var(--color-blue),1)' 1066 | img_cell: 1067 | - background-color: 'rgba(var(--color-blue), 0.2)' 1068 | - value: 'standby' 1069 | styles: 1070 | icon: 1071 | - color: 'rgba(var(--color-theme),0.2)' 1072 | img_cell: 1073 | - background-color: 'rgba(var(--color-theme),0.05)' 1074 | - operator: template 1075 | value: > 1076 | [[[ 1077 | return entity.state !='unknown' 1078 | ]]] 1079 | name: > 1080 | [[[ 1081 | return entity.attributes.media_title; 1082 | ]]] 1083 | label: > 1084 | [[[ 1085 | return entity.attributes.friendly_name; 1086 | ]]] 1087 | styles: 1088 | label: 1089 | - color: white 1090 | - filter: opacity(100%) 1091 | img_cell: 1092 | - background-color: 'none' 1093 | icon: 1094 | - color: white 1095 | name: 1096 | - color: white 1097 | card: 1098 | - background-blend-mode: multiply 1099 | - background: > 1100 | [[[ 1101 | var image = entity.attributes.entity_picture; 1102 | return 'center / cover url(' + image + ') rgba(0, 0, 0, 0.15)'; 1103 | ]]] 1104 | ``` 1105 | 1106 |
1109 |
1110 | 1111 | ## Person 1112 | ![Personne](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/person.png) 1113 |
Information 1114 | 1115 | **Dot** : 1116 | - At home : Blue 1117 | - Away : Green 1118 | 1119 | 1120 | **Dot icon** : 1121 | - At home : Home 1122 | - Away : Walking man 1123 | - Sleeping : Moon 1124 | 1125 | **Comment** : The sleep state takes over the At home or Away state to display the moon icon 1126 |
1127 |
Code 1128 | 1129 | 1130 | 1131 | 1132 | 1133 | 1134 | 1148 | 1208 | 1209 |
Example Template
1135 | 1136 | ```yaml 1137 | - entity: input_select.localisation_thomas 1138 | variables: 1139 | personne: "thomas" 1140 | template: 1141 | - icon_info_bg 1142 | - personne-thomas 1143 | name: Thomas 1144 | type: 'custom:button-card' 1145 | ``` 1146 | 1147 | 1149 | 1150 | ```yaml 1151 | person: 1152 | tap_action: 1153 | action: more-info 1154 | show_label: true 1155 | label: > 1156 | [[[return entity.state]]] 1157 | styles: 1158 | icon: 1159 | - color: 'rgba(var(--color-theme),0.9)' 1160 | custom_fields: 1161 | notification: 1162 | - border-radius: 50% 1163 | - position: absolute 1164 | - left: 38px 1165 | - top: 8px 1166 | - height: 16px 1167 | - width: 16px 1168 | - border: 2px solid var(--card-background-color) 1169 | - font-size: 12px 1170 | - line-height: 14px 1171 | 1172 | #################################################### 1173 | 1174 | person-thomas: 1175 | variables: 1176 | person: "thomas" 1177 | template: person 1178 | hold_action: 1179 | action: more-info 1180 | entity: input_boolean.thomas_nuit 1181 | styles: 1182 | custom_fields: 1183 | notification: 1184 | - background-color: > 1185 | [[[ 1186 | if (states['input_select.localisation_thomas'].state == 'Present'){ 1187 | return "rgba(var(--color-blue),1)"; 1188 | }else{ 1189 | return "rgba(var(--color-green),1)"; 1190 | } 1191 | ]]] 1192 | custom_fields: 1193 | notification: > 1194 | [[[ 1195 | if (states['input_boolean.thomas_nuit'].state == 'on'){ 1196 | return `` 1197 | }else{ 1198 | if (states['input_select.localisation_thomas'].state == 'Present'){ 1199 | return `` 1200 | }else{ 1201 | return `` 1202 | } 1203 | } 1204 | ]]] 1205 | ``` 1206 | 1207 |
1210 |
1211 | 1212 | ## Generic 1213 | 1214 | ![Generic](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/generic.png) 1215 |
Code 1216 | 1217 | 1218 | 1219 | 1220 | 1221 | 1222 | 1233 | 1263 | 1264 |
Example Template
1223 | 1224 | ```yaml 1225 | - entity: sensor.example 1226 | template: 1227 | - icon_info_bg 1228 | - generic 1229 | type: 'custom:button-card' 1230 | ``` 1231 | 1232 | 1234 | 1235 | ```yaml 1236 | generic: 1237 | label: > 1238 | [[[return entity.state + " " + entity.attributes.unit_of_measurement]]] 1239 | styles: 1240 | icon: 1241 | - color: 'rgba(var(--color-theme),0.9)' 1242 | grid: 1243 | - grid-template-areas: '"i l" "i n"' 1244 | - grid-template-columns: min-content auto 1245 | - grid-template-rows: min-content min-content 1246 | label: 1247 | - align-self: end 1248 | - justify-self: start 1249 | - font-weight: bold 1250 | - font-size: 14px 1251 | - margin-left: 12px 1252 | - filter: opacity(100%) 1253 | name: 1254 | - justify-self: start 1255 | - align-self: start 1256 | - font-weight: bolder 1257 | - font-size: 12px 1258 | - filter: opacity(40%) 1259 | - margin-left: 12px 1260 | ``` 1261 | 1262 |
1265 |
1266 | 1267 | ## Generic + graph 1268 | 1269 | ![Entity - graph](https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/main/screenshots/entity_graph.png) 1270 |
Code 1271 | 1272 | 1273 | 1274 | 1275 | 1276 | 1277 | 1289 | 1337 | 1338 |
Example Template
1278 | 1279 | ```yaml 1280 | - type: 'custom:button-card' 1281 | template: graph 1282 | variables: 1283 | entity: "sensor.exemple" 1284 | color: "var(--google-blue)" 1285 | name: "Température" 1286 | ``` 1287 | 1288 | 1290 | 1291 | ```yaml 1292 | graph: 1293 | variables: 1294 | entity: "sensor.xiaomi_multisensor_salon_humidite" 1295 | color: "var(--info-color)" 1296 | name: "Default name" 1297 | styles: 1298 | card: 1299 | - border-radius: var(--border-radius) 1300 | - box-shadow: var(--box-shadow) 1301 | - padding: 0px 1302 | grid: 1303 | - grid-template-areas: '"item1" "item2"' 1304 | - grid-template-columns: 1fr 1305 | - grid-template-rows: min-content min-content 1306 | custom_fields: 1307 | item1: 1308 | card: 1309 | entity: '[[[ return variables.entity ]]]' 1310 | name: '[[[ return variables.name ]]]' 1311 | template: 1312 | - icon_info 1313 | - generic 1314 | styles: 1315 | card: 1316 | - padding: 12px 1317 | type: 'custom:button-card' 1318 | item2: 1319 | card: 1320 | type: 'custom:mini-graph-card' 1321 | entities: 1322 | - entity: '[[[ return variables.entity ]]]' 1323 | line_color: '[[[ return variables.color ]]]' 1324 | show: 1325 | name: false 1326 | icon: false 1327 | legend: false 1328 | state: false 1329 | style: | 1330 | ha-card { 1331 | box-shadow: none; 1332 | border-radius: var(--border-radius); 1333 | } 1334 | ``` 1335 | 1336 |
1339 |
1340 | -------------------------------------------------------------------------------- /configuration.yaml: -------------------------------------------------------------------------------- 1 | lovelace: 2 | mode: yaml 3 | resources: !include lovelace/resources/resources.yaml 4 | 5 | frontend: 6 | themes: !include configuration/themes.yaml 7 | 8 | 9 | -------------------------------------------------------------------------------- /configuration/themes.yaml: -------------------------------------------------------------------------------- 1 | desktop: 2 | !include themes/desktop/desktop.yaml 3 | mobile: 4 | !include themes/mobile/mobile.yaml -------------------------------------------------------------------------------- /configuration/themes/desktop/desktop.yaml: -------------------------------------------------------------------------------- 1 | # Journal 2 | state-icon-color: 'rgb(var(--color-theme))' 3 | border-radius: '20px' 4 | error-color: 'var(--google-red)' 5 | warning-color: 'var(--google-yellow)' 6 | success-color: 'var(--google-green)' 7 | info-color: 'var(--google-blue)' 8 | divider-color: 'rgba(var(--color-theme),.12)' 9 | accent-color: 'var(--google-yellow)' 10 | modes: 11 | light: 12 | !include desktop_light.yaml 13 | dark: 14 | !include desktop_dark.yaml -------------------------------------------------------------------------------- /configuration/themes/desktop/desktop_dark.yaml: -------------------------------------------------------------------------------- 1 | #################################################### 2 | # # 3 | # DARK # 4 | # # 5 | #################################################### 6 | #text 7 | primary-text-color: '#DDDDDD' 8 | 9 | #main interface colors 10 | primary-color: '#89B3F8' 11 | google-red : '#F18B82' 12 | google-green : '#80C994' 13 | google-yellow : '#FCD663' 14 | google-blue : '#89B3F8' 15 | google-violet : '#BB86FC' 16 | google-grey: '#BBBBBB' 17 | color-red: 241, 139, 130 18 | color-green: 128, 201, 148 19 | color-yellow: 252, 214, 99 20 | color-blue : 137, 179, 248 21 | color-theme : 221,221,221 22 | color-purple : 102, 31, 255 23 | color-grey : 187, 187, 187 24 | color-pink : 233, 30, 99 25 | color-background-yellow : 'var(--color-yellow)' 26 | color-background-blue : 'var(--color-blue)' 27 | color-background-green : 'var(--color-green)' 28 | color-background-red : 'var(--color-red)' 29 | color-yellow-text: 'var(--color-yellow)' 30 | color-blue-text: 'var(--color-blue)' 31 | color-green-text: 'var(--color-green)' 32 | color-red-text: 'var(--color-red)' 33 | opacity-bg: '0.1' 34 | 35 | #floating button text color 36 | mdc-theme-on-secondary: 'var(--card-background-color)' 37 | 38 | #background and sidebar 39 | card-background-color: '#1D1D1D' 40 | primary-background-color: '#121212' 41 | secondary-background-color: '#121212' 42 | 43 | #header 44 | app-header-text-color: 'var(--primary-text-color)' 45 | app-header-background-color: 'var(--primary-background-color)' 46 | paper-tabs-selection-bar-color: 'var(--primary-text-color)' 47 | 48 | #Sidebar 49 | sidebar-selected-text-color: 'rgb(var(--color-blue))' 50 | sidebar-selected-icon-color: 'rgb(var(--color-blue))' 51 | 52 | #Slider 53 | slider-color: 'rgb(var(--color-blue))' 54 | slider-bar-color: 'rgba(var(--color-blue),0.38)' 55 | 56 | # card 57 | box-shadow: 'none' 58 | 59 | #media player 60 | mini-media-player-accent-color: 'var(--google-blue)' 61 | 62 | # Journal 63 | state-icon-color: 'rgb(var(--color-theme))' 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /configuration/themes/desktop/desktop_light.yaml: -------------------------------------------------------------------------------- 1 | #################################################### 2 | # # 3 | # LIGHT # 4 | # # 5 | #################################################### 6 | #text 7 | primary-text-color: '#212121' 8 | 9 | #main interface colors 10 | primary-color: '#434343' 11 | google-red : '#F54436' 12 | google-green : '#01C852' 13 | google-yellow : '#FF9101' 14 | google-blue : '#3D5AFE' 15 | google-violet : '#661FFF' 16 | google-grey: '#BBBBBB' 17 | color-red : 245, 68, 54 18 | color-green : 1, 200, 82 19 | color-yellow : 255, 145, 1 20 | color-blue : 61, 90, 254 21 | color-purple : 102, 31, 255 22 | color-grey : 187, 187, 187 23 | color-pink : 233, 30, 99 24 | color-theme : 51,51,51 25 | color-background-yellow : 250, 250, 250 26 | color-background-blue : 250, 250, 250 27 | color-background-green : 250, 250, 250 28 | color-background-red : 250, 250, 250 29 | 30 | color-yellow-text: 'var(--primary-text-color)' 31 | color-blue-text: 'var(--primary-text-color)' 32 | color-green-text: 'var(--primary-text-color)' 33 | color-red-text: 'var(--primary-text-color)' 34 | opacity-bg: '1' 35 | 36 | #background and sidebar 37 | card-background-color: '#FAFAFA' 38 | primary-background-color: '#EFEFEF' 39 | secondary-background-color: '#EFEFEF' 40 | 41 | #header 42 | app-header-text-color: 'var(--primary-text-color)' 43 | app-header-background-color: 'var(--primary-background-color)' 44 | # paper-tabs-selection-bar-color: 'var(--primary-text-color)' 45 | 46 | #slider 47 | slider-color: 'rgb(var(--color-blue))' 48 | slider-bar-color: 'rgba(var(--color-blue),0.38)' 49 | 50 | #cards 51 | box-shadow: '0px 2px 4px 0px rgba(0,0,0,0.16)' 52 | ha-card-box-shadow: 'var(--box-shadow)' 53 | 54 | #sidebar 55 | sidebar-selected-text-color: 'var(--google-red)' 56 | sidebar-selected-icon-color: 'var(--google-red)' 57 | sidebar-text-color: '#80868b' 58 | 59 | #switch 60 | switch-checked-color: 'var(--google-blue)' 61 | 62 | #media player 63 | mini-media-player-accent-color: 'var(--google-red)' 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /configuration/themes/mobile/mobile.yaml: -------------------------------------------------------------------------------- 1 | # Journal 2 | state-icon-color: 'rgb(var(--color-theme))' 3 | border-radius: '20px' 4 | error-color: 'var(--google-red)' 5 | warning-color: 'var(--google-yellow)' 6 | success-color: 'var(--google-green)' 7 | info-color: 'var(--google-blue)' 8 | divider-color: 'rgba(var(--color-theme),.12)' 9 | accent-color: 'var(--google-yellow)' 10 | card-mod-theme: mobile 11 | card-mod-root: | 12 | app-toolbar { 13 | display: none; 14 | } 15 | modes: 16 | light: 17 | !include mobile_light.yaml 18 | dark: 19 | !include mobile_dark.yaml -------------------------------------------------------------------------------- /configuration/themes/mobile/mobile_dark.yaml: -------------------------------------------------------------------------------- 1 | #################################################### 2 | # # 3 | # DARK # 4 | # # 5 | #################################################### 6 | #text 7 | primary-text-color: '#DDDDDD' 8 | 9 | #main interface colors 10 | primary-color: '#89B3F8' 11 | google-red : '#F18B82' 12 | google-green : '#80C994' 13 | google-yellow : '#FCD663' 14 | google-blue : '#89B3F8' 15 | google-violet : '#BB86FC' 16 | google-grey: '#BBBBBB' 17 | color-red: 241, 139, 130 18 | color-green: 128, 201, 148 19 | color-yellow: 252, 214, 99 20 | color-blue : 137, 179, 248 21 | color-theme : 221,221,221 22 | color-purple : 102, 31, 255 23 | color-grey : 187, 187, 187 24 | color-pink : 233, 30, 99 25 | color-background-yellow : 'var(--color-yellow)' 26 | color-background-blue : 'var(--color-blue)' 27 | color-background-green : 'var(--color-green)' 28 | color-background-red : 'var(--color-red)' 29 | color-yellow-text: 'var(--color-yellow)' 30 | color-blue-text: 'var(--color-blue)' 31 | color-green-text: 'var(--color-green)' 32 | color-red-text: 'var(--color-red)' 33 | opacity-bg: '0.1' 34 | 35 | #floating button text color 36 | mdc-theme-on-secondary: 'var(--card-background-color)' 37 | 38 | #background and sidebar 39 | card-background-color: '#1D1D1D' 40 | primary-background-color: '#121212' 41 | secondary-background-color: '#121212' 42 | 43 | #header 44 | app-header-text-color: 'var(--primary-text-color)' 45 | app-header-background-color: 'var(--primary-background-color)' 46 | paper-tabs-selection-bar-color: 'var(--primary-text-color)' 47 | 48 | #Sidebar 49 | sidebar-selected-text-color: 'rgb(var(--color-blue))' 50 | sidebar-selected-icon-color: 'rgb(var(--color-blue))' 51 | 52 | #Slider 53 | slider-color: 'rgb(var(--color-blue))' 54 | slider-bar-color: 'rgba(var(--color-blue),0.38)' 55 | 56 | # card 57 | box-shadow: 'none' 58 | 59 | #media player 60 | mini-media-player-accent-color: 'var(--google-blue)' 61 | 62 | # Journal 63 | state-icon-color: 'rgb(var(--color-theme))' 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /configuration/themes/mobile/mobile_light.yaml: -------------------------------------------------------------------------------- 1 | #################################################### 2 | # # 3 | # LIGHT # 4 | # # 5 | #################################################### 6 | #text 7 | primary-text-color: '#212121' 8 | 9 | #main interface colors 10 | primary-color: '#434343' 11 | google-red : '#F54436' 12 | google-green : '#01C852' 13 | google-yellow : '#FF9101' 14 | google-blue : '#3D5AFE' 15 | google-violet : '#661FFF' 16 | google-grey: '#BBBBBB' 17 | color-red : 245, 68, 54 18 | color-green : 1, 200, 82 19 | color-yellow : 255, 145, 1 20 | color-blue : 61, 90, 254 21 | color-purple : 102, 31, 255 22 | color-grey : 187, 187, 187 23 | color-pink : 233, 30, 99 24 | color-theme : 51,51,51 25 | color-background-yellow : 250, 250, 250 26 | color-background-blue : 250, 250, 250 27 | color-background-green : 250, 250, 250 28 | color-background-red : 250, 250, 250 29 | 30 | color-yellow-text: 'var(--primary-text-color)' 31 | color-blue-text: 'var(--primary-text-color)' 32 | color-green-text: 'var(--primary-text-color)' 33 | color-red-text: 'var(--primary-text-color)' 34 | opacity-bg: '1' 35 | 36 | #background and sidebar 37 | card-background-color: '#FAFAFA' 38 | primary-background-color: '#EFEFEF' 39 | secondary-background-color: '#EFEFEF' 40 | 41 | #header 42 | app-header-text-color: 'var(--primary-text-color)' 43 | app-header-background-color: 'var(--primary-background-color)' 44 | # paper-tabs-selection-bar-color: 'var(--primary-text-color)' 45 | 46 | #slider 47 | slider-color: 'rgb(var(--color-blue))' 48 | slider-bar-color: 'rgba(var(--color-blue),0.38)' 49 | 50 | #cards 51 | box-shadow: '0px 2px 4px 0px rgba(0,0,0,0.16)' 52 | ha-card-box-shadow: 'var(--box-shadow)' 53 | 54 | #sidebar 55 | sidebar-selected-text-color: 'var(--google-red)' 56 | sidebar-selected-icon-color: 'var(--google-red)' 57 | sidebar-text-color: '#80868b' 58 | 59 | #switch 60 | switch-checked-color: 'var(--google-blue)' 61 | 62 | #media player 63 | mini-media-player-accent-color: 'var(--google-red)' 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /lovelace/resources/resources.yaml: -------------------------------------------------------------------------------- 1 | - type: module 2 | url: /hacsfiles/mini-graph-card/mini-graph-card-bundle.js 3 | - type: module 4 | url: /hacsfiles/mini-media-player/mini-media-player-bundle.js 5 | - type: module 6 | url: /hacsfiles/button-card/button-card.js 7 | - type: module 8 | url: /hacsfiles/lovelace-card-mod/card-mod.js 9 | - type: module 10 | url: /hacsfiles/swipe-card/swipe-card.js 11 | - type: module 12 | url: /hacsfiles/vertical-stack-in-card/vertical-stack-in-card.js 13 | - type: module 14 | url: /hacsfiles/lovelace-state-switch/state-switch.js 15 | - type: module 16 | url: /hacsfiles/lovelace-auto-entities/auto-entities.js 17 | - type: module 18 | url: /hacsfiles/ha-slider-card/slider-card.js -------------------------------------------------------------------------------- /lovelace/views/01_home.yaml: -------------------------------------------------------------------------------- 1 | - title: Home 2 | icon: 'mdi:home-variant' 3 | path: home 4 | cards: 5 | - cards: 6 | - cards: 7 | - template: edge 8 | type: 'custom:button-card' 9 | - template: chips_temperature 10 | type: 'custom:button-card' 11 | - template: chips_icon 12 | label: Activée 13 | variables: 14 | icon: "mdi:shield-check" 15 | type: 'custom:button-card' 16 | - template: chips_localisation_present 17 | type: 'custom:button-card' 18 | - card: 19 | entity: input_boolean.invite_present 20 | template: chips 21 | label : "😃" 22 | type: 'custom:button-card' 23 | conditions: 24 | - entity: input_boolean.invite_present 25 | state_not: 'off' 26 | type: conditional 27 | - card: 28 | entity: input_boolean.mode_vacances 29 | template: chips 30 | label : "⛱️" 31 | type: 'custom:button-card' 32 | conditions: 33 | - entity: input_boolean.mode_vacances 34 | state_not: 'off' 35 | type: conditional 36 | - template: edge 37 | type: 'custom:button-card' 38 | type: horizontal-stack 39 | 40 | #################################################### 41 | # # 42 | # SCENES # 43 | # # 44 | #################################################### 45 | - type: custom:state-switch 46 | entity: user 47 | default: default 48 | states: 49 | Thomas: 50 | type: vertical-stack 51 | cards: 52 | - type: 'custom:button-card' 53 | name: Scènes 54 | template: title 55 | - cards: 56 | - template: edge 57 | type: 'custom:button-card' 58 | - entity: sensor.present 59 | template: scene_blue 60 | variables: 61 | state: "Present" 62 | type: 'custom:button-card' 63 | - entity: sensor.absent 64 | template: scene_green 65 | variables: 66 | state: "Absent" 67 | type: 'custom:button-card' 68 | - entity: sensor.travail 69 | template: scene_green 70 | variables: 71 | state: "Travail" 72 | type: 'custom:button-card' 73 | - entity: sensor.nuit 74 | template: 75 | - scene 76 | - blue 77 | tap_action: 78 | action: more-info 79 | entity: input_boolean.thomas_nuit 80 | type: 'custom:button-card' 81 | - template: edge 82 | type: 'custom:button-card' 83 | type: horizontal-stack 84 | 85 | #################################################### 86 | # # 87 | # PS4 # 88 | # # 89 | #################################################### 90 | 91 | - card: 92 | cards: 93 | - type: 'custom:button-card' 94 | name: Media 95 | template: title 96 | - cards: 97 | - template: edge 98 | type: 'custom:button-card' 99 | - artwork: full-cover 100 | entity: media_player.playstation_4 101 | style: | 102 | :host { 103 | --ha-card-border-radius: var(--border-radius); 104 | --ha-card-box-shadow: var(--box-shadow); 105 | } 106 | type: 'custom:mini-media-player' 107 | - template: edge 108 | type: 'custom:button-card' 109 | type: horizontal-stack 110 | type: vertical-stack 111 | conditions: 112 | - entity: media_player.playstation_4 113 | state_not: 'unknown' 114 | type: conditional 115 | 116 | #################################################### 117 | # # 118 | # MEDIA # 119 | # # 120 | #################################################### 121 | 122 | - card: 123 | cards: 124 | - type: 'custom:button-card' 125 | name: Media 126 | template: title 127 | - cards: 128 | - template: edge 129 | type: 'custom:button-card' 130 | 131 | 132 | - artwork: full-cover 133 | entity: media_player.cuisine 134 | style: | 135 | :host { 136 | --ha-card-border-radius: var(--border-radius); 137 | --ha-card-box-shadow: var(--box-shadow); 138 | } 139 | type: 'custom:mini-media-player' 140 | - template: edge 141 | type: 'custom:button-card' 142 | type: horizontal-stack 143 | type: vertical-stack 144 | conditions: 145 | - entity: media_player.cuisine 146 | state_not: 'off' 147 | type: conditional 148 | 149 | #################################################### 150 | # # 151 | # SALON # 152 | # # 153 | #################################################### 154 | - type: 'custom:button-card' 155 | name: Salon 156 | label: '4 appareils' 157 | template: title 158 | - cards: 159 | - template: edge 160 | type: 'custom:button-card' 161 | - type: grid 162 | columns: 2 163 | square: false 164 | cards: 165 | - entity: light.hue_light_table 166 | name: Principale 167 | template: 168 | - icon_info_bg 169 | - light 170 | type: 'custom:button-card' 171 | 172 | - entity: switch.shelly_prise_salon 173 | name: Prise 174 | template: 175 | - icon_info_bg 176 | - outlet 177 | label: |- 178 | [[[ if (entity.state =='on') 179 | var etat = "On • " + states["sensor.shelly_prise_salon_conso"].state + "W"; 180 | else 181 | var etat = "Off"; 182 | return etat ; ]]] 183 | type: 'custom:button-card' 184 | 185 | - entity: binary_sensor.fibaro_multisensor_salon_mouvement 186 | name: Mouvement 187 | icon: 'mdi:run' 188 | template: 189 | - icon_info_bg 190 | - binary_sensor 191 | type: 'custom:button-card' 192 | 193 | - entity: climate.thermostat 194 | name: Thermostat 195 | template: 196 | - icon_info_bg 197 | - thermostat 198 | type: 'custom:button-card' 199 | 200 | - entity: switch.nas 201 | name: NAS 202 | template: 203 | - icon_info_bg 204 | - nas 205 | type: 'custom:button-card' 206 | 207 | - entity: switch.shelly_prise_salon 208 | name: Chauffe eau 209 | template: 210 | - icon_info_bg 211 | - water_heater 212 | type: 'custom:button-card' 213 | 214 | - template: cover_buttons 215 | variables: 216 | entity: "cover.fibaro_cover_fenetre" 217 | name: "Fenêtre" 218 | type: 'custom:button-card' 219 | 220 | - template: cover_buttons 221 | variables: 222 | entity: "cover.fibaro_cover_balcon" 223 | name: "Balcon" 224 | type: 'custom:button-card' 225 | 226 | - entity: media_player.playstation_4 227 | template: 228 | - icon_info_bg 229 | - ps4 230 | type: 'custom:button-card' 231 | 232 | - template: edge 233 | type: 'custom:button-card' 234 | type: horizontal-stack 235 | 236 | #################################################### 237 | # # 238 | # CHAMBRE # 239 | # # 240 | #################################################### 241 | 242 | - type: 'custom:button-card' 243 | name: Chambre 244 | label: '2 appareils' 245 | template: title 246 | - cards: 247 | - template: edge 248 | type: 'custom:button-card' 249 | - type: grid 250 | columns: 2 251 | square: false 252 | cards: 253 | - entity: light.hue_light_chambre 254 | name: Lumière 255 | template: 256 | - icon_info_bg 257 | - light 258 | type: 'custom:button-card' 259 | 260 | - entity: light.hue_light_go_chambre 261 | template: 262 | - light_slider 263 | variables: 264 | entity: "light.hue_light_go_chambre" 265 | name: "Hue Go" 266 | type: 'custom:button-card' 267 | 268 | - template: edge 269 | type: 'custom:button-card' 270 | type: horizontal-stack 271 | 272 | #################################################### 273 | # # 274 | # CUISINE # 275 | # # 276 | #################################################### 277 | 278 | - type: 'custom:button-card' 279 | name: Cuisine 280 | label: '2 appareils' 281 | template: title 282 | - cards: 283 | - template: edge 284 | type: 'custom:button-card' 285 | - type: grid 286 | columns: 2 287 | square: false 288 | cards: 289 | - entity: light.cuisine 290 | name: Lumière 291 | template: 292 | - icon_info_bg 293 | - light 294 | type: 'custom:button-card' 295 | - entity: media_player.cuisine 296 | name: Enceintes 297 | template: 298 | - icon_info_bg 299 | - media 300 | type: 'custom:button-card' 301 | - template: edge 302 | type: 'custom:button-card' 303 | type: horizontal-stack 304 | 305 | #################################################### 306 | # # 307 | # SALLE DE BAIN # 308 | # # 309 | #################################################### 310 | - type: 'custom:button-card' 311 | name: Salle de bain 312 | label: '1 appareils' 313 | template: title 314 | - cards: 315 | - template: edge 316 | type: 'custom:button-card' 317 | - type: grid 318 | columns: 2 319 | square: false 320 | cards: 321 | - entity: light.hue_light_salle_de_bain 322 | name: Lumière 323 | template: 324 | - icon_info_bg 325 | - light 326 | type: 'custom:button-card' 327 | - template: edge 328 | type: 'custom:button-card' 329 | type: horizontal-stack 330 | 331 | type: vertical-stack 332 | -------------------------------------------------------------------------------- /lovelace/views/02_temperature.yaml: -------------------------------------------------------------------------------- 1 | - title: temperature 2 | icon: 'mdi:thermometer' 3 | path: temperature 4 | cards: 5 | - cards: 6 | - cards: 7 | - template: edge 8 | type: 'custom:button-card' 9 | - template: chips_return 10 | type: 'custom:button-card' 11 | - template: chips_temperature 12 | type: 'custom:button-card' 13 | - template: edge 14 | type: 'custom:button-card' 15 | type: horizontal-stack 16 | - type: 'custom:button-card' 17 | name: Températures 18 | template: title 19 | - cards: 20 | - template: edge 21 | type: 'custom:button-card' 22 | - type: weather-forecast 23 | style: | 24 | ha-card { 25 | box-shadow: var(--box-shadow); 26 | border-radius: 20px; 27 | padding: 12px !important; 28 | } 29 | .icon-image{ 30 | min-width: 42px !important; 31 | margin-right: 12px !important; 32 | } 33 | .icon-image > *{ 34 | height: 42px !important; 35 | width: 42px; 36 | flex: 0 0 42px !important; 37 | } 38 | .state { 39 | font-size: 14px !important; 40 | font-weight: bold; 41 | } 42 | .name{ 43 | font-weight: bolder; 44 | font-size: 12px !important; 45 | filter: opacity(40%); 46 | color: var(--primary-text-color) !important; 47 | } 48 | .temp{ 49 | font-size: 14px !important; 50 | font-weight: bold; 51 | margin-right: 14px !important; 52 | } 53 | .attribute{ 54 | font-size: 12px !important; 55 | font-weight: bolder; 56 | filter: opacity(40%); 57 | color: var(--primary-text-color) !important; 58 | } 59 | span{ 60 | font-size: 14px !important; 61 | font-weight: bold; 62 | } 63 | entity: weather.dark_sky 64 | show_forecast : false 65 | name: Toulouse 66 | - template: edge 67 | type: 'custom:button-card' 68 | type: horizontal-stack 69 | - type: 'custom:button-card' 70 | label: 'Salon' 71 | template: title 72 | 73 | - type: 'custom:button-card' 74 | label: 'Intérieur' 75 | template: title 76 | 77 | - cards: 78 | - template: edge 79 | type: 'custom:button-card' 80 | - type: grid 81 | columns: 2 82 | square: false 83 | cards: 84 | - type: 'custom:button-card' 85 | template: graph 86 | variables: 87 | entity: "sensor.fibaro_multisensor_salon_temperature" 88 | color: "var(--google-blue)" 89 | name: "Température" 90 | - type: 'custom:button-card' 91 | template: graph 92 | variables: 93 | entity: "sensor.fibaro_multisensor_salon_luminosite" 94 | color: "var(--google-blue)" 95 | name: "Luminosité" 96 | - type: 'custom:button-card' 97 | template: graph 98 | variables: 99 | entity: "sensor.xiaomi_multisensor_chambre_humidite" 100 | color: "var(--google-blue)" 101 | name: "Humidité" 102 | 103 | - type: 'custom:button-card' 104 | template: graph 105 | variables: 106 | entity: "sensor.xiaomi_multisensor_chambre_pression" 107 | color: "var(--google-blue)" 108 | name: "Pression" 109 | - template: edge 110 | type: 'custom:button-card' 111 | type: horizontal-stack 112 | 113 | - type: 'custom:button-card' 114 | label: 'Extérieur' 115 | template: title 116 | 117 | - cards: 118 | - template: edge 119 | type: 'custom:button-card' 120 | - type: grid 121 | columns: 2 122 | square: false 123 | cards: 124 | - type: 'custom:button-card' 125 | template: graph 126 | variables: 127 | entity: "sensor.fibaro_multisensor_balcon_temperature" 128 | color: "var(--google-green)" 129 | name: "Température" 130 | 131 | - type: 'custom:button-card' 132 | template: graph 133 | variables: 134 | entity: "sensor.fibaro_multisensor_balcon_luminosite" 135 | color: "var(--google-green)" 136 | name: "Luminosité" 137 | - template: edge 138 | type: 'custom:button-card' 139 | type: horizontal-stack 140 | 141 | type: vertical-stack 142 | 143 | -------------------------------------------------------------------------------- /lovelace/views/03_consommation.yaml: -------------------------------------------------------------------------------- 1 | - title: Consommation 2 | icon: 'mdi:flash' 3 | path: consommation 4 | cards: 5 | - cards: 6 | - cards: 7 | - template: edge 8 | type: 'custom:button-card' 9 | - template: chips_return 10 | type: 'custom:button-card' 11 | - template: edge 12 | type: 'custom:button-card' 13 | type: horizontal-stack 14 | 15 | - type: 'custom:button-card' 16 | name: Batterie 17 | template: title 18 | 19 | - cards: 20 | - template: edge 21 | type: 'custom:button-card' 22 | - type: 'custom:auto-entities' 23 | sort: 24 | method: state 25 | numeric: true 26 | card: 27 | type: grid 28 | columns: 1 29 | square: false 30 | card_param: cards 31 | filter: 32 | exclude: null 33 | include: 34 | - entity_id: sensor.*battery_level 35 | options: 36 | type: 'custom:button-card' 37 | template: 38 | - icon_info_bg 39 | - generic 40 | - template: edge 41 | type: 'custom:button-card' 42 | type: horizontal-stack 43 | type: vertical-stack -------------------------------------------------------------------------------- /lovelace/views/04_localisation.yaml: -------------------------------------------------------------------------------- 1 | - title: Localisation 2 | icon: 'mdi:map-marker' 3 | path: localisation 4 | cards: 5 | - cards: 6 | - cards: 7 | - template: bordures 8 | type: 'custom:button-card' 9 | - template: return_button 10 | type: 'custom:button-card' 11 | - template: pilule_localisation_present 12 | type: 'custom:button-card' 13 | - template: pilule_localisation_absent 14 | type: 'custom:button-card' 15 | - template: pilule_localisation_nuit 16 | type: 'custom:button-card' 17 | - card: 18 | entity: input_boolean.invite_present 19 | template: pilule 20 | label : "😃" 21 | type: 'custom:button-card' 22 | conditions: 23 | - entity: input_boolean.invite_present 24 | state_not: 'off' 25 | type: conditional 26 | - card: 27 | entity: input_boolean.mode_vacances 28 | template: pilule 29 | label : "⛱️" 30 | type: 'custom:button-card' 31 | conditions: 32 | - entity: input_boolean.mode_vacances 33 | state_not: 'off' 34 | type: conditional 35 | - template: bordures 36 | type: 'custom:button-card' 37 | type: horizontal-stack 38 | 39 | #################################################### 40 | # # 41 | # LOCALISATION # 42 | # # 43 | #################################################### 44 | 45 | - type: 'custom:button-card' 46 | name: Localisation 47 | label: '2 personnes' 48 | template: titre 49 | - cards: 50 | - template: bordures 51 | type: 'custom:button-card' 52 | - type: grid 53 | columns: 2 54 | square: false 55 | cards: 56 | - entity: input_select.localisation_thomas 57 | variables: 58 | personne: "thomas" 59 | template: 60 | - icon_info_bg 61 | - personne-thomas 62 | name: Thomas 63 | type: 'custom:button-card' 64 | - entity: input_select.localisation_milena 65 | template: 66 | - icon_info_bg 67 | - personne-milena 68 | name: Miléna 69 | type: 'custom:button-card' 70 | 71 | - template: bordures 72 | type: 'custom:button-card' 73 | 74 | type: horizontal-stack 75 | - type: 'custom:button-card' 76 | label: 'Modes' 77 | template: titre 78 | - cards: 79 | - template: bordures 80 | type: 'custom:button-card' 81 | - type: grid 82 | columns: 2 83 | square: false 84 | cards: 85 | - entity: input_boolean.invite_present 86 | template: 87 | - icon_info_bg 88 | - personne-invite 89 | type: 'custom:button-card' 90 | - entity: input_boolean.mode_vacances 91 | name: "Vacances" 92 | show_last_changed: false 93 | label: > 94 | [[[return entity.state]]] 95 | template: 96 | - icon_info_bg 97 | - mouvement 98 | type: 'custom:button-card' 99 | icon: 'mdi:white-balance-sunny' 100 | - template: bordures 101 | type: 'custom:button-card' 102 | 103 | type: horizontal-stack 104 | type: vertical-stack 105 | 106 | -------------------------------------------------------------------------------- /screenshots/anatomy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/anatomy.png -------------------------------------------------------------------------------- /screenshots/binary_sensor-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/binary_sensor-1.png -------------------------------------------------------------------------------- /screenshots/binary_sensor-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/binary_sensor-2.png -------------------------------------------------------------------------------- /screenshots/cards.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/cards.png -------------------------------------------------------------------------------- /screenshots/chips.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/chips.png -------------------------------------------------------------------------------- /screenshots/chips_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/chips_icon.png -------------------------------------------------------------------------------- /screenshots/chips_localisation_present.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/chips_localisation_present.png -------------------------------------------------------------------------------- /screenshots/chips_return.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/chips_return.png -------------------------------------------------------------------------------- /screenshots/chips_temperature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/chips_temperature.png -------------------------------------------------------------------------------- /screenshots/cover_buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/cover_buttons.png -------------------------------------------------------------------------------- /screenshots/entity_graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/entity_graph.png -------------------------------------------------------------------------------- /screenshots/generic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/generic.png -------------------------------------------------------------------------------- /screenshots/light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/light.png -------------------------------------------------------------------------------- /screenshots/light_slider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/light_slider.png -------------------------------------------------------------------------------- /screenshots/media.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/media.png -------------------------------------------------------------------------------- /screenshots/outlet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/outlet.png -------------------------------------------------------------------------------- /screenshots/person.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/person.png -------------------------------------------------------------------------------- /screenshots/playstation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/playstation.png -------------------------------------------------------------------------------- /screenshots/power_consumption.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/power_consumption.png -------------------------------------------------------------------------------- /screenshots/thermostat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/thermostat.png -------------------------------------------------------------------------------- /screenshots/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/title.png -------------------------------------------------------------------------------- /screenshots/water-heater.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/screenshots/water-heater.png -------------------------------------------------------------------------------- /ui-lovelace.yaml: -------------------------------------------------------------------------------- 1 | button_card_templates: !include lovelace/button_card_templates/button_card_templates.yaml 2 | title: 'Home' 3 | views: !include_dir_merge_list lovelace/views/ 4 | 5 | -------------------------------------------------------------------------------- /www/community/button-card/button-card.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/www/community/button-card/button-card.js.gz -------------------------------------------------------------------------------- /www/community/ha-slider-card/slider-card.js: -------------------------------------------------------------------------------- 1 | import { 2 | LitElement, 3 | html, 4 | css 5 | } from "https://unpkg.com/lit-element@2.0.1/lit-element.js?module"; 6 | class SliderCard extends LitElement { 7 | 8 | static get properties() { 9 | return { 10 | hass: {}, 11 | config: {}, 12 | active: {} 13 | }; 14 | } 15 | 16 | constructor() { 17 | super(); 18 | // console.log("SLIDER-CARD V36 INSTALLED--------------------------------------------------------------"); 19 | } 20 | 21 | render() { 22 | // Size Variables 23 | var minBar = this.config.minBar ? this.config.minBar : 0; 24 | var maxBar = this.config.maxBar ? this.config.maxBar : 100; 25 | var minSet = this.config.minSet ? this.config.minSet : 0; 26 | var maxSet = this.config.maxSet ? this.config.maxSet : 100; 27 | var width = this.config.width ? this.config.width : "100%"; 28 | var height = this.config.height ? this.config.height : "50px"; 29 | var radius = this.config.radius ? this.config.radius : "4px"; 30 | var top = this.config.top ? this.config.top : "0px"; 31 | var bottom = this.config.bottom ? this.config.bottom : "0px"; 32 | var right = this.config.right ? this.config.right : "0px"; 33 | var left = this.config.left ? this.config.left : "0px"; 34 | var rotate = this.config.rotate ? this.config.rotate : "0"; 35 | var containerHeight = this.config.containerHeight ? this.config.containerHeight : height; 36 | if (rotate != "0") { 37 | rotate = rotate + "deg"; 38 | } 39 | // Slider Background Color Variables 40 | var mainSliderColor = this.config.mainSliderColor ? this.config.mainSliderColor : "var(--accent-color)"; 41 | var secondarySliderColor = this.config.secondarySliderColor ? this.config.secondarySliderColor : "#4d4d4d"; 42 | var mainSliderColorOff = this.config.mainSliderColorOff ? this.config.mainSliderColorOff : "#636363"; 43 | var secondarySliderColorOff = this.config.secondarySliderColorOff ? this.config.secondarySliderColorOff : "#4d4d4d"; 44 | var border = this.config.border ? this.config.border : "0"; 45 | // Slider Thumb Variables 46 | var thumbWidth = this.config.thumbWidth ? this.config.thumbWidth : "25px"; 47 | var thumbHeight = this.config.thumbHeight ? this.config.thumbHeight : "80px"; 48 | var thumbColor = this.config.thumbColor ? this.config.thumbColor : "#FFFFFF"; 49 | var thumbColorOff = this.config.thumbColorOff ? this.config.thumbColorOff : "#969696"; 50 | var thumbHorizontalPadding = this.config.thumbHorizontalPadding ? this.config.thumbHorizontalPadding : "10px"; 51 | var thumbVerticalPadding = this.config.thumbVerticalPadding ? this.config.thumbVerticalPadding : "20px"; 52 | var thumbTop = this.config.thumpTop ? this.config.thumpTop : "calc((var(--slider-width) - var(--thumb-height)) / 2)"; 53 | var thumbBorderRight = this.config.thumbBorderRight ? this.config.thumbBorderRight : "var(--thumb-horizontal-padding) solid var(--slider-main-color)"; 54 | var thumbBorderLeft = this.config.thumbBorderLeft ? this.config.thumbBorderLeft : "var(--thumb-horizontal-padding) solid var(--slider-main-color)"; 55 | var thumbBorderTop = this.config.thumbBorderTop ? this.config.thumbBorderTop : "var(--thumb-vertical-padding) solid var(--slider-main-color)"; 56 | var thumbBorderBotton = this.config.thumbBorderBotton ? this.config.thumbBorderBotton : "var(--thumb-vertical-padding) solid var(--slider-main-color)"; 57 | // top: calc((var(--slider-width) - var(--thumb-height)) / 2); 58 | // border-right: var(--thumb-horizontal-padding) solid var(--slider-main-color); 59 | // border-left: var(--thumb-horizontal-padding) solid var(--slider-main-color); 60 | // border-top: var(--thumb-vertical-padding) solid var(--slider-main-color); 61 | // border-bottom: var(--thumb-vertical-padding) solid var(--slider-main-color); 62 | 63 | 64 | var entity = this.config.entity; 65 | var entityClass = this.hass.states[entity] 66 | 67 | var isLight = false; 68 | var isInputNumber = false; 69 | var isMediaPlayer= false; 70 | var isCover = false; 71 | var isFan = false; 72 | var isSwitch = false; 73 | var isLock = false; 74 | 75 | // Check if entity is light or input_number 76 | if (this.config.entity.includes("light.")) { 77 | isLight = true; 78 | var step = this.config.step ? this.config.step: "1"; 79 | } 80 | else if (this.config.entity.includes("input_number.")) { 81 | isInputNumber = true; 82 | var step = this.config.step ? this.config.step: entityClass.attributes.step; 83 | } 84 | else if (this.config.entity.includes("media_player.")) { 85 | isMediaPlayer = true; 86 | var step = this.config.step ? this.config.step: "1"; 87 | } 88 | else if (this.config.entity.includes("cover.")) { 89 | isCover = true; 90 | var step = this.config.step ? this.config.step: "1"; 91 | } 92 | else if (this.config.entity.includes("fan.")) { 93 | isFan = true; 94 | var step = this.config.step ? this.config.step: "1"; 95 | } 96 | else if (this.config.entity.includes("switch.")) { 97 | isSwitch = true; 98 | var step = this.config.step ? this.config.step: "1"; 99 | } 100 | else if (this.config.entity.includes("lock.")) { 101 | isLock = true; 102 | var step = this.config.step ? this.config.step: "1"; 103 | } 104 | 105 | var styleStr = ` 106 | --slider-width: ${width}; 107 | --slider-width-inverse: -${width}; 108 | --slider-height: ${height}; 109 | --slider-main-color: ${(entityClass.state === "off" || entityClass.state === "locked" || entityClass.state == undefined) ? "var(--slider-main-color-off)" : "var(--slider-main-color-on)"}; 110 | --slider-main-color-on: ${mainSliderColor}; 111 | --slider-main-color-off: ${mainSliderColorOff}; 112 | --slider-secondary-color: ${(entityClass.state === "off" || entityClass.state === "locked" || entityClass.state == undefined) ? "var(--slider-secondary-color-off)" : "var(--slider-secondary-color-on)"}; 113 | --slider-secondary-color-on: ${secondarySliderColor}; 114 | --slider-secondary-color-off: ${secondarySliderColorOff}; 115 | --slider-radius: ${radius}; 116 | --border: ${border}; 117 | 118 | --thumb-width: ${thumbWidth}; 119 | --thumb-height: ${thumbHeight}; 120 | --thumb-color: ${(entityClass.state === "off" || entityClass.state == undefined) ? "var(--thumb-color-off)" : "var(--thumb-color-on)"}; 121 | --thumb-color-on: ${thumbColor}; 122 | --thumb-color-off: ${thumbColorOff}; 123 | --thumb-horizontal-padding: ${thumbHorizontalPadding}; 124 | --thumb-vertical-padding: ${thumbVerticalPadding}; 125 | 126 | --rotate: ${rotate}; 127 | --top: ${top}; 128 | --bottom: ${bottom}; 129 | --right: ${right}; 130 | --left: ${left}; 131 | --container-height: ${containerHeight}; 132 | --thumb-top: ${thumbTop}; 133 | --thumb-border-right: ${thumbBorderRight}; 134 | --thumb-border-left: ${thumbBorderLeft}; 135 | --thumb-border-top: ${thumbBorderTop}; 136 | --thumb-border-bottom: ${thumbBorderBotton}; 137 | `; 138 | if (isLight) { 139 | if (this.config.function == "Warmth") { 140 | return html` 141 | 142 |
143 | this._setWarmth(entityClass, e.target, minSet, maxSet)}> 144 |
145 |
146 | `; 147 | } 148 | else { 149 | return html` 150 | 151 |
152 | this._setBrightness(entityClass, e.target, minSet, maxSet)}> 153 |
154 |
155 | `; 156 | } 157 | } 158 | 159 | if (isInputNumber) { 160 | return html` 161 | 162 |
163 | this._setInputNumber(entityClass, e.target, minSet, maxSet)}> 164 |
165 |
166 | `; 167 | } 168 | 169 | if (isMediaPlayer) { 170 | var num = 0; 171 | if (entityClass.attributes.volume_level != undefined) { 172 | var num = Number(entityClass.attributes.volume_level * 100) 173 | } 174 | 175 | return html` 176 | 177 |
178 | this._setMediaVolume(entityClass, e.target, minSet, maxSet)}> 179 |
180 |
181 | `; 182 | } 183 | 184 | if (isCover) { 185 | return html` 186 | 187 |
188 | this._setCover(entityClass, e.target, minSet, maxSet)}> 189 |
190 |
191 | `; 192 | } 193 | 194 | if (isFan) { 195 | return html` 196 | 197 |
198 | this._setFan(entityClass, e.target, minSet, maxSet)}> 199 |
200 |
201 | `; 202 | } 203 | 204 | if (isSwitch) { 205 | return html` 206 | 207 |
208 | this._setSwitch(entityClass, e.target, minSet, maxSet, minBar, maxBar)}> 209 |
210 |
211 | `; 212 | } 213 | 214 | if (isLock) { 215 | return html` 216 | 217 |
218 | this._setLock(entityClass, e.target, minSet, maxSet, minBar, maxBar)}> 219 |
220 |
221 | `; 222 | } 223 | } 224 | 225 | 226 | updated() {} 227 | 228 | 229 | _setFan(entityClass, target, minSet, maxSet) { 230 | var value = target.value; 231 | if (value > maxSet) { 232 | var value = maxSet; 233 | } else if (value < minSet) { 234 | var value = minSet; 235 | } 236 | 237 | this.hass.callService("fan", "set_percentage", { 238 | entity_id: entityClass.entity_id, 239 | percentage: value 240 | }); 241 | 242 | target.value = value; 243 | } 244 | 245 | _setCover(entityClass, target, minSet, maxSet) { 246 | var value = target.value; 247 | if (value > maxSet) { 248 | var value = maxSet; 249 | } else if (value < minSet) { 250 | var value = minSet; 251 | } 252 | // console.log("Setting Cover to: " + value); 253 | // console.log("From Position: " + entityClass.attributes.current_position); 254 | this.hass.callService("cover", "set_cover_position", { 255 | entity_id: entityClass.entity_id, 256 | position: value 257 | }); 258 | 259 | target.value = value; 260 | } 261 | 262 | _setMediaVolume(entityClass, target, minSet, maxSet) { 263 | var value = target.value; 264 | if (value > maxSet) { 265 | var value = maxSet; 266 | } else if (value < minSet) { 267 | var value = minSet; 268 | } 269 | 270 | this.hass.callService("media_player", "volume_set", { 271 | entity_id: entityClass.entity_id, 272 | volume_level: value / 100 273 | }); 274 | 275 | target.value = value; 276 | } 277 | 278 | _setInputNumber(entityClass, number, minSet, maxSet) { 279 | var value = target.value; 280 | if (value > maxSet) { 281 | var value = maxSet; 282 | } else if (value < minSet) { 283 | var value = minSet; 284 | } 285 | 286 | this.hass.callService("input_number", "set_value", { 287 | entity_id: entityClass.entity_id, 288 | value: value 289 | }); 290 | 291 | target.value = value; 292 | } 293 | 294 | _setBrightness(entityClass, target, minSet, maxSet) { 295 | var value = target.value; 296 | if (value > maxSet) { 297 | var value = maxSet; 298 | } else if (value < minSet) { 299 | var value = minSet; 300 | } 301 | 302 | this.hass.callService("homeassistant", "turn_on", { 303 | entity_id: entityClass.entity_id, 304 | brightness: value * 2.55 305 | }); 306 | 307 | // console.dir(this) 308 | target.value = value; 309 | 310 | } 311 | 312 | _setWarmth(entityClass, target, minSet, maxSet) { 313 | var value = target.value; 314 | if (value > maxSet) { 315 | var value = maxSet; 316 | } else if (value < minSet) { 317 | var value = minSet; 318 | } 319 | 320 | this.hass.callService("homeassistant", "turn_on", { 321 | entity_id: entityClass.entity_id, 322 | color_temp: value 323 | }); 324 | 325 | target.value = value; 326 | } 327 | 328 | _setSwitch(entityClass, target, minSet, maxSet, minBar, maxBar) { 329 | var value = target.value; 330 | var threshold = Math.min(maxSet,maxBar) //pick lesser of the two 331 | if (Number(threshold) <= value) { 332 | this.hass.callService("homeassistant", "toggle", { 333 | entity_id: entityClass.entity_id 334 | }); 335 | } 336 | 337 | target.value = Number(Math.max(minSet, minBar)); 338 | } 339 | 340 | _setLock(entityClass, target, minSet, maxSet, minBar, maxBar) { 341 | var value = target.value; 342 | var threshold = Math.min(maxSet,maxBar) //pick lesser of the two 343 | if (Number(threshold) <= value) { 344 | var newLockState = entityClass.state === "locked" ? 'unlock' : 'lock' 345 | this.hass.callService("lock", newLockState, { 346 | entity_id: entityClass.entity_id 347 | }); 348 | } 349 | 350 | target.value = Number(Math.max(minSet, minBar)); 351 | } 352 | 353 | _switch(entityClass) { 354 | this.hass.callService("homeassistant", "toggle", { 355 | entity_id: entityClass.entity_id 356 | }); 357 | } 358 | 359 | _navigate(path) { 360 | window.location.href = path; 361 | } 362 | 363 | setConfig(config) { 364 | if (!config.entity) { 365 | throw new Error("You need to define entity"); 366 | } 367 | 368 | if (!config.entity.includes("input_number.") && !config.entity.includes("light.") && !config.entity.includes("media_player.") && !config.entity.includes("cover.") && !config.entity.includes("fan.") && !config.entity.includes("switch.") && !config.entity.includes("lock.") ) { 369 | throw new Error("Entity has to be a light, input_number, media_player, cover or a fan."); 370 | } 371 | 372 | this.config = config; 373 | } 374 | 375 | getCardSize() { 376 | return 0; 377 | } 378 | 379 | // -webkit-transform: rotate(270deg); 380 | // -moz-transform: rotate(270deg); 381 | // -o-transform: rotate(270deg); 382 | // -ms-transform: rotate(270deg); 383 | // transform: rotate(270deg); 384 | static get styles() { 385 | return css` 386 | .slider-container { 387 | height: var(--container-height); 388 | position: relative; 389 | overflow: hidden; 390 | border-radius: var(--slider-radius); 391 | } 392 | 393 | .slider-container input[type="range"] { 394 | outline: 0; 395 | border: var(--border); 396 | width: var(--slider-width); 397 | height: var(--slider-height); 398 | border-radius: var(--slider-radius); 399 | background-color: var(--slider-secondary-color); /*Remaining Slider color*/ 400 | margin: 0; 401 | transition: box-shadow 0.2s ease-in-out; 402 | overflow: hidden; 403 | -webkit-appearance: none; 404 | position: absolute; 405 | top: var(--top); 406 | bottom: var(--bottom); 407 | right: var(--right); 408 | left: var(--left); 409 | -webkit-transform: rotate(var(--rotate)); 410 | -moz-transform: rotate(var(--rotate)); 411 | -o-transform: rotate(var(--rotate)); 412 | -ms-transform: rotate(var(--rotate)); 413 | transform: rotate(var(--rotate)); 414 | } 415 | 416 | .slider-container input[type="range"]::-webkit-slider-runnable-track { 417 | height: var(--slider-height); 418 | -webkit-appearance: none; 419 | color: var(--slider-main-color); 420 | transition: box-shadow 0.2s ease-in-out; 421 | } 422 | 423 | .slider-container input[type="range"]::-webkit-slider-thumb { 424 | width: var(--thumb-width); 425 | height: var(--thumb-height); 426 | -webkit-appearance: none; 427 | cursor: ew-resize; 428 | border-radius: 0; 429 | transition: box-shadow 0.2s ease-in-out; 430 | position: relative; 431 | 432 | box-shadow: -3500px 0 0 3500px var(--slider-main-color), inset 0 0 0 25px var(--thumb-color); 433 | 434 | top: var(--thumb-top); 435 | border-right: var(--thumb-border-right); 436 | border-left: var(--thumb-border-left); 437 | border-top: var(--thumb-border-top); 438 | border-bottom: var(--thumb-border-bottom); 439 | } 440 | 441 | .slider-container input[type=range]::-moz-range-thumb { 442 | width: calc(var(--thumb-width) / 4); 443 | height: calc(var(--thumb-height) / 2); 444 | box-shadow: -3500px 10px 0 3500px var(--slider-main-color), inset 0 0 0 25px var(--thumb-color); 445 | top: var(--thumb-top); 446 | cursor: ew-resize; 447 | border-radius: 0; 448 | transition: box-shadow 0.2s ease-in-out; 449 | position: relative; 450 | border-radius: 0; 451 | border-right: var(--thumb-border-right); 452 | border-left: var(--thumb-border-left); 453 | border-top: var(--thumb-border-top); 454 | border-bottom: var(--thumb-border-bottom); 455 | } 456 | 457 | .slider-container input[type="range"]::-webkit-slider-thumb:hover { 458 | cursor: default; 459 | } 460 | 461 | .slider-container input[type="range"]:hover { 462 | cursor: default; 463 | } 464 | `; 465 | } 466 | 467 | } 468 | 469 | customElements.define('slider-card', SliderCard); 470 | -------------------------------------------------------------------------------- /www/community/ha-slider-card/slider-card.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/www/community/ha-slider-card/slider-card.js.gz -------------------------------------------------------------------------------- /www/community/lovelace-auto-entities/auto-entities.js: -------------------------------------------------------------------------------- 1 | function t(t,e,i,s){var n,o=arguments.length,r=o<3?e:null===s?s=Object.getOwnPropertyDescriptor(e,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(t,e,i,s);else for(var a=t.length-1;a>=0;a--)(n=t[a])&&(r=(o<3?n(r):o>3?n(e,i,r):n(e,i))||r);return o>3&&r&&Object.defineProperty(e,i,r),r}const e="undefined"!=typeof window&&null!=window.customElements&&void 0!==window.customElements.polyfillWrapFlushCallback,i=(t,e,i=null)=>{for(;e!==i;){const i=e.nextSibling;t.removeChild(e),e=i}},s=`{{lit-${String(Math.random()).slice(2)}}}`,n=`\x3c!--${s}--\x3e`,o=new RegExp(`${s}|${n}`);class r{constructor(t,e){this.parts=[],this.element=e;const i=[],n=[],r=document.createTreeWalker(e.content,133,null,!1);let l=0,h=-1,u=0;const{strings:p,values:{length:f}}=t;for(;u0;){const e=p[u],i=d.exec(e)[2],s=i.toLowerCase()+"$lit$",n=t.getAttribute(s);t.removeAttribute(s);const r=n.split(o);this.parts.push({type:"attribute",index:h,name:i,strings:r}),u+=r.length-1}}"TEMPLATE"===t.tagName&&(n.push(t),r.currentNode=t.content)}else if(3===t.nodeType){const e=t.data;if(e.indexOf(s)>=0){const s=t.parentNode,n=e.split(o),r=n.length-1;for(let e=0;e{const i=t.length-e.length;return i>=0&&t.slice(i)===e},l=t=>-1!==t.index,c=()=>document.createComment(""),d=/([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F "'>=/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/;function h(t,e){const{element:{content:i},parts:s}=t,n=document.createTreeWalker(i,133,null,!1);let o=p(s),r=s[o],a=-1,l=0;const c=[];let d=null;for(;n.nextNode();){a++;const t=n.currentNode;for(t.previousSibling===d&&(d=null),e.has(t)&&(c.push(t),null===d&&(d=t)),null!==d&&l++;void 0!==r&&r.index===a;)r.index=null!==d?-1:r.index-l,o=p(s,o),r=s[o]}c.forEach((t=>t.parentNode.removeChild(t)))}const u=t=>{let e=11===t.nodeType?0:1;const i=document.createTreeWalker(t,133,null,!1);for(;i.nextNode();)e++;return e},p=(t,e=-1)=>{for(let i=e+1;i"function"==typeof t&&f.has(t),_={},v={};class m{constructor(t,e,i){this.__parts=[],this.template=t,this.processor=e,this.options=i}update(t){let e=0;for(const i of this.__parts)void 0!==i&&i.setValue(t[e]),e++;for(const t of this.__parts)void 0!==t&&t.commit()}_clone(){const t=e?this.template.element.content.cloneNode(!0):document.importNode(this.template.element.content,!0),i=[],s=this.template.parts,n=document.createTreeWalker(t,133,null,!1);let o,r=0,a=0,c=n.nextNode();for(;rt}),b=` ${s} `;class w{constructor(t,e,i,s){this.strings=t,this.values=e,this.type=i,this.processor=s}getHTML(){const t=this.strings.length-1;let e="",i=!1;for(let o=0;o-1||i)&&-1===t.indexOf("--\x3e",r+1);const a=d.exec(t);e+=null===a?t+(i?b:n):t.substr(0,a.index)+a[1]+a[2]+"$lit$"+a[3]+s}return e+=this.strings[t],e}getTemplateElement(){const t=document.createElement("template");let e=this.getHTML();return void 0!==y&&(e=y.createHTML(e)),t.innerHTML=e,t}}const S=t=>null===t||!("object"==typeof t||"function"==typeof t),C=t=>Array.isArray(t)||!(!t||!t[Symbol.iterator]);class O{constructor(t,e,i){this.dirty=!0,this.element=t,this.name=e,this.strings=i,this.parts=[];for(let t=0;t{try{const t={get capture(){return N=!0,!1}};window.addEventListener("test",t,t),window.removeEventListener("test",t,t)}catch(t){}})();class T{constructor(t,e,i){this.value=void 0,this.__pendingValue=void 0,this.element=t,this.eventName=e,this.eventContext=i,this.__boundHandleEvent=t=>this.handleEvent(t)}setValue(t){this.__pendingValue=t}commit(){for(;g(this.__pendingValue);){const t=this.__pendingValue;this.__pendingValue=_,t(this)}if(this.__pendingValue===_)return;const t=this.__pendingValue,e=this.value,i=null==t||null!=e&&(t.capture!==e.capture||t.once!==e.once||t.passive!==e.passive),s=null!=t&&(null==e||i);i&&this.element.removeEventListener(this.eventName,this.__boundHandleEvent,this.__options),s&&(this.__options=k(t),this.element.addEventListener(this.eventName,this.__boundHandleEvent,this.__options)),this.value=t,this.__pendingValue=_}handleEvent(t){"function"==typeof this.value?this.value.call(this.eventContext||this.element,t):this.value.handleEvent(t)}}const k=t=>t&&(N?{capture:t.capture,passive:t.passive,once:t.once}:t.capture);function A(t){let e=M.get(t.type);void 0===e&&(e={stringsArray:new WeakMap,keyString:new Map},M.set(t.type,e));let i=e.stringsArray.get(t.strings);if(void 0!==i)return i;const n=t.strings.join(s);return i=e.keyString.get(n),void 0===i&&(i=new r(t,t.getTemplateElement()),e.keyString.set(n,i)),e.stringsArray.set(t.strings,i),i}const M=new Map,U=new WeakMap;const F=new class{handleAttributeExpressions(t,e,i,s){const n=e[0];if("."===n){return new j(t,e.slice(1),i).parts}if("@"===n)return[new T(t,e.slice(1),s.eventContext)];if("?"===n)return[new P(t,e.slice(1),i)];return new O(t,e,i).parts}handleTextExpression(t){return new x(t)}};"undefined"!=typeof window&&(window.litHtmlVersions||(window.litHtmlVersions=[])).push("1.3.0");const V=(t,...e)=>new w(t,e,"html",F),I=(t,e)=>`${t}--${e}`;let R=!0;void 0===window.ShadyCSS?R=!1:void 0===window.ShadyCSS.prepareTemplateDom&&(console.warn("Incompatible ShadyCSS version detected. Please update to at least @webcomponents/webcomponentsjs@2.0.2 and @webcomponents/shadycss@1.3.1."),R=!1);const D=t=>e=>{const i=I(e.type,t);let n=M.get(i);void 0===n&&(n={stringsArray:new WeakMap,keyString:new Map},M.set(i,n));let o=n.stringsArray.get(e.strings);if(void 0!==o)return o;const a=e.strings.join(s);if(o=n.keyString.get(a),void 0===o){const i=e.getTemplateElement();R&&window.ShadyCSS.prepareTemplateDom(i,t),o=new r(e,i),n.keyString.set(a,o)}return n.stringsArray.set(e.strings,o),o},q=["html","svg"],W=new Set,G=(t,e,i)=>{W.add(t);const s=i?i.element:document.createElement("template"),n=e.querySelectorAll("style"),{length:o}=n;if(0===o)return void window.ShadyCSS.prepareTemplateStyles(s,t);const r=document.createElement("style");for(let t=0;t{q.forEach((e=>{const i=M.get(I(e,t));void 0!==i&&i.keyString.forEach((t=>{const{element:{content:e}}=t,i=new Set;Array.from(e.querySelectorAll("style")).forEach((t=>{i.add(t)})),h(t,i)}))}))})(t);const a=s.content;i?function(t,e,i=null){const{element:{content:s},parts:n}=t;if(null==i)return void s.appendChild(e);const o=document.createTreeWalker(s,133,null,!1);let r=p(n),a=0,l=-1;for(;o.nextNode();)for(l++,o.currentNode===i&&(a=u(e),i.parentNode.insertBefore(e,i));-1!==r&&n[r].index===l;){if(a>0){for(;-1!==r;)n[r].index+=a,r=p(n,r);return}r=p(n,r)}}(i,r,a.firstChild):a.insertBefore(r,a.firstChild),window.ShadyCSS.prepareTemplateStyles(s,t);const l=a.querySelector("style");if(window.ShadyCSS.nativeShadow&&null!==l)e.insertBefore(l.cloneNode(!0),e.firstChild);else if(i){a.insertBefore(r,a.firstChild);const t=new Set;t.add(r),h(i,t)}};window.JSCompiler_renameProperty=(t,e)=>t;const z={toAttribute(t,e){switch(e){case Boolean:return t?"":null;case Object:case Array:return null==t?t:JSON.stringify(t)}return t},fromAttribute(t,e){switch(e){case Boolean:return null!==t;case Number:return null===t?null:Number(t);case Object:case Array:return JSON.parse(t)}return t}},L=(t,e)=>e!==t&&(e==e||t==t),B={attribute:!0,type:String,converter:z,reflect:!1,hasChanged:L};class H extends HTMLElement{constructor(){super(),this.initialize()}static get observedAttributes(){this.finalize();const t=[];return this._classProperties.forEach(((e,i)=>{const s=this._attributeNameForProperty(i,e);void 0!==s&&(this._attributeToPropertyMap.set(s,i),t.push(s))})),t}static _ensureClassProperties(){if(!this.hasOwnProperty(JSCompiler_renameProperty("_classProperties",this))){this._classProperties=new Map;const t=Object.getPrototypeOf(this)._classProperties;void 0!==t&&t.forEach(((t,e)=>this._classProperties.set(e,t)))}}static createProperty(t,e=B){if(this._ensureClassProperties(),this._classProperties.set(t,e),e.noAccessor||this.prototype.hasOwnProperty(t))return;const i="symbol"==typeof t?Symbol():`__${t}`,s=this.getPropertyDescriptor(t,i,e);void 0!==s&&Object.defineProperty(this.prototype,t,s)}static getPropertyDescriptor(t,e,i){return{get(){return this[e]},set(s){const n=this[t];this[e]=s,this.requestUpdateInternal(t,n,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this._classProperties&&this._classProperties.get(t)||B}static finalize(){const t=Object.getPrototypeOf(this);if(t.hasOwnProperty("finalized")||t.finalize(),this.finalized=!0,this._ensureClassProperties(),this._attributeToPropertyMap=new Map,this.hasOwnProperty(JSCompiler_renameProperty("properties",this))){const t=this.properties,e=[...Object.getOwnPropertyNames(t),..."function"==typeof Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(t):[]];for(const i of e)this.createProperty(i,t[i])}}static _attributeNameForProperty(t,e){const i=e.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof t?t.toLowerCase():void 0}static _valueHasChanged(t,e,i=L){return i(t,e)}static _propertyValueFromAttribute(t,e){const i=e.type,s=e.converter||z,n="function"==typeof s?s:s.fromAttribute;return n?n(t,i):t}static _propertyValueToAttribute(t,e){if(void 0===e.reflect)return;const i=e.type,s=e.converter;return(s&&s.toAttribute||z.toAttribute)(t,i)}initialize(){this._updateState=0,this._updatePromise=new Promise((t=>this._enableUpdatingResolver=t)),this._changedProperties=new Map,this._saveInstanceProperties(),this.requestUpdateInternal()}_saveInstanceProperties(){this.constructor._classProperties.forEach(((t,e)=>{if(this.hasOwnProperty(e)){const t=this[e];delete this[e],this._instanceProperties||(this._instanceProperties=new Map),this._instanceProperties.set(e,t)}}))}_applyInstanceProperties(){this._instanceProperties.forEach(((t,e)=>this[e]=t)),this._instanceProperties=void 0}connectedCallback(){this.enableUpdating()}enableUpdating(){void 0!==this._enableUpdatingResolver&&(this._enableUpdatingResolver(),this._enableUpdatingResolver=void 0)}disconnectedCallback(){}attributeChangedCallback(t,e,i){e!==i&&this._attributeToProperty(t,i)}_propertyToAttribute(t,e,i=B){const s=this.constructor,n=s._attributeNameForProperty(t,i);if(void 0!==n){const t=s._propertyValueToAttribute(e,i);if(void 0===t)return;this._updateState=8|this._updateState,null==t?this.removeAttribute(n):this.setAttribute(n,t),this._updateState=-9&this._updateState}}_attributeToProperty(t,e){if(8&this._updateState)return;const i=this.constructor,s=i._attributeToPropertyMap.get(t);if(void 0!==s){const t=i.getPropertyOptions(s);this._updateState=16|this._updateState,this[s]=i._propertyValueFromAttribute(e,t),this._updateState=-17&this._updateState}}requestUpdateInternal(t,e,i){let s=!0;if(void 0!==t){const n=this.constructor;i=i||n.getPropertyOptions(t),n._valueHasChanged(this[t],e,i.hasChanged)?(this._changedProperties.has(t)||this._changedProperties.set(t,e),!0!==i.reflect||16&this._updateState||(void 0===this._reflectingProperties&&(this._reflectingProperties=new Map),this._reflectingProperties.set(t,i))):s=!1}!this._hasRequestedUpdate&&s&&(this._updatePromise=this._enqueueUpdate())}requestUpdate(t,e){return this.requestUpdateInternal(t,e),this.updateComplete}async _enqueueUpdate(){this._updateState=4|this._updateState;try{await this._updatePromise}catch(t){}const t=this.performUpdate();return null!=t&&await t,!this._hasRequestedUpdate}get _hasRequestedUpdate(){return 4&this._updateState}get hasUpdated(){return 1&this._updateState}performUpdate(){if(!this._hasRequestedUpdate)return;this._instanceProperties&&this._applyInstanceProperties();let t=!1;const e=this._changedProperties;try{t=this.shouldUpdate(e),t?this.update(e):this._markUpdated()}catch(e){throw t=!1,this._markUpdated(),e}t&&(1&this._updateState||(this._updateState=1|this._updateState,this.firstUpdated(e)),this.updated(e))}_markUpdated(){this._changedProperties=new Map,this._updateState=-5&this._updateState}get updateComplete(){return this._getUpdateComplete()}_getUpdateComplete(){return this._updatePromise}shouldUpdate(t){return!0}update(t){void 0!==this._reflectingProperties&&this._reflectingProperties.size>0&&(this._reflectingProperties.forEach(((t,e)=>this._propertyToAttribute(e,this[e],t))),this._reflectingProperties=void 0),this._markUpdated()}updated(t){}firstUpdated(t){}}H.finalized=!0;const J=(t,e)=>"method"===e.kind&&e.descriptor&&!("value"in e.descriptor)?Object.assign(Object.assign({},e),{finisher(i){i.createProperty(e.key,t)}}):{kind:"field",key:Symbol(),placement:"own",descriptor:{},initializer(){"function"==typeof e.initializer&&(this[e.key]=e.initializer.call(this))},finisher(i){i.createProperty(e.key,t)}};function K(t){return(e,i)=>void 0!==i?((t,e,i)=>{e.constructor.createProperty(i,t)})(t,e,i):J(t,e)}function Y(t){return K({attribute:!1,hasChanged:null==t?void 0:t.hasChanged})}const Q=(t,e,i)=>{Object.defineProperty(e,i,t)},X=(t,e)=>({kind:"method",placement:"prototype",key:e.key,descriptor:t}),Z=window.ShadowRoot&&(void 0===window.ShadyCSS||window.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,tt=Symbol();class et{constructor(t,e){if(e!==tt)throw new Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t}get styleSheet(){return void 0===this._styleSheet&&(Z?(this._styleSheet=new CSSStyleSheet,this._styleSheet.replaceSync(this.cssText)):this._styleSheet=null),this._styleSheet}toString(){return this.cssText}}const it=(t,...e)=>{const i=e.reduce(((e,i,s)=>e+(t=>{if(t instanceof et)return t.cssText;if("number"==typeof t)return t;throw new Error(`Value passed to 'css' function must be a 'css' function result: ${t}. Use 'unsafeCSS' to pass non-literal values, but\n take care to ensure page security.`)})(i)+t[s+1]),t[0]);return new et(i,tt)};(window.litElementVersions||(window.litElementVersions=[])).push("2.4.0");const st={};class nt extends H{static getStyles(){return this.styles}static _getUniqueStyles(){if(this.hasOwnProperty(JSCompiler_renameProperty("_styles",this)))return;const t=this.getStyles();if(Array.isArray(t)){const e=(t,i)=>t.reduceRight(((t,i)=>Array.isArray(i)?e(i,t):(t.add(i),t)),i),i=e(t,new Set),s=[];i.forEach((t=>s.unshift(t))),this._styles=s}else this._styles=void 0===t?[]:[t];this._styles=this._styles.map((t=>{if(t instanceof CSSStyleSheet&&!Z){const e=Array.prototype.slice.call(t.cssRules).reduce(((t,e)=>t+e.cssText),"");return new et(String(e),tt)}return t}))}initialize(){super.initialize(),this.constructor._getUniqueStyles(),this.renderRoot=this.createRenderRoot(),window.ShadowRoot&&this.renderRoot instanceof window.ShadowRoot&&this.adoptStyles()}createRenderRoot(){return this.attachShadow({mode:"open"})}adoptStyles(){const t=this.constructor._styles;0!==t.length&&(void 0===window.ShadyCSS||window.ShadyCSS.nativeShadow?Z?this.renderRoot.adoptedStyleSheets=t.map((t=>t instanceof CSSStyleSheet?t:t.styleSheet)):this._needsShimAdoptedStyleSheets=!0:window.ShadyCSS.ScopingShim.prepareAdoptedCssText(t.map((t=>t.cssText)),this.localName))}connectedCallback(){super.connectedCallback(),this.hasUpdated&&void 0!==window.ShadyCSS&&window.ShadyCSS.styleElement(this)}update(t){const e=this.render();super.update(t),e!==st&&this.constructor.render(e,this.renderRoot,{scopeName:this.localName,eventContext:this}),this._needsShimAdoptedStyleSheets&&(this._needsShimAdoptedStyleSheets=!1,this.constructor._styles.forEach((t=>{const e=document.createElement("style");e.textContent=t.cssText,this.renderRoot.appendChild(e)})))}render(){return st}}function ot(){return document.querySelector("hc-main")?document.querySelector("hc-main").hass:document.querySelector("home-assistant")?document.querySelector("home-assistant").hass:void 0}nt.finalized=!0,nt.render=(t,e,s)=>{if(!s||"object"!=typeof s||!s.scopeName)throw new Error("The `scopeName` option is required.");const n=s.scopeName,o=U.has(e),r=R&&11===e.nodeType&&!!e.host,a=r&&!W.has(n),l=a?document.createDocumentFragment():e;if(((t,e,s)=>{let n=U.get(e);void 0===n&&(i(e,e.firstChild),U.set(e,n=new x(Object.assign({templateFactory:A},s))),n.appendInto(e)),n.setValue(t),n.commit()})(t,l,Object.assign({templateFactory:D(n)},s)),a){const t=U.get(l);U.delete(l);const s=t.value instanceof m?t.value.template:void 0;G(n,l,s),i(e,e.firstChild),e.appendChild(l),U.set(e,t)}!o&&r&&window.ShadyCSS.styleElement(e.host)};const rt="lovelace-player-device-id";function at(){if(!localStorage[rt]){const t=()=>Math.floor(1e5*(1+Math.random())).toString(16).substring(1);window.fully&&"function"==typeof fully.getDeviceId?localStorage[rt]=fully.getDeviceId():localStorage[rt]=`${t()}${t()}-${t()}${t()}`}return localStorage[rt]}let lt=at();const ct=new URLSearchParams(window.location.search);var dt;function ht(t){return!!String(t).includes("{%")||(!!String(t).includes("{{")||void 0)}ct.get("deviceID")&&null!==(dt=ct.get("deviceID"))&&("clear"===dt?localStorage.removeItem(rt):localStorage[rt]=dt,lt=at()),window.cardMod_template_cache=window.cardMod_template_cache||{};const ut=window.cardMod_template_cache;async function pt(t,e,i){const s=ot().connection,n=JSON.stringify([e,i]);let o=ut[n];o?(o.callbacks.has(t)||ft(t),t(o.value),o.callbacks.add(t)):(ft(t),t(""),i=Object.assign({user:ot().user.name,browser:lt,hash:location.hash.substr(1)||""},i),ut[n]=o={template:e,variables:i,value:"",callbacks:new Set([t]),unsubscribe:s.subscribeMessage((t=>function(t,e){const i=ut[t];i&&(i.value=e.result,i.callbacks.forEach((t=>t(e.result))))}(n,t)),{type:"render_template",template:e,variables:i})})}async function ft(t){let e;for(const[i,s]of Object.entries(ut))if(s.callbacks.has(t)){s.callbacks.delete(t),0==s.callbacks.size&&(e=s.unsubscribe,delete ut[i]);break}e&&await(await e)()}var gt;function _t(t,e){if("string"==typeof e&&"string"==typeof t&&(t.startsWith("/")&&t.endsWith("/")||-1!==t.indexOf("*"))){return t.startsWith("/")||(t=`/^${t=t.replace(/\./g,".").replace(/\*/g,".*")}$/`),new RegExp(t.slice(1,-1)).test(e)}if("string"==typeof t){if(t.startsWith("<="))return parseFloat(e)<=parseFloat(t.substr(2));if(t.startsWith(">="))return parseFloat(e)>=parseFloat(t.substr(2));if(t.startsWith("<"))return parseFloat(e)"))return parseFloat(e)>parseFloat(t.substr(1));if(t.startsWith("!"))return parseFloat(e)!=parseFloat(t.substr(1));if(t.startsWith("="))return parseFloat(e)==parseFloat(t.substr(1))}return t===e}window.autoEntities_cache=null!==(gt=window.autoEntities_cache)&&void 0!==gt?gt:{};const vt=window.autoEntities_cache;async function mt(t){var e;return vt.areas=null!==(e=vt.areas)&&void 0!==e?e:await t.callWS({type:"config/area_registry/list"}),vt.areas}async function yt(t){var e;return vt.devices=null!==(e=vt.devices)&&void 0!==e?e:await t.callWS({type:"config/device_registry/list"}),vt.devices}async function bt(t){var e;return vt.entities=null!==(e=vt.entities)&&void 0!==e?e:await t.callWS({type:"config/entity_registry/list"}),vt.entities}const wt={options:async()=>!0,sort:async()=>!0,domain:async(t,e,i)=>_t(e,i.entity_id.split(".")[0]),entity_id:async(t,e,i)=>_t(e,i.entity_id),state:async(t,e,i)=>_t(e,i.state),name:async(t,e,i)=>{var s;return _t(e,null===(s=i.attributes)||void 0===s?void 0:s.friendly_name)},group:async(t,e,i)=>{var s,n,o;return null===(o=null===(n=null===(s=t.states[e])||void 0===s?void 0:s.attributes)||void 0===n?void 0:n.entity_id)||void 0===o?void 0:o.includes(i.entity_id)},attributes:async(t,e,i)=>{for(const[t,s]of Object.entries(e)){let e=t.split(" ")[0],n=i.attributes;for(const t of e.split(":"))n=n?n[t]:void 0;if(void 0===n||!_t(s,n))return!1}return!0},not:async(t,e,i)=>!await St(t,e,i.entity_id),or:async(t,e,i)=>{for(const s of e)if(await St(t,s,i.entity_id))return!0;return!1},device:async(t,e,i)=>{const s=(await bt(t)).find((t=>t.entity_id===i.entity_id));if(!s)return!1;const n=(await yt(t)).find((t=>t.id===s.device_id));return!!n&&(_t(e,n.name_by_user)||_t(e,n.name))},area:async(t,e,i)=>{const s=(await bt(t)).find((t=>t.entity_id===i.entity_id));if(!s)return!1;let n=(await mt(t)).find((t=>t.area_id===s.area_id));if(n)return _t(e,n.name);const o=(await yt(t)).find((t=>t.id===s.device_id));return!!o&&(n=(await mt(t)).find((t=>t.area_id===o.area_id)),!!n&&_t(e,n.name))},last_changed:async(t,e,i)=>_t(e,((new Date).getTime()-new Date(i.last_changed).getTime())/6e4),last_updated:async(t,e,i)=>_t(e,((new Date).getTime()-new Date(i.last_updated).getTime())/6e4),last_triggered:async(t,e,i)=>{if(null==i.attributes.last_triggered)return!1;return _t(e,((new Date).getTime()-new Date(i.attributes.last_triggered).getTime())/6e4)}};async function St(t,e,i){var s;if(!t.states[i])return!1;for(let[n,o]of Object.entries(e))if(n=n.trim().split(" ")[0].trim(),!await(null===(s=wt[n])||void 0===s?void 0:s.call(wt,t,o,t.states[i])))return!1;return!0}function Ct(t,e,i){var s,n,o,r;const[a,l]=i.reverse?[-1,1]:[1,-1];return i.ignore_case&&(t=null!==(n=null===(s=null==t?void 0:t.toLowerCase)||void 0===s?void 0:s.call(t))&&void 0!==n?n:t,e=null!==(r=null===(o=null==e?void 0:e.toLowerCase)||void 0===o?void 0:o.call(e))&&void 0!==r?r:e),i.numeric&&(isNaN(parseFloat(t))&&isNaN(parseFloat(e))||(t=isNaN(parseFloat(t))?void 0:parseFloat(t),e=isNaN(parseFloat(e))?void 0:parseFloat(e))),void 0===t&&void 0===e?0:void 0===t?a:void 0===e?l:(i.reverse?-1:1)*String(t).localeCompare(String(e),void 0,i)}const Ot={none:()=>0,domain:(t,e,i)=>{var s,n;return Ct(null===(s=null==t?void 0:t.entity_id)||void 0===s?void 0:s.split(".")[0],null===(n=null==e?void 0:e.entity_id)||void 0===n?void 0:n.split(".")[0],i)},entity_id:(t,e,i)=>Ct(null==t?void 0:t.entity_id,null==e?void 0:e.entity_id,i),friendly_name:(t,e,i)=>{var s,n,o,r;return Ct((null===(s=null==t?void 0:t.attributes)||void 0===s?void 0:s.friendly_name)||(null===(n=null==t?void 0:t.entity_id)||void 0===n?void 0:n.split(".")[1]),(null===(o=null==e?void 0:e.attributes)||void 0===o?void 0:o.friendly_name)||(null===(r=null==e?void 0:e.entity_id)||void 0===r?void 0:r.split(".")[1]),i)},name:(t,e,i)=>{var s,n,o,r;return Ct((null===(s=null==t?void 0:t.attributes)||void 0===s?void 0:s.friendly_name)||(null===(n=null==t?void 0:t.entity_id)||void 0===n?void 0:n.split(".")[1]),(null===(o=null==e?void 0:e.attributes)||void 0===o?void 0:o.friendly_name)||(null===(r=null==e?void 0:e.entity_id)||void 0===r?void 0:r.split(".")[1]),i)},state:(t,e,i)=>Ct(null==t?void 0:t.state,null==e?void 0:e.state,i),attribute:(t,e,i)=>{var s;const[n,o]=(null==i?void 0:i.reverse)?[-1,1]:[1,-1];let r=null==t?void 0:t.attributes,a=null==e?void 0:e.attributes;for(const t of null===(s=null==i?void 0:i.attribute)||void 0===s?void 0:s.split(":")){if(void 0===r&&void 0===a)return 0;if(void 0===r)return n;if(void 0===a)return o;[r,a]=[r[t],a[t]]}return Ct(r,a,i)},last_changed:(t,e,i)=>{const[s,n]=(null==i?void 0:i.reverse)?[-1,1]:[1,-1];return null==(null==t?void 0:t.last_changed)&&null==(null==e?void 0:e.last_changed)?0:null==(null==t?void 0:t.last_changed)?s:null==(null==e?void 0:e.last_changed)?n:(i.numeric=!0,Ct(new Date(null==t?void 0:t.last_changed).getTime(),new Date(null==e?void 0:e.last_changed).getTime(),i))},last_updated:(t,e,i)=>{const[s,n]=(null==i?void 0:i.reverse)?[-1,1]:[1,-1];return null==(null==t?void 0:t.last_updated)&&null==(null==e?void 0:e.last_updated)?0:null==(null==t?void 0:t.last_updated)?s:null==(null==e?void 0:e.last_updated)?n:(i.numeric=!0,Ct(new Date(null==t?void 0:t.last_updated).getTime(),new Date(null==e?void 0:e.last_updated).getTime(),i))},last_triggered:(t,e,i)=>{var s,n,o,r,a,l;const[c,d]=(null==i?void 0:i.reverse)?[-1,1]:[1,-1];return null==(null===(s=null==t?void 0:t.attributes)||void 0===s?void 0:s.last_triggered)&&null==(null===(n=null==e?void 0:e.attributes)||void 0===n?void 0:n.last_triggered)?0:null==(null===(o=null==t?void 0:t.attributes)||void 0===o?void 0:o.last_triggered)?c:null==(null===(r=null==e?void 0:e.attributes)||void 0===r?void 0:r.last_triggered)?d:(i.numeric=!0,Ct(new Date(null===(a=null==t?void 0:t.attributes)||void 0===a?void 0:a.last_triggered).getTime(),new Date(null===(l=null==e?void 0:e.attributes)||void 0===l?void 0:l.last_triggered).getTime(),i))}};function Et(t,e){return function(i,s){var n,o;return null!==(o=null===(n=Ot[e.method])||void 0===n?void 0:n.call(Ot,t.states[i.entity],t.states[s.entity],e))&&void 0!==o?o:0}}var xt="1.9.1";const Pt=["domain","entity_id","state","name","group","device","area","last_changed","last_updated","last_triggered"],jt=["none","domain","entity_id","friendly_name","state","last_changed","last_updated","last_triggered"];class $t extends nt{constructor(){super(...arguments),this._selectedTab=0,this._cardGUIMode=!0,this._cardGUIModeAvailable=!0}setConfig(t){this._config=t}_handleSwitchTab(t){this._selectedTab=parseInt(t.detail.index,10)}_addFilterGroup(){var t;if(!this._config)return;const e=[...null===(t=this._config.filter)||void 0===t?void 0:t.include];e.push({domain:""});const i=Object.assign(Object.assign({},this._config.filter),{include:e});this._config=Object.assign(Object.assign({},this._config),{filter:i}),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}_deleteFilterGroup(t){var e;if(!this._config)return;const i=[...null===(e=this._config.filter)||void 0===e?void 0:e.include];i.splice(t,1);const s=Object.assign(Object.assign({},this._config.filter),{include:i});this._config=Object.assign(Object.assign({},this._config),{filter:s}),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}_moveFilterGroup(t,e){var i;if(!this._config)return;const s=[...null===(i=this._config.filter)||void 0===i?void 0:i.include];[s[t],s[t+e]]=[s[t+e],s[t]];const n=Object.assign(Object.assign({},this._config.filter),{include:s});this._config=Object.assign(Object.assign({},this._config),{filter:n}),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}_addSpecialEntry(){var t;if(!this._config)return;const e=[...null===(t=this._config.filter)||void 0===t?void 0:t.include];e.push({type:""});const i=Object.assign(Object.assign({},this._config.filter),{include:e});this._config=Object.assign(Object.assign({},this._config),{filter:i}),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}async _changeSpecialEntry(t,e){var i;if(!this._config)return;const s=[...null===(i=this._config.filter)||void 0===i?void 0:i.include];s[t]=e.detail.value;const n=Object.assign(Object.assign({},this._config.filter),{include:s});this._config=Object.assign(Object.assign({},this._config),{filter:n}),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}async _changeGroupOptions(t,e){var i;if(!this._config)return;const s=e.detail.value,n=[...null===(i=this._config.filter)||void 0===i?void 0:i.include];n[t]=Object.assign(Object.assign({},n[t]),{options:s});const o=Object.assign(Object.assign({},this._config.filter),{include:n});this._config=Object.assign(Object.assign({},this._config),{filter:o}),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}_addFilter(t){var e;if(!this._config)return;const i=Pt.find((e=>void 0===this._config.filter.include[t][e]));if(void 0===i)return;const s=[...null===(e=this._config.filter)||void 0===e?void 0:e.include];s[t]=Object.assign(Object.assign({},s[t]),{[i]:""});const n=Object.assign(Object.assign({},this._config.filter),{include:s});this._config=Object.assign(Object.assign({},this._config),{filter:n}),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}_removeFilter(t,e){var i;if(!this._config)return;const s=[...null===(i=this._config.filter)||void 0===i?void 0:i.include],n=Object.assign({},s[t]);if(delete n[e],0===Object.keys(n).length)return this._deleteFilterGroup(t);s[t]=n;const o=Object.assign(Object.assign({},this._config.filter),{include:s});this._config=Object.assign(Object.assign({},this._config),{filter:o}),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}_changeFilterKey(t,e,i){var s;if(!this._config)return;const n=Pt[i.target.selected];if(void 0===n||n===e)return;const o=[...null===(s=this._config.filter)||void 0===s?void 0:s.include],r=Object.assign({},o[t]);if(void 0===r[e])return;r[n]=r[e],delete r[e],o[t]=r;const a=Object.assign(Object.assign({},this._config.filter),{include:o});this._config=Object.assign(Object.assign({},this._config),{filter:a}),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}_changeFilterValue(t,e,i){var s;if(!this._config)return;const n=[...null===(s=this._config.filter)||void 0===s?void 0:s.include],o=Object.assign({},n[t]);o[e]=i.target.value,n[t]=o;const r=Object.assign(Object.assign({},this._config.filter),{include:n});this._config=Object.assign(Object.assign({},this._config),{filter:r}),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}_changeSortMethod(t){if(!this._config)return;const e=jt[t.target.selected],i=Object.assign(Object.assign({},this._config.sort),{method:e});this._config=Object.assign(Object.assign({},this._config),{sort:i}),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}_sortOptionToggle(t,e){if(!this._config)return;const i=Object.assign({},this._config.sort);i[t]=e.target.checked,this._config=Object.assign(Object.assign({},this._config),{sort:i}),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}_showEmptyToggle(){if(!this._config)return;const t=!1===this._config.show_empty;this._config=Object.assign(Object.assign({},this._config),{show_empty:t}),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}_changeCardParam(t){if(!this._config)return;const e=""===t.target.value||"entities"===t.target.value?void 0:t.target.value;this._config=Object.assign(Object.assign({},this._config),{card_param:e}),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}_getCardConfig(){const t=Object.assign({},this._config.card);return t[this._config.card_param||"entities"]=[],t}_handleCardPicked(t){if(t.stopPropagation(),!this._config)return;const e=Object.assign({},t.detail.config);delete e.entities,this._config=Object.assign(Object.assign({},this._config),{card:e}),this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}_handleCardConfigChanged(t){if(t.stopPropagation(),!this._config)return;const e=Object.assign({},t.detail.config);delete e[this._config.card_param||"entities"],this._config=Object.assign(Object.assign({},this._config),{card:e}),this._cardGUIModeAvailable=t.detail.guiModeAvailable,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}}))}_deleteCard(t){this._config&&(this._config=Object.assign({},this._config),delete this._config.card,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config}})))}_toggleCardMode(t){var e;null===(e=this._cardEditorEl)||void 0===e||e.toggleMode()}_cardGUIModeChanged(t){t.stopPropagation(),this._cardGUIMode=t.detail.guiMode,this._cardGUIModeAvailable=t.detail.guiModeAvailable}render(){return this.hass&&this._config?V` 2 |
3 |
4 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | ${[this._renderFilterEditor,this._renderSortEditor,this._renderCardEditor][this._selectedTab].bind(this)()} 15 |
16 |
17 | `:V``}_renderFilterEditor(){var t;return(null===(t=this._config.filter)||void 0===t?void 0:t.template)||this._config.entities?V` 18 |
19 |

20 | Your filter method is not handled by the GUI editor. 21 |

22 |

Please switch to the CODE EDITOR to access all options.

23 |
24 | `:V` 25 | ${this._config.filter.include.map(((t,e)=>V` 26 |
27 |
28 | this._moveFilterGroup(e,-1)} 31 | > 32 | 33 | 34 | this._moveFilterGroup(e,1)} 37 | > 38 | 39 | 40 | this._deleteFilterGroup(e)} 42 | > 43 | 44 | 45 |
46 | ${void 0===t.type?V` 47 | ${Object.entries(t).map((([t,i],s)=>V` 48 | ${Pt.includes(t)?V` 49 |
50 | 51 | this._changeFilterKey(e,t,i)} 55 | > 56 | ${Pt.map((t=>V` ${t} `))} 57 | 58 | 59 | this._changeFilterValue(e,t,i)} 62 | > 63 | this._removeFilter(e,t)} 66 | > 67 | 68 | 69 | 70 |
71 | `:"options"===t?V``:V`

Some filters are not shown

72 |

73 | Please switch to the CODE EDITOR to access all 74 | options. 75 |

`} 76 | `))} 77 | this._addFilter(e)}> 78 | Add filter 79 | 80 | this._changeGroupOptions(e,t)} 85 | > 86 | `:V`this._changeSpecialEntry(e,t)} 90 | >`} 91 |
92 | `))} 93 | 94 | Add filter group 95 | 96 | 97 | Add non-filter entry 98 | 99 | `}_renderSortEditor(){var t,e,i,s,n;return V` 100 |
101 | ${(null===(t=this._config.sort)||void 0===t?void 0:t.method)&&!jt.includes(this._config.sort.method)?V`

102 | Your sort method is not handled by the GUI editor. 103 |

104 |

Please switch to the CODE EDITOR to access all options.

`:V` 105 | Method: 106 | 107 | 112 | ${jt.map((t=>V` ${t} `))} 113 | 114 | 115 |

116 | 117 | this._sortOptionToggle("reverse",t)} 120 | > 121 | 122 |

123 |

124 | 125 | this._sortOptionToggle("numeric",t)} 128 | > 129 | 130 |

131 | `} 132 |
133 | `}_renderCardEditor(){var t;return V` 134 |
135 | 136 | 140 | 141 | 146 | 147 | ${this._config.card?V` 148 |
149 | 154 | ${!this._cardEditorEl||this._cardGUIMode?"Show code editor":"Show Visual Editor"} 155 | 156 | 160 | 161 | 162 |
163 | 170 | `:V` 171 | 176 | `} 177 |
178 | `}static get styles(){return[it` 179 | mwc-tab-bar { 180 | border-bottom: 1px solid var(--divider-color); 181 | } 182 | 183 | .filter, 184 | .card { 185 | margin-top: 8px; 186 | border: 1px solid var(--divider-color); 187 | padding: 12px; 188 | } 189 | .filter .option { 190 | display: flex; 191 | align-items: flex-end; 192 | } 193 | .filter .option paper-dropdown-menu { 194 | margin-right: 16px; 195 | width: 150px; 196 | } 197 | .filter .option paper-input { 198 | flex-grow: 2; 199 | } 200 | 201 | .filter .toolbar, 202 | .card .card-options { 203 | display: flex; 204 | justify-content: flex-end; 205 | width: 100%; 206 | } 207 | .gui-mode-button { 208 | margin-right: auto; 209 | } 210 | `]}}function Nt(t,e){if(t===e)return!0;if(typeof t!=typeof e)return!1;if(!(t instanceof Object&&e instanceof Object))return!1;for(const i in t)if(t.hasOwnProperty(i)){if(!e.hasOwnProperty(i))return!1;if(t[i]!==e[i]){if("object"!=typeof t[i])return!1;if(!Nt(t[i],e[i]))return!1}}for(const i in e)if(e.hasOwnProperty(i)&&!t.hasOwnProperty(i))return!1;return!0}t([Y()],$t.prototype,"_config",void 0),t([K()],$t.prototype,"lovelace",void 0),t([K()],$t.prototype,"hass",void 0),t([Y()],$t.prototype,"_selectedTab",void 0),t([Y()],$t.prototype,"_cardGUIMode",void 0),t([Y()],$t.prototype,"_cardGUIModeAvailable",void 0),t([function(t,e){return(i,s)=>{const n={get(){return this.renderRoot.querySelector(t)},enumerable:!0,configurable:!0};if(e){const e="symbol"==typeof s?Symbol():`__${s}`;n.get=function(){return void 0===this[e]&&(this[e]=this.renderRoot.querySelector(t)),this[e]}}return void 0!==s?Q(n,i,s):X(n,i)}}("hui-card-element-editor")],$t.prototype,"_cardEditorEl",void 0),customElements.define("auto-entities-editor",$t),window.customCards=window.customCards||[],window.customCards.push({type:"auto-entities",name:"Auto Entities",preview:!1,description:"Entity Filter on Steroids. Auto Entities allows you to fill other cards with entities automatically, based on a number of attributes."}),window.queueMicrotask=window.queueMicrotask||(t=>window.setTimeout(t,1));class Tt extends nt{constructor(){super(...arguments),this._updateCooldown={timer:void 0,rerun:!1},this._renderer=t=>{this._template="string"==typeof t?t.split(/[\s,]+/):t}}static getConfigElement(){return document.createElement("auto-entities-editor")}static getStubConfig(){return{card:{type:"entities"},filter:{include:[],exclude:[]}}}setConfig(t){var e,i;if(!t)throw new Error("No configuration.");if(!(null===(e=t.card)||void 0===e?void 0:e.type))throw new Error("No card type specified.");if(!t.filter&&!t.entities)throw new Error("No filters specified.");t=JSON.parse(JSON.stringify(t)),this._config=t,(null===(i=this._config.filter)||void 0===i?void 0:i.template)&&ht(this._config.filter.template)&&pt(this._renderer,this._config.filter.template,{config:t}),this._cardBuilt=new Promise((t=>this._cardBuiltResolve=t)),queueMicrotask((()=>this.update_all()))}connectedCallback(){var t,e;super.connectedCallback(),(null===(e=null===(t=this._config)||void 0===t?void 0:t.filter)||void 0===e?void 0:e.template)&&ht(this._config.filter.template)&&pt(this._renderer,this._config.filter.template,{config:this._config})}disconnectedCallback(){super.disconnectedCallback(),ft(this._renderer)}async update_all(){if(this.card&&(this.card.hass=this.hass),this._updateCooldown.timer)return void(this._updateCooldown.rerun=!0);this._updateCooldown.rerun=!1,this._updateCooldown.timer=window.setTimeout((()=>{this._updateCooldown.timer=void 0,this._updateCooldown.rerun&&this.update_all()}),500);const t=await this.update_entities();this.update_card(t)}async update_card(t){var e,i,s;if(this._entities&&Nt(t,this._entities)&&Nt(this._cardConfig,this._config.card))return;const n=(null===(e=this._cardConfig)||void 0===e?void 0:e.type)!==this._config.card.type;this._entities=t,this._cardConfig=JSON.parse(JSON.stringify(this._config.card));const o=Object.assign({[this._config.card_param||"entities"]:t},this._config.card);if(!this.card||n){const t=await window.loadCardHelpers(),e=console.error;let s=!1;if(console.error=(...t)=>{var i,n,o,r,a,l;3===t.length&&t[2].message&&((null===(n=(i=t[2].message).startsWith)||void 0===n?void 0:n.call(i,"Entities"))||(null===(r=(o=t[2].message).startsWith)||void 0===r?void 0:r.call(o,"Either entities"))||(null===(l=(a=t[2].message).endsWith)||void 0===l?void 0:l.call(a,"entity")))?s=!0:e(...t)},this.card=await t.createCardElement(o),console.error=e,s)return this.card=void 0,this._entities=void 0,this._cardConfig=void 0,void(null===(i=this._cardBuiltResolve)||void 0===i||i.call(this))}else this.card.setConfig(o);null===(s=this._cardBuiltResolve)||void 0===s||s.call(this),this.card.hass=this.hass;const r=0===t.length&&!1===this._config.show_empty;this.style.display=r?"none":null,this.style.margin=r?"0":null,this.card.requestUpdate&&(await this.updateComplete,this.card.requestUpdate())}async update_entities(){var t,e,i,s,n,o;const r=t=>t?"string"==typeof t?{entity:t.trim()}:t:null;let a=[...(null===(e=null===(t=this._config)||void 0===t?void 0:t.entities)||void 0===e?void 0:e.map(r))||[]];if(!this.hass)return a;if(this._template&&(a=a.concat(this._template.map(r))),a=a.filter(Boolean),null===(i=this._config.filter)||void 0===i?void 0:i.include){const t=Object.keys(this.hass.states).map(r);for(const e of this._config.filter.include){if(e.type){a.push(e);continue}let i=[];for(const s of t)await St(this.hass,e,s.entity)&&i.push(JSON.parse(JSON.stringify(Object.assign(Object.assign({},s),e.options)).replace(/this.entity_id/g,s.entity)));if(e.sort&&(i=i.sort(Et(this.hass,e.sort)),e.sort.count)){const t=null!==(s=e.sort.first)&&void 0!==s?s:0;i=i.slice(t,t+e.sort.count)}a=a.concat(i)}}if(null===(n=this._config.filter)||void 0===n?void 0:n.exclude)for(const t of this._config.filter.exclude){const e=[];for(const i of a)void 0!==i.entity&&await St(this.hass,t,i.entity)||e.push(i);a=e}if(this._config.sort&&(a=a.sort(Et(this.hass,this._config.sort)),this._config.sort.count)){const t=null!==(o=this._config.sort.first)&&void 0!==o?o:0;a=a.slice(t,t+this._config.sort.count)}if(this._config.unique){let t=[];for(const e of a)"entity"===this._config.unique&&e.entity&&t.some((t=>t.entity===e.entity))||t.some((t=>Nt(t,e)))||t.push(e);a=t}return a}async updated(t){(t.has("_template")||t.has("hass")&&this.hass)&&queueMicrotask((()=>this.update_all()))}createRenderRoot(){return this}render(){return V`${this.card}`}async getCardSize(){var t,e;let i=0;return await this._cardBuilt,this.card&&this.card.getCardSize&&(i=await this.card.getCardSize()),1===i&&(null===(t=this._entities)||void 0===t?void 0:t.length)&&(i=this._entities.length),0===i&&(null===(e=this._config.filter)||void 0===e?void 0:e.include)&&(i=Object.keys(this._config.filter.include).length),i||5}}t([K()],Tt.prototype,"_config",void 0),t([K()],Tt.prototype,"hass",void 0),t([K()],Tt.prototype,"card",void 0),t([K()],Tt.prototype,"_template",void 0),customElements.get("auto-entities")||(customElements.define("auto-entities",Tt),console.info(`%cAUTO-ENTITIES ${xt} IS INSTALLED`,"color: green; font-weight: bold","")); 211 | -------------------------------------------------------------------------------- /www/community/lovelace-auto-entities/auto-entities.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/www/community/lovelace-auto-entities/auto-entities.js.gz -------------------------------------------------------------------------------- /www/community/lovelace-auto-entities/rollup.config.js: -------------------------------------------------------------------------------- 1 | import nodeResolve from "@rollup/plugin-node-resolve"; 2 | import json from "@rollup/plugin-json"; 3 | import typescript from "rollup-plugin-typescript2"; 4 | import { terser } from "rollup-plugin-terser"; 5 | import babel from "@rollup/plugin-babel"; 6 | 7 | const dev = process.env.ROLLUP_WATCH; 8 | 9 | export default { 10 | input: "src/main.ts", 11 | output: { 12 | file: "auto-entities.js", 13 | format: "es", 14 | }, 15 | plugins: [ 16 | nodeResolve(), 17 | json(), 18 | typescript(), 19 | babel({ 20 | exclude: "node_modules/**", 21 | }), 22 | !dev && terser({ format: { comments: false } }), 23 | ], 24 | }; 25 | -------------------------------------------------------------------------------- /www/community/lovelace-auto-entities/rollup.config.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/www/community/lovelace-auto-entities/rollup.config.js.gz -------------------------------------------------------------------------------- /www/community/lovelace-card-mod/card-mod.js: -------------------------------------------------------------------------------- 1 | function e(){return document.querySelector("hc-main")?document.querySelector("hc-main").hass:document.querySelector("home-assistant")?document.querySelector("home-assistant").hass:void 0}function t(e,t,s=null){if((e=new Event(e,{bubbles:!0,cancelable:!1,composed:!0})).detail=t||{},s)s.dispatchEvent(e);else{var n=function(){var e=document.querySelector("hc-main");return e?(e=(e=(e=e&&e.shadowRoot)&&e.querySelector("hc-lovelace"))&&e.shadowRoot)&&e.querySelector("hui-view")||e.querySelector("hui-panel-view"):(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=(e=document.querySelector("home-assistant"))&&e.shadowRoot)&&e.querySelector("home-assistant-main"))&&e.shadowRoot)&&e.querySelector("app-drawer-layout partial-panel-resolver"))&&e.shadowRoot||e)&&e.querySelector("ha-panel-lovelace"))&&e.shadowRoot)&&e.querySelector("hui-root"))&&e.shadowRoot)&&e.querySelector("ha-app-layout"))&&e.querySelector("#view"))&&e.firstElementChild}();n&&n.dispatchEvent(e)}}const s="undefined"!=typeof window&&null!=window.customElements&&void 0!==window.customElements.polyfillWrapFlushCallback,n=(e,t,s=null)=>{for(;t!==s;){const s=t.nextSibling;e.removeChild(t),t=s}},o=`{{lit-${String(Math.random()).slice(2)}}}`,i=`\x3c!--${o}--\x3e`,r=new RegExp(`${o}|${i}`);class a{constructor(e,t){this.parts=[],this.element=t;const s=[],n=[],i=document.createTreeWalker(t.content,133,null,!1);let a=0,l=-1,u=0;const{strings:p,values:{length:m}}=e;for(;u0;){const t=p[u],s=h.exec(t)[2],n=s.toLowerCase()+"$lit$",o=e.getAttribute(n);e.removeAttribute(n);const i=o.split(r);this.parts.push({type:"attribute",index:l,name:s,strings:i}),u+=i.length-1}}"TEMPLATE"===e.tagName&&(n.push(e),i.currentNode=e.content)}else if(3===e.nodeType){const t=e.data;if(t.indexOf(o)>=0){const n=e.parentNode,o=t.split(r),i=o.length-1;for(let t=0;t{const s=e.length-t.length;return s>=0&&e.slice(s)===t},l=e=>-1!==e.index,c=()=>document.createComment(""),h=/([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F "'>=/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/;function u(e,t){const{element:{content:s},parts:n}=e,o=document.createTreeWalker(s,133,null,!1);let i=m(n),r=n[i],a=-1,d=0;const l=[];let c=null;for(;o.nextNode();){a++;const e=o.currentNode;for(e.previousSibling===c&&(c=null),t.has(e)&&(l.push(e),null===c&&(c=e)),null!==c&&d++;void 0!==r&&r.index===a;)r.index=null!==c?-1:r.index-d,i=m(n,i),r=n[i]}l.forEach((e=>e.parentNode.removeChild(e)))}const p=e=>{let t=11===e.nodeType?0:1;const s=document.createTreeWalker(e,133,null,!1);for(;s.nextNode();)t++;return t},m=(e,t=-1)=>{for(let s=t+1;s"function"==typeof e&&f.has(e),_={},g={};class v{constructor(e,t,s){this.__parts=[],this.template=e,this.processor=t,this.options=s}update(e){let t=0;for(const s of this.__parts)void 0!==s&&s.setValue(e[t]),t++;for(const e of this.__parts)void 0!==e&&e.commit()}_clone(){const e=s?this.template.element.content.cloneNode(!0):document.importNode(this.template.element.content,!0),t=[],n=this.template.parts,o=document.createTreeWalker(e,133,null,!1);let i,r=0,a=0,d=o.nextNode();for(;re}),S=` ${o} `;class b{constructor(e,t,s,n){this.strings=e,this.values=t,this.type=s,this.processor=n}getHTML(){const e=this.strings.length-1;let t="",s=!1;for(let n=0;n-1||s)&&-1===e.indexOf("--\x3e",r+1);const a=h.exec(e);t+=null===a?e+(s?S:i):e.substr(0,a.index)+a[1]+a[2]+"$lit$"+a[3]+o}return t+=this.strings[e],t}getTemplateElement(){const e=document.createElement("template");let t=this.getHTML();return void 0!==w&&(t=w.createHTML(t)),e.innerHTML=t,e}}const E=e=>null===e||!("object"==typeof e||"function"==typeof e),C=e=>Array.isArray(e)||!(!e||!e[Symbol.iterator]);class N{constructor(e,t,s){this.dirty=!0,this.element=e,this.name=t,this.strings=s,this.parts=[];for(let e=0;e{try{const e={get capture(){return M=!0,!1}};window.addEventListener("test",e,e),window.removeEventListener("test",e,e)}catch(e){}})();class U{constructor(e,t,s){this.value=void 0,this.__pendingValue=void 0,this.element=e,this.eventName=t,this.eventContext=s,this.__boundHandleEvent=e=>this.handleEvent(e)}setValue(e){this.__pendingValue=e}commit(){for(;y(this.__pendingValue);){const e=this.__pendingValue;this.__pendingValue=_,e(this)}if(this.__pendingValue===_)return;const e=this.__pendingValue,t=this.value,s=null==e||null!=t&&(e.capture!==t.capture||e.once!==t.once||e.passive!==t.passive),n=null!=e&&(null==t||s);s&&this.element.removeEventListener(this.eventName,this.__boundHandleEvent,this.__options),n&&(this.__options=R(e),this.element.addEventListener(this.eventName,this.__boundHandleEvent,this.__options)),this.value=e,this.__pendingValue=_}handleEvent(e){"function"==typeof this.value?this.value.call(this.eventContext||this.element,e):this.value.handleEvent(e)}}const R=e=>e&&(M?{capture:e.capture,passive:e.passive,once:e.once}:e.capture);function k(e){let t=$.get(e.type);void 0===t&&(t={stringsArray:new WeakMap,keyString:new Map},$.set(e.type,t));let s=t.stringsArray.get(e.strings);if(void 0!==s)return s;const n=e.strings.join(o);return s=t.keyString.get(n),void 0===s&&(s=new a(e,e.getTemplateElement()),t.keyString.set(n,s)),t.stringsArray.set(e.strings,s),s}const $=new Map,D=new WeakMap;const V=new class{handleAttributeExpressions(e,t,s,n){const o=t[0];if("."===o){return new A(e,t.slice(1),s).parts}if("@"===o)return[new U(e,t.slice(1),n.eventContext)];if("?"===o)return[new T(e,t.slice(1),s)];return new N(e,t,s).parts}handleTextExpression(e){return new x(e)}};"undefined"!=typeof window&&(window.litHtmlVersions||(window.litHtmlVersions=[])).push("1.3.0");const q=(e,...t)=>new b(e,t,"html",V),L=(e,t)=>`${e}--${t}`;let I=!0;void 0===window.ShadyCSS?I=!1:void 0===window.ShadyCSS.prepareTemplateDom&&(console.warn("Incompatible ShadyCSS version detected. Please update to at least @webcomponents/webcomponentsjs@2.0.2 and @webcomponents/shadycss@1.3.1."),I=!1);const j=e=>t=>{const s=L(t.type,e);let n=$.get(s);void 0===n&&(n={stringsArray:new WeakMap,keyString:new Map},$.set(s,n));let i=n.stringsArray.get(t.strings);if(void 0!==i)return i;const r=t.strings.join(o);if(i=n.keyString.get(r),void 0===i){const s=t.getTemplateElement();I&&window.ShadyCSS.prepareTemplateDom(s,e),i=new a(t,s),n.keyString.set(r,i)}return n.stringsArray.set(t.strings,i),i},z=["html","svg"],H=new Set,J=(e,t,s)=>{H.add(e);const n=s?s.element:document.createElement("template"),o=t.querySelectorAll("style"),{length:i}=o;if(0===i)return void window.ShadyCSS.prepareTemplateStyles(n,e);const r=document.createElement("style");for(let e=0;e{z.forEach((t=>{const s=$.get(L(t,e));void 0!==s&&s.keyString.forEach((e=>{const{element:{content:t}}=e,s=new Set;Array.from(t.querySelectorAll("style")).forEach((e=>{s.add(e)})),u(e,s)}))}))})(e);const a=n.content;s?function(e,t,s=null){const{element:{content:n},parts:o}=e;if(null==s)return void n.appendChild(t);const i=document.createTreeWalker(n,133,null,!1);let r=m(o),a=0,d=-1;for(;i.nextNode();)for(d++,i.currentNode===s&&(a=p(t),s.parentNode.insertBefore(t,s));-1!==r&&o[r].index===d;){if(a>0){for(;-1!==r;)o[r].index+=a,r=m(o,r);return}r=m(o,r)}}(s,r,a.firstChild):a.insertBefore(r,a.firstChild),window.ShadyCSS.prepareTemplateStyles(n,e);const d=a.querySelector("style");if(window.ShadyCSS.nativeShadow&&null!==d)t.insertBefore(d.cloneNode(!0),t.firstChild);else if(s){a.insertBefore(r,a.firstChild);const e=new Set;e.add(r),u(s,e)}};window.JSCompiler_renameProperty=(e,t)=>e;const F={toAttribute(e,t){switch(t){case Boolean:return e?"":null;case Object:case Array:return null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){switch(t){case Boolean:return null!==e;case Number:return null===e?null:Number(e);case Object:case Array:return JSON.parse(e)}return e}},B=(e,t)=>t!==e&&(t==t||e==e),W={attribute:!0,type:String,converter:F,reflect:!1,hasChanged:B};class Y extends HTMLElement{constructor(){super(),this.initialize()}static get observedAttributes(){this.finalize();const e=[];return this._classProperties.forEach(((t,s)=>{const n=this._attributeNameForProperty(s,t);void 0!==n&&(this._attributeToPropertyMap.set(n,s),e.push(n))})),e}static _ensureClassProperties(){if(!this.hasOwnProperty(JSCompiler_renameProperty("_classProperties",this))){this._classProperties=new Map;const e=Object.getPrototypeOf(this)._classProperties;void 0!==e&&e.forEach(((e,t)=>this._classProperties.set(t,e)))}}static createProperty(e,t=W){if(this._ensureClassProperties(),this._classProperties.set(e,t),t.noAccessor||this.prototype.hasOwnProperty(e))return;const s="symbol"==typeof e?Symbol():`__${e}`,n=this.getPropertyDescriptor(e,s,t);void 0!==n&&Object.defineProperty(this.prototype,e,n)}static getPropertyDescriptor(e,t,s){return{get(){return this[t]},set(n){const o=this[e];this[t]=n,this.requestUpdateInternal(e,o,s)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this._classProperties&&this._classProperties.get(e)||W}static finalize(){const e=Object.getPrototypeOf(this);if(e.hasOwnProperty("finalized")||e.finalize(),this.finalized=!0,this._ensureClassProperties(),this._attributeToPropertyMap=new Map,this.hasOwnProperty(JSCompiler_renameProperty("properties",this))){const e=this.properties,t=[...Object.getOwnPropertyNames(e),..."function"==typeof Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(e):[]];for(const s of t)this.createProperty(s,e[s])}}static _attributeNameForProperty(e,t){const s=t.attribute;return!1===s?void 0:"string"==typeof s?s:"string"==typeof e?e.toLowerCase():void 0}static _valueHasChanged(e,t,s=B){return s(e,t)}static _propertyValueFromAttribute(e,t){const s=t.type,n=t.converter||F,o="function"==typeof n?n:n.fromAttribute;return o?o(e,s):e}static _propertyValueToAttribute(e,t){if(void 0===t.reflect)return;const s=t.type,n=t.converter;return(n&&n.toAttribute||F.toAttribute)(e,s)}initialize(){this._updateState=0,this._updatePromise=new Promise((e=>this._enableUpdatingResolver=e)),this._changedProperties=new Map,this._saveInstanceProperties(),this.requestUpdateInternal()}_saveInstanceProperties(){this.constructor._classProperties.forEach(((e,t)=>{if(this.hasOwnProperty(t)){const e=this[t];delete this[t],this._instanceProperties||(this._instanceProperties=new Map),this._instanceProperties.set(t,e)}}))}_applyInstanceProperties(){this._instanceProperties.forEach(((e,t)=>this[t]=e)),this._instanceProperties=void 0}connectedCallback(){this.enableUpdating()}enableUpdating(){void 0!==this._enableUpdatingResolver&&(this._enableUpdatingResolver(),this._enableUpdatingResolver=void 0)}disconnectedCallback(){}attributeChangedCallback(e,t,s){t!==s&&this._attributeToProperty(e,s)}_propertyToAttribute(e,t,s=W){const n=this.constructor,o=n._attributeNameForProperty(e,s);if(void 0!==o){const e=n._propertyValueToAttribute(t,s);if(void 0===e)return;this._updateState=8|this._updateState,null==e?this.removeAttribute(o):this.setAttribute(o,e),this._updateState=-9&this._updateState}}_attributeToProperty(e,t){if(8&this._updateState)return;const s=this.constructor,n=s._attributeToPropertyMap.get(e);if(void 0!==n){const e=s.getPropertyOptions(n);this._updateState=16|this._updateState,this[n]=s._propertyValueFromAttribute(t,e),this._updateState=-17&this._updateState}}requestUpdateInternal(e,t,s){let n=!0;if(void 0!==e){const o=this.constructor;s=s||o.getPropertyOptions(e),o._valueHasChanged(this[e],t,s.hasChanged)?(this._changedProperties.has(e)||this._changedProperties.set(e,t),!0!==s.reflect||16&this._updateState||(void 0===this._reflectingProperties&&(this._reflectingProperties=new Map),this._reflectingProperties.set(e,s))):n=!1}!this._hasRequestedUpdate&&n&&(this._updatePromise=this._enqueueUpdate())}requestUpdate(e,t){return this.requestUpdateInternal(e,t),this.updateComplete}async _enqueueUpdate(){this._updateState=4|this._updateState;try{await this._updatePromise}catch(e){}const e=this.performUpdate();return null!=e&&await e,!this._hasRequestedUpdate}get _hasRequestedUpdate(){return 4&this._updateState}get hasUpdated(){return 1&this._updateState}performUpdate(){if(!this._hasRequestedUpdate)return;this._instanceProperties&&this._applyInstanceProperties();let e=!1;const t=this._changedProperties;try{e=this.shouldUpdate(t),e?this.update(t):this._markUpdated()}catch(t){throw e=!1,this._markUpdated(),t}e&&(1&this._updateState||(this._updateState=1|this._updateState,this.firstUpdated(t)),this.updated(t))}_markUpdated(){this._changedProperties=new Map,this._updateState=-5&this._updateState}get updateComplete(){return this._getUpdateComplete()}_getUpdateComplete(){return this._updatePromise}shouldUpdate(e){return!0}update(e){void 0!==this._reflectingProperties&&this._reflectingProperties.size>0&&(this._reflectingProperties.forEach(((e,t)=>this._propertyToAttribute(t,this[t],e))),this._reflectingProperties=void 0),this._markUpdated()}updated(e){}firstUpdated(e){}}Y.finalized=!0;const G=(e,t)=>"method"===t.kind&&t.descriptor&&!("value"in t.descriptor)?Object.assign(Object.assign({},t),{finisher(s){s.createProperty(t.key,e)}}):{kind:"field",key:Symbol(),placement:"own",descriptor:{},initializer(){"function"==typeof t.initializer&&(this[t.key]=t.initializer.call(this))},finisher(s){s.createProperty(t.key,e)}};const K=window.ShadowRoot&&(void 0===window.ShadyCSS||window.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,Q=Symbol();class X{constructor(e,t){if(t!==Q)throw new Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e}get styleSheet(){return void 0===this._styleSheet&&(K?(this._styleSheet=new CSSStyleSheet,this._styleSheet.replaceSync(this.cssText)):this._styleSheet=null),this._styleSheet}toString(){return this.cssText}}(window.litElementVersions||(window.litElementVersions=[])).push("2.4.0");const Z={};class ee extends Y{static getStyles(){return this.styles}static _getUniqueStyles(){if(this.hasOwnProperty(JSCompiler_renameProperty("_styles",this)))return;const e=this.getStyles();if(Array.isArray(e)){const t=(e,s)=>e.reduceRight(((e,s)=>Array.isArray(s)?t(s,e):(e.add(s),e)),s),s=t(e,new Set),n=[];s.forEach((e=>n.unshift(e))),this._styles=n}else this._styles=void 0===e?[]:[e];this._styles=this._styles.map((e=>{if(e instanceof CSSStyleSheet&&!K){const t=Array.prototype.slice.call(e.cssRules).reduce(((e,t)=>e+t.cssText),"");return new X(String(t),Q)}return e}))}initialize(){super.initialize(),this.constructor._getUniqueStyles(),this.renderRoot=this.createRenderRoot(),window.ShadowRoot&&this.renderRoot instanceof window.ShadowRoot&&this.adoptStyles()}createRenderRoot(){return this.attachShadow({mode:"open"})}adoptStyles(){const e=this.constructor._styles;0!==e.length&&(void 0===window.ShadyCSS||window.ShadyCSS.nativeShadow?K?this.renderRoot.adoptedStyleSheets=e.map((e=>e instanceof CSSStyleSheet?e:e.styleSheet)):this._needsShimAdoptedStyleSheets=!0:window.ShadyCSS.ScopingShim.prepareAdoptedCssText(e.map((e=>e.cssText)),this.localName))}connectedCallback(){super.connectedCallback(),this.hasUpdated&&void 0!==window.ShadyCSS&&window.ShadyCSS.styleElement(this)}update(e){const t=this.render();super.update(e),t!==Z&&this.constructor.render(t,this.renderRoot,{scopeName:this.localName,eventContext:this}),this._needsShimAdoptedStyleSheets&&(this._needsShimAdoptedStyleSheets=!1,this.constructor._styles.forEach((e=>{const t=document.createElement("style");t.textContent=e.cssText,this.renderRoot.appendChild(t)})))}render(){return Z}}ee.finalized=!0,ee.render=(e,t,s)=>{if(!s||"object"!=typeof s||!s.scopeName)throw new Error("The `scopeName` option is required.");const o=s.scopeName,i=D.has(t),r=I&&11===t.nodeType&&!!t.host,a=r&&!H.has(o),d=a?document.createDocumentFragment():t;if(((e,t,s)=>{let o=D.get(t);void 0===o&&(n(t,t.firstChild),D.set(t,o=new x(Object.assign({templateFactory:k},s))),o.appendInto(t)),o.setValue(e),o.commit()})(e,d,Object.assign({templateFactory:j(o)},s)),a){const e=D.get(d);D.delete(d);const s=e.value instanceof v?e.value.template:void 0;J(o,d,s),n(t,t.firstChild),t.appendChild(d),D.set(t,e)}!i&&r&&window.ShadyCSS.styleElement(t.host)};const te="lovelace-player-device-id";function se(){if(!localStorage[te]){const e=()=>Math.floor(1e5*(1+Math.random())).toString(16).substring(1);window.fully&&"function"==typeof fully.getDeviceId?localStorage[te]=fully.getDeviceId():localStorage[te]=`${e()}${e()}-${e()}${e()}`}return localStorage[te]}let ne=se();const oe=new URLSearchParams(window.location.search);var ie;oe.get("deviceID")&&null!==(ie=oe.get("deviceID"))&&("clear"===ie?localStorage.removeItem(te):localStorage[te]=ie,ne=se()),window.cardMod_template_cache=window.cardMod_template_cache||{};const re=window.cardMod_template_cache;async function ae(t,s,n){const o=e().connection,i=JSON.stringify([s,n]);let r=re[i];r?(r.callbacks.has(t)||de(t),t(r.value),r.callbacks.add(t)):(de(t),t(""),n=Object.assign({user:e().user.name,browser:ne,hash:location.hash.substr(1)||""},n),re[i]=r={template:s,variables:n,value:"",callbacks:new Set([t]),unsubscribe:o.subscribeMessage((e=>function(e,t){const s=re[e];s&&(s.value=t.result,s.callbacks.forEach((e=>e(t.result))))}(i,e)),{type:"render_template",template:s,variables:n})})}async function de(e){let t;for(const[s,n]of Object.entries(re))if(n.callbacks.has(e)){n.callbacks.delete(e),0==n.callbacks.size&&(t=n.unsubscribe,delete re[s]);break}t&&await(await t)()}var le="3.0.12";async function ce(e,t,s=!1){let n=e;"string"==typeof t&&(t=t.split(/(\$| )/)),""===t[t.length-1]&&t.pop();for(const[e,o]of t.entries())if(o.trim().length){if(!n)return null;n.localName&&n.localName.includes("-")&&await customElements.whenDefined(n.localName),n.updateComplete&&await n.updateComplete,n="$"===o?s&&e==t.length-1?[n.shadowRoot]:n.shadowRoot:s&&e==t.length-1?n.querySelectorAll(o):n.querySelector(o)}return n}async function he(e,t,s=!1,n=1e4){return Promise.race([ce(e,t,s),new Promise(((e,t)=>setTimeout((()=>t(new Error("timeout"))),n)))]).catch((e=>{if(!e.message||"timeout"!==e.message)throw e;return null}))}const ue=async e=>{await(async()=>{if(customElements.get("developer-tools-event"))return;await customElements.whenDefined("partial-panel-resolver");const e=document.createElement("partial-panel-resolver");e.hass={panels:[{url_path:"tmp",component_name:"developer-tools"}]},e._updateRoutes(),await e.routerOptions.routes.tmp.load(),await customElements.whenDefined("developer-tools-router");const t=document.createElement("developer-tools-router");await t.routerOptions.routes.event.load()})();return document.createElement("developer-tools-event")._computeParsedEventData(e)};async function pe(e,t,s="",n={},o=null,i=!0){var r;let a;(null===(r=e.localName)||void 0===r?void 0:r.includes("-"))&&await customElements.whenDefined(e.localName),e.updateComplete&&await e.updateComplete,void 0===e._cardMod&&(e._cardMod=[]);for(const s of e._cardMod)if(s.type===t){a=s;break}return a||(a=document.createElement("card-mod"),a.type=t,e._cardMod.push(a)),queueMicrotask((async()=>{(e.modElement?e.modElement:i&&e.shadowRoot||e).appendChild(a),a.variables=n,a.styles=s})),a}function me(e,t){const s=e=>e&&"object"==typeof e&&!Array.isArray(e);if(s(e)&&s(t))for(const n in t)s(t[n])?(e[n]||Object.assign(e,{[n]:{}}),"string"==typeof e[n]&&(e[n]={".":e[n]}),me(e[n],t[n])):e[n]?e[n]=t[n]+e[n]:e[n]=t[n];return e}function fe(e,t){if(e===t)return!0;if(typeof e!=typeof t)return!1;if(!(e instanceof Object&&t instanceof Object))return!1;for(const s in e)if(e.hasOwnProperty(s)){if(!t.hasOwnProperty(s))return!1;if(e[s]!==t[s]){if("object"!=typeof e[s])return!1;if(!fe(e[s],t[s]))return!1}}for(const s in t)if(t.hasOwnProperty(s)&&!e.hasOwnProperty(s))return!1;return!0}function ye(e){return e.config?e.config:e._config?e._config:e.host?ye(e.host):e.parentElement?ye(e.parentElement):e.parentNode?ye(e.parentNode):null}function _e(e,t){for(const s of t)e.add(s)}async function ge(e,t=0){let s=new Set;if(10==t)return s;if(!e)return s;if(e._cardMod)for(const t of e._cardMod)t.styles&&s.add(t);return e.updateComplete&&await e.updateComplete,e.parentElement?_e(s,await ge(e.parentElement,t+1)):e.parentNode&&_e(s,await ge(e.parentNode,t+1)),e.host&&_e(s,await ge(e.host,t+1)),s}class ve extends ee{constructor(){super(),this._rendered_styles="",this._styleChildren=new Set,this._observer=new MutationObserver((e=>{for(const t of e){if("card-mod"===t.target.localName)return;let e=!0;if(t.addedNodes.length&&t.addedNodes.forEach((t=>{"card-mod"!==t.localName&&(e=!1)})),e)return;if(e=!0,t.removedNodes.length&&t.removedNodes.forEach((t=>{"card-mod"!==t.localName&&(e=!1)})),e)return}this.refresh()})),document.addEventListener("cm_update",(()=>{this.refresh()}))}static get applyToElement(){return pe}connectedCallback(){super.connectedCallback(),this._connect(),this.setAttribute("slot","none")}disconnectedCallback(){super.disconnectedCallback(),this._disconnect()}set styles(e){fe(e,this._input_styles)||(this._input_styles=e,this._connect())}get styles(){return this._styles}refresh(){this._connect()}async _connect(){const t=this._input_styles;let s=JSON.parse(JSON.stringify(t||{}));"string"==typeof s&&(s={".":s});me(s,await async function(t){if(!t.type)return null;const s=t.parentElement?t.parentElement:t,n=window.getComputedStyle(s).getPropertyValue("--card-mod-theme"),o=e().themes.themes;return o[n]?o[n][`card-mod-${t.type}-yaml`]?ue(o[n][`card-mod-${t.type}-yaml`]):o[n][`card-mod-${t.type}`]?{".":o[n][`card-mod-${t.type}`]}:{}:{}}(this));const n=new Set;let o;const i=this.parentElement||this.parentNode;s["."]||(o="");for(const[e,t]of Object.entries(s))if("."===e)o=t;else{const s=await he(i,e,!0);if(!s)continue;for(const e of s)if(e){const s=await pe(e,`${this.type}-child`,t,this.variables,null,!1);s.refresh(),n.add(s)}}for(const e of this._styleChildren)n.has(e)||e&&(e.styles="");var r;(this._styleChildren=n,this._styles!==o)&&(this._styles=o,this._styles&&(r=this._styles,String(r).includes("{%")||String(r).includes("{{"))?(this._renderer=this._renderer||this._style_rendered.bind(this),ae(this._renderer,this._styles,this.variables)):this._style_rendered(this._styles||""),this._observer.observe(function(e){if(!e)return;const t=e.parentElement||e.parentNode;return t?t.host?t.host:t:void 0}(this),{childList:!0}))}async _disconnect(){this._observer.disconnect(),this._styles="",await de(this._renderer)}_style_rendered(e){this._rendered_styles=e,this.dispatchEvent(new Event("card-mod-update"))}createRenderRoot(){return this}render(){return q` 2 | 5 | `}}var we;!function(e,t,s,n){var o,i=arguments.length,r=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,s):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(e,t,s,n);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(r=(i<3?o(r):i>3?o(t,s,r):o(t,s))||r);i>3&&r&&Object.defineProperty(t,s,r)}([(e,t)=>void 0!==t?((e,t,s)=>{t.constructor.createProperty(s,e)})(we,e,t):G(we,e)],ve.prototype,"_rendered_styles",void 0),customElements.get("card-mod")||(customElements.define("card-mod",ve),console.info(`%cCARD-MOD ${le} IS INSTALLED`,"color: green; font-weight: bold","")),customElements.whenDefined("ha-card").then((()=>{const e=customElements.get("ha-card");if(e.prototype.cardmod_patched)return;e.prototype.cardmod_patched=!0;const t=e.prototype.firstUpdated;e.prototype.firstUpdated=function(e){var s,n;null==t||t.bind(this)(e);const o=this.shadowRoot.querySelector(".card-header");o&&this.insertBefore(o,this.children[0]);const i=ye(this);(null===(s=null==i?void 0:i.card_mod)||void 0===s?void 0:s.class)&&this.classList.add(i.card_mod.class),(null==i?void 0:i.type)&&this.classList.add(`type-${i.type.replace(":","-")}`),pe(this,"card",(null===(n=null==i?void 0:i.card_mod)||void 0===n?void 0:n.style)||(null==i?void 0:i.style)||"",{config:i},null,!1).then((e=>{var t;const s=null===(t=this.parentNode)||void 0===t?void 0:t.host;if(s){if(s.setConfig&&!s.setConfig.cm_patched){const t=s.setConfig;s.setConfig=function(s){var n;t.bind(this)(s),e.variables={config:s},e.styles=(null===(n=s.card_mod)||void 0===n?void 0:n.style)||{}},s.setConfig.cm_patched=!0}if(s.update&&!s.update.cm_patched){const t=s.update;s.update=function(s){t.bind(this)(s),e.refresh(),this.updateComplete.then((()=>{e.refresh()}))},s.update.cm_patched=!0}window.setTimeout((()=>e.refresh()),100),window.setTimeout((()=>e.refresh()),500),window.setTimeout((()=>e.refresh()),1e3)}}))}})),customElements.whenDefined("hui-entities-card").then((()=>{const e=customElements.get("hui-entities-card");if(e.prototype.cardmod_patched)return;e.prototype.cardmod_patched=!0;const t=e.prototype.renderEntity;e.prototype.renderEntity=function(e){var s;const n=t.bind(this)(e);if(!n||!n.values)return n;const o=n.values[0];if(!o)return n;(null===(s=null==e?void 0:e.card_mod)||void 0===s?void 0:s.class)&&o.classList.add(e.card_mod.class),(null==e?void 0:e.type)&&o.classList.add(`type-${e.type.replace(":","-")}`);const i=()=>{var t;return pe(o,"row",(null===(t=null==e?void 0:e.card_mod)||void 0===t?void 0:t.style)||(null==e?void 0:e.style)||"",{config:e})};return this.updateComplete.then((()=>i())),n.values[0]&&n.values[0].addEventListener("ll-rebuild",i),n}}));customElements.whenDefined("hui-glance-card").then((()=>{const e=customElements.get("hui-glance-card");if(e.prototype.cardmod_patched)return;e.prototype.cardmod_patched=!0;const t=e.prototype.updated;e.prototype.updated=function(e){var s,n;null==t||t.bind(this)(e);for(const e of this.shadowRoot.querySelectorAll("ha-card div.entity")){if(!e.cardmod_patched){e.cardmod_patched=!0;const t=e.attachShadow({mode:"open"});for(;e.firstChild;)t.append(e.firstChild);const s=document.createElement("style");t.appendChild(s),s.innerHTML="\ndiv {\n width: 100%;\n text-align: center;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.name {\n min-height: var(--paper-font-body1_-_line-height, 20px);\n}\nstate-badge {\n margin: 8px 0;\n}\n"}const t=e.config||e.entityConf;(null===(s=null==t?void 0:t.card_mod)||void 0===s?void 0:s.class)&&e.classList.add(t.card_mod.class),pe(e,"glance",(null===(n=null==t?void 0:t.card_mod)||void 0===n?void 0:n.style)||(null==t?void 0:t.style)||"",{config:t})}}})),customElements.whenDefined("hui-state-label-badge").then((()=>{const e=customElements.get("hui-state-label-badge");if(e.prototype.cardmod_patched)return;e.prototype.cardmod_patched=!0;const t=e.prototype.firstUpdated;e.prototype.firstUpdated=function(e){var s,n;null==t||t.bind(this)(e);const o=this._config;(null===(s=null==o?void 0:o.card_mod)||void 0===s?void 0:s.class)&&this.classList.add(o.card_mod.class),pe(this,"badge",(null===(n=null==o?void 0:o.card_mod)||void 0===n?void 0:n.style)||(null==o?void 0:o.style)||"",{config:o})}})),customElements.whenDefined("hui-view").then((()=>{const e=customElements.get("hui-view");if(e.prototype.cardmod_patched)return;e.prototype.cardmod_patched=!0;const t=e.prototype.firstUpdated;e.prototype.firstUpdated=function(e){null==t||t.bind(this)(e),pe(this,"view")}})),customElements.whenDefined("hui-root").then((()=>{const e=customElements.get("hui-root");if(e.prototype.cardmod_patched)return;e.prototype.cardmod_patched=!0;const t=e.prototype.firstUpdated;e.prototype.firstUpdated=async function(e){null==t||t.bind(this)(e),pe(this,"root")},he(document,"home-assistant$home-assistant-main$app-drawer-layout partial-panel-resolver ha-panel-lovelace$hui-root",!1).then((e=>{null==e||e.firstUpdated()}))})),customElements.whenDefined("ha-more-info-dialog").then((()=>{const e=customElements.get("ha-more-info-dialog");if(e.prototype.cardmod_patched)return;e.prototype.cardmod_patched=!0;const t=e.prototype.showDialog;e.prototype.showDialog=function(e){null==t||t.bind(this)(e),this.requestUpdate().then((async()=>{pe(this.shadowRoot.querySelector("ha-dialog"),"more-info","",{config:e},null,!1)}))},he(document,"home-assistant$ha-more-info-dialog",!1).then((t=>{t&&(t.showDialog=e.prototype.showDialog.bind(t),t.showDialog({entityId:t.entityId}))}))})),customElements.whenDefined("ha-sidebar").then((()=>{const e=customElements.get("ha-sidebar");if(e.prototype.cardmod_patched)return;e.prototype.cardmod_patched=!0;const t=e.prototype.firstUpdated;e.prototype.firstUpdated=async function(e){null==t||t.bind(this)(e),pe(this,"sidebar")},he(document,"home-assistant$home-assistant-main$app-drawer-layout app-drawer ha-sidebar",!1).then((e=>null==e?void 0:e.firstUpdated()))})),customElements.whenDefined("hui-card-element-editor").then((()=>{const e=customElements.get("hui-card-element-editor");if(e.prototype.cardmod_patched)return;e.prototype.cardmod_patched=!0;const t=e.prototype.getConfigElement;e.prototype.getConfigElement=async function(){const e=await t.bind(this)();if(e){const t=e.setConfig;e.setConfig=function(e){var s,n;const o=JSON.parse(JSON.stringify(e));if(this._cardModData={card:o.card_mod,entities:[]},o.entities)for(const[e,t]of null===(s=o.entities)||void 0===s?void 0:s.entries())this._cardModData.entities[e]=t.card_mod,delete t.card_mod;if(delete o.card_mod,t.bind(this)(o),o.entities)for(const[e,t]of null===(n=o.entities)||void 0===n?void 0:n.entries())this._cardModData.entities[e]&&(t.card_mod=this._cardModData.entities[e])}}return e};const s=e.prototype._handleUIConfigChanged;e.prototype._handleUIConfigChanged=function(e){if(this._configElement&&this._configElement._cardModData){const t=this._configElement._cardModData;t.card&&(e.detail.config.card_mod=t.card)}s.bind(this)(e)}})),customElements.whenDefined("hui-dialog-edit-card").then((()=>{const e=customElements.get("hui-dialog-edit-card");if(e.prototype.cardmod_patched)return;e.prototype.cardmod_patched=!0;const t=e.prototype.updated;e.prototype.updated=function(e){null==t||t.bind(this)(e),this.updateComplete.then((async()=>{var e,t,s;this._cardModIcon||(this._cardModIcon=document.createElement("ha-icon"),this._cardModIcon.icon="mdi:brush");const n=this.shadowRoot.querySelector("mwc-button[slot=secondaryAction]");n&&(n.appendChild(this._cardModIcon),(null===(e=this._cardConfig)||void 0===e?void 0:e.card_mod)||(null===(s=null===(t=this._cardConfig)||void 0===t?void 0:t.entities)||void 0===s?void 0:s.some((e=>e.card_mod)))?this._cardModIcon.style.visibility="visible":this._cardModIcon.style.visibility="hidden")}))}})),customElements.whenDefined("hui-picture-elements-card").then((()=>{const e=customElements.get("hui-picture-elements-card");if(e.prototype.cardmod_patched)return;e.prototype.cardmod_patched=!0;const t=e.prototype.setConfig;e.prototype.setConfig=function(e){var s,n;null==t||t.bind(this)(e);for(const[e,t]of this._elements.entries()){const o=this._config.elements[e];(null===(s=null==o?void 0:o.card_mod)||void 0===s?void 0:s.class)&&t.classList.add(o.card_mod.class),(null==o?void 0:o.type)&&t.classList.add(`type-${o.type.replace(":","-")}`),pe(t,"element",null===(n=null==o?void 0:o.card_mod)||void 0===n?void 0:n.style,{config:o})}}})),customElements.whenDefined("ha-icon").then((()=>{const e=customElements.get("ha-icon");if(e.prototype.cardmod_patched)return;e.prototype.cardmod_patched=!0;const t=e.prototype.firstUpdated;e.prototype.firstUpdated=function(){null==t||t.bind(this)();const e=()=>{const e=window.getComputedStyle(this).getPropertyValue("--card-mod-icon");e&&(this.icon=e.trim());const t=window.getComputedStyle(this).getPropertyValue("--card-mod-icon-color");t&&(this.style.color=t)};(async()=>{const t=await ge(this);for(const s of t)s.addEventListener("card-mod-update",(async()=>{await s.updateComplete,e()}));e()})()}}));let Se=window.cardHelpers;const be=new Promise((async(t,s)=>{Se&&t();const n=async()=>{Se=await window.loadCardHelpers(),window.cardHelpers=Se,t()};window.loadCardHelpers?n():window.addEventListener("load",(async()=>{!async function(){if(customElements.get("hui-view"))return!0;await customElements.whenDefined("partial-panel-resolver");const t=document.createElement("partial-panel-resolver");if(t.hass={panels:[{url_path:"tmp",component_name:"lovelace"}]},t._updateRoutes(),await t.routerOptions.routes.tmp.load(),!customElements.get("ha-panel-lovelace"))return!1;const s=document.createElement("ha-panel-lovelace");s.hass=e(),void 0===s.hass&&(await new Promise((e=>{window.addEventListener("connection-status",(t=>{console.log(t),e()}),{once:!0})})),s.hass=e()),s.panel={config:{mode:null}},s._fetchConfig()}(),window.loadCardHelpers&&n()}))}));function Ee(e,s){const n={type:"error",error:e,origConfig:s},o=document.createElement("hui-error-card");return customElements.whenDefined("hui-error-card").then((()=>{const e=document.createElement("hui-error-card");e.setConfig(n),o.parentElement&&o.parentElement.replaceChild(e,o)})),be.then((()=>{t("ll-rebuild",{},o)})),o}function Ce(e,s){if(!s||"object"!=typeof s||!s.type)return Ee(`No ${e} type configured`,s);let n=s.type;if(n=n.startsWith("custom:")?n.substr("custom:".length):`hui-${n}-${e}`,customElements.get(n))return function(e,s){let n=document.createElement(e);try{n.setConfig(JSON.parse(JSON.stringify(s)))}catch(e){n=Ee(e,s)}return be.then((()=>{t("ll-rebuild",{},n)})),n}(n,s);const o=Ee(`Custom element doesn't exist: ${n}.`,s);o.style.display="None";const i=setTimeout((()=>{o.style.display=""}),2e3);return customElements.whenDefined(n).then((()=>{clearTimeout(i),t("ll-rebuild",{},o)})),o}const Ne="\nha-card {\n background: none;\n box-shadow: none;\n}";function Pe(){document.dispatchEvent(new Event("cm_update"))}customElements.define("mod-card",class extends ee{static get properties(){return{hass:{}}}setConfig(t){var s;this._config=JSON.parse(JSON.stringify(t));let n=(null===(s=this._config.card_mod)||void 0===s?void 0:s.style)||this._config.style;void 0===n?n=Ne:"string"==typeof n?n=Ne+n:n["."]?n["."]=Ne+n["."]:n["."]=Ne,this._config.card_mod={style:n},this.card=function(e){return Se?Se.createCardElement(e):Ce("card",e)}(t.card),this.card.hass=e()}firstUpdated(){window.setTimeout((()=>{var e,t;if(null===(t=null===(e=this.card)||void 0===e?void 0:e.shadowRoot)||void 0===t?void 0:t.querySelector("ha-card")){console.info("%cYou are doing it wrong!","color: red; font-weight: bold","");let e=this.card.localName.replace(/hui-(.*)-card/,"$1");console.info(`mod-card should NEVER be used with a card that already has a ha-card element, such as ${e}`)}}),3e3)}render(){return q` ${this.card} `}set hass(e){this.card&&(this.card.hass=e)}getCardSize(){if(this._config.report_size)return this._config.report_size;let e=this.shadowRoot;return e&&(e=e.querySelector("ha-card card-maker")),e&&(e=e.getCardSize),e&&(e=e()),e||1}});const xe=[customElements.whenDefined("home-assistant"),customElements.whenDefined("hc-main")];Promise.race(xe).then((()=>{window.setTimeout((()=>{var t,s;e().connection.subscribeEvents((()=>{window.setTimeout(Pe,500)}),"themes_updated"),null===(t=document.querySelector("home-assistant"))||void 0===t||t.addEventListener("settheme",Pe),null===(s=document.querySelector("hc-main"))||void 0===s||s.addEventListener("settheme",Pe)}),1e3)})),t("ll-rebuild",{}); 6 | -------------------------------------------------------------------------------- /www/community/lovelace-card-mod/card-mod.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/www/community/lovelace-card-mod/card-mod.js.gz -------------------------------------------------------------------------------- /www/community/lovelace-card-mod/rollup.config.js: -------------------------------------------------------------------------------- 1 | import nodeResolve from "@rollup/plugin-node-resolve"; 2 | import json from "@rollup/plugin-json"; 3 | import typescript from "rollup-plugin-typescript2"; 4 | import { terser } from "rollup-plugin-terser"; 5 | import babel from "@rollup/plugin-babel"; 6 | 7 | const dev = process.env.ROLLUP_WATCH; 8 | 9 | export default { 10 | input: "src/main.ts", 11 | output: { 12 | file: "card-mod.js", 13 | format: "es", 14 | }, 15 | plugins: [ 16 | nodeResolve(), 17 | json(), 18 | typescript(), 19 | babel({ 20 | exclude: "node_modules/**", 21 | }), 22 | !dev && terser({ format: { comments: false } }), 23 | ], 24 | }; 25 | -------------------------------------------------------------------------------- /www/community/lovelace-card-mod/rollup.config.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/www/community/lovelace-card-mod/rollup.config.js.gz -------------------------------------------------------------------------------- /www/community/lovelace-state-switch/state-switch.js: -------------------------------------------------------------------------------- 1 | !function(t){var e={};function i(s){if(e[s])return e[s].exports;var r=e[s]={i:s,l:!1,exports:{}};return t[s].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.m=t,i.c=e,i.d=function(t,e,s){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:s})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,e){if(1&e&&(t=i(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var s=Object.create(null);if(i.r(s),Object.defineProperty(s,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)i.d(s,r,function(e){return t[e]}.bind(null,r));return s},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=0)}([function(t,e,i){"use strict";i.r(e);const s=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view")),r=s.prototype.html,o=s.prototype.css;function a(){return document.querySelector("hc-main")?document.querySelector("hc-main").hass:document.querySelector("home-assistant")?document.querySelector("home-assistant").hass:void 0}function n(t,e,i=null){if((t=new Event(t,{bubbles:!0,cancelable:!1,composed:!0})).detail=e||{},i)i.dispatchEvent(t);else{var s=function(){var t=document.querySelector("hc-main");return t=t?(t=(t=(t=t&&t.shadowRoot)&&t.querySelector("hc-lovelace"))&&t.shadowRoot)&&t.querySelector("hui-view")||t.querySelector("hui-panel-view"):(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=document.querySelector("home-assistant"))&&t.shadowRoot)&&t.querySelector("home-assistant-main"))&&t.shadowRoot)&&t.querySelector("app-drawer-layout partial-panel-resolver"))&&t.shadowRoot||t)&&t.querySelector("ha-panel-lovelace"))&&t.shadowRoot)&&t.querySelector("hui-root"))&&t.shadowRoot)&&t.querySelector("ha-app-layout #view"))&&t.firstElementChild}();s&&s.dispatchEvent(t)}}let l=window.cardHelpers;const c=new Promise(async(t,e)=>{l&&t();const i=async()=>{l=await window.loadCardHelpers(),window.cardHelpers=l,t()};window.loadCardHelpers?i():window.addEventListener("load",async()=>{!function(){if(customElements.get("hui-view"))return!0;const t=document.createElement("partial-panel-resolver");if(t.hass=a(),!t.hass||!t.hass.panels)return!1;t.route={path:"/lovelace/"},t._updateRoutes();try{document.querySelector("home-assistant").appendChild(t)}catch(t){}finally{document.querySelector("home-assistant").removeChild(t)}customElements.get("hui-view")}(),window.loadCardHelpers&&i()})});function d(t,e){const i={type:"error",error:t,origConfig:e},s=document.createElement("hui-error-card");return customElements.whenDefined("hui-error-card").then(()=>{const t=document.createElement("hui-error-card");t.setConfig(i),s.parentElement&&s.parentElement.replaceChild(t,s)}),c.then(()=>{n("ll-rebuild",{},s)}),s}function u(t,e){if(!e||"object"!=typeof e||!e.type)return d(`No ${t} type configured`,e);let i=e.type;if(i=i.startsWith("custom:")?i.substr("custom:".length):`hui-${i}-${t}`,customElements.get(i))return function(t,e){let i=document.createElement(t);try{i.setConfig(JSON.parse(JSON.stringify(e)))}catch(t){i=d(t,e)}return c.then(()=>{n("ll-rebuild",{},i)}),i}(i,e);const s=d(`Custom element doesn't exist: ${i}.`,e);s.style.display="None";const r=setTimeout(()=>{s.style.display=""},2e3);return customElements.whenDefined(i).then(()=>{clearTimeout(r),n("ll-rebuild",{},s)}),s}function h(t){return l?l.createCardElement(t):u("card",t)}let p=function(){if(window.fully&&"function"==typeof fully.getDeviceId)return fully.getDeviceId();if(!localStorage["lovelace-player-device-id"]){const t=()=>Math.floor(1e5*(1+Math.random())).toString(16).substring(1);localStorage["lovelace-player-device-id"]=`${t()}${t()}-${t()}${t()}`}return localStorage["lovelace-player-device-id"]}();customElements.define("state-switch",class extends s{static get properties(){return{hass:{},state:{}}}setConfig(t){this._config=t,this.state=void 0,this.classList.add("no-match"),this.cards={};for(let e in t.states)this.cards[e]=h(t.states[e]),this.cards[e].hass=a();if("hash"===t.entity&&window.addEventListener("location-changed",()=>this.updated(new Map)),"mediaquery"===t.entity)for(const t in this.cards)window.matchMedia(t).addListener(this.update_state.bind(this));if("template"===t.entity){const e=t.template;String(e).includes("{%")||String(e).includes("{{")?function(t,e,i){t||(t=a().connection);let s={user:a().user.name,browser:p,hash:location.hash.substr(1)||" ",...i.variables},r=i.template,o=i.entity_ids;t.subscribeMessage(t=>{let i=t.result;i=i.replace(/_\([^)]*\)/g,t=>a().localize(t.substring(2,t.length-1))||t),e(i)},{type:"render_template",template:r,variables:s,entity_ids:o})}(null,t=>{this._tmpl=t,this.update_state()},{template:e,variables:{config:t},entity_ids:t.entity_ids}):this._tmpl=e}}update_state(){let t=void 0;switch(this._config.entity){case"template":t=this._tmpl;break;case"user":t=this.hass&&this.hass.user&&this.hass.user.name||void 0;break;case"group":t=this.hass&&this.hass.user&&this.hass.user.is_admin?"admin":"user";break;case"deviceID":case"browser":t=p;break;case"hash":t=location.hash.substr(1);break;case"mediaquery":for(const e in this.cards)if(window.matchMedia(e).matches){t=e;break}break;default:t=this.hass.states[this._config.entity],t=t?t.state:void 0}void 0!==t&&this.cards.hasOwnProperty(t)||(t=this._config.default),this.state=t}updated(t){if(t.has("hass"))for(let t in this.cards)this.cards[t].hass=this.hass;if(t.has("state")){const e=t.get("state");this.cards[e]&&(this.cards[e].classList.remove("visible"),this.cards[e].classList.add("out"),window.setTimeout(()=>{this.cards[e].classList.remove("out")},this._config.transition_time||500)),this.cards[this.state]?(this.cards[this.state].classList.add("visible"),this.classList.remove("no-match")):this.classList.add("no-match")}else this.update_state()}render(){return r` 2 |
10 | ${Object.keys(this.cards).map(t=>r` 11 | ${this.cards[t]} 12 | `)} 13 |
14 | `}getCardSize(){let t=1;for(let e in this.cards)this.cards[e]&&this.cards[e].getCardSize&&(t=Math.max(t,this.cards[e].getCardSize()));return t}static get styles(){return o` 15 | :host { 16 | perspective: 1000px; 17 | } 18 | :host(.no-match) { 19 | display: none; 20 | } 21 | #root * { 22 | display: none; 23 | } 24 | #root .visible { 25 | display: block; 26 | } 27 | 28 | 29 | #root.slide-right, 30 | #root.slide-left { 31 | display: grid; 32 | } 33 | #root.slide-right *, 34 | #root.slide-left * { 35 | grid-column: 1; 36 | grid-row: 1; 37 | display: block; 38 | opacity: 0; 39 | height: 0; 40 | transition-property: transform; 41 | transition-timing-function: linear; 42 | transition-duration: inherit; 43 | transform: translate(-110%); 44 | } 45 | #root.slide-left * { 46 | transform: translate(110%); 47 | } 48 | #root.slide-right .visible, 49 | #root.slide-left .visible { 50 | opacity: 1; 51 | height: auto; 52 | transform: translate(0%); 53 | } 54 | #root.slide-right .out, 55 | #root.slide-left .out { 56 | opacity: 1; 57 | height: auto; 58 | transform: translate(110%); 59 | } 60 | #root.slide-left .out { 61 | transform: translate(-110%); 62 | } 63 | 64 | 65 | #root.swap-right, 66 | #root.swap-left { 67 | display: grid; 68 | } 69 | #root.swap-right *, 70 | #root.swap-left * { 71 | grid-column: 1; 72 | grid-row: 1; 73 | display: block; 74 | opacity: 0; 75 | height: 0; 76 | transition-property: transform; 77 | transition-timing-function: linear; 78 | transition-duration: inherit; 79 | transform: translate(110%); 80 | } 81 | #root.swap-left *{ 82 | transform: translate(-110%); 83 | } 84 | #root.swap-right .visible, 85 | #root.swap-left .visible { 86 | opacity: 1; 87 | height: auto; 88 | transition-delay: inherit; 89 | transform: translate(0%); 90 | } 91 | #root.swap-right .out, 92 | #root.swap-left .out { 93 | opacity: 1; 94 | height: auto; 95 | } 96 | 97 | 98 | 99 | #root.flip { 100 | display: grid; 101 | width: 100%; 102 | height: 100%; 103 | position: relative; 104 | } 105 | #root.flip * { 106 | grid-column: 1; 107 | grid-row: 1; 108 | display: block; 109 | opacity: 0; 110 | height: 0; 111 | transform: rotateY(-180deg); 112 | transition-property: transform; 113 | transition-timing-function: linear; 114 | transition-duration: inherit; 115 | transform-style: preserve-3d; 116 | backface-visibility: hidden; 117 | z-index: 100; 118 | } 119 | #root.flip .visible { 120 | opacity: 1; 121 | height: auto; 122 | backface-visibility: hidden; 123 | transform: rotateY(0deg); 124 | } 125 | #root.flip .out { 126 | opacity: 1; 127 | height: auto; 128 | transform: rotateY(180deg); 129 | } 130 | `}})}]); -------------------------------------------------------------------------------- /www/community/lovelace-state-switch/state-switch.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/www/community/lovelace-state-switch/state-switch.js.gz -------------------------------------------------------------------------------- /www/community/lovelace-state-switch/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | entry: './src/main.js', 5 | mode: 'production', 6 | output: { 7 | filename: 'state-switch.js', 8 | path: path.resolve(__dirname) 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /www/community/lovelace-state-switch/webpack.config.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/www/community/lovelace-state-switch/webpack.config.js.gz -------------------------------------------------------------------------------- /www/community/mini-graph-card/mini-graph-card-bundle.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/www/community/mini-graph-card/mini-graph-card-bundle.js.gz -------------------------------------------------------------------------------- /www/community/mini-media-player/mini-media-player-bundle.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/www/community/mini-media-player/mini-media-player-bundle.js.gz -------------------------------------------------------------------------------- /www/community/swipe-card/swipe-card.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/www/community/swipe-card/swipe-card.js.gz -------------------------------------------------------------------------------- /www/community/vertical-stack-in-card/vertical-stack-in-card.js: -------------------------------------------------------------------------------- 1 | console.log(`%cvertical-stack-in-card\n%cVersion: ${'0.4.1'}`, 'color: #1976d2; font-weight: bold;', ''); 2 | 3 | class VerticalStackInCard extends HTMLElement { 4 | constructor() { 5 | super(); 6 | } 7 | 8 | setConfig(config) { 9 | this._cardSize = {}; 10 | this._cardSize.promise = new Promise((resolve) => (this._cardSize.resolve = resolve)); 11 | 12 | if (!config || !config.cards || !Array.isArray(config.cards)) { 13 | throw new Error('Card config incorrect'); 14 | } 15 | this._config = config; 16 | this._refCards = []; 17 | this.renderCard(); 18 | } 19 | 20 | async renderCard() { 21 | const config = this._config; 22 | if (window.loadCardHelpers) { 23 | this.helpers = await window.loadCardHelpers(); 24 | } 25 | const promises = config.cards.map((config) => this.createCardElement(config)); 26 | this._refCards = await Promise.all(promises); 27 | 28 | // Style cards 29 | this._refCards.forEach((card) => { 30 | if (card.updateComplete) { 31 | card.updateComplete.then(() => this.styleCard(card)); 32 | } else { 33 | this.styleCard(card); 34 | } 35 | }); 36 | 37 | // Create the card 38 | const card = document.createElement('ha-card'); 39 | const cardContent = document.createElement('div'); 40 | card.header = config.title; 41 | card.style.overflow = 'hidden'; 42 | this._refCards.forEach((card) => cardContent.appendChild(card)); 43 | if (config.horizontal) { 44 | cardContent.style.display = 'flex'; 45 | cardContent.childNodes.forEach((card) => { 46 | card.style.flex = '1 1 0'; 47 | card.style.minWidth = 0; 48 | }); 49 | } 50 | card.appendChild(cardContent); 51 | while (this.hasChildNodes()) { 52 | this.removeChild(this.lastChild); 53 | } 54 | this.appendChild(card); 55 | 56 | // Calculate card size 57 | this._cardSize.resolve(); 58 | } 59 | 60 | async createCardElement(cardConfig) { 61 | const createError = (error, origConfig) => { 62 | return createThing('hui-error-card', { 63 | type: 'error', 64 | error, 65 | origConfig 66 | }); 67 | }; 68 | 69 | const createThing = (tag, config) => { 70 | if (this.helpers) { 71 | if (config.type === 'divider') { 72 | return this.helpers.createRowElement(config); 73 | } else { 74 | return this.helpers.createCardElement(config); 75 | } 76 | } 77 | 78 | const element = document.createElement(tag); 79 | try { 80 | element.setConfig(config); 81 | } catch (err) { 82 | console.error(tag, err); 83 | return createError(err.message, config); 84 | } 85 | return element; 86 | }; 87 | 88 | let tag = cardConfig.type; 89 | if (tag.startsWith('divider')) { 90 | tag = `hui-divider-row`; 91 | } else if (tag.startsWith('custom:')) { 92 | tag = tag.substr('custom:'.length); 93 | } else { 94 | tag = `hui-${tag}-card`; 95 | } 96 | 97 | const element = createThing(tag, cardConfig); 98 | element.hass = this._hass; 99 | element.addEventListener( 100 | 'll-rebuild', 101 | (ev) => { 102 | ev.stopPropagation(); 103 | this.createCardElement(cardConfig).then(() => { 104 | this.renderCard(); 105 | }); 106 | }, 107 | { once: true } 108 | ); 109 | return element; 110 | } 111 | 112 | set hass(hass) { 113 | this._hass = hass; 114 | if (this._refCards) { 115 | this._refCards.forEach((card) => { 116 | card.hass = hass; 117 | }); 118 | } 119 | } 120 | 121 | styleCard(element) { 122 | const config = this._config; 123 | if (element.shadowRoot) { 124 | if (element.shadowRoot.querySelector('ha-card')) { 125 | let ele = element.shadowRoot.querySelector('ha-card'); 126 | ele.style.boxShadow = 'none'; 127 | ele.style.borderRadius = '0'; 128 | if ('styles' in config) { 129 | Object.entries(config.styles).forEach(([key, value]) => ele.style.setProperty(key, value)); 130 | } 131 | } else { 132 | let searchEles = element.shadowRoot.getElementById('root'); 133 | if (!searchEles) { 134 | searchEles = element.shadowRoot.getElementById('card'); 135 | } 136 | if (!searchEles) return; 137 | searchEles = searchEles.childNodes; 138 | for (let i = 0; i < searchEles.length; i++) { 139 | if (searchEles[i].style) { 140 | searchEles[i].style.margin = '0px'; 141 | } 142 | this.styleCard(searchEles[i]); 143 | } 144 | } 145 | } else { 146 | if (typeof element.querySelector === 'function' && element.querySelector('ha-card')) { 147 | let ele = element.querySelector('ha-card'); 148 | ele.style.boxShadow = 'none'; 149 | ele.style.borderRadius = '0'; 150 | if ('styles' in config) { 151 | Object.entries(config.styles).forEach(([key, value]) => ele.style.setProperty(key, value)); 152 | } 153 | } 154 | let searchEles = element.childNodes; 155 | for (let i = 0; i < searchEles.length; i++) { 156 | if (searchEles[i] && searchEles[i].style) { 157 | searchEles[i].style.margin = '0px'; 158 | } 159 | this.styleCard(searchEles[i]); 160 | } 161 | } 162 | } 163 | 164 | _computeCardSize(card) { 165 | if (typeof card.getCardSize === 'function') { 166 | return card.getCardSize(); 167 | } 168 | return customElements 169 | .whenDefined(card.localName) 170 | .then(() => this._computeCardSize(card)) 171 | .catch(() => 1); 172 | } 173 | 174 | async getCardSize() { 175 | await this._cardSize.promise; 176 | const sizes = await Promise.all(this._refCards.map(this._computeCardSize)); 177 | return sizes.reduce((a, b) => a + b); 178 | } 179 | } 180 | 181 | customElements.define('vertical-stack-in-card', VerticalStackInCard); 182 | -------------------------------------------------------------------------------- /www/community/vertical-stack-in-card/vertical-stack-in-card.js.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TBens/lovelace-ui-minimalist/db4b250248c4c6a1666061d358844ee529c4cd99/www/community/vertical-stack-in-card/vertical-stack-in-card.js.gz --------------------------------------------------------------------------------