From 134ebc030467d68da02d9cf5e2c147e9d98b2b9a Mon Sep 17 00:00:00 2001 From: Cloos <36499953+Clooos@users.noreply.github.com> Date: Sat, 18 Nov 2023 12:02:37 +0100 Subject: [PATCH] Moved to dist/ --- bubble-card.js | 1 - 1 file changed, 1 deletion(-) delete mode 100644 bubble-card.js diff --git a/bubble-card.js b/bubble-card.js deleted file mode 100644 index 4931d20..0000000 --- a/bubble-card.js +++ /dev/null @@ -1 +0,0 @@ -var version="v1.5.0-beta.2";let editor,entityStates={},lastCall={entityId:null,stateChanged:null,timestamp:null},globalHosts={};class BubbleCard extends HTMLElement{set hass(hass){if(!this.content){this.attachShadow({mode:"open"}),this.shadowRoot.innerHTML='\n \n
\n
\n
\n ',this.card=this.shadowRoot.querySelector("ha-card"),this.content=this.shadowRoot.querySelector("div");const t=new Promise((t=>{t(document.querySelector("body > home-assistant").shadowRoot.querySelector("home-assistant-main").shadowRoot.querySelector("ha-drawer > partial-panel-resolver > ha-panel-lovelace").shadowRoot.querySelector("hui-root").shadowRoot.querySelector("div"))}));t.then((t=>{this.editorElement=t}))}let customStyles=this.config.styles?this.config.styles:"",entityId=this.config.entity?this.config.entity:"",icon=!this.config.icon&&this.config.entity?hass.states[entityId].attributes.icon||hass.states[entityId].attributes.entity_picture||"":this.config.icon||"",name=this.config.name?this.config.name:this.config.entity?hass.states[entityId].attributes.friendly_name:"",widthDesktop=this.config.width_desktop||"540px",widthDesktopDivided=widthDesktop?widthDesktop.match(/(\d+)(\D+)/):"",shadowOpacity=void 0!==this.config.shadow_opacity?this.config.shadow_opacity:"0",bgBlur=void 0!==this.config.bg_blur?this.config.bg_blur:"10",isSidebarHidden=this.config.is_sidebar_hidden||!1,state=entityId?hass.states[entityId].state:"",stateOn=["on","open","cleaning","true","home","playing"].includes(state)||0!==Number(state)&&!isNaN(Number(state)),formatedState,autoClose=this.config.auto_close||!1,riseAnimation=void 0===this.config.rise_animation||this.config.rise_animation,marginCenter=this.config.margin?"0"!==this.config.margin?this.config.margin:"0px":"7px";function toggleEntity(t){hass.callService("homeassistant","toggle",{entity_id:t})}function stateChanged(t){let e=Date.now();if(lastCall.entityId===t&&e-lastCall.timestamp<100)return lastCall.stateChanged;if(!hass.states[t]||!hass.states[t].state)return!1;let n=hass.states[t].state,i=hass.states[t].attributes.rgb_color;entityStates[t]||(entityStates[t]={prevState:null,prevColor:null});let o=entityStates[t].prevState!==n||entityStates[t].prevColor!==i;return entityStates[t].prevState=n,entityStates[t].prevColor=i,lastCall={entityId:t,stateChanged:o,timestamp:e},o}this.editorElement&&(editor=this.editorElement.classList.contains("edit-mode"));const addStyles=function(context,styles,customStyles,state,entityId,stateChangedVar,path="",element=context.content){const customStylesEval=customStyles?eval("`"+customStyles+"`"):"";let styleAddedKey=styles+"Added";if(!context[styleAddedKey]||context.previousStyle!==customStylesEval||stateChangedVar||context.previousConfig!==context.config){if(!context[styleAddedKey]){if(context.styleElement=element.querySelector("style"),!context.styleElement){context.styleElement=document.createElement("style");const t=path?element.querySelector(path):element;t?.appendChild(context.styleElement)}context[styleAddedKey]=!0}context.styleElement.innerHTML!==customStylesEval+styles&&(context.styleElement.innerHTML=customStylesEval+styles),context.previousStyle=customStylesEval,context.previousConfig=context.config}},forwardHaptic=t=>{fireEvent(window,"haptic",t)},navigate=(t,e,n=!1)=>{n?history.replaceState(null,"",e):history.pushState(null,"",e),fireEvent(window,"location-changed",{replace:n})},handleActionConfig=(t,e,n,i)=>{if(!i.confirmation||i.confirmation.exemptions&&i.confirmation.exemptions.some((t=>t.user===e.user.id))||(forwardHaptic("warning"),confirm(i.confirmation.text||`Are you sure you want to ${i.action}?`)))switch(i.action){case"more-info":(this.config.entity||this.config.camera_image)&&fireEvent(t,"hass-more-info",{entityId:this.config.entity?this.config.entity:this.config.camera_image});break;case"navigate":i.navigation_path&&navigate(t,i.navigation_path);break;case"url":i.url_path&&window.open(i.url_path);break;case"toggle":this.config.entity&&(toggleEntity(this.config.entity),forwardHaptic("success"));break;case"call-service":{if(!i.service)return void forwardHaptic("failure");const[t,n]=i.service.split(".",2);e.callService(t,n,i.service_data,i.target),forwardHaptic("success");break}case"fire-dom-event":fireEvent(t,"ll-custom",i)}},handleAction=(t,e,n,i)=>{let o;"double_tap"===i&&this.config.double_tap_action?o=this.config.double_tap_action:"hold"===i&&this.config.hold_action?o=this.config.hold_action:"tap"===i&&this.config.tap_action?o=this.config.tap_action:"double_tap"!==i||this.config.double_tap_action?("hold"!==i||this.config.hold_action)&&("tap"!==i||this.config.tap_action)||(o={action:"more-info"}):o={action:"toggle"},handleActionConfig(t,e,n,o)},addAction=function(){let t,e;return function(n,i,o,a){o.addEventListener(n,(()=>{const i=(new Date).getTime();"click"===n?i-(e||0)<250?(clearTimeout(t),handleAction(a,hass,{},"double_tap")):t=setTimeout((()=>{handleAction(a,hass,{},"tap")}),250):handleAction(a,hass,{},"hold"),e=i}),{passive:!0})}}();function addActions(t,e){addAction("click","tap",e,t),addAction("contextmenu","hold",e,t)}if(entityId){const e=!!hass.states[entityId].attributes&&hass.states[entityId].attributes;this.newPictureUrl=!!e.entity_picture&&e.entity_picture}function createIcon(t,e,n,i,o){updateIcon(t,e,n,i,o),editor||e.connection.subscribeEvents((a=>{a.data.entity_id===n&&t.newPictureUrl!==t.currentPictureUrl&&(t.currentPictureUrl=t.newPictureUrl,updateIcon(t,e,n,i,o))}),"state_changed")}function updateIcon(t,e,n,i,o){for(;o.firstChild;)o.removeChild(o.firstChild);if(t.newPictureUrl&&!t.config.icon){const e=document.createElement("img");e.setAttribute("src",t.newPictureUrl),e.setAttribute("class","entity-picture"),e.setAttribute("alt","Icon"),o&&o.appendChild(e)}else{const t=document.createElement("ha-icon");t.setAttribute("icon",i),t.setAttribute("class","icon"),o&&o.appendChild(t)}}function isColorCloseToWhite(t){let e=[220,220,190];for(let n=0;n<3;n++)if(t[n]{const i=document.createElement("button");return i.setAttribute("class",`button ${e.substring(1)}`),i.innerHTML=`\n ${""!==n?``:""}\n ${""!==t?`

${t}

`:""}\n `,i.hasListener||(i.addEventListener("click",(t=>{t.stopPropagation(),popUpOpen=location.hash+!0;localStorage.getItem("isManuallyClosed_"+e);popUpOpen!==e+!0?(navigate("",e),popUpOpen=e+!0):(history.replaceState(null,null,location.href.split("#")[0]),popUpOpen=e+!1)}),{passive:!0}),i.hasListener=!0),i};if(!this.buttonsAdded){const R=document.createElement("div");R.setAttribute("class","horizontal-buttons-stack-container"),this.content.appendChild(R),this.buttonsContainer=R}const i=(t,e)=>{if(hass.states[e].attributes.rgb_color){const n=hass.states[e].attributes.rgb_color,i=isColorCloseToWhite(n)?"rgba(255,220,200, 0.5)":`rgba(${n}, 0.5)`;t.style.backgroundColor=i,t.style.border="1px solid rgba(0,0,0,0)"}else hass.states[e].attributes.rgb_color||"on"!=hass.states[e].state?(t.style.backgroundColor="rgba(0,0,0,0)",t.style.border="1px solid var(--primary-text-color)"):(t.style.backgroundColor="rgba(255,255,255,0.5)",t.style.border="1px solid rgba(0,0,0,0)")};let o=[],a=1;for(;this.config[a+"_link"];){const U=a+"_",F=this.config[U+"name"]||"",X=this.config[U+"pir_sensor"];icon=this.config[U+"icon"]||"";const j=this.config[U+"link"],N=this.config[U+"entity"];o.push({button:F,pirSensor:X,icon:icon,link:j,lightEntity:N}),a++}if(this.config.auto_order&&o.sort(((t,e)=>{if(t.pirSensor&&e.pirSensor){if("on"===hass.states[t.pirSensor].state&&"on"===hass.states[e.pirSensor].state){return hass.states[t.pirSensor].last_updated{const e=n(t.button,t.link,t.icon);G[t.link]=e,this.buttonsContainer.appendChild(e)})),this.buttonsAdded=!0,this.buttons=G}let s=0,r=12;async function c(){let t=[];for(let e of o){this.buttons[e.link]&&(t.push(localStorage.getItem(`buttonWidth-${e.link}`)),t.push(localStorage.getItem(`buttonContent-${e.link}`)))}let e=await Promise.all(t),n=0;for(let t of o){let o=this.buttons[t.link];if(o){let i=e[n],a=e[n+1];n+=2,i&&"0"!==i&&a===o.innerHTML&&this.previousConfig===this.config||(i=o.offsetWidth,await localStorage.setItem(`buttonWidth-${t.link}`,i),await localStorage.setItem(`buttonContent-${t.link}`,o.innerHTML),this.previousConfig=this.config),o.style.transform=`translateX(${s}px)`,s+=parseInt(i)+r}t.lightEntity&&i(o,t.lightEntity)}}c.call(this);const l=`\n ha-card {\n border-radius: 0;\n }\n .horizontal-buttons-stack {\n width: 100%;\n margin-top: 0 !important;\n background: none !important;\n position: fixed;\n height: 51px;\n bottom: 16px;\n left: ${marginCenter};\n z-index: 1 !important; /* Higher value hide the more-info panel */\n }\n @keyframes from-bottom {\n 0% {transform: translateY(200px);}\n 20% {transform: translateY(200px);}\n 46% {transform: translateY(-8px);}\n 56% {transform: translateY(1px);}\n 62% {transform: translateY(-2px);}\n 70% {transform: translateY(0);}\n 100% {transform: translateY(0);}\n }\n .horizontal-buttons-stack-container {\n width: max-content;\n position: relative;\n height: 51px;\n }\n .button {\n display: flex;\n position: absolute;\n box-sizing: border-box !important;\n border: 1px solid var(--primary-text-color);\n align-items: center;\n height: 50px;\n white-space: nowrap;\n width: auto;\n border-radius: 25px;\n z-index: 1;\n padding: 16px;\n background: none;\n transition: background-color 1s, border 1s, transform 1s;\n color: var(--primary-text-color);\n }\n .icon {\n height: 24px;\n }\n .card-content {\n width: calc(100% + 18px);\n box-sizing: border-box !important;\n margin: 0 -36px !important;\n padding: 0 36px !important;\n overflow: scroll !important;\n -ms-overflow-style: none;\n scrollbar-width: none;\n -webkit-mask-image: linear-gradient(90deg, transparent 0%, rgba(0, 0, 0, 1) calc(0% + 28px), rgba(0, 0, 0, 1) calc(100% - 28px), transparent 100%);\n /* mask-image: linear-gradient(90deg, transparent 2%, rgba(0, 0, 0, 1) 6%, rgba(0, 0, 0, 1) 96%, transparent 100%); */\n /* -webkit-mask-image: linear-gradient(90deg, transparent 2%, rgba(0, 0, 0, 1) 6%, rgba(0, 0, 0, 1) 96%, transparent 100%); */\n }\n .horizontal-buttons-stack::before {\n content: '';\n position: absolute;\n top: -32px;\n left: -100%;\n display: block;\n background: linear-gradient(0deg, var(--background-color, var(--primary-background-color)) 50%, rgba(79, 69, 87, 0));\n width: 200%;\n height: 100px;\n }\n .card-content::-webkit-scrollbar {\n display: none;\n }\n @media only screen and (min-width: 768px) {\n .card-content {\n position: fixed;\n width: ${widthDesktop} !important;\n left: calc(50% - ${widthDesktopDivided[1]/2}${widthDesktopDivided[2]});\n margin-left: -13px !important;\n padding: 0 26px !important;\n }\n }\n @media only screen and (min-width: 870px) {\n .card-content {\n position: fixed;\n width: calc(${widthDesktop}${"%"!==widthDesktopDivided[2]||isSidebarHidden?"":" - var(--mdc-drawer-width)"}) !important;\n left: calc(50% - ${widthDesktopDivided[1]/2}${widthDesktopDivided[2]} + ${!0===isSidebarHidden?"0px":"var(--mdc-drawer-width) "+("%"===widthDesktopDivided[2]?"":"/ 2")});\n margin-left: -13px !important;\n padding: 0 26px !important;\n }\n }\n .horizontal-buttons-stack.editor {\n position: relative;\n bottom: 0;\n left: 0;\n overflow: hidden;\n }\n \n .horizontal-buttons-stack.editor::before {\n top: -32px;\n left: -100%;\n background: none;\n width: 100%;\n height: 0;\n }\n \n .horizontal-buttons-stack-container.editor > .button {\n transition: background-color 0s, border 0s, transform 0s;\n }\n \n .horizontal-buttons-stack-container.editor {\n margin-left: 1px;\n }\n \n .horizontal-buttons-stack.editor > .card-content {\n position: relative;\n width: calc(100% + 26px) !important;\n left: -26px;\n margin: 0 !important;\n padding: 0;\n }\n `;!window.hasAnimated&&riseAnimation&&(this.content.style.animation="from-bottom 1.3s forwards",window.hasAnimated=!0,setTimeout((()=>{this.content.style.animation="none"}),1500)),addStyles(this,l,customStyles),editor?(this.buttonsContainer.classList.add("editor"),this.card.classList.add("editor")):(this.buttonsContainer.classList.remove("editor"),this.card.classList.remove("editor"));break;case"button":if(!this.buttonAdded){const K=document.createElement("div");K.setAttribute("class","button-container"),this.content.appendChild(K)}const d=this.config.button_type||"switch";formatedState=hass.formatEntityState(hass.states[entityId]);const h=!!this.config.show_state&&this.config.show_state;let p=entityId?hass.states[entityId].attributes.brightness||0:"",u=entityId?hass.states[entityId].attributes.volume_level||0:"",g=!1,b=p,m=u,f=0,y=0,v=0,_=!1,w=null;const x=stateChanged(entityId),k=document.createElement("div");k.setAttribute("class","icon-container"),this.iconContainer=k;const C=document.createElement("div");C.setAttribute("class","name-container");const $=document.createElement("div");$.setAttribute("class","switch-button");const S=document.createElement("div");S.setAttribute("class","range-slider");const E=document.createElement("div");if(E.setAttribute("class","range-fill"),!this.buttonContainer||editor){if(editor&&this.buttonContainer){for(;this.buttonContainer.firstChild;)this.buttonContainer.removeChild(this.buttonContainer.firstChild);this.eventAdded=!1,this.wasEditing=!0}this.buttonContainer=this.content.querySelector(".button-container"),"slider"!==d||this.buttonAdded&&!editor?("switch"===d||"custom"===d||editor)&&(this.buttonContainer.appendChild($),$.appendChild(k),$.appendChild(C),this.switchButton=this.content.querySelector(".switch-button")):(this.buttonContainer.appendChild(S),S.appendChild(k),S.appendChild(C),S.appendChild(E),this.rangeFill=this.content.querySelector(".range-fill")),createIcon(this,hass,entityId,icon,this.iconContainer),C.innerHTML=`\n

${name}

\n ${h?`

${formatedState}

`:""}\n `,this.buttonAdded=!0}function A(t){let e=t.querySelector(".feedback-element");e||(e=document.createElement("div"),e.setAttribute("class","feedback-element"),t.appendChild(e)),e.style.animation="tap-feedback .5s",setTimeout((()=>{e.style.animation="none",t.removeChild(e)}),500)}function I(t){f=t.pageX||(t.touches?t.touches[0].pageX:0),y=t.pageY||(t.touches?t.touches[0].pageY:0),v=S.value,t.target!==k&&t.target!==k.querySelector("ha-icon")&&(g=!0,document.addEventListener("mouseup",O,{passive:!0}),document.addEventListener("touchend",O,{passive:!0}),document.addEventListener("mousemove",L,{passive:!0}),document.addEventListener("touchmove",L,{passive:!0}),w=setTimeout((()=>{V(t.pageX||t.touches[0].pageX),D(),w=null}),200))}function L(t){const e=t.pageX||(t.touches?t.touches[0].pageX:0),n=t.pageY||(t.touches?t.touches[0].pageY:0);Math.abs(n-y)>Math.abs(e-f)?(clearTimeout(w),O()):(document.removeEventListener("mousemove",L),document.removeEventListener("touchmove",L),document.addEventListener("mousemove",T,{passive:!0}),document.addEventListener("touchmove",T,{passive:!0}))}function O(){g=!1,_=!1,D(),document.removeEventListener("mouseup",O),document.removeEventListener("touchend",O),document.removeEventListener("mousemove",T),document.removeEventListener("touchmove",T)}function D(){entityId.startsWith("light.")?(p=b,hass.callService("light","turn_on",{entity_id:entityId,brightness:p})):entityId.startsWith("media_player.")&&(u=m,hass.callService("media_player","volume_set",{entity_id:entityId,volume_level:u}))}function T(t){const e=t.pageX||(t.touches?t.touches[0].pageX:0),n=t.pageY||(t.touches?t.touches[0].pageY:0);g&&Math.abs(e-f)>10?V(e):g&&Math.abs(n-y)>10&&(g=!1,S.value=v)}function V(t){const e=S.getBoundingClientRect(),n=Math.min(Math.max(t-e.left,0),e.width)/e.width;entityId.startsWith("light.")?b=Math.round(255*n):entityId.startsWith("media_player.")&&(m=n),E.style.transition="none",E.style.transform=`translateX(${100*n}%)`}if(h&&formatedState&&(this.content.querySelector(".state").textContent=formatedState),this.eventAdded||"switch"!==d?this.eventAdded||"slider"!==d?this.eventAdded||"custom"!==d||($.addEventListener("click",(()=>A(this.switchButton)),{passive:!0}),addActions(this,this.switchButton),this.eventAdded=!0):(S.addEventListener("mousedown",I,{passive:!0}),S.addEventListener("touchstart",I,{passive:!0}),addActions(this,this.iconContainer),this.eventAdded=!0):($.addEventListener("click",(()=>A(this.switchButton)),{passive:!0}),$.addEventListener("click",(function(t){t.target!==k&&t.target!==k.querySelector("ha-icon")&&toggleEntity(entityId)}),{passive:!0}),addActions(this,this.iconContainer),this.eventAdded=!0),this.isDragging||"slider"!==d||(this.rangeFill.style.transition="all .3s",entityId.startsWith("light.")?this.rangeFill.style.transform=`translateX(${p/255*100}%)`:entityId.startsWith("media_player.")&&(this.rangeFill.style.transform=`translateX(${100*u}%)`)),"slider"===d&&(!this.colorAdded||x||this.wasEditing)){if(entityId.startsWith("light.")){const Z=hass.states[entityId].attributes.rgb_color;this.rgbColorOpacity=Z?isColorCloseToWhite(Z)?"rgba(255,220,200,0.5)":`rgba(${Z}, 0.5)`:stateOn?"rgba(255,220,200, 0.5)":"rgba(255, 255, 255, 0.5)",this.rgbColor=Z?isColorCloseToWhite(Z)?"rgb(255,220,200)":`rgb(${Z})`:stateOn?"rgba(255,220,200, 1)":"rgba(255, 255, 255, 1)",this.iconFilter=Z?isColorCloseToWhite(Z)?"none":"brightness(1.1)":"none"}else this.rgbColorOpacity="var(--accent-color)",this.iconFilter="brightness(1.1)";this.colorAdded=!0,this.wasEditing=!1}const B=`\n ha-card {\n margin-top: 0 !important;\n background: none !important;\n opacity: ${"unavailable"!==state?"1":"0.5"};\n }\n \n .button-container {\n position: relative;\n width: 100%;\n height: 50px;\n z-index: 0;\n background-color: var(--background-color-2,var(--secondary-background-color));\n border-radius: 25px;\n mask-image: radial-gradient(white, black);\n -webkit-mask-image: radial-gradient(white, black);\n -webkit-backface-visibility: hidden;\n -moz-backface-visibility: hidden;\n -webkit-transform: translateZ(0);\n overflow: hidden;\n }\n \n .switch-button,\n .range-slider {\n display: inline-flex;\n position: absolute;\n height: 100%;\n width: 100%;\n transition: background-color 1.5s;\n background-color: ${stateOn&&["switch","custom"].includes(d)?"var(--accent-color)":"rgba(0,0,0,0)"};\n }\n \n .range-fill {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n background-color: ${this.rgbColorOpacity};\n }\n \n .switch-button {\n cursor: pointer !important;\n }\n \n .range-slider {\n cursor: ew-resize;\n }\n \n .range-fill {\n z-index: 0;\n width: 100%;\n left: -100%;\n }\n \n .icon-container {\n position: absolute;\n display: flex;\n z-index: 1;\n width: 38px;\n height: 38px;\n margin: 6px;\n border-radius: 50%;\n cursor: pointer !important;\n background-color: var(--card-background-color,var(--ha-card-background));\n }\n \n .icon-container::after {\n content: '';\n position: absolute;\n display: block;\n opacity: ${entityId.startsWith("light.")?"0.2":"0"};\n width: 100%;\n height: 100%;\n transition: all 1s;\n border-radius: 50%;\n background-color: ${stateOn?this.rgbColor?this.rgbColor:"var(--accent-color)":"var(--card-background-color,var(--ha-card-background))"};\n }\n \n ha-icon {\n display: flex;\n position: absolute;\n margin: inherit;\n padding: 1px 2px;\n width: 22px; \n height: 22px;\n color: ${stateOn?this.rgbColor?this.rgbColor:"var(--accent-color)":"inherit"};\n opacity: ${stateOn?"1":"0.6"};\n filter: ${stateOn?this.rgbColor?this.iconFilter:"brightness(1.1)":"inherit"};\n }\n \n .entity-picture {\n display: flex;\n height: 38px;\n width: 38px;\n border-radius: 100%;\n }\n \n .name-container {\n position: relative;\n display: ${h?"block":"inline-flex"};\n margin-left: 58px;\n z-index: 1;\n font-weight: 600;\n align-items: center;\n line-height: ${h?"4px":"16px"};\n padding-right: 16px;\n }\n \n .state {\n font-size: 12px;\n opacity: 0.7;\n }\n \n .feedback-element {\n position: absolute;\n top: 0;\n left: 0;\n opacity: 0;\n width: 100%;\n height: 100%;\n background-color: rgb(0,0,0);\n }\n \n @keyframes tap-feedback {\n 0% {transform: translateX(-100%); opacity: 0;}\n 64% {transform: translateX(0); opacity: 0.1;}\n 100% {transform: translateX(100%); opacity: 0;}\n }\n `;addStyles(this,B,customStyles,state,entityId,x);break;case"separator":if(!this.separatorAdded||editor){if(editor&&this.separatorContainer)for(;this.separatorContainer.firstChild;)this.separatorContainer.removeChild(this.separatorContainer.firstChild);this.separatorAdded||(this.separatorContainer=document.createElement("div"),this.separatorContainer.setAttribute("class","separator-container")),this.separatorContainer.innerHTML=`\n
\n \n

${name}

\n
\n
\n `,this.content.appendChild(this.separatorContainer),this.separatorAdded=!0}const z="\n .separator-container {\n display: inline-flex;\n width: 100%;\n margin-top: 12px;\n }\n .separator-container div:first-child {\n display: inline-flex;\n max-width: calc(100% - 38px);\n }\n .separator-container div ha-icon{\n display: inline-flex;\n height: 24px;\n width: 24px;\n margin: 0 20px 0 8px;\n transform: translateY(-2px);\n }\n .separator-container div h4{\n display: inline-flex;\n margin: 0 20px 0 0;\n font-size: 17px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .separator-container div:last-child{\n display: inline-flex; \n border-radius: 6px; \n opacity: 0.3; \n margin-left: 10px; \n flex-grow: 1; \n height: 6px; \n align-self: center; \n background-color: var(--background-color,var(--secondary-background-color));\n ";addStyles(this,z,customStyles);break;case"cover":const H=this.config.icon_open?this.config.icon_open:"mdi:window-shutter-open",M=this.config.icon_close?this.config.icon_close:"mdi:window-shutter",q=this.config.open_service?this.config.open_service:"cover.open_cover",P=this.config.close_service?this.config.close_service:"cover.close_cover",Y=this.config.stop_service?this.config.stop_service:"cover.stop_cover";if(icon="open"===hass.states[this.config.entity].state?H:M,formatedState=this.config.entity?hass.formatEntityState(hass.states[this.config.entity]):"",!this.coverAdded||editor){if(editor&&this.coverContainer)for(;this.coverContainer.firstChild;)this.coverContainer.removeChild(this.coverContainer.firstChild);this.coverContainer=document.createElement("div"),this.coverContainer.setAttribute("class","cover-container"),this.coverContainer.innerHTML=`\n
\n
\n
\n
\n

${name}

\n

${formatedState}

\n
\n
\n
\n \n \n \n
\n `,this.content.appendChild(this.coverContainer);const J=this.coverContainer.querySelector(".open"),Q=this.coverContainer.querySelector(".stop"),tt=this.coverContainer.querySelector(".close");J.addEventListener("click",(()=>{hass.callService(q.split(".")[0],q.split(".")[1],{entity_id:entityId})}),{passive:!0}),Q.addEventListener("click",(()=>{hass.callService(Y.split(".")[0],Y.split(".")[1],{entity_id:entityId})}),{passive:!0}),tt.addEventListener("click",(()=>{hass.callService(P.split(".")[0],P.split(".")[1],{entity_id:entityId})}),{passive:!0}),this.iconContainer=this.content.querySelector(".icon-container"),addActions(this,this.iconContainer),this.coverAdded=!0}this.iconContainer&&(this.iconContainer.innerHTML=``,this.content.querySelector(".state").textContent=formatedState);const W="\n ha-card {\n margin-top: 0 !important;\n background: none !important;\n }\n \n .header-container {\n display: flex;\n align-items: center;\n margin-bottom: 10px;\n }\n \n .cover-container {\n display: grid;\n }\n \n .icon-container {\n display: flex;\n margin: 0 !important;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n /*z-index: 1;*/\n width: 48px;\n height: 48px;\n margin: 6px;\n border-radius: 50%;\n background-color: var(--card-background-color,var(--ha-card-background));\n border: 6px solid var(--background-color-2,var(--secondary-background-color));\n box-sizing: border-box;\n }\n \n .name-container {\n font-weight: 600;\n margin-left: 10px;\n line-height: 4px;\n }\n \n .buttons-container {\n display: grid;\n align-self: center;\n grid-auto-flow: column;\n grid-gap: 18px; \n }\n \n .state {\n font-size: 12px;\n opacity: 0.7;\n }\n \n ha-icon {\n display: flex; \n height: 24px; \n width: 24px; \n color: var(--primary-text-color);\n }\n \n .button {\n display: flex;\n background: var(--background-color-2,var(--secondary-background-color));\n height: 42px;\n border-radius: 32px;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n border: none;\n }\n ";addStyles(this,W,customStyles,state,entityId);break;case"empty-column":if(!this.emptyCollumnAdded){const et=document.createElement("div");et.setAttribute("class","empty-column"),et.innerHTML='\n
\n ',this.content.appendChild(et),this.emptyColumnAdded=!0}}}setConfig(t){if("pop-up"===t.card_type)throw new Error('Since v1.5.0 you need to manually add a new frontend extra module into your configuration.yaml. Then replace "custom:bubble-card" with "custom:bubble-pop-up" in all your pop-ups.');if("horizontal-buttons-stack"===t.card_type){var e={};for(var n in t)if(n.match(/^\d+_icon$/)){var i=n.replace("_icon","_link");if(void 0===t[i])throw new Error("You need to define "+i);if(e[t[i]])throw new Error("You can't use "+t[i]+" twice");e[t[i]]=!0}}else if(("button"===t.card_type||"cover"===t.card_type)&&!t.entity)throw new Error("You need to define an entity");this.config=t}getCardSize(){return 0}static getConfigElement(){return document.createElement("bubble-card-editor")}}console.info(`%c Bubble Card %c ${version} `,"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)"),customElements.define("bubble-card",BubbleCard);const fireEvent=(t,e,n,i)=>{i=i||{},n=null==n?{}:n;const o=new Event(e,{bubbles:void 0===i.bubbles||i.bubbles,cancelable:Boolean(i.cancelable),composed:void 0===i.composed||i.composed});return o.detail=n,t.dispatchEvent(o),o};customElements.get("ha-switch");const LitElement=Object.getPrototypeOf(customElements.get("ha-panel-lovelace")),html=LitElement.prototype.html,css=LitElement.prototype.css;class BubbleCardEditor extends LitElement{setConfig(t){this._config={...t}}static get properties(){return{hass:{},_config:{}}}get _card_type(){return this._config.card_type||""}get _button_type(){return this._config.button_type||"switch"}get _entity(){return this._config.entity||""}get _name(){return this._config.name||""}get _icon(){return this._config.icon||""}get _state(){return this._config.state||""}get _width_desktop(){return this._config.width_desktop||"540px"}get _is_sidebar_hidden(){return this._config.is_sidebar_hidden||!1}get _rise_animation(){return void 0===this._config.rise_animation||this._config.rise_animation}get _icon_open(){return this._config.icon_open||""}get _icon_close(){return this._config.icon_close||""}get _open_service(){return this._config.open_service||"cover.open_cover"}get _close_service(){return this._config.open_service||"cover.close_cover"}get _stop_service(){return this._config.open_service||"cover.stop_cover"}get _auto_order(){return this._config.auto_order||!1}get _show_state(){return this._config.show_state||!1}render(){if(!this.hass)return html``;if(!this.listsUpdated){const t=t=>({label:t,value:t});this.allEntitiesList=Object.keys(this.hass.states).map(t),this.lightList=Object.keys(this.hass.states).filter((t=>"light"===t.substr(0,t.indexOf(".")))).map(t),this.sensorList=Object.keys(this.hass.states).filter((t=>"sensor"===t.substr(0,t.indexOf(".")))).map(t),this.binarySensorList=Object.keys(this.hass.states).filter((t=>"binary_sensor"===t.substr(0,t.indexOf(".")))).map(t),this.coverList=Object.keys(this.hass.states).filter((t=>"cover"===t.substr(0,t.indexOf(".")))).map(t),this.cardTypeList=[{label:"Button",value:"button"},{label:"Cover",value:"cover"},{label:"Empty column",value:"empty-column"},{label:"Horizontal buttons stack",value:"horizontal-buttons-stack"},{label:"Pop-up",value:"pop-up"},{label:"Separator",value:"separator"}],this.buttonTypeList=[{label:"Switch",value:"switch"},{label:"Slider",value:"slider"}],this.listsUpdated=!0}const t=this.allEntitiesList,e=(this.lightList,this.sensorList,this.coverList),n=this.cardTypeList,i=this.buttonTypeList;if("pop-up"===this._config.card_type)return html`
${this.makeDropdown("Card type","card_type",n)}

Pop-up

This card allows you to convert any vertical stack into a pop-up. Each pop-up can be opened by targeting its link (e.g. '#pop-up-name'), with navigation_path or with the horizontal buttons stack that is included. Since v1.5.0 you need to manually add a new frontend extra module into your configuration.yaml.

Installation

  • In your configuration.yaml, add the following under frontend :
  • frontend:
        extra_module_url:
            /hacsfiles/Bubble-Card/bubble-pop-up.js
  • Restart Home Assistant.
  • Now in edit mode, from the card list create a vertical stack then create a Bubble Pop-up in it.
  • For YAML users :
  • type: vertical-stack
    cards:
      - type: custom:bubble-pop-up
        hash: '#pop-up-name'
    ${this.makeVersion()}
`;if("button"===this._config.card_type)return html`
${this.makeDropdown("Card type","card_type",n)}

Button

This card can be a slider or a button, allowing you to toggle your entities, control the brightness of your lights and the volume of your media players. To access color / control of an entity, simply tap on the icon. ${this.makeDropdown("slider"!==this._button_type?"Entity (toggle)":"Entity (light or media_player)","entity",t)} ${this.makeDropdown("Button type","button_type",i)} ${this.makeDropdown("Optional - Icon","icon")}
${this.makeVersion()}
`;if("separator"===this._config.card_type)return html`
${this.makeDropdown("Card type","card_type",n)}

Separator

This card is a simple separator for dividing your pop-up into categories / sections. e.g. Lights, Devices, Covers, Settings, Automations... ${this.makeDropdown("Icon","icon")} ${this.makeVersion()}
`;if("horizontal-buttons-stack"===this._config.card_type){if(!this.buttonAdded&&this.shadowRoot.querySelector("#add-button")){const t=this.shadowRoot.querySelector("#add-button");for(this.buttonIndex=0;this._config[this.buttonIndex+1+"_link"];)this.buttonIndex++;t.addEventListener("click",(()=>{this.buttonIndex++;const e=t.style.opacity,n=t.innerText;t.style.opacity="0.6",t.style.transition="opacity 1s",t.innerText="Loading...",setTimeout((()=>{t.style.opacity=e,t.innerText=n}),5e3)}),{passive:!0}),this.buttonAdded=!0}return html`
${this.makeDropdown("Card type","card_type",n)}

Horizontal buttons stack

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.

Please note that this card may take some time to load in edit mode.
${this.makeButton()}

Styling options

${this.makeVersion()}
`}return"cover"===this._config.card_type?html`
${this.makeDropdown("Card type","card_type",n)}

Cover

This card allows you to control your covers. ${this.makeDropdown("Entity","entity",e)} ${this.makeDropdown("Optional - Open icon","icon_open")} ${this.makeDropdown("Optional - Closed icon","icon_close")} ${this.makeVersion()}
`:"empty-column"===this._config.card_type?html`
${this.makeDropdown("Card type","card_type",n)}

Empty column

Just an empty card to fill any empty column. ${this.makeVersion()}
`:this._config.card_type?void 0:html`
${this.makeDropdown("Card type","card_type",n)} You need to add a card type first.

Almost everything is available in the GUI editor, but in the YAML editor you can add your own custom styles, create custom buttons or modify the tap actions of all cards. You can find more details on my GitHub page.

And if you like my project and want to support me, please consider making a donation. Any amount is welcome and very much appreciated! 🍻

${this.makeVersion()}
`}makeDropdown(t,e,n){this.hass;return t.includes("icon")||t.includes("Icon")?html`
`:html`
`}makeButton(){let t=[];for(let e=1;e<=this.buttonIndex;e++)t.push(html`
this.removeButton(e)}> Button ${e}
`);return t}makeVersion(){return html`

Bubble Card ${version}

`}removeButton(t){delete this._config[t+"_name"],delete this._config[t+"_icon"],delete this._config[t+"_link"],delete this._config[t+"_entity"],delete this._config[t+"_pir_sensor"];for(let e=t;e