Skip to content

Instantly share code, notes, and snippets.

@alex-phillips
Created March 21, 2025 00:29
Show Gist options
  • Select an option

  • Save alex-phillips/f5fb91c801ad8b2b45231b11da255262 to your computer and use it in GitHub Desktop.

Select an option

Save alex-phillips/f5fb91c801ad8b2b45231b11da255262 to your computer and use it in GitHub Desktop.

Revisions

  1. alex-phillips created this gist Mar 21, 2025.
    171 changes: 171 additions & 0 deletions music-group-card.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,171 @@
    import {
    LitElement,
    html,
    css,
    } from "https://unpkg.com/[email protected]/lit-element.js?module";

    class MusicGroupCard extends LitElement {
    static get properties() {
    return {
    hass: {},
    config: {},
    };
    }

    render() {
    return html` <div>${this.renderPlayers()}</div> `;
    }

    renderPlayers() {
    const players = this.config.players
    .map((player) => {
    return {
    name: player.name,
    entity_id: player.entity_id,
    default_source: player.default_source,
    isGrouped: this.hass.states[player.entity_id].attributes.source === this.config.source,
    };
    })
    // .sort((a, b) => a.name.localeCompare(b.name))
    // .sort((a, b) => {
    // if (a.isGrouped && !b.isGrouped) {
    // return -1;
    // }
    // return 0;
    // });
    return html`<div class="chips">
    ${players.map((player) => {
    return html`
    <div
    @click="${() => {
    if (player.isGrouped) {
    this._ungroupSpeaker(player.entity_id, player.default_source);
    } else {
    this._groupSpeaker(player.entity_id);
    }
    }}"
    class="chip hide-scrollbar ${!player.isGrouped
    ? "chip-inactive"
    : "chip-active"}"
    >
    <div style="display: flex; aligh-items: center; justify-content: space-between;">
    <div class="music-group-circle" style="cursor: pointer;">
    <ha-icon class="bubble-icon icon" style="color: inherit;" icon="${player.isGrouped ? "mdi:speaker" : "mdi:speaker-off"}"></ha-icon>
    </div>
    <div class="music-group-name">
    ${player.name}
    </div>
    </div>
    </div>
    `;
    })}
    </div> `;
    }

    _ungroupSpeaker(entity_id, source) {
    this.hass.callService("media_player", "select_source", {
    entity_id: entity_id,
    source: source
    });
    }

    _groupSpeaker(entity_id) {
    this.hass.callService("media_player", "select_source", {
    entity_id: entity_id,
    source: this.config.source
    });
    }

    setConfig(config) {
    if (!config.source) {
    throw new Error("You need to define the source");
    }
    this.config = config;
    }

    // The height of your card. Home Assistant uses this to automatically
    // distribute all cards over the available columns.
    getCardSize() {
    return 1;
    }

    static get styles() {
    return css`
    :host {
    :host {
    }
    }
    .hide-scrollbar {
    /*FireFox*/
    scrollbar-width: none;
    /*IE10+*/
    -ms-overflow-style: -ms-autohiding-scrollbar;
    }
    .hide-scrollbar::-webkit-scrollbar {
    /*Chrome, Safari, Edge*/
    display: none;
    }
    .icon {
    // --mdc-icon-size: 16px;
    fill: var(--primary-text-color);
    color: var(--primary-text-color);
    current-color: var(--primary-text-color);
    }
    .chips {
    display: flex;
    flex-direction: row;
    justify-content: space-around;
    overflow-x: auto;
    }
    .chip {
    display: flex;
    flex-direction: row;
    height: 50px;
    width: 100%;
    // font-size: 13px;
    font-weight: 500;
    color: rgba(0, 0, 0, 0.6);
    line-height: 32px;
    padding: 0;
    border-radius: 32px;
    background-color: var(--secondary-background-color);
    color: var(--primary-text-color);
    // margin-bottom: 5px;
    margin: 0px 2px;
    justify-content: space-between;
    align-items: center;
    gap: 4px;
    text-wrap: nowrap;
    cursor: pointer;
    transition: background-color 0.5s linear;
    }
    .music-group-circle {
    display: flex;
    flex-wrap: wrap;
    align-content: center;
    justify-content: center;
    min-width: 38px;
    min-height: 38px;
    border-radius: 50%;
    background-color: var(--card-background-color, var(--ha-card-background));
    overflow: hidden;
    position: relative;
    margin: 6px;
    }
    .music-group-name {
    display: flex;
    justify-content: center;
    flex-direction: column;
    margin-left: 4px;
    }
    .chip-inactive {
    // opacity: 0.5;
    }
    .chip-active {
    // background-color: rgba(255, 152, 0);
    background-color: var(--accent-color);
    }
    `;
    }
    }
    customElements.define("music-group-card", MusicGroupCard);