Mushroom Cards - Build a beautiful dashboard easily šŸ„ (Part 1)

Iā€™m using

--chip-spacing: -12px !important;

to get chips close enough together for my cards

2 Likes

Thank you for your response. However, what I am trying to do is add a new button that will open another window to activate the timer. Specifically, I have created an input boolean for the fan to turn on for 20 minutes, 30 minutes, and 120 minutes, with the name ā€œ20ā€, ā€œ30ā€, and ā€œ120ā€ respectively.( input_boolean.fan_on_for_20_minutes_minutes_minutes_minutes_minutes_minutes
name: 20) The service I am using is ā€œscript.set_20_time_for_fan_parentsā€. My question is, how can I add these options to the new window I am creating with the additional button? Thank you for your assistance.

I also adapted your code to no longer go through state-switch but rather with conditional-card and CSS:

Without media_player being played:

Capture

When media_player is playing or paused:

Capture2

      - type: horizontal-stack
        cards:
          - type: custom:mushroom-template-card
            primary: Search...
            secondary: ''
            icon: mdi:search-web
            icon_color: white
            entity: input_select.plex_recently
            tap_action:
              action: fire-dom-event
              browser_mod:
                service: browser_mod.popup
                data:
                  title: ChatGPT
                  content:
                    type: custom:stack-in-card
                    cards:
                      - type: entities
                        entities:
                          - entity: input_text.gpt_prompt
                      - type: markdown
                        content: >-
                          {{ state_attr('sensor.hassio_mindsdb_response',
                          'response_text') }}
                        title: RĆ©ponse
            card_mod:
              style: |
                ha-card {
                  {% if is_state('media_player.currently_playing', ['idle','off']) %}
                    background: var(--card-background-color) !important;
                    box-shadow: var(--ha-card-box-shadow) !important;
                    width: 100%;
                    --spacing: 5px;
                    margin-bottom: 2px;
                    margin-top: 2px;
                    border-radius: calc(var(--ha-card-border-radius, 12px) * 2) !important;
                    margin-left: 0px;
                    margin-right: auto;
                  {% else %}
                    width: 50px;
                    --spacing: 5px;
                    background: var(--card-background-color) !important;
                    box-shadow: var(--ha-card-box-shadow) !important;
                    border-radius: calc(var(--ha-card-border-radius, 12px) * 2) !important;
                    margin-top: 2px;
                    margin-bottom: 2px;
                    margin-left: 1%;
                    transition: all 0.5s;
                  {% endif %} 
                }
                ha-card:hover {
                  background: color-mix(in srgb, var(--{{ config.icon_color }}-color) 25%, var(--card-background-color)) !important;
                  transition: all 0.1s;
                }
          - type: conditional
            conditions:
              - entity: media_player.currently_playing
                state_not: 'off'
              - entity: media_player.currently_playing
                state_not: idle
            card:
              type: custom:stack-in-card
              mode: horizontal
              cards:
                - type: custom:mushroom-media-player-card
                  entity: media_player.currently_playing
                  layout: horizontal
                  show_volume_level: true
                  use_media_info: true
                  tap_action:
                    action: fire-dom-event
                    browser_mod:
                      service: browser_mod.popup
                      data:
                        title: En cours
                        content:
                          type: custom:stack-in-card
                          cards:
                            - type: custom:mushroom-media-player-card
                              entity: media_player.currently_playing
                              icon_type: none
                              layout: vertical
                              media_controls:
                                - previous
                                - play_pause_stop
                                - next
                              volume_controls:
                                - volume_set
                                - volume_buttons
                              show_volume_level: false
                              use_media_info: true
                              collapsible_controls: false
                              card_mod:
                                style:
                                  mushroom-state-info$: |
                                    /* CSS for Mushroom Popup Media Player */
                                    .secondary:before {

                                      /* Add album name between song title and artist name */
                                      {% if state_attr(config.entity, 'media_album_name') != none %}
                                        content: "{{ state_attr(config.entity, 'media_album_name')}}\A";
                                      {% endif %}

                                      /* Format title to fit on seperate line */
                                      white-space: pre;
                                      text-overflow: ellipsis;
                                    }
                                  .: |
                                    ha-card {

                                      /* Remove border from media player */
                                      --ha-card-border-width: 0;

                                      /* Apply album art color to media player icon & volume bar */
                                      --rgb-state-media-player: var(--album-art-color);

                                      /* Disable transitions */
                                      transition: all 0.5s;
                                    }
                                    .actions {

                                      /* Apply album art color to media player controls */
                                      --rgb-primary-text-color: var(--album-art-color);
                                      --primary-text-color: rgb(var(--album-art-color));

                                      /* Move volume button to seperate row */
                                      display: block !important;
                                    }
                                    ha-card:before {
                                      content: "";

                                      /* Show album art above media player when active and default image when idle */
                                      {% if is_state(config.entity, ['playing', 'paused']) %}
                                        background: url( '{{ state_attr(config.entity, "entity_picture") }}') center no-repeat;
                                      {% else %}
                                        background: url('/local/idle_art.png') center no-repeat;
                                      {% endif %}

                                      /* Add padding around album art */
                                      margin: 0px 4px 16px;

                                      /* Add drop shadow to album art */
                                      filter: drop-shadow(4px 4px 6px rgba(var(--album-art-color), 0.3));

                                      /* Round borders of album art */
                                      border-radius: var(--control-border-radius);

                                      /* Adjust the album art aspect ratio based on media type */
                                      {% set media_type = state_attr(config.entity, 'media_content_type') %}
                                      {% if media_type == 'tvshow' %}
                                        aspect-ratio: 16 / 9;
                                      {% elif media_type == 'movie' %}
                                        aspect-ratio: 2 / 3;
                                      {% else %}
                                        aspect-ratio: 1 / 1;
                                      {% endif %}

                                      /* Stretch album art to fit box. Fix for if album art is not sized correctly */
                                      background-size: 100% 100%;
                                    }
                                    mushroom-button {

                                      /* Size volume button to match other controls and center */
                                      display: flex;
                                      width: calc((100% / 3) - (var(--spacing) / 3) * 2);
                                      margin: auto;
                                    }
                                    mushroom-media-player-media-control,
                                    mushroom-media-player-volume-control {

                                      /* Correct margins for volume button on second row */
                                      display: flex;
                                      margin-right: 0px !important;
                                      
                                      /* Check if PLAY|STOP are supported and adjust margin accordingly */
                                      {% if state_attr(config.entity, 'supported_features') | int | bitwise_and(20480) > 0 %}
                                        margin-bottom: var(--spacing) !important;
                                      {% endif %}
                                    }
                            - entity: media_player.currently_playing
                              hide:
                                icon: true
                                name: true
                                runtime: true
                                source: true
                                power: true
                                state_label: true
                                volume: true
                                info: true
                                progress: false
                                controls: true
                              more_info: false
                              type: custom:mini-media-player
                              toggle_power: false
                              group: true
                              card_mod:
                                style:
                                  mmp-progress$: |
                                    paper-progress {

                                      /* Apply album art color to progress bar when paused */
                                      --paper-progress-container-color: rgba(var(--album-art-color), 0.2) !important;
                                      
                                      /* Apply album art color to progress bar when playing */
                                      --paper-progress-active-color: rgb(var(--album-art-color)) !important;
                                    }
                                  .: |
                                    ha-card {

                                      /* Move progress bar up into gap. Check if PLAY|STOP are supported */
                                      --base-offset: calc(4 * var(--mush-spacing, 12px)
                                                          + 1.33 * var(--mush-spacing, 12px)
                                                          + var(--mush-card-primary-line-height, 1.5) * var(--mush-card-primary-font-size, 14px)
                                                          + var(--mush-card-secondary-line-height, 1.5) * var(--mush-card-secondary-font-size, 12px)
                                                          + var(--mush-control-height, 42px));

                                      /* Check if Play (16385) or Stop (4096) are supported and add control button height if they are */
                                      {% if state_attr(config.entity, 'supported_features') | int | bitwise_and(20480) > 0 %}
                                        --control-offset: calc(var(--mush-spacing, 12px) + var(--mush-control-height, 42px));
                                      {% else %}
                                        --control-offset: 0px;
                                      {% endif %}

                                      /* Check if album name is present and add to height if it is */
                                      {% set album_name = state_attr(config.entity, 'media_album_name') %}
                                      {% if album_name == None or album_name == "" %}
                                        --album-offset: 0px;
                                      {% else %}
                                        --album-offset: calc(var(--mush-card-secondary-line-height, 1.5) * var(--mush-card-secondary-font-size, 12px));
                                      {% endif %}

                                      bottom: calc(var(--base-offset) + var(--control-offset) + var(--album-offset));

                                      /* Correct margins for progress bar */
                                      margin: 0px 28px -12px;

                                      /* Set height of card to match pregress bar height */
                                      height: var(--mmp-progress-height);

                                      /* Remove border outline */
                                      --ha-card-border-width: 0;

                                      /* Round corners of progress bar */
                                      --mmp-border-radius: var(--control-border-radius, 12px) !important;

                                      /* Set height of progress bar */
                                      --mmp-progress-height: 12px !important;

                                      /* Remove transitions to prevent progress bar floating in */
                                      transition: all 0.5s;
                                    }
                          card_mod:
                            style: |
                              :host {

                                /* Assign album art color to variable used in popup */
                                --album-art-color:      
                                {% if is_state('media_player.currently_playing', ['playing', 'paused']) %}
                                  {{ states('sensor.muted_color') }}
                                {% else %}
                                  141, 117, 238
                                {% endif %};

                                /* Remove background because it is applied to popup */
                                --ha-card-background: none;

                                
                              }
                        card_mod:
                          style:
                            ha-dialog$: |
                              .mdc-dialog__surface {

                                /* Apply gradient background to popup using album art colors. Set to default colors when idle */
                                {% if is_state('media_player.currently_playing', ['playing', 'paused']) %}
                                  background: linear-gradient(305deg, transparent 50%, rgba({{ states('sensor.dark_vibrant_color') }}, 0.4)), 
                                              linear-gradient(55deg, transparent 50%, rgba({{ states('sensor.vibrant_color') }}, 0.2)),  
                                              linear-gradient(180deg, transparent 40%, rgba({{ states('sensor.dark_muted_color') }}, 0.3));
                                {% else %}
                                  background: linear-gradient(0deg, transparent 40%, rgba(192, 127, 190, 0.3)), 
                                              linear-gradient(240deg, transparent 40%, rgba(143, 119, 237, 0.3)),  
                                              linear-gradient(120deg, transparent 40%, rgba(122, 181, 239, 0.3));
                                {% endif %}
                              }
                            ha-header-bar$: |
                              .mdc-top-app-bar {

                                /* Remove header background so that popup background is visible */
                                --mdc-theme-primary: none;

                                /* Reduced the gap between header and album art */
                                margin-bottom: -16px;
                              }
                            .: |
                              :host {

                                /* Set width of popup */
                                --popup-min-width: 450px;
                              }
                  card_mod:
                    style: |
                      mushroom-shape-icon {
                        display: flex;
                        {% set media_type = state_attr(config.entity, 'media_content_type') %}
                        {% if media_type == 'tvshow' %}
                          --card-mod-icon: mdi:television-classic;
                          animation: flicker 1s linear infinite alternate;
                        {% elif media_type == 'movie' %}
                          --card-mod-icon: mdi:movie-roll;
                          --icon-animation: spin 2s linear infinite reverse;
                        {% elif media_type == 'music' %}
                          --card-mod-icon: mdi:music;
                          animation: beat 1.3s ease-out infinite both;
                        {% elif media_type == 'playlist' %}
                          --card-mod-icon: mdi:music;
                          animation: beat 1.3s ease-out infinite both;
                        {% else %}
                          --card-mod-icon: mdi:play;
                        {% endif %}
                      }
                      @keyframes flicker {
                        0%, 31.98%, 32.98%, 34.98%, 36.98%, 39.98%, 67.98%, 68.98%, 95.98%, 96.98%, 97.98%, 98.98%, 100% { --icon-color: rgba(var(--rgb-indigo), 1); }
                        32%, 33%, 35%, 36%, 37%, 40%, 68%, 69%, 96%, 97%, 98%, 99% { --icon-color: rgba(var(--rgb-indigo), 0.6); }
                      }
                      @keyframes beat {
                        0%, 60% { --icon-symbol-size: 21px; }
                        5%, 17%, 57% { --icon-symbol-size: 22px; }
                        10%, 20%, 51% { --icon-symbol-size: 23px; }
                        25%, 45% { --icon-symbol-size: 24px; }
                        30%, 39% { --icon-symbol-size: 25px; }
                        33% { --icon-symbol-size: 26px; }
                      }
                      ha-card {
                        {% if not is_state(config.entity, 'off') %}
                          background: rgba(var(--rgb-card-background-color), 0.6) url( '{{ state_attr(config.entity, "entity_picture") }}' ) center no-repeat;
                          background-size: cover;
                          background-blend-mode: overlay;
                        {% endif %} 
                        border-radius: 35px 35px 35px 35px !important;
                        height: 55px !important;
                        margin-left: -8px;
                      }
              card_mod:
                style: |
                  ha-card {
                    {% if is_state('media_player.currently_playing', ['playing','paused']) %}
                      background-image: url( '{{ state_attr( "media_player.currently_playing", "entity_picture" ) }}' );
                      background-position: center;
                      background-repeat: no-repeat;
                      background-size: cover;
                      background-color: rgba(var(--rgb-card-background-color), 0.8);
                      background-blend-mode: overlay;
                      position: relative;
                      margin-left: -72%;
                      width: 170%;
                      border-radius: 35px 35px 35px 35px !important;
                      transition: all 0.5s;
                    {% else %}
                      width: 50px;
                      --spacing: 5px;
                      background: var(--card-background-color) !important;
                      box-shadow: var(--ha-card-box-shadow) !important;
                      border-radius: calc(var(--ha-card-border-radius, 12px) * 2) !important;
                      margin-top: 2px;
                      margin-left: auto;
                      margin-right: -64%;
                      transition: all 0.5s;
                    {% endif %} 
                  }

