1441 lines
240 KiB
JavaScript
1441 lines
240 KiB
JavaScript
|
(()=>{"use strict";var __webpack_modules__={946:(e,t,n)=>{function o(e,t=40){if(Array.isArray(e)&&3===e.length){for(let t=0;t<3;t++)if(e[t]<0||e[t]>255)return;return e.every((e=>Math.abs(e-255)<=t))}}let a;function i(e,t,n=1){if(e.startsWith("#"))if(4===e.length){let o=Math.min(255,parseInt(e.charAt(1).repeat(2),16)*n),i=Math.min(255,parseInt(e.charAt(2).repeat(2),16)*n),r=Math.min(255,parseInt(e.charAt(3).repeat(2),16)*n);a="rgba("+o+", "+i+", "+r+", "+t+")"}else{let o=Math.min(255,parseInt(e.slice(1,3),16)*n),i=Math.min(255,parseInt(e.slice(3,5),16)*n),r=Math.min(255,parseInt(e.slice(5,7),16)*n);a="rgba("+o+", "+i+", "+r+", "+t+")"}else if(e.startsWith("rgb")){let o=e.match(/\d+/g);a="rgba("+Math.min(255,o[0]*n)+", "+Math.min(255,o[1]*n)+", "+Math.min(255,o[2]*n)+", "+t+")"}else if(e.startsWith("var(--")){let o=e.slice(4,-1),r=window.getComputedStyle(document.documentElement).getPropertyValue(o);(r.startsWith("#")||r.startsWith("rgb"))&&(a=i(r,t,n))}return a}n.d(t,{_k:()=>i,wW:()=>o})},191:(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{__webpack_require__.d(__webpack_exports__,{BX:()=>fireEvent,GP:()=>applyScrollingEffect,IL:()=>getAttribute,Jn:()=>tapFeedback,OC:()=>isEntityType,P2:()=>throttle,Vv:()=>isColorLight,X:()=>getWeatherIcon,az:()=>createElement,gJ:()=>getImage,jk:()=>forwardHaptic,jx:()=>setLayout,mk:()=>getIconColor,o0:()=>formatDateTime,oY:()=>getName,pr:()=>isStateOn,q7:()=>getIcon,y0:()=>getState});var _style_ts__WEBPACK_IMPORTED_MODULE_0__=__webpack_require__(946);function hasStateChanged(e,t,n){if(e.hasState=t.states[n],e.hasState)return e.newState=[e.hasState.state,e.hasState.attributes.rgb_color],e.oldState&&e.newState[0]===e.oldState[0]&&e.newState[1]===e.oldState[1]?e.stateChanged=!1:(e.oldState=e.newState,e.stateChanged=!0),e.stateChanged}function configChanged(e,t){return!(!t.classList.contains("editor")||e.config===e.previousConfig||(e.previousConfig=e.config,0))}const fireEvent=(e,t,n,o)=>{o=o||{},n=null==n?{}:n;const a=new Event(t,{bubbles:void 0===o.bubbles||o.bubbles,cancelable:Boolean(o.cancelable),composed:void 0===o.composed||o.composed});return a.detail=n,e.dispatchEvent(a),a},forwardHaptic=e=>{fireEvent(window,"haptic",e)},navigate=(e,t,n=!1)=>{n?history.replaceState(null,"",t):history.pushState(null,"",t),fireEvent(window,"location-changed",{replace:n})};function toggleEntity(e,t){e.callService("homeassistant","toggle",{entity_id:t})}function tapFeedback(e){void 0!==e&&(e.style.display="",e.style.animation="tap-feedback .3s",setTimeout((()=>{e.style.animation="none",e.style.display="none"}),500))}function getIcon(e,t=e.config.entity,n=e.config.icon){const o=t?.split(".")[0],a=getAttribute(e,"device_class",t),i=getAttribute(e,"icon",t),r=n,s=getState(e,t),l={alarm_control_panel:"mdi:shield",alert:"mdi:alert",automation:"mdi:playlist-play",binary_sensor:function(){const n="off"===s;switch(getAttribute(e,"device_class",t)){case"battery":return n?"mdi:battery":"mdi:battery-outline";case"battery_charging":return n?"mdi:battery":"mdi:battery-charging";case"cold":return n?"mdi:thermometer":"mdi:snowflake";case"connectivity":return n?"mdi:server-network-off":"mdi:server-network";case"door":return n?"mdi:door-closed":"mdi:door-open";case"garage_door":return n?"mdi:garage":"mdi:garage-open";case"heat":return n?"mdi:thermometer":"mdi:fire";case"light":return n?"mdi:brightness-5":"mdi:brightness-7";case"lock":return n?"mdi:lock":"mdi:lock-open";case"moisture":return n?"mdi:water-off":"mdi:water";case"motion":return n?"mdi:motion-sensor-off":"mdi:motion-sensor";case"occupancy":case"presence":return n?"mdi:home-outline":"mdi:home";case"opening":return n?"mdi:square":"mdi:square-outline";case"plug":case"power":return n?"mdi:power-plug-off":"mdi:power-plug";case"running":return n?"mdi:stop":"mdi:play";case"safety":case"tamper":return n?"mdi:check-circle":"mdi:alert-circle";case"smoke":return n?"mdi:check-circle":"mdi:smoke";case"sound":return n?"mdi:music-note-off":"mdi:music-note";case"update":return n?"mdi:package":"mdi:package-up";case"vibration":return n?"mdi:crop-portrait":
|
||
|
<div class="card-config">
|
||
|
${this.makeDropdown("Card type","card_type",a)}
|
||
|
<ha-textfield
|
||
|
label="Hash (e.g. #kitchen)"
|
||
|
.value="${this._hash}"
|
||
|
.configValue="${"hash"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:dock-top"></ha-icon>
|
||
|
Header settings
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<ha-formfield .label="Optional - Show header">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Show header"
|
||
|
.checked=${this._show_header}
|
||
|
.configValue="${"show_header"}"
|
||
|
@change=${this._valueChanged}
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Show header</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
<ha-alert alert-type="info">You can completely hide the pop-up header, including the close button. To close it when hidden, either make a long swipe within the pop-up or click outside of it.</ha-alert>
|
||
|
<div style="${this._show_header?"":"display: none;"}">
|
||
|
<hr />
|
||
|
${this.makeDropdown("Button type","button_type",i)}
|
||
|
${this.makeDropdown("Optional - Entity","entity",n,r)}
|
||
|
<ha-textfield
|
||
|
label="Optional - Name"
|
||
|
.value="${this._name}"
|
||
|
.configValue="${"name"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
${this.makeDropdown("Optional - Icon","icon")}
|
||
|
${this.makeShowState()}
|
||
|
<hr />
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:gesture-tap"></ha-icon>
|
||
|
Tap action on icon
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${this.makeTapActionPanel("Tap action")}
|
||
|
${this.makeTapActionPanel("Double tap action")}
|
||
|
${this.makeTapActionPanel("Hold action")}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined style="display: ${"slider"===this._config.button_type?"none":""}">
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:gesture-tap"></ha-icon>
|
||
|
Tap action on button
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${this.makeTapActionPanel("Tap action",this._button_action,"name"!==this._config.button_type?"state"===this._config.button_type?"more-info":"toggle":"none","button_action")}
|
||
|
${this.makeTapActionPanel("Double tap action",this._button_action,"name"!==this._config.button_type?"state"===this._config.button_type?"more-info":"toggle":"none","button_action")}
|
||
|
${this.makeTapActionPanel("Hold action",this._button_action,"name"!==this._config.button_type?"more-info":"none","button_action")}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
${this.makeSubButtonPanel()}
|
||
|
</div>
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:cog"></ha-icon>
|
||
|
Pop-up settings
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<ha-textfield
|
||
|
label="Optional - Auto close in milliseconds (e.g. 15000)"
|
||
|
type="number"
|
||
|
inputMode="numeric"
|
||
|
min="0"
|
||
|
step="1000"
|
||
|
.value="${this._auto_close}"
|
||
|
.configValue="${"auto_close"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
<ha-textfield
|
||
|
label="Optional - Slide to close distance (default to 400)"
|
||
|
type="number"
|
||
|
inputMode="numeric"
|
||
|
min="0"
|
||
|
step="10"
|
||
|
.value="${this._slide_to_close_distance}"
|
||
|
.configValue="${"slide_to_close_distance"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
<ha-formfield .label="Optional - Close the pop-up by clicking outside of it (a refresh is needed)">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Close the pop-up by clicking outside of it (a refresh is needed)"
|
||
|
.checked=${this._close_by_clicking_outside}
|
||
|
.configValue="${"close_by_clicking_outside"}"
|
||
|
@change=${this._valueChanged}
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Close the pop-up by clicking outside of it (a refresh is needed)</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
<ha-formfield .label="Optional - Close the pop-up after any click or tap">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Close the pop-up after any click or tap"
|
||
|
.checked=${this._close_on_click}
|
||
|
.configValue="${"close_on_click"}"
|
||
|
@change=${this._valueChanged}
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Close the pop-up after any click or tap</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
<ha-formfield .label="Optional - Update cards in background (not recommended)">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Update cards in background (not recommended)"
|
||
|
.checked=${this._background_update}
|
||
|
.configValue="${"background_update"}"
|
||
|
@change=${this._valueChanged}
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Update cards in background (not recommended)</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
<ha-alert alert-type="info">Background updates are only recommended if you encounter issues with certain cards within your pop-up.</ha-alert>
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:bell"></ha-icon>
|
||
|
Pop-up trigger
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<ha-card-conditions-editor
|
||
|
.hass=${this.hass}
|
||
|
.conditions=${l}
|
||
|
@value-changed=${e=>this._conditionChanged(e)}
|
||
|
>
|
||
|
</ha-card-conditions-editor>
|
||
|
<ha-alert alert-type="info">
|
||
|
The pop-up will be opened when ALL conditions are fulfilled. For example you can open a "Security" pop-up with a camera when a person is in front of your house. You can also create a toggle helper (<code>input_boolean</code>) and trigger its opening/closing in an automation.
|
||
|
</ha-alert>
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:gesture-tap"></ha-icon>
|
||
|
Pop-up open/close action
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${this.makeTapActionPanel("Open action",this._config,"none")}
|
||
|
${this.makeTapActionPanel("Close action",this._config,"none")}
|
||
|
<ha-alert alert-type="info">This allows you to trigger an action on pop-up open/close.</ha-alert>
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:palette"></ha-icon>
|
||
|
Styling options
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${this.makeLayoutOptions()}
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:palette"></ha-icon>
|
||
|
Pop-up styling
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<ha-textfield
|
||
|
label="Optional - Margin (fix centering on some themes) (e.g. 13px)"
|
||
|
.value="${this._margin}"
|
||
|
.configValue="${"margin"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
<ha-textfield
|
||
|
label="Optional - Top margin on mobile (e.g. -56px if your header is hidden)"
|
||
|
.value="${this._margin_top_mobile}"
|
||
|
.configValue="${"margin_top_mobile"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
<ha-textfield
|
||
|
label="Optional - Top margin on desktop (e.g. 50vh for an half sized pop-up)"
|
||
|
.value="${this._margin_top_desktop}"
|
||
|
.configValue="${"margin_top_desktop"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
<ha-textfield
|
||
|
label="Optional - Width on desktop (100% by default on mobile)"
|
||
|
.value="${this._width_desktop}"
|
||
|
.configValue="${"width_desktop"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
<ha-textfield
|
||
|
label="Optional - Background color (any var, hex, rgb or rgba value)"
|
||
|
.value="${this._bg_color}"
|
||
|
.configValue="${"bg_color"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
<ha-textfield
|
||
|
label="Optional - Background opacity (0-100 range)"
|
||
|
type="number"
|
||
|
inputMode="numeric"
|
||
|
min="0"
|
||
|
max="100"
|
||
|
.value="${this._bg_opacity}"
|
||
|
.configValue="${"bg_opacity"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
<ha-textfield
|
||
|
label="Optional - Background blur (0-100 range)"
|
||
|
type="number"
|
||
|
inputMode="numeric"
|
||
|
min="0"
|
||
|
max="100"
|
||
|
.value="${this._bg_blur}"
|
||
|
.configValue="${"bg_blur"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
<ha-textfield
|
||
|
label="Optional - Backdrop blur (0-100 range)"
|
||
|
type="number"
|
||
|
inputMode="numeric"
|
||
|
min="0"
|
||
|
max="100"
|
||
|
.value="${this._backdrop_blur}"
|
||
|
.configValue="${"backdrop_blur"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
<ha-textfield
|
||
|
label="Optional - Shadow opacity (0-100 range)"
|
||
|
type="number"
|
||
|
inputMode="numeric"
|
||
|
min="0"
|
||
|
max="100"
|
||
|
.configValue="${"shadow_opacity"}"
|
||
|
.value="${this._shadow_opacity}""
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
<ha-formfield .label="Optional - Hide pop-up backdrop (a refresh is needed)">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Hide pop-up backdrop (a refresh is needed)"
|
||
|
.checked=${this._hide_backdrop}
|
||
|
.configValue="${"hide_backdrop"}"
|
||
|
@change=${this._valueChanged}
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Hide pop-up backdrop (a refresh is needed)</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
<ha-alert alert-type="warning">Set this toggle to true on the first pop-up of your main dashboard to hide the darker backdrop behind all pop-ups. <b>You can add a blurred effect to it by changing <code>Optional - Backdrop blur</code> just below, but be aware that this can slow down your dashboard when opening pop-ups. It is now set to 0 for that reason.</b></ha-alert>
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
${this.makeStyleEditor()}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-alert alert-type="info">
|
||
|
This card allows you to convert any vertical stack into a pop-up. Each pop-up is hidden by default and can be opened by targeting its link (e.g., '#pop-up-name'), with <a style="color: var(--text-primary-color)" href="https://github.com/Clooos/Bubble-Card#example">any card</a> that supports the <code>navigate</code> action, or with the <a style="color: var(--text-primary-color)" href="https://github.com/Clooos/Bubble-Card#horizontal-buttons-stack">horizontal buttons stack</a> that is included.
|
||
|
<br><br><b>Important:</b> This card must be placed within a <a style="color: var(--text-primary-color)" href="https://www.home-assistant.io/dashboards/vertical-stack/">vertical stack</a> card at the topmost position to function properly. To avoid misalignment with your view, place vertical stacks/pop-ups after all other dashboard cards. It should be called from the same view to work.
|
||
|
<br><br><b>You can also watch this <a style="color: var(--text-primary-color)" href="https://www.youtube.com/watch?v=7mOV7BfWoFc">video</a> that explains how to create your first pop-up.</b>
|
||
|
</ha-alert>
|
||
|
<ha-alert alert-type="warning">Since v1.7.0, the optimized mode has been removed to ensure stability and to simplify updates for everyone. However, if your pop-up content still appears on the screen during page loading, <a style="color: var(--text-primary-color)" href="https://github.com/Clooos/Bubble-Card#pop-up-initialization-fix">you can install this similar fix.</a></ha-alert>
|
||
|
${this.makeVersion()}
|
||
|
</div>
|
||
|
`}if("button"===this._config?.card_type)return ce`
|
||
|
<div class="card-config">
|
||
|
${this.makeDropdown("Card type","card_type",a)}
|
||
|
${this.makeDropdown("Button type","button_type",i)}
|
||
|
${this.makeDropdown("slider"!==this._button_type?"Entity (toggle)":"Entity (light, media_player, cover or input_number)","entity",n,r)}
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:cog"></ha-icon>
|
||
|
Button settings
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<ha-textfield
|
||
|
label="Optional - Name"
|
||
|
.value="${this._name}"
|
||
|
.configValue="${"name"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
${this.makeDropdown("Optional - Icon","icon")}
|
||
|
${this.makeShowState()}
|
||
|
<ha-formfield .label="Optional - Slider live update" style="display: ${"slider"!==this._button_type?"none":""}">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Slider live update"
|
||
|
.checked=${this._slider_live_update}
|
||
|
.configValue="${"slider_live_update"}"
|
||
|
@change=${this._valueChanged}
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Slider live update</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
<ha-alert style="display: ${"slider"!==this._button_type?"none":""}" alert-type="info">By default, sliders are updated only on release. You can toggle this option to enable live updates while sliding.</ha-alert>
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:gesture-tap"></ha-icon>
|
||
|
Tap action on icon
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${this.makeTapActionPanel("Tap action")}
|
||
|
${this.makeTapActionPanel("Double tap action")}
|
||
|
${this.makeTapActionPanel("Hold action")}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined style="display: ${"slider"===this._config.button_type?"none":""}">
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:gesture-tap"></ha-icon>
|
||
|
Tap action on button
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${this.makeTapActionPanel("Tap action",this._button_action,"name"!==this._config.button_type?"state"===this._config.button_type?"more-info":"toggle":"none","button_action")}
|
||
|
${this.makeTapActionPanel("Double tap action",this._button_action,"name"!==this._config.button_type?"state"===this._config.button_type?"more-info":"toggle":"none","button_action")}
|
||
|
${this.makeTapActionPanel("Hold action",this._button_action,"name"!==this._config.button_type?"more-info":"none","button_action")}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:palette"></ha-icon>
|
||
|
Styling options
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${this.makeLayoutOptions()}
|
||
|
${this.makeStyleEditor()}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
${this.makeSubButtonPanel()}
|
||
|
<ha-alert alert-type="info">This card allows you to control your entities. ${"slider"===this._config.button_type?"Supported entities: Light (brightness), media player (volume), cover (position), fan (percentage), climate (temperature), input number and number (value). To access color / control of an entity, simply tap on the icon.":""}</ha-alert>
|
||
|
${this.makeVersion()}
|
||
|
</div>
|
||
|
`;if("separator"===this._config?.card_type)return ce`
|
||
|
<div class="card-config">
|
||
|
${this.makeDropdown("Card type","card_type",a)}
|
||
|
<ha-textfield
|
||
|
label="Name"
|
||
|
.value="${this._name}"
|
||
|
.configValue="${"name"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
${this.makeDropdown("Icon","icon")}
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:palette"></ha-icon>
|
||
|
Styling options
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${this.makeLayoutOptions()}
|
||
|
${this.makeStyleEditor()}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
${this.makeSubButtonPanel()}
|
||
|
<ha-alert alert-type="info">This card is a simple separator for dividing your pop-up into categories / sections. e.g. Lights, Devices, Covers, Settings, Automations...</ha-alert>
|
||
|
${this.makeVersion()}
|
||
|
</div>
|
||
|
`;if("horizontal-buttons-stack"===this._config?.card_type){if(!this.buttonAdded)for(this.buttonAdded=!0,this.buttonIndex=0;this._config[this.buttonIndex+1+"_link"];)this.buttonIndex++;function c(){this.buttonIndex++,this.requestUpdate()}return ce`
|
||
|
<div class="card-config">
|
||
|
${this.makeDropdown("Card type","card_type",a)}
|
||
|
<div id="buttons-container">
|
||
|
${this.makeButton()}
|
||
|
</div>
|
||
|
<button class="icon-button" @click="${c}">
|
||
|
<ha-icon icon="mdi:plus"></ha-icon>
|
||
|
New button
|
||
|
</button>
|
||
|
<ha-formfield .label="Auto order">
|
||
|
<ha-switch
|
||
|
aria-label="Toggle auto order"
|
||
|
.checked=${this._auto_order}
|
||
|
.configValue="${"auto_order"}"
|
||
|
@change=${this._valueChanged}
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Auto order (Presence/occupancy sensors needed)</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:palette"></ha-icon>
|
||
|
Styling options
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:palette"></ha-icon>
|
||
|
Horizontal buttons stack styling
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<ha-textfield
|
||
|
label="Optional - Margin (fix centering on some themes) (e.g. 13px)"
|
||
|
.value="${this._margin}"
|
||
|
.configValue="${"margin"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
<ha-textfield
|
||
|
label="Optional - Width on desktop (100% by default on mobile)"
|
||
|
.value="${this._width_desktop}"
|
||
|
.configValue="${"width_desktop"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
<ha-formfield .label="Optional - Rise animation (Displays an animation once the page has loaded)">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Rise animation (Displays an animation once the page has loaded)"
|
||
|
.checked=${this._rise_animation}
|
||
|
.configValue="${"rise_animation"}"
|
||
|
@change=${this._valueChanged}
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Rise animation (Displays an animation once the page has loaded)</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
<ha-formfield .label="Optional - Highlight current hash / view">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Highlight current hash / view"
|
||
|
.checked=${this._highlight_current_view}
|
||
|
.configValue="${"highlight_current_view"}"
|
||
|
@change=${this._valueChanged}
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Highlight current hash / view</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
<ha-formfield .label="Optional - Hide gradient">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Hide gradient"
|
||
|
.checked=${this._hide_gradient}
|
||
|
.configValue="${"hide_gradient"}"
|
||
|
@change=${this._valueChanged}
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Hide gradient</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
${this.makeStyleEditor()}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-alert alert-type="info">This card is the companion to the pop-up card, allowing you to open the corresponding pop-ups. It also allows you to open any page of your dashboard. In addition, you can add your motion sensors so that the order of the buttons adapts according to the room you just entered. This card is scrollable, remains visible and acts as a footer.</ha-alert>
|
||
|
${this.makeVersion()}
|
||
|
</div>
|
||
|
`}if("cover"===this._config?.card_type)return ce`
|
||
|
<div class="card-config">
|
||
|
${this.makeDropdown("Card type","card_type",a)}
|
||
|
${this.makeDropdown("Entity","entity",o)}
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:cog"></ha-icon>
|
||
|
Cover settings
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<ha-textfield
|
||
|
label="Optional - Name"
|
||
|
.value="${this._name||""}"
|
||
|
.configValue="${"name"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
${this.makeDropdown("Optional - Open icon","icon_open")}
|
||
|
${this.makeDropdown("Optional - Closed icon","icon_close")}
|
||
|
${this.makeShowState()}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:window-shutter-cog"></ha-icon>
|
||
|
Custom services
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<ha-textfield
|
||
|
label="Optional - Open service (cover.open_cover by default)"
|
||
|
.value="${this._open_service}"
|
||
|
.configValue="${"open_service"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
<ha-textfield
|
||
|
label="Optional - Stop service (cover.stop_cover by default)"
|
||
|
.value="${this._stop_service}"
|
||
|
.configValue="${"stop_service"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
<ha-textfield
|
||
|
label="Optional - Close service (cover.close_cover by default)"
|
||
|
.value="${this._close_service}"
|
||
|
.configValue="${"close_service"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:gesture-tap"></ha-icon>
|
||
|
Tap action on icon
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${this.makeTapActionPanel("Tap action")}
|
||
|
${this.makeTapActionPanel("Double tap action")}
|
||
|
${this.makeTapActionPanel("Hold action")}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:palette"></ha-icon>
|
||
|
Styling options
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${this.makeLayoutOptions()}
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:palette"></ha-icon>
|
||
|
Cover styling
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${this.makeDropdown("Optional - Arrow down icon","icon_down")}
|
||
|
${this.makeDropdown("Optional - Arrow up icon","icon_up")}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
${this.makeStyleEditor()}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
${this.makeSubButtonPanel()}
|
||
|
<ha-alert alert-type="info">This card allows you to control your covers.</ha-alert>
|
||
|
${this.makeVersion()}
|
||
|
</div>
|
||
|
`;if("media-player"===this._config?.card_type)return ce`
|
||
|
<div class="card-config">
|
||
|
${this.makeDropdown("Card type","card_type",a)}
|
||
|
${this.makeDropdown("Entity","entity",this.mediaPlayerList)}
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:cog"></ha-icon>
|
||
|
Media player settings
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<ha-textfield
|
||
|
label="Optional - Name"
|
||
|
.value="${this._name||""}"
|
||
|
.configValue="${"name"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
${this.makeDropdown("Optional - Icon","icon")}
|
||
|
${this.makeShowState()}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:eye-off"></ha-icon>
|
||
|
Display/hide buttons
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<ha-formfield .label="Optional - Hide play/pause button">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Hide play/pause button"
|
||
|
.checked=${this._hide_play_pause_button}
|
||
|
.configValue="${"hide.play_pause_button"}"
|
||
|
@change=${this._valueChanged}
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Hide play/pause button</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
<ha-formfield .label="Optional - Hide volume button">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Hide volume button"
|
||
|
.checked=${this._hide_volume_button}
|
||
|
.configValue="${"hide.volume_button"}"
|
||
|
@change=${this._valueChanged}
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Hide volume button</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
<ha-formfield .label="Optional - Hide next button">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Hide next button"
|
||
|
.checked=${this._hide_next_button}
|
||
|
.configValue="${"hide.next_button"}"
|
||
|
@change=${this._valueChanged}
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Hide next button</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
<ha-formfield .label="Optional - Hide previous button">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Hide previous button"
|
||
|
.checked=${this._hide_previous_button}
|
||
|
.configValue="${"hide.previous_button"}"
|
||
|
@change=${this._valueChanged}
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Hide previous button</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
<ha-formfield .label="Optional - Hide power button">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Hide power button"
|
||
|
.checked=${this._hide_power_button}
|
||
|
.configValue="${"hide.power_button"}"
|
||
|
@change=${this._valueChanged}
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Hide power button</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:gesture-tap"></ha-icon>
|
||
|
Tap action on icon
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${this.makeTapActionPanel("Tap action")}
|
||
|
${this.makeTapActionPanel("Double tap action")}
|
||
|
${this.makeTapActionPanel("Hold action")}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:palette"></ha-icon>
|
||
|
Styling options
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${this.makeLayoutOptions()}
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:palette"></ha-icon>
|
||
|
Media player styling
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<ha-formfield .label="Optional - Blurred media cover in background">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Blurred media cover in background"
|
||
|
.checked=${this._cover_background}
|
||
|
.configValue="${"cover_background"}"
|
||
|
@change=${this._valueChanged}
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Blurred media cover in background</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
${this.makeStyleEditor()}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
${this.makeSubButtonPanel()}
|
||
|
<ha-alert alert-type="info">This card allows you to control a media player. You can tap on the icon to get more control.</ha-alert>
|
||
|
${this.makeVersion()}
|
||
|
</div>
|
||
|
`;if("empty-column"===this._config?.card_type)return ce`
|
||
|
<div class="card-config">
|
||
|
${this.makeDropdown("Card type","card_type",a)}
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:palette"></ha-icon>
|
||
|
Styling options
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${this.makeLayoutOptions()}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-alert alert-type="info">Just an empty card to fill any empty column.</ha-alert>
|
||
|
${this.makeVersion()}
|
||
|
</div>
|
||
|
`;if("select"===this._config?.card_type){const d=this._config.entity,u=(d?.startsWith("input_select")||d?.startsWith("select")||this._config.select_attribute,this.hass.states[d]?.attributes),b=this._selectable_attributes.some((e=>u?.[e])),p=Object.keys(this.hass.states[d]?.attributes||{}).map((e=>{let t=this.hass.states[d];return{label:this.hass.formatEntityAttributeName(t,e),value:e}})).filter((e=>this._selectable_attributes.includes(e.value)));return ce`
|
||
|
<div class="card-config">
|
||
|
${this.makeDropdown("Card type","card_type",a)}
|
||
|
${this.makeDropdown("Entity","entity",this.inputSelectList)}
|
||
|
${b?ce`
|
||
|
<div class="ha-combo-box">
|
||
|
<ha-combo-box
|
||
|
label="Select menu (from attributes)"
|
||
|
.value="${this._config.select_attribute}"
|
||
|
.items="${p}"
|
||
|
.configValue="${"select_attribute"}"
|
||
|
@value-changed="${this._valueChanged}"
|
||
|
></ha-combo-box>
|
||
|
</div>
|
||
|
`:""}
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:cog"></ha-icon>
|
||
|
Button settings
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<ha-textfield
|
||
|
label="Optional - Name"
|
||
|
.value="${this._name}"
|
||
|
.configValue="${"name"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
${this.makeDropdown("Optional - Icon","icon")}
|
||
|
${this.makeShowState()}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:gesture-tap"></ha-icon>
|
||
|
Tap action on icon
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${this.makeTapActionPanel("Tap action")}
|
||
|
${this.makeTapActionPanel("Double tap action")}
|
||
|
${this.makeTapActionPanel("Hold action")}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:palette"></ha-icon>
|
||
|
Styling options
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${this.makeLayoutOptions()}
|
||
|
${this.makeStyleEditor()}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
${this.makeSubButtonPanel()}
|
||
|
<ha-alert alert-type="info">
|
||
|
This card allows you to have a select menu for your
|
||
|
<code>input_select</code>, <code>select</code> entities, and
|
||
|
any other entities that have attribute lists like
|
||
|
<code>source_list</code>, <code>sound_mode_list</code>,
|
||
|
<code>hvac_modes</code>, <code>fan_modes</code>,
|
||
|
<code>swing_modes</code>, <code>preset_modes</code>, or
|
||
|
<code>effect_list</code>.
|
||
|
</ha-alert>
|
||
|
${this.makeVersion()}
|
||
|
</div>
|
||
|
`}if("climate"===this._config?.card_type){if("climate"===this._config.card_type&&!this.climateSubButtonsAdded&&this._config.entity){const h=this.hass.states[this._config.entity]?.attributes?.hvac_modes;this._config.sub_button&&0!==this._config.sub_button.length||(this._config.sub_button=[h?{name:"HVAC modes menu",select_attribute:"hvac_modes",state_background:!1,show_arrow:!1}:null].filter(Boolean)),this.climateSubButtonsAdded=!0}return ce`
|
||
|
<div class="card-config">
|
||
|
${this.makeDropdown("Card type","card_type",a)}
|
||
|
${this.makeDropdown("Entity","entity",this.climateList)}
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:cog"></ha-icon>
|
||
|
Climate settings
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<ha-textfield
|
||
|
label="Optional - Name"
|
||
|
.value="${this._name}"
|
||
|
.configValue="${"name"}"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
${this.makeDropdown("Optional - Icon","icon")}
|
||
|
${this.makeShowState()}
|
||
|
${this.hass.states[this._config.entity]?.attributes?.target_temp_low?ce`
|
||
|
<ha-formfield .label="Optional - Hide target temp low">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Hide target temp low"
|
||
|
.checked=${this._config.hide_target_temp_low}
|
||
|
.configValue="${"hide_target_temp_low"}"
|
||
|
@change=${this._valueChanged}
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Hide target temp low</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
`:""}
|
||
|
${this.hass.states[this._config.entity]?.attributes?.target_temp_high?ce`
|
||
|
<ha-formfield .label="Optional - Hide target temp high">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Hide target temp high"
|
||
|
.checked=${this._config.hide_target_temp_high}
|
||
|
.configValue="${"hide_target_temp_high"}"
|
||
|
@change=${this._valueChanged}
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Hide target temp high</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
`:""}
|
||
|
<ha-formfield .label="Optional - Constant background color when ON">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Constant background color when ON"
|
||
|
.checked=${!0===this._config.state_color}
|
||
|
.configValue="${"state_color"}"
|
||
|
@change=${this._valueChanged}
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Constant background color when ON</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:gesture-tap"></ha-icon>
|
||
|
Tap action on icon
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${this.makeTapActionPanel("Tap action")}
|
||
|
${this.makeTapActionPanel("Double tap action")}
|
||
|
${this.makeTapActionPanel("Hold action")}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:palette"></ha-icon>
|
||
|
Styling options
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${this.makeLayoutOptions()}
|
||
|
${this.makeStyleEditor()}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
${this.makeSubButtonPanel()}
|
||
|
<ha-alert alert-type="info">This card allows you to control your climate entities. You can also add a sub-button that display a select menu for your climate modes (check if you have "Select menu" available when you create a new sub-button).</ha-alert>
|
||
|
${this.makeVersion()}
|
||
|
</div>
|
||
|
`}return this._config?.card_type?void 0:ce`
|
||
|
<div class="card-config">
|
||
|
${this.makeDropdown("Card type","card_type",a)}
|
||
|
<ha-alert alert-type="info">You need to add a card type first. Please note that in some cases, a page refresh might be needed after exiting the editor.</ha-alert>
|
||
|
<img style="width: 100%; height: auto; border-radius: 24px;" src="https://raw.githubusercontent.com/Clooos/Bubble-Card/main/.github/bubble-card.gif">
|
||
|
<p>The <b>Bubble Card ${e}</b> changelog is available <a href="https://github.com/Clooos/Bubble-Card/releases/tag/${e}"><b>here</b></a>.</p>
|
||
|
<hr />
|
||
|
<p>If you have an issue or a question you can find more details in the GitHub documentation. You can also find useful resources and help in these links.</p>
|
||
|
<div style="display: inline-block;">
|
||
|
<a href="https://github.com/Clooos/Bubble-Card"><img src="https://img.shields.io/badge/GitHub-Documentation-blue?logo=github"></a>
|
||
|
<a href="https://www.youtube.com/@cloooos"><img src="https://img.shields.io/badge/YouTube-My%20channel-red?logo=youtube"></a>
|
||
|
<a href="https://www.reddit.com/r/BubbleCard/"><img src="https://img.shields.io/badge/Reddit-r/BubbleCard-orange?logo=reddit"></a>
|
||
|
<a href="https://community.home-assistant.io/t/bubble-card-a-minimalist-card-collection-for-home-assistant-with-a-nice-pop-up-touch/609678"><img src="https://img.shields.io/badge/Home%20Assistant-Community%20Forum-blue?logo=home-assistant"></a>
|
||
|
</div>
|
||
|
<hr />
|
||
|
<p>I dedicate most of my spare time to making this project the best it can be. So if you appreciate my work, any donation would be a great way to show your support.</p>
|
||
|
<div style="display: inline-block;">
|
||
|
<a href="https://www.buymeacoffee.com/clooos"><img src="https://img.shields.io/badge/Donate-Buy%20me%20a%20beer-yellow?logo=buy-me-a-coffee"></a>
|
||
|
<a href="https://www.paypal.com/donate/?business=MRVBV9PLT9ZPL&no_recurring=0&item_name=Hi%2C+I%27m+Clooos+the+creator+of+Bubble+Card.+Thank+you+for+supporting+me+and+my+passion.+You+are+awesome%21+%F0%9F%8D%BB¤cy_code=EUR"><img src="https://img.shields.io/badge/Donate-PayPal-blue?logo=paypal"></img></a>
|
||
|
</div>
|
||
|
<p>Looking for more advanced examples? Check out my <a href="https://www.patreon.com/Clooos"><b>Patreon</b></a> for exclusive custom styles and templates!</p>
|
||
|
<a href="https://www.patreon.com/Clooos"><img src="https://img.shields.io/badge/Patreon-Clooos-orange?logo=patreon"></a>
|
||
|
<p style="margin-top: 0;">Thank you! 🍻</p>
|
||
|
${this.makeVersion()}
|
||
|
</div>
|
||
|
`}makeLayoutOptions(){return ce`
|
||
|
<ha-combo-box
|
||
|
label="${"pop-up"===this._config.card_type?"Header card layout":"Card layout"}"
|
||
|
.value="${this._config.card_layout||"normal"}"
|
||
|
.configValue="${"card_layout"}"
|
||
|
.items="${[{label:"Normal",value:"normal"},{label:"Large (Optimized for sections)",value:"large"},{label:"Large with 2 sub-buttons rows (Optimized for sections)",value:"large-2-rows"}]}"
|
||
|
@value-changed="${this._valueChanged}"
|
||
|
></ha-combo-box>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:table"></ha-icon>
|
||
|
Layout options for sections
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<ha-combo-box
|
||
|
label="Columns"
|
||
|
.value="${this._config.columns}"
|
||
|
.configValue="${"columns"}"
|
||
|
.items="${[{label:"Auto",value:null},{label:"1/4",value:1},{label:"2/4",value:2},{label:"3/4",value:3},{label:"4/4",value:4}]}"
|
||
|
@value-changed="${this._valueChanged}"
|
||
|
></ha-combo-box>
|
||
|
<ha-combo-box
|
||
|
label="Rows"
|
||
|
.value="${this._config.rows}"
|
||
|
.configValue="${"rows"}"
|
||
|
.items="${[{label:"Auto",value:null},{label:"1/4",value:1},{label:"2/4",value:2},{label:"3/4",value:3},{label:"4/4",value:4}]}"
|
||
|
@value-changed="${this._valueChanged}"
|
||
|
></ha-combo-box>
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
`}makeShowState(e=this._config,t="",n=!1,o){const a=e?.entity??this._config.entity??"",i="name"===this._config.button_type,r=a?.startsWith("input_select")||a?.startsWith("select")||e.select_attribute,s=Object.keys(this.hass.states[a]?.attributes||{}).map((e=>{let t=this.hass.states[a];return{label:this.hass.formatEntityAttributeName(t,e),value:e}}));return ce`
|
||
|
${"sub_button"!==n?ce`
|
||
|
<ha-formfield .label="Optional - Text scrolling effect">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Text scrolling effect"
|
||
|
.checked=${e?.scrolling_effect??!0}
|
||
|
.configValue="${t+"scrolling_effect"}"
|
||
|
@change="${n?e=>this._arrayValueChange(o,{scrolling_effect:e.target.checked},n):this._valueChanged}"
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Text scrolling effect</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
`:""}
|
||
|
${"sub_button"===n?ce`
|
||
|
<ha-formfield .label="Optional - Show background">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Show background when entity is on"
|
||
|
.checked=${e?.show_background??!0}
|
||
|
@change="${e=>this._arrayValueChange(o,{show_background:e.target.checked},n)}"
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Show background when entity is on</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
`:""}
|
||
|
${"sub_button"===n&&(e?.show_background??1)?ce`
|
||
|
<ha-formfield .label="Optional - Background color based on state">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Background color based on state"
|
||
|
.checked=${e?.state_background??!0}
|
||
|
@change="${e=>this._arrayValueChange(o,{state_background:e.target.checked},n)}"
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Background color based on state</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
`:""}
|
||
|
${"sub_button"===n&&(e?.state_background??1)&&a.startsWith("light")?ce`
|
||
|
<ha-formfield .label="Optional - Background color based on light color">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Background color based on light color"
|
||
|
.checked=${e?.light_background??!0}
|
||
|
@change="${e=>this._arrayValueChange(o,{light_background:e.target.checked},n)}"
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Background color based on light color</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
`:""}
|
||
|
${"sub_button"!==n&&a.startsWith("light")?ce`
|
||
|
<ha-formfield .label="Optional - Use accent color instead of light color">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Use accent color instead of light color"
|
||
|
.checked=${e?.use_accent_color??!1}
|
||
|
.configValue="${t+"use_accent_color"}"
|
||
|
@change="${this._valueChanged}"
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Use accent color instead of light color</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
`:""}
|
||
|
<ha-formfield .label="Optional - Show icon">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Show icon"
|
||
|
.checked=${e?.show_icon??!0}
|
||
|
.configValue="${t+"show_icon"}"
|
||
|
@change="${n?e=>this._arrayValueChange(o,{show_icon:e.target.checked},n):this._valueChanged}"
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Show icon</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
${"sub_button"!==n?ce`
|
||
|
<ha-formfield .label="Optional - Prioritize icon over entity picture">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Prioritize icon over entity picture"
|
||
|
.checked=${e?.force_icon??!1}
|
||
|
.configValue="${t+"force_icon"}"
|
||
|
.disabled="${i}"
|
||
|
@change="${n?e=>this._arrayValueChange(o,{force_icon:e.target.checked},n):this._valueChanged}"
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Prioritize icon over entity picture</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
`:""}
|
||
|
<ha-formfield .label="Optional - Show name">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Show name"
|
||
|
.checked=${!!(e?.show_name??"sub_button"!==n)}
|
||
|
.configValue="${t+"show_name"}"
|
||
|
@change="${n?e=>this._arrayValueChange(o,{show_name:e.target.checked},n):this._valueChanged}"
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Show name</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
<ha-formfield .label="Optional - Show entity state">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Show entity state"
|
||
|
.checked="${e?.show_state??"state"===e.button_type}"
|
||
|
.configValue="${t+"show_state"}"
|
||
|
.disabled="${i&&"sub_button"!==n}"
|
||
|
@change="${n?e=>this._arrayValueChange(o,{show_state:e.target.checked},n):this._valueChanged}"
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Show entity state</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
<ha-formfield .label="Optional - Show last changed">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Show last changed"
|
||
|
.checked=${e?.show_last_changed}
|
||
|
.configValue="${t+"show_last_changed"}"
|
||
|
.disabled="${i&&"sub_button"!==n}"
|
||
|
@change="${n?e=>this._arrayValueChange(o,{show_last_changed:e.target.checked},n):this._valueChanged}"
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Show last changed</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
<ha-formfield .label="Optional - Show attribute">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Show attribute"
|
||
|
.checked=${e?.show_attribute}
|
||
|
.configValue="${t+"show_attribute"}"
|
||
|
.disabled="${i&&"sub_button"!==n}"
|
||
|
@change="${n?e=>this._arrayValueChange(o,{show_attribute:e.target.checked},n):this._valueChanged}"
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Show attribute</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
${e?.show_attribute?ce`
|
||
|
<div class="ha-combo-box">
|
||
|
<ha-combo-box
|
||
|
label="Optional - Attribute to show"
|
||
|
.value="${e?.attribute}"
|
||
|
.configValue="${t+"attribute"}"
|
||
|
.items="${s}"
|
||
|
.disabled="${i}"
|
||
|
@value-changed="${n?e=>this._arrayValueChange(o,{attribute:e.detail.value},n):this._valueChanged}"
|
||
|
></ha-combo-box>
|
||
|
</div>
|
||
|
`:""}
|
||
|
${"sub_button"===n&&r?ce`
|
||
|
<ha-formfield .label="Optional - Show arrow (Select entities only)">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Show arrow (Select entities only)"
|
||
|
.checked=${e?.show_arrow??!0}
|
||
|
.configValue="${t+"show_arrow"}"
|
||
|
@change="${n?e=>this._arrayValueChange(o,{show_arrow:e.target.checked},n):this._valueChanged}"
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Show arrow (Select menu only)</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
`:""}
|
||
|
`}makeDropdown(e,t,n,o){return e.includes("icon")||e.includes("Icon")?ce`
|
||
|
<div class="ha-icon-picker">
|
||
|
<ha-icon-picker
|
||
|
label="${e}"
|
||
|
.value="${this["_"+t]}"
|
||
|
.configValue="${t}"
|
||
|
item-value-path="icon"
|
||
|
item-label-path="icon"
|
||
|
@value-changed="${this._valueChanged}"
|
||
|
></ha-icon-picker>
|
||
|
</div>
|
||
|
`:ce`
|
||
|
<div class="ha-combo-box">
|
||
|
<ha-combo-box
|
||
|
label="${e}"
|
||
|
.value="${this["_"+t]}"
|
||
|
.configValue="${t}"
|
||
|
.items="${n}"
|
||
|
.disabled="${o}"
|
||
|
@value-changed="${this._valueChanged}"
|
||
|
></ha-combo-box>
|
||
|
</div>
|
||
|
`}makeTapActionPanel(e,t=this._config,n,o,a=this._config){this.hass;const i="Tap action"===e?"mdi:gesture-tap":"Double tap action"===e?"mdi:gesture-double-tap":"Hold action"===e?"mdi:gesture-tap-hold":"mdi:gesture-tap",r="Tap action"===e?t.tap_action:"Double tap action"===e?t.double_tap_action:"Hold action"===e?t.hold_action:"Open action"===e?t.open_action:t.close_action,s="Tap action"===e?"tap_action":"Double tap action"===e?"double_tap_action":"Hold action"===e?"hold_action":"Open action"===e?"open_action":"close_action",l=t===this._config;return n||(n=l&&"Tap action"===e?"name"!==this._config.button_type?"more-info":"none":l?"name"!==this._config.button_type?"toggle":"none":""),ce`
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="${i}"></ha-icon>
|
||
|
${e}
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<div class="ha-combo-box">
|
||
|
<ha-combo-box
|
||
|
label="${e}"
|
||
|
.value="${r?.action??n}"
|
||
|
.items="${this.tapActionTypeList}"
|
||
|
@value-changed="${e=>this._tapActionValueChange(a,{[s]:{action:e.detail.value}},o)}"
|
||
|
></ha-combo-box>
|
||
|
</div>
|
||
|
${"navigate"===r?.action?ce`
|
||
|
<div class="ha-textfield">
|
||
|
<ha-textfield
|
||
|
label="Navigation path"
|
||
|
.value="${r?.navigation_path??""}"
|
||
|
@input="${e=>this._tapActionValueChange(a,{[s]:{navigation_path:e.target.value}},o)}"
|
||
|
></ha-textfield>
|
||
|
</div>
|
||
|
`:""}
|
||
|
${"url"===r?.action?ce`
|
||
|
<div class="ha-textfield">
|
||
|
<ha-textfield
|
||
|
label="URL path"
|
||
|
.value="${r?.url_path??""}"
|
||
|
@input="${e=>this._tapActionValueChange(a,{[s]:{url_path:e.target.value}},o)}"
|
||
|
></ha-textfield>
|
||
|
</div>
|
||
|
`:""}
|
||
|
${"call-service"===r?.action?ce`
|
||
|
<div class="ha-textfield">
|
||
|
<ha-textfield
|
||
|
label="Service"
|
||
|
.value="${r?.service??""}"
|
||
|
@input="${e=>this._tapActionValueChange(a,{[s]:{service:e.target.value}},o)}"
|
||
|
></ha-textfield>
|
||
|
</div>
|
||
|
<div class="ha-combo-box">
|
||
|
<ha-combo-box
|
||
|
label="Optional - Entity"
|
||
|
.value="${r?.target?.entity_id}"
|
||
|
.items="${this.allEntitiesList}"
|
||
|
@value-changed="${"entity"!==r?.target?.entity_id?e=>{this._tapActionValueChange(a,{[s]:{target:{entity_id:e.detail.value}}},o)}:""}"
|
||
|
></ha-combo-box>
|
||
|
</div>
|
||
|
<ha-formfield .label="Optional - Use default entity">
|
||
|
<ha-switch
|
||
|
aria-label="Optional - Use default entity"
|
||
|
.checked=${"entity"===r?.target?.entity_id}
|
||
|
@change="${e=>{"entity"!==r?.target?.entity_id?this._tapActionValueChange(a,{[s]:{target:{entity_id:"entity"}}},o):this._tapActionValueChange(a,{[s]:{target:{}}},o)}}"
|
||
|
></ha-switch>
|
||
|
<div class="mdc-form-field">
|
||
|
<label class="mdc-label">Optional - Use default entity</label>
|
||
|
</div>
|
||
|
</ha-formfield>
|
||
|
`:""}
|
||
|
${"call-service"===r?.action&&r?.service?ce`
|
||
|
<ha-alert alert-type="info">For now, you still need to switch to the YAML editor if you want to add <code>data:</code> to your service.</ha-alert>
|
||
|
`:""}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
`}makeSubButtonPanel(){const e=this._config?.sub_button?.map(((e,t)=>{if(!e)return;const n="sub_button."+t+".",o=e.entity??this._config.entity,a=o?.startsWith("input_select")||o?.startsWith("select")||e.select_attribute,i=this.hass.states[o]?.attributes,r=this._selectable_attributes.some((e=>i?.[e])),s=Object.keys(this.hass.states[o]?.attributes||{}).map((e=>{let t=this.hass.states[o];return{label:this.hass.formatEntityAttributeName(t,e),value:e}})).filter((e=>this._selectable_attributes.includes(e.value))),l=e.visibility??[];return ce`
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:border-radius"></ha-icon>
|
||
|
${this._config.sub_button[t]?"Button "+(t+1)+(e.name?" - "+e.name:""):"New button"}
|
||
|
<button class="icon-button header" @click="${n=>{n.stopPropagation();let o=[...this._config.sub_button];o.splice(t,1),this._config.sub_button=o,this._valueChanged({target:{configValue:"sub_button."+(t-1),value:e}}),this.requestUpdate()}}">
|
||
|
<ha-icon icon="mdi:delete"></ha-icon>
|
||
|
</button>
|
||
|
${t>0?ce`<button class="icon-button header" @click="${e=>{if(e.stopPropagation(),t>0){let e=[...this._config.sub_button];[e[t],e[t-1]]=[e[t-1],e[t]],this._config.sub_button=e,this._valueChanged({target:{configValue:"sub_button."+t,value:this._config.sub_button[t]}})}this.requestUpdate()}}">
|
||
|
<ha-icon icon="mdi:arrow-left"></ha-icon>
|
||
|
</button>`:""}
|
||
|
${t<this._config.sub_button.length-1?ce`<button class="icon-button header" @click="${e=>{if(e.stopPropagation(),t<this._config.sub_button.length-1){let e=[...this._config.sub_button];[e[t],e[t+1]]=[e[t+1],e[t]],this._config.sub_button=e,this._valueChanged({target:{configValue:"sub_button."+t,value:this._config.sub_button[t]}})}this.requestUpdate()}}">
|
||
|
<ha-icon icon="mdi:arrow-right"></ha-icon>
|
||
|
</button>`:""}
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:cog"></ha-icon>
|
||
|
Button settings
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<div class="ha-combo-box">
|
||
|
<ha-combo-box
|
||
|
label="${"Optional - Entity (default to card entity)"}"
|
||
|
.value="${o}"
|
||
|
.items="${this.allEntitiesList}"
|
||
|
@value-changed="${e=>this._arrayValueChange(t,{entity:e.detail.value},"sub_button")}"
|
||
|
></ha-combo-box>
|
||
|
</div>
|
||
|
${r?ce`
|
||
|
<div class="ha-combo-box">
|
||
|
<ha-combo-box
|
||
|
label="Optional - Select menu (from attributes)"
|
||
|
.value="${e.select_attribute}"
|
||
|
.items="${s}"
|
||
|
@value-changed="${e=>this._arrayValueChange(t,{select_attribute:e.detail.value},"sub_button")}"
|
||
|
></ha-combo-box>
|
||
|
</div>
|
||
|
`:""}
|
||
|
<div class="ha-textfield">
|
||
|
<ha-textfield
|
||
|
label="Optional - Name"
|
||
|
.value="${e.name??""}"
|
||
|
@input="${e=>this._arrayValueChange(t,{name:e.target.value},"sub_button")}"
|
||
|
></ha-textfield>
|
||
|
</div>
|
||
|
<div class="ha-icon-picker">
|
||
|
<ha-icon-picker
|
||
|
label="Optional - Icon"
|
||
|
.value="${e.icon}"
|
||
|
item-label-path="label"
|
||
|
item-value-path="value"
|
||
|
@value-changed="${e=>this._arrayValueChange(t,{icon:e.detail.value},"sub_button")}"
|
||
|
></ha-icon-picker>
|
||
|
</div>
|
||
|
${this.makeShowState(e,n,"sub_button",t)}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined style="${a?"opacity: 0.5; pointer-events: none;":""}">
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:gesture-tap"></ha-icon>
|
||
|
Tap action on button
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${this.makeTapActionPanel("Tap action",e,"more-info","sub_button",t)}
|
||
|
${this.makeTapActionPanel("Double tap action",e,"none","sub_button",t)}
|
||
|
${this.makeTapActionPanel("Hold action",e,"none","sub_button",t)}
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:eye"></ha-icon>
|
||
|
Visibility
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<ha-card-conditions-editor
|
||
|
.hass=${this.hass}
|
||
|
.conditions=${l}
|
||
|
@value-changed=${e=>this._conditionChanged(e,t,"sub_button")}
|
||
|
>
|
||
|
</ha-card-conditions-editor>
|
||
|
<ha-alert alert-type="info">
|
||
|
The sub-button will be shown when ALL conditions are fulfilled. If no conditions are set, the sub-button will always be shown.
|
||
|
</ha-alert>
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
`}));return ce`
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:shape-square-rounded-plus"></ha-icon>
|
||
|
Sub-buttons editor
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
${e}
|
||
|
<button class="icon-button" @click="${()=>{this._config.sub_button||(this._config.sub_button=[]);let e={entity:this._config.entity};this._config.sub_button=[...this._config.sub_button],this._config.sub_button.push(e),(0,n.BX)(this,"config-changed",{config:this._config}),this.requestUpdate()}}">
|
||
|
<ha-icon icon="mdi:plus"></ha-icon>
|
||
|
New sub-button
|
||
|
</button>
|
||
|
<ha-alert alert-type="info">
|
||
|
Add new customized buttons fixed to the right.
|
||
|
These buttons can also display a select menu for your
|
||
|
<code>input_select</code>, <code>select</code> entities, and
|
||
|
any other entities that have attribute lists like
|
||
|
<code>source_list</code>, <code>sound_mode_list</code>,
|
||
|
<code>hvac_modes</code>, <code>fan_modes</code>,
|
||
|
<code>swing_modes</code>, <code>preset_modes</code>, or
|
||
|
<code>effect_list</code>.
|
||
|
</ha-alert>
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
`}makeButton(){let e=[];for(let t=1;t<=this.buttonIndex;t++)e.push(ce`
|
||
|
<div class="${t}_button">
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:border-radius"></ha-icon>
|
||
|
Button ${t} ${this._config[t+"_name"]?"- "+this._config[t+"_name"]:""}
|
||
|
<button class="icon-button header" @click="${()=>this.removeButton(t)}">
|
||
|
<ha-icon icon="mdi:delete"></ha-icon>
|
||
|
</button>
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<ha-textfield
|
||
|
label="Link / Hash to pop-up (e.g. #kitchen)"
|
||
|
.value="${this._config[t+"_link"]||""}"
|
||
|
.configValue="${t}_link"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
<ha-textfield
|
||
|
label="Optional - Name"
|
||
|
.value="${this._config[t+"_name"]||""}"
|
||
|
.configValue="${t}_name"
|
||
|
@input="${this._valueChanged}"
|
||
|
></ha-textfield>
|
||
|
<ha-icon-picker
|
||
|
label="Optional - Icon"
|
||
|
.value="${this._config[t+"_icon"]||""}"
|
||
|
.configValue="${t}_icon"
|
||
|
item-label-path="label"
|
||
|
item-value-path="value"
|
||
|
@value-changed="${this._valueChanged}"
|
||
|
></ha-icon-picker>
|
||
|
<ha-combo-box
|
||
|
label="Optional - Light / Light group (For background color)"
|
||
|
.value="${this._config[t+"_entity"]||""}"
|
||
|
.configValue="${t}_entity"
|
||
|
.items="${this.allEntitiesList}"
|
||
|
@value-changed="${this._valueChanged}"
|
||
|
></ha-combo-box>
|
||
|
<ha-combo-box
|
||
|
label="Optional - Presence / Occupancy sensor (For button auto order)"
|
||
|
.value="${this._config[t+"_pir_sensor"]||""}"
|
||
|
.configValue="${t}_pir_sensor"
|
||
|
.disabled=${!this._config.auto_order}
|
||
|
.items="${this.allEntitiesList}"
|
||
|
@value-changed="${this._valueChanged}"
|
||
|
></ha-combo-box>
|
||
|
<ha-alert alert-type="info">In fact you can also get the auto order with any entity type, for example you can add light groups to these fields and the order will change based on the last changed states.</ha-alert>
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
</div>
|
||
|
`);return e}makeVersion(){return ce`
|
||
|
<h4 style="
|
||
|
font-size: 12px !important;
|
||
|
color: #fff;
|
||
|
background: rgba(0,0,0,0.1);
|
||
|
padding: 8px 16px;
|
||
|
border-radius: 32px;
|
||
|
">
|
||
|
Bubble Card
|
||
|
<span style="
|
||
|
font-size: 10px;
|
||
|
background: rgba(0,120,180,1);
|
||
|
padding: 0px 8px;
|
||
|
border-radius: 12px;
|
||
|
margin-right: -6px;
|
||
|
float: right;
|
||
|
color: white;
|
||
|
">
|
||
|
${e}
|
||
|
</span>
|
||
|
</h4>
|
||
|
`}removeButton(e){delete this._config[e+"_name"],delete this._config[e+"_icon"],delete this._config[e+"_link"],delete this._config[e+"_entity"],delete this._config[e+"_pir_sensor"];for(let t=e;t<this.buttonIndex;t++)this._config[t+"_name"]=this._config[t+1+"_name"],this._config[t+"_icon"]=this._config[t+1+"_icon"],this._config[t+"_link"]=this._config[t+1+"_link"],this._config[t+"_entity"]=this._config[t+1+"_entity"],this._config[t+"_pir_sensor"]=this._config[t+1+"_pir_sensor"];delete this._config[this.buttonIndex+"_name"],delete this._config[this.buttonIndex+"_icon"],delete this._config[this.buttonIndex+"_link"],delete this._config[this.buttonIndex+"_entity"],delete this._config[this.buttonIndex+"_pir_sensor"],this.buttonIndex--,(0,n.BX)(this,"config-changed",{config:this._config})}makeStyleEditor(){return ce`
|
||
|
<ha-expansion-panel outlined>
|
||
|
<h4 slot="header">
|
||
|
<ha-icon icon="mdi:code-braces"></ha-icon>
|
||
|
Custom styles / Templates
|
||
|
</h4>
|
||
|
<div class="content">
|
||
|
<div class="code-editor">
|
||
|
<ha-code-editor
|
||
|
mode="yaml"
|
||
|
autofocus
|
||
|
autocomplete-entities
|
||
|
autocomplete-icons
|
||
|
.hass=${this.hass}
|
||
|
.value=${this._config.styles}
|
||
|
.configValue="${"styles"}"
|
||
|
@value-changed=${this._valueChanged}
|
||
|
></ha-code-editor>
|
||
|
</div>
|
||
|
<ha-alert alert-type="info">
|
||
|
For advanced users, you can edit the CSS style of this card in this editor. More information <a href="https://github.com/Clooos/Bubble-Card#styling">here</a>. You don't need to add <code>styles: |</code>, it will be added automatically. You can also add <a href="https://github.com/Clooos/Bubble-Card#templates">templates</a>.
|
||
|
<br><br><b>Looking for more advanced examples?</b> Check out my <a href="https://www.patreon.com/Clooos">Patreon</a> for exclusive custom styles and advanced templates, this is also the best way to show your support to my project!
|
||
|
</ha-alert>
|
||
|
</div>
|
||
|
</ha-expansion-panel>
|
||
|
`}_valueChanged(e){const t=e.target,o=e.detail;let a;if("HA-SWITCH"===t.tagName?a=t.checked:void 0!==t.value&&(a="string"==typeof t.value?t.value.replace(",","."):t.value),"string"==typeof a&&(a.endsWith(".")||"-"===a))return;const{configValue:i,checked:r}=t;if(i){const n=i.split(".");let r=this._config;for(let e=0;e<n.length-1;e++)r[n[e]]=r[n[e]]||{},r=r[n[e]];"input"===e.type?r[n[n.length-1]]=a:o&&r[n[n.length-1]]!==o.value?r[n[n.length-1]]=o.value:"HA-SWITCH"===t.tagName&&(r[n[n.length-1]]=a)}(0,n.BX)(this,"config-changed",{config:this._config}),this.requestUpdate()}_arrayValueChange(e,t,o){if(this._config.sub_button&&!this.subButtonJustAdded)return this.subButtonJustAdded=!0,void setTimeout((()=>this._arrayValueChange(e,t,o)),10);this._config[o]=this._config[o]||[];let a=[...this._config[o]];a[e]=a[e]||{},a[e]={...a[e],...t},this._config[o]=a,(0,n.BX)(this,"config-changed",{config:this._config}),this.requestUpdate()}_tapActionValueChange(e,t,o){if(void 0===o)for(let e in t)this._config[e]={...this._config[e],...t[e]};else{this._config[o]=this._config[o]||(o?{}:[]);let n=Array.isArray(this._config[o])?[...this._config[o]]:{...this._config[o]};if(Array.isArray(n)){n[e]=n[e]||{};let o={...n[e]};for(let e in t)o[e]=e in o?{...o[e],...t[e]}:t[e];n[e]=o}else for(let e in t)n.hasOwnProperty(e)?n[e]={...n[e],...t[e]}:n[e]=t[e];this._config[o]=n}(0,n.BX)(this,"config-changed",{config:this._config}),this.requestUpdate()}_conditionChanged(e,t,o){if(e.stopPropagation(),o){this._config[o]=this._config[o]||[];let n=[...this._config[o]];n[t]=n[t]||{};const a=e.detail.value;n[t]={...n[t],visibility:a},this._config[o]=n}else if("pop-up"===this._config.card_type){const t=e.detail.value;this._config={...this._config,trigger:t}}(0,n.BX)(this,"config-changed",{config:this._config}),this.requestUpdate()}static get styles(){return de`
|
||
|
div {
|
||
|
display: grid;
|
||
|
grid-gap: 12px;
|
||
|
}
|
||
|
|
||
|
ha-combo-box[label="Card type"]::after {
|
||
|
content: "";
|
||
|
position: relative;
|
||
|
background-color: var(--background-color, var(--secondary-background-color));
|
||
|
display: block;
|
||
|
width: 100%;
|
||
|
height: 1px;
|
||
|
top: 12px;
|
||
|
margin-bottom: 12px !important;
|
||
|
opacity: 0.6;
|
||
|
}
|
||
|
|
||
|
#add-button {
|
||
|
margin: 0 0 14px 0;
|
||
|
color: var(--text-primary-color);
|
||
|
width: 100%;
|
||
|
height: 32px;
|
||
|
border-radius: 16px;
|
||
|
border: none;
|
||
|
background-color: var(--accent-color);
|
||
|
cursor: pointer;
|
||
|
}
|
||
|
|
||
|
p {
|
||
|
margin-bottom: 4px;
|
||
|
}
|
||
|
|
||
|
ha-icon, a, p, button, h4 {
|
||
|
color: var(--primary-text-color) !important;
|
||
|
}
|
||
|
|
||
|
hr {
|
||
|
display: inline-block;
|
||
|
width: 100%;
|
||
|
border: 1px solid var(--background-color, var(--secondary-background-color));
|
||
|
opacity: 0.6;
|
||
|
margin: 8px 0 0 0;
|
||
|
}
|
||
|
|
||
|
code {
|
||
|
background: var(--accent-color);
|
||
|
background-blend-mode: darken;
|
||
|
padding: 2px 4px;
|
||
|
border-radius: 6px;
|
||
|
}
|
||
|
|
||
|
.button-header {
|
||
|
height: auto;
|
||
|
width: 100%;
|
||
|
display: inline-flex;
|
||
|
align-items: center;
|
||
|
margin: 0 8px;
|
||
|
}
|
||
|
|
||
|
.button-number {
|
||
|
display: inline-flex;
|
||
|
width: auto;
|
||
|
}
|
||
|
|
||
|
.remove-button {
|
||
|
display: inline-flex;
|
||
|
border-radius: 50%;
|
||
|
width: 24px;
|
||
|
height: 24px;
|
||
|
text-align: center;
|
||
|
line-height: 24px;
|
||
|
vertical-align: middle;
|
||
|
cursor: pointer;
|
||
|
}
|
||
|
|
||
|
.content {
|
||
|
margin: 12px 4px 14px 4px;
|
||
|
}
|
||
|
|
||
|
h4 > ha-icon {
|
||
|
margin: 8px;
|
||
|
}
|
||
|
|
||
|
ha-textfield {
|
||
|
width: 100%;
|
||
|
}
|
||
|
|
||
|
h3 {
|
||
|
margin: 4px 0;
|
||
|
}
|
||
|
|
||
|
.code-editor {
|
||
|
overflow: scroll;
|
||
|
}
|
||
|
|
||
|
.icon-button {
|
||
|
background: var(--accent-color);
|
||
|
border: none;
|
||
|
cursor: pointer;
|
||
|
padding: 8px;
|
||
|
margin: 0;
|
||
|
border-radius: 32px;
|
||
|
font-weight: bold;
|
||
|
}
|
||
|
|
||
|
.icon-button.header {
|
||
|
background: none;
|
||
|
float: right;
|
||
|
padding: 0;
|
||
|
margin: 0 8px;
|
||
|
}
|
||
|
|
||
|
ha-card-conditions-editor {
|
||
|
margin-top: -12px;
|
||
|
}
|
||
|
`}})}(),document.createElement("bubble-card-editor")}getLayoutOptions(){let e=1;"pop-up"===this.config.card_type?e=0:"horizontal-buttons-stack"===this.config.card_type?e=1:["cover"].includes(this.config.card_type)&&(e=2);let t=4;return"pop-up"===this.config.card_type?t=0:"horizontal-buttons-stack"===this.config.card_type&&(t=4),{grid_columns:this.config.columns??t,grid_rows:this.config.rows??e}}}customElements.define("bubble-card",ue),window.customCards=window.customCards||[],window.customCards.push({type:"bubble-card",name:"Bubble Card",preview:!1,description:"A minimalist card collection with a nice pop-up touch.",documentationURL:"https://github.com/Clooos/Bubble-Card/"}),console.info(`%c Bubble Card %c ${e} `,"background-color: #555;color: #fff;padding: 3px 2px 3px 3px;border-radius: 14px 0 0 14px;font-family: DejaVu Sans,Verdana,Geneva,sans-serif;text-shadow: 0 1px 0 rgba(1, 1, 1, 0.3)","background-color: #506eac;color: #fff;padding: 3px 3px 3px 2px;border-radius: 0 14px 14px 0;font-family: DejaVu Sans,Verdana,Geneva,sans-serif;text-shadow: 0 1px 0 rgba(1, 1, 1, 0.3)")})()})();
|