Skip to content

Instantly share code, notes, and snippets.

@grischard
Last active October 2, 2024 21:56
Show Gist options
  • Save grischard/ce5b9707652b67e81bc6957911f2324a to your computer and use it in GitHub Desktop.
Save grischard/ce5b9707652b67e81bc6957911f2324a to your computer and use it in GitHub Desktop.

Revisions

  1. grischard revised this gist Oct 2, 2024. 1 changed file with 44 additions and 235 deletions.
    279 changes: 44 additions & 235 deletions swatch_beats.js
    Original file line number Diff line number Diff line change
    @@ -1,52 +1,55 @@
    class SwatchBeatBase extends HTMLElement {
    interval = null;

    connectedCallback() {
    this.interval = setInterval(() => this.updateBeats(), 86);
    if (!this.interval) {
    this.interval = setInterval(() => this.updateBeats(), 86);
    }
    }

    disconnectedCallback() {
    clearInterval(this.interval);
    if (this.interval) {
    clearInterval(this.interval);
    this.interval = null;
    }
    }

    updateBeats() {
    // 3600 seconds in an hour; 86400 seconds in a day
    const now = new Date();
    const beats = (
    (((now.getUTCHours() * 3600 +
    now.getUTCMinutes() * 60 +
    now.getUTCSeconds()) *
    1000 +
    now.getUTCSeconds()) * 1000 +
    now.getUTCMilliseconds() +
    3600000) %
    86400000) /
    86400
    3600000) % 86400000) / 86400
    ).toFixed(3);
    this.render(beats);
    }

    render(beats) {
    throw new Error('Method "render(beats)" must be implemented');
    }

    setConfig(config) {
    this.config = config;
    }
    }


    class SwatchBeatCard extends SwatchBeatBase {
    set hass(hass) {
    if (!this.content) {
    const card = document.createElement("hui-badge");
    card.header = "Swatch Internet Beats";
    this.content = document.createElement("div");
    this.content.id = "swatch-beat";
    this.content.className = "card-content";
    card.appendChild(this.content);
    this.appendChild(card);
    }
    this.updateBeats();
    constructor() {
    super();
    const card = document.createElement("ha-card");
    card.header = "Swatch Internet Beats";
    this.content = document.createElement("div");
    this.content.className = "card-content";
    card.appendChild(this.content);
    this.appendChild(card);
    }

    render(beats) {
    this.content.innerHTML = `@${beats}`;
    }

    setConfig(config) {
    this.config = config;
    this.content.textContent = `@${beats}`;
    }

    getCardSize() {
    @@ -55,218 +58,24 @@ class SwatchBeatCard extends SwatchBeatBase {
    }

    class SwatchBeatBadge extends SwatchBeatBase {
    setConfig() {}

    set hass(hass) {
    this._hass = hass;
    if (!this.shadowRoot) {
    this.attachShadow({mode: "open" });
    this.shadowRoot.innerHTML = `
    <style>
    :host {
    --badge-color: var(--state-inactive-color);
    -webkit-tap-highlight-color: transparent;
    }
    .badge.error {
    --badge-color: var(--red-color);
    }
    .badge {
    position: relative;
    --ha-ripple-color: var(--badge-color);
    --ha-ripple-hover-opacity: 0.04;
    --ha-ripple-pressed-opacity: 0.12;
    transition:
    box-shadow 180ms ease-in-out,
    border-color 180ms ease-in-out;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 8px;
    height: var(--ha-badge-size, 36px);
    min-width: var(--ha-badge-size, 36px);
    padding: 0px 8px;
    box-sizing: border-box;
    width: auto;
    border-radius: var(
    --ha-badge-border-radius,
    calc(var(--ha-badge-size, 36px) / 2)
    );
    background: var(
    --ha-card-background,
    var(--card-background-color, white)
    );
    -webkit-backdrop-filter: var(--ha-card-backdrop-filter, none);
    backdrop-filter: var(--ha-card-backdrop-filter, none);
    border-width: var(--ha-card-border-width, 1px);
    box-shadow: var(--ha-card-box-shadow, none);
    border-style: solid;
    border-color: var(
    --ha-card-border-color,
    var(--divider-color, #e0e0e0)
    );
    --mdc-icon-size: 18px;
    text-align: center;
    font-family: Roboto;
    }
    .badge:focus-visible {
    --shadow-default: var(--ha-card-box-shadow, 0 0 0 0 transparent);
    --shadow-focus: 0 0 0 1px var(--badge-color);
    border-color: var(--badge-color);
    box-shadow: var(--shadow-default), var(--shadow-focus);
    }
    button,
    [role="button"] {
    cursor: pointer;
    }
    button:focus,
    [role="button"]:focus {
    outline: none;
    }
    .badge.active {
    --badge-color: var(--primary-color);
    }
    .info {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding-right: 4px;
    padding-inline-end: 4px;
    padding-inline-start: initial;
    }
    .label {
    font-size: 10px;
    font-style: normal;
    font-weight: 500;
    line-height: 10px;
    letter-spacing: 0.1px;
    color: var(--secondary-text-color);
    }
    .content {
    font-size: 12px;
    font-style: normal;
    font-weight: 500;
    line-height: 16px;
    letter-spacing: 0.1px;
    color: var(--primary-text-color);
    }
    ha-icon,
    ha-state-icon,
    ha-svg-icon {
    color: var(--badge-color);
    line-height: 0;
    }
    img {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    object-fit: cover;
    overflow: hidden;
    }
    .badge.no-info {
    padding: 0;
    }
    .badge:not(.no-icon):not(.no-info) img {
    margin-left: -6px;
    margin-inline-start: -6px;
    margin-inline-end: initial;
    }
    .badge.no-icon .info {
    padding-right: 4px;
    padding-left: 4px;
    padding-inline-end: 4px;
    padding-inline-start: 4px;
    }
    .content {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding-right: 4px;
    padding-inline-end: 4px;
    padding-inline-start: initial;
    }
    .name {
    font-size: 10px;
    font-style: normal;
    font-weight: 500;
    line-height: 10px;
    letter-spacing: 0.1px;
    color: var(--secondary-text-color);
    }
    </style>
    <div style="" class="badge active complete " role="button" tabindex="0">
    <ha-ripple aria-hidden="true"></ha-ripple>
    <ha-icon icon="mdi:at"></ha-icon>
    <span class="content">
    <span class="name">Beats</span>
    <span class="state">
    <state-display></state-display>
    </span>
    </span>
    </div>
    `;
    this.beatsDisplay = this.shadowRoot.querySelector('state-display');
    constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
    <ha-badge>
    <ha-icon slot="icon" icon="mdi:at"></ha-icon>
    <span id="beats"></span>
    </ha-badge>
    `;
    }

    // this.beatsDisplay = document.createElement("div");
    // this.shadowRoot.appendChild(this.beatsDisplay);
    // this.content.setAttribute("style", "");
    // this.content.className = "badge active standard";
    // this.content.setAttribute("role", "button");
    // this.content.setAttribute("tabindex", "0");

    // // Ripple effect?
    // const ripple = document.createElement("ha-ripple");
    // ripple.setAttribute("aria-hidden", "true");
    // const surface = document.createElement("div");
    // surface.className = "surface";
    // ripple.appendChild(surface);
    // this.content.appendChild(ripple);

    // // State icon
    // const stateIcon = document.createElement("ha-state-icon");
    // const haIcon = document.createElement("ha-icon");
    // haIcon.setAttribute("icon", "mdi:at"); // Using mdi:at icon
    // stateIcon.appendChild(haIcon);
    // this.content.appendChild(stateIcon);

    // // Content
    // const contentSpan = document.createElement("span");
    // contentSpan.className = "content";

    // // Name
    // const nameSpan = document.createElement("span");
    // nameSpan.className = "name";
    // nameSpan.textContent = "beat"; // Set the name of your badge
    // contentSpan.appendChild(nameSpan);

    // // State
    // const stateSpan = document.createElement("span");
    // stateSpan.className = "state";
    // this.beatsDisplay = document.createElement("state-display");
    // stateSpan.appendChild(this.beatsDisplay);
    // contentSpan.appendChild(stateSpan);

    // this.content.appendChild(contentSpan);
    // this.appendChild(this.content);
    }

    this.updateBeats();
    }

    render(beats) {
    if (this.beatsDisplay) {
    this.beatsDisplay.textContent = `${beats}`;
    }
    }


    setConfig(config) {
    this.config = config;
    render(beats) {
    const beatsElement = this.shadowRoot.getElementById('beats');
    if (beatsElement) {
    beatsElement.textContent = `${beats}`; // Using template literals here as well
    }
    }

    customElements.define("swatch-beat-badge", SwatchBeatBadge);
    customElements.define("swatch-beat-card", SwatchBeatCard);
    }

    customElements.define('swatch-beat-card', SwatchBeatCard);
    customElements.define('swatch-beat-badge', SwatchBeatBadge);
  2. grischard revised this gist Sep 3, 2024. 1 changed file with 189 additions and 36 deletions.
    225 changes: 189 additions & 36 deletions swatch_beats.js
    Original file line number Diff line number Diff line change
    @@ -30,7 +30,7 @@ class SwatchBeatBase extends HTMLElement {
    class SwatchBeatCard extends SwatchBeatBase {
    set hass(hass) {
    if (!this.content) {
    const card = document.createElement("ha-card");
    const card = document.createElement("hui-badge");
    card.header = "Swatch Internet Beats";
    this.content = document.createElement("div");
    this.content.id = "swatch-beat";
    @@ -55,49 +55,202 @@ class SwatchBeatCard extends SwatchBeatBase {
    }

    class SwatchBeatBadge extends SwatchBeatBase {
    setConfig() {}

    set hass(hass) {
    this._hass = hass;
    if (!this.content) {
    this.content = document.createElement("div");
    this.content.setAttribute("style", "");
    this.content.className = "badge active standard";
    this.content.setAttribute("role", "button");
    this.content.setAttribute("tabindex", "0");
    if (!this.shadowRoot) {
    this.attachShadow({mode: "open" });
    this.shadowRoot.innerHTML = `
    <style>
    :host {
    --badge-color: var(--state-inactive-color);
    -webkit-tap-highlight-color: transparent;
    }
    .badge.error {
    --badge-color: var(--red-color);
    }
    .badge {
    position: relative;
    --ha-ripple-color: var(--badge-color);
    --ha-ripple-hover-opacity: 0.04;
    --ha-ripple-pressed-opacity: 0.12;
    transition:
    box-shadow 180ms ease-in-out,
    border-color 180ms ease-in-out;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 8px;
    height: var(--ha-badge-size, 36px);
    min-width: var(--ha-badge-size, 36px);
    padding: 0px 8px;
    box-sizing: border-box;
    width: auto;
    border-radius: var(
    --ha-badge-border-radius,
    calc(var(--ha-badge-size, 36px) / 2)
    );
    background: var(
    --ha-card-background,
    var(--card-background-color, white)
    );
    -webkit-backdrop-filter: var(--ha-card-backdrop-filter, none);
    backdrop-filter: var(--ha-card-backdrop-filter, none);
    border-width: var(--ha-card-border-width, 1px);
    box-shadow: var(--ha-card-box-shadow, none);
    border-style: solid;
    border-color: var(
    --ha-card-border-color,
    var(--divider-color, #e0e0e0)
    );
    --mdc-icon-size: 18px;
    text-align: center;
    font-family: Roboto;
    }
    .badge:focus-visible {
    --shadow-default: var(--ha-card-box-shadow, 0 0 0 0 transparent);
    --shadow-focus: 0 0 0 1px var(--badge-color);
    border-color: var(--badge-color);
    box-shadow: var(--shadow-default), var(--shadow-focus);
    }
    button,
    [role="button"] {
    cursor: pointer;
    }
    button:focus,
    [role="button"]:focus {
    outline: none;
    }
    .badge.active {
    --badge-color: var(--primary-color);
    }
    .info {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding-right: 4px;
    padding-inline-end: 4px;
    padding-inline-start: initial;
    }
    .label {
    font-size: 10px;
    font-style: normal;
    font-weight: 500;
    line-height: 10px;
    letter-spacing: 0.1px;
    color: var(--secondary-text-color);
    }
    .content {
    font-size: 12px;
    font-style: normal;
    font-weight: 500;
    line-height: 16px;
    letter-spacing: 0.1px;
    color: var(--primary-text-color);
    }
    ha-icon,
    ha-state-icon,
    ha-svg-icon {
    color: var(--badge-color);
    line-height: 0;
    }
    img {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    object-fit: cover;
    overflow: hidden;
    }
    .badge.no-info {
    padding: 0;
    }
    .badge:not(.no-icon):not(.no-info) img {
    margin-left: -6px;
    margin-inline-start: -6px;
    margin-inline-end: initial;
    }
    .badge.no-icon .info {
    padding-right: 4px;
    padding-left: 4px;
    padding-inline-end: 4px;
    padding-inline-start: 4px;
    }
    .content {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding-right: 4px;
    padding-inline-end: 4px;
    padding-inline-start: initial;
    }
    .name {
    font-size: 10px;
    font-style: normal;
    font-weight: 500;
    line-height: 10px;
    letter-spacing: 0.1px;
    color: var(--secondary-text-color);
    }
    </style>
    <div style="" class="badge active complete " role="button" tabindex="0">
    <ha-ripple aria-hidden="true"></ha-ripple>
    <ha-icon icon="mdi:at"></ha-icon>
    <span class="content">
    <span class="name">Beats</span>
    <span class="state">
    <state-display></state-display>
    </span>
    </span>
    </div>
    `;
    this.beatsDisplay = this.shadowRoot.querySelector('state-display');

    // this.beatsDisplay = document.createElement("div");
    // this.shadowRoot.appendChild(this.beatsDisplay);
    // this.content.setAttribute("style", "");
    // this.content.className = "badge active standard";
    // this.content.setAttribute("role", "button");
    // this.content.setAttribute("tabindex", "0");

    // Ripple effect?
    const ripple = document.createElement("ha-ripple");
    ripple.setAttribute("aria-hidden", "true");
    const surface = document.createElement("div");
    surface.className = "surface";
    ripple.appendChild(surface);
    this.content.appendChild(ripple);
    // // Ripple effect?
    // const ripple = document.createElement("ha-ripple");
    // ripple.setAttribute("aria-hidden", "true");
    // const surface = document.createElement("div");
    // surface.className = "surface";
    // ripple.appendChild(surface);
    // this.content.appendChild(ripple);

    // State icon
    const stateIcon = document.createElement("ha-state-icon");
    const haIcon = document.createElement("ha-icon");
    haIcon.setAttribute("icon", "mdi:at"); // Using mdi:at icon
    stateIcon.appendChild(haIcon);
    this.content.appendChild(stateIcon);
    // // State icon
    // const stateIcon = document.createElement("ha-state-icon");
    // const haIcon = document.createElement("ha-icon");
    // haIcon.setAttribute("icon", "mdi:at"); // Using mdi:at icon
    // stateIcon.appendChild(haIcon);
    // this.content.appendChild(stateIcon);

    // Content
    const contentSpan = document.createElement("span");
    contentSpan.className = "content";
    // // Content
    // const contentSpan = document.createElement("span");
    // contentSpan.className = "content";

    // Name
    const nameSpan = document.createElement("span");
    nameSpan.className = "name";
    nameSpan.textContent = "beat"; // Set the name of your badge
    contentSpan.appendChild(nameSpan);
    // // Name
    // const nameSpan = document.createElement("span");
    // nameSpan.className = "name";
    // nameSpan.textContent = "beat"; // Set the name of your badge
    // contentSpan.appendChild(nameSpan);

    // State
    const stateSpan = document.createElement("span");
    stateSpan.className = "state";
    this.beatsDisplay = document.createElement("state-display");
    stateSpan.appendChild(this.beatsDisplay);
    contentSpan.appendChild(stateSpan);
    // // State
    // const stateSpan = document.createElement("span");
    // stateSpan.className = "state";
    // this.beatsDisplay = document.createElement("state-display");
    // stateSpan.appendChild(this.beatsDisplay);
    // contentSpan.appendChild(stateSpan);

    this.content.appendChild(contentSpan);
    this.appendChild(this.content);
    // this.content.appendChild(contentSpan);
    // this.appendChild(this.content);
    }

    this.updateBeats();
  3. grischard created this gist Aug 31, 2024.
    119 changes: 119 additions & 0 deletions swatch_beats.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,119 @@
    class SwatchBeatBase extends HTMLElement {
    connectedCallback() {
    this.interval = setInterval(() => this.updateBeats(), 86);
    }

    disconnectedCallback() {
    clearInterval(this.interval);
    }

    updateBeats() {
    const now = new Date();
    const beats = (
    (((now.getUTCHours() * 3600 +
    now.getUTCMinutes() * 60 +
    now.getUTCSeconds()) *
    1000 +
    now.getUTCMilliseconds() +
    3600000) %
    86400000) /
    86400
    ).toFixed(3);
    this.render(beats);
    }

    render(beats) {
    throw new Error('Method "render(beats)" must be implemented');
    }
    }

    class SwatchBeatCard extends SwatchBeatBase {
    set hass(hass) {
    if (!this.content) {
    const card = document.createElement("ha-card");
    card.header = "Swatch Internet Beats";
    this.content = document.createElement("div");
    this.content.id = "swatch-beat";
    this.content.className = "card-content";
    card.appendChild(this.content);
    this.appendChild(card);
    }
    this.updateBeats();
    }

    render(beats) {
    this.content.innerHTML = `@${beats}`;
    }

    setConfig(config) {
    this.config = config;
    }

    getCardSize() {
    return 1;
    }
    }

    class SwatchBeatBadge extends SwatchBeatBase {
    set hass(hass) {
    this._hass = hass;
    if (!this.content) {
    this.content = document.createElement("div");
    this.content.setAttribute("style", "");
    this.content.className = "badge active standard";
    this.content.setAttribute("role", "button");
    this.content.setAttribute("tabindex", "0");

    // Ripple effect?
    const ripple = document.createElement("ha-ripple");
    ripple.setAttribute("aria-hidden", "true");
    const surface = document.createElement("div");
    surface.className = "surface";
    ripple.appendChild(surface);
    this.content.appendChild(ripple);

    // State icon
    const stateIcon = document.createElement("ha-state-icon");
    const haIcon = document.createElement("ha-icon");
    haIcon.setAttribute("icon", "mdi:at"); // Using mdi:at icon
    stateIcon.appendChild(haIcon);
    this.content.appendChild(stateIcon);

    // Content
    const contentSpan = document.createElement("span");
    contentSpan.className = "content";

    // Name
    const nameSpan = document.createElement("span");
    nameSpan.className = "name";
    nameSpan.textContent = "beat"; // Set the name of your badge
    contentSpan.appendChild(nameSpan);

    // State
    const stateSpan = document.createElement("span");
    stateSpan.className = "state";
    this.beatsDisplay = document.createElement("state-display");
    stateSpan.appendChild(this.beatsDisplay);
    contentSpan.appendChild(stateSpan);

    this.content.appendChild(contentSpan);
    this.appendChild(this.content);
    }

    this.updateBeats();
    }

    render(beats) {
    if (this.beatsDisplay) {
    this.beatsDisplay.textContent = `${beats}`;
    }
    }


    setConfig(config) {
    this.config = config;
    }
    }

    customElements.define("swatch-beat-badge", SwatchBeatBadge);
    customElements.define("swatch-beat-card", SwatchBeatCard);