I also applied a color modification depending on the media being played:

    ha-card:before {
      content: "";
      position: absolute;
      top: 0px;
      left: 0px;
      height: 100%;
      width: calc(100% - 2 * var(--ha-card-border-width, 1px));
      z-index: -1;
      backdrop-filter: blur(12px);
      -webkit-backdrop-filter: blur(12px);
      border-radius: 35px;
      box-shadow: var(--ha-card-box-shadow);
      border: var(--ha-card-border-width, 1px) solid var(--ha-card-border-color, var(--divider-color, #e0e0e0));
      {% if is_state('media_player.currently_playing', ['playing', 'paused']) %}
        background: linear-gradient(135deg, rgba({{ states('sensor.dark_vibrant_color') }}, 0.85), rgba({{ states('sensor.dark_muted_color') }}, 0.75));
      {% else %}
        background: rgba(var(--rgb-card-background-color), 0.20);
      {% endif %}
    }

header2

11 Likes

That looks amazing! I am also using a bottom bar, but I havenā€™t been able to get it exacly how I want it. Would you mind sharing your code on how you did it? I am very interested in implementing the ā€œleft-rightā€ swiping.

Also, I saw your search button is linked to ChatGPT? Can I ask you how you have integrated that?

Thanks :slight_smile:

great!
I was really looking for someone to help me with the development.

Share all the code please.

1 Like

Hi,

I will share my bar code soon.

Regarding ChatGPT, I went through this integration:

1 Like

I opted for a dashboard with a single view. To keep and use only one menu bar on my entire dashboard.
I chose to use local-conditional-card to do this.
It also allows me to easily manage which cards are shown or hidden.

Result:

mushroom

Here is the full code for my top bar:

19 Likes

Is there anyway to change the colors of the alarm card icon? The normal alarm card uses blue for disarmed and green for armed. Iā€™d like to make it green for disarmed, and red for armed, but I donā€™t see options in the visual editor or looking over the options on github. Iā€™m guessing Iā€™d have to use a template card, but I also want the arm/disarm buttons at the bottom of the card.

This is how I want it to look, just the colors of the icon different.

image

Any suggestions?

Can you make a version of this with ā€œtype: custom:search-cardā€ if you have it, please? Thanks.

I replaced the first card with it and doesnā€™t look right for me so maybe you can style it better.

1 Like

something like thisā€¦

card_mod:
  style:
    mushroom-shape-icon$: |
      .shape {
        {% if is_state('xxxx', 'on') %}
           --shape-color: rgba(var(--rgb-red), 0.25);
           --icon-color: rgba(var(--rgb-white), 1);
        {% else %}
           --shape-color: rgba(var(--rgb-green), 0.25);
           --icon-color: rgba(var(--rgb-white), 1);
        {% endif %}
      }

2 Likes

Thank you, that worked perfectly. I hadnā€™t thought about using a card mod, and honestly, Iā€™d never used one before to know how to do that even if I had. I really appreciate it.

Hi,

Iā€™m facing an issue where I canā€™t get nested mushroom template chips (combined with different mushroom cards in a vertical-stack-in-card) to be visible in chrome or edge browser on e.g. desktop/tablet or the companion app on my phone.

However, it is working when showing the same view on my mobile in brave browser or opera on my desktop. And I can also see those conditional mushroom chips in edit mode, every time.

Is there anybody who has an idea, why that is the case? I canā€™t seem to figure out, why this is behaving so inconsistently.

Iā€™ve already been playing around and tested different approaches (for the conditional visibility). I tried the ā€œoriginalā€ approach, from the code example I started with, with the conditional card and also tried to achieve a similar behaviour with only a conditional if-clause in the icon-value.

I also played around with different margins and sizes in general. But it was never consistently showing in all contexts (except for the mentioned contexts where it always works, e.g. edit mode).

My current approach is using conditional if-clauses in the icon parameter value, instead of conditional cards. Hereā€™s a code example.

- type: custom:vertical-stack-in-card
cards:
  - type: custom:mushroom-template-card
	entity: sensor.lights_currently_turned_on
	icon: mdi:lightbulb-group
	icon_color: |
	  {% if states('sensor.lights_currently_turned_on') == '0' %}
		grey
	  {% else %}  
		#f39c12
	  {% endif %}
	primary: Licht
	secondary: |
	  {% if states('sensor.lights_currently_turned_on') == '0' %}
		aus
	  {% else %}
		{{ states('sensor.lights_currently_turned_on') }} eingeschaltet
	  {% endif %}
	layout: horizontal
	tap_action:
	  action: navigate
	  navigation_path: /dashboard-start/lichtsteuerung
	double_tap_action:
	  action: navigate
	  navigation_path: /dashboard-start/lichtsteuerung
	hold_action:
	  action: toggle
	card_mod:
	  style:
		mushroom-state-info$: |
		  .primary {
			font-size: 14px !important;
			position: relative;
			top: -50px;
			left: -160px;
			overflow: visible !important;
			white-space: normal !important;
		  }
		  .secondary {
			position: relative;
			overflow: visible !important;
			top: -52px;
			left: -160px;
		  }
		mushroom-shape-icon$: |
		  .shape {
			position: relative;
			left: -50px;
			top: 45px;
		  }
		.: |
		  :host {
			--mush-icon-size: 146px;
		  }
  - type: custom:mushroom-chips-card
	chips:
	  - type: template
		entity: media_player.player
		icon: >-
		  {% if is_state('media_player.player', 'on') or
		  is_state('media_player.player_zone_2', 'on') %}
			{% if is_state('media_player.player', 'on') and (is_state_attr('media_player.player', 'source',
				'strm-box') or                
				is_state_attr('media_player.player', 'source',
				'video1') or
				is_state_attr('media_player.player', 'source',
				'video2') or
				is_state_attr('media_player.player', 'source',
				'video3') or
				is_state_attr('media_player.player', 'source',
				'video4') or
				is_state_attr('media_player.player', 'source',
				'video5') or
				is_state_attr('media_player.player', 'source',
				'video6')) %}
				  mdi:television-play
			{% else %} 
			  mdi:music
			{% endif %}
		  {% else %}

		  {% endif %}
		icon_color: blue
		content_info: none
	card_mod:
	  style:
		.: |
		  ha-card {
			width: 66px;
			margin-left: 75%;;
			top: -70px;
			background: none;
			--chip-border-width: 0;
		  }
		  :host {
			--mush-icon-size: 20px;
			--mush-chip-spacing: -2.9px;
		  }

The result remains the same.
In card-editor view the ā€œconditional mushroom chipsā€ work like a charm.

In most contexts the ā€œconditional mushroom template chipsā€ can only be seen, if the whole browser/app was stopped and re-run. Sometimes those chips become visible. But after some time it stops working again and needs a new restart-cycle, to maybe become visible again.

I dont suppose anyone has got a card that you can add a google calendar event ?

I want to choose the date, time and name and pick the calendar I would like to add it to.

The service for this isnt the friendliest, so was hoping there was a card or way to do this

Thanks

@rhysb

Kindly guideā€¦

Put this code in your configuration.yaml

binary_sensor:
   - platform: template
     sensors:
       general_high_temperature_alert sensation:
         friendly_name: "Kitchen high temperature warning."
         value_template: "{{ states('sensor.media_thermal_sensation') | float > 25 }}"

       general_low_temperature_alert sensation:
         friendly_name: "Kitchen low temperature warning."
         value_template: "{{ states('sensor.media_thermal_sensation') | float < 15 }}"

This will create the necessary sensors to work in friend code, Iā€™ve changed the names to my language, feel free to customize. The principle will be the same.

About the sensor.nightstate, I didnā€™t use it, I preferred to put an entity that shows humidity, but if you want:

sensor:
   - platform: template
     sensors:
       night_state:
         friendly_name: "State of the Night"
         value_template: >
           {% if is_state('sun.sun', 'below_horizon') %}
             Night
           {% else %}
             Day
           {% endif %}

Sorry for any translation errors, Iā€™m using google.

How can I make it work vertically to increase and decrease using the mouse

20230607153742

  - type: grid
    columns: 1
    cards:
      - type: custom:mushroom-number-card
        entity: input_number.set_temperatura
        fill_container: false
        secondary_info: none
        icon_type: none
        primary_info: state
        icon_color: red
        card_mod:
          style:
            mushroom-state-info$: |
              .primary {
                position: absolute;
                top: 35px !important;
                left: 200px !important;
              }
            .: |
              ha-card {
                top: 100px!important;
                width: 300px !important;
                transform: rotate(-90deg);
                background: transparent !important;
                box-shadow: none !important;
              }       
1 Like

Iā€™m sure this is another simple fix, but Iā€™m trying to get Chips to align closer together. They look ok if you have several with a bunch of text, but Iā€™m trying to have a Menu Chip, Back Chip, and a Navigation Chip all together in a Horizontal Stack. How can I move them closer together to the left side of the Stack?

image

Add a ā€œspacerā€ as the last ā€œchipā€

1 Like

That worked, I had to add a bunch to get them moved over where I wanted them, but it solved the issue. Thanks!!!

Can something help please