From ff90439d70e0e44d70c8fe49c1827e841296793e Mon Sep 17 00:00:00 2001 From: Nick Freear Date: Fri, 13 May 2022 19:31:36 +0100 Subject: [PATCH] feat: Add a Countdown Timer Widget (#23) --- demo/my-countdown.html | 55 ++++++++++++++++ index.js | 1 + src/components/MyCountdownElement.js | 95 ++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 demo/my-countdown.html create mode 100644 src/components/MyCountdownElement.js diff --git a/demo/my-countdown.html b/demo/my-countdown.html new file mode 100644 index 0000000..4a6155a --- /dev/null +++ b/demo/my-countdown.html @@ -0,0 +1,55 @@ +my-countdown + + + + + + + + +

my-countdown

+ +

+ +
Until midnight on 31st December 2022
+ + + <my-countdown + datetime="2022-12-31 23:59:59" + >Until midnight on 31st December 2022 + </my-countdown> + +
+ + + + diff --git a/index.js b/index.js index 94b198c..7612ff1 100644 --- a/index.js +++ b/index.js @@ -25,6 +25,7 @@ export { MyAtbarButtonElement } from './src/components/MyAtbarButtonElement.js'; export { MyFontElement } from './src/components/MyFontElement.js'; export { MySearchElement } from './src/components/MySearchElement.js'; export { MyGaadWidgetElement } from './src/components/MyGaadWidgetElement.js'; +export { MyCountdownElement } from './src/components/MyCountdownElement.js'; export { MyElement } from './src/MyElement.js'; diff --git a/src/components/MyCountdownElement.js b/src/components/MyCountdownElement.js new file mode 100644 index 0000000..f8c1b5c --- /dev/null +++ b/src/components/MyCountdownElement.js @@ -0,0 +1,95 @@ +/** + * A Countdown Timer Widget. + * + * @copyright © Nick Freear, 07-May-2022. + * + * @see https://geeksforgeeks.org/create-countdown-timer-using-javascript/ + */ + +import { MyElement } from '../MyElement.js'; + +const STYLES = ` +.countdown { display: inline-block; line-height: 1.6; } +.countdown > * { text-align: center; } +span { background: var(--my-countdown-bg-num, transparent); display: inline-block; margin: 0 1.5%; width: 29%; } +tx { background: var(--my-countdown-bg-label, transparent); display: block; font-size: 75%; padding: .25rem 0; } +num { display: block; font-size: 200%; min-height: 3rem; padding: .5rem 0; } +footer { font-size: 70%; margin: .6rem 0; } + +.red { color: red; } +`; + +/* const STYLES = ` +.countdown { display: inline-block; } +.countdown > * { text-align: center; } +span { background: #eee; display: inline-block; margin: 0 .2rem; width: 4.2rem; } +tx { background: #ddd; display: block; font-size: small; padding: .25rem 0; } +num { display: block; font-size: 2.2rem; min-height: 3rem; padding: .5rem 0; } +footer { font-size: small; } +`; */ + +const INTERVAL_MS = 5 * 1000; + +export class MyCountdownElement extends MyElement { + static getTag () { + return 'my-countdown'; + } + + async connectedCallback () { + const datetime = this.getAttribute('datetime') || '2022-12-31 23:59:59'; + + const countdown = this._calculate(datetime); + const ELEM = document.createElement('div'); + const STYLE_EL = document.createElement('style'); + + ELEM.innerHTML = this._template(countdown); + ELEM.classList.add('countdown'); + // ELEM.classList.add('red'); + STYLE_EL.textContent = STYLES; + + this.attachShadow({ mode: 'open' }).appendChild(STYLE_EL); + this.shadowRoot.appendChild(ELEM); + + setInterval(() => { + const CD = this._calculate(datetime); + + ELEM.title = `… and ${CD.seconds} seconds`; + ELEM.innerHTML = this._template(CD); + + console.debug('.'); + }, + INTERVAL_MS); + + console.debug('my-countdown:', countdown, this); + } + + _template (countdown) { + const { days, hours, minutes, deadline } = countdown; + + return ` + ${days} days + ${hours} hours + ${minutes} minutes + + `; + } + + _calculate (deadlineStr) { + const deadline = new Date(deadlineStr).getTime(); + const now = new Date().getTime(); + const diff = deadline - now; + + if (isNaN(deadline)) { + throw new Error(`Input not recognized as a date-time: '${deadlineStr}'`); + } + + const days = Math.floor(diff / (1000 * 60 * 60 * 24)); + const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); + const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); + const seconds = Math.floor((diff % (1000 * 60)) / 1000); + + return { days, hours, minutes, seconds, deadline: deadlineStr, diff, expired: diff < 0 }; + } +} + +MyCountdownElement.define();