{"version":3,"file":"count-down.js","sources":["../../dev/js/count-down.js"],"sourcesContent":["/**\n * Defines a custom element `` for displaying a countdown timer.\n * This component supports displaying days, hours, minutes, and seconds until a specified date and time.\n * It can be styled through CSS custom properties and supports a link and a close button.\n *\n * Attributes:\n * - `data-date`: The target date and time for the countdown in ISO 8601 format.\n * - `data-has-close-button`: (optional) If present, displays a close button that, when clicked, removes the countdown from the DOM and stores a flag in sessionStorage to prevent its re-display.\n *\n * CSS Custom Properties:\n * -- The component exposes various CSS custom properties for styling the countdown timer, including background, color, font-family, and more.\n *\n * Example usage:\n * \n * Any html content you want to show in the countdown\n * \n */\nconst styles = `\n :host {\n background: rgba(12, 10, 8, 1);\n color: rgba(252, 252, 252, 1);\n min-height: auto !important;\n font-size: 15px;\n line-height: 22px;\n }\n\n .site-center{\n max-width: 1280px;\n padding: .5rem 1rem;\n display: flex;\n gap: .5rem;\n align-items: flex-start;\n justify-content: center;\n flex: 1;\n box-sizing: border-box;\n }\n\n .content-container{\n all: unset;\n display: flex;\n flex: 1;\n flex-direction: column;\n align-items: center;\n gap:.5rem;\n }\n\n .content-container.has-link{\n cursor: pointer;\n }\n\n .content{\n text-align: center;\n flex:1;\n }\n\n .content > p{\n margin: 0\n }\n\n .content a{\n color:rgba(235, 114, 46, 1);\n text-decoration: none;\n text-align: center;\n }\n button{\n background: none;\n border: none;\n color: inherit;\n padding: 0;\n display: none;\n cursor: pointer;\n }\n\n button:hover{\n opacity:0.7;\n }\n\n button.visible{\n display:block;\n }\n\n .time-container{\n display: flex;\n padding: .25rem 0;\n background: rgba(33, 27, 23, 1);\n font-weight: 500;\n }\n .time-container > div{\n padding:0 .25rem\n }\n .time-block{\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: .25rem;\n min-width: 40px;\n }\n\n .time-block .label{\n font-size: 10px;\n line-height: 16px;\n color:rgba(252, 252, 252, 0.64);\n font-weight: 400;\n }\n\n .time{\n position: relative;\n overflow: hidden;\n }\n\n .time .placeholder{\n visibility: hidden;\n }\n\n .time .next,.current,.prev{\n position:absolute;\n left:0;\n transition: all .5s ease-out;\n z-index: 2;\n background-color: rgba(33, 27, 23, 1);\n }\n\n .time .prev{\n bottom: 100%;\n }\n\n .time .next{\n bottom: -100%;\n }\n\n .time .current{\n bottom:0;\n }\n\n mark {\n color: #eb722e;\n background: unset;\n font-weight: 500;\n }\n\n @media screen and (min-width: 768px){\n .site-center {\n padding: .75rem 1.5rem;\n align-items: center;\n }\n .content-container{\n flex-direction: row;\n gap: 1.5rem;\n justify-content: space-between;\n }\n .content{\n flex: unset;\n text-align: left;\n }\n }\n\n @media screen and (min-width: 1024px){\n .site-center {\n padding: .75rem 2rem;\n }\n }\n\n @media screen and (min-width: 1440px){\n .site-center {\n padding: .75rem 2.5rem;\n }\n }\n `;\n\nconst buttonTemplate = `\n `;\n\nconst template = `\n
\n
\n
\n\n
\n \n
\n ${buttonTemplate}\n
\n `;\n\nclass CountDown extends HTMLElement {\n #intervalMs = 1e3;\n #sessionStorageDidCloseKey = 'burnification-closed';\n constructor() {\n super();\n this.fetchData().then((notification) => {\n this.notification = notification;\n this.attachShadow({ mode: 'open' });\n this.shadowRoot.innerHTML = template;\n this.useSlotContent();\n this.adoptStyleSheet();\n if (this.didClose) {\n this.remove();\n return;\n }\n this.initLink();\n this.initButton();\n this.initTimer();\n });\n }\n async fetchData() {\n const data = await fetch('https://burnsoft.de/api/notification');\n if (!data.ok) {\n return;\n }\n const notifications = await data.json();\n if (!notifications) {\n return;\n }\n const path = window.location.pathname;\n const notification = notifications.find(\n (item) => item.active && new RegExp(`^${item.scope}$`).test(path)\n );\n return notification;\n }\n get didClose() {\n return !!sessionStorage.getItem(this.#sessionStorageDidCloseKey);\n }\n adoptStyleSheet() {\n if (this.dataset.useStyles == 'false') return;\n const sheet = new CSSStyleSheet();\n sheet.replaceSync(styles);\n this.shadowRoot.adoptedStyleSheets = [sheet];\n }\n useSlotContent() {\n const content = this.notification?.message;\n const contentElement = this.shadowRoot.querySelector('.content');\n if (content) contentElement.innerHTML = content;\n else contentElement.remove();\n }\n initLink() {\n const link = this.notification?.link;\n if (!link) return;\n const container = this.shadowRoot.querySelector('.content-container');\n container.classList.add('has-link');\n container.addEventListener('click', (e) => {\n if (e.target.className === 'close-button') return;\n window.open(link, '_blank');\n });\n }\n initButton() {\n if (!this.hasAttribute('data-has-close-button')) return;\n const button = this.shadowRoot.querySelector('.close-button');\n button.classList.add('visible');\n button.addEventListener('click', () => {\n this.close();\n });\n }\n close() {\n this.finish();\n this.remove();\n sessionStorage.setItem(this.#sessionStorageDidCloseKey, true);\n }\n initTimer() {\n const date = this.notification?.endCountdown;\n if (!date) {\n this.hideTimeContainer();\n return;\n }\n const diff = this.initTime(date);\n if (diff <= 0) {\n this.hideTimeContainer();\n return;\n }\n this.setDatetimeAttribute(date);\n this.startCountDown();\n }\n setDatetimeAttribute(date) {\n const timeElement = this.shadowRoot.querySelector('.time-container');\n timeElement.setAttribute('datetime', date);\n }\n initTime(isoDate) {\n const date = new Date(isoDate).getTime();\n const now = new Date().getTime();\n const diff = date - now;\n const days = Math.floor(diff / (1e3 * 60 * 60 * 24));\n const hours = Math.floor((diff / (1e3 * 60 * 60)) % 24);\n const minutes = Math.floor((diff / (1e3 * 60)) % 60);\n const seconds = Math.floor((diff / 1e3) % 60);\n const { secondTime, minuteTime, hourTime, dayTime } = this.getElements();\n this.initTimeElement(secondTime, seconds);\n this.initTimeElement(minuteTime, minutes);\n this.initTimeElement(hourTime, hours);\n this.initTimeElement(dayTime, days);\n return diff;\n }\n initTimeElement(element, value) {\n element.querySelector('.current').innerHTML = this.formatTime(value);\n const next = this.createNext(value);\n element.appendChild(next);\n }\n startCountDown() {\n const elements = this.getElements();\n this.animate(elements);\n this.interval = setInterval(() => this.animate(elements), this.#intervalMs);\n }\n animate({ secondTime, minuteTime, hourTime, dayTime }) {\n const { hasDay, hasHour, hasMinute } = this.getStatus();\n const onDayFinished = () => {\n this.finish();\n };\n const onHourFinished = () => {\n this.animateTimeBlock({ timeElement: dayTime, onFinished: onDayFinished, resetValue: null });\n };\n const onMinuteFinished = () => {\n this.animateTimeBlock({\n timeElement: hourTime,\n onFinished: onHourFinished,\n resetValue: hasDay ? 24 : null,\n });\n };\n const onSecondFinished = () => {\n this.animateTimeBlock({\n timeElement: minuteTime,\n onFinished: onMinuteFinished,\n resetValue: hasHour ? 60 : null,\n });\n };\n this.animateTimeBlock({\n timeElement: secondTime,\n onFinished: onSecondFinished,\n resetValue: hasMinute ? 60 : null,\n });\n }\n finish() {\n if (this.interval) clearInterval(this.interval);\n this.hideTimeContainer();\n }\n hideTimeContainer() {\n this.shadowRoot.querySelector('.time-container')?.remove();\n }\n getStatus() {\n const { minuteTime, hourTime, dayTime } = this.getElements();\n const { current: currentDay } = this.getTimeElements(dayTime);\n const { current: currentHour } = this.getTimeElements(hourTime);\n const { current: currentMinute } = this.getTimeElements(minuteTime);\n return {\n hasDay: currentDay.innerHTML !== '00',\n hasHour: currentHour.innerHTML !== '00',\n hasMinute: currentMinute.innerHTML !== '00',\n };\n }\n animateTimeBlock({ timeElement, onFinished, resetValue = 60 }) {\n let { current, next, prev } = this.getTimeElements(timeElement);\n let currentValue = parseInt(current.innerText);\n if (currentValue === 0) {\n onFinished?.();\n if (!resetValue) return;\n currentValue = resetValue;\n }\n if (!next) {\n next = this.createNext(currentValue);\n timeElement.appendChild(next);\n }\n current.classList.add('prev');\n current.classList.remove('current');\n next.classList.add('current');\n next.classList.remove('next');\n prev?.remove();\n const newNext = this.createNext(currentValue - 1);\n timeElement.appendChild(newNext);\n }\n createNext(currentValue) {\n const next = document.createElement('span');\n if (currentValue == 0) currentValue = 60;\n next.innerHTML = this.formatTime(currentValue - 1);\n next.className = 'next';\n return next;\n }\n getTimeElements(timeElement) {\n const current = timeElement.querySelector('.current');\n const prev = timeElement.querySelector('.prev');\n const next = timeElement.querySelector('.next');\n return { current, prev, next };\n }\n formatTime(time) {\n return time < 10 ? `0${time}` : time;\n }\n getElements() {\n const second = this.shadowRoot.querySelector('[data-sec]');\n const minute = this.shadowRoot.querySelector('[data-min]');\n const hour = this.shadowRoot.querySelector('[data-hour]');\n const day = this.shadowRoot.querySelector('[data-day]');\n const secondTime = second?.querySelector('.time');\n const minuteTime = minute?.querySelector('.time');\n const hourTime = hour?.querySelector('.time');\n const dayTime = day?.querySelector('.time');\n return { second, minute, hour, day, secondTime, minuteTime, hourTime, dayTime };\n }\n}\nif (customElements.get('count-down') === undefined) {\n customElements.define('count-down', CountDown);\n}\n"],"names":["styles","buttonTemplate","template","CountDown","HTMLElement","intervalMs","sessionStorageDidCloseKey","constructor","super","this","fetchData","then","notification","attachShadow","mode","shadowRoot","innerHTML","useSlotContent","adoptStyleSheet","didClose","remove","initLink","initButton","initTimer","data","fetch","ok","notifications","json","path","window","location","pathname","find","item","active","RegExp","scope","test","sessionStorage","getItem","dataset","useStyles","sheet","CSSStyleSheet","replaceSync","adoptedStyleSheets","content","message","contentElement","querySelector","link","container","classList","add","addEventListener","e","target","className","open","hasAttribute","button","close","finish","setItem","date","endCountdown","hideTimeContainer","diff","initTime","setDatetimeAttribute","startCountDown","timeElement","setAttribute","isoDate","Date","getTime","now","days","Math","floor","hours","minutes","seconds","secondTime","minuteTime","hourTime","dayTime","getElements","initTimeElement","element","value","formatTime","next","createNext","appendChild","elements","animate","interval","setInterval","hasDay","hasHour","hasMinute","getStatus","onDayFinished","onHourFinished","animateTimeBlock","onFinished","resetValue","onMinuteFinished","onSecondFinished","clearInterval","current","currentDay","getTimeElements","currentHour","currentMinute","prev","currentValue","parseInt","innerText","newNext","document","createElement","time","second","minute","hour","day","customElements","get","undefined","define"],"mappings":"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"}