diff --git a/dynamic-weather-card.js b/dynamic-weather-card.js index 880e46f..22cbc43 100644 --- a/dynamic-weather-card.js +++ b/dynamic-weather-card.js @@ -1,8 +1,684 @@ -var w=function(o,i,a,n){var l=arguments.length,s=l<3?i:n===null?n=Object.getOwnPropertyDescriptor(i,a):n,r;if(typeof Reflect==="object"&&typeof Reflect.decorate==="function")s=Reflect.decorate(o,i,a,n);else for(var c=o.length-1;c>=0;c--)if(r=o[c])s=(l<3?r(s):l>3?r(i,a,s):r(i,a))||s;return l>3&&s&&Object.defineProperty(i,a,s),s};var io=globalThis,yo=io.ShadowRoot&&(io.ShadyCSS===void 0||io.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,fo=Symbol(),Yo=new WeakMap;class wo{constructor(o,i,a){if(this._$cssResult$=!0,a!==fo)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=o,this._strings=i}get styleSheet(){let o=this._styleSheet,i=this._strings;if(yo&&o===void 0){let a=i!==void 0&&i.length===1;if(a)o=Yo.get(i);if(o===void 0){if((this._styleSheet=o=new CSSStyleSheet).replaceSync(this.cssText),a)Yo.set(i,o)}}return o}toString(){return this.cssText}}var Oi=(o)=>{if(o._$cssResult$===!0)return o.cssText;else if(typeof o==="number")return o;else throw Error(`Value passed to 'css' function must be a 'css' function result: ${o}. Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.`)},Ei=(o)=>new wo(typeof o==="string"?o:String(o),void 0,fo),W=(o,...i)=>{let a=o.length===1?o[0]:i.reduce((n,l,s)=>n+Oi(l)+o[s+1],o[0]);return new wo(a,o,fo)},Lo=(o,i)=>{if(yo)o.adoptedStyleSheets=i.map((a)=>a instanceof CSSStyleSheet?a:a.styleSheet);else for(let a of i){let n=document.createElement("style"),l=io.litNonce;if(l!==void 0)n.setAttribute("nonce",l);n.textContent=a.cssText,o.appendChild(n)}},oa=(o)=>{let i="";for(let a of o.cssRules)i+=a.cssText;return Ei(i)},to=yo?(o)=>o:(o)=>o instanceof CSSStyleSheet?oa(o):o;var{is:ia,defineProperty:aa,getOwnPropertyDescriptor:Io,getOwnPropertyNames:na,getOwnPropertySymbols:la,getPrototypeOf:Oo}=Object,sa=!1,z=globalThis;if(sa)z.customElements??=customElements;var H=!0,Z,Eo=z.trustedTypes,ra=Eo?Eo.emptyScript:"",ii=H?z.reactiveElementPolyfillSupportDevMode:z.reactiveElementPolyfillSupport;if(H)z.litIssuedWarnings??=new Set,Z=(o,i)=>{if(i+=` See https://lit.dev/msg/${o} for more information.`,!z.litIssuedWarnings.has(i)&&!z.litIssuedWarnings.has(o))console.warn(i),z.litIssuedWarnings.add(i)},queueMicrotask(()=>{if(Z("dev-mode","Lit is in dev mode. Not recommended for production!"),z.ShadyDOM?.inUse&&ii===void 0)Z("polyfill-support-missing","Shadow DOM is being polyfilled via `ShadyDOM` but the `polyfill-support` module has not been loaded.")});var ca=H?(o)=>{if(!z.emitLitDebugLogEvents)return;z.dispatchEvent(new CustomEvent("lit-debug",{detail:o}))}:void 0,x=(o,i)=>o,j={toAttribute(o,i){switch(i){case Boolean:o=o?ra:null;break;case Object:case Array:o=o==null?o:JSON.stringify(o);break}return o},fromAttribute(o,i){let a=o;switch(i){case Boolean:a=o!==null;break;case Number:a=o===null?null:Number(o);break;case Object:case Array:try{a=JSON.parse(o)}catch(n){a=null}break}return a}},ao=(o,i)=>!ia(o,i),oi={attribute:!0,type:String,converter:j,reflect:!1,useDefault:!1,hasChanged:ao};Symbol.metadata??=Symbol("metadata");z.litPropertyMetadata??=new WeakMap;class A extends HTMLElement{static addInitializer(o){this.__prepare(),(this._initializers??=[]).push(o)}static get observedAttributes(){return this.finalize(),this.__attributeToPropertyMap&&[...this.__attributeToPropertyMap.keys()]}static createProperty(o,i=oi){if(i.state)i.attribute=!1;if(this.__prepare(),this.prototype.hasOwnProperty(o))i=Object.create(i),i.wrapped=!0;if(this.elementProperties.set(o,i),!i.noAccessor){let a=H?Symbol.for(`${String(o)} (@property() cache)`):Symbol(),n=this.getPropertyDescriptor(o,a,i);if(n!==void 0)aa(this.prototype,o,n)}}static getPropertyDescriptor(o,i,a){let{get:n,set:l}=Io(this.prototype,o)??{get(){return this[i]},set(s){this[i]=s}};if(H&&n==null){if("value"in(Io(this.prototype,o)??{}))throw Error(`Field ${JSON.stringify(String(o))} on ${this.name} was declared as a reactive property but it's actually declared as a value on the prototype. Usually this is due to using @property or @state on a method.`);Z("reactive-property-without-getter",`Field ${JSON.stringify(String(o))} on ${this.name} was declared as a reactive property but it does not have a getter. This will be an error in a future version of Lit.`)}return{get:n,set(s){let r=n?.call(this);l?.call(this,s),this.requestUpdate(o,r,a)},configurable:!0,enumerable:!0}}static getPropertyOptions(o){return this.elementProperties.get(o)??oi}static __prepare(){if(this.hasOwnProperty(x("elementProperties",this)))return;let o=Oo(this);if(o.finalize(),o._initializers!==void 0)this._initializers=[...o._initializers];this.elementProperties=new Map(o.elementProperties)}static finalize(){if(this.hasOwnProperty(x("finalized",this)))return;if(this.finalized=!0,this.__prepare(),this.hasOwnProperty(x("properties",this))){let i=this.properties,a=[...na(i),...la(i)];for(let n of a)this.createProperty(n,i[n])}let o=this[Symbol.metadata];if(o!==null){let i=litPropertyMetadata.get(o);if(i!==void 0)for(let[a,n]of i)this.elementProperties.set(a,n)}this.__attributeToPropertyMap=new Map;for(let[i,a]of this.elementProperties){let n=this.__attributeNameForProperty(i,a);if(n!==void 0)this.__attributeToPropertyMap.set(n,i)}if(this.elementStyles=this.finalizeStyles(this.styles),H){if(this.hasOwnProperty("createProperty"))Z("no-override-create-property","Overriding ReactiveElement.createProperty() is deprecated. The override will not be called with standard decorators");if(this.hasOwnProperty("getPropertyDescriptor"))Z("no-override-get-property-descriptor","Overriding ReactiveElement.getPropertyDescriptor() is deprecated. The override will not be called with standard decorators")}}static finalizeStyles(o){let i=[];if(Array.isArray(o)){let a=new Set(o.flat(1/0).reverse());for(let n of a)i.unshift(to(n))}else if(o!==void 0)i.push(to(o));return i}static __attributeNameForProperty(o,i){let a=i.attribute;return a===!1?void 0:typeof a==="string"?a:typeof o==="string"?o.toLowerCase():void 0}constructor(){super();this.__instanceProperties=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this.__reflectingProperty=null,this.__initialize()}__initialize(){this.__updatePromise=new Promise((o)=>this.enableUpdating=o),this._$changedProperties=new Map,this.__saveInstanceProperties(),this.requestUpdate(),this.constructor._initializers?.forEach((o)=>o(this))}addController(o){if((this.__controllers??=new Set).add(o),this.renderRoot!==void 0&&this.isConnected)o.hostConnected?.()}removeController(o){this.__controllers?.delete(o)}__saveInstanceProperties(){let o=new Map,i=this.constructor.elementProperties;for(let a of i.keys())if(this.hasOwnProperty(a))o.set(a,this[a]),delete this[a];if(o.size>0)this.__instanceProperties=o}createRenderRoot(){let o=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return Lo(o,this.constructor.elementStyles),o}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this.__controllers?.forEach((o)=>o.hostConnected?.())}enableUpdating(o){}disconnectedCallback(){this.__controllers?.forEach((o)=>o.hostDisconnected?.())}attributeChangedCallback(o,i,a){this._$attributeToProperty(o,a)}__propertyToAttribute(o,i){let n=this.constructor.elementProperties.get(o),l=this.constructor.__attributeNameForProperty(o,n);if(l!==void 0&&n.reflect===!0){let r=(n.converter?.toAttribute!==void 0?n.converter:j).toAttribute(i,n.type);if(H&&this.constructor.enabledWarnings.includes("migration")&&r===void 0)Z("undefined-attribute-value",`The attribute value for the ${o} property is undefined on element ${this.localName}. The attribute will be removed, but in the previous version of \`ReactiveElement\`, the attribute would not have changed.`);if(this.__reflectingProperty=o,r==null)this.removeAttribute(l);else this.setAttribute(l,r);this.__reflectingProperty=null}}_$attributeToProperty(o,i){let a=this.constructor,n=a.__attributeToPropertyMap.get(o);if(n!==void 0&&this.__reflectingProperty!==n){let l=a.getPropertyOptions(n),s=typeof l.converter==="function"?{fromAttribute:l.converter}:l.converter?.fromAttribute!==void 0?l.converter:j;this.__reflectingProperty=n;let r=s.fromAttribute(i,l.type);this[n]=r??this.__defaultValues?.get(n)??r,this.__reflectingProperty=null}}requestUpdate(o,i,a,n=!1,l){if(o!==void 0){if(H&&o instanceof Event)Z("","The requestUpdate() method was called with an Event as the property name. This is probably a mistake caused by binding this.requestUpdate as an event listener. Instead bind a function that will call it with no arguments: () => this.requestUpdate()");let s=this.constructor;if(n===!1)l=this[o];if(a??=s.getPropertyOptions(o),(a.hasChanged??ao)(l,i)||a.useDefault&&a.reflect&&l===this.__defaultValues?.get(o)&&!this.hasAttribute(s.__attributeNameForProperty(o,a)))this._$changeProperty(o,i,a);else return}if(this.isUpdatePending===!1)this.__updatePromise=this.__enqueueUpdate()}_$changeProperty(o,i,{useDefault:a,reflect:n,wrapped:l},s){if(a&&!(this.__defaultValues??=new Map).has(o)){if(this.__defaultValues.set(o,s??i??this[o]),l!==!0||s!==void 0)return}if(!this._$changedProperties.has(o)){if(!this.hasUpdated&&!a)i=void 0;this._$changedProperties.set(o,i)}if(n===!0&&this.__reflectingProperty!==o)(this.__reflectingProperties??=new Set).add(o)}async __enqueueUpdate(){this.isUpdatePending=!0;try{await this.__updatePromise}catch(i){Promise.reject(i)}let o=this.scheduleUpdate();if(o!=null)await o;return!this.isUpdatePending}scheduleUpdate(){let o=this.performUpdate();if(H&&this.constructor.enabledWarnings.includes("async-perform-update")&&typeof o?.then==="function")Z("async-perform-update",`Element ${this.localName} returned a Promise from performUpdate(). This behavior is deprecated and will be removed in a future version of ReactiveElement.`);return o}performUpdate(){if(!this.isUpdatePending)return;if(ca?.({kind:"update"}),!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),H){let l=[...this.constructor.elementProperties.keys()].filter((s)=>this.hasOwnProperty(s)&&(s in Oo(this)));if(l.length)throw Error(`The following properties on element ${this.localName} will not trigger updates as expected because they are set using class fields: ${l.join(", ")}. Native class fields and some compiled output will overwrite accessors used for detecting changes. See https://lit.dev/msg/class-field-shadowing for more information.`)}if(this.__instanceProperties){for(let[n,l]of this.__instanceProperties)this[n]=l;this.__instanceProperties=void 0}let a=this.constructor.elementProperties;if(a.size>0)for(let[n,l]of a){let{wrapped:s}=l,r=this[n];if(s===!0&&!this._$changedProperties.has(n)&&r!==void 0)this._$changeProperty(n,void 0,l,r)}}let o=!1,i=this._$changedProperties;try{if(o=this.shouldUpdate(i),o)this.willUpdate(i),this.__controllers?.forEach((a)=>a.hostUpdate?.()),this.update(i);else this.__markUpdated()}catch(a){throw o=!1,this.__markUpdated(),a}if(o)this._$didUpdate(i)}willUpdate(o){}_$didUpdate(o){if(this.__controllers?.forEach((i)=>i.hostUpdated?.()),!this.hasUpdated)this.hasUpdated=!0,this.firstUpdated(o);if(this.updated(o),H&&this.isUpdatePending&&this.constructor.enabledWarnings.includes("change-in-update"))Z("change-in-update",`Element ${this.localName} scheduled an update (generally because a property was set) after an update completed, causing a new update to be scheduled. This is inefficient and should be avoided unless the next update can only be scheduled as a side effect of the previous update.`)}__markUpdated(){this._$changedProperties=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this.__updatePromise}shouldUpdate(o){return!0}update(o){this.__reflectingProperties&&=this.__reflectingProperties.forEach((i)=>this.__propertyToAttribute(i,this[i])),this.__markUpdated()}updated(o){}firstUpdated(o){}}A.elementStyles=[];A.shadowRootOptions={mode:"open"};A[x("elementProperties",A)]=new Map;A[x("finalized",A)]=new Map;ii?.({ReactiveElement:A});if(H){A.enabledWarnings=["change-in-update","async-perform-update"];let o=function(i){if(!i.hasOwnProperty(x("enabledWarnings",i)))i.enabledWarnings=i.enabledWarnings.slice()};A.enableWarning=function(i){if(o(this),!this.enabledWarnings.includes(i))this.enabledWarnings.push(i)},A.disableWarning=function(i){o(this);let a=this.enabledWarnings.indexOf(i);if(a>=0)this.enabledWarnings.splice(a,1)}}(z.reactiveElementVersions??=[]).push("2.1.2");if(H&&z.reactiveElementVersions.length>1)queueMicrotask(()=>{Z("multiple-versions","Multiple versions of Lit loaded. Loading multiple versions is not recommended.")});var K=globalThis,u=(o)=>{if(!K.emitLitDebugLogEvents)return;K.dispatchEvent(new CustomEvent("lit-debug",{detail:o}))},_a=0,V;K.litIssuedWarnings??=new Set,V=(o,i)=>{if(i+=o?` See https://lit.dev/msg/${o} for more information.`:"",!K.litIssuedWarnings.has(i)&&!K.litIssuedWarnings.has(o))console.warn(i),K.litIssuedWarnings.add(i)},queueMicrotask(()=>{V("dev-mode","Lit is in dev mode. Not recommended for production!")});var v=K.ShadyDOM?.inUse&&K.ShadyDOM?.noPatch===!0?K.ShadyDOM.wrap:(o)=>o,no=K.trustedTypes,ai=no?no.createPolicy("lit-html",{createHTML:(o)=>o}):void 0,da=(o)=>o,co=(o,i,a)=>da,ha=(o)=>{if(P!==co)throw Error("Attempted to overwrite existing lit-html security policy. setSanitizeDOMValueFactory should be called at most once.");P=o},ga=()=>{P=co},Mo=(o,i,a)=>{return P(o,i,a)},di="$lit$",q=`lit$${Math.random().toFixed(9).slice(2)}$`,hi="?"+q,ea=`<${hi}>`,Q=document,U=()=>Q.createComment(""),R=(o)=>o===null||typeof o!="object"&&typeof o!="function",zo=Array.isArray,ua=(o)=>zo(o)||typeof o?.[Symbol.iterator]==="function",mo=`[ -\f\r]`,ka=`[^ -\f\r"'\`<>=]`,ya=`[^\\s"'>=/]`,D=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,ni=1,po=2,fa=3,li=/-->/g,si=/>/g,B=new RegExp(`>|${mo}(?:(${ya}+)(${mo}*=${mo}*(?:${ka}|("|')|))|$)`,"g"),wa=0,ri=1,ta=2,ci=3,bo=/'/g,Fo=/"/g,gi=/^(?:script|style|textarea|title)$/i,ma=1,lo=2,so=3,Ho=1,ro=2,pa=3,ba=4,Fa=5,Ao=6,Ma=7,Ko=(o)=>(i,...a)=>{if(i.some((n)=>n===void 0))console.warn(`Some template strings are undefined. -This is probably caused by illegal octal escape sequences.`);if(a.some((n)=>n?._$litStatic$))V("",`Static values 'literal' or 'unsafeStatic' cannot be used as values to non-static templates. -Please use the static 'html' tag function. See https://lit.dev/docs/templates/expressions/#static-expressions`);return{["_$litType$"]:o,strings:i,values:a}},k=Ko(ma),y=Ko(lo),ln=Ko(so),C=Symbol.for("lit-noChange"),p=Symbol.for("lit-nothing"),_i=new WeakMap,$=Q.createTreeWalker(Q,129),P=co;function ei(o,i){if(!zo(o)||!o.hasOwnProperty("raw")){let a="invalid template strings array";throw a=` +var __legacyDecorateClassTS = function(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") + r = Reflect.decorate(decorators, target, key, desc); + else + for (var i = decorators.length - 1;i >= 0; i--) + if (d = decorators[i]) + r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; + +// node_modules/@lit/reactive-element/development/css-tag.js +var NODE_MODE = false; +var global = globalThis; +var supportsAdoptingStyleSheets = global.ShadowRoot && (global.ShadyCSS === undefined || global.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype; +var constructionToken = Symbol(); +var cssTagCache = new WeakMap; + +class CSSResult { + constructor(cssText, strings, safeToken) { + this["_$cssResult$"] = true; + if (safeToken !== constructionToken) { + throw new Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead."); + } + this.cssText = cssText; + this._strings = strings; + } + get styleSheet() { + let styleSheet = this._styleSheet; + const strings = this._strings; + if (supportsAdoptingStyleSheets && styleSheet === undefined) { + const cacheable = strings !== undefined && strings.length === 1; + if (cacheable) { + styleSheet = cssTagCache.get(strings); + } + if (styleSheet === undefined) { + (this._styleSheet = styleSheet = new CSSStyleSheet).replaceSync(this.cssText); + if (cacheable) { + cssTagCache.set(strings, styleSheet); + } + } + } + return styleSheet; + } + toString() { + return this.cssText; + } +} +var textFromCSSResult = (value) => { + if (value["_$cssResult$"] === true) { + return value.cssText; + } else if (typeof value === "number") { + return value; + } else { + throw new Error(`Value passed to 'css' function must be a 'css' function result: ` + `${value}. Use 'unsafeCSS' to pass non-literal values, but take care ` + `to ensure page security.`); + } +}; +var unsafeCSS = (value) => new CSSResult(typeof value === "string" ? value : String(value), undefined, constructionToken); +var css = (strings, ...values) => { + const cssText = strings.length === 1 ? strings[0] : values.reduce((acc, v, idx) => acc + textFromCSSResult(v) + strings[idx + 1], strings[0]); + return new CSSResult(cssText, strings, constructionToken); +}; +var adoptStyles = (renderRoot, styles) => { + if (supportsAdoptingStyleSheets) { + renderRoot.adoptedStyleSheets = styles.map((s) => s instanceof CSSStyleSheet ? s : s.styleSheet); + } else { + for (const s of styles) { + const style = document.createElement("style"); + const nonce = global["litNonce"]; + if (nonce !== undefined) { + style.setAttribute("nonce", nonce); + } + style.textContent = s.cssText; + renderRoot.appendChild(style); + } + } +}; +var cssResultFromStyleSheet = (sheet) => { + let cssText = ""; + for (const rule of sheet.cssRules) { + cssText += rule.cssText; + } + return unsafeCSS(cssText); +}; +var getCompatibleStyle = supportsAdoptingStyleSheets || NODE_MODE && global.CSSStyleSheet === undefined ? (s) => s : (s) => s instanceof CSSStyleSheet ? cssResultFromStyleSheet(s) : s; + +// node_modules/@lit/reactive-element/development/reactive-element.js +var { is, defineProperty, getOwnPropertyDescriptor, getOwnPropertyNames, getOwnPropertySymbols, getPrototypeOf } = Object; +var NODE_MODE2 = false; +var global2 = globalThis; +if (NODE_MODE2) { + global2.customElements ??= customElements; +} +var DEV_MODE = true; +var issueWarning; +var trustedTypes = global2.trustedTypes; +var emptyStringForBooleanAttribute = trustedTypes ? trustedTypes.emptyScript : ""; +var polyfillSupport = DEV_MODE ? global2.reactiveElementPolyfillSupportDevMode : global2.reactiveElementPolyfillSupport; +if (DEV_MODE) { + global2.litIssuedWarnings ??= new Set; + issueWarning = (code, warning) => { + warning += ` See https://lit.dev/msg/${code} for more information.`; + if (!global2.litIssuedWarnings.has(warning) && !global2.litIssuedWarnings.has(code)) { + console.warn(warning); + global2.litIssuedWarnings.add(warning); + } + }; + queueMicrotask(() => { + issueWarning("dev-mode", `Lit is in dev mode. Not recommended for production!`); + if (global2.ShadyDOM?.inUse && polyfillSupport === undefined) { + issueWarning("polyfill-support-missing", `Shadow DOM is being polyfilled via \`ShadyDOM\` but ` + `the \`polyfill-support\` module has not been loaded.`); + } + }); +} +var debugLogEvent = DEV_MODE ? (event) => { + const shouldEmit = global2.emitLitDebugLogEvents; + if (!shouldEmit) { + return; + } + global2.dispatchEvent(new CustomEvent("lit-debug", { + detail: event + })); +} : undefined; +var JSCompiler_renameProperty = (prop, _obj) => prop; +var defaultConverter = { + toAttribute(value, type) { + switch (type) { + case Boolean: + value = value ? emptyStringForBooleanAttribute : null; + break; + case Object: + case Array: + value = value == null ? value : JSON.stringify(value); + break; + } + return value; + }, + fromAttribute(value, type) { + let fromValue = value; + switch (type) { + case Boolean: + fromValue = value !== null; + break; + case Number: + fromValue = value === null ? null : Number(value); + break; + case Object: + case Array: + try { + fromValue = JSON.parse(value); + } catch (e) { + fromValue = null; + } + break; + } + return fromValue; + } +}; +var notEqual = (value, old) => !is(value, old); +var defaultPropertyDeclaration = { + attribute: true, + type: String, + converter: defaultConverter, + reflect: false, + useDefault: false, + hasChanged: notEqual +}; +Symbol.metadata ??= Symbol("metadata"); +global2.litPropertyMetadata ??= new WeakMap; + +class ReactiveElement extends HTMLElement { + static addInitializer(initializer) { + this.__prepare(); + (this._initializers ??= []).push(initializer); + } + static get observedAttributes() { + this.finalize(); + return this.__attributeToPropertyMap && [...this.__attributeToPropertyMap.keys()]; + } + static createProperty(name, options = defaultPropertyDeclaration) { + if (options.state) { + options.attribute = false; + } + this.__prepare(); + if (this.prototype.hasOwnProperty(name)) { + options = Object.create(options); + options.wrapped = true; + } + this.elementProperties.set(name, options); + if (!options.noAccessor) { + const key = DEV_MODE ? Symbol.for(`${String(name)} (@property() cache)`) : Symbol(); + const descriptor = this.getPropertyDescriptor(name, key, options); + if (descriptor !== undefined) { + defineProperty(this.prototype, name, descriptor); + } + } + } + static getPropertyDescriptor(name, key, options) { + const { get, set } = getOwnPropertyDescriptor(this.prototype, name) ?? { + get() { + return this[key]; + }, + set(v) { + this[key] = v; + } + }; + if (DEV_MODE && get == null) { + if ("value" in (getOwnPropertyDescriptor(this.prototype, name) ?? {})) { + throw new Error(`Field ${JSON.stringify(String(name))} on ` + `${this.name} was declared as a reactive property ` + `but it's actually declared as a value on the prototype. ` + `Usually this is due to using @property or @state on a method.`); + } + issueWarning("reactive-property-without-getter", `Field ${JSON.stringify(String(name))} on ` + `${this.name} was declared as a reactive property ` + `but it does not have a getter. This will be an error in a ` + `future version of Lit.`); + } + return { + get, + set(value) { + const oldValue = get?.call(this); + set?.call(this, value); + this.requestUpdate(name, oldValue, options); + }, + configurable: true, + enumerable: true + }; + } + static getPropertyOptions(name) { + return this.elementProperties.get(name) ?? defaultPropertyDeclaration; + } + static __prepare() { + if (this.hasOwnProperty(JSCompiler_renameProperty("elementProperties", this))) { + return; + } + const superCtor = getPrototypeOf(this); + superCtor.finalize(); + if (superCtor._initializers !== undefined) { + this._initializers = [...superCtor._initializers]; + } + this.elementProperties = new Map(superCtor.elementProperties); + } + static finalize() { + if (this.hasOwnProperty(JSCompiler_renameProperty("finalized", this))) { + return; + } + this.finalized = true; + this.__prepare(); + if (this.hasOwnProperty(JSCompiler_renameProperty("properties", this))) { + const props = this.properties; + const propKeys = [ + ...getOwnPropertyNames(props), + ...getOwnPropertySymbols(props) + ]; + for (const p of propKeys) { + this.createProperty(p, props[p]); + } + } + const metadata = this[Symbol.metadata]; + if (metadata !== null) { + const properties = litPropertyMetadata.get(metadata); + if (properties !== undefined) { + for (const [p, options] of properties) { + this.elementProperties.set(p, options); + } + } + } + this.__attributeToPropertyMap = new Map; + for (const [p, options] of this.elementProperties) { + const attr = this.__attributeNameForProperty(p, options); + if (attr !== undefined) { + this.__attributeToPropertyMap.set(attr, p); + } + } + this.elementStyles = this.finalizeStyles(this.styles); + if (DEV_MODE) { + if (this.hasOwnProperty("createProperty")) { + issueWarning("no-override-create-property", "Overriding ReactiveElement.createProperty() is deprecated. " + "The override will not be called with standard decorators"); + } + if (this.hasOwnProperty("getPropertyDescriptor")) { + issueWarning("no-override-get-property-descriptor", "Overriding ReactiveElement.getPropertyDescriptor() is deprecated. " + "The override will not be called with standard decorators"); + } + } + } + static finalizeStyles(styles) { + const elementStyles = []; + if (Array.isArray(styles)) { + const set = new Set(styles.flat(Infinity).reverse()); + for (const s of set) { + elementStyles.unshift(getCompatibleStyle(s)); + } + } else if (styles !== undefined) { + elementStyles.push(getCompatibleStyle(styles)); + } + return elementStyles; + } + static __attributeNameForProperty(name, options) { + const attribute = options.attribute; + return attribute === false ? undefined : typeof attribute === "string" ? attribute : typeof name === "string" ? name.toLowerCase() : undefined; + } + constructor() { + super(); + this.__instanceProperties = undefined; + this.isUpdatePending = false; + this.hasUpdated = false; + this.__reflectingProperty = null; + this.__initialize(); + } + __initialize() { + this.__updatePromise = new Promise((res) => this.enableUpdating = res); + this._$changedProperties = new Map; + this.__saveInstanceProperties(); + this.requestUpdate(); + this.constructor._initializers?.forEach((i) => i(this)); + } + addController(controller) { + (this.__controllers ??= new Set).add(controller); + if (this.renderRoot !== undefined && this.isConnected) { + controller.hostConnected?.(); + } + } + removeController(controller) { + this.__controllers?.delete(controller); + } + __saveInstanceProperties() { + const instanceProperties = new Map; + const elementProperties = this.constructor.elementProperties; + for (const p of elementProperties.keys()) { + if (this.hasOwnProperty(p)) { + instanceProperties.set(p, this[p]); + delete this[p]; + } + } + if (instanceProperties.size > 0) { + this.__instanceProperties = instanceProperties; + } + } + createRenderRoot() { + const renderRoot = this.shadowRoot ?? this.attachShadow(this.constructor.shadowRootOptions); + adoptStyles(renderRoot, this.constructor.elementStyles); + return renderRoot; + } + connectedCallback() { + this.renderRoot ??= this.createRenderRoot(); + this.enableUpdating(true); + this.__controllers?.forEach((c) => c.hostConnected?.()); + } + enableUpdating(_requestedUpdate) {} + disconnectedCallback() { + this.__controllers?.forEach((c) => c.hostDisconnected?.()); + } + attributeChangedCallback(name, _old, value) { + this._$attributeToProperty(name, value); + } + __propertyToAttribute(name, value) { + const elemProperties = this.constructor.elementProperties; + const options = elemProperties.get(name); + const attr = this.constructor.__attributeNameForProperty(name, options); + if (attr !== undefined && options.reflect === true) { + const converter = options.converter?.toAttribute !== undefined ? options.converter : defaultConverter; + const attrValue = converter.toAttribute(value, options.type); + if (DEV_MODE && this.constructor.enabledWarnings.includes("migration") && attrValue === undefined) { + issueWarning("undefined-attribute-value", `The attribute value for the ${name} property is ` + `undefined on element ${this.localName}. The attribute will be ` + `removed, but in the previous version of \`ReactiveElement\`, ` + `the attribute would not have changed.`); + } + this.__reflectingProperty = name; + if (attrValue == null) { + this.removeAttribute(attr); + } else { + this.setAttribute(attr, attrValue); + } + this.__reflectingProperty = null; + } + } + _$attributeToProperty(name, value) { + const ctor = this.constructor; + const propName = ctor.__attributeToPropertyMap.get(name); + if (propName !== undefined && this.__reflectingProperty !== propName) { + const options = ctor.getPropertyOptions(propName); + const converter = typeof options.converter === "function" ? { fromAttribute: options.converter } : options.converter?.fromAttribute !== undefined ? options.converter : defaultConverter; + this.__reflectingProperty = propName; + const convertedValue = converter.fromAttribute(value, options.type); + this[propName] = convertedValue ?? this.__defaultValues?.get(propName) ?? convertedValue; + this.__reflectingProperty = null; + } + } + requestUpdate(name, oldValue, options, useNewValue = false, newValue) { + if (name !== undefined) { + if (DEV_MODE && name instanceof Event) { + issueWarning(``, `The requestUpdate() method was called with an Event as the property name. This is probably a mistake caused by binding this.requestUpdate as an event listener. Instead bind a function that will call it with no arguments: () => this.requestUpdate()`); + } + const ctor = this.constructor; + if (useNewValue === false) { + newValue = this[name]; + } + options ??= ctor.getPropertyOptions(name); + const changed = (options.hasChanged ?? notEqual)(newValue, oldValue) || options.useDefault && options.reflect && newValue === this.__defaultValues?.get(name) && !this.hasAttribute(ctor.__attributeNameForProperty(name, options)); + if (changed) { + this._$changeProperty(name, oldValue, options); + } else { + return; + } + } + if (this.isUpdatePending === false) { + this.__updatePromise = this.__enqueueUpdate(); + } + } + _$changeProperty(name, oldValue, { useDefault, reflect, wrapped }, initializeValue) { + if (useDefault && !(this.__defaultValues ??= new Map).has(name)) { + this.__defaultValues.set(name, initializeValue ?? oldValue ?? this[name]); + if (wrapped !== true || initializeValue !== undefined) { + return; + } + } + if (!this._$changedProperties.has(name)) { + if (!this.hasUpdated && !useDefault) { + oldValue = undefined; + } + this._$changedProperties.set(name, oldValue); + } + if (reflect === true && this.__reflectingProperty !== name) { + (this.__reflectingProperties ??= new Set).add(name); + } + } + async __enqueueUpdate() { + this.isUpdatePending = true; + try { + await this.__updatePromise; + } catch (e) { + Promise.reject(e); + } + const result = this.scheduleUpdate(); + if (result != null) { + await result; + } + return !this.isUpdatePending; + } + scheduleUpdate() { + const result = this.performUpdate(); + if (DEV_MODE && this.constructor.enabledWarnings.includes("async-perform-update") && typeof result?.then === "function") { + issueWarning("async-perform-update", `Element ${this.localName} returned a Promise from performUpdate(). ` + `This behavior is deprecated and will be removed in a future ` + `version of ReactiveElement.`); + } + return result; + } + performUpdate() { + if (!this.isUpdatePending) { + return; + } + debugLogEvent?.({ kind: "update" }); + if (!this.hasUpdated) { + this.renderRoot ??= this.createRenderRoot(); + if (DEV_MODE) { + const ctor = this.constructor; + const shadowedProperties = [...ctor.elementProperties.keys()].filter((p) => this.hasOwnProperty(p) && (p in getPrototypeOf(this))); + if (shadowedProperties.length) { + throw new Error(`The following properties on element ${this.localName} will not ` + `trigger updates as expected because they are set using class ` + `fields: ${shadowedProperties.join(", ")}. ` + `Native class fields and some compiled output will overwrite ` + `accessors used for detecting changes. See ` + `https://lit.dev/msg/class-field-shadowing ` + `for more information.`); + } + } + if (this.__instanceProperties) { + for (const [p, value] of this.__instanceProperties) { + this[p] = value; + } + this.__instanceProperties = undefined; + } + const elementProperties = this.constructor.elementProperties; + if (elementProperties.size > 0) { + for (const [p, options] of elementProperties) { + const { wrapped } = options; + const value = this[p]; + if (wrapped === true && !this._$changedProperties.has(p) && value !== undefined) { + this._$changeProperty(p, undefined, options, value); + } + } + } + } + let shouldUpdate = false; + const changedProperties = this._$changedProperties; + try { + shouldUpdate = this.shouldUpdate(changedProperties); + if (shouldUpdate) { + this.willUpdate(changedProperties); + this.__controllers?.forEach((c) => c.hostUpdate?.()); + this.update(changedProperties); + } else { + this.__markUpdated(); + } + } catch (e) { + shouldUpdate = false; + this.__markUpdated(); + throw e; + } + if (shouldUpdate) { + this._$didUpdate(changedProperties); + } + } + willUpdate(_changedProperties) {} + _$didUpdate(changedProperties) { + this.__controllers?.forEach((c) => c.hostUpdated?.()); + if (!this.hasUpdated) { + this.hasUpdated = true; + this.firstUpdated(changedProperties); + } + this.updated(changedProperties); + if (DEV_MODE && this.isUpdatePending && this.constructor.enabledWarnings.includes("change-in-update")) { + issueWarning("change-in-update", `Element ${this.localName} scheduled an update ` + `(generally because a property was set) ` + `after an update completed, causing a new update to be scheduled. ` + `This is inefficient and should be avoided unless the next update ` + `can only be scheduled as a side effect of the previous update.`); + } + } + __markUpdated() { + this._$changedProperties = new Map; + this.isUpdatePending = false; + } + get updateComplete() { + return this.getUpdateComplete(); + } + getUpdateComplete() { + return this.__updatePromise; + } + shouldUpdate(_changedProperties) { + return true; + } + update(_changedProperties) { + this.__reflectingProperties &&= this.__reflectingProperties.forEach((p) => this.__propertyToAttribute(p, this[p])); + this.__markUpdated(); + } + updated(_changedProperties) {} + firstUpdated(_changedProperties) {} +} +ReactiveElement.elementStyles = []; +ReactiveElement.shadowRootOptions = { mode: "open" }; +ReactiveElement[JSCompiler_renameProperty("elementProperties", ReactiveElement)] = new Map; +ReactiveElement[JSCompiler_renameProperty("finalized", ReactiveElement)] = new Map; +polyfillSupport?.({ ReactiveElement }); +if (DEV_MODE) { + ReactiveElement.enabledWarnings = [ + "change-in-update", + "async-perform-update" + ]; + const ensureOwnWarnings = function(ctor) { + if (!ctor.hasOwnProperty(JSCompiler_renameProperty("enabledWarnings", ctor))) { + ctor.enabledWarnings = ctor.enabledWarnings.slice(); + } + }; + ReactiveElement.enableWarning = function(warning) { + ensureOwnWarnings(this); + if (!this.enabledWarnings.includes(warning)) { + this.enabledWarnings.push(warning); + } + }; + ReactiveElement.disableWarning = function(warning) { + ensureOwnWarnings(this); + const i = this.enabledWarnings.indexOf(warning); + if (i >= 0) { + this.enabledWarnings.splice(i, 1); + } + }; +} +(global2.reactiveElementVersions ??= []).push("2.1.2"); +if (DEV_MODE && global2.reactiveElementVersions.length > 1) { + queueMicrotask(() => { + issueWarning("multiple-versions", `Multiple versions of Lit loaded. Loading multiple versions ` + `is not recommended.`); + }); +} + +// node_modules/lit-html/development/lit-html.js +var DEV_MODE2 = true; +var ENABLE_EXTRA_SECURITY_HOOKS = true; +var ENABLE_SHADYDOM_NOPATCH = true; +var NODE_MODE3 = false; +var global3 = globalThis; +var debugLogEvent2 = DEV_MODE2 ? (event) => { + const shouldEmit = global3.emitLitDebugLogEvents; + if (!shouldEmit) { + return; + } + global3.dispatchEvent(new CustomEvent("lit-debug", { + detail: event + })); +} : undefined; +var debugLogRenderId = 0; +var issueWarning2; +if (DEV_MODE2) { + global3.litIssuedWarnings ??= new Set; + issueWarning2 = (code, warning) => { + warning += code ? ` See https://lit.dev/msg/${code} for more information.` : ""; + if (!global3.litIssuedWarnings.has(warning) && !global3.litIssuedWarnings.has(code)) { + console.warn(warning); + global3.litIssuedWarnings.add(warning); + } + }; + queueMicrotask(() => { + issueWarning2("dev-mode", `Lit is in dev mode. Not recommended for production!`); + }); +} +var wrap = ENABLE_SHADYDOM_NOPATCH && global3.ShadyDOM?.inUse && global3.ShadyDOM?.noPatch === true ? global3.ShadyDOM.wrap : (node) => node; +var trustedTypes2 = global3.trustedTypes; +var policy = trustedTypes2 ? trustedTypes2.createPolicy("lit-html", { + createHTML: (s) => s +}) : undefined; +var identityFunction = (value) => value; +var noopSanitizer = (_node, _name, _type) => identityFunction; +var setSanitizer = (newSanitizer) => { + if (!ENABLE_EXTRA_SECURITY_HOOKS) { + return; + } + if (sanitizerFactoryInternal !== noopSanitizer) { + throw new Error(`Attempted to overwrite existing lit-html security policy.` + ` setSanitizeDOMValueFactory should be called at most once.`); + } + sanitizerFactoryInternal = newSanitizer; +}; +var _testOnlyClearSanitizerFactoryDoNotCallOrElse = () => { + sanitizerFactoryInternal = noopSanitizer; +}; +var createSanitizer = (node, name, type) => { + return sanitizerFactoryInternal(node, name, type); +}; +var boundAttributeSuffix = "$lit$"; +var marker = `lit$${Math.random().toFixed(9).slice(2)}$`; +var markerMatch = "?" + marker; +var nodeMarker = `<${markerMatch}>`; +var d = NODE_MODE3 && global3.document === undefined ? { + createTreeWalker() { + return {}; + } +} : document; +var createMarker = () => d.createComment(""); +var isPrimitive = (value) => value === null || typeof value != "object" && typeof value != "function"; +var isArray = Array.isArray; +var isIterable = (value) => isArray(value) || typeof value?.[Symbol.iterator] === "function"; +var SPACE_CHAR = `[ +\f\r]`; +var ATTR_VALUE_CHAR = `[^ +\f\r"'\`<>=]`; +var NAME_CHAR = `[^\\s"'>=/]`; +var textEndRegex = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g; +var COMMENT_START = 1; +var TAG_NAME = 2; +var DYNAMIC_TAG_NAME = 3; +var commentEndRegex = /-->/g; +var comment2EndRegex = />/g; +var tagEndRegex = new RegExp(`>|${SPACE_CHAR}(?:(${NAME_CHAR}+)(${SPACE_CHAR}*=${SPACE_CHAR}*(?:${ATTR_VALUE_CHAR}|("|')|))|$)`, "g"); +var ENTIRE_MATCH = 0; +var ATTRIBUTE_NAME = 1; +var SPACES_AND_EQUALS = 2; +var QUOTE_CHAR = 3; +var singleQuoteAttrEndRegex = /'/g; +var doubleQuoteAttrEndRegex = /"/g; +var rawTextElement = /^(?:script|style|textarea|title)$/i; +var HTML_RESULT = 1; +var SVG_RESULT = 2; +var MATHML_RESULT = 3; +var ATTRIBUTE_PART = 1; +var CHILD_PART = 2; +var PROPERTY_PART = 3; +var BOOLEAN_ATTRIBUTE_PART = 4; +var EVENT_PART = 5; +var ELEMENT_PART = 6; +var COMMENT_PART = 7; +var tag = (type) => (strings, ...values) => { + if (DEV_MODE2 && strings.some((s) => s === undefined)) { + console.warn(`Some template strings are undefined. +` + "This is probably caused by illegal octal escape sequences."); + } + if (DEV_MODE2) { + if (values.some((val) => val?.["_$litStatic$"])) { + issueWarning2("", `Static values 'literal' or 'unsafeStatic' cannot be used as values to non-static templates. +` + `Please use the static 'html' tag function. See https://lit.dev/docs/templates/expressions/#static-expressions`); + } + } + return { + ["_$litType$"]: type, + strings, + values + }; +}; +var html = tag(HTML_RESULT); +var svg = tag(SVG_RESULT); +var mathml = tag(MATHML_RESULT); +var noChange = Symbol.for("lit-noChange"); +var nothing = Symbol.for("lit-nothing"); +var templateCache = new WeakMap; +var walker = d.createTreeWalker(d, 129); +var sanitizerFactoryInternal = noopSanitizer; +function trustFromTemplateString(tsa, stringFromTSA) { + if (!isArray(tsa) || !tsa.hasOwnProperty("raw")) { + let message = "invalid template strings array"; + if (DEV_MODE2) { + message = ` Internal Error: expected template strings to be an array with a 'raw' field. Faking a template strings array by calling html or svg like an ordinary function is effectively @@ -12,8 +688,2635 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex and still seeing this error, please file a bug at https://github.com/lit/lit/issues/new?template=bug_report.md and include information about your build tooling, if any. - `.trim().replace(/\n */g,` -`),Error(a)}return ai!==void 0?ai.createHTML(i):i}var za=(o,i)=>{let a=o.length-1,n=[],l=i===lo?"":i===so?"":"",s,r=D;for(let _=0;_")r=s??D,h=-1;else if(b[ri]===void 0)h=-2;else h=r.lastIndex-b[ta].length,f=b[ri],r=b[ci]===void 0?B:b[ci]==='"'?Fo:bo;else if(r===Fo||r===bo)r=B;else if(r===li||r===si)r=D;else r=B,s=void 0}console.assert(h===-1||r===B||r===bo||r===Fo,"unexpected parse state B");let S=r===B&&o[_+1].startsWith("/>")?" ":"";l+=r===D?g+ea:h>=0?(n.push(f),g.slice(0,h)+di+g.slice(h))+q+S:g+q+(h===-2?_:S)}let c=l+(o[a]||"")+(i===lo?"":i===so?"":"");return[ei(o,c),n]};class X{constructor({strings:o,["_$litType$"]:i},a){this.parts=[];let n,l=0,s=0,r=o.length-1,c=this.parts,[_,g]=za(o,i);if(this.el=X.createElement(_,a),$.currentNode=this.el.content,i===lo||i===so){let h=this.el.content.firstChild;h.replaceWith(...h.childNodes)}while((n=$.nextNode())!==null&&c.length0){n.textContent=no?no.emptyScript:"";for(let m=0;m" contains a duplicate "disabled" attribute. The error was detected in the following template: \n`'+o.join("${...}")+"`");u&&u({kind:"template prep",template:this,clonableTemplate:this.el,parts:this.parts,strings:o})}static createElement(o,i){let a=Q.createElement("template");return a.innerHTML=o,a}}function G(o,i,a=o,n){if(i===C)return i;let l=n!==void 0?a.__directives?.[n]:a.__directive,s=R(i)?void 0:i._$litDirective$;if(l?.constructor!==s){if(l?._$notifyDirectiveConnectionChanged?.(!1),s===void 0)l=void 0;else l=new s(o),l._$initialize(o,a,n);if(n!==void 0)(a.__directives??=[])[n]=l;else a.__directive=l}if(l!==void 0)i=G(o,l._$resolve(o,i.values),l,n);return i}class ui{constructor(o,i){this._$parts=[],this._$disconnectableChildren=void 0,this._$template=o,this._$parent=i}get parentNode(){return this._$parent.parentNode}get _$isConnected(){return this._$parent._$isConnected}_clone(o){let{el:{content:i},parts:a}=this._$template,n=(o?.creationScope??Q).importNode(i,!0);$.currentNode=n;let l=$.nextNode(),s=0,r=0,c=a[0];while(c!==void 0){if(s===c.index){let _;if(c.type===ro)_=new Y(l,l.nextSibling,this,o);else if(c.type===Ho)_=new c.ctor(l,c.name,c.strings,this,o);else if(c.type===Ao)_=new wi(l,this,o);this._$parts.push(_),c=a[++r]}if(s!==c?.index)l=$.nextNode(),s++}return $.currentNode=Q,n}_update(o){let i=0;for(let a of this._$parts){if(a!==void 0)if(u&&u({kind:"set part",part:a,value:o[i],valueIndex:i,values:o,templateInstance:this}),a.strings!==void 0)a._$setValue(o,a,i),i+=a.strings.length-2;else a._$setValue(o[i]);i++}}}class Y{get _$isConnected(){return this._$parent?._$isConnected??this.__isConnected}constructor(o,i,a,n){this.type=ro,this._$committedValue=p,this._$disconnectableChildren=void 0,this._$startNode=o,this._$endNode=i,this._$parent=a,this.options=n,this.__isConnected=n?.isConnected??!0,this._textSanitizer=void 0}get parentNode(){let o=v(this._$startNode).parentNode,i=this._$parent;if(i!==void 0&&o?.nodeType===11)o=i.parentNode;return o}get startNode(){return this._$startNode}get endNode(){return this._$endNode}_$setValue(o,i=this){if(this.parentNode===null)throw Error("This `ChildPart` has no `parentNode` and therefore cannot accept a value. This likely means the element containing the part was manipulated in an unsupported way outside of Lit's control such that the part's marker nodes were ejected from DOM. For example, setting the element's `innerHTML` or `textContent` can do this.");if(o=G(this,o,i),R(o)){if(o===p||o==null||o===""){if(this._$committedValue!==p)u&&u({kind:"commit nothing to child",start:this._$startNode,end:this._$endNode,parent:this._$parent,options:this.options}),this._$clear();this._$committedValue=p}else if(o!==this._$committedValue&&o!==C)this._commitText(o)}else if(o._$litType$!==void 0)this._commitTemplateResult(o);else if(o.nodeType!==void 0){if(this.options?.host===o){this._commitText("[probable mistake: rendered a template's host in itself (commonly caused by writing ${this} in a template]"),console.warn("Attempted to render the template host",o,"inside itself. This is almost always a mistake, and in dev mode ","we render some warning text. In production however, we'll ","render it, which will usually result in an error, and sometimes ","in the element disappearing from the DOM.");return}this._commitNode(o)}else if(ua(o))this._commitIterable(o);else this._commitText(o)}_insert(o){return v(v(this._$startNode).parentNode).insertBefore(o,this._$endNode)}_commitNode(o){if(this._$committedValue!==o){if(this._$clear(),P!==co){let i=this._$startNode.parentNode?.nodeName;if(i==="STYLE"||i==="SCRIPT"){let a="Forbidden";if(i==="STYLE")a="Lit does not support binding inside style nodes. This is a security risk, as style injection attacks can exfiltrate data and spoof UIs. Consider instead using css`...` literals to compose styles, and do dynamic styling with css custom properties, ::parts, s, and by mutating the DOM rather than stylesheets.";else a="Lit does not support binding inside script nodes. This is a security risk, as it could allow arbitrary code execution.";throw Error(a)}}u&&u({kind:"commit node",start:this._$startNode,parent:this._$parent,value:o,options:this.options}),this._$committedValue=this._insert(o)}}_commitText(o){if(this._$committedValue!==p&&R(this._$committedValue)){let i=v(this._$startNode).nextSibling;if(this._textSanitizer===void 0)this._textSanitizer=Mo(i,"data","property");o=this._textSanitizer(o),u&&u({kind:"commit text",node:i,value:o,options:this.options}),i.data=o}else{let i=Q.createTextNode("");if(this._commitNode(i),this._textSanitizer===void 0)this._textSanitizer=Mo(i,"data","property");o=this._textSanitizer(o),u&&u({kind:"commit text",node:i,value:o,options:this.options}),i.data=o}this._$committedValue=o}_commitTemplateResult(o){let{values:i,["_$litType$"]:a}=o,n=typeof a==="number"?this._$getTemplate(o):(a.el===void 0&&(a.el=X.createElement(ei(a.h,a.h[0]),this.options)),a);if(this._$committedValue?._$template===n)u&&u({kind:"template updating",template:n,instance:this._$committedValue,parts:this._$committedValue._$parts,options:this.options,values:i}),this._$committedValue._update(i);else{let l=new ui(n,this),s=l._clone(this.options);u&&u({kind:"template instantiated",template:n,instance:l,parts:l._$parts,options:this.options,fragment:s,values:i}),l._update(i),u&&u({kind:"template instantiated and updated",template:n,instance:l,parts:l._$parts,options:this.options,fragment:s,values:i}),this._commitNode(s),this._$committedValue=l}}_$getTemplate(o){let i=_i.get(o.strings);if(i===void 0)_i.set(o.strings,i=new X(o));return i}_commitIterable(o){if(!zo(this._$committedValue))this._$committedValue=[],this._$clear();let i=this._$committedValue,a=0,n;for(let l of o){if(a===i.length)i.push(n=new Y(this._insert(U()),this._insert(U()),this,this.options));else n=i[a];n._$setValue(l),a++}if(a2||a[0]!==""||a[1]!=="")this._$committedValue=Array(a.length-1).fill(new String),this.strings=a;else this._$committedValue=p;this._sanitizer=void 0}_$setValue(o,i=this,a,n){let l=this.strings,s=!1;if(l===void 0){if(o=G(this,o,i,0),s=!R(o)||o!==this._$committedValue&&o!==C,s)this._$committedValue=o}else{let r=o;o=l[0];let c,_;for(c=0;c\` has a \`@${i}=...\` listener with invalid content. Event listeners in templates must have exactly one expression and no surrounding text.`)}_$setValue(o,i=this){if(o=G(this,o,i,0)??p,o===C)return;let a=this._$committedValue,n=o===p&&a!==p||o.capture!==a.capture||o.once!==a.once||o.passive!==a.passive,l=o!==p&&(a===p||n);if(u&&u({kind:"commit event listener",element:this.element,name:this.name,value:o,options:this.options,removeListener:n,addListener:l,oldListener:a}),n)this.element.removeEventListener(this.name,this,a);if(l)this.element.addEventListener(this.name,this,o);this._$committedValue=o}handleEvent(o){if(typeof this._$committedValue==="function")this._$committedValue.call(this.options?.host??this.element,o);else this._$committedValue.handleEvent(o)}}class wi{constructor(o,i,a){this.element=o,this.type=Ao,this._$disconnectableChildren=void 0,this._$parent=i,this.options=a}get _$isConnected(){return this._$parent._$isConnected}_$setValue(o){u&&u({kind:"commit to element binding",element:this.element,value:o,options:this.options}),G(this,o)}}var Ha=K.litHtmlPolyfillSupportDevMode;Ha?.(X,Y);(K.litHtmlVersions??=[]).push("3.3.2");if(K.litHtmlVersions.length>1)queueMicrotask(()=>{V("multiple-versions","Multiple versions of Lit loaded. Loading multiple versions is not recommended.")});var T=(o,i,a)=>{if(i==null)throw TypeError(`The container to render into may not be ${i}`);let n=_a++,l=a?.renderBefore??i,s=l._$litPart$;if(u&&u({kind:"begin render",id:n,value:o,container:i,options:a,part:s}),s===void 0){let r=a?.renderBefore??null;l._$litPart$=s=new Y(i.insertBefore(U(),r),r,void 0,a??{})}return s._$setValue(o),u&&u({kind:"end render",id:n,value:o,container:i,options:a,part:s}),s};T.setSanitizer=ha,T.createSanitizer=Mo,T._testOnlyClearSanitizerFactoryDoNotCallOrElse=ga;var Aa=(o,i)=>o,Zo=!0,J=globalThis,ti;if(Zo)J.litIssuedWarnings??=new Set,ti=(o,i)=>{if(i+=` See https://lit.dev/msg/${o} for more information.`,!J.litIssuedWarnings.has(i)&&!J.litIssuedWarnings.has(o))console.warn(i),J.litIssuedWarnings.add(i)};class F extends A{constructor(){super(...arguments);this.renderOptions={host:this},this.__childPart=void 0}createRenderRoot(){let o=super.createRenderRoot();return this.renderOptions.renderBefore??=o.firstChild,o}update(o){let i=this.render();if(!this.hasUpdated)this.renderOptions.isConnected=this.isConnected;super.update(o),this.__childPart=T(i,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this.__childPart?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this.__childPart?.setConnected(!1)}render(){return C}}F._$litElement$=!0;F[Aa("finalized",F)]=!0;J.litElementHydrateSupport?.({LitElement:F});var Ka=Zo?J.litElementPolyfillSupportDevMode:J.litElementPolyfillSupport;Ka?.({LitElement:F});(J.litElementVersions??=[]).push("4.2.2");if(Zo&&J.litElementVersions.length>1)queueMicrotask(()=>{ti("multiple-versions","Multiple versions of Lit loaded. Loading multiple versions is not recommended.")});var mi=!0,pi;if(mi)globalThis.litIssuedWarnings??=new Set,pi=(o,i)=>{if(i+=` See https://lit.dev/msg/${o} for more information.`,!globalThis.litIssuedWarnings.has(i)&&!globalThis.litIssuedWarnings.has(o))console.warn(i),globalThis.litIssuedWarnings.add(i)};var Za=(o,i,a)=>{let n=i.hasOwnProperty(a);return i.constructor.createProperty(a,o),n?Object.getOwnPropertyDescriptor(i,a):void 0},va={attribute:!0,type:String,converter:j,reflect:!1,hasChanged:ao},Na=(o=va,i,a)=>{let{kind:n,metadata:l}=a;if(mi&&l==null)pi("missing-class-metadata",`The class ${i} is missing decorator metadata. This could mean that you're using a compiler that supports decorators but doesn't support decorator metadata, such as TypeScript 5.1. Please update your compiler.`);let s=globalThis.litPropertyMetadata.get(l);if(s===void 0)globalThis.litPropertyMetadata.set(l,s=new Map);if(n==="setter")o=Object.create(o),o.wrapped=!0;if(s.set(a.name,o),n==="accessor"){let{name:r}=a;return{set(c){let _=i.get.call(this);i.set.call(this,c),this.requestUpdate(r,_,o,!0,c)},init(c){if(c!==void 0)this._$changeProperty(r,void 0,o,c);return c}}}else if(n==="setter"){let{name:r}=a;return function(c){let _=this[r];i.call(this,c),this.requestUpdate(r,_,o,!0,c)}}throw Error(`Unsupported decorator location: ${n}`)};function t(o){return(i,a)=>{return typeof a==="object"?Na(o,i,a):Za(o,i,a)}}function _o(o){return t({...o,state:!0,attribute:!1})}var Sa=!0,qa;if(Sa)globalThis.litIssuedWarnings??=new Set,qa=(o,i)=>{if(i+=o?` See https://lit.dev/msg/${o} for more information.`:"",!globalThis.litIssuedWarnings.has(i)&&!globalThis.litIssuedWarnings.has(o))console.warn(i),globalThis.litIssuedWarnings.add(i)};var bi="0.5.2",N={SUNRISE_START:360,SUNRISE_END:480,DAY_END:1080,SUNSET_END:1200},Fi=["templow","temperature_low","temp_low","min_temp","yandex_pogoda_minimal_forecast_temperature"],e={showFeelsLike:!0,showWind:!1,showWindGust:!1,showWindDirection:!1,showHumidity:!1,showMinTemp:!0,showForecast:!1,showHourlyForecast:!1,showDailyForecast:!1,hourlyForecastHours:5,dailyForecastDays:5,showSunriseSunset:!1,showClock:!1,clockPosition:"top",clockFormat:"24h",overlayOpacity:0.1,language:"auto",height:null,windSpeedUnit:"ms"};var Mi={sunny:"Солнечно",clear:"Ясно",overcast:"Пасмурно",cloudy:"Облачно",partlycloudy:"Переменная облачность",rainy:"Дождь",rain:"Дождь",snowy:"Снег",snow:"Снег",foggy:"Туман",fog:"Туман",lightning:"Гроза","lightning-rainy":"Гроза с дождем",pouring:"Сильный дождь","snowy-rainy":"Мокрый снег",hail:"Град","clear-night":"Ясная ночь",feels_like:"Ощущается как",forecast_title:"Прогноз на сегодня",daily_forecast_title:"Ежедневный прогноз",no_data:"Нет данных",forecast_unavailable:"Прогноз недоступен",weather:"Погода",language:"Language",wind_unit_kmh:"км/ч",wind_unit_ms:"м/с",wind_unit_mph:"миль/ч",wind_unit_knots:"узлы",wind_unit_fts:"фут/с",show_clock:"Показывать часы",am:"ДП",pm:"ПП",editor:{entity:"Погодная сущность",name:"Название карточки",height:"Высота карточки",show_feels_like:"Показывать ощущаемую температуру",show_wind:"Показывать скорость ветра",show_wind_gust:"Показывать порывы ветра",show_wind_direction:"Показывать направление ветра",show_humidity:"Показывать влажность",show_min_temp:"Показывать минимальную температуру",show_hourly_forecast:"Показывать почасовой прогноз",hourly_forecast_hours:"Часы прогноза",show_daily_forecast:"Показывать дневной прогноз",daily_forecast_days:"Дни прогноза",show_sunrise_sunset:"Показывать восход/закат",sunrise_entity:"Сущность восхода",sunset_entity:"Сущность заката",show_clock:"Показывать часы",clock_position:"Позиция часов",clock_position_top:"Вверху",clock_position_details:"Детали",clock_format:"Формат времени",clock_format_12h:"12-часовой (AM/PM)",clock_format_24h:"24-часовой",overlay_opacity:"Прозрачность подложки",language:"Язык",language_auto:"Авто",language_en:"Английский",language_ru:"Русский",language_de:"Немецкий",language_nl:"Нидерландский",language_fr:"Французский",language_es:"Испанский",language_it:"Итальянский",language_sk:"Словацкий",language_hu:"Венгерский",wind_speed_unit:"Единицы скорости ветра",wind_speed_unit_ms:"м/с",wind_speed_unit_kmh:"км/ч"},demo:{pageTitle:"Динамическая карточка погоды",pageSubtitle:"Интерактивная демонстрация и настройка",livePreview:"Предпросмотр",configuration:"Конфигурация",quickPresets:"Быстрые пресеты",sunnyDay:"Солнечный день",rainy:"Дождь",snowy:"Снег",clearNight:"Ясная ночь",weatherCondition:"Погодные условия",condition:"Состояние",temperature:"Температура",humidity:"Влажность (%)",windSpeed:"Скорость ветра",timeOfDay:"Время суток",timeMode:"Режим времени",autoTime:"Авто (текущее время)",manualControl:"Ручное управление",sunrise:"Восход",day:"День",sunset:"Закат",night:"Ночь",currentTime:"Текущее время",displayOptions:"Опции отображения",cardName:"Название карточки",height:"Высота (px)",feelsLike:"Ощущается как",minTemp:"Мин. температура",windDirection:"Направление ветра",windGust:"Порывы ветра",hourlyForecast:"Почасовой прогноз",dailyForecast:"Ежедневный прогноз",sunriseSunset:"Восход/Закат",showClock:"Часы",clockPosition:"Позиция часов",clockPositionTop:"Вверху справа",clockPositionDetails:"В строке деталей",clockFormat:"Формат часов",clockFormat12h:"12-часовой (AM/PM)",clockFormat24h:"24-часовой",overlayOpacity:"Прозрачность подложки (0-1)",windSpeedUnit:"Единицы скорости ветра",dailyForecastDays:"Дни прогноза",hourlyForecastHours:"Часы прогноза",updateCard:"Обновить карточку",startDemo:"Запустить демо",stopDemo:"Остановить демо",madeWith:"Сделано с любовью для Home Assistant",loading:"Загрузка карточки...",errorTitle:"Не удалось загрузить карточку",errorDetails:"Проверьте консоль браузера (F12) для деталей",errorServer:"Убедитесь, что файл открыт через локальный сервер (не file://)",placeholderEmpty:"Оставьте пустым, чтобы скрыть",weatherConditions:{sunny:"Солнечно",clear:"Ясно",clearNight:"Ясная ночь",partlyCloudy:"Переменная облачность",cloudy:"Облачно",rainy:"Дождь",pouring:"Ливень",snowy:"Снег",sleet:"Мокрый снег",hail:"Град",foggy:"Туман",lightning:"Гроза",thunderstorm:"Гроза с дождем"},language:{title:"Язык",english:"English",russian:"Русский",french:"Français",german:"Deutsch",dutch:"Nederlands",spanish:"Español",italian:"Italiano",slovak:"Slovenčina",hungarian:"Magyar"}}};var zi={sunny:"Sonnig",clear:"Klar",overcast:"Bedeckt",cloudy:"Bewölkt",partlycloudy:"Teilweise bewölkt",rainy:"Regnerisch",rain:"Regen",snowy:"Schneefall",snow:"Schnee",foggy:"Nebelig",fog:"Nebel",lightning:"Blitz","lightning-rainy":"Gewitter",pouring:"Starkregen","snowy-rainy":"Schneeregen",hail:"Hagel","clear-night":"Klare Nacht",feels_like:"Gefühlt",forecast_title:"Heutige Vorhersage",daily_forecast_title:"Tagesvorhersage",no_data:"Keine Daten",forecast_unavailable:"Vorhersage nicht verfügbar",weather:"Wetter",language:"Sprache",wind_unit_kmh:"km/h",wind_unit_ms:"m/s",wind_unit_mph:"mph",wind_unit_knots:"Knoten",wind_unit_fts:"ft/s",show_clock:"Aktuelle Uhrzeit anzeigen",am:"AM",pm:"PM",editor:{entity:"Wetter-Entität",name:"Kartentitel",height:"Kartenhöhe",show_feels_like:"Gefühlte Temperatur anzeigen",show_wind:"Windgeschwindigkeit anzeigen",show_wind_gust:"Windböen anzeigen",show_wind_direction:"Windrichtung anzeigen",show_humidity:"Luftfeuchtigkeit anzeigen",show_min_temp:"Mindesttemperatur anzeigen",show_hourly_forecast:"Stundenprognose anzeigen",hourly_forecast_hours:"Stunden der Prognose",show_daily_forecast:"Tagesprognose anzeigen",daily_forecast_days:"Tage der Prognose",show_sunrise_sunset:"Sonnenaufgang/Sonnenuntergang anzeigen",sunrise_entity:"Sonnenaufgang-Entität",sunset_entity:"Sonnenuntergang-Entität",show_clock:"Uhr anzeigen",clock_position:"Uhrposition",clock_position_top:"Oben",clock_position_details:"Details",clock_format:"Zeitformat",clock_format_12h:"12-Stunden (AM/PM)",clock_format_24h:"24-Stunden",overlay_opacity:"Überlagerungs-Transparenz",language:"Sprache",language_auto:"Automatisch",language_en:"Englisch",language_ru:"Russisch",language_de:"Deutsch",language_nl:"Niederländisch",language_fr:"Französisch",language_es:"Spanisch",language_it:"Italienisch",language_sk:"Slowakisch",language_hu:"Ungarisch",wind_speed_unit:"Einheit der Windgeschwindigkeit",wind_speed_unit_ms:"m/s",wind_speed_unit_kmh:"km/h"},demo:{pageTitle:"Dynamische Wetterkarte",pageSubtitle:"Interaktive Demo & Konfiguration",livePreview:"Live-Vorschau",configuration:"Konfiguration",quickPresets:"Schnellvorlagen",sunnyDay:"Sonniger Tag",rainy:"Regnerisch",snowy:"Schnee",clearNight:"Klare Nacht",weatherCondition:"Wetterbedingungen",condition:"Zustand",temperature:"Temperatur",humidity:"Luftfeuchtigkeit (%)",windSpeed:"Windgeschwindigkeit",timeOfDay:"Tageszeit",timeMode:"Zeitmodus",autoTime:"Automatisch (Aktuelle Zeit)",manualControl:"Manuelle Steuerung",sunrise:"Sonnenaufgang",day:"Tag",sunset:"Sonnenuntergang",night:"Nacht",currentTime:"Aktuelle Zeit",displayOptions:"Anzeigeoptionen",cardName:"Kartenname",height:"Höhe (px)",feelsLike:"Gefühlte Temperatur",minTemp:"Mindesttemperatur",windDirection:"Windrichtung",windGust:"Windböen",hourlyForecast:"Stündliche Vorhersage",dailyForecast:"Tägliche Vorhersage",sunriseSunset:"Sonnenaufgang / Sonnenuntergang",showClock:"Uhr",clockPosition:"Uhrposition",clockPositionTop:"Oben rechts",clockPositionDetails:"Detailzeile",clockFormat:"Uhrzeitformat",clockFormat12h:"12-Stunden (AM/PM)",clockFormat24h:"24-Stunden",overlayOpacity:"Überlagerungs-Transparenz (0-1)",windSpeedUnit:"Windgeschwindigkeitseinheit",dailyForecastDays:"Tage der Prognose",hourlyForecastHours:"Stunden der Prognose",updateCard:"Karte aktualisieren",startDemo:"Demo starten",stopDemo:"Demo stoppen",madeWith:"Mit Liebe für Home Assistant gemacht",loading:"Karte wird geladen...",errorTitle:"Karte konnte nicht geladen werden",errorDetails:"Überprüfe die Browser-Konsole (F12) für Details",errorServer:"Stelle sicher, dass die Datei über einen lokalen Server geladen wird (nicht file://)",placeholderEmpty:"Leer lassen, um auszublenden",weatherConditions:{sunny:"Sonnig",clear:"Klar",clearNight:"Klare Nacht",partlyCloudy:"Teilweise bewölkt",cloudy:"Bewölkt",rainy:"Regen",pouring:"Starkregen",snowy:"Schnee",sleet:"Schneeregen",hail:"Hagel",foggy:"Nebel",lightning:"Blitz",thunderstorm:"Gewitter"},language:{title:"Sprache",english:"English",russian:"Русский",french:"Français",german:"Deutsch",dutch:"Nederlands",spanish:"Español",italian:"Italiano",slovak:"Slovenčina",hungarian:"Magyar"}}};var Hi={sunny:"Zonnig",clear:"Helder",overcast:"Bewolkt",cloudy:"Bewolkt",partlycloudy:"Gedeeltelijk bewolkt",rainy:"Regenachtig",rain:"Regen",snowy:"Sneeuwachtig",snow:"Sneeuw",foggy:"Mistig",fog:"Mist",lightning:"Bliksem","lightning-rainy":"Onweersbui",pouring:"Zware regen","snowy-rainy":"Natte sneeuw",hail:"Hagel","clear-night":"Heldere nacht",feels_like:"Gevoelstemperatuur",forecast_title:"Voorspelling van vandaag",daily_forecast_title:"Dagelijkse voorspelling",no_data:"Geen gegevens",forecast_unavailable:"Voorspelling niet beschikbaar",weather:"Weer",language:"Taal",wind_unit_kmh:"km/u",wind_unit_ms:"m/s",wind_unit_mph:"mph",wind_unit_knots:"knots",wind_unit_fts:"ft/s",show_clock:"Huidige tijd weergeven",am:"AM",pm:"PM",editor:{entity:"Weer-entiteit",name:"Kaarttitel",height:"Kaart hoogte",show_feels_like:"Gevoelstemperatuur tonen",show_wind:"Windsnelheid tonen",show_wind_gust:"Windstoten tonen",show_wind_direction:"Windrichting tonen",show_humidity:"Luchtvochtigheid tonen",show_min_temp:"Minimumtemperatuur tonen",show_hourly_forecast:"Uurverwachting tonen",hourly_forecast_hours:"Aantal uren",show_daily_forecast:"Dagverwachting tonen",daily_forecast_days:"Aantal dagen",show_sunrise_sunset:"Zonsopgang/zonsondergang tonen",sunrise_entity:"Zonsopgang-entiteit",sunset_entity:"Zonsondergang-entiteit",show_clock:"Klok tonen",clock_position:"Klokpositie",clock_position_top:"Boven",clock_position_details:"Details",clock_format:"Tijdformaat",clock_format_12h:"12-uurs (AM/PM)",clock_format_24h:"24-uurs",overlay_opacity:"Overlay-doorzichtigheid",language:"Taal",language_auto:"Automatisch",language_en:"Engels",language_ru:"Russisch",language_de:"Duits",language_nl:"Nederlands",language_fr:"Frans",language_es:"Spaans",language_it:"Italiaans",language_sk:"Slowaaks",language_hu:"Hongaars",wind_speed_unit:"Windsnelheidseenheid",wind_speed_unit_ms:"m/s",wind_speed_unit_kmh:"km/u"},demo:{pageTitle:"Dynamische Weerkaart",pageSubtitle:"Interactieve demo & configuratietool",livePreview:"Live voorbeeld",configuration:"Configuratie",quickPresets:"Snelle presets",sunnyDay:"Zonnige dag",rainy:"Regen",snowy:"Sneeuw",clearNight:"Heldere nacht",weatherCondition:"Weersomstandigheden",condition:"Conditie",temperature:"Temperatuur",humidity:"Luchtvochtigheid (%)",windSpeed:"Windsnelheid",timeOfDay:"Tijd van de dag",timeMode:"Tijdmodus",autoTime:"Automatisch (huidige tijd)",manualControl:"Handmatige bediening",sunrise:"Zonsopgang",day:"Dag",sunset:"Zonsondergang",night:"Nacht",currentTime:"Huidige tijd",displayOptions:"Weergaveopties",cardName:"Kaartnaam",height:"Hoogte (px)",feelsLike:"Gevoelstemperatuur",minTemp:"Minimumtemperatuur",windDirection:"Windrichting",windGust:"Windstoten",hourlyForecast:"Uurlijkse voorspelling",dailyForecast:"Dagelijkse voorspelling",sunriseSunset:"Zonsopgang / Zonsondergang",showClock:"Klok",clockPosition:"Klokpositie",clockPositionTop:"Rechtsboven",clockPositionDetails:"Detailregel",clockFormat:"Klokformaat",clockFormat12h:"12-uurs (AM/PM)",clockFormat24h:"24-uurs",overlayOpacity:"Overlay-transparantie (0-1)",windSpeedUnit:"Windsnelheidseenheid",dailyForecastDays:"Voorspellingsdagen",hourlyForecastHours:"Voorspellingsuren",updateCard:"Kaart bijwerken",startDemo:"Demo starten",stopDemo:"Demo stoppen",madeWith:"Gemaakt met liefde voor Home Assistant",loading:"Kaart laden...",errorTitle:"Kan kaart niet laden",errorDetails:"Controleer de browserconsole (F12) voor details",errorServer:"Zorg ervoor dat het bestand via een lokale server wordt geladen (niet file://)",placeholderEmpty:"Leeg laten om te verbergen",weatherConditions:{sunny:"Zonnig",clear:"Helder",clearNight:"Heldere nacht",partlyCloudy:"Gedeeltelijk bewolkt",cloudy:"Bewolkt",rainy:"Regen",pouring:"Zware regen",snowy:"Sneeuw",sleet:"Natte sneeuw",hail:"Hagel",foggy:"Mist",lightning:"Bliksem",thunderstorm:"Onweer"},language:{title:"Taal",english:"English",russian:"Русский",french:"Français",german:"Deutsch",dutch:"Nederlands",spanish:"Español",italian:"Italiano",slovak:"Slovenčina",hungarian:"Magyar"}}};var Ai={sunny:"Ensoleillé",clear:"Dégagé",overcast:"Couvert",cloudy:"Nuageux",partlycloudy:"Partiellement nuageux",rainy:"Pluvieux",rain:"Pluie",snowy:"Neigeux",snow:"Neige",foggy:"Brumeux",fog:"Brouillard",lightning:"Éclairs","lightning-rainy":"Orage",pouring:"Forte pluie","snowy-rainy":"Neige fondue",hail:"Grêle","clear-night":"Nuit claire",feels_like:"Ressenti",forecast_title:"Prévisions du jour",daily_forecast_title:"Prévisions quotidiennes",no_data:"Aucune donnée",forecast_unavailable:"Prévisions non disponibles",weather:"Météo",language:"Langue",wind_unit_kmh:"km/h",wind_unit_ms:"m/s",wind_unit_mph:"mph",wind_unit_knots:"knots",wind_unit_fts:"ft/s",show_clock:"Afficher l'heure actuelle",am:"AM",pm:"PM",editor:{entity:"Entité météo",name:"Titre de la carte",height:"Hauteur de la carte",show_feels_like:"Afficher le ressenti",show_wind:"Afficher la vitesse du vent",show_wind_gust:"Afficher les rafales",show_wind_direction:"Afficher la direction du vent",show_humidity:"Afficher l'humidité",show_min_temp:"Afficher la température minimale",show_hourly_forecast:"Afficher la prévision horaire",hourly_forecast_hours:"Heures de prévision",show_daily_forecast:"Afficher la prévision quotidienne",daily_forecast_days:"Jours de prévision",show_sunrise_sunset:"Afficher lever/coucher du soleil",sunrise_entity:"Entité de lever du soleil",sunset_entity:"Entité de coucher du soleil",show_clock:"Afficher l'horloge",clock_position:"Position de l'horloge",clock_position_top:"En haut",clock_position_details:"Détails",clock_format:"Format de l'heure",clock_format_12h:"12 heures (AM/PM)",clock_format_24h:"24 heures",overlay_opacity:"Opacité du voile",language:"Langue",language_auto:"Auto",language_en:"Anglais",language_ru:"Russe",language_de:"Allemand",language_nl:"Néerlandais",language_fr:"Français",language_es:"Espagnol",language_it:"Italien",language_sk:"Slovaque",language_hu:"Hongrois",wind_speed_unit:"Unité de vitesse du vent",wind_speed_unit_ms:"m/s",wind_speed_unit_kmh:"km/h"},demo:{pageTitle:"Carte Météo Dynamique",pageSubtitle:"Démo Interactive & Outil de Configuration",livePreview:"Aperçu en direct",configuration:"Configuration",quickPresets:"Pré-réglages rapides",sunnyDay:"Journée ensoleillée",rainy:"Pluvieux",snowy:"Neigeux",clearNight:"Nuit claire",weatherCondition:"Condition météo",condition:"Condition",temperature:"Température",humidity:"Humidité (%)",windSpeed:"Vitesse du vent",timeOfDay:"Moment de la journée",timeMode:"Mode horaire",autoTime:"Auto (heure actuelle)",manualControl:"Contrôle manuel",sunrise:"Lever du soleil",day:"Jour",sunset:"Coucher du soleil",night:"Nuit",currentTime:"Heure actuelle",displayOptions:"Options d'affichage",cardName:"Nom de la carte",height:"Hauteur (px)",feelsLike:"Température ressentie",minTemp:"Température minimale",windDirection:"Direction du vent",windGust:"Rafales de vent",hourlyForecast:"Prévisions horaires",dailyForecast:"Prévisions quotidiennes",sunriseSunset:"Lever/Coucher du soleil",showClock:"Horloge",clockPosition:"Position de l'horloge",clockPositionTop:"En haut à droite",clockPositionDetails:"Ligne de détails",clockFormat:"Format de l'horloge",clockFormat12h:"12 heures (AM/PM)",clockFormat24h:"24 heures",overlayOpacity:"Opacité du voile (0-1)",windSpeedUnit:"Unité de vitesse du vent",dailyForecastDays:"Jours de prévision",hourlyForecastHours:"Heures de prévision",updateCard:"Mettre à jour la carte",startDemo:"Démarrer le mode démo",stopDemo:"Arrêter la démo",madeWith:"Fait avec amour pour Home Assistant",loading:"Chargement de la carte...",errorTitle:"Échec du chargement de la carte",errorDetails:"Vérifiez la console du navigateur (F12) pour plus de détails",errorServer:"Assurez-vous que le fichier est servi via un serveur local (pas file://)",placeholderEmpty:"Laisser vide pour masquer",weatherConditions:{sunny:"Ensoleillé",clear:"Dégagé",clearNight:"Nuit claire",partlyCloudy:"Partiellement nuageux",cloudy:"Nuageux",rainy:"Pluvieux",pouring:"Forte pluie",snowy:"Neigeux",sleet:"Neige fondue",hail:"Grêle",foggy:"Brumeux",lightning:"Éclairs",thunderstorm:"Orage"},language:{title:"Langue",english:"English",russian:"Русский",french:"Français",german:"Deutsch",dutch:"Nederlands",spanish:"Español",italian:"Italiano",slovak:"Slovenčina",hungarian:"Magyar"}}};var Ki={sunny:"Sunny",clear:"Clear",overcast:"Overcast",cloudy:"Cloudy",partlycloudy:"Partly Cloudy",rainy:"Rainy",rain:"Rain",snowy:"Snowy",snow:"Snow",foggy:"Foggy",fog:"Fog",lightning:"Lightning","lightning-rainy":"Thunderstorm",pouring:"Heavy Rain","snowy-rainy":"Sleet",hail:"Hail","clear-night":"Clear Night",feels_like:"Feels like",forecast_title:"Today's Forecast",daily_forecast_title:"Daily's Forecast",no_data:"No data",forecast_unavailable:"Forecast unavailable",weather:"Weather",language:"Language",wind_unit_kmh:"km/h",wind_unit_ms:"m/s",wind_unit_mph:"mph",wind_unit_knots:"knots",wind_unit_fts:"ft/s",show_clock:"Show current time",am:"AM",pm:"PM",editor:{entity:"Weather Entity",name:"Card Title",height:"Card Height",show_feels_like:"Show Feels Like",show_wind:"Show Wind Speed",show_wind_gust:"Show Wind Gust",show_wind_direction:"Show Wind Direction",show_humidity:"Show Humidity",show_min_temp:"Show Min Temperature",show_hourly_forecast:"Show Hourly Forecast",hourly_forecast_hours:"Hourly Forecast Hours",show_daily_forecast:"Show Daily Forecast",daily_forecast_days:"Daily Forecast Days",show_sunrise_sunset:"Show Sunrise/Sunset",sunrise_entity:"Sunrise Entity",sunset_entity:"Sunset Entity",show_clock:"Show Clock",clock_position:"Clock Position",clock_position_top:"Top",clock_position_details:"Details",clock_format:"Clock Format",clock_format_12h:"12-hour (AM/PM)",clock_format_24h:"24-hour",overlay_opacity:"Overlay Opacity",language:"Language",language_auto:"Auto",language_en:"English",language_ru:"Russian",language_de:"German",language_nl:"Dutch",language_fr:"French",language_es:"Spanish",language_it:"Italian",language_sk:"Slovak",language_hu:"Hungarian",wind_speed_unit:"Wind Speed Unit",wind_speed_unit_ms:"m/s",wind_speed_unit_kmh:"km/h"},demo:{pageTitle:"Dynamic Weather Card",pageSubtitle:"Interactive Demo & Configuration Tool",livePreview:"Live Preview",configuration:"Configuration",quickPresets:"Quick Presets",sunnyDay:"Sunny Day",rainy:"Rainy",snowy:"Snowy",clearNight:"Clear Night",weatherCondition:"Weather Condition",condition:"Condition",temperature:"Temperature",humidity:"Humidity (%)",windSpeed:"Wind Speed",timeOfDay:"Time of Day",timeMode:"Time Mode",autoTime:"Auto (Current Time)",manualControl:"Manual Control",sunrise:"Sunrise",day:"Day",sunset:"Sunset",night:"Night",currentTime:"Current Time",displayOptions:"Display Options",cardName:"Card Name",height:"Height (px)",feelsLike:"Feels Like Temperature",minTemp:"Min Temperature",windDirection:"Wind Direction",windGust:"Wind Gust",hourlyForecast:"Hourly Forecast",dailyForecast:"Daily Forecast",sunriseSunset:"Sunrise/Sunset",showClock:"Clock",clockPosition:"Clock Position",clockPositionTop:"Top right",clockPositionDetails:"Details row",clockFormat:"Clock Format",clockFormat12h:"12-hour (AM/PM)",clockFormat24h:"24-hour",overlayOpacity:"Overlay Opacity (0-1)",windSpeedUnit:"Wind Speed Unit",dailyForecastDays:"Daily Forecast Days",hourlyForecastHours:"Hourly Forecast Hours",updateCard:"Update Card",startDemo:"Start Demo Mode",stopDemo:"Stop Demo",madeWith:"Made with love for Home Assistant",loading:"Loading card...",errorTitle:"Failed to load card",errorDetails:"Check the browser console (F12) for details",errorServer:"Make sure the file is served via a local server (not file://)",placeholderEmpty:"Leave empty to hide",weatherConditions:{sunny:"Sunny",clear:"Clear",clearNight:"Clear Night",partlyCloudy:"Partly Cloudy",cloudy:"Cloudy",rainy:"Rainy",pouring:"Pouring",snowy:"Snowy",sleet:"Sleet",hail:"Hail",foggy:"Foggy",lightning:"Lightning",thunderstorm:"Thunderstorm"},language:{title:"Language",english:"English",russian:"Russian",french:"French",german:"German",dutch:"Dutch",spanish:"Spanish",italian:"Italian",slovak:"Slovak",hungarian:"Magyar"}}};var Zi={sunny:"Soleado",clear:"Despejado",overcast:"Cubierto",cloudy:"Nublado",partlycloudy:"Parcialmente Nublado",rainy:"Lluvioso",rain:"Lluvia",snowy:"Nevado",snow:"Nieve",foggy:"Nublado",fog:"Niebla",lightning:"Rayo","lightning-rainy":"Tormenta Eléctrica",pouring:"Lluvia Intensa","snowy-rainy":"Aguanieve",hail:"Granizo","clear-night":"Noche Despejada",feels_like:"Sensación térmica",forecast_title:"Previsión para hoy",daily_forecast_title:"Previsión Diaria",no_data:"Sin datos",forecast_unavailable:"Previsión no disponible",weather:"Clima",language:"Idioma",wind_unit_kmh:"km/h",wind_unit_ms:"m/s",wind_unit_mph:"mph",wind_unit_knots:"knots",wind_unit_fts:"ft/s",show_clock:"Mostrar hora actual",am:"AM",pm:"PM",editor:{entity:"Entidad de clima",name:"Título de la tarjeta",height:"Altura de la tarjeta",show_feels_like:"Mostrar sensación térmica",show_wind:"Mostrar velocidad del viento",show_wind_gust:"Mostrar ráfaga de viento",show_wind_direction:"Mostrar dirección del viento",show_humidity:"Mostrar humedad",show_min_temp:"Mostrar temperatura mínima",show_hourly_forecast:"Mostrar pronóstico por horas",hourly_forecast_hours:"Horas del pronóstico",show_daily_forecast:"Mostrar pronóstico diario",daily_forecast_days:"Días del pronóstico",show_sunrise_sunset:"Mostrar amanecer/atardecer",sunrise_entity:"Entidad de amanecer",sunset_entity:"Entidad de atardecer",show_clock:"Mostrar reloj",clock_position:"Posición del reloj",clock_position_top:"Arriba",clock_position_details:"Detalles",clock_format:"Formato de hora",clock_format_12h:"12 horas (AM/PM)",clock_format_24h:"24 horas",overlay_opacity:"Opacidad de superposición",language:"Idioma",language_auto:"Automático",language_en:"Inglés",language_ru:"Ruso",language_de:"Alemán",language_nl:"Neerlandés",language_fr:"Francés",language_es:"Español",language_it:"Italiano",language_sk:"Eslovaco",language_hu:"Húngaro",wind_speed_unit:"Unidad de velocidad del viento",wind_speed_unit_ms:"m/s",wind_speed_unit_kmh:"km/h"},demo:{pageTitle:"Tarjeta Meteorológica Dinámica",pageSubtitle:"Demostración interactiva y Herramienta de Configuración",livePreview:"Vista previa en vivo",configuration:"Configuración",quickPresets:"Ajustes Rápidos",sunnyDay:"Día soleado",rainy:"Lluvioso",snowy:"Nevado",clearNight:"Noche despejada",weatherCondition:"Condiciones Meteorológicas",condition:"Condición",temperature:"Temperatura",humidity:"Humedad (%)",windSpeed:"Velocidad del Viento",timeOfDay:"Hora del Día",timeMode:"Modo Tiempo",autoTime:"Auto (Hora Actual)",manualControl:"Control Manual",sunrise:"Amanecer",day:"Día",sunset:"Atardecer",night:"Noche",currentTime:"Hora Actual",displayOptions:"Opciones de Visualización",cardName:"Nombre de la tarjeta",height:"Altura (px)",feelsLike:"Sensación Térmica",minTemp:"Temperatura Mínima",windDirection:"Dirección del Viento",windGust:"Ráfaga de Viento",hourlyForecast:"Previsión por Horas",dailyForecast:"Previsión Diaria",sunriseSunset:"Amanecer/Atardecer",showClock:"Reloj",clockPosition:"Posición del Reloj",clockPositionTop:"Arriba a la derecha",clockPositionDetails:"Línea de detalles",clockFormat:"Formato del Reloj",clockFormat12h:"12 horas (AM/PM)",clockFormat24h:"24 horas",overlayOpacity:"Opacidad de Superposición (0-1)",windSpeedUnit:"Unidad de Velocidad del Viento",dailyForecastDays:"Días de Previsión",hourlyForecastHours:"Horas de Previsión",updateCard:"Actualizar Tarjeta",startDemo:"Iniciar Modo Demostración",stopDemo:"Detener Demostración",madeWith:"Hecho con amor para Home Assistant",loading:"Cargando tarjeta...",errorTitle:"No se pudo cargar la tarjeta",errorDetails:"Consulte la consola del navegador (F12) para obtener más detalles",errorServer:"Asegúrese de que el archivo se sirve a través de un servidor local (no file://)",placeholderEmpty:"Deje vacío para ocultar",weatherConditions:{sunny:"Soleado",clear:"Despejado",clearNight:"Noche Despejada",partlyCloudy:"Parcialmente Nublado",cloudy:"Nublado",rainy:"Lluvioso",pouring:"Torrencial",snowy:"Nevado",sleet:"Aguanieve",hail:"Granizo",foggy:"Nublado",lightning:"Rayos",thunderstorm:"Tormenta Eléctrica"},language:{title:"Idioma",english:"English",russian:"Русский",french:"Français",german:"Deutsch",dutch:"Nederlands",spanish:"Español",italian:"Italiano",slovak:"Slovenčina",hungarian:"Magyar"}}};var vi={sunny:"Soleggiato",clear:"Sereno",overcast:"Coperto",cloudy:"Nuvoloso",partlycloudy:"Parzialmente Nuvoloso",rainy:"Piovoso",rain:"Pioggia",snowy:"Nevoso",snow:"Neve",foggy:"Nebbia",fog:"Nebbia",lightning:"Fulmine","lightning-rainy":"Temporale",pouring:"Pioggia Intensa","snowy-rainy":"Nevischio",hail:"Grandine","clear-night":"Notte Serena",feels_like:"Percepita",forecast_title:"Previsioni di oggi",daily_forecast_title:"Previsioni Giornaliere",no_data:"Nessun dato",forecast_unavailable:"Previsioni non disponibili",weather:"Meteo",language:"Lingua",wind_unit_kmh:"km/h",wind_unit_ms:"m/s",wind_unit_mph:"mph",wind_unit_knots:"knots",wind_unit_fts:"ft/s",show_clock:"Mostra ora corrente",am:"AM",pm:"PM",editor:{entity:"Entità meteo",name:"Titolo della scheda",height:"Altezza della scheda",show_feels_like:"Mostra temperatura percepita",show_wind:"Mostra velocità del vento",show_wind_gust:"Mostra raffiche di vento",show_wind_direction:"Mostra direzione del vento",show_humidity:"Mostra umidità",show_min_temp:"Mostra temperatura minima",show_hourly_forecast:"Mostra previsione oraria",hourly_forecast_hours:"Ore di previsione",show_daily_forecast:"Mostra previsione giornaliera",daily_forecast_days:"Giorni di previsione",show_sunrise_sunset:"Mostra alba/tramonto",sunrise_entity:"Entità alba",sunset_entity:"Entità tramonto",show_clock:"Mostra orologio",clock_position:"Posizione orologio",clock_position_top:"In alto",clock_position_details:"Dettagli",clock_format:"Formato orario",clock_format_12h:"12 ore (AM/PM)",clock_format_24h:"24 ore",overlay_opacity:"Opacità sovrapposizione",language:"Lingua",language_auto:"Auto",language_en:"Inglese",language_ru:"Russo",language_de:"Tedesco",language_nl:"Olandese",language_fr:"Francese",language_es:"Spagnolo",language_it:"Italiano",language_sk:"Slovacco",language_hu:"Ungherese",wind_speed_unit:"Unità velocità del vento",wind_speed_unit_ms:"m/s",wind_speed_unit_kmh:"km/h"},demo:{pageTitle:"Dynamic Weather Card",pageSubtitle:"Demo interattiva & Strumento di configurazione",livePreview:"Anteprima live",configuration:"Configurazione",quickPresets:"Preset veloci",sunnyDay:"Giornata Soleggiata",rainy:"Piovoso",snowy:"Nevoso",clearNight:"Notte Serena",weatherCondition:"Condizione Meteo",condition:"Condizione",temperature:"Temperatura",humidity:"Umidità (%)",windSpeed:"Velocità del Vento",timeOfDay:"Momento della giornata",timeMode:"Modalità ora",autoTime:"Automatico (Ora corrente)",manualControl:"Controllo manuale",sunrise:"Alba",day:"Giorno",sunset:"Tramonto",night:"Notte",currentTime:"Ora corrente",displayOptions:"Opzioni di visualizzazione",cardName:"Nome della card",height:"Altezza (px)",feelsLike:"Temperatura percepita",minTemp:"Temperatura minima",windDirection:"Direzione del vento",windGust:"Raffiche di vento",hourlyForecast:"Previsioni orarie",dailyForecast:"Previsioni giornaliere",sunriseSunset:"Alba/Tramonto",showClock:"Orologio",clockPosition:"Posizione Orologio",clockPositionTop:"In alto a destra",clockPositionDetails:"Riga dettagli",clockFormat:"Formato Orologio",clockFormat12h:"12 ore (AM/PM)",clockFormat24h:"24 ore",overlayOpacity:"Opacità Sovrapposizione (0-1)",windSpeedUnit:"Unità Velocità Vento",dailyForecastDays:"Giorni di Previsione",hourlyForecastHours:"Ore di Previsione",updateCard:"Aggiorna card",startDemo:"Avvia Demo",stopDemo:"Ferma Demo",madeWith:"Creato con amore per Home Assistant",loading:"Caricamento card...",errorTitle:"Impossibile caricare la card",errorDetails:"Controlla la console del browser (F12) per i dettagli",errorServer:"Assicurati che il file sia servito tramite server locale (non file://)",placeholderEmpty:"Lascia vuoto per nascondere",weatherConditions:{sunny:"Soleggiato",clear:"Sereno",clearNight:"Notte Serena",partlyCloudy:"Parzialmente Nuvoloso",cloudy:"Nuvoloso",rainy:"Piovoso",pouring:"Pioggia Intensa",snowy:"Nevoso",sleet:"Nevischio",hail:"Grandine",foggy:"Nebbia",lightning:"Fulmine",thunderstorm:"Temporale"},language:{title:"Lingua",english:"English",russian:"Русский",french:"Français",german:"Deutsch",dutch:"Nederlands",spanish:"Español",italian:"Italiano",slovak:"Slovenčina",hungarian:"Magyar"}}};var Ni={sunny:"Slnečno",clear:"Jasno",overcast:"Zamračené",cloudy:"Oblačno",partlycloudy:"Polooblačno",rainy:"Daždivo",rain:"Dážď",snowy:"Sneženie",snow:"Sneh",foggy:"Hmlisto",fog:"Hmla",lightning:"Blesky","lightning-rainy":"Búrka",pouring:"Silný dážď","snowy-rainy":"Dážď so snehom",hail:"Krúpy","clear-night":"Jasná noc",feels_like:"Pocitová teplota",forecast_title:"Predpoveď na dnes",daily_forecast_title:"Denná predpoveď",no_data:"Žiadne dáta",forecast_unavailable:"Predpoveď nedostupná",weather:"Počasie",language:"Jazyk",wind_unit_kmh:"km/h",wind_unit_ms:"m/s",wind_unit_mph:"mph",wind_unit_knots:"uzly",wind_unit_fts:"ft/s",show_clock:"Zobraziť aktuálny čas",am:"dop.",pm:"pop.",editor:{entity:"Entita počasia",name:"Názov karty",height:"Výška karty",show_feels_like:"Zobraziť pocitovú teplotu",show_wind:"Zobraziť rýchlosť vetra",show_wind_gust:"Zobraziť nárazy vetra",show_wind_direction:"Zobraziť smer vetra",show_humidity:"Zobraziť vlhkosť",show_min_temp:"Zobraziť minimálnu teplotu",show_hourly_forecast:"Zobraziť hodinovú predpoveď",hourly_forecast_hours:"Počet hodín v predpovedi",show_daily_forecast:"Zobraziť dennú predpoveď",daily_forecast_days:"Počet dní v predpovedi",show_sunrise_sunset:"Zobraziť východ/západ slnka",sunrise_entity:"Entita východu slnka",sunset_entity:"Entita západu slnka",show_clock:"Zobraziť hodiny",clock_position:"Pozícia hodín",clock_position_top:"Hore",clock_position_details:"V detailoch",clock_format:"Formát času",clock_format_12h:"12-hodinový (AM/PM)",clock_format_24h:"24-hodinový",overlay_opacity:"Priehľadnosť vrstvy",language:"Jazyk",language_auto:"Automaticky",language_en:"Angličtina",language_ru:"Ruština",language_de:"Nemčina",language_nl:"Holandčina",language_fr:"Francúzština",language_es:"Španielčina",language_it:"Taliančina",language_sk:"Slovenčina",language_hu:"Maďarčina",wind_speed_unit:"Jednotka rýchlosti vetra",wind_speed_unit_ms:"m/s",wind_speed_unit_kmh:"km/h"},demo:{pageTitle:"Dynamická karta počasia",pageSubtitle:"Interaktívne demo a konfiguračný nástroj",livePreview:"Živý náhľad",configuration:"Konfigurácia",quickPresets:"Rýchle predvoľby",sunnyDay:"Slnečný deň",rainy:"Daždivo",snowy:"Sneženie",clearNight:"Jasná noc",weatherCondition:"Poveternostné podmienky",condition:"Stav",temperature:"Teplota",humidity:"Vlhkosť (%)",windSpeed:"Rýchlosť vetra",timeOfDay:"Čas dňa",timeMode:"Režim času",autoTime:"Automaticky (Aktuálny čas)",manualControl:"Manuálne ovládanie",sunrise:"Východ slnka",day:"Deň",sunset:"Západ slnka",night:"Noc",currentTime:"Aktuálny čas",displayOptions:"Možnosti zobrazenia",cardName:"Názov karty",height:"Výška (px)",feelsLike:"Pocitová teplota",minTemp:"Minimálna teplota",windDirection:"Smer vetra",windGust:"Nárazy vetra",hourlyForecast:"Hodinová predpoveď",dailyForecast:"Denná predpoveď",sunriseSunset:"Východ/Západ slnka",showClock:"Hodiny",clockPosition:"Pozícia hodín",clockPositionTop:"Vpravo hore",clockPositionDetails:"Riadok s detailmi",clockFormat:"Formát času",clockFormat12h:"12-hodinový (AM/PM)",clockFormat24h:"24-hodinový",overlayOpacity:"Priehľadnosť vrstvy (0-1)",windSpeedUnit:"Jednotka rýchlosti vetra",dailyForecastDays:"Dni dennej predpovede",hourlyForecastHours:"Hodiny hodinovej predpovede",updateCard:"Aktualizovať kartu",startDemo:"Spustiť Demo režim",stopDemo:"Zastaviť Demo",madeWith:"Vytvorené s láskou pre Home Assistant",loading:"Načítavam kartu...",errorTitle:"Nepodarilo sa načítať kartu",errorDetails:"Skontrolujte konzolu prehliadača (F12) pre detaily",errorServer:"Uistite sa, že súbor je poskytovaný cez lokálny server (nie cez file://)",placeholderEmpty:"Ponechajte prázdne pre skrytie",weatherConditions:{sunny:"Slnečno",clear:"Jasno",clearNight:"Jasná noc",partlyCloudy:"Polooblačno",cloudy:"Oblačno",rainy:"Daždivo",pouring:"Lejak",snowy:"Sneženie",sleet:"Dážď so snehom",hail:"Krúpy",foggy:"Hmla",lightning:"Blesky",thunderstorm:"Búrka"},language:{title:"Jazyk",english:"English",russian:"Русский",french:"Français",german:"Deutsch",dutch:"Nederlands",spanish:"Español",italian:"Italiano",slovak:"Slovenčina",hungarian:"Magyar"}}};var Si={sunny:"Napos",clear:"Derült",overcast:"Borult",cloudy:"Felhős",partlycloudy:"Részben felhős",rainy:"Esős",rain:"Eső",snowy:"Havas",snow:"Hó",foggy:"Ködös",fog:"Köd",lightning:"Villámlás","lightning-rainy":"Zivatar",pouring:"Heves eső","snowy-rainy":"Havas eső",hail:"Jégeső","clear-night":"Derült éj",feels_like:"Hőérzet",forecast_title:"Mai előrejelzés",daily_forecast_title:"Napi előrejelzés",no_data:"Nincs adat",forecast_unavailable:"Előrejelzés nem elérhető",weather:"Időjárás",language:"Nyelv",wind_unit_kmh:"km/h",wind_unit_ms:"m/s",wind_unit_mph:"mph",wind_unit_knots:"csomó",wind_unit_fts:"ft/s",show_clock:"Aktuális idő mutatása",am:"DE",pm:"DU",editor:{entity:"Időjárás entitás",name:"Kártya címe",height:"Kártya magasság",show_feels_like:"Hőérzet mutatása",show_wind:"Szélsebesség mutatása",show_wind_gust:"Széllökések mutatása",show_wind_direction:"Szélirány mutatása",show_humidity:"Páratartalom mutatása",show_min_temp:"Min. hőmérséklet",show_hourly_forecast:"Óránkénti előrejelzés",hourly_forecast_hours:"Óránkénti órák száma",show_daily_forecast:"Napi előrejelzés",daily_forecast_days:"Napok száma a napi előrejelzésben",show_sunrise_sunset:"Napkelte/Napnyugta",sunrise_entity:"Napkelte entitás",sunset_entity:"Napnyugta entitás",show_clock:"Óra mutatása",clock_position:"Óra pozíció",clock_position_top:"Felül",clock_position_details:"Részletek",clock_format:"Óra formátum",clock_format_12h:"12 órás (DE/DU)",clock_format_24h:"24 órás",overlay_opacity:"Fedőréteg átlátszóság",language:"Nyelv",language_auto:"Automatikus",language_en:"Angol",language_ru:"Orosz",language_de:"Német",language_nl:"Holland",language_fr:"Francia",language_es:"Spanyol",language_it:"Olasz",language_hu:"Magyar",language_sk:"Szlovák",wind_speed_unit:"Szélsebesség egység",wind_speed_unit_ms:"m/s",wind_speed_unit_kmh:"km/h"},demo:{pageTitle:"Dynamic Weather Card",pageSubtitle:"Interaktív demó és beállító eszköz",livePreview:"Élő előnézet",configuration:"Beállítások",quickPresets:"Gyors presetek",sunnyDay:"Napos nap",rainy:"Esős",snowy:"Havas",clearNight:"Derült éj",weatherCondition:"Időjárási állapot",condition:"Állapot",temperature:"Hőmérséklet",humidity:"Páratartalom (%)",windSpeed:"Szélsebesség",timeOfDay:"Napszak",timeMode:"Idő mód",autoTime:"Automatikus (aktuális idő)",manualControl:"Kézi vezérlés",sunrise:"Napkelte",day:"Nappal",sunset:"Napnyugta",night:"Éjszaka",currentTime:"Aktuális idő",displayOptions:"Megjelenítés",cardName:"Kártya neve",height:"Magasság (px)",feelsLike:"Hőérzet",minTemp:"Min. hőmérséklet",windDirection:"Szélirány",windGust:"Széllökés",hourlyForecast:"Óránkénti előrejelzés",dailyForecast:"Napi előrejelzés",sunriseSunset:"Napkelte/Napnyugta",showClock:"Óra",clockPosition:"Óra pozíció",clockPositionTop:"Jobb felső",clockPositionDetails:"Részletek sora",clockFormat:"Óra formátum",clockFormat12h:"12 órás (DE/DU)",clockFormat24h:"24 órás",overlayOpacity:"Fedőréteg átlátszóság (0–1)",windSpeedUnit:"Szélsebesség egység",dailyForecastDays:"Napi napok",hourlyForecastHours:"Óránkénti órák",updateCard:"Kártya frissítése",startDemo:"Demó indítása",stopDemo:"Demó leállítása",madeWith:"Szeretettel a Home Assistanthez",loading:"Kártya betöltése…",errorTitle:"Nem sikerült betölteni",errorDetails:"Részletek a böngésző konzolban (F12)",errorServer:"A fájlt helyi szerveren szolgáld ki (nem file://)",placeholderEmpty:"Üresen hagyva elrejt",weatherConditions:{sunny:"Napos",clear:"Derült",clearNight:"Derült éj",partlyCloudy:"Részben felhős",cloudy:"Felhős",rainy:"Esős",pouring:"Zuhogó eső",snowy:"Havas",sleet:"Havas eső",hail:"Jégeső",foggy:"Ködös",lightning:"Villámlás",thunderstorm:"Zivatar"},language:{title:"Nyelv",english:"Angol",russian:"Orosz",french:"Francia",german:"Német",dutch:"Holland",spanish:"Spanyol",italian:"Olasz",hungarian:"Magyar",slovak:"Slovenčina"}}};var vo={en:Ki,ru:Mi,de:zi,nl:Hi,fr:Ai,es:Zi,it:vi,sk:Ni,hu:Si};class qi{lang="en";fallback="en";t(o){let i=o.split("."),a=i.reduce((l,s)=>l?.[s],vo[this.lang]);if(a!=null)return a;return i.reduce((l,s)=>l?.[s],vo[this.fallback])??o}setLanguage(o){if(!vo[o]||this.lang===o)return;this.lang=o,window.dispatchEvent(new CustomEvent("language-changed"))}}var d=new qi;window.i18n=d;var I=({configLang:o,hassLang:i}={})=>{if(o&&o!=="auto")return o;if(i)return i;if(typeof navigator<"u"&&navigator.language){let a=navigator.language.toLowerCase();if(a.startsWith("ru"))return"ru";if(a.startsWith("de"))return"de";if(a.startsWith("nl"))return"nl";if(a.startsWith("fr"))return"fr";if(a.startsWith("it"))return"it";if(a.startsWith("es"))return"es";if(a.startsWith("sk"))return"sk";if(a.startsWith("hu"))return"hu"}return"en"};function ja(){let o=new Date,i=o.getHours(),a=o.getMinutes(),n=i*60+a;if(n>=N.SUNRISE_START&&n=N.SUNRISE_END&&n=N.DAY_END&&n=12?n:a;return s=s%12||12,`${s}:${r.toString().padStart(2,"0")} ${c}`}else return`${s.toString().padStart(2,"0")}:${r.toString().padStart(2,"0")}`}function So(o,i=null,a=null,n=null){let l=null,s=null;if(i&&n&&n.states[i]){let r=n.states[i];l=new Date(r.state)}if(a&&n&&n.states[a]){let r=n.states[a];s=new Date(r.state)}if(!l||!s){if(o&&o.attributes){let r=o.attributes;if(!l&&(r.forecast_sunrise||r.sunrise))l=new Date(r.forecast_sunrise||r.sunrise);if(!s&&(r.forecast_sunset||r.sunset))s=new Date(r.forecast_sunset||r.sunset)}}if((!l||!s)&&n&&n.states["sun.sun"]){let c=n.states["sun.sun"].attributes;if(!l&&c.next_rising)l=new Date(c.next_rising);if(!s&&c.next_setting)s=new Date(c.next_setting)}return{sunrise:l,sunset:s,hasSunData:!!(l&&s)}}function qo(o){let i=new Date;if(o.hasSunData&&o.sunrise&&o.sunset){let a=i.getTime(),n=o.sunrise.getTime(),l=o.sunset.getTime();if(n-a>43200000)n-=86400000;if(l-a>43200000)l-=86400000;let s=n-3600000,r=n+3600000,c=l-3600000,_=l+3600000;if(a>=s&&a=r&&a=c&&a<_)return{type:"sunset",progress:(a-c)/(_-c)};return{type:"night",progress:0}}return ja()}function Jo(o,i,a){if(o==null)return null;if(i.wind_speed_unit)return Math.round(o*10)/10;if(a==="kmh")return Math.round(o*3.6*10)/10;return Math.round(o*10)/10}function Qi(o,i,a){let n=o.wind_speed_unit;if(n){let l=n.toLowerCase().replace(/[^a-z]/g,"");if(l==="kmh"||l==="kmph")return a("wind_unit_kmh");else if(l==="ms"||l==="mps")return a("wind_unit_ms");else if(l==="mph")return a("wind_unit_mph");else if(l==="knots"||l==="kn"||l==="kt")return a("wind_unit_knots");else if(l==="fts"||l==="ftps")return a("wind_unit_fts");return n}return i==="kmh"?a("wind_unit_kmh"):a("wind_unit_ms")}function Ci(o,i,a,n){if(i==="12h"){let l=o.getHours(),s=String(o.getMinutes()).padStart(2,"0"),r=l>=12?n:a;return l=l%12||12,`${l}:${s} ${r}`}else{let l=String(o.getHours()).padStart(2,"0"),s=String(o.getMinutes()).padStart(2,"0");return`${l}:${s}`}}function go(o,i){let a=o?.querySelector(i);if(!a)return null;let n=(l)=>{let s=l;if(s.deltaY!==0)l.preventDefault(),a.scrollLeft+=s.deltaY};return a.addEventListener("wheel",n,{passive:!1}),()=>a.removeEventListener("wheel",n)}var Pi=W` + `.trim().replace(/\n */g, ` +`); + } + throw new Error(message); + } + return policy !== undefined ? policy.createHTML(stringFromTSA) : stringFromTSA; +} +var getTemplateHtml = (strings, type) => { + const l = strings.length - 1; + const attrNames = []; + let html2 = type === SVG_RESULT ? "" : type === MATHML_RESULT ? "" : ""; + let rawTextEndRegex; + let regex = textEndRegex; + for (let i = 0;i < l; i++) { + const s = strings[i]; + let attrNameEndIndex = -1; + let attrName; + let lastIndex = 0; + let match; + while (lastIndex < s.length) { + regex.lastIndex = lastIndex; + match = regex.exec(s); + if (match === null) { + break; + } + lastIndex = regex.lastIndex; + if (regex === textEndRegex) { + if (match[COMMENT_START] === "!--") { + regex = commentEndRegex; + } else if (match[COMMENT_START] !== undefined) { + regex = comment2EndRegex; + } else if (match[TAG_NAME] !== undefined) { + if (rawTextElement.test(match[TAG_NAME])) { + rawTextEndRegex = new RegExp(`") { + regex = rawTextEndRegex ?? textEndRegex; + attrNameEndIndex = -1; + } else if (match[ATTRIBUTE_NAME] === undefined) { + attrNameEndIndex = -2; + } else { + attrNameEndIndex = regex.lastIndex - match[SPACES_AND_EQUALS].length; + attrName = match[ATTRIBUTE_NAME]; + regex = match[QUOTE_CHAR] === undefined ? tagEndRegex : match[QUOTE_CHAR] === '"' ? doubleQuoteAttrEndRegex : singleQuoteAttrEndRegex; + } + } else if (regex === doubleQuoteAttrEndRegex || regex === singleQuoteAttrEndRegex) { + regex = tagEndRegex; + } else if (regex === commentEndRegex || regex === comment2EndRegex) { + regex = textEndRegex; + } else { + regex = tagEndRegex; + rawTextEndRegex = undefined; + } + } + if (DEV_MODE2) { + console.assert(attrNameEndIndex === -1 || regex === tagEndRegex || regex === singleQuoteAttrEndRegex || regex === doubleQuoteAttrEndRegex, "unexpected parse state B"); + } + const end = regex === tagEndRegex && strings[i + 1].startsWith("/>") ? " " : ""; + html2 += regex === textEndRegex ? s + nodeMarker : attrNameEndIndex >= 0 ? (attrNames.push(attrName), s.slice(0, attrNameEndIndex) + boundAttributeSuffix + s.slice(attrNameEndIndex)) + marker + end : s + marker + (attrNameEndIndex === -2 ? i : end); + } + const htmlResult = html2 + (strings[l] || "") + (type === SVG_RESULT ? "" : type === MATHML_RESULT ? "" : ""); + return [trustFromTemplateString(strings, htmlResult), attrNames]; +}; + +class Template { + constructor({ strings, ["_$litType$"]: type }, options) { + this.parts = []; + let node; + let nodeIndex = 0; + let attrNameIndex = 0; + const partCount = strings.length - 1; + const parts = this.parts; + const [html2, attrNames] = getTemplateHtml(strings, type); + this.el = Template.createElement(html2, options); + walker.currentNode = this.el.content; + if (type === SVG_RESULT || type === MATHML_RESULT) { + const wrapper = this.el.content.firstChild; + wrapper.replaceWith(...wrapper.childNodes); + } + while ((node = walker.nextNode()) !== null && parts.length < partCount) { + if (node.nodeType === 1) { + if (DEV_MODE2) { + const tag2 = node.localName; + if (/^(?:textarea|template)$/i.test(tag2) && node.innerHTML.includes(marker)) { + const m = `Expressions are not supported inside \`${tag2}\` ` + `elements. See https://lit.dev/msg/expression-in-${tag2} for more ` + `information.`; + if (tag2 === "template") { + throw new Error(m); + } else + issueWarning2("", m); + } + } + if (node.hasAttributes()) { + for (const name of node.getAttributeNames()) { + if (name.endsWith(boundAttributeSuffix)) { + const realName = attrNames[attrNameIndex++]; + const value = node.getAttribute(name); + const statics = value.split(marker); + const m = /([.?@])?(.*)/.exec(realName); + parts.push({ + type: ATTRIBUTE_PART, + index: nodeIndex, + name: m[2], + strings: statics, + ctor: m[1] === "." ? PropertyPart : m[1] === "?" ? BooleanAttributePart : m[1] === "@" ? EventPart : AttributePart + }); + node.removeAttribute(name); + } else if (name.startsWith(marker)) { + parts.push({ + type: ELEMENT_PART, + index: nodeIndex + }); + node.removeAttribute(name); + } + } + } + if (rawTextElement.test(node.tagName)) { + const strings2 = node.textContent.split(marker); + const lastIndex = strings2.length - 1; + if (lastIndex > 0) { + node.textContent = trustedTypes2 ? trustedTypes2.emptyScript : ""; + for (let i = 0;i < lastIndex; i++) { + node.append(strings2[i], createMarker()); + walker.nextNode(); + parts.push({ type: CHILD_PART, index: ++nodeIndex }); + } + node.append(strings2[lastIndex], createMarker()); + } + } + } else if (node.nodeType === 8) { + const data = node.data; + if (data === markerMatch) { + parts.push({ type: CHILD_PART, index: nodeIndex }); + } else { + let i = -1; + while ((i = node.data.indexOf(marker, i + 1)) !== -1) { + parts.push({ type: COMMENT_PART, index: nodeIndex }); + i += marker.length - 1; + } + } + } + nodeIndex++; + } + if (DEV_MODE2) { + if (attrNames.length !== attrNameIndex) { + throw new Error(`Detected duplicate attribute bindings. This occurs if your template ` + `has duplicate attributes on an element tag. For example ` + `"" contains a ` + `duplicate "disabled" attribute. The error was detected in ` + `the following template: +` + "`" + strings.join("${...}") + "`"); + } + } + debugLogEvent2 && debugLogEvent2({ + kind: "template prep", + template: this, + clonableTemplate: this.el, + parts: this.parts, + strings + }); + } + static createElement(html2, _options) { + const el = d.createElement("template"); + el.innerHTML = html2; + return el; + } +} +function resolveDirective(part, value, parent = part, attributeIndex) { + if (value === noChange) { + return value; + } + let currentDirective = attributeIndex !== undefined ? parent.__directives?.[attributeIndex] : parent.__directive; + const nextDirectiveConstructor = isPrimitive(value) ? undefined : value["_$litDirective$"]; + if (currentDirective?.constructor !== nextDirectiveConstructor) { + currentDirective?.["_$notifyDirectiveConnectionChanged"]?.(false); + if (nextDirectiveConstructor === undefined) { + currentDirective = undefined; + } else { + currentDirective = new nextDirectiveConstructor(part); + currentDirective._$initialize(part, parent, attributeIndex); + } + if (attributeIndex !== undefined) { + (parent.__directives ??= [])[attributeIndex] = currentDirective; + } else { + parent.__directive = currentDirective; + } + } + if (currentDirective !== undefined) { + value = resolveDirective(part, currentDirective._$resolve(part, value.values), currentDirective, attributeIndex); + } + return value; +} + +class TemplateInstance { + constructor(template, parent) { + this._$parts = []; + this._$disconnectableChildren = undefined; + this._$template = template; + this._$parent = parent; + } + get parentNode() { + return this._$parent.parentNode; + } + get _$isConnected() { + return this._$parent._$isConnected; + } + _clone(options) { + const { el: { content }, parts } = this._$template; + const fragment = (options?.creationScope ?? d).importNode(content, true); + walker.currentNode = fragment; + let node = walker.nextNode(); + let nodeIndex = 0; + let partIndex = 0; + let templatePart = parts[0]; + while (templatePart !== undefined) { + if (nodeIndex === templatePart.index) { + let part; + if (templatePart.type === CHILD_PART) { + part = new ChildPart(node, node.nextSibling, this, options); + } else if (templatePart.type === ATTRIBUTE_PART) { + part = new templatePart.ctor(node, templatePart.name, templatePart.strings, this, options); + } else if (templatePart.type === ELEMENT_PART) { + part = new ElementPart(node, this, options); + } + this._$parts.push(part); + templatePart = parts[++partIndex]; + } + if (nodeIndex !== templatePart?.index) { + node = walker.nextNode(); + nodeIndex++; + } + } + walker.currentNode = d; + return fragment; + } + _update(values) { + let i = 0; + for (const part of this._$parts) { + if (part !== undefined) { + debugLogEvent2 && debugLogEvent2({ + kind: "set part", + part, + value: values[i], + valueIndex: i, + values, + templateInstance: this + }); + if (part.strings !== undefined) { + part._$setValue(values, part, i); + i += part.strings.length - 2; + } else { + part._$setValue(values[i]); + } + } + i++; + } + } +} + +class ChildPart { + get _$isConnected() { + return this._$parent?._$isConnected ?? this.__isConnected; + } + constructor(startNode, endNode, parent, options) { + this.type = CHILD_PART; + this._$committedValue = nothing; + this._$disconnectableChildren = undefined; + this._$startNode = startNode; + this._$endNode = endNode; + this._$parent = parent; + this.options = options; + this.__isConnected = options?.isConnected ?? true; + if (ENABLE_EXTRA_SECURITY_HOOKS) { + this._textSanitizer = undefined; + } + } + get parentNode() { + let parentNode = wrap(this._$startNode).parentNode; + const parent = this._$parent; + if (parent !== undefined && parentNode?.nodeType === 11) { + parentNode = parent.parentNode; + } + return parentNode; + } + get startNode() { + return this._$startNode; + } + get endNode() { + return this._$endNode; + } + _$setValue(value, directiveParent = this) { + if (DEV_MODE2 && this.parentNode === null) { + throw new Error(`This \`ChildPart\` has no \`parentNode\` and therefore cannot accept a value. This likely means the element containing the part was manipulated in an unsupported way outside of Lit's control such that the part's marker nodes were ejected from DOM. For example, setting the element's \`innerHTML\` or \`textContent\` can do this.`); + } + value = resolveDirective(this, value, directiveParent); + if (isPrimitive(value)) { + if (value === nothing || value == null || value === "") { + if (this._$committedValue !== nothing) { + debugLogEvent2 && debugLogEvent2({ + kind: "commit nothing to child", + start: this._$startNode, + end: this._$endNode, + parent: this._$parent, + options: this.options + }); + this._$clear(); + } + this._$committedValue = nothing; + } else if (value !== this._$committedValue && value !== noChange) { + this._commitText(value); + } + } else if (value["_$litType$"] !== undefined) { + this._commitTemplateResult(value); + } else if (value.nodeType !== undefined) { + if (DEV_MODE2 && this.options?.host === value) { + this._commitText(`[probable mistake: rendered a template's host in itself ` + `(commonly caused by writing \${this} in a template]`); + console.warn(`Attempted to render the template host`, value, `inside itself. This is almost always a mistake, and in dev mode `, `we render some warning text. In production however, we'll `, `render it, which will usually result in an error, and sometimes `, `in the element disappearing from the DOM.`); + return; + } + this._commitNode(value); + } else if (isIterable(value)) { + this._commitIterable(value); + } else { + this._commitText(value); + } + } + _insert(node) { + return wrap(wrap(this._$startNode).parentNode).insertBefore(node, this._$endNode); + } + _commitNode(value) { + if (this._$committedValue !== value) { + this._$clear(); + if (ENABLE_EXTRA_SECURITY_HOOKS && sanitizerFactoryInternal !== noopSanitizer) { + const parentNodeName = this._$startNode.parentNode?.nodeName; + if (parentNodeName === "STYLE" || parentNodeName === "SCRIPT") { + let message = "Forbidden"; + if (DEV_MODE2) { + if (parentNodeName === "STYLE") { + message = `Lit does not support binding inside style nodes. ` + `This is a security risk, as style injection attacks can ` + `exfiltrate data and spoof UIs. ` + `Consider instead using css\`...\` literals ` + `to compose styles, and do dynamic styling with ` + `css custom properties, ::parts, s, ` + `and by mutating the DOM rather than stylesheets.`; + } else { + message = `Lit does not support binding inside script nodes. ` + `This is a security risk, as it could allow arbitrary ` + `code execution.`; + } + } + throw new Error(message); + } + } + debugLogEvent2 && debugLogEvent2({ + kind: "commit node", + start: this._$startNode, + parent: this._$parent, + value, + options: this.options + }); + this._$committedValue = this._insert(value); + } + } + _commitText(value) { + if (this._$committedValue !== nothing && isPrimitive(this._$committedValue)) { + const node = wrap(this._$startNode).nextSibling; + if (ENABLE_EXTRA_SECURITY_HOOKS) { + if (this._textSanitizer === undefined) { + this._textSanitizer = createSanitizer(node, "data", "property"); + } + value = this._textSanitizer(value); + } + debugLogEvent2 && debugLogEvent2({ + kind: "commit text", + node, + value, + options: this.options + }); + node.data = value; + } else { + if (ENABLE_EXTRA_SECURITY_HOOKS) { + const textNode = d.createTextNode(""); + this._commitNode(textNode); + if (this._textSanitizer === undefined) { + this._textSanitizer = createSanitizer(textNode, "data", "property"); + } + value = this._textSanitizer(value); + debugLogEvent2 && debugLogEvent2({ + kind: "commit text", + node: textNode, + value, + options: this.options + }); + textNode.data = value; + } else { + this._commitNode(d.createTextNode(value)); + debugLogEvent2 && debugLogEvent2({ + kind: "commit text", + node: wrap(this._$startNode).nextSibling, + value, + options: this.options + }); + } + } + this._$committedValue = value; + } + _commitTemplateResult(result) { + const { values, ["_$litType$"]: type } = result; + const template = typeof type === "number" ? this._$getTemplate(result) : (type.el === undefined && (type.el = Template.createElement(trustFromTemplateString(type.h, type.h[0]), this.options)), type); + if (this._$committedValue?._$template === template) { + debugLogEvent2 && debugLogEvent2({ + kind: "template updating", + template, + instance: this._$committedValue, + parts: this._$committedValue._$parts, + options: this.options, + values + }); + this._$committedValue._update(values); + } else { + const instance = new TemplateInstance(template, this); + const fragment = instance._clone(this.options); + debugLogEvent2 && debugLogEvent2({ + kind: "template instantiated", + template, + instance, + parts: instance._$parts, + options: this.options, + fragment, + values + }); + instance._update(values); + debugLogEvent2 && debugLogEvent2({ + kind: "template instantiated and updated", + template, + instance, + parts: instance._$parts, + options: this.options, + fragment, + values + }); + this._commitNode(fragment); + this._$committedValue = instance; + } + } + _$getTemplate(result) { + let template = templateCache.get(result.strings); + if (template === undefined) { + templateCache.set(result.strings, template = new Template(result)); + } + return template; + } + _commitIterable(value) { + if (!isArray(this._$committedValue)) { + this._$committedValue = []; + this._$clear(); + } + const itemParts = this._$committedValue; + let partIndex = 0; + let itemPart; + for (const item of value) { + if (partIndex === itemParts.length) { + itemParts.push(itemPart = new ChildPart(this._insert(createMarker()), this._insert(createMarker()), this, this.options)); + } else { + itemPart = itemParts[partIndex]; + } + itemPart._$setValue(item); + partIndex++; + } + if (partIndex < itemParts.length) { + this._$clear(itemPart && wrap(itemPart._$endNode).nextSibling, partIndex); + itemParts.length = partIndex; + } + } + _$clear(start = wrap(this._$startNode).nextSibling, from) { + this._$notifyConnectionChanged?.(false, true, from); + while (start !== this._$endNode) { + const n = wrap(start).nextSibling; + wrap(start).remove(); + start = n; + } + } + setConnected(isConnected) { + if (this._$parent === undefined) { + this.__isConnected = isConnected; + this._$notifyConnectionChanged?.(isConnected); + } else if (DEV_MODE2) { + throw new Error("part.setConnected() may only be called on a " + "RootPart returned from render()."); + } + } +} + +class AttributePart { + get tagName() { + return this.element.tagName; + } + get _$isConnected() { + return this._$parent._$isConnected; + } + constructor(element, name, strings, parent, options) { + this.type = ATTRIBUTE_PART; + this._$committedValue = nothing; + this._$disconnectableChildren = undefined; + this.element = element; + this.name = name; + this._$parent = parent; + this.options = options; + if (strings.length > 2 || strings[0] !== "" || strings[1] !== "") { + this._$committedValue = new Array(strings.length - 1).fill(new String); + this.strings = strings; + } else { + this._$committedValue = nothing; + } + if (ENABLE_EXTRA_SECURITY_HOOKS) { + this._sanitizer = undefined; + } + } + _$setValue(value, directiveParent = this, valueIndex, noCommit) { + const strings = this.strings; + let change = false; + if (strings === undefined) { + value = resolveDirective(this, value, directiveParent, 0); + change = !isPrimitive(value) || value !== this._$committedValue && value !== noChange; + if (change) { + this._$committedValue = value; + } + } else { + const values = value; + value = strings[0]; + let i, v; + for (i = 0;i < strings.length - 1; i++) { + v = resolveDirective(this, values[valueIndex + i], directiveParent, i); + if (v === noChange) { + v = this._$committedValue[i]; + } + change ||= !isPrimitive(v) || v !== this._$committedValue[i]; + if (v === nothing) { + value = nothing; + } else if (value !== nothing) { + value += (v ?? "") + strings[i + 1]; + } + this._$committedValue[i] = v; + } + } + if (change && !noCommit) { + this._commitValue(value); + } + } + _commitValue(value) { + if (value === nothing) { + wrap(this.element).removeAttribute(this.name); + } else { + if (ENABLE_EXTRA_SECURITY_HOOKS) { + if (this._sanitizer === undefined) { + this._sanitizer = sanitizerFactoryInternal(this.element, this.name, "attribute"); + } + value = this._sanitizer(value ?? ""); + } + debugLogEvent2 && debugLogEvent2({ + kind: "commit attribute", + element: this.element, + name: this.name, + value, + options: this.options + }); + wrap(this.element).setAttribute(this.name, value ?? ""); + } + } +} + +class PropertyPart extends AttributePart { + constructor() { + super(...arguments); + this.type = PROPERTY_PART; + } + _commitValue(value) { + if (ENABLE_EXTRA_SECURITY_HOOKS) { + if (this._sanitizer === undefined) { + this._sanitizer = sanitizerFactoryInternal(this.element, this.name, "property"); + } + value = this._sanitizer(value); + } + debugLogEvent2 && debugLogEvent2({ + kind: "commit property", + element: this.element, + name: this.name, + value, + options: this.options + }); + this.element[this.name] = value === nothing ? undefined : value; + } +} + +class BooleanAttributePart extends AttributePart { + constructor() { + super(...arguments); + this.type = BOOLEAN_ATTRIBUTE_PART; + } + _commitValue(value) { + debugLogEvent2 && debugLogEvent2({ + kind: "commit boolean attribute", + element: this.element, + name: this.name, + value: !!(value && value !== nothing), + options: this.options + }); + wrap(this.element).toggleAttribute(this.name, !!value && value !== nothing); + } +} + +class EventPart extends AttributePart { + constructor(element, name, strings, parent, options) { + super(element, name, strings, parent, options); + this.type = EVENT_PART; + if (DEV_MODE2 && this.strings !== undefined) { + throw new Error(`A \`<${element.localName}>\` has a \`@${name}=...\` listener with ` + "invalid content. Event listeners in templates must have exactly " + "one expression and no surrounding text."); + } + } + _$setValue(newListener, directiveParent = this) { + newListener = resolveDirective(this, newListener, directiveParent, 0) ?? nothing; + if (newListener === noChange) { + return; + } + const oldListener = this._$committedValue; + const shouldRemoveListener = newListener === nothing && oldListener !== nothing || newListener.capture !== oldListener.capture || newListener.once !== oldListener.once || newListener.passive !== oldListener.passive; + const shouldAddListener = newListener !== nothing && (oldListener === nothing || shouldRemoveListener); + debugLogEvent2 && debugLogEvent2({ + kind: "commit event listener", + element: this.element, + name: this.name, + value: newListener, + options: this.options, + removeListener: shouldRemoveListener, + addListener: shouldAddListener, + oldListener + }); + if (shouldRemoveListener) { + this.element.removeEventListener(this.name, this, oldListener); + } + if (shouldAddListener) { + this.element.addEventListener(this.name, this, newListener); + } + this._$committedValue = newListener; + } + handleEvent(event) { + if (typeof this._$committedValue === "function") { + this._$committedValue.call(this.options?.host ?? this.element, event); + } else { + this._$committedValue.handleEvent(event); + } + } +} + +class ElementPart { + constructor(element, parent, options) { + this.element = element; + this.type = ELEMENT_PART; + this._$disconnectableChildren = undefined; + this._$parent = parent; + this.options = options; + } + get _$isConnected() { + return this._$parent._$isConnected; + } + _$setValue(value) { + debugLogEvent2 && debugLogEvent2({ + kind: "commit to element binding", + element: this.element, + value, + options: this.options + }); + resolveDirective(this, value); + } +} +var polyfillSupport2 = DEV_MODE2 ? global3.litHtmlPolyfillSupportDevMode : global3.litHtmlPolyfillSupport; +polyfillSupport2?.(Template, ChildPart); +(global3.litHtmlVersions ??= []).push("3.3.2"); +if (DEV_MODE2 && global3.litHtmlVersions.length > 1) { + queueMicrotask(() => { + issueWarning2("multiple-versions", `Multiple versions of Lit loaded. ` + `Loading multiple versions is not recommended.`); + }); +} +var render = (value, container, options) => { + if (DEV_MODE2 && container == null) { + throw new TypeError(`The container to render into may not be ${container}`); + } + const renderId = DEV_MODE2 ? debugLogRenderId++ : 0; + const partOwnerNode = options?.renderBefore ?? container; + let part = partOwnerNode["_$litPart$"]; + debugLogEvent2 && debugLogEvent2({ + kind: "begin render", + id: renderId, + value, + container, + options, + part + }); + if (part === undefined) { + const endNode = options?.renderBefore ?? null; + partOwnerNode["_$litPart$"] = part = new ChildPart(container.insertBefore(createMarker(), endNode), endNode, undefined, options ?? {}); + } + part._$setValue(value); + debugLogEvent2 && debugLogEvent2({ + kind: "end render", + id: renderId, + value, + container, + options, + part + }); + return part; +}; +if (ENABLE_EXTRA_SECURITY_HOOKS) { + render.setSanitizer = setSanitizer; + render.createSanitizer = createSanitizer; + if (DEV_MODE2) { + render._testOnlyClearSanitizerFactoryDoNotCallOrElse = _testOnlyClearSanitizerFactoryDoNotCallOrElse; + } +} + +// node_modules/lit-element/development/lit-element.js +var JSCompiler_renameProperty2 = (prop, _obj) => prop; +var DEV_MODE3 = true; +var global4 = globalThis; +var issueWarning3; +if (DEV_MODE3) { + global4.litIssuedWarnings ??= new Set; + issueWarning3 = (code, warning) => { + warning += ` See https://lit.dev/msg/${code} for more information.`; + if (!global4.litIssuedWarnings.has(warning) && !global4.litIssuedWarnings.has(code)) { + console.warn(warning); + global4.litIssuedWarnings.add(warning); + } + }; +} + +class LitElement extends ReactiveElement { + constructor() { + super(...arguments); + this.renderOptions = { host: this }; + this.__childPart = undefined; + } + createRenderRoot() { + const renderRoot = super.createRenderRoot(); + this.renderOptions.renderBefore ??= renderRoot.firstChild; + return renderRoot; + } + update(changedProperties) { + const value = this.render(); + if (!this.hasUpdated) { + this.renderOptions.isConnected = this.isConnected; + } + super.update(changedProperties); + this.__childPart = render(value, this.renderRoot, this.renderOptions); + } + connectedCallback() { + super.connectedCallback(); + this.__childPart?.setConnected(true); + } + disconnectedCallback() { + super.disconnectedCallback(); + this.__childPart?.setConnected(false); + } + render() { + return noChange; + } +} +LitElement["_$litElement$"] = true; +LitElement[JSCompiler_renameProperty2("finalized", LitElement)] = true; +global4.litElementHydrateSupport?.({ LitElement }); +var polyfillSupport3 = DEV_MODE3 ? global4.litElementPolyfillSupportDevMode : global4.litElementPolyfillSupport; +polyfillSupport3?.({ LitElement }); +(global4.litElementVersions ??= []).push("4.2.2"); +if (DEV_MODE3 && global4.litElementVersions.length > 1) { + queueMicrotask(() => { + issueWarning3("multiple-versions", `Multiple versions of Lit loaded. Loading multiple versions ` + `is not recommended.`); + }); +} +// node_modules/@lit/reactive-element/development/decorators/property.js +var DEV_MODE4 = true; +var issueWarning4; +if (DEV_MODE4) { + globalThis.litIssuedWarnings ??= new Set; + issueWarning4 = (code, warning) => { + warning += ` See https://lit.dev/msg/${code} for more information.`; + if (!globalThis.litIssuedWarnings.has(warning) && !globalThis.litIssuedWarnings.has(code)) { + console.warn(warning); + globalThis.litIssuedWarnings.add(warning); + } + }; +} +var legacyProperty = (options, proto, name) => { + const hasOwnProperty = proto.hasOwnProperty(name); + proto.constructor.createProperty(name, options); + return hasOwnProperty ? Object.getOwnPropertyDescriptor(proto, name) : undefined; +}; +var defaultPropertyDeclaration2 = { + attribute: true, + type: String, + converter: defaultConverter, + reflect: false, + hasChanged: notEqual +}; +var standardProperty = (options = defaultPropertyDeclaration2, target, context) => { + const { kind, metadata } = context; + if (DEV_MODE4 && metadata == null) { + issueWarning4("missing-class-metadata", `The class ${target} is missing decorator metadata. This ` + `could mean that you're using a compiler that supports decorators ` + `but doesn't support decorator metadata, such as TypeScript 5.1. ` + `Please update your compiler.`); + } + let properties = globalThis.litPropertyMetadata.get(metadata); + if (properties === undefined) { + globalThis.litPropertyMetadata.set(metadata, properties = new Map); + } + if (kind === "setter") { + options = Object.create(options); + options.wrapped = true; + } + properties.set(context.name, options); + if (kind === "accessor") { + const { name } = context; + return { + set(v) { + const oldValue = target.get.call(this); + target.set.call(this, v); + this.requestUpdate(name, oldValue, options, true, v); + }, + init(v) { + if (v !== undefined) { + this._$changeProperty(name, undefined, options, v); + } + return v; + } + }; + } else if (kind === "setter") { + const { name } = context; + return function(value) { + const oldValue = this[name]; + target.call(this, value); + this.requestUpdate(name, oldValue, options, true, value); + }; + } + throw new Error(`Unsupported decorator location: ${kind}`); +}; +function property(options) { + return (protoOrTarget, nameOrContext) => { + return typeof nameOrContext === "object" ? standardProperty(options, protoOrTarget, nameOrContext) : legacyProperty(options, protoOrTarget, nameOrContext); + }; +} +// node_modules/@lit/reactive-element/development/decorators/state.js +function state(options) { + return property({ + ...options, + state: true, + attribute: false + }); +} +// node_modules/@lit/reactive-element/development/decorators/query.js +var DEV_MODE5 = true; +var issueWarning5; +if (DEV_MODE5) { + globalThis.litIssuedWarnings ??= new Set; + issueWarning5 = (code, warning) => { + warning += code ? ` See https://lit.dev/msg/${code} for more information.` : ""; + if (!globalThis.litIssuedWarnings.has(warning) && !globalThis.litIssuedWarnings.has(code)) { + console.warn(warning); + globalThis.litIssuedWarnings.add(warning); + } + }; +} +// src/constants.ts +var VERSION = "dev"; +var TIME_THRESHOLDS = { + SUNRISE_START: 360, + SUNRISE_END: 480, + DAY_END: 1080, + SUNSET_END: 1200 +}; +var TEMPLOW_ATTRIBUTES = [ + "templow", + "temperature_low", + "temp_low", + "min_temp", + "yandex_pogoda_minimal_forecast_temperature" +]; +var DEFAULT_CONFIG = { + showFeelsLike: true, + showWind: false, + showWindGust: false, + showWindDirection: false, + showHumidity: false, + showMinTemp: true, + showForecast: false, + showHourlyForecast: false, + showDailyForecast: false, + hourlyForecastHours: 5, + dailyForecastDays: 5, + showSunriseSunset: false, + showClock: false, + clockPosition: "top", + clockFormat: "24h", + overlayOpacity: 0.1, + language: "auto", + height: null, + windSpeedUnit: "ms" +}; +// src/internationalization/locales/ru/translation.json +var translation_default = { + sunny: "Солнечно", + clear: "Ясно", + overcast: "Пасмурно", + cloudy: "Облачно", + partlycloudy: "Переменная облачность", + rainy: "Дождь", + rain: "Дождь", + snowy: "Снег", + snow: "Снег", + foggy: "Туман", + fog: "Туман", + lightning: "Гроза", + "lightning-rainy": "Гроза с дождем", + pouring: "Сильный дождь", + "snowy-rainy": "Мокрый снег", + hail: "Град", + "clear-night": "Ясная ночь", + feels_like: "Ощущается как", + forecast_title: "Прогноз на сегодня", + daily_forecast_title: "Ежедневный прогноз", + no_data: "Нет данных", + forecast_unavailable: "Прогноз недоступен", + weather: "Погода", + language: "Language", + wind_unit_kmh: "км/ч", + wind_unit_ms: "м/с", + wind_unit_mph: "миль/ч", + wind_unit_knots: "узлы", + wind_unit_fts: "фут/с", + show_clock: "Показывать часы", + am: "ДП", + pm: "ПП", + editor: { + entity: "Погодная сущность", + name: "Название карточки", + height: "Высота карточки", + show_feels_like: "Показывать ощущаемую температуру", + show_wind: "Показывать скорость ветра", + show_wind_gust: "Показывать порывы ветра", + show_wind_direction: "Показывать направление ветра", + show_humidity: "Показывать влажность", + show_min_temp: "Показывать минимальную температуру", + show_hourly_forecast: "Показывать почасовой прогноз", + hourly_forecast_hours: "Часы прогноза", + show_daily_forecast: "Показывать дневной прогноз", + daily_forecast_days: "Дни прогноза", + show_sunrise_sunset: "Показывать восход/закат", + sunrise_entity: "Сущность восхода", + sunset_entity: "Сущность заката", + show_clock: "Показывать часы", + clock_position: "Позиция часов", + clock_position_top: "Вверху", + clock_position_details: "Детали", + clock_format: "Формат времени", + clock_format_12h: "12-часовой (AM/PM)", + clock_format_24h: "24-часовой", + overlay_opacity: "Прозрачность подложки", + language: "Язык", + language_auto: "Авто", + language_en: "Английский", + language_ru: "Русский", + language_de: "Немецкий", + language_nl: "Нидерландский", + language_fr: "Французский", + language_es: "Испанский", + language_it: "Итальянский", + language_sk: "Словацкий", + language_hu: "Венгерский", + wind_speed_unit: "Единицы скорости ветра", + wind_speed_unit_ms: "м/с", + wind_speed_unit_kmh: "км/ч" + }, + demo: { + pageTitle: "Динамическая карточка погоды", + pageSubtitle: "Интерактивная демонстрация и настройка", + livePreview: "Предпросмотр", + configuration: "Конфигурация", + quickPresets: "Быстрые пресеты", + sunnyDay: "Солнечный день", + rainy: "Дождь", + snowy: "Снег", + clearNight: "Ясная ночь", + weatherCondition: "Погодные условия", + condition: "Состояние", + temperature: "Температура", + humidity: "Влажность (%)", + windSpeed: "Скорость ветра", + timeOfDay: "Время суток", + timeMode: "Режим времени", + autoTime: "Авто (текущее время)", + manualControl: "Ручное управление", + sunrise: "Восход", + day: "День", + sunset: "Закат", + night: "Ночь", + currentTime: "Текущее время", + displayOptions: "Опции отображения", + cardName: "Название карточки", + height: "Высота (px)", + feelsLike: "Ощущается как", + minTemp: "Мин. температура", + windDirection: "Направление ветра", + windGust: "Порывы ветра", + hourlyForecast: "Почасовой прогноз", + dailyForecast: "Ежедневный прогноз", + sunriseSunset: "Восход/Закат", + showClock: "Часы", + clockPosition: "Позиция часов", + clockPositionTop: "Вверху справа", + clockPositionDetails: "В строке деталей", + clockFormat: "Формат часов", + clockFormat12h: "12-часовой (AM/PM)", + clockFormat24h: "24-часовой", + overlayOpacity: "Прозрачность подложки (0-1)", + windSpeedUnit: "Единицы скорости ветра", + dailyForecastDays: "Дни прогноза", + hourlyForecastHours: "Часы прогноза", + updateCard: "Обновить карточку", + startDemo: "Запустить демо", + stopDemo: "Остановить демо", + madeWith: "Сделано с любовью для Home Assistant", + loading: "Загрузка карточки...", + errorTitle: "Не удалось загрузить карточку", + errorDetails: "Проверьте консоль браузера (F12) для деталей", + errorServer: "Убедитесь, что файл открыт через локальный сервер (не file://)", + placeholderEmpty: "Оставьте пустым, чтобы скрыть", + weatherConditions: { + sunny: "Солнечно", + clear: "Ясно", + clearNight: "Ясная ночь", + partlyCloudy: "Переменная облачность", + cloudy: "Облачно", + rainy: "Дождь", + pouring: "Ливень", + snowy: "Снег", + sleet: "Мокрый снег", + hail: "Град", + foggy: "Туман", + lightning: "Гроза", + thunderstorm: "Гроза с дождем" + }, + language: { + title: "Язык", + english: "English", + russian: "Русский", + french: "Français", + german: "Deutsch", + dutch: "Nederlands", + spanish: "Español", + italian: "Italiano", + slovak: "Slovenčina", + hungarian: "Magyar" + } + } +}; +// src/internationalization/locales/de/translation.json +var translation_default2 = { + sunny: "Sonnig", + clear: "Klar", + overcast: "Bedeckt", + cloudy: "Bewölkt", + partlycloudy: "Teilweise bewölkt", + rainy: "Regnerisch", + rain: "Regen", + snowy: "Schneefall", + snow: "Schnee", + foggy: "Nebelig", + fog: "Nebel", + lightning: "Blitz", + "lightning-rainy": "Gewitter", + pouring: "Starkregen", + "snowy-rainy": "Schneeregen", + hail: "Hagel", + "clear-night": "Klare Nacht", + feels_like: "Gefühlt", + forecast_title: "Heutige Vorhersage", + daily_forecast_title: "Tagesvorhersage", + no_data: "Keine Daten", + forecast_unavailable: "Vorhersage nicht verfügbar", + weather: "Wetter", + language: "Sprache", + wind_unit_kmh: "km/h", + wind_unit_ms: "m/s", + wind_unit_mph: "mph", + wind_unit_knots: "Knoten", + wind_unit_fts: "ft/s", + show_clock: "Aktuelle Uhrzeit anzeigen", + am: "AM", + pm: "PM", + editor: { + entity: "Wetter-Entität", + name: "Kartentitel", + height: "Kartenhöhe", + show_feels_like: "Gefühlte Temperatur anzeigen", + show_wind: "Windgeschwindigkeit anzeigen", + show_wind_gust: "Windböen anzeigen", + show_wind_direction: "Windrichtung anzeigen", + show_humidity: "Luftfeuchtigkeit anzeigen", + show_min_temp: "Mindesttemperatur anzeigen", + show_hourly_forecast: "Stundenprognose anzeigen", + hourly_forecast_hours: "Stunden der Prognose", + show_daily_forecast: "Tagesprognose anzeigen", + daily_forecast_days: "Tage der Prognose", + show_sunrise_sunset: "Sonnenaufgang/Sonnenuntergang anzeigen", + sunrise_entity: "Sonnenaufgang-Entität", + sunset_entity: "Sonnenuntergang-Entität", + show_clock: "Uhr anzeigen", + clock_position: "Uhrposition", + clock_position_top: "Oben", + clock_position_details: "Details", + clock_format: "Zeitformat", + clock_format_12h: "12-Stunden (AM/PM)", + clock_format_24h: "24-Stunden", + overlay_opacity: "Überlagerungs-Transparenz", + language: "Sprache", + language_auto: "Automatisch", + language_en: "Englisch", + language_ru: "Russisch", + language_de: "Deutsch", + language_nl: "Niederländisch", + language_fr: "Französisch", + language_es: "Spanisch", + language_it: "Italienisch", + language_sk: "Slowakisch", + language_hu: "Ungarisch", + wind_speed_unit: "Einheit der Windgeschwindigkeit", + wind_speed_unit_ms: "m/s", + wind_speed_unit_kmh: "km/h" + }, + demo: { + pageTitle: "Dynamische Wetterkarte", + pageSubtitle: "Interaktive Demo & Konfiguration", + livePreview: "Live-Vorschau", + configuration: "Konfiguration", + quickPresets: "Schnellvorlagen", + sunnyDay: "Sonniger Tag", + rainy: "Regnerisch", + snowy: "Schnee", + clearNight: "Klare Nacht", + weatherCondition: "Wetterbedingungen", + condition: "Zustand", + temperature: "Temperatur", + humidity: "Luftfeuchtigkeit (%)", + windSpeed: "Windgeschwindigkeit", + timeOfDay: "Tageszeit", + timeMode: "Zeitmodus", + autoTime: "Automatisch (Aktuelle Zeit)", + manualControl: "Manuelle Steuerung", + sunrise: "Sonnenaufgang", + day: "Tag", + sunset: "Sonnenuntergang", + night: "Nacht", + currentTime: "Aktuelle Zeit", + displayOptions: "Anzeigeoptionen", + cardName: "Kartenname", + height: "Höhe (px)", + feelsLike: "Gefühlte Temperatur", + minTemp: "Mindesttemperatur", + windDirection: "Windrichtung", + windGust: "Windböen", + hourlyForecast: "Stündliche Vorhersage", + dailyForecast: "Tägliche Vorhersage", + sunriseSunset: "Sonnenaufgang / Sonnenuntergang", + showClock: "Uhr", + clockPosition: "Uhrposition", + clockPositionTop: "Oben rechts", + clockPositionDetails: "Detailzeile", + clockFormat: "Uhrzeitformat", + clockFormat12h: "12-Stunden (AM/PM)", + clockFormat24h: "24-Stunden", + overlayOpacity: "Überlagerungs-Transparenz (0-1)", + windSpeedUnit: "Windgeschwindigkeitseinheit", + dailyForecastDays: "Tage der Prognose", + hourlyForecastHours: "Stunden der Prognose", + updateCard: "Karte aktualisieren", + startDemo: "Demo starten", + stopDemo: "Demo stoppen", + madeWith: "Mit Liebe für Home Assistant gemacht", + loading: "Karte wird geladen...", + errorTitle: "Karte konnte nicht geladen werden", + errorDetails: "Überprüfe die Browser-Konsole (F12) für Details", + errorServer: "Stelle sicher, dass die Datei über einen lokalen Server geladen wird (nicht file://)", + placeholderEmpty: "Leer lassen, um auszublenden", + weatherConditions: { + sunny: "Sonnig", + clear: "Klar", + clearNight: "Klare Nacht", + partlyCloudy: "Teilweise bewölkt", + cloudy: "Bewölkt", + rainy: "Regen", + pouring: "Starkregen", + snowy: "Schnee", + sleet: "Schneeregen", + hail: "Hagel", + foggy: "Nebel", + lightning: "Blitz", + thunderstorm: "Gewitter" + }, + language: { + title: "Sprache", + english: "English", + russian: "Русский", + french: "Français", + german: "Deutsch", + dutch: "Nederlands", + spanish: "Español", + italian: "Italiano", + slovak: "Slovenčina", + hungarian: "Magyar" + } + } +}; +// src/internationalization/locales/nl/translation.json +var translation_default3 = { + sunny: "Zonnig", + clear: "Helder", + overcast: "Bewolkt", + cloudy: "Bewolkt", + partlycloudy: "Gedeeltelijk bewolkt", + rainy: "Regenachtig", + rain: "Regen", + snowy: "Sneeuwachtig", + snow: "Sneeuw", + foggy: "Mistig", + fog: "Mist", + lightning: "Bliksem", + "lightning-rainy": "Onweersbui", + pouring: "Zware regen", + "snowy-rainy": "Natte sneeuw", + hail: "Hagel", + "clear-night": "Heldere nacht", + feels_like: "Gevoelstemperatuur", + forecast_title: "Voorspelling van vandaag", + daily_forecast_title: "Dagelijkse voorspelling", + no_data: "Geen gegevens", + forecast_unavailable: "Voorspelling niet beschikbaar", + weather: "Weer", + language: "Taal", + wind_unit_kmh: "km/u", + wind_unit_ms: "m/s", + wind_unit_mph: "mph", + wind_unit_knots: "knots", + wind_unit_fts: "ft/s", + show_clock: "Huidige tijd weergeven", + am: "AM", + pm: "PM", + editor: { + entity: "Weer-entiteit", + name: "Kaarttitel", + height: "Kaart hoogte", + show_feels_like: "Gevoelstemperatuur tonen", + show_wind: "Windsnelheid tonen", + show_wind_gust: "Windstoten tonen", + show_wind_direction: "Windrichting tonen", + show_humidity: "Luchtvochtigheid tonen", + show_min_temp: "Minimumtemperatuur tonen", + show_hourly_forecast: "Uurverwachting tonen", + hourly_forecast_hours: "Aantal uren", + show_daily_forecast: "Dagverwachting tonen", + daily_forecast_days: "Aantal dagen", + show_sunrise_sunset: "Zonsopgang/zonsondergang tonen", + sunrise_entity: "Zonsopgang-entiteit", + sunset_entity: "Zonsondergang-entiteit", + show_clock: "Klok tonen", + clock_position: "Klokpositie", + clock_position_top: "Boven", + clock_position_details: "Details", + clock_format: "Tijdformaat", + clock_format_12h: "12-uurs (AM/PM)", + clock_format_24h: "24-uurs", + overlay_opacity: "Overlay-doorzichtigheid", + language: "Taal", + language_auto: "Automatisch", + language_en: "Engels", + language_ru: "Russisch", + language_de: "Duits", + language_nl: "Nederlands", + language_fr: "Frans", + language_es: "Spaans", + language_it: "Italiaans", + language_sk: "Slowaaks", + language_hu: "Hongaars", + wind_speed_unit: "Windsnelheidseenheid", + wind_speed_unit_ms: "m/s", + wind_speed_unit_kmh: "km/u" + }, + demo: { + pageTitle: "Dynamische Weerkaart", + pageSubtitle: "Interactieve demo & configuratietool", + livePreview: "Live voorbeeld", + configuration: "Configuratie", + quickPresets: "Snelle presets", + sunnyDay: "Zonnige dag", + rainy: "Regen", + snowy: "Sneeuw", + clearNight: "Heldere nacht", + weatherCondition: "Weersomstandigheden", + condition: "Conditie", + temperature: "Temperatuur", + humidity: "Luchtvochtigheid (%)", + windSpeed: "Windsnelheid", + timeOfDay: "Tijd van de dag", + timeMode: "Tijdmodus", + autoTime: "Automatisch (huidige tijd)", + manualControl: "Handmatige bediening", + sunrise: "Zonsopgang", + day: "Dag", + sunset: "Zonsondergang", + night: "Nacht", + currentTime: "Huidige tijd", + displayOptions: "Weergaveopties", + cardName: "Kaartnaam", + height: "Hoogte (px)", + feelsLike: "Gevoelstemperatuur", + minTemp: "Minimumtemperatuur", + windDirection: "Windrichting", + windGust: "Windstoten", + hourlyForecast: "Uurlijkse voorspelling", + dailyForecast: "Dagelijkse voorspelling", + sunriseSunset: "Zonsopgang / Zonsondergang", + showClock: "Klok", + clockPosition: "Klokpositie", + clockPositionTop: "Rechtsboven", + clockPositionDetails: "Detailregel", + clockFormat: "Klokformaat", + clockFormat12h: "12-uurs (AM/PM)", + clockFormat24h: "24-uurs", + overlayOpacity: "Overlay-transparantie (0-1)", + windSpeedUnit: "Windsnelheidseenheid", + dailyForecastDays: "Voorspellingsdagen", + hourlyForecastHours: "Voorspellingsuren", + updateCard: "Kaart bijwerken", + startDemo: "Demo starten", + stopDemo: "Demo stoppen", + madeWith: "Gemaakt met liefde voor Home Assistant", + loading: "Kaart laden...", + errorTitle: "Kan kaart niet laden", + errorDetails: "Controleer de browserconsole (F12) voor details", + errorServer: "Zorg ervoor dat het bestand via een lokale server wordt geladen (niet file://)", + placeholderEmpty: "Leeg laten om te verbergen", + weatherConditions: { + sunny: "Zonnig", + clear: "Helder", + clearNight: "Heldere nacht", + partlyCloudy: "Gedeeltelijk bewolkt", + cloudy: "Bewolkt", + rainy: "Regen", + pouring: "Zware regen", + snowy: "Sneeuw", + sleet: "Natte sneeuw", + hail: "Hagel", + foggy: "Mist", + lightning: "Bliksem", + thunderstorm: "Onweer" + }, + language: { + title: "Taal", + english: "English", + russian: "Русский", + french: "Français", + german: "Deutsch", + dutch: "Nederlands", + spanish: "Español", + italian: "Italiano", + slovak: "Slovenčina", + hungarian: "Magyar" + } + } +}; +// src/internationalization/locales/fr/translation.json +var translation_default4 = { + sunny: "Ensoleillé", + clear: "Dégagé", + overcast: "Couvert", + cloudy: "Nuageux", + partlycloudy: "Partiellement nuageux", + rainy: "Pluvieux", + rain: "Pluie", + snowy: "Neigeux", + snow: "Neige", + foggy: "Brumeux", + fog: "Brouillard", + lightning: "Éclairs", + "lightning-rainy": "Orage", + pouring: "Forte pluie", + "snowy-rainy": "Neige fondue", + hail: "Grêle", + "clear-night": "Nuit claire", + feels_like: "Ressenti", + forecast_title: "Prévisions du jour", + daily_forecast_title: "Prévisions quotidiennes", + no_data: "Aucune donnée", + forecast_unavailable: "Prévisions non disponibles", + weather: "Météo", + language: "Langue", + wind_unit_kmh: "km/h", + wind_unit_ms: "m/s", + wind_unit_mph: "mph", + wind_unit_knots: "knots", + wind_unit_fts: "ft/s", + show_clock: "Afficher l'heure actuelle", + am: "AM", + pm: "PM", + editor: { + entity: "Entité météo", + name: "Titre de la carte", + height: "Hauteur de la carte", + show_feels_like: "Afficher le ressenti", + show_wind: "Afficher la vitesse du vent", + show_wind_gust: "Afficher les rafales", + show_wind_direction: "Afficher la direction du vent", + show_humidity: "Afficher l'humidité", + show_min_temp: "Afficher la température minimale", + show_hourly_forecast: "Afficher la prévision horaire", + hourly_forecast_hours: "Heures de prévision", + show_daily_forecast: "Afficher la prévision quotidienne", + daily_forecast_days: "Jours de prévision", + show_sunrise_sunset: "Afficher lever/coucher du soleil", + sunrise_entity: "Entité de lever du soleil", + sunset_entity: "Entité de coucher du soleil", + show_clock: "Afficher l'horloge", + clock_position: "Position de l'horloge", + clock_position_top: "En haut", + clock_position_details: "Détails", + clock_format: "Format de l'heure", + clock_format_12h: "12 heures (AM/PM)", + clock_format_24h: "24 heures", + overlay_opacity: "Opacité du voile", + language: "Langue", + language_auto: "Auto", + language_en: "Anglais", + language_ru: "Russe", + language_de: "Allemand", + language_nl: "Néerlandais", + language_fr: "Français", + language_es: "Espagnol", + language_it: "Italien", + language_sk: "Slovaque", + language_hu: "Hongrois", + wind_speed_unit: "Unité de vitesse du vent", + wind_speed_unit_ms: "m/s", + wind_speed_unit_kmh: "km/h" + }, + demo: { + pageTitle: "Carte Météo Dynamique", + pageSubtitle: "Démo Interactive & Outil de Configuration", + livePreview: "Aperçu en direct", + configuration: "Configuration", + quickPresets: "Pré-réglages rapides", + sunnyDay: "Journée ensoleillée", + rainy: "Pluvieux", + snowy: "Neigeux", + clearNight: "Nuit claire", + weatherCondition: "Condition météo", + condition: "Condition", + temperature: "Température", + humidity: "Humidité (%)", + windSpeed: "Vitesse du vent", + timeOfDay: "Moment de la journée", + timeMode: "Mode horaire", + autoTime: "Auto (heure actuelle)", + manualControl: "Contrôle manuel", + sunrise: "Lever du soleil", + day: "Jour", + sunset: "Coucher du soleil", + night: "Nuit", + currentTime: "Heure actuelle", + displayOptions: "Options d'affichage", + cardName: "Nom de la carte", + height: "Hauteur (px)", + feelsLike: "Température ressentie", + minTemp: "Température minimale", + windDirection: "Direction du vent", + windGust: "Rafales de vent", + hourlyForecast: "Prévisions horaires", + dailyForecast: "Prévisions quotidiennes", + sunriseSunset: "Lever/Coucher du soleil", + showClock: "Horloge", + clockPosition: "Position de l'horloge", + clockPositionTop: "En haut à droite", + clockPositionDetails: "Ligne de détails", + clockFormat: "Format de l'horloge", + clockFormat12h: "12 heures (AM/PM)", + clockFormat24h: "24 heures", + overlayOpacity: "Opacité du voile (0-1)", + windSpeedUnit: "Unité de vitesse du vent", + dailyForecastDays: "Jours de prévision", + hourlyForecastHours: "Heures de prévision", + updateCard: "Mettre à jour la carte", + startDemo: "Démarrer le mode démo", + stopDemo: "Arrêter la démo", + madeWith: "Fait avec amour pour Home Assistant", + loading: "Chargement de la carte...", + errorTitle: "Échec du chargement de la carte", + errorDetails: "Vérifiez la console du navigateur (F12) pour plus de détails", + errorServer: "Assurez-vous que le fichier est servi via un serveur local (pas file://)", + placeholderEmpty: "Laisser vide pour masquer", + weatherConditions: { + sunny: "Ensoleillé", + clear: "Dégagé", + clearNight: "Nuit claire", + partlyCloudy: "Partiellement nuageux", + cloudy: "Nuageux", + rainy: "Pluvieux", + pouring: "Forte pluie", + snowy: "Neigeux", + sleet: "Neige fondue", + hail: "Grêle", + foggy: "Brumeux", + lightning: "Éclairs", + thunderstorm: "Orage" + }, + language: { + title: "Langue", + english: "English", + russian: "Русский", + french: "Français", + german: "Deutsch", + dutch: "Nederlands", + spanish: "Español", + italian: "Italiano", + slovak: "Slovenčina", + hungarian: "Magyar" + } + } +}; +// src/internationalization/locales/en/translation.json +var translation_default5 = { + sunny: "Sunny", + clear: "Clear", + overcast: "Overcast", + cloudy: "Cloudy", + partlycloudy: "Partly Cloudy", + rainy: "Rainy", + rain: "Rain", + snowy: "Snowy", + snow: "Snow", + foggy: "Foggy", + fog: "Fog", + lightning: "Lightning", + "lightning-rainy": "Thunderstorm", + pouring: "Heavy Rain", + "snowy-rainy": "Sleet", + hail: "Hail", + "clear-night": "Clear Night", + feels_like: "Feels like", + forecast_title: "Today's Forecast", + daily_forecast_title: "Daily's Forecast", + no_data: "No data", + forecast_unavailable: "Forecast unavailable", + weather: "Weather", + language: "Language", + wind_unit_kmh: "km/h", + wind_unit_ms: "m/s", + wind_unit_mph: "mph", + wind_unit_knots: "knots", + wind_unit_fts: "ft/s", + show_clock: "Show current time", + am: "AM", + pm: "PM", + editor: { + entity: "Weather Entity", + name: "Card Title", + height: "Card Height", + show_feels_like: "Show Feels Like", + show_wind: "Show Wind Speed", + show_wind_gust: "Show Wind Gust", + show_wind_direction: "Show Wind Direction", + show_humidity: "Show Humidity", + show_min_temp: "Show Min Temperature", + show_hourly_forecast: "Show Hourly Forecast", + hourly_forecast_hours: "Hourly Forecast Hours", + show_daily_forecast: "Show Daily Forecast", + daily_forecast_days: "Daily Forecast Days", + show_sunrise_sunset: "Show Sunrise/Sunset", + sunrise_entity: "Sunrise Entity", + sunset_entity: "Sunset Entity", + show_clock: "Show Clock", + clock_position: "Clock Position", + clock_position_top: "Top", + clock_position_details: "Details", + clock_format: "Clock Format", + clock_format_12h: "12-hour (AM/PM)", + clock_format_24h: "24-hour", + overlay_opacity: "Overlay Opacity", + language: "Language", + language_auto: "Auto", + language_en: "English", + language_ru: "Russian", + language_de: "German", + language_nl: "Dutch", + language_fr: "French", + language_es: "Spanish", + language_it: "Italian", + language_sk: "Slovak", + language_hu: "Hungarian", + wind_speed_unit: "Wind Speed Unit", + wind_speed_unit_ms: "m/s", + wind_speed_unit_kmh: "km/h" + }, + demo: { + pageTitle: "Dynamic Weather Card", + pageSubtitle: "Interactive Demo & Configuration Tool", + livePreview: "Live Preview", + configuration: "Configuration", + quickPresets: "Quick Presets", + sunnyDay: "Sunny Day", + rainy: "Rainy", + snowy: "Snowy", + clearNight: "Clear Night", + weatherCondition: "Weather Condition", + condition: "Condition", + temperature: "Temperature", + humidity: "Humidity (%)", + windSpeed: "Wind Speed", + timeOfDay: "Time of Day", + timeMode: "Time Mode", + autoTime: "Auto (Current Time)", + manualControl: "Manual Control", + sunrise: "Sunrise", + day: "Day", + sunset: "Sunset", + night: "Night", + currentTime: "Current Time", + displayOptions: "Display Options", + cardName: "Card Name", + height: "Height (px)", + feelsLike: "Feels Like Temperature", + minTemp: "Min Temperature", + windDirection: "Wind Direction", + windGust: "Wind Gust", + hourlyForecast: "Hourly Forecast", + dailyForecast: "Daily Forecast", + sunriseSunset: "Sunrise/Sunset", + showClock: "Clock", + clockPosition: "Clock Position", + clockPositionTop: "Top right", + clockPositionDetails: "Details row", + clockFormat: "Clock Format", + clockFormat12h: "12-hour (AM/PM)", + clockFormat24h: "24-hour", + overlayOpacity: "Overlay Opacity (0-1)", + windSpeedUnit: "Wind Speed Unit", + dailyForecastDays: "Daily Forecast Days", + hourlyForecastHours: "Hourly Forecast Hours", + updateCard: "Update Card", + startDemo: "Start Demo Mode", + stopDemo: "Stop Demo", + madeWith: "Made with love for Home Assistant", + loading: "Loading card...", + errorTitle: "Failed to load card", + errorDetails: "Check the browser console (F12) for details", + errorServer: "Make sure the file is served via a local server (not file://)", + placeholderEmpty: "Leave empty to hide", + weatherConditions: { + sunny: "Sunny", + clear: "Clear", + clearNight: "Clear Night", + partlyCloudy: "Partly Cloudy", + cloudy: "Cloudy", + rainy: "Rainy", + pouring: "Pouring", + snowy: "Snowy", + sleet: "Sleet", + hail: "Hail", + foggy: "Foggy", + lightning: "Lightning", + thunderstorm: "Thunderstorm" + }, + language: { + title: "Language", + english: "English", + russian: "Russian", + french: "French", + german: "German", + dutch: "Dutch", + spanish: "Spanish", + italian: "Italian", + slovak: "Slovak", + hungarian: "Magyar" + } + } +}; +// src/internationalization/locales/es/translation.json +var translation_default6 = { + sunny: "Soleado", + clear: "Despejado", + overcast: "Cubierto", + cloudy: "Nublado", + partlycloudy: "Parcialmente Nublado", + rainy: "Lluvioso", + rain: "Lluvia", + snowy: "Nevado", + snow: "Nieve", + foggy: "Nublado", + fog: "Niebla", + lightning: "Rayo", + "lightning-rainy": "Tormenta Eléctrica", + pouring: "Lluvia Intensa", + "snowy-rainy": "Aguanieve", + hail: "Granizo", + "clear-night": "Noche Despejada", + feels_like: "Sensación térmica", + forecast_title: "Previsión para hoy", + daily_forecast_title: "Previsión Diaria", + no_data: "Sin datos", + forecast_unavailable: "Previsión no disponible", + weather: "Clima", + language: "Idioma", + wind_unit_kmh: "km/h", + wind_unit_ms: "m/s", + wind_unit_mph: "mph", + wind_unit_knots: "knots", + wind_unit_fts: "ft/s", + show_clock: "Mostrar hora actual", + am: "AM", + pm: "PM", + editor: { + entity: "Entidad de clima", + name: "Título de la tarjeta", + height: "Altura de la tarjeta", + show_feels_like: "Mostrar sensación térmica", + show_wind: "Mostrar velocidad del viento", + show_wind_gust: "Mostrar ráfaga de viento", + show_wind_direction: "Mostrar dirección del viento", + show_humidity: "Mostrar humedad", + show_min_temp: "Mostrar temperatura mínima", + show_hourly_forecast: "Mostrar pronóstico por horas", + hourly_forecast_hours: "Horas del pronóstico", + show_daily_forecast: "Mostrar pronóstico diario", + daily_forecast_days: "Días del pronóstico", + show_sunrise_sunset: "Mostrar amanecer/atardecer", + sunrise_entity: "Entidad de amanecer", + sunset_entity: "Entidad de atardecer", + show_clock: "Mostrar reloj", + clock_position: "Posición del reloj", + clock_position_top: "Arriba", + clock_position_details: "Detalles", + clock_format: "Formato de hora", + clock_format_12h: "12 horas (AM/PM)", + clock_format_24h: "24 horas", + overlay_opacity: "Opacidad de superposición", + language: "Idioma", + language_auto: "Automático", + language_en: "Inglés", + language_ru: "Ruso", + language_de: "Alemán", + language_nl: "Neerlandés", + language_fr: "Francés", + language_es: "Español", + language_it: "Italiano", + language_sk: "Eslovaco", + language_hu: "Húngaro", + wind_speed_unit: "Unidad de velocidad del viento", + wind_speed_unit_ms: "m/s", + wind_speed_unit_kmh: "km/h" + }, + demo: { + pageTitle: "Tarjeta Meteorológica Dinámica", + pageSubtitle: "Demostración interactiva y Herramienta de Configuración", + livePreview: "Vista previa en vivo", + configuration: "Configuración", + quickPresets: "Ajustes Rápidos", + sunnyDay: "Día soleado", + rainy: "Lluvioso", + snowy: "Nevado", + clearNight: "Noche despejada", + weatherCondition: "Condiciones Meteorológicas", + condition: "Condición", + temperature: "Temperatura", + humidity: "Humedad (%)", + windSpeed: "Velocidad del Viento", + timeOfDay: "Hora del Día", + timeMode: "Modo Tiempo", + autoTime: "Auto (Hora Actual)", + manualControl: "Control Manual", + sunrise: "Amanecer", + day: "Día", + sunset: "Atardecer", + night: "Noche", + currentTime: "Hora Actual", + displayOptions: "Opciones de Visualización", + cardName: "Nombre de la tarjeta", + height: "Altura (px)", + feelsLike: "Sensación Térmica", + minTemp: "Temperatura Mínima", + windDirection: "Dirección del Viento", + windGust: "Ráfaga de Viento", + hourlyForecast: "Previsión por Horas", + dailyForecast: "Previsión Diaria", + sunriseSunset: "Amanecer/Atardecer", + showClock: "Reloj", + clockPosition: "Posición del Reloj", + clockPositionTop: "Arriba a la derecha", + clockPositionDetails: "Línea de detalles", + clockFormat: "Formato del Reloj", + clockFormat12h: "12 horas (AM/PM)", + clockFormat24h: "24 horas", + overlayOpacity: "Opacidad de Superposición (0-1)", + windSpeedUnit: "Unidad de Velocidad del Viento", + dailyForecastDays: "Días de Previsión", + hourlyForecastHours: "Horas de Previsión", + updateCard: "Actualizar Tarjeta", + startDemo: "Iniciar Modo Demostración", + stopDemo: "Detener Demostración", + madeWith: "Hecho con amor para Home Assistant", + loading: "Cargando tarjeta...", + errorTitle: "No se pudo cargar la tarjeta", + errorDetails: "Consulte la consola del navegador (F12) para obtener más detalles", + errorServer: "Asegúrese de que el archivo se sirve a través de un servidor local (no file://)", + placeholderEmpty: "Deje vacío para ocultar", + weatherConditions: { + sunny: "Soleado", + clear: "Despejado", + clearNight: "Noche Despejada", + partlyCloudy: "Parcialmente Nublado", + cloudy: "Nublado", + rainy: "Lluvioso", + pouring: "Torrencial", + snowy: "Nevado", + sleet: "Aguanieve", + hail: "Granizo", + foggy: "Nublado", + lightning: "Rayos", + thunderstorm: "Tormenta Eléctrica" + }, + language: { + title: "Idioma", + english: "English", + russian: "Русский", + french: "Français", + german: "Deutsch", + dutch: "Nederlands", + spanish: "Español", + italian: "Italiano", + slovak: "Slovenčina", + hungarian: "Magyar" + } + } +}; +// src/internationalization/locales/it/translation.json +var translation_default7 = { + sunny: "Soleggiato", + clear: "Sereno", + overcast: "Coperto", + cloudy: "Nuvoloso", + partlycloudy: "Parzialmente Nuvoloso", + rainy: "Piovoso", + rain: "Pioggia", + snowy: "Nevoso", + snow: "Neve", + foggy: "Nebbia", + fog: "Nebbia", + lightning: "Fulmine", + "lightning-rainy": "Temporale", + pouring: "Pioggia Intensa", + "snowy-rainy": "Nevischio", + hail: "Grandine", + "clear-night": "Notte Serena", + feels_like: "Percepita", + forecast_title: "Previsioni di oggi", + daily_forecast_title: "Previsioni Giornaliere", + no_data: "Nessun dato", + forecast_unavailable: "Previsioni non disponibili", + weather: "Meteo", + language: "Lingua", + wind_unit_kmh: "km/h", + wind_unit_ms: "m/s", + wind_unit_mph: "mph", + wind_unit_knots: "knots", + wind_unit_fts: "ft/s", + show_clock: "Mostra ora corrente", + am: "AM", + pm: "PM", + editor: { + entity: "Entità meteo", + name: "Titolo della scheda", + height: "Altezza della scheda", + show_feels_like: "Mostra temperatura percepita", + show_wind: "Mostra velocità del vento", + show_wind_gust: "Mostra raffiche di vento", + show_wind_direction: "Mostra direzione del vento", + show_humidity: "Mostra umidità", + show_min_temp: "Mostra temperatura minima", + show_hourly_forecast: "Mostra previsione oraria", + hourly_forecast_hours: "Ore di previsione", + show_daily_forecast: "Mostra previsione giornaliera", + daily_forecast_days: "Giorni di previsione", + show_sunrise_sunset: "Mostra alba/tramonto", + sunrise_entity: "Entità alba", + sunset_entity: "Entità tramonto", + show_clock: "Mostra orologio", + clock_position: "Posizione orologio", + clock_position_top: "In alto", + clock_position_details: "Dettagli", + clock_format: "Formato orario", + clock_format_12h: "12 ore (AM/PM)", + clock_format_24h: "24 ore", + overlay_opacity: "Opacità sovrapposizione", + language: "Lingua", + language_auto: "Auto", + language_en: "Inglese", + language_ru: "Russo", + language_de: "Tedesco", + language_nl: "Olandese", + language_fr: "Francese", + language_es: "Spagnolo", + language_it: "Italiano", + language_sk: "Slovacco", + language_hu: "Ungherese", + wind_speed_unit: "Unità velocità del vento", + wind_speed_unit_ms: "m/s", + wind_speed_unit_kmh: "km/h" + }, + demo: { + pageTitle: "Dynamic Weather Card", + pageSubtitle: "Demo interattiva & Strumento di configurazione", + livePreview: "Anteprima live", + configuration: "Configurazione", + quickPresets: "Preset veloci", + sunnyDay: "Giornata Soleggiata", + rainy: "Piovoso", + snowy: "Nevoso", + clearNight: "Notte Serena", + weatherCondition: "Condizione Meteo", + condition: "Condizione", + temperature: "Temperatura", + humidity: "Umidità (%)", + windSpeed: "Velocità del Vento", + timeOfDay: "Momento della giornata", + timeMode: "Modalità ora", + autoTime: "Automatico (Ora corrente)", + manualControl: "Controllo manuale", + sunrise: "Alba", + day: "Giorno", + sunset: "Tramonto", + night: "Notte", + currentTime: "Ora corrente", + displayOptions: "Opzioni di visualizzazione", + cardName: "Nome della card", + height: "Altezza (px)", + feelsLike: "Temperatura percepita", + minTemp: "Temperatura minima", + windDirection: "Direzione del vento", + windGust: "Raffiche di vento", + hourlyForecast: "Previsioni orarie", + dailyForecast: "Previsioni giornaliere", + sunriseSunset: "Alba/Tramonto", + showClock: "Orologio", + clockPosition: "Posizione Orologio", + clockPositionTop: "In alto a destra", + clockPositionDetails: "Riga dettagli", + clockFormat: "Formato Orologio", + clockFormat12h: "12 ore (AM/PM)", + clockFormat24h: "24 ore", + overlayOpacity: "Opacità Sovrapposizione (0-1)", + windSpeedUnit: "Unità Velocità Vento", + dailyForecastDays: "Giorni di Previsione", + hourlyForecastHours: "Ore di Previsione", + updateCard: "Aggiorna card", + startDemo: "Avvia Demo", + stopDemo: "Ferma Demo", + madeWith: "Creato con amore per Home Assistant", + loading: "Caricamento card...", + errorTitle: "Impossibile caricare la card", + errorDetails: "Controlla la console del browser (F12) per i dettagli", + errorServer: "Assicurati che il file sia servito tramite server locale (non file://)", + placeholderEmpty: "Lascia vuoto per nascondere", + weatherConditions: { + sunny: "Soleggiato", + clear: "Sereno", + clearNight: "Notte Serena", + partlyCloudy: "Parzialmente Nuvoloso", + cloudy: "Nuvoloso", + rainy: "Piovoso", + pouring: "Pioggia Intensa", + snowy: "Nevoso", + sleet: "Nevischio", + hail: "Grandine", + foggy: "Nebbia", + lightning: "Fulmine", + thunderstorm: "Temporale" + }, + language: { + title: "Lingua", + english: "English", + russian: "Русский", + french: "Français", + german: "Deutsch", + dutch: "Nederlands", + spanish: "Español", + italian: "Italiano", + slovak: "Slovenčina", + hungarian: "Magyar" + } + } +}; +// src/internationalization/locales/sk/translation.json +var translation_default8 = { + sunny: "Slnečno", + clear: "Jasno", + overcast: "Zamračené", + cloudy: "Oblačno", + partlycloudy: "Polooblačno", + rainy: "Daždivo", + rain: "Dážď", + snowy: "Sneženie", + snow: "Sneh", + foggy: "Hmlisto", + fog: "Hmla", + lightning: "Blesky", + "lightning-rainy": "Búrka", + pouring: "Silný dážď", + "snowy-rainy": "Dážď so snehom", + hail: "Krúpy", + "clear-night": "Jasná noc", + feels_like: "Pocitová teplota", + forecast_title: "Predpoveď na dnes", + daily_forecast_title: "Denná predpoveď", + no_data: "Žiadne dáta", + forecast_unavailable: "Predpoveď nedostupná", + weather: "Počasie", + language: "Jazyk", + wind_unit_kmh: "km/h", + wind_unit_ms: "m/s", + wind_unit_mph: "mph", + wind_unit_knots: "uzly", + wind_unit_fts: "ft/s", + show_clock: "Zobraziť aktuálny čas", + am: "dop.", + pm: "pop.", + editor: { + entity: "Entita počasia", + name: "Názov karty", + height: "Výška karty", + show_feels_like: "Zobraziť pocitovú teplotu", + show_wind: "Zobraziť rýchlosť vetra", + show_wind_gust: "Zobraziť nárazy vetra", + show_wind_direction: "Zobraziť smer vetra", + show_humidity: "Zobraziť vlhkosť", + show_min_temp: "Zobraziť minimálnu teplotu", + show_hourly_forecast: "Zobraziť hodinovú predpoveď", + hourly_forecast_hours: "Počet hodín v predpovedi", + show_daily_forecast: "Zobraziť dennú predpoveď", + daily_forecast_days: "Počet dní v predpovedi", + show_sunrise_sunset: "Zobraziť východ/západ slnka", + sunrise_entity: "Entita východu slnka", + sunset_entity: "Entita západu slnka", + show_clock: "Zobraziť hodiny", + clock_position: "Pozícia hodín", + clock_position_top: "Hore", + clock_position_details: "V detailoch", + clock_format: "Formát času", + clock_format_12h: "12-hodinový (AM/PM)", + clock_format_24h: "24-hodinový", + overlay_opacity: "Priehľadnosť vrstvy", + language: "Jazyk", + language_auto: "Automaticky", + language_en: "Angličtina", + language_ru: "Ruština", + language_de: "Nemčina", + language_nl: "Holandčina", + language_fr: "Francúzština", + language_es: "Španielčina", + language_it: "Taliančina", + language_sk: "Slovenčina", + language_hu: "Maďarčina", + wind_speed_unit: "Jednotka rýchlosti vetra", + wind_speed_unit_ms: "m/s", + wind_speed_unit_kmh: "km/h" + }, + demo: { + pageTitle: "Dynamická karta počasia", + pageSubtitle: "Interaktívne demo a konfiguračný nástroj", + livePreview: "Živý náhľad", + configuration: "Konfigurácia", + quickPresets: "Rýchle predvoľby", + sunnyDay: "Slnečný deň", + rainy: "Daždivo", + snowy: "Sneženie", + clearNight: "Jasná noc", + weatherCondition: "Poveternostné podmienky", + condition: "Stav", + temperature: "Teplota", + humidity: "Vlhkosť (%)", + windSpeed: "Rýchlosť vetra", + timeOfDay: "Čas dňa", + timeMode: "Režim času", + autoTime: "Automaticky (Aktuálny čas)", + manualControl: "Manuálne ovládanie", + sunrise: "Východ slnka", + day: "Deň", + sunset: "Západ slnka", + night: "Noc", + currentTime: "Aktuálny čas", + displayOptions: "Možnosti zobrazenia", + cardName: "Názov karty", + height: "Výška (px)", + feelsLike: "Pocitová teplota", + minTemp: "Minimálna teplota", + windDirection: "Smer vetra", + windGust: "Nárazy vetra", + hourlyForecast: "Hodinová predpoveď", + dailyForecast: "Denná predpoveď", + sunriseSunset: "Východ/Západ slnka", + showClock: "Hodiny", + clockPosition: "Pozícia hodín", + clockPositionTop: "Vpravo hore", + clockPositionDetails: "Riadok s detailmi", + clockFormat: "Formát času", + clockFormat12h: "12-hodinový (AM/PM)", + clockFormat24h: "24-hodinový", + overlayOpacity: "Priehľadnosť vrstvy (0-1)", + windSpeedUnit: "Jednotka rýchlosti vetra", + dailyForecastDays: "Dni dennej predpovede", + hourlyForecastHours: "Hodiny hodinovej predpovede", + updateCard: "Aktualizovať kartu", + startDemo: "Spustiť Demo režim", + stopDemo: "Zastaviť Demo", + madeWith: "Vytvorené s láskou pre Home Assistant", + loading: "Načítavam kartu...", + errorTitle: "Nepodarilo sa načítať kartu", + errorDetails: "Skontrolujte konzolu prehliadača (F12) pre detaily", + errorServer: "Uistite sa, že súbor je poskytovaný cez lokálny server (nie cez file://)", + placeholderEmpty: "Ponechajte prázdne pre skrytie", + weatherConditions: { + sunny: "Slnečno", + clear: "Jasno", + clearNight: "Jasná noc", + partlyCloudy: "Polooblačno", + cloudy: "Oblačno", + rainy: "Daždivo", + pouring: "Lejak", + snowy: "Sneženie", + sleet: "Dážď so snehom", + hail: "Krúpy", + foggy: "Hmla", + lightning: "Blesky", + thunderstorm: "Búrka" + }, + language: { + title: "Jazyk", + english: "English", + russian: "Русский", + french: "Français", + german: "Deutsch", + dutch: "Nederlands", + spanish: "Español", + italian: "Italiano", + slovak: "Slovenčina", + hungarian: "Magyar" + } + } +}; +// src/internationalization/locales/hu/translation.json +var translation_default9 = { + sunny: "Napos", + clear: "Derült", + overcast: "Borult", + cloudy: "Felhős", + partlycloudy: "Részben felhős", + rainy: "Esős", + rain: "Eső", + snowy: "Havas", + snow: "Hó", + foggy: "Ködös", + fog: "Köd", + lightning: "Villámlás", + "lightning-rainy": "Zivatar", + pouring: "Heves eső", + "snowy-rainy": "Havas eső", + hail: "Jégeső", + "clear-night": "Derült éj", + feels_like: "Hőérzet", + forecast_title: "Mai előrejelzés", + daily_forecast_title: "Napi előrejelzés", + no_data: "Nincs adat", + forecast_unavailable: "Előrejelzés nem elérhető", + weather: "Időjárás", + language: "Nyelv", + wind_unit_kmh: "km/h", + wind_unit_ms: "m/s", + wind_unit_mph: "mph", + wind_unit_knots: "csomó", + wind_unit_fts: "ft/s", + show_clock: "Aktuális idő mutatása", + am: "DE", + pm: "DU", + editor: { + entity: "Időjárás entitás", + name: "Kártya címe", + height: "Kártya magasság", + show_feels_like: "Hőérzet mutatása", + show_wind: "Szélsebesség mutatása", + show_wind_gust: "Széllökések mutatása", + show_wind_direction: "Szélirány mutatása", + show_humidity: "Páratartalom mutatása", + show_min_temp: "Min. hőmérséklet", + show_hourly_forecast: "Óránkénti előrejelzés", + hourly_forecast_hours: "Óránkénti órák száma", + show_daily_forecast: "Napi előrejelzés", + daily_forecast_days: "Napok száma a napi előrejelzésben", + show_sunrise_sunset: "Napkelte/Napnyugta", + sunrise_entity: "Napkelte entitás", + sunset_entity: "Napnyugta entitás", + show_clock: "Óra mutatása", + clock_position: "Óra pozíció", + clock_position_top: "Felül", + clock_position_details: "Részletek", + clock_format: "Óra formátum", + clock_format_12h: "12 órás (DE/DU)", + clock_format_24h: "24 órás", + overlay_opacity: "Fedőréteg átlátszóság", + language: "Nyelv", + language_auto: "Automatikus", + language_en: "Angol", + language_ru: "Orosz", + language_de: "Német", + language_nl: "Holland", + language_fr: "Francia", + language_es: "Spanyol", + language_it: "Olasz", + language_hu: "Magyar", + language_sk: "Szlovák", + wind_speed_unit: "Szélsebesség egység", + wind_speed_unit_ms: "m/s", + wind_speed_unit_kmh: "km/h" + }, + demo: { + pageTitle: "Dynamic Weather Card", + pageSubtitle: "Interaktív demó és beállító eszköz", + livePreview: "Élő előnézet", + configuration: "Beállítások", + quickPresets: "Gyors presetek", + sunnyDay: "Napos nap", + rainy: "Esős", + snowy: "Havas", + clearNight: "Derült éj", + weatherCondition: "Időjárási állapot", + condition: "Állapot", + temperature: "Hőmérséklet", + humidity: "Páratartalom (%)", + windSpeed: "Szélsebesség", + timeOfDay: "Napszak", + timeMode: "Idő mód", + autoTime: "Automatikus (aktuális idő)", + manualControl: "Kézi vezérlés", + sunrise: "Napkelte", + day: "Nappal", + sunset: "Napnyugta", + night: "Éjszaka", + currentTime: "Aktuális idő", + displayOptions: "Megjelenítés", + cardName: "Kártya neve", + height: "Magasság (px)", + feelsLike: "Hőérzet", + minTemp: "Min. hőmérséklet", + windDirection: "Szélirány", + windGust: "Széllökés", + hourlyForecast: "Óránkénti előrejelzés", + dailyForecast: "Napi előrejelzés", + sunriseSunset: "Napkelte/Napnyugta", + showClock: "Óra", + clockPosition: "Óra pozíció", + clockPositionTop: "Jobb felső", + clockPositionDetails: "Részletek sora", + clockFormat: "Óra formátum", + clockFormat12h: "12 órás (DE/DU)", + clockFormat24h: "24 órás", + overlayOpacity: "Fedőréteg átlátszóság (0–1)", + windSpeedUnit: "Szélsebesség egység", + dailyForecastDays: "Napi napok", + hourlyForecastHours: "Óránkénti órák", + updateCard: "Kártya frissítése", + startDemo: "Demó indítása", + stopDemo: "Demó leállítása", + madeWith: "Szeretettel a Home Assistanthez", + loading: "Kártya betöltése…", + errorTitle: "Nem sikerült betölteni", + errorDetails: "Részletek a böngésző konzolban (F12)", + errorServer: "A fájlt helyi szerveren szolgáld ki (nem file://)", + placeholderEmpty: "Üresen hagyva elrejt", + weatherConditions: { + sunny: "Napos", + clear: "Derült", + clearNight: "Derült éj", + partlyCloudy: "Részben felhős", + cloudy: "Felhős", + rainy: "Esős", + pouring: "Zuhogó eső", + snowy: "Havas", + sleet: "Havas eső", + hail: "Jégeső", + foggy: "Ködös", + lightning: "Villámlás", + thunderstorm: "Zivatar" + }, + language: { + title: "Nyelv", + english: "Angol", + russian: "Orosz", + french: "Francia", + german: "Német", + dutch: "Holland", + spanish: "Spanyol", + italian: "Olasz", + hungarian: "Magyar", + slovak: "Slovenčina" + } + } +}; + +// src/internationalization/index.ts +var translations = { + en: translation_default5, + ru: translation_default, + de: translation_default2, + nl: translation_default3, + fr: translation_default4, + es: translation_default6, + it: translation_default7, + sk: translation_default8, + hu: translation_default9 +}; + +class I18n { + lang = "en"; + fallback = "en"; + t(key) { + const path = key.split("."); + const fromCurrent = path.reduce((o, k) => o?.[k], translations[this.lang]); + if (fromCurrent != null) + return fromCurrent; + const fromFallback = path.reduce((o, k) => o?.[k], translations[this.fallback]); + return fromFallback ?? key; + } + setLanguage(lang) { + if (!translations[lang] || this.lang === lang) + return; + this.lang = lang; + window.dispatchEvent(new CustomEvent("language-changed")); + } +} +var i18n = new I18n; +window.i18n = i18n; + +// src/internationalization/resolveLanguage.ts +var resolveLanguage = ({ configLang, hassLang } = {}) => { + if (configLang && configLang !== "auto") + return configLang; + if (hassLang) + return hassLang; + if (typeof navigator !== "undefined" && navigator.language) { + const lang = navigator.language.toLowerCase(); + if (lang.startsWith("ru")) + return "ru"; + if (lang.startsWith("de")) + return "de"; + if (lang.startsWith("nl")) + return "nl"; + if (lang.startsWith("fr")) + return "fr"; + if (lang.startsWith("it")) + return "it"; + if (lang.startsWith("es")) + return "es"; + if (lang.startsWith("sk")) + return "sk"; + if (lang.startsWith("hu")) + return "hu"; + } + return "en"; +}; + +// src/utils.ts +function getTimeOfDay() { + const now = new Date; + const hour = now.getHours(); + const minute = now.getMinutes(); + const totalMinutes = hour * 60 + minute; + if (totalMinutes >= TIME_THRESHOLDS.SUNRISE_START && totalMinutes < TIME_THRESHOLDS.SUNRISE_END) { + const progress = (totalMinutes - TIME_THRESHOLDS.SUNRISE_START) / 120; + return { type: "sunrise", progress }; + } + if (totalMinutes >= TIME_THRESHOLDS.SUNRISE_END && totalMinutes < TIME_THRESHOLDS.DAY_END) { + const progress = (totalMinutes - TIME_THRESHOLDS.SUNRISE_END) / 600; + return { type: "day", progress }; + } + if (totalMinutes >= TIME_THRESHOLDS.DAY_END && totalMinutes < TIME_THRESHOLDS.SUNSET_END) { + const progress = (totalMinutes - TIME_THRESHOLDS.DAY_END) / 120; + return { type: "sunset", progress }; + } + return { type: "night", progress: 0 }; +} +function getSunPosition(timeOfDay, width, height) { + if (timeOfDay.type === "sunrise") { + const progress = timeOfDay.progress; + return { + x: width * (0.3 + progress * 0.4), + y: height * (0.85 - progress * 0.55) + }; + } else if (timeOfDay.type === "sunset") { + const progress = timeOfDay.progress; + return { + x: width * (0.5 + progress * 0.3), + y: height * (0.3 + progress * 0.55) + }; + } else if (timeOfDay.type === "day") { + const progress = timeOfDay.progress; + const angle = progress * Math.PI; + return { + x: width * (0.5 + Math.sin(angle) * 0.25), + y: height * (0.25 - Math.sin(angle) * 0.1) + }; + } else { + return { + x: width * 0.75, + y: height * 0.3 + }; + } +} +function getBackgroundGradient(timeOfDay) { + if (timeOfDay.type === "sunrise") { + const progress = timeOfDay.progress; + const nightStart = { r: 26, g: 26, b: 46 }; + const dayStart = { r: 255, g: 160, b: 122 }; + const dayEnd = { r: 255, g: 215, b: 0 }; + return { + start: { + r: Math.round(nightStart.r + (dayStart.r - nightStart.r) * progress), + g: Math.round(nightStart.g + (dayStart.g - nightStart.g) * progress), + b: Math.round(nightStart.b + (dayStart.b - nightStart.b) * progress) + }, + end: { + r: Math.round(nightStart.r + (dayEnd.r - nightStart.r) * progress), + g: Math.round(nightStart.g + (dayEnd.g - nightStart.g) * progress), + b: Math.round(nightStart.b + (dayEnd.b - nightStart.b) * progress) + } + }; + } else if (timeOfDay.type === "sunset") { + const progress = timeOfDay.progress; + const dayStart = { r: 255, g: 107, b: 107 }; + const dayEnd = { r: 255, g: 160, b: 122 }; + const nightStart = { r: 26, g: 26, b: 46 }; + return { + start: { + r: Math.round(dayStart.r + (nightStart.r - dayStart.r) * progress), + g: Math.round(dayStart.g + (nightStart.g - dayStart.g) * progress), + b: Math.round(dayStart.b + (nightStart.b - dayStart.b) * progress) + }, + end: { + r: Math.round(dayEnd.r + (nightStart.r - dayEnd.r) * progress), + g: Math.round(dayEnd.g + (nightStart.g - dayEnd.g) * progress), + b: Math.round(dayEnd.b + (nightStart.b - dayEnd.b) * progress) + } + }; + } + return null; +} +function formatForecastTime(datetime, format = "24h", am = "AM", pm = "PM") { + if (!datetime) + return ""; + const date = new Date(datetime); + const hours = date.getHours(); + if (format === "12h") { + const h = hours % 12 || 12; + const period = hours < 12 ? am : pm; + return `${h} ${period}`; + } + return `${hours.toString().padStart(2, "0")}:00`; +} +function formatForecastDay(datetime, locale) { + if (!datetime) + return ""; + const date = new Date(datetime); + if (Number.isNaN(date.getTime())) + return ""; + return date.toLocaleDateString(locale || undefined, { + weekday: "short", + day: "numeric", + month: "short" + }); +} +function formatTime(datetime, format = "24h", amText = "AM", pmText = "PM") { + if (!datetime) + return ""; + const date = typeof datetime === "string" ? new Date(datetime) : datetime; + let hours = date.getHours(); + const minutes = date.getMinutes(); + if (format === "12h") { + const period = hours >= 12 ? pmText : amText; + hours = hours % 12 || 12; + return `${hours}:${minutes.toString().padStart(2, "0")} ${period}`; + } else { + return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`; + } +} +function getSunriseSunsetData(weatherState, sunriseEntity = null, sunsetEntity = null, hass = null) { + let sunrise = null; + let sunset = null; + if (sunriseEntity && hass && hass.states[sunriseEntity]) { + const sunriseState = hass.states[sunriseEntity]; + sunrise = new Date(sunriseState.state); + } + if (sunsetEntity && hass && hass.states[sunsetEntity]) { + const sunsetState = hass.states[sunsetEntity]; + sunset = new Date(sunsetState.state); + } + if (!sunrise || !sunset) { + if (weatherState && weatherState.attributes) { + const attrs = weatherState.attributes; + if (!sunrise && (attrs.forecast_sunrise || attrs.sunrise)) { + sunrise = new Date(attrs.forecast_sunrise || attrs.sunrise); + } + if (!sunset && (attrs.forecast_sunset || attrs.sunset)) { + sunset = new Date(attrs.forecast_sunset || attrs.sunset); + } + } + } + if ((!sunrise || !sunset) && hass && hass.states["sun.sun"]) { + const sunEntity = hass.states["sun.sun"]; + const sunAttrs = sunEntity.attributes; + if (!sunrise && sunAttrs.next_rising) { + sunrise = new Date(sunAttrs.next_rising); + } + if (!sunset && sunAttrs.next_setting) { + sunset = new Date(sunAttrs.next_setting); + } + } + return { + sunrise, + sunset, + hasSunData: !!(sunrise && sunset) + }; +} +function getTimeOfDayWithSunData(sunData) { + const now = new Date; + if (sunData.hasSunData && sunData.sunrise && sunData.sunset) { + const currentTime = now.getTime(); + let sunriseTime = sunData.sunrise.getTime(); + let sunsetTime = sunData.sunset.getTime(); + if (sunriseTime - currentTime > 12 * 60 * 60 * 1000) { + sunriseTime -= 24 * 60 * 60 * 1000; + } + if (sunsetTime - currentTime > 12 * 60 * 60 * 1000) { + sunsetTime -= 24 * 60 * 60 * 1000; + } + const sunriseStart = sunriseTime - 60 * 60 * 1000; + const sunriseEnd = sunriseTime + 60 * 60 * 1000; + const sunsetStart = sunsetTime - 60 * 60 * 1000; + const sunsetEnd = sunsetTime + 60 * 60 * 1000; + if (currentTime >= sunriseStart && currentTime < sunriseEnd) { + const progress = (currentTime - sunriseStart) / (sunriseEnd - sunriseStart); + return { type: "sunrise", progress }; + } + if (currentTime >= sunriseEnd && currentTime < sunsetStart) { + const progress = (currentTime - sunriseEnd) / (sunsetStart - sunriseEnd); + return { type: "day", progress }; + } + if (currentTime >= sunsetStart && currentTime < sunsetEnd) { + const progress = (currentTime - sunsetStart) / (sunsetEnd - sunsetStart); + return { type: "sunset", progress }; + } + return { type: "night", progress: 0 }; + } + return getTimeOfDay(); +} +function convertWindSpeed(speed, attrs, configUnit) { + if (speed == null) + return null; + if (attrs.wind_speed_unit) { + return Math.round(speed * 10) / 10; + } + if (configUnit === "kmh") { + return Math.round(speed * 3.6 * 10) / 10; + } + return Math.round(speed * 10) / 10; +} +function getWindSpeedUnit(attrs, configUnit, t) { + const unit = attrs.wind_speed_unit; + if (unit) { + const normalizedUnit = unit.toLowerCase().replace(/[^a-z]/g, ""); + if (normalizedUnit === "kmh" || normalizedUnit === "kmph") { + return t("wind_unit_kmh"); + } else if (normalizedUnit === "ms" || normalizedUnit === "mps") { + return t("wind_unit_ms"); + } else if (normalizedUnit === "mph") { + return t("wind_unit_mph"); + } else if (normalizedUnit === "knots" || normalizedUnit === "kn" || normalizedUnit === "kt") { + return t("wind_unit_knots"); + } else if (normalizedUnit === "fts" || normalizedUnit === "ftps") { + return t("wind_unit_fts"); + } + return unit; + } + return configUnit === "kmh" ? t("wind_unit_kmh") : t("wind_unit_ms"); +} +function formatClockTime(date, format, amLabel, pmLabel) { + if (format === "12h") { + let hours = date.getHours(); + const minutes = String(date.getMinutes()).padStart(2, "0"); + const period = hours >= 12 ? pmLabel : amLabel; + hours = hours % 12 || 12; + return `${hours}:${minutes} ${period}`; + } else { + const hours = String(date.getHours()).padStart(2, "0"); + const minutes = String(date.getMinutes()).padStart(2, "0"); + return `${hours}:${minutes}`; + } +} +function setupHorizontalScroll(root, selector) { + const element = root?.querySelector(selector); + if (!element) + return null; + const handler = (e) => { + const wheelEvent = e; + if (wheelEvent.deltaY !== 0) { + e.preventDefault(); + element.scrollLeft += wheelEvent.deltaY; + } + }; + element.addEventListener("wheel", handler, { passive: false }); + return () => element.removeEventListener("wheel", handler); +} + +// src/components/styles.ts +var cardStyles = css` :host { display: block; --card-width: 100%; @@ -70,6 +3373,7 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex height: 100%; min-height: 100%; pointer-events: none; + z-index: 0; } canvas { @@ -91,13 +3395,13 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex rgba(0, 0, 0, calc(var(--overlay-opacity) * 0.8)) 0%, rgba(0, 0, 0, calc(var(--overlay-opacity) * 1.2)) 100% ); - z-index: 0; + z-index: 1; border-radius: 16px; } .content { position: relative; - z-index: 1; + z-index: 2; padding: 20px; display: flex; flex-direction: column; @@ -319,7 +3623,869 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex margin-bottom: 0; } } -`;class M{ctx;constructor(o){this.ctx=o}drawCloud(o,i,a,n){let l=this.ctx.shadowBlur,s=this.ctx.shadowColor,r=this.ctx.globalAlpha;this.ctx.shadowBlur=a*0.25,this.ctx.shadowColor=`rgba(255, 255, 255, ${n*0.4})`,this.ctx.globalAlpha=n*0.85,this.ctx.fillStyle="rgba(255, 255, 255, 1)",[{x:o,y:i,r:a*0.4},{x:o+a*0.35,y:i,r:a*0.5},{x:o+a*0.65,y:i,r:a*0.48},{x:o+a*0.92,y:i,r:a*0.38},{x:o+a*0.18,y:i-a*0.28,r:a*0.38},{x:o+a*0.52,y:i-a*0.32,r:a*0.42},{x:o+a*0.78,y:i-a*0.28,r:a*0.38},{x:o+a*0.32,y:i-a*0.42,r:a*0.32},{x:o+a*0.62,y:i-a*0.48,r:a*0.36},{x:o+a*0.82,y:i-a*0.42,r:a*0.32}].forEach((_)=>{this.ctx.beginPath(),this.ctx.arc(_.x,_.y,_.r,0,Math.PI*2),this.ctx.fill()}),this.ctx.shadowBlur=l,this.ctx.shadowColor=s,this.ctx.globalAlpha=r}drawClouds(o,i,a,n=0.5){let l=Math.max(2,Math.floor(i/150*n));for(let s=0;s=s-50){let r=Math.max(0,(s-i)/50)*0.3;this.ctx.fillStyle=`rgba(255, 140, 0, ${r})`,this.ctx.beginPath(),this.ctx.ellipse(o,s,l*1.5,l*0.5,0,0,Math.PI*2),this.ctx.fill()}}drawNightSky(o,i,a){this.ctx.fillStyle="#FFFFFF";for(let s=0;s<20;s++){let r=(o*0.2+s*47)%o,c=(i*0.2+s*23)%(i*0.6),_=Math.sin(a*0.8+s)*0.5+0.5;this.ctx.globalAlpha=_*0.8,this.ctx.beginPath(),this.ctx.arc(r,c,1.5,0,Math.PI*2),this.ctx.fill()}let n=o*0.75,l=i*0.3;this.ctx.globalAlpha=0.9,this.ctx.fillStyle="#F0F0F0",this.ctx.beginPath(),this.ctx.arc(n,l,25,0,Math.PI*2),this.ctx.fill(),this.ctx.fillStyle="#1a1a2e",this.ctx.beginPath(),this.ctx.arc(n-8,l-5,22,0,Math.PI*2),this.ctx.fill(),this.ctx.globalAlpha=1}}class O extends M{rainDrops=[];lastTime=0;draw(o,i,a,n,l=!1){let s=Date.now()*0.001;this.drawClouds(s,i,a,l?1:0.8),this.drawRain(i,a,l)}drawRain(o,i,a){let n=a?130:90;if(this.rainDrops.length!==n){this.rainDrops=[];for(let c=0;c0?Math.min(l-this.lastTime,0.1):0.016666666666666666;this.lastTime=l;let r=l;for(let c=0;ci+50)_.y=-50-Math.random()*100,_.x=Math.random()*o;let g=_.windOffset*(1+Math.sin(r*0.5+_.phase)*0.2),h=_.x+g;if(h<-10)_.x=o+10;else if(h>o+10)_.x=-10;this.drawRainDrop(h,_.y,_)}}drawRainDrop(o,i,a){this.ctx.save(),this.ctx.globalAlpha=a.alpha;let n=i-a.length*0.5,l=i+a.length*0.5,s=a.alpha,r=a.alpha*0.5;this.ctx.fillStyle="rgba(220, 240, 255, "+s+")",this.ctx.strokeStyle="rgba(240, 250, 255, "+r+")",this.ctx.lineWidth=0.4,this.ctx.beginPath(),this.ctx.moveTo(o,n),this.ctx.quadraticCurveTo(o-a.width*0.3,i,o-a.width,l-a.width*0.3),this.ctx.arc(o,l,a.width,Math.PI,0,!1),this.ctx.quadraticCurveTo(o+a.width*0.3,i,o,n),this.ctx.closePath(),this.ctx.fill(),this.ctx.stroke(),this.ctx.restore()}}class Bo extends M{snowflakes=[];lastTime=0;draw(o,i,a,n){let l=Date.now()*0.001;this.drawClouds(l,i,a,0.7),this.drawSnowflakes(i,a)}drawSnowflakes(o,i){let a=Math.floor(o*i/5000),n=Math.max(30,Math.min(a,80));if(this.snowflakes.length!==n){this.snowflakes=[];for(let c=0;c0?Math.min(l-this.lastTime,0.1):0.016666666666666666;this.lastTime=l;let r=l;this.ctx.lineCap="round";for(let c=0;ci+20)_.y=-20-Math.random()*50,_.x=Math.random()*o;if(_.x<-10)_.x=o+10;else if(_.x>o+10)_.x=-10;this.drawSnowflake(_.x,_.y,_.size,_.alpha,_.rotation)}}drawSnowflake(o,i,a,n,l){this.ctx.save(),this.ctx.translate(o,i),this.ctx.rotate(l),this.ctx.strokeStyle=`rgba(255, 255, 255, ${n})`,this.ctx.lineWidth=1,this.ctx.beginPath();for(let s=0;s<6;s++){let r=Math.PI/3*s,c=Math.cos(r),_=Math.sin(r);this.ctx.moveTo(0,0),this.ctx.lineTo(_*a*2.5,c*a*2.5);let g=_*a*1.5+c*a*0.5,h=c*a*1.5-_*a*0.5,f=_*a*1.8+c*a*1.2,m=c*a*1.8-_*a*1.2;this.ctx.moveTo(g,h),this.ctx.lineTo(f,m);let b=_*a*1.5-c*a*0.5,S=c*a*1.5+_*a*0.5,Li=_*a*1.8-c*a*1.2,Ii=c*a*1.8+_*a*1.2;this.ctx.moveTo(b,S),this.ctx.lineTo(Li,Ii)}this.ctx.stroke(),this.ctx.restore()}}class $o extends M{draw(o,i,a,n){let l=Date.now()*0.001;this.drawClouds(l,i,a,0.7)}}class Qo extends M{draw(o,i,a,n){let l=Date.now()*0.0003;this.ctx.fillStyle="rgba(200, 200, 200, 0.4)";for(let s=0;s<3;s++){let r=a*(0.4+s*0.2),c=Math.sin(l+s)*20;this.ctx.beginPath(),this.ctx.moveTo(0,r);for(let _=0;_<=i;_+=5){let g=Math.sin((_/i+l)*Math.PI*4+s)*15;this.ctx.lineTo(_,r+g+c)}this.ctx.lineTo(i,a),this.ctx.lineTo(0,a),this.ctx.closePath(),this.ctx.fill()}}}class Co extends M{hailStones=[];draw(o,i,a,n){let l=Date.now()*0.001;this.drawClouds(l,i,a,1),this.drawHailStones(i,a)}drawHailStones(o,i){if(this.hailStones.length!==60){this.hailStones=[];for(let l=0;l<60;l++)this.hailStones.push({startX:Math.random()*o,startY:Math.random()*(i+150)-75,speed:120+Math.random()*80,windOffset:(Math.random()-0.5)*20,size:2+Math.random()*3,alpha:0.8+Math.random()*0.15,phase:Math.random()*Math.PI*2})}let n=Date.now()*0.002;this.ctx.fillStyle="rgba(240, 250, 255, 1)",this.ctx.strokeStyle="rgba(255, 255, 255, 0.9)",this.ctx.lineWidth=0.5;for(let l=0;li+30)s.startY=-30-Math.random()*30,s.startX=Math.random()*o;let c=s.windOffset*(1+Math.sin(n*0.6+s.phase)*0.15),_=(s.startX+c+n*20%o)%o;if(_<-5)s.startX=o+5;else if(_>o+5)s.startX=-5;this.drawHailStone(_,r,s)}}drawHailStone(o,i,a){this.ctx.save(),this.ctx.globalAlpha=a.alpha,this.ctx.beginPath(),this.ctx.ellipse(o,i,a.size,a.size*0.9,0,0,Math.PI*2),this.ctx.fill(),this.ctx.stroke(),this.ctx.fillStyle="rgba(255, 255, 255, 0.6)",this.ctx.beginPath(),this.ctx.ellipse(o-a.size*0.3,i-a.size*0.3,a.size*0.3,a.size*0.25,0,0,Math.PI*2),this.ctx.fill(),this.ctx.fillStyle="rgba(240, 250, 255, 1)",this.ctx.restore()}}class Po extends M{rainyAnimation;constructor(o){super(o);this.rainyAnimation=new O(o)}draw(o,i,a,n,l=!0){let s=Date.now()*0.001;if(this.drawClouds(s,i,a,1),l)this.rainyAnimation.draw(o,i,a,n,!1);this.drawLightning(i,a,s)}drawLightning(o,i,a){let n=Math.sin(a*2.5)*Math.sin(a*5.3)*Math.sin(a*7.1),l=Math.max(0,n);if(l>0.4){let s=(l-0.4)/0.6,r=s*0.6,c=Math.min(r,Math.sin(s*Math.PI)*0.6);this.ctx.fillStyle=`rgba(255, 255, 255, ${c})`,this.ctx.fillRect(0,0,o,i)}}}class xo{canvas=null;ctx=null;animationFrame=null;animations={};resizeObserver=null;width=0;height=0;container=null;getDrawParams;handleVisibilityChange=()=>{if(document.hidden)this.stopAnimation();else this.startAnimation()};constructor(o){this.getDrawParams=o}setup(o){if(this.container=o,this.setupCanvas(),this.canvas&&this.ctx)this.initializeAnimations(),this.startAnimation(),this.setupResizeObserver(),document.addEventListener("visibilitychange",this.handleVisibilityChange)}destroy(){if(document.removeEventListener("visibilitychange",this.handleVisibilityChange),this.stopAnimation(),this.resizeObserver)this.resizeObserver.disconnect(),this.resizeObserver=null;this.canvas=null,this.ctx=null,this.container=null}resize(){if(this.canvas&&this.ctx)this.resizeCanvas()}setupCanvas(){if(!this.container)return;let o=this.container.querySelector("canvas");if(o)o.remove();this.canvas=document.createElement("canvas"),this.container.appendChild(this.canvas),this.resizeCanvas()}resizeCanvas(){if(!this.canvas||!this.container)return;let o=this.container.getBoundingClientRect();if(o.width===0||o.height===0)return;let i=window.devicePixelRatio||2;if(this.canvas.width=o.width*i,this.canvas.height=o.height*i,this.canvas.style.width="100%",this.canvas.style.height="100%",this.ctx=this.canvas.getContext("2d"),this.ctx)this.ctx.scale(i,i);this.width=o.width,this.height=o.height,this.initializeAnimations()}setupResizeObserver(){if(!this.container)return;this.resizeObserver=new ResizeObserver(()=>{this.resizeCanvas()}),this.resizeObserver.observe(this.container)}initializeAnimations(){if(!this.ctx)return;this.animations={sunny:new Wo(this.ctx),rainy:new O(this.ctx),snowy:new Bo(this.ctx),cloudy:new $o(this.ctx),foggy:new Qo(this.ctx),hail:new Co(this.ctx),thunderstorm:new Po(this.ctx)}}startAnimation(){if(this.animationFrame)return;let o=()=>{this.draw(),this.animationFrame=requestAnimationFrame(o)};o()}stopAnimation(){if(this.animationFrame)cancelAnimationFrame(this.animationFrame),this.animationFrame=null}draw(){if(!this.ctx||!this.canvas)return;if(!this.width||!this.height){if(this.resizeCanvas(),!this.width||!this.height)return}let o=this.getDrawParams();if(!o)return;let{condition:i,timeOfDay:a}=o,n=this.width,l=this.height;switch(this.ctx.clearRect(0,0,n,l),i.toLowerCase()){case"sunny":case"clear":this.animations.sunny?.draw(Date.now(),n,l,a);break;case"clear-night":this.animations.sunny?.draw(Date.now(),n,l,{type:"night",progress:0});break;case"rainy":case"rain":this.animations.rainy?.draw(Date.now(),n,l,a,!1);break;case"pouring":this.animations.rainy?.draw(Date.now(),n,l,a,!0);break;case"snowy":case"snow":this.animations.snowy?.draw(Date.now(),n,l,a);break;case"snowy-rainy":this.animations.rainy?.draw(Date.now(),n,l,a,!1),this.animations.snowy?.draw(Date.now(),n,l,a);break;case"hail":this.animations.hail?.draw(Date.now(),n,l,a);break;case"foggy":case"fog":this.animations.foggy?.draw(Date.now(),n,l,a);break;case"lightning":this.animations.thunderstorm?.draw(Date.now(),n,l,a,!1);break;case"lightning-rainy":this.animations.thunderstorm?.draw(Date.now(),n,l,a,!0);break;case"cloudy":case"partlycloudy":default:this.animations.cloudy?.draw(Date.now(),n,l,a);break}}}class Go{hourlyForecast=[];dailyForecast=[];hourlySubscription=null;dailySubscription=null;onUpdate;constructor(o){this.onUpdate=o}getHourlyData(){return this.hourlyForecast}getDailyData(){return this.dailyForecast}async subscribe(o,i,a){if(!o||!i)return;this.unsubscribe();try{if(this.hourlySubscription=o.connection.subscribeMessage((n)=>{if(n.forecast&&n.forecast.length>0)this.hourlyForecast=n.forecast,this.onUpdate()},{type:"weather/subscribe_forecast",forecast_type:"hourly",entity_id:i}),a)this.dailySubscription=o.connection.subscribeMessage((n)=>{if(n.forecast&&n.forecast.length>0)this.dailyForecast=n.forecast,this.onUpdate()},{type:"weather/subscribe_forecast",forecast_type:"daily",entity_id:i})}catch{}}async unsubscribe(){if(this.hourlySubscription){try{(await this.hourlySubscription)()}catch{}this.hourlySubscription=null}if(this.dailySubscription){try{(await this.dailySubscription)()}catch{}this.dailySubscription=null}}getHourlyForecast(o,i){let a=Math.max(1,Math.floor(Number(o??e.hourlyForecastHours)));if(this.hourlyForecast&&this.hourlyForecast.length>0)return this.hourlyForecast.slice(0,a);if(!i?.forecast||i.forecast.length===0)return[];let n=new Date,l=new Date(n.getFullYear(),n.getMonth(),n.getDate()),s=new Date(l);return s.setDate(s.getDate()+1),i.forecast.filter((c)=>{if(!c.datetime)return!1;let _=new Date(c.datetime),g=new Date(_.getFullYear(),_.getMonth(),_.getDate());return g.getTime()===l.getTime()||g.getTime()===s.getTime()&&_.getHours()<=n.getHours()}).sort((c,_)=>new Date(c.datetime).getTime()-new Date(_.datetime).getTime()).slice(0,a)}getDailyForecast(o,i){let a=Math.max(1,Math.floor(Number(o??e.dailyForecastDays)));if(this.dailyForecast&&this.dailyForecast.length>0)return this.dailyForecast.slice(0,a);if(!i?.forecast||i.forecast.length===0)return[];let n=new Date,l=new Date(n.getFullYear(),n.getMonth(),n.getDate()),s=new Date(l);s.setDate(s.getDate()+a);let r=(_)=>{let g=_.getFullYear(),h=String(_.getMonth()+1).padStart(2,"0"),f=String(_.getDate()).padStart(2,"0");return`${g}-${h}-${f}`},c=new Map;return i.forecast.forEach((_)=>{if(!_.datetime)return;let g=new Date(_.datetime);if(Number.isNaN(g.getTime()))return;if(g=s)return;let h=r(g),f=Math.abs(g.getHours()+g.getMinutes()/60-12),m=c.get(h);if(!m||f_.itemDate.getTime()-g.itemDate.getTime()).map((_)=>_.item).slice(0,a)}}class jo{holdTimer=null;lastTap=null;holdFired=!1;holdDelay=500;getHass;getConfig;fireEvent;constructor(o,i,a){this.getHass=o,this.getConfig=i,this.fireEvent=a}handleTap(o){if(o.target.closest(".forecast-item")||o.target.closest(".info-item"))return;if(this.lastTap&&Date.now()-this.lastTap<300){this.handleDoubleTap(),this.lastTap=null;return}this.lastTap=Date.now(),setTimeout(()=>{if(this.lastTap)this.handleAction(this.getConfig().tapAction),this.lastTap=null},300)}handlePointerDown(){this.holdTimer=window.setTimeout(()=>{this.handleHold(),this.holdFired=!0},this.holdDelay)}handlePointerUp(o){if(this.holdTimer)clearTimeout(this.holdTimer);if(this.holdFired)o.preventDefault(),o.stopPropagation(),this.holdFired=!1}handleHold(){this.handleAction(this.getConfig().holdAction)}handleDoubleTap(){this.handleAction(this.getConfig().doubleTapAction)}handleAction(o){let i=this.getHass(),a=this.getConfig();if(!o||!i)return;switch(o.action||"more-info"){case"more-info":this.fireEvent("hass-more-info",{entityId:o.entity||a.entity});break;case"toggle":i.callService("homeassistant","toggle",{entity_id:o.entity||a.entity});break;case"call-service":if(o.service){let[l,s]=o.service.split(".");i.callService(l,s,o.service_data||{})}break;case"navigate":if(o.navigation_path)window.history.pushState(null,"",o.navigation_path),this.fireEvent("location-changed",{replace:!1});break;case"url":if(o.url_path)window.open(o.url_path);break;case"none":default:break}}}function Da(o,i){if(!o||!i)return null;let a=o.states[i];return a?a.state:null}function Do(o,i){if(!o||!i)return{};let a=o.states[i];return a?a.attributes:{}}function To(o,i,a,n){let l=Da(o,i),s=Do(o,i),r=s.condition||l||"sunny",c=null;if(a.templowAttribute&&s[a.templowAttribute]!=null)c=s[a.templowAttribute];else{for(let _ of Fi)if(s[_]!=null){c=s[_];break}if(c==null)c=(s.forecast&&s.forecast[0]?s.forecast[0].templow??null:null)||(s.forecast_hourly&&s.forecast_hourly[0]?s.forecast_hourly[0].native_templow??null:null)}return{condition:r,temperature:s.temperature!=null?s.temperature:null,apparentTemperature:s.apparent_temperature||null,humidity:s.humidity!=null?s.humidity:null,windSpeed:s.wind_speed!=null?s.wind_speed:null,windGust:s.wind_gust_speed||s.wind_gust||null,windBearing:s.wind_bearing!=null?s.wind_bearing:null,windDirection:s.wind_direction||null,pressure:s.pressure||null,forecast:s.forecast||s.forecast_hourly||n||[],friendlyName:s.friendly_name||d.t("weather"),templow:c}}class xi extends F{constructor(){super(...arguments);this.format=null;this.currentTime=""}clockInterval=null;static styles=W` +`; + +// src/animations/base.ts +class BaseAnimation { + ctx; + constructor(ctx) { + this.ctx = ctx; + } + drawCloud(x, y, size, opacity) { + const savedShadowBlur = this.ctx.shadowBlur; + const savedShadowColor = this.ctx.shadowColor; + const savedGlobalAlpha = this.ctx.globalAlpha; + this.ctx.shadowBlur = size * 0.25; + this.ctx.shadowColor = `rgba(255, 255, 255, ${opacity * 0.4})`; + this.ctx.globalAlpha = opacity * 0.85; + this.ctx.fillStyle = "rgba(255, 255, 255, 1)"; + const parts = [ + { x, y, r: size * 0.4 }, + { x: x + size * 0.35, y, r: size * 0.5 }, + { x: x + size * 0.65, y, r: size * 0.48 }, + { x: x + size * 0.92, y, r: size * 0.38 }, + { x: x + size * 0.18, y: y - size * 0.28, r: size * 0.38 }, + { x: x + size * 0.52, y: y - size * 0.32, r: size * 0.42 }, + { x: x + size * 0.78, y: y - size * 0.28, r: size * 0.38 }, + { x: x + size * 0.32, y: y - size * 0.42, r: size * 0.32 }, + { x: x + size * 0.62, y: y - size * 0.48, r: size * 0.36 }, + { x: x + size * 0.82, y: y - size * 0.42, r: size * 0.32 } + ]; + parts.forEach((part) => { + this.ctx.beginPath(); + this.ctx.arc(part.x, part.y, part.r, 0, Math.PI * 2); + this.ctx.fill(); + }); + this.ctx.shadowBlur = savedShadowBlur; + this.ctx.shadowColor = savedShadowColor; + this.ctx.globalAlpha = savedGlobalAlpha; + } + drawClouds(time, width, height, density = 0.5) { + const cloudCount = Math.max(2, Math.floor(width / 150 * density)); + for (let i = 0;i < cloudCount; i++) { + const baseX = (time * 3 + i * 150) % (width + 200) - 100; + const baseY = height * (0.2 + i % 3 * 0.15) + Math.sin(time * 0.2 + i) * 8; + const size = 40 + i % 3 * 15; + const opacity = 0.6 + i % 2 * 0.2; + this.drawCloud(baseX, baseY, size, opacity); + } + } +} + +// src/animations/sunny.ts +class SunnyAnimation extends BaseAnimation { + draw(time, width, height, timeOfDay) { + const currentTime = Date.now() * 0.001; + const sunPos = getSunPosition(timeOfDay, width, height); + const sunX = sunPos.x; + const sunY = sunPos.y; + if (timeOfDay.type === "day" || timeOfDay.type === "sunrise" || timeOfDay.type === "sunset") { + this.drawSun(sunX, sunY, currentTime); + if (timeOfDay.type === "sunrise" || timeOfDay.type === "sunset") { + this.drawHorizonReflection(sunX, sunY, height, currentTime); + } + } else if (timeOfDay.type === "night") { + this.drawNightSky(width, height, currentTime); + } + this.drawClouds(currentTime, width, height, 0.3); + } + drawSun(sunX, sunY, time) { + const sunRadius = 48 + Math.sin(time * 0.15) * 1.5; + const outerHalo = this.ctx.createRadialGradient(sunX, sunY, sunRadius * 0.3, sunX, sunY, sunRadius * 3.5); + outerHalo.addColorStop(0, "rgba(255, 248, 230, 0.25)"); + outerHalo.addColorStop(0.15, "rgba(255, 240, 200, 0.2)"); + outerHalo.addColorStop(0.3, "rgba(255, 230, 170, 0.15)"); + outerHalo.addColorStop(0.5, "rgba(255, 220, 140, 0.1)"); + outerHalo.addColorStop(0.7, "rgba(255, 210, 120, 0.06)"); + outerHalo.addColorStop(0.85, "rgba(255, 200, 100, 0.03)"); + outerHalo.addColorStop(1, "rgba(255, 190, 90, 0)"); + this.ctx.fillStyle = outerHalo; + this.ctx.beginPath(); + this.ctx.arc(sunX, sunY, sunRadius * 3.5, 0, Math.PI * 2); + this.ctx.fill(); + const midHalo = this.ctx.createRadialGradient(sunX, sunY, sunRadius * 0.5, sunX, sunY, sunRadius * 2.2); + midHalo.addColorStop(0, "rgba(255, 250, 220, 0.35)"); + midHalo.addColorStop(0.3, "rgba(255, 240, 190, 0.25)"); + midHalo.addColorStop(0.6, "rgba(255, 230, 160, 0.15)"); + midHalo.addColorStop(0.85, "rgba(255, 220, 140, 0.08)"); + midHalo.addColorStop(1, "rgba(255, 210, 120, 0)"); + this.ctx.fillStyle = midHalo; + this.ctx.beginPath(); + this.ctx.arc(sunX, sunY, sunRadius * 2.2, 0, Math.PI * 2); + this.ctx.fill(); + const innerHalo = this.ctx.createRadialGradient(sunX, sunY, sunRadius * 0.6, sunX, sunY, sunRadius * 1.6); + innerHalo.addColorStop(0, "rgba(255, 252, 240, 0.5)"); + innerHalo.addColorStop(0.4, "rgba(255, 245, 210, 0.35)"); + innerHalo.addColorStop(0.7, "rgba(255, 235, 180, 0.2)"); + innerHalo.addColorStop(1, "rgba(255, 225, 150, 0)"); + this.ctx.fillStyle = innerHalo; + this.ctx.beginPath(); + this.ctx.arc(sunX, sunY, sunRadius * 1.6, 0, Math.PI * 2); + this.ctx.fill(); + const sunGradient = this.ctx.createRadialGradient(sunX - sunRadius * 0.1, sunY - sunRadius * 0.1, 0, sunX, sunY, sunRadius); + sunGradient.addColorStop(0, "#FFFEF5"); + sunGradient.addColorStop(0.15, "#FFF9E6"); + sunGradient.addColorStop(0.3, "#FFF4D6"); + sunGradient.addColorStop(0.5, "#FFEDC0"); + sunGradient.addColorStop(0.7, "#FFE4A8"); + sunGradient.addColorStop(0.85, "#FFDC95"); + sunGradient.addColorStop(1, "#FFD37F"); + this.ctx.fillStyle = sunGradient; + this.ctx.beginPath(); + this.ctx.arc(sunX, sunY, sunRadius, 0, Math.PI * 2); + this.ctx.fill(); + } + drawHorizonReflection(sunX, sunY, height, time) { + const sunRadius = 48 + Math.sin(time * 0.15) * 1.5; + const horizonY = height * 0.85; + if (sunY >= horizonY - 50) { + const reflectionAlpha = Math.max(0, (horizonY - sunY) / 50) * 0.3; + this.ctx.fillStyle = `rgba(255, 140, 0, ${reflectionAlpha})`; + this.ctx.beginPath(); + this.ctx.ellipse(sunX, horizonY, sunRadius * 1.5, sunRadius * 0.5, 0, 0, Math.PI * 2); + this.ctx.fill(); + } + } + drawNightSky(width, height, time) { + this.ctx.fillStyle = "#FFFFFF"; + for (let i = 0;i < 20; i++) { + const x = (width * 0.2 + i * 47) % width; + const y = (height * 0.2 + i * 23) % (height * 0.6); + const twinkle = Math.sin(time * 0.8 + i) * 0.5 + 0.5; + this.ctx.globalAlpha = twinkle * 0.8; + this.ctx.beginPath(); + this.ctx.arc(x, y, 1.5, 0, Math.PI * 2); + this.ctx.fill(); + } + const moonX = width * 0.75; + const moonY = height * 0.3; + this.ctx.globalAlpha = 0.9; + this.ctx.fillStyle = "#F0F0F0"; + this.ctx.beginPath(); + this.ctx.arc(moonX, moonY, 25, 0, Math.PI * 2); + this.ctx.fill(); + this.ctx.fillStyle = "#1a1a2e"; + this.ctx.beginPath(); + this.ctx.arc(moonX - 8, moonY - 5, 22, 0, Math.PI * 2); + this.ctx.fill(); + this.ctx.globalAlpha = 1; + } +} + +// src/animations/rainy.ts +class RainyAnimation extends BaseAnimation { + rainDrops = []; + lastTime = 0; + draw(time, width, height, timeOfDay, heavy = false) { + const currentTime = Date.now() * 0.001; + this.drawClouds(currentTime, width, height, heavy ? 1 : 0.8); + this.drawRain(width, height, heavy); + } + drawRain(width, height, heavy) { + const dropCount = heavy ? 130 : 90; + if (this.rainDrops.length !== dropCount) { + this.rainDrops = []; + for (let i = 0;i < dropCount; i++) { + this.rainDrops.push({ + x: Math.random() * width, + y: Math.random() * height - Math.random() * 200, + speed: heavy ? 80 + Math.random() * 100 : 60 + Math.random() * 80, + windOffset: (Math.random() - 0.5) * 30, + width: heavy ? 1.2 + Math.random() * 1 : 0.8 + Math.random() * 0.7, + length: heavy ? 8 + Math.random() * 10 : 6 + Math.random() * 8, + alpha: heavy ? 0.75 + Math.random() * 0.15 : 0.65 + Math.random() * 0.2, + phase: Math.random() * Math.PI * 2 + }); + } + } + const currentTime = Date.now() * 0.001; + const deltaTime = this.lastTime > 0 ? Math.min(currentTime - this.lastTime, 0.1) : 1 / 60; + this.lastTime = currentTime; + const currentAnimTime = currentTime; + for (let i = 0;i < this.rainDrops.length; i++) { + const drop = this.rainDrops[i]; + drop.y += drop.speed * deltaTime; + if (drop.y > height + 50) { + drop.y = -50 - Math.random() * 100; + drop.x = Math.random() * width; + } + const wind = drop.windOffset * (1 + Math.sin(currentAnimTime * 0.5 + drop.phase) * 0.2); + const dropX = drop.x + wind; + if (dropX < -10) { + drop.x = width + 10; + } else if (dropX > width + 10) { + drop.x = -10; + } + this.drawRainDrop(dropX, drop.y, drop); + } + } + drawRainDrop(dropX, dropY, drop) { + this.ctx.save(); + this.ctx.globalAlpha = drop.alpha; + const topY = dropY - drop.length * 0.5; + const bottomY = dropY + drop.length * 0.5; + const fillAlpha = drop.alpha; + const strokeAlpha = drop.alpha * 0.5; + this.ctx.fillStyle = "rgba(220, 240, 255, " + fillAlpha + ")"; + this.ctx.strokeStyle = "rgba(240, 250, 255, " + strokeAlpha + ")"; + this.ctx.lineWidth = 0.4; + this.ctx.beginPath(); + this.ctx.moveTo(dropX, topY); + this.ctx.quadraticCurveTo(dropX - drop.width * 0.3, dropY, dropX - drop.width, bottomY - drop.width * 0.3); + this.ctx.arc(dropX, bottomY, drop.width, Math.PI, 0, false); + this.ctx.quadraticCurveTo(dropX + drop.width * 0.3, dropY, dropX, topY); + this.ctx.closePath(); + this.ctx.fill(); + this.ctx.stroke(); + this.ctx.restore(); + } +} + +// src/animations/snowy.ts +class SnowyAnimation extends BaseAnimation { + snowflakes = []; + lastTime = 0; + draw(time, width, height, _timeOfDay) { + const currentTime = Date.now() * 0.001; + this.drawClouds(currentTime, width, height, 0.7); + this.drawSnowflakes(width, height); + } + drawSnowflakes(width, height) { + const snowflakeCount = Math.floor(width * height / 5000); + const targetCount = Math.max(30, Math.min(snowflakeCount, 80)); + if (this.snowflakes.length !== targetCount) { + this.snowflakes = []; + for (let i = 0;i < targetCount; i++) { + this.snowflakes.push({ + x: Math.random() * width, + y: Math.random() * height - Math.random() * 100, + speedY: 15 + Math.random() * 10, + speedX: (Math.random() - 0.5) * 8, + size: 1.5 + Math.random() * 1.5, + alpha: 0.6 + Math.random() * 0.3, + rotation: Math.random() * Math.PI * 2, + rotationSpeed: (Math.random() - 0.5) * 0.3, + swayPhase: Math.random() * Math.PI * 2, + swaySpeed: 0.5 + Math.random() * 0.5 + }); + } + } + const currentTime = Date.now() * 0.001; + const deltaTime = this.lastTime > 0 ? Math.min(currentTime - this.lastTime, 0.1) : 1 / 60; + this.lastTime = currentTime; + const currentAnimTime = currentTime; + this.ctx.lineCap = "round"; + for (let i = 0;i < this.snowflakes.length; i++) { + const flake = this.snowflakes[i]; + const sway = Math.sin(currentAnimTime * flake.swaySpeed + flake.swayPhase) * 2; + flake.y += flake.speedY * deltaTime; + flake.x += (flake.speedX + sway) * deltaTime; + flake.rotation += flake.rotationSpeed * deltaTime; + if (flake.y > height + 20) { + flake.y = -20 - Math.random() * 50; + flake.x = Math.random() * width; + } + if (flake.x < -10) { + flake.x = width + 10; + } else if (flake.x > width + 10) { + flake.x = -10; + } + this.drawSnowflake(flake.x, flake.y, flake.size, flake.alpha, flake.rotation); + } + } + drawSnowflake(x, y, size, alpha, rotation) { + this.ctx.save(); + this.ctx.translate(x, y); + this.ctx.rotate(rotation); + this.ctx.strokeStyle = `rgba(255, 255, 255, ${alpha})`; + this.ctx.lineWidth = 1; + this.ctx.beginPath(); + for (let j = 0;j < 6; j++) { + const angle = Math.PI / 3 * j; + const cos = Math.cos(angle); + const sin = Math.sin(angle); + this.ctx.moveTo(0, 0); + this.ctx.lineTo(sin * size * 2.5, cos * size * 2.5); + const branch1X = sin * size * 1.5 + cos * size * 0.5; + const branch1Y = cos * size * 1.5 - sin * size * 0.5; + const branch1EndX = sin * size * 1.8 + cos * size * 1.2; + const branch1EndY = cos * size * 1.8 - sin * size * 1.2; + this.ctx.moveTo(branch1X, branch1Y); + this.ctx.lineTo(branch1EndX, branch1EndY); + const branch2X = sin * size * 1.5 - cos * size * 0.5; + const branch2Y = cos * size * 1.5 + sin * size * 0.5; + const branch2EndX = sin * size * 1.8 - cos * size * 1.2; + const branch2EndY = cos * size * 1.8 + sin * size * 1.2; + this.ctx.moveTo(branch2X, branch2Y); + this.ctx.lineTo(branch2EndX, branch2EndY); + } + this.ctx.stroke(); + this.ctx.restore(); + } +} + +// src/animations/cloudy.ts +class CloudyAnimation extends BaseAnimation { + draw(time, width, height, _timeOfDay) { + const currentTime = Date.now() * 0.001; + this.drawClouds(currentTime, width, height, 0.7); + } +} + +// src/animations/foggy.ts +class FoggyAnimation extends BaseAnimation { + draw(time, width, height, _timeOfDay) { + const currentTime = Date.now() * 0.0003; + this.ctx.fillStyle = "rgba(200, 200, 200, 0.4)"; + for (let i = 0;i < 3; i++) { + const y = height * (0.4 + i * 0.2); + const offset = Math.sin(currentTime + i) * 20; + this.ctx.beginPath(); + this.ctx.moveTo(0, y); + for (let x = 0;x <= width; x += 5) { + const wave = Math.sin((x / width + currentTime) * Math.PI * 4 + i) * 15; + this.ctx.lineTo(x, y + wave + offset); + } + this.ctx.lineTo(width, height); + this.ctx.lineTo(0, height); + this.ctx.closePath(); + this.ctx.fill(); + } + } +} + +// src/animations/hail.ts +class HailAnimation extends BaseAnimation { + hailStones = []; + draw(time, width, height, _timeOfDay) { + const currentTime = Date.now() * 0.001; + this.drawClouds(currentTime, width, height, 1); + this.drawHailStones(width, height); + } + drawHailStones(width, height) { + const stoneCount = 60; + if (this.hailStones.length !== stoneCount) { + this.hailStones = []; + for (let i = 0;i < stoneCount; i++) { + this.hailStones.push({ + startX: Math.random() * width, + startY: Math.random() * (height + 150) - 75, + speed: 120 + Math.random() * 80, + windOffset: (Math.random() - 0.5) * 20, + size: 2 + Math.random() * 3, + alpha: 0.8 + Math.random() * 0.15, + phase: Math.random() * Math.PI * 2 + }); + } + } + const time = Date.now() * 0.002; + this.ctx.fillStyle = "rgba(240, 250, 255, 1)"; + this.ctx.strokeStyle = "rgba(255, 255, 255, 0.9)"; + this.ctx.lineWidth = 0.5; + for (let i = 0;i < this.hailStones.length; i++) { + const hail = this.hailStones[i]; + const hailY = (hail.startY + time * hail.speed) % (height + 150); + if (hailY > height + 30) { + hail.startY = -30 - Math.random() * 30; + hail.startX = Math.random() * width; + } + const wind = hail.windOffset * (1 + Math.sin(time * 0.6 + hail.phase) * 0.15); + const hailX = (hail.startX + wind + time * 20 % width) % width; + if (hailX < -5) { + hail.startX = width + 5; + } else if (hailX > width + 5) { + hail.startX = -5; + } + this.drawHailStone(hailX, hailY, hail); + } + } + drawHailStone(hailX, hailY, hail) { + this.ctx.save(); + this.ctx.globalAlpha = hail.alpha; + this.ctx.beginPath(); + this.ctx.ellipse(hailX, hailY, hail.size, hail.size * 0.9, 0, 0, Math.PI * 2); + this.ctx.fill(); + this.ctx.stroke(); + this.ctx.fillStyle = "rgba(255, 255, 255, 0.6)"; + this.ctx.beginPath(); + this.ctx.ellipse(hailX - hail.size * 0.3, hailY - hail.size * 0.3, hail.size * 0.3, hail.size * 0.25, 0, 0, Math.PI * 2); + this.ctx.fill(); + this.ctx.fillStyle = "rgba(240, 250, 255, 1)"; + this.ctx.restore(); + } +} + +// src/animations/thunderstorm.ts +class ThunderstormAnimation extends BaseAnimation { + rainyAnimation; + constructor(ctx) { + super(ctx); + this.rainyAnimation = new RainyAnimation(ctx); + } + draw(time, width, height, timeOfDay, withRain = true) { + const currentTime = Date.now() * 0.001; + this.drawClouds(currentTime, width, height, 1); + if (withRain) { + this.rainyAnimation.draw(time, width, height, timeOfDay, false); + } + this.drawLightning(width, height, currentTime); + } + drawLightning(width, height, time) { + const flashPattern = Math.sin(time * 2.5) * Math.sin(time * 5.3) * Math.sin(time * 7.1); + const flashIntensity = Math.max(0, flashPattern); + if (flashIntensity > 0.4) { + const normalizedIntensity = (flashIntensity - 0.4) / 0.6; + const alpha = normalizedIntensity * 0.6; + const fadeAlpha = Math.min(alpha, Math.sin(normalizedIntensity * Math.PI) * 0.6); + this.ctx.fillStyle = `rgba(255, 255, 255, ${fadeAlpha})`; + this.ctx.fillRect(0, 0, width, height); + } + } +} + +// src/components/animation-manager.ts +class AnimationManager { + canvas = null; + ctx = null; + animationFrame = null; + animations = {}; + resizeObserver = null; + width = 0; + height = 0; + container = null; + getDrawParams; + handleVisibilityChange = () => { + if (document.hidden) { + this.stopAnimation(); + } else { + this.startAnimation(); + } + }; + constructor(getDrawParams) { + this.getDrawParams = getDrawParams; + } + setup(container) { + this.container = container; + this.setupCanvas(); + if (this.canvas && this.ctx) { + this.initializeAnimations(); + this.startAnimation(); + this.setupResizeObserver(); + document.addEventListener("visibilitychange", this.handleVisibilityChange); + } + } + destroy() { + document.removeEventListener("visibilitychange", this.handleVisibilityChange); + this.stopAnimation(); + if (this.resizeObserver) { + this.resizeObserver.disconnect(); + this.resizeObserver = null; + } + this.canvas = null; + this.ctx = null; + this.container = null; + } + resize() { + if (this.canvas && this.ctx) { + this.resizeCanvas(); + } + } + setupCanvas() { + if (!this.container) + return; + const oldCanvas = this.container.querySelector("canvas"); + if (oldCanvas) { + oldCanvas.remove(); + } + this.canvas = document.createElement("canvas"); + this.container.appendChild(this.canvas); + this.resizeCanvas(); + } + resizeCanvas() { + if (!this.canvas || !this.container) + return; + const rect = this.container.getBoundingClientRect(); + if (rect.width === 0 || rect.height === 0) + return; + const dpr = window.devicePixelRatio || 2; + this.canvas.width = rect.width * dpr; + this.canvas.height = rect.height * dpr; + this.canvas.style.width = "100%"; + this.canvas.style.height = "100%"; + this.ctx = this.canvas.getContext("2d"); + if (this.ctx) { + this.ctx.scale(dpr, dpr); + } + this.width = rect.width; + this.height = rect.height; + this.initializeAnimations(); + } + setupResizeObserver() { + if (!this.container) + return; + this.resizeObserver = new ResizeObserver(() => { + this.resizeCanvas(); + }); + this.resizeObserver.observe(this.container); + } + initializeAnimations() { + if (!this.ctx) + return; + this.animations = { + sunny: new SunnyAnimation(this.ctx), + rainy: new RainyAnimation(this.ctx), + snowy: new SnowyAnimation(this.ctx), + cloudy: new CloudyAnimation(this.ctx), + foggy: new FoggyAnimation(this.ctx), + hail: new HailAnimation(this.ctx), + thunderstorm: new ThunderstormAnimation(this.ctx) + }; + } + startAnimation() { + if (this.animationFrame) + return; + const animate = () => { + this.draw(); + this.animationFrame = requestAnimationFrame(animate); + }; + animate(); + } + stopAnimation() { + if (this.animationFrame) { + cancelAnimationFrame(this.animationFrame); + this.animationFrame = null; + } + } + draw() { + if (!this.ctx || !this.canvas) + return; + if (!this.width || !this.height) { + this.resizeCanvas(); + if (!this.width || !this.height) + return; + } + const params = this.getDrawParams(); + if (!params) + return; + const { condition, timeOfDay } = params; + const width = this.width; + const height = this.height; + this.ctx.clearRect(0, 0, width, height); + const conditionLower = condition.toLowerCase(); + switch (conditionLower) { + case "sunny": + case "clear": + this.animations.sunny?.draw(Date.now(), width, height, timeOfDay); + break; + case "clear-night": + this.animations.sunny?.draw(Date.now(), width, height, { type: "night", progress: 0 }); + break; + case "rainy": + case "rain": + this.animations.rainy?.draw(Date.now(), width, height, timeOfDay, false); + break; + case "pouring": + this.animations.rainy?.draw(Date.now(), width, height, timeOfDay, true); + break; + case "snowy": + case "snow": + this.animations.snowy?.draw(Date.now(), width, height, timeOfDay); + break; + case "snowy-rainy": + this.animations.rainy?.draw(Date.now(), width, height, timeOfDay, false); + this.animations.snowy?.draw(Date.now(), width, height, timeOfDay); + break; + case "hail": + this.animations.hail?.draw(Date.now(), width, height, timeOfDay); + break; + case "foggy": + case "fog": + this.animations.foggy?.draw(Date.now(), width, height, timeOfDay); + break; + case "lightning": + this.animations.thunderstorm?.draw(Date.now(), width, height, timeOfDay, false); + break; + case "lightning-rainy": + this.animations.thunderstorm?.draw(Date.now(), width, height, timeOfDay, true); + break; + case "cloudy": + case "partlycloudy": + default: + this.animations.cloudy?.draw(Date.now(), width, height, timeOfDay); + break; + } + } +} + +// src/components/forecast-service.ts +class ForecastService { + hourlyForecast = []; + dailyForecast = []; + hourlySubscription = null; + dailySubscription = null; + onUpdate; + constructor(onUpdate) { + this.onUpdate = onUpdate; + } + getHourlyData() { + return this.hourlyForecast; + } + getDailyData() { + return this.dailyForecast; + } + async subscribe(hass, entityId, showDaily) { + if (!hass || !entityId) { + return; + } + this.unsubscribe(); + try { + this.hourlySubscription = hass.connection.subscribeMessage((event) => { + if (event.forecast && event.forecast.length > 0) { + this.hourlyForecast = event.forecast; + this.onUpdate(); + } + }, { + type: "weather/subscribe_forecast", + forecast_type: "hourly", + entity_id: entityId + }); + if (showDaily) { + this.dailySubscription = hass.connection.subscribeMessage((event) => { + if (event.forecast && event.forecast.length > 0) { + this.dailyForecast = event.forecast; + this.onUpdate(); + } + }, { + type: "weather/subscribe_forecast", + forecast_type: "daily", + entity_id: entityId + }); + } + } catch {} + } + async unsubscribe() { + if (this.hourlySubscription) { + try { + const unsubscribe = await this.hourlySubscription; + unsubscribe(); + } catch {} + this.hourlySubscription = null; + } + if (this.dailySubscription) { + try { + const unsubscribe = await this.dailySubscription; + unsubscribe(); + } catch {} + this.dailySubscription = null; + } + } + getHourlyForecast(hours, fallbackWeatherData) { + const maxHours = Math.max(1, Math.floor(Number(hours ?? DEFAULT_CONFIG.hourlyForecastHours))); + if (this.hourlyForecast && this.hourlyForecast.length > 0) { + return this.hourlyForecast.slice(0, maxHours); + } + if (!fallbackWeatherData?.forecast || fallbackWeatherData.forecast.length === 0) { + return []; + } + const now = new Date; + const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); + const tomorrow = new Date(today); + tomorrow.setDate(tomorrow.getDate() + 1); + const todayForecast = fallbackWeatherData.forecast.filter((item) => { + if (!item.datetime) + return false; + const itemDate = new Date(item.datetime); + const itemDay = new Date(itemDate.getFullYear(), itemDate.getMonth(), itemDate.getDate()); + return itemDay.getTime() === today.getTime() || itemDay.getTime() === tomorrow.getTime() && itemDate.getHours() <= now.getHours(); + }); + return todayForecast.sort((a, b) => new Date(a.datetime).getTime() - new Date(b.datetime).getTime()).slice(0, maxHours); + } + getDailyForecast(days, fallbackWeatherData) { + const maxDays = Math.max(1, Math.floor(Number(days ?? DEFAULT_CONFIG.dailyForecastDays))); + if (this.dailyForecast && this.dailyForecast.length > 0) { + return this.dailyForecast.slice(0, maxDays); + } + if (!fallbackWeatherData?.forecast || fallbackWeatherData.forecast.length === 0) { + return []; + } + const now = new Date; + const start = new Date(now.getFullYear(), now.getMonth(), now.getDate()); + const end = new Date(start); + end.setDate(end.getDate() + maxDays); + const toDayKey = (date) => { + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, "0"); + const day = String(date.getDate()).padStart(2, "0"); + return `${year}-${month}-${day}`; + }; + const dayBuckets = new Map; + fallbackWeatherData.forecast.forEach((item) => { + if (!item.datetime) + return; + const itemDate = new Date(item.datetime); + if (Number.isNaN(itemDate.getTime())) + return; + if (itemDate < start || itemDate >= end) + return; + const key = toDayKey(itemDate); + const hourScore = Math.abs(itemDate.getHours() + itemDate.getMinutes() / 60 - 12); + const existing = dayBuckets.get(key); + if (!existing || hourScore < existing.hourScore) { + dayBuckets.set(key, { item, itemDate, hourScore }); + } + }); + return Array.from(dayBuckets.values()).sort((a, b) => a.itemDate.getTime() - b.itemDate.getTime()).map((entry) => entry.item).slice(0, maxDays); + } +} + +// src/components/action-handler.ts +class ActionHandler { + holdTimer = null; + lastTap = null; + holdFired = false; + holdDelay = 500; + getHass; + getConfig; + fireEvent; + constructor(getHass, getConfig, fireEvent) { + this.getHass = getHass; + this.getConfig = getConfig; + this.fireEvent = fireEvent; + } + handleTap(e) { + if (e.target.closest(".forecast-item") || e.target.closest(".info-item")) { + return; + } + if (this.lastTap && Date.now() - this.lastTap < 300) { + this.handleDoubleTap(); + this.lastTap = null; + return; + } + this.lastTap = Date.now(); + setTimeout(() => { + if (this.lastTap) { + this.handleAction(this.getConfig().tapAction); + this.lastTap = null; + } + }, 300); + } + handlePointerDown() { + this.holdTimer = window.setTimeout(() => { + this.handleHold(); + this.holdFired = true; + }, this.holdDelay); + } + handlePointerUp(e) { + if (this.holdTimer) { + clearTimeout(this.holdTimer); + } + if (this.holdFired) { + e.preventDefault(); + e.stopPropagation(); + this.holdFired = false; + } + } + handleHold() { + this.handleAction(this.getConfig().holdAction); + } + handleDoubleTap() { + this.handleAction(this.getConfig().doubleTapAction); + } + handleAction(actionConfig) { + const hass = this.getHass(); + const config = this.getConfig(); + if (!actionConfig || !hass) + return; + const action = actionConfig.action || "more-info"; + switch (action) { + case "more-info": + this.fireEvent("hass-more-info", { entityId: actionConfig.entity || config.entity }); + break; + case "toggle": + hass.callService("homeassistant", "toggle", { + entity_id: actionConfig.entity || config.entity + }); + break; + case "call-service": + if (actionConfig.service) { + const [domain, service] = actionConfig.service.split("."); + hass.callService(domain, service, actionConfig.service_data || {}); + } + break; + case "navigate": + if (actionConfig.navigation_path) { + window.history.pushState(null, "", actionConfig.navigation_path); + this.fireEvent("location-changed", { replace: false }); + } + break; + case "url": + if (actionConfig.url_path) { + window.open(actionConfig.url_path); + } + break; + case "none": + default: + break; + } + } +} + +// src/components/weather-data.ts +function getWeatherState(hass, entityId) { + if (!hass || !entityId) + return null; + const entity = hass.states[entityId]; + return entity ? entity.state : null; +} +function getWeatherAttributes(hass, entityId) { + if (!hass || !entityId) + return {}; + const entity = hass.states[entityId]; + return entity ? entity.attributes : {}; +} +function getWeatherData(hass, entityId, config, hourlyForecast) { + const state3 = getWeatherState(hass, entityId); + const attrs = getWeatherAttributes(hass, entityId); + const condition = attrs.condition || state3 || "sunny"; + let templow = null; + if (config.templowAttribute && attrs[config.templowAttribute] != null) { + templow = attrs[config.templowAttribute]; + } else { + for (const attrName of TEMPLOW_ATTRIBUTES) { + if (attrs[attrName] != null) { + templow = attrs[attrName]; + break; + } + } + if (templow == null) { + templow = (attrs.forecast && attrs.forecast[0] ? attrs.forecast[0].templow ?? null : null) || (attrs.forecast_hourly && attrs.forecast_hourly[0] ? attrs.forecast_hourly[0].native_templow ?? null : null); + } + } + return { + condition, + temperature: attrs.temperature != null ? attrs.temperature : null, + apparentTemperature: attrs.apparent_temperature || null, + humidity: attrs.humidity != null ? attrs.humidity : null, + windSpeed: attrs.wind_speed != null ? attrs.wind_speed : null, + windGust: attrs.wind_gust_speed || attrs.wind_gust || null, + windBearing: attrs.wind_bearing != null ? attrs.wind_bearing : null, + windDirection: attrs.wind_direction || null, + pressure: attrs.pressure || null, + forecast: attrs.forecast || attrs.forecast_hourly || hourlyForecast || [], + friendlyName: attrs.friendly_name || i18n.t("weather"), + templow + }; +} + +// src/components/clock.ts +class WeatherClock extends LitElement { + constructor() { + super(...arguments); + this.format = null; + this.currentTime = ""; + } + clockInterval = null; + static styles = css` :host { display: block; } @@ -351,7 +4517,56 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex margin-bottom: 0; } } - `;connectedCallback(){if(super.connectedCallback(),this.format)this.updateTime(),this.clockInterval=window.setInterval(()=>this.updateTime(),1000)}disconnectedCallback(){if(super.disconnectedCallback(),this.clockInterval)clearInterval(this.clockInterval),this.clockInterval=null}updated(o){if(super.updated(o),o.has("format")){if(this.clockInterval)clearInterval(this.clockInterval),this.clockInterval=null;if(this.format)this.updateTime(),this.clockInterval=window.setInterval(()=>this.updateTime(),1000)}}updateTime(){if(!this.format)return;this.currentTime=Ci(new Date,this.format,d.t("am"),d.t("pm"))}render(){if(!this.format)return k``;return k`
${this.currentTime}
`}}w([t({type:String})],xi.prototype,"format",void 0),w([_o()],xi.prototype,"currentTime",void 0);customElements.define("weather-clock",xi);var Ta={wind:y` + `; + connectedCallback() { + super.connectedCallback(); + if (this.format) { + this.updateTime(); + this.clockInterval = window.setInterval(() => this.updateTime(), 1000); + } + } + disconnectedCallback() { + super.disconnectedCallback(); + if (this.clockInterval) { + clearInterval(this.clockInterval); + this.clockInterval = null; + } + } + updated(changedProperties) { + super.updated(changedProperties); + if (changedProperties.has("format")) { + if (this.clockInterval) { + clearInterval(this.clockInterval); + this.clockInterval = null; + } + if (this.format) { + this.updateTime(); + this.clockInterval = window.setInterval(() => this.updateTime(), 1000); + } + } + } + updateTime() { + if (!this.format) + return; + this.currentTime = formatClockTime(new Date, this.format, i18n.t("am"), i18n.t("pm")); + } + render() { + if (!this.format) + return html``; + return html`
${this.currentTime}
`; + } +} +__legacyDecorateClassTS([ + property({ type: String }) +], WeatherClock.prototype, "format", undefined); +__legacyDecorateClassTS([ + state() +], WeatherClock.prototype, "currentTime", undefined); +customElements.define("weather-clock", WeatherClock); + +// src/icons/svg-icons.ts +var SVG_ICONS = { + wind: svg` @@ -360,49 +4575,59 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex - `,humidity:y` + `, + humidity: svg` - `,sunrise:y` + `, + sunrise: svg` - `,sunset:y` + `, + sunset: svg` - `},Gi=(o)=>y` - + ` +}; +var windDirection = (bearing) => svg` + -`,Va={sunny:y` +`; +var WEATHER_CONDITION_ICONS = { + sunny: svg` - `,clear:y` + `, + clear: svg` - `,"clear-night":y` + `, + "clear-night": svg` - `,partlycloudy:y` + `, + partlycloudy: svg` @@ -417,7 +4642,8 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex - `,overcast:y` + `, + overcast: svg` @@ -446,14 +4672,16 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex - `,cloudy:y` + `, + cloudy: svg` - `,rainy:y` + `, + rainy: svg` @@ -472,7 +4700,8 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex - `,rain:y` + `, + rain: svg` @@ -491,7 +4720,8 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex - `,pouring:y` + `, + pouring: svg` @@ -510,7 +4740,8 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex - `,snowy:y` + `, + snowy: svg` @@ -535,7 +4766,8 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex - `,snow:y` + `, + snow: svg` @@ -560,7 +4792,8 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex - `,foggy:y` + `, + foggy: svg` @@ -572,7 +4805,8 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex - `,fog:y` + `, + fog: svg` @@ -584,7 +4818,8 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex - `,hail:y` + `, + hail: svg` @@ -603,7 +4838,8 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex - `,"snowy-rainy":y` + `, + "snowy-rainy": svg` @@ -622,7 +4858,8 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex - `,lightning:y` + `, + lightning: svg` @@ -645,7 +4882,8 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex - `,"lightning-rainy":y` + `, + "lightning-rainy": svg` @@ -668,21 +4906,48 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex - `,windy:y` + `, + windy: svg` - `,"windy-variant":y` + `, + "windy-variant": svg` - `};function E(o,...i){let a=Ta[o];if(typeof a==="function")return a(...i);return a||""}function eo(o){if(!o)return"";return Va[o.toLowerCase()]||""}class ji extends F{constructor(){super(...arguments);this.weather=null;this.sunData=null;this.config=null;this.entityAttributes=null}static styles=W` + ` +}; +function getSVGIcon(name, ...args) { + const icon = SVG_ICONS[name]; + if (typeof icon === "function") { + return icon(...args); + } + return icon || ""; +} +function getWeatherConditionIcon(condition) { + if (!condition) + return ""; + const icon = WEATHER_CONDITION_ICONS[condition.toLowerCase()]; + return icon || ""; +} + +// src/components/details.ts +class WeatherDetails extends LitElement { + constructor() { + super(...arguments); + this.weather = null; + this.sunData = null; + this.config = null; + this.entityAttributes = null; + } + static styles = css` :host { display: block; } @@ -724,34 +4989,92 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex height: 20px; display: block; } - `;hasContent(){if(!this.weather||!this.config)return!1;return this.config.showHumidity&&this.weather.humidity!=null||this.config.showWind&&this.weather.windSpeed!=null||this.config.showSunriseSunset&&this.sunData?.hasSunData===!0}renderHumidity(){if(!this.config?.showHumidity||this.weather?.humidity==null)return k``;return k` + `; + hasContent() { + if (!this.weather || !this.config) + return false; + return this.config.showHumidity && this.weather.humidity != null || this.config.showWind && this.weather.windSpeed != null || this.config.showSunriseSunset && this.sunData?.hasSunData === true; + } + renderHumidity() { + if (!this.config?.showHumidity || this.weather?.humidity == null) + return html``; + return html`
- ${E("humidity")} + ${getSVGIcon("humidity")} ${this.weather.humidity} %
- `}renderSunrise(){if(!this.config?.showSunriseSunset||!this.sunData?.hasSunData||!this.sunData.sunrise)return k``;return k` + `; + } + renderSunrise() { + if (!this.config?.showSunriseSunset || !this.sunData?.hasSunData || !this.sunData.sunrise) { + return html``; + } + return html`
- ${E("sunrise")} - ${No(this.sunData.sunrise,this.config.clockFormat,d.t("am"),d.t("pm"))} + ${getSVGIcon("sunrise")} + ${formatTime(this.sunData.sunrise, this.config.clockFormat, i18n.t("am"), i18n.t("pm"))}
- `}renderWind(){if(!this.config?.showWind||this.weather?.windSpeed==null)return k``;let o=this.entityAttributes||{},i=Jo(this.weather.windSpeed,o,this.config.windSpeedUnit),a=Qi(o,this.config.windSpeedUnit,d.t.bind(d)),n="";if(this.config.showWindGust&&this.weather.windGust)n=` / ${Jo(this.weather.windGust,o,this.config.windSpeedUnit)} ${a}`;let l=this.config.showWindDirection&&this.weather.windBearing!=null?Gi(this.weather.windBearing):E("wind");return k` + `; + } + renderWind() { + if (!this.config?.showWind || this.weather?.windSpeed == null) + return html``; + const attrs = this.entityAttributes || {}; + const speed = convertWindSpeed(this.weather.windSpeed, attrs, this.config.windSpeedUnit); + const unit = getWindSpeedUnit(attrs, this.config.windSpeedUnit, i18n.t.bind(i18n)); + let gustText = ""; + if (this.config.showWindGust && this.weather.windGust) { + const gustSpeed = convertWindSpeed(this.weather.windGust, attrs, this.config.windSpeedUnit); + gustText = ` / ${gustSpeed} ${unit}`; + } + const icon = this.config.showWindDirection && this.weather.windBearing != null ? windDirection(this.weather.windBearing) : getSVGIcon("wind"); + return html`
- ${l} - ${i} ${a}${n} + ${icon} + ${speed} ${unit}${gustText}
- `}renderSunset(){if(!this.config?.showSunriseSunset||!this.sunData?.hasSunData||!this.sunData.sunset)return k``;return k` + `; + } + renderSunset() { + if (!this.config?.showSunriseSunset || !this.sunData?.hasSunData || !this.sunData.sunset) { + return html``; + } + return html`
- ${E("sunset")} - ${No(this.sunData.sunset,this.config.clockFormat,d.t("am"),d.t("pm"))} + ${getSVGIcon("sunset")} + ${formatTime(this.sunData.sunset, this.config.clockFormat, i18n.t("am"), i18n.t("pm"))}
- `}render(){if(!this.hasContent())return k``;return k` + `; + } + render() { + if (!this.hasContent()) + return html``; + return html`
${this.renderHumidity()} ${this.renderSunrise()} ${this.renderWind()} ${this.renderSunset()}
- `}}w([t({type:Object})],ji.prototype,"weather",void 0),w([t({type:Object})],ji.prototype,"sunData",void 0),w([t({type:Object})],ji.prototype,"config",void 0),w([t({type:Object})],ji.prototype,"entityAttributes",void 0);customElements.define("weather-details",ji);var uo=W` + `; + } +} +__legacyDecorateClassTS([ + property({ type: Object }) +], WeatherDetails.prototype, "weather", undefined); +__legacyDecorateClassTS([ + property({ type: Object }) +], WeatherDetails.prototype, "sunData", undefined); +__legacyDecorateClassTS([ + property({ type: Object }) +], WeatherDetails.prototype, "config", undefined); +__legacyDecorateClassTS([ + property({ type: Object }) +], WeatherDetails.prototype, "entityAttributes", undefined); +customElements.define("weather-details", WeatherDetails); + +// src/components/forecast-styles.ts +var forecastStyles = css` :host { display: block; } @@ -841,87 +5164,465 @@ Please use the static 'html' tag function. See https://lit.dev/docs/templates/ex opacity: 0.6; font-size: 14px; } -`;class Di extends F{constructor(){super(...arguments);this.forecast=[];this.clockFormat="24h"}static styles=uo;_cleanup=null;connectedCallback(){super.connectedCallback(),this.updateComplete.then(()=>{this._cleanup=go(this.shadowRoot,".forecast-scroll")})}disconnectedCallback(){super.disconnectedCallback(),this._cleanup?.(),this._cleanup=null}getTemperature(o){return Math.round(o.temperature??o.temp??o.native_temperature??0)}render(){if(this.forecast.length===0)return k``;return k` +`; + +// src/components/hourly-forecast.ts +class HourlyForecast extends LitElement { + constructor() { + super(...arguments); + this.forecast = []; + this.clockFormat = "24h"; + } + static styles = forecastStyles; + _cleanup = null; + connectedCallback() { + super.connectedCallback(); + this.updateComplete.then(() => { + this._cleanup = setupHorizontalScroll(this.shadowRoot, ".forecast-scroll"); + }); + } + disconnectedCallback() { + super.disconnectedCallback(); + this._cleanup?.(); + this._cleanup = null; + } + getTemperature(item) { + return Math.round(item.temperature ?? item.temp ?? item.native_temperature ?? 0); + } + render() { + if (this.forecast.length === 0) + return html``; + return html`
-
${d.t("forecast_title")}
+
${i18n.t("forecast_title")}
- ${this.forecast.map((o)=>k` + ${this.forecast.map((item) => html`
-
${Bi(o.datetime,this.clockFormat,d.t("am"),d.t("pm"))}
-
${eo(o.condition||"sunny")}
-
${this.getTemperature(o)}°
+
${formatForecastTime(item.datetime, this.clockFormat, i18n.t("am"), i18n.t("pm"))}
+
${getWeatherConditionIcon(item.condition || "sunny")}
+
${this.getTemperature(item)}°
`)}
- `}}w([t({type:Array})],Di.prototype,"forecast",void 0),w([t({type:String})],Di.prototype,"clockFormat",void 0);customElements.define("hourly-forecast",Di);class Ti extends F{constructor(){super(...arguments);this.forecast=[];this.lang="en"}static styles=uo;_cleanup=null;connectedCallback(){super.connectedCallback(),this.updateComplete.then(()=>{this._cleanup=go(this.shadowRoot,".forecast-scroll")})}disconnectedCallback(){super.disconnectedCallback(),this._cleanup?.(),this._cleanup=null}getTemperature(o){return Math.round(o.temperature??o.temp??o.native_temperature??0)}render(){if(this.forecast.length===0)return k``;return k` + `; + } +} +__legacyDecorateClassTS([ + property({ type: Array }) +], HourlyForecast.prototype, "forecast", undefined); +__legacyDecorateClassTS([ + property({ type: String }) +], HourlyForecast.prototype, "clockFormat", undefined); +customElements.define("hourly-forecast", HourlyForecast); + +// src/components/daily-forecast.ts +class DailyForecast extends LitElement { + constructor() { + super(...arguments); + this.forecast = []; + this.lang = "en"; + } + static styles = forecastStyles; + _cleanup = null; + connectedCallback() { + super.connectedCallback(); + this.updateComplete.then(() => { + this._cleanup = setupHorizontalScroll(this.shadowRoot, ".forecast-scroll"); + }); + } + disconnectedCallback() { + super.disconnectedCallback(); + this._cleanup?.(); + this._cleanup = null; + } + getTemperature(item) { + return Math.round(item.temperature ?? item.temp ?? item.native_temperature ?? 0); + } + render() { + if (this.forecast.length === 0) + return html``; + return html`
-
${d.t("daily_forecast_title")}
+
${i18n.t("daily_forecast_title")}
- ${this.forecast.map((o)=>k` + ${this.forecast.map((item) => html`
-
${$i(o.datetime,this.lang)}
-
${eo(o.condition||"sunny")}
-
${this.getTemperature(o)}°
+
${formatForecastDay(item.datetime, this.lang)}
+
${getWeatherConditionIcon(item.condition || "sunny")}
+
${this.getTemperature(item)}°
`)}
- `}}w([t({type:Array})],Ti.prototype,"forecast",void 0),w([t({type:String})],Ti.prototype,"lang",void 0);customElements.define("daily-forecast",Ti);class Vo extends F{animationManager;forecastService;actionHandler;subscribedEntity=null;subscribedShowDaily=!1;_testTimeOfDay;static get styles(){return Pi}static getConfigElement(){return document.createElement("dynamic-weather-card-editor")}static getStubConfig(){return{type:"custom:dynamic-weather-card",entity:"weather.home",show_hourly_forecast:!0,hourly_forecast_hours:e.hourlyForecastHours,show_daily_forecast:!0,daily_forecast_days:e.dailyForecastDays}}constructor(){super();this.config={},this.animationManager=new xo(()=>this.getDrawParams()),this.forecastService=new Go(()=>this.requestUpdate()),this.actionHandler=new jo(()=>this.hass,()=>this.config,(o,i)=>this.fireEvent(o,i))}connectedCallback(){super.connectedCallback(),this.updateComplete.then(()=>{setTimeout(()=>{let o=this.shadowRoot?.querySelector(".canvas-container");if(o)this.animationManager.setup(o)},100)})}disconnectedCallback(){super.disconnectedCallback(),this.animationManager.destroy(),this.forecastService.unsubscribe()}updated(o){if(super.updated(o),o.has("hass")||o.has("config")){let a=this.config.entity,n=this.config.showDailyForecast??!1;if(this.hass&&a&&(a!==this.subscribedEntity||n!==this.subscribedShowDaily))this.subscribedEntity=a,this.subscribedShowDaily=n,this.forecastService.subscribe(this.hass,a,n)}let i=I({configLang:this.config?.language,hassLang:this.hass?.language});if(d.lang!==i)d.setLanguage(i)}getDrawParams(){if(!this.hass||!this.config.entity)return null;let o=To(this.hass,this.config.entity,this.config,this.forecastService.getHourlyData()),i=this.hass.states[this.config.entity],a=So(i||{},this.config.sunriseEntity,this.config.sunsetEntity,this.hass),n=this._testTimeOfDay||qo(a);return{condition:o.condition,timeOfDay:n}}getDetailsConfig(){return{showHumidity:this.config.showHumidity??!0,showWind:this.config.showWind??!0,showWindGust:this.config.showWindGust??!0,showWindDirection:this.config.showWindDirection??!0,showSunriseSunset:this.config.showSunriseSunset??!0,clockFormat:this.config.clockFormat??"24h",windSpeedUnit:this.config.windSpeedUnit??"ms"}}setConfig(o){if(!o.entity)throw Error("Please define a weather entity");let i=o.show_hourly_forecast??o.show_forecast;if(this.config={type:"custom:dynamic-weather-card",entity:o.entity,icons_path:o.icons_path,name:o.name,height:o.height||e.height,showFeelsLike:o.show_feels_like!==!1,showWind:o.show_wind!==!1,showWindGust:o.show_wind_gust!==!1,showWindDirection:o.show_wind_direction!==!1,showHumidity:o.show_humidity!==!1,showMinTemp:o.show_min_temp!==!1,showForecast:o.show_forecast===!0,showHourlyForecast:i===!0,showDailyForecast:o.show_daily_forecast===!0,hourlyForecastHours:o.hourly_forecast_hours??e.hourlyForecastHours,dailyForecastDays:o.daily_forecast_days??e.dailyForecastDays,showSunriseSunset:o.show_sunrise_sunset!==!1,showClock:o.show_clock===!0,clockPosition:o.clock_position||e.clockPosition,clockFormat:o.clock_format||e.clockFormat,overlayOpacity:o.overlay_opacity!==void 0?o.overlay_opacity:e.overlayOpacity,language:o.language||e.language,windSpeedUnit:o.wind_speed_unit||e.windSpeedUnit,sunriseEntity:o.sunrise_entity||null,sunsetEntity:o.sunset_entity||null,templowAttribute:o.templow_attribute||null,tapAction:o.tap_action||{action:"more-info"},holdAction:o.hold_action||{action:"none"},doubleTapAction:o.double_tap_action||{action:"none"}},this.config.language)d.setLanguage(this.config.language)}fireEvent(o,i={}){let a=new CustomEvent(o,{detail:i,bubbles:!0,composed:!0});this.dispatchEvent(a)}getCardSize(){return 1}render(){if(!this.hass)return k`
No Home Assistant connection
`;let o=To(this.hass,this.config.entity,this.config,this.forecastService.getHourlyData()),i=this.hass.states[this.config.entity],a=So(i,this.config.sunriseEntity,this.config.sunsetEntity,this.hass),n=this._testTimeOfDay||qo(a),l=`weather-card ${n.type}`,s=this.config.height?`${this.config.height}px`:"200px",r=Wi(n),c=r?`background: linear-gradient(135deg, rgb(${r.start.r}, ${r.start.g}, ${r.start.b}), rgb(${r.end.r}, ${r.end.g}, ${r.end.b}));`:"",g=`--overlay-opacity: ${this.config.overlayOpacity!==void 0?this.config.overlayOpacity:e.overlayOpacity};`,h=this.config.showHourlyForecast?this.forecastService.getHourlyForecast(this.config.hourlyForecastHours??e.hourlyForecastHours,o):[],f=this.config.showDailyForecast?this.forecastService.getDailyForecast(this.config.dailyForecastDays??e.dailyForecastDays,o):[];return k` + `; + } +} +__legacyDecorateClassTS([ + property({ type: Array }) +], DailyForecast.prototype, "forecast", undefined); +__legacyDecorateClassTS([ + property({ type: String }) +], DailyForecast.prototype, "lang", undefined); +customElements.define("daily-forecast", DailyForecast); + +// src/components/card.ts +class AnimatedWeatherCard extends LitElement { + animationManager; + forecastService; + actionHandler; + subscribedEntity = null; + subscribedShowDaily = false; + _testTimeOfDay; + static get styles() { + return cardStyles; + } + static getConfigElement() { + return document.createElement("dynamic-weather-card-editor"); + } + static getStubConfig() { + return { + type: "custom:dynamic-weather-card", + entity: "weather.home", + show_hourly_forecast: true, + hourly_forecast_hours: DEFAULT_CONFIG.hourlyForecastHours, + show_daily_forecast: true, + daily_forecast_days: DEFAULT_CONFIG.dailyForecastDays + }; + } + constructor() { + super(); + this.config = {}; + this.animationManager = new AnimationManager(() => this.getDrawParams()); + this.forecastService = new ForecastService(() => this.requestUpdate()); + this.actionHandler = new ActionHandler(() => this.hass, () => this.config, (type, detail) => this.fireEvent(type, detail)); + } + connectedCallback() { + super.connectedCallback(); + this.updateComplete.then(() => { + setTimeout(() => { + const container = this.shadowRoot?.querySelector(".canvas-container"); + if (container) { + this.animationManager.setup(container); + } + }, 100); + }); + } + disconnectedCallback() { + super.disconnectedCallback(); + this.animationManager.destroy(); + this.forecastService.unsubscribe(); + } + updated(changedProperties) { + super.updated(changedProperties); + if (changedProperties.has("hass") || changedProperties.has("config")) { + const entity = this.config.entity; + const showDaily = this.config.showDailyForecast ?? false; + if (this.hass && entity && (entity !== this.subscribedEntity || showDaily !== this.subscribedShowDaily)) { + this.subscribedEntity = entity; + this.subscribedShowDaily = showDaily; + this.forecastService.subscribe(this.hass, entity, showDaily); + } + } + const resolvedLang = resolveLanguage({ + configLang: this.config?.language, + hassLang: this.hass?.language + }); + if (i18n.lang !== resolvedLang) { + i18n.setLanguage(resolvedLang); + } + } + getDrawParams() { + if (!this.hass || !this.config.entity) + return null; + const weather = getWeatherData(this.hass, this.config.entity, this.config, this.forecastService.getHourlyData()); + const weatherState = this.hass.states[this.config.entity]; + const sunData = getSunriseSunsetData(weatherState || {}, this.config.sunriseEntity, this.config.sunsetEntity, this.hass); + const timeOfDay = this._testTimeOfDay || getTimeOfDayWithSunData(sunData); + return { + condition: weather.condition, + timeOfDay + }; + } + getDetailsConfig() { + return { + showHumidity: this.config.showHumidity ?? true, + showWind: this.config.showWind ?? true, + showWindGust: this.config.showWindGust ?? true, + showWindDirection: this.config.showWindDirection ?? true, + showSunriseSunset: this.config.showSunriseSunset ?? true, + clockFormat: this.config.clockFormat ?? "24h", + windSpeedUnit: this.config.windSpeedUnit ?? "ms" + }; + } + setConfig(config) { + if (!config.entity) { + throw new Error("Please define a weather entity"); + } + const showHourlyForecast = config.show_hourly_forecast ?? config.show_forecast; + this.config = { + type: "custom:dynamic-weather-card", + entity: config.entity, + icons_path: config.icons_path, + name: config.name, + height: config.height || DEFAULT_CONFIG.height, + showFeelsLike: config.show_feels_like !== false, + showWind: config.show_wind !== false, + showWindGust: config.show_wind_gust !== false, + showWindDirection: config.show_wind_direction !== false, + showHumidity: config.show_humidity !== false, + showMinTemp: config.show_min_temp !== false, + showForecast: config.show_forecast === true, + showHourlyForecast: showHourlyForecast === true, + showDailyForecast: config.show_daily_forecast === true, + hourlyForecastHours: config.hourly_forecast_hours ?? DEFAULT_CONFIG.hourlyForecastHours, + dailyForecastDays: config.daily_forecast_days ?? DEFAULT_CONFIG.dailyForecastDays, + showSunriseSunset: config.show_sunrise_sunset !== false, + showClock: config.show_clock === true, + clockPosition: config.clock_position || DEFAULT_CONFIG.clockPosition, + clockFormat: config.clock_format || DEFAULT_CONFIG.clockFormat, + overlayOpacity: config.overlay_opacity !== undefined ? config.overlay_opacity : DEFAULT_CONFIG.overlayOpacity, + language: config.language || DEFAULT_CONFIG.language, + windSpeedUnit: config.wind_speed_unit || DEFAULT_CONFIG.windSpeedUnit, + sunriseEntity: config.sunrise_entity || null, + sunsetEntity: config.sunset_entity || null, + templowAttribute: config.templow_attribute || null, + tapAction: config.tap_action || { action: "more-info" }, + holdAction: config.hold_action || { action: "none" }, + doubleTapAction: config.double_tap_action || { action: "none" } + }; + if (this.config.language) { + i18n.setLanguage(this.config.language); + } + } + fireEvent(type, detail = {}) { + const event = new CustomEvent(type, { + detail, + bubbles: true, + composed: true + }); + this.dispatchEvent(event); + } + getCardSize() { + return 1; + } + render() { + if (!this.hass) { + return html`
No Home Assistant connection
`; + } + const weather = getWeatherData(this.hass, this.config.entity, this.config, this.forecastService.getHourlyData()); + const weatherState = this.hass.states[this.config.entity]; + const sunData = getSunriseSunsetData(weatherState, this.config.sunriseEntity, this.config.sunsetEntity, this.hass); + const timeOfDay = this._testTimeOfDay || getTimeOfDayWithSunData(sunData); + const cardClasses = `weather-card ${timeOfDay.type}`; + const minHeight = this.config.height ? `${this.config.height}px` : "200px"; + const bgGradient = getBackgroundGradient(timeOfDay); + const bgStyle = bgGradient ? `background: linear-gradient(135deg, rgb(${bgGradient.start.r}, ${bgGradient.start.g}, ${bgGradient.start.b}), rgb(${bgGradient.end.r}, ${bgGradient.end.g}, ${bgGradient.end.b}));` : ""; + const overlayOpacity = this.config.overlayOpacity !== undefined ? this.config.overlayOpacity : DEFAULT_CONFIG.overlayOpacity; + const overlayStyle = `--overlay-opacity: ${overlayOpacity};`; + const hourlyForecast = this.config.showHourlyForecast ? this.forecastService.getHourlyForecast(this.config.hourlyForecastHours ?? DEFAULT_CONFIG.hourlyForecastHours, weather) : []; + const dailyForecast = this.config.showDailyForecast ? this.forecastService.getDailyForecast(this.config.dailyForecastDays ?? DEFAULT_CONFIG.dailyForecastDays, weather) : []; + return html` this.actionHandler.handleTap(m)} - @pointerdown=${()=>this.actionHandler.handlePointerDown()} - @pointerup=${(m)=>this.actionHandler.handlePointerUp(m)} - @pointercancel=${(m)=>this.actionHandler.handlePointerUp(m)} + @click=${(e) => this.actionHandler.handleTap(e)} + @pointerdown=${() => this.actionHandler.handlePointerDown()} + @pointerup=${(e) => this.actionHandler.handlePointerUp(e)} + @pointercancel=${(e) => this.actionHandler.handlePointerUp(e)} > -
+
- ${this.config.name&&this.config.name.trim()!==""?k` + ${this.config.name && this.config.name.trim() !== "" ? html`
${this.config.name}
- `:""} + ` : ""}
-
${d.t(o.condition)}
-
${o.temperature!=null?Math.round(o.temperature)+"°":d.t("no_data")}
- ${this.config.showMinTemp?k` +
${i18n.t(weather.condition)}
+
${weather.temperature != null ? Math.round(weather.temperature) + "°" : i18n.t("no_data")}
+ ${this.config.showMinTemp ? html`
- ↓ ${o.templow!=null?`${Math.round(o.templow)}°`:d.t("no_data")} + ↓ ${weather.templow != null ? `${Math.round(weather.templow)}°` : i18n.t("no_data")}
- `:""} - ${this.config.showFeelsLike?k` -
${d.t("feels_like")} ${o.apparentTemperature!=null?`${Math.round(o.apparentTemperature)}°`:d.t("no_data")}
- `:""} + ` : ""} + ${this.config.showFeelsLike ? html` +
${i18n.t("feels_like")} ${weather.apparentTemperature != null ? `${Math.round(weather.apparentTemperature)}°` : i18n.t("no_data")}
+ ` : ""}
-
+
- `}}w([t({type:Object})],Vo.prototype,"hass",void 0),w([t({type:Object})],Vo.prototype,"config",void 0);class Uo extends F{constructor(){super(...arguments);this._config={}}setConfig(o){this._config={name:"",height:e.height,show_feels_like:e.showFeelsLike,show_wind:e.showWind,show_wind_gust:e.showWindGust,show_wind_direction:e.showWindDirection,show_humidity:e.showHumidity,show_min_temp:e.showMinTemp,show_hourly_forecast:e.showHourlyForecast,hourly_forecast_hours:e.hourlyForecastHours,show_daily_forecast:e.showDailyForecast,daily_forecast_days:e.dailyForecastDays,show_sunrise_sunset:e.showSunriseSunset,show_clock:e.showClock,clock_position:e.clockPosition,clock_format:e.clockFormat,overlay_opacity:e.overlayOpacity,language:e.language,wind_speed_unit:e.windSpeedUnit,sunrise_entity:"",sunset_entity:"",...o}}updated(o){if(super.updated(o),o.has("hass")){let i=I({hassLang:this.hass?.language});if(d.lang!==i)d.setLanguage(i),this.requestUpdate()}}get _schema(){return[{name:"entity",required:!0,selector:{entity:{domain:["weather"]}}},{name:"name",selector:{text:{}}},{name:"height",selector:{number:{min:200,max:800,step:10,mode:"box"}}},{name:"show_feels_like",selector:{boolean:{}}},{name:"show_wind",selector:{boolean:{}}},{name:"show_wind_gust",selector:{boolean:{}}},{name:"show_wind_direction",selector:{boolean:{}}},{name:"show_humidity",selector:{boolean:{}}},{name:"show_min_temp",selector:{boolean:{}}},{name:"show_hourly_forecast",selector:{boolean:{}}},{name:"hourly_forecast_hours",selector:{number:{min:1,max:24,step:1,mode:"box"}}},{name:"show_daily_forecast",selector:{boolean:{}}},{name:"daily_forecast_days",selector:{number:{min:1,max:14,step:1,mode:"box"}}},{name:"show_sunrise_sunset",selector:{boolean:{}}},{name:"sunrise_entity",selector:{entity:{domain:["sensor"]}}},{name:"sunset_entity",selector:{entity:{domain:["sensor"]}}},{name:"show_clock",selector:{boolean:{}}},{name:"clock_position",selector:{select:{options:[{label:d.t("editor.clock_position_top"),value:"top"},{label:d.t("editor.clock_position_details"),value:"details"}]}}},{name:"clock_format",selector:{select:{options:[{label:d.t("editor.clock_format_24h"),value:"24h"},{label:d.t("editor.clock_format_12h"),value:"12h"}]}}},{name:"overlay_opacity",selector:{number:{min:0,max:1,step:0.05,mode:"box"}}},{name:"language",selector:{select:{options:[{label:d.t("editor.language_auto"),value:"auto"},{label:d.t("editor.language_en"),value:"en"},{label:d.t("editor.language_ru"),value:"ru"},{label:d.t("editor.language_de"),value:"de"},{label:d.t("editor.language_nl"),value:"nl"},{label:d.t("editor.language_fr"),value:"fr"},{label:d.t("editor.language_es"),value:"es"},{label:d.t("editor.language_it"),value:"it"},{label:d.t("editor.language_sk"),value:"sk"},{label:d.t("editor.language_hu"),value:"hu"}]}}},{name:"wind_speed_unit",selector:{select:{options:[{label:d.t("editor.wind_speed_unit_ms"),value:"ms"},{label:d.t("editor.wind_speed_unit_kmh"),value:"kmh"}]}}}]}_computeLabel=(o)=>{let i=`editor.${o.name}`,a=d.t(i);return a===i?o.name:a};_valueChanged(o){let i=o.detail?.value;if(!i)return;this._config=i,this.dispatchEvent(new CustomEvent("config-changed",{detail:{config:this._config},bubbles:!0,composed:!0}))}render(){if(!this.hass)return k``;return k` + `; + } +} +__legacyDecorateClassTS([ + property({ type: Object }) +], AnimatedWeatherCard.prototype, "hass", undefined); +__legacyDecorateClassTS([ + property({ type: Object }) +], AnimatedWeatherCard.prototype, "config", undefined); + +// src/components/editor.ts +class DynamicWeatherCardEditor extends LitElement { + constructor() { + super(...arguments); + this._config = {}; + } + setConfig(config) { + this._config = { + name: "", + height: DEFAULT_CONFIG.height, + show_feels_like: DEFAULT_CONFIG.showFeelsLike, + show_wind: DEFAULT_CONFIG.showWind, + show_wind_gust: DEFAULT_CONFIG.showWindGust, + show_wind_direction: DEFAULT_CONFIG.showWindDirection, + show_humidity: DEFAULT_CONFIG.showHumidity, + show_min_temp: DEFAULT_CONFIG.showMinTemp, + show_hourly_forecast: DEFAULT_CONFIG.showHourlyForecast, + hourly_forecast_hours: DEFAULT_CONFIG.hourlyForecastHours, + show_daily_forecast: DEFAULT_CONFIG.showDailyForecast, + daily_forecast_days: DEFAULT_CONFIG.dailyForecastDays, + show_sunrise_sunset: DEFAULT_CONFIG.showSunriseSunset, + show_clock: DEFAULT_CONFIG.showClock, + clock_position: DEFAULT_CONFIG.clockPosition, + clock_format: DEFAULT_CONFIG.clockFormat, + overlay_opacity: DEFAULT_CONFIG.overlayOpacity, + language: DEFAULT_CONFIG.language, + wind_speed_unit: DEFAULT_CONFIG.windSpeedUnit, + sunrise_entity: "", + sunset_entity: "", + ...config + }; + } + updated(changedProperties) { + super.updated(changedProperties); + if (changedProperties.has("hass")) { + const resolvedLang = resolveLanguage({ hassLang: this.hass?.language }); + if (i18n.lang !== resolvedLang) { + i18n.setLanguage(resolvedLang); + this.requestUpdate(); + } + } + } + get _schema() { + return [ + { name: "entity", required: true, selector: { entity: { domain: ["weather"] } } }, + { name: "name", selector: { text: {} } }, + { name: "height", selector: { number: { min: 200, max: 800, step: 10, mode: "box" } } }, + { name: "show_feels_like", selector: { boolean: {} } }, + { name: "show_wind", selector: { boolean: {} } }, + { name: "show_wind_gust", selector: { boolean: {} } }, + { name: "show_wind_direction", selector: { boolean: {} } }, + { name: "show_humidity", selector: { boolean: {} } }, + { name: "show_min_temp", selector: { boolean: {} } }, + { name: "show_hourly_forecast", selector: { boolean: {} } }, + { name: "hourly_forecast_hours", selector: { number: { min: 1, max: 24, step: 1, mode: "box" } } }, + { name: "show_daily_forecast", selector: { boolean: {} } }, + { name: "daily_forecast_days", selector: { number: { min: 1, max: 14, step: 1, mode: "box" } } }, + { name: "show_sunrise_sunset", selector: { boolean: {} } }, + { name: "sunrise_entity", selector: { entity: { domain: ["sensor"] } } }, + { name: "sunset_entity", selector: { entity: { domain: ["sensor"] } } }, + { name: "show_clock", selector: { boolean: {} } }, + { + name: "clock_position", + selector: { + select: { + options: [ + { label: i18n.t("editor.clock_position_top"), value: "top" }, + { label: i18n.t("editor.clock_position_details"), value: "details" } + ] + } + } + }, + { + name: "clock_format", + selector: { + select: { + options: [ + { label: i18n.t("editor.clock_format_24h"), value: "24h" }, + { label: i18n.t("editor.clock_format_12h"), value: "12h" } + ] + } + } + }, + { name: "overlay_opacity", selector: { number: { min: 0, max: 1, step: 0.05, mode: "box" } } }, + { + name: "language", + selector: { + select: { + options: [ + { label: i18n.t("editor.language_auto"), value: "auto" }, + { label: i18n.t("editor.language_en"), value: "en" }, + { label: i18n.t("editor.language_ru"), value: "ru" }, + { label: i18n.t("editor.language_de"), value: "de" }, + { label: i18n.t("editor.language_nl"), value: "nl" }, + { label: i18n.t("editor.language_fr"), value: "fr" }, + { label: i18n.t("editor.language_es"), value: "es" }, + { label: i18n.t("editor.language_it"), value: "it" }, + { label: i18n.t("editor.language_sk"), value: "sk" }, + { label: i18n.t("editor.language_hu"), value: "hu" } + ] + } + } + }, + { + name: "wind_speed_unit", + selector: { + select: { + options: [ + { label: i18n.t("editor.wind_speed_unit_ms"), value: "ms" }, + { label: i18n.t("editor.wind_speed_unit_kmh"), value: "kmh" } + ] + } + } + } + ]; + } + _computeLabel = (schema) => { + const key = `editor.${schema.name}`; + const label = i18n.t(key); + return label === key ? schema.name : label; + }; + _valueChanged(ev) { + const value = ev.detail?.value; + if (!value) + return; + this._config = value; + this.dispatchEvent(new CustomEvent("config-changed", { + detail: { config: this._config }, + bubbles: true, + composed: true + })); + } + render() { + if (!this.hass) { + return html``; + } + return html` - `}}w([t({attribute:!1})],Uo.prototype,"hass",void 0),w([_o()],Uo.prototype,"_config",void 0);var Vi={ATTRIBUTE:1,CHILD:2,PROPERTY:3,BOOLEAN_ATTRIBUTE:4,EVENT:5,ELEMENT:6},Ui=(o)=>(...i)=>({["_$litDirective$"]:o,values:i});class Ro{constructor(o){}get _$isConnected(){return this._$parent._$isConnected}_$initialize(o,i,a){this.__part=o,this._$parent=i,this.__attributeIndex=a}_$resolve(o,i){return this.update(o,i)}update(o,i){return this.render(...i)}}var Ua=!0,cr=Ua&&window.ShadyDOM?.inUse&&window.ShadyDOM?.noPatch===!0?window.ShadyDOM.wrap:(o)=>o;var Ri=(o)=>o.strings===void 0;var Ra=!0,oo=(o,i)=>{let a=o._$disconnectableChildren;if(a===void 0)return!1;for(let n of a)n._$notifyDirectiveConnectionChanged?.(i,!1),oo(n,i);return!0},ko=(o)=>{let i,a;do{if((i=o._$parent)===void 0)break;a=i._$disconnectableChildren,a.delete(o),o=i}while(a?.size===0)},Xi=(o)=>{for(let i;i=o._$parent;o=i){let a=i._$disconnectableChildren;if(a===void 0)i._$disconnectableChildren=a=new Set;else if(a.has(o))break;a.add(o),La(i)}};function Xa(o){if(this._$disconnectableChildren!==void 0)ko(this),this._$parent=o,Xi(this);else this._$parent=o}function Ya(o,i=!1,a=0){let n=this._$committedValue,l=this._$disconnectableChildren;if(l===void 0||l.size===0)return;if(i){if(Array.isArray(n))for(let s=a;s{if(o.type==Vi.CHILD)o._$notifyConnectionChanged??=Ya,o._$reparentDisconnectables??=Xa};class Xo extends Ro{constructor(){super(...arguments);this._$disconnectableChildren=void 0}_$initialize(o,i,a){super._$initialize(o,i,a),Xi(this),this.isConnected=o._$isConnected}["_$notifyDirectiveConnectionChanged"](o,i=!0){if(o!==this.isConnected)if(this.isConnected=o,o)this.reconnected?.();else this.disconnected?.();if(i)oo(this,o),ko(this)}setValue(o){if(Ri(this.__part))this.__part._$setValue(o,this);else{if(Ra&&this.__attributeIndex===void 0)throw Error("Expected this.__attributeIndex to be a number");let i=[...this.__part._$committedValue];i[this.__attributeIndex]=o,this.__part._$setValue(i,this,0)}}disconnected(){}reconnected(){}}class Yi extends Xo{_key="";_onLangChange=null;render(o){return this._key=o,d.t(o)}reconnected(){this._onLangChange=()=>{this.setValue(d.t(this._key))},window.addEventListener("language-changed",this._onLangChange)}disconnected(){if(this._onLangChange)window.removeEventListener("language-changed",this._onLangChange)}}var Ia=Ui(Yi);try{customElements.define("dynamic-weather-card",Vo),customElements.define("dynamic-weather-card-editor",Uo),console.log(`%cDynamic Weather Card %c${bi}`,"color: #007AFF; font-weight: bold; font-size: 14px;","color: #666; font-size: 12px;",` -Динамическая карточка погоды`),window.customCards=window.customCards||[];let o={type:"dynamic-weather-card",name:"Dynamic Weather Card",description:"Динамическая карточка погоды",preview:!0,documentationURL:"https://github.com/teuchezh/dynamic-weather-card"};window.customCards.push(o)}catch(o){console.error("❌ Ошибка при регистрации Dynamic Weather Card:",o)}export{Ia as t,I as resolveLanguage,d as i18n}; + `; + } +} +__legacyDecorateClassTS([ + property({ attribute: false }) +], DynamicWeatherCardEditor.prototype, "hass", undefined); +__legacyDecorateClassTS([ + state() +], DynamicWeatherCardEditor.prototype, "_config", undefined); +// node_modules/lit-html/development/directive.js +var PartType = { + ATTRIBUTE: 1, + CHILD: 2, + PROPERTY: 3, + BOOLEAN_ATTRIBUTE: 4, + EVENT: 5, + ELEMENT: 6 +}; +var directive = (c) => (...values) => ({ + ["_$litDirective$"]: c, + values +}); + +class Directive { + constructor(_partInfo) {} + get _$isConnected() { + return this._$parent._$isConnected; + } + _$initialize(part, parent, attributeIndex) { + this.__part = part; + this._$parent = parent; + this.__attributeIndex = attributeIndex; + } + _$resolve(part, props) { + return this.update(part, props); + } + update(_part, props) { + return this.render(...props); + } +} +// node_modules/lit-html/development/directive-helpers.js +var ENABLE_SHADYDOM_NOPATCH2 = true; +var wrap2 = ENABLE_SHADYDOM_NOPATCH2 && window.ShadyDOM?.inUse && window.ShadyDOM?.noPatch === true ? window.ShadyDOM.wrap : (node) => node; +var isSingleExpression = (part) => part.strings === undefined; + +// node_modules/lit-html/development/async-directive.js +var DEV_MODE6 = true; +var notifyChildrenConnectedChanged = (parent, isConnected) => { + const children = parent._$disconnectableChildren; + if (children === undefined) { + return false; + } + for (const obj of children) { + obj["_$notifyDirectiveConnectionChanged"]?.(isConnected, false); + notifyChildrenConnectedChanged(obj, isConnected); + } + return true; +}; +var removeDisconnectableFromParent = (obj) => { + let parent, children; + do { + if ((parent = obj._$parent) === undefined) { + break; + } + children = parent._$disconnectableChildren; + children.delete(obj); + obj = parent; + } while (children?.size === 0); +}; +var addDisconnectableToParent = (obj) => { + for (let parent;parent = obj._$parent; obj = parent) { + let children = parent._$disconnectableChildren; + if (children === undefined) { + parent._$disconnectableChildren = children = new Set; + } else if (children.has(obj)) { + break; + } + children.add(obj); + installDisconnectAPI(parent); + } +}; +function reparentDisconnectables(newParent) { + if (this._$disconnectableChildren !== undefined) { + removeDisconnectableFromParent(this); + this._$parent = newParent; + addDisconnectableToParent(this); + } else { + this._$parent = newParent; + } +} +function notifyChildPartConnectedChanged(isConnected, isClearingValue = false, fromPartIndex = 0) { + const value = this._$committedValue; + const children = this._$disconnectableChildren; + if (children === undefined || children.size === 0) { + return; + } + if (isClearingValue) { + if (Array.isArray(value)) { + for (let i = fromPartIndex;i < value.length; i++) { + notifyChildrenConnectedChanged(value[i], false); + removeDisconnectableFromParent(value[i]); + } + } else if (value != null) { + notifyChildrenConnectedChanged(value, false); + removeDisconnectableFromParent(value); + } + } else { + notifyChildrenConnectedChanged(this, isConnected); + } +} +var installDisconnectAPI = (obj) => { + if (obj.type == PartType.CHILD) { + obj._$notifyConnectionChanged ??= notifyChildPartConnectedChanged; + obj._$reparentDisconnectables ??= reparentDisconnectables; + } +}; + +class AsyncDirective extends Directive { + constructor() { + super(...arguments); + this._$disconnectableChildren = undefined; + } + _$initialize(part, parent, attributeIndex) { + super._$initialize(part, parent, attributeIndex); + addDisconnectableToParent(this); + this.isConnected = part._$isConnected; + } + ["_$notifyDirectiveConnectionChanged"](isConnected, isClearingDirective = true) { + if (isConnected !== this.isConnected) { + this.isConnected = isConnected; + if (isConnected) { + this.reconnected?.(); + } else { + this.disconnected?.(); + } + } + if (isClearingDirective) { + notifyChildrenConnectedChanged(this, isConnected); + removeDisconnectableFromParent(this); + } + } + setValue(value) { + if (isSingleExpression(this.__part)) { + this.__part._$setValue(value, this); + } else { + if (DEV_MODE6 && this.__attributeIndex === undefined) { + throw new Error(`Expected this.__attributeIndex to be a number`); + } + const newValues = [...this.__part._$committedValue]; + newValues[this.__attributeIndex] = value; + this.__part._$setValue(newValues, this, 0); + } + } + disconnected() {} + reconnected() {} +} +// src/internationalization/directive.ts +class TDirective extends AsyncDirective { + _key = ""; + _onLangChange = null; + render(key) { + this._key = key; + return i18n.t(key); + } + reconnected() { + this._onLangChange = () => { + this.setValue(i18n.t(this._key)); + }; + window.addEventListener("language-changed", this._onLangChange); + } + disconnected() { + if (this._onLangChange) { + window.removeEventListener("language-changed", this._onLangChange); + } + } +} +var t = directive(TDirective); + +// src/index.ts +try { + customElements.define("dynamic-weather-card", AnimatedWeatherCard); + customElements.define("dynamic-weather-card-editor", DynamicWeatherCardEditor); + console.log(`%cDynamic Weather Card %c${VERSION}`, "color: #007AFF; font-weight: bold; font-size: 14px;", "color: #666; font-size: 12px;", ` +Динамическая карточка погоды`); + window.customCards = window.customCards || []; + const cardRegistration = { + type: "dynamic-weather-card", + name: "Dynamic Weather Card", + description: "Динамическая карточка погоды", + preview: true, + documentationURL: "https://github.com/teuchezh/dynamic-weather-card" + }; + window.customCards.push(cardRegistration); +} catch (error) { + console.error("❌ Ошибка при регистрации Dynamic Weather Card:", error); +} +export { + t, + resolveLanguage, + i18n +}; diff --git a/src/components/styles.ts b/src/components/styles.ts index a34b7a3..6c375e5 100644 --- a/src/components/styles.ts +++ b/src/components/styles.ts @@ -57,6 +57,7 @@ export const cardStyles = css` height: 100%; min-height: 100%; pointer-events: none; + z-index: 0; } canvas { @@ -78,13 +79,13 @@ export const cardStyles = css` rgba(0, 0, 0, calc(var(--overlay-opacity) * 0.8)) 0%, rgba(0, 0, 0, calc(var(--overlay-opacity) * 1.2)) 100% ); - z-index: 0; + z-index: 1; border-radius: 16px; } .content { position: relative; - z-index: 1; + z-index: 2; padding: 20px; display: flex; flex-direction: column;