senangwebs-epoch 1.1.2 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -94,6 +94,25 @@ Include SenangWebs Epoch directly in your HTML file:
94
94
  - `data-swe-second`
95
95
  - `data-swe-format`: Specifies display format for each unit
96
96
 
97
+ ### Format Options
98
+
99
+ The format string determines zero-padding based on its length:
100
+
101
+ | Unit | Format | Output Example | Description |
102
+ |------|--------|----------------|-------------|
103
+ | Year | `yyyy` | `2026` | Four-digit year |
104
+ | Month | `m` | `5` | Single digit month |
105
+ | Month | `mm` | `05` | Two-digit month |
106
+ | Day | `d` | `5` | Single digit day |
107
+ | Day | `dd` | `05` | Two-digit day |
108
+ | Day | `ddd` | `005` | Three-digit day (for long countdowns) |
109
+ | Hour | `H` | `9` | Single digit hour |
110
+ | Hour | `HH` | `09` | Two-digit hour |
111
+ | Minute | `m` | `7` | Single digit minute |
112
+ | Minute | `mm` | `07` | Two-digit minute |
113
+ | Second | `s` | `3` | Single digit second |
114
+ | Second | `ss` | `03` | Two-digit second |
115
+
97
116
  ### JavaScript Initialization
98
117
 
99
118
  ```javascript
@@ -190,7 +209,7 @@ Contributions are welcome! Please feel free to submit a Pull Request.
190
209
 
191
210
  ## License
192
211
 
193
- This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details.
212
+ MIT License
194
213
 
195
214
  ## Support
196
215
 
package/dist/swe.js CHANGED
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.SWE=e():t.SWE=e()}(this,(()=>(()=>{"use strict";var t={d:(e,n)=>{for(var i in n)t.o(n,i)&&!t.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:n[i]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}function i(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,i=Array(e);n<e;n++)i[n]=t[n];return i}function o(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,r(i.key),i)}}function r(t){var e=function(t){if("object"!=n(t)||!t)return t;var e=t[Symbol.toPrimitive];if(void 0!==e){var i=e.call(t,"string");if("object"!=n(i))return i;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return"symbol"==n(e)?e:e+""}t.d(e,{default:()=>s});var a=function(){return t=function t(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.element=e,this.options={autostart:void 0===n.autostart||n.autostart,duration:n.duration,countdownEnd:n.countdownEnd,onTick:n.onTick,onEnd:n.onEnd,onStart:n.onStart,onPause:n.onPause,onResume:n.onResume,onReset:n.onReset,onStop:n.onStop},this.intervalId=null,this.isPaused=!1,this.startTime=null,this.pausedTimeRemaining=null,this.endTime=null,this.initialize()},(e=[{key:"initialize",value:function(){if(!(this.element&&this.element instanceof HTMLElement))throw new Error("SWE: Invalid element provided");if(this.mode=this.determineMode(),this.setupElements(),this.options.autostart)this.start();else if("countdown-duration"===this.mode&&this.options.duration)this.updateDisplay(1e3*this.options.duration);else if("countdown-end"===this.mode&&this.options.countdownEnd){var t=new Date(this.options.countdownEnd),e=new Date,n=t.getTime()-e.getTime();this.updateDisplay(n>0?n:0)}}},{key:"determineMode",value:function(){if(this.options.countdownEnd)return"countdown-end";if(this.options.duration)return"countdown-duration";if(this.element.hasAttribute("data-swe-countdown-end"))return"countdown-end";if(this.element.hasAttribute("data-swe-countdown-duration"))return"countdown-duration";if(this.element.hasAttribute("data-swe-current"))return"current";if(this.options.countdownEnd)return"countdown-end";throw new Error("SWE: Invalid mode - missing required configuration")}},{key:"setupElements",value:function(){this.elements={year:this.element.querySelector("[data-swe-year]"),month:this.element.querySelector("[data-swe-month]"),day:this.element.querySelector("[data-swe-day]"),hour:this.element.querySelector("[data-swe-hour]"),minute:this.element.querySelector("[data-swe-minute]"),second:this.element.querySelector("[data-swe-second]")}}},{key:"start",value:function(){if(!this.intervalId){switch(this.isPaused=!1,this.startTime=Date.now(),this.mode){case"countdown-end":this.startCountdownToDate();break;case"countdown-duration":this.startCountdownDuration();break;case"current":this.startCurrentTime()}this.dispatchEvent("start")}}},{key:"startCountdownToDate",value:function(){var t=new Date(this.options.countdownEnd||this.element.getAttribute("data-swe-countdown-end"));if(isNaN(t.getTime()))throw new Error("SWE: Invalid end date format");this.endTime=t.getTime(),this.updateTimer()}},{key:"startCountdownDuration",value:function(){var t=this.options.duration||parseInt(this.element.getAttribute("data-swe-countdown-duration"),10);if(isNaN(t)||t<0)throw new Error("SWE: Invalid duration");null!==this.pausedTimeRemaining?this.endTime=Date.now()+this.pausedTimeRemaining:this.endTime=Date.now()+1e3*t,this.updateTimer()}},{key:"updateTimer",value:function(){var t=this,e=function(){var e=Date.now(),n=t.endTime-e;if(n<=0)return t.stop(),t.updateDisplay(0),void t.dispatchEvent("end");t.updateDisplay(n),t.dispatchEvent("tick")};e(),this.intervalId=setInterval(e,1e3)}},{key:"startCurrentTime",value:function(){var t=this,e=function(){var e=new Date;t.updateCurrentTimeDisplay(e),t.dispatchEvent("tick")};e(),this.intervalId=setInterval(e,1e3)}},{key:"updateDisplay",value:function(t){var e=this,n=this.calculateTimeUnits(t);Object.entries(this.elements).forEach((function(t){var o=function(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var i,o,r,a,s=[],u=!0,d=!1;try{if(r=(n=n.call(t)).next,0===e){if(Object(n)!==n)return;u=!1}else for(;!(u=(i=r.call(n)).done)&&(s.push(i.value),s.length!==e);u=!0);}catch(t){d=!0,o=t}finally{try{if(!u&&null!=n.return&&(a=n.return(),Object(a)!==a))return}finally{if(d)throw o}}return s}}(t,e)||function(t,e){if(t){if("string"==typeof t)return i(t,e);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?i(t,e):void 0}}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}(t,2),r=o[0],a=o[1];a&&e.updateElement(a,n[r])}))}},{key:"updateCurrentTimeDisplay",value:function(t){this.elements.hour&&this.updateElement(this.elements.hour,t.getHours()),this.elements.minute&&this.updateElement(this.elements.minute,t.getMinutes()),this.elements.second&&this.updateElement(this.elements.second,t.getSeconds())}},{key:"updateElement",value:function(t,e){var n=t.getAttribute("data-swe-format");t.textContent=this.formatValue(e,n)}},{key:"formatValue",value:function(t,e){return e?t.toString().padStart(e.length,"0"):t.toString()}},{key:"calculateTimeUnits",value:function(t){var e=Math.floor(t/1e3),n=Math.floor(e/60),i=Math.floor(n/60),o=Math.floor(i/24),r=Math.floor(o/30);return{year:Math.floor(o/365),month:r%12,day:o%30,hour:i%24,minute:n%60,second:e%60}}},{key:"dispatchEvent",value:function(t){var e="on".concat(t.charAt(0).toUpperCase()+t.slice(1));"function"==typeof this.options[e]&&this.options[e].call(this);var n=new CustomEvent("swe:".concat(t),{bubbles:!0,detail:{instance:this}});this.element.dispatchEvent(n)}},{key:"pause",value:function(){this.intervalId&&!this.isPaused&&(clearInterval(this.intervalId),this.intervalId=null,this.isPaused=!0,this.pausedTimeRemaining=this.endTime-Date.now(),this.dispatchEvent("pause"))}},{key:"resume",value:function(){this.isPaused&&(this.start(),this.dispatchEvent("resume"))}},{key:"reset",value:function(){if(this.stop(),this.pausedTimeRemaining=null,this.endTime=null,"countdown-end"===this.mode&&this.options.countdownEnd){var t=new Date(this.options.countdownEnd),e=new Date,n=t.getTime()-e.getTime();this.updateDisplay(n>0?n:0)}else"countdown-duration"===this.mode&&this.options.duration&&this.updateDisplay(1e3*this.options.duration);this.dispatchEvent("reset"),this.options.autostart&&this.start()}},{key:"stop",value:function(){this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null,this.isPaused=!1,this.dispatchEvent("stop"))}}])&&o(t.prototype,e),Object.defineProperty(t,"prototype",{writable:!1}),t;var t,e}();document.addEventListener("DOMContentLoaded",(function(){document.querySelectorAll("[data-swe]").forEach((function(t){new a(t)}))}));const s=a;return"undefined"!=typeof window&&(window.SWE=a),e.default})()));
1
+ !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.SWE=e():t.SWE=e()}(this,(()=>(()=>{"use strict";var t={d:(e,n)=>{for(var i in n)t.o(n,i)&&!t.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:n[i]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}function i(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,i=Array(e);n<e;n++)i[n]=t[n];return i}function o(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,r(i.key),i)}}function r(t){var e=function(t){if("object"!=n(t)||!t)return t;var e=t[Symbol.toPrimitive];if(void 0!==e){var i=e.call(t,"string");if("object"!=n(i))return i;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return"symbol"==n(e)?e:e+""}t.d(e,{default:()=>s});var a=function(){return t=function t(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.element=e,this.options={autostart:void 0===n.autostart||n.autostart,duration:n.duration,countdownEnd:n.countdownEnd,onTick:n.onTick,onEnd:n.onEnd,onStart:n.onStart,onPause:n.onPause,onResume:n.onResume,onReset:n.onReset,onStop:n.onStop},this.intervalId=null,this.isPaused=!1,this.startTime=null,this.pausedTimeRemaining=null,this.endTime=null,this.initialize()},(e=[{key:"initialize",value:function(){if(!(this.element&&this.element instanceof HTMLElement))throw new Error("SWE: Invalid element provided");if(this.mode=this.determineMode(),this.setupElements(),this.options.autostart)this.start();else if("countdown-duration"===this.mode&&this.options.duration)this.updateDisplay(1e3*this.options.duration);else if("countdown-end"===this.mode&&this.options.countdownEnd){var t=new Date(this.options.countdownEnd),e=new Date,n=t.getTime()-e.getTime();this.updateDisplay(n>0?n:0)}}},{key:"determineMode",value:function(){if(this.options.countdownEnd)return"countdown-end";if(this.options.duration)return"countdown-duration";if(this.element.hasAttribute("data-swe-countdown-end"))return"countdown-end";if(this.element.hasAttribute("data-swe-countdown-duration"))return"countdown-duration";if(this.element.hasAttribute("data-swe-current"))return"current";if(this.options.countdownEnd)return"countdown-end";throw new Error("SWE: Invalid mode - missing required configuration")}},{key:"setupElements",value:function(){this.elements={year:this.element.querySelector("[data-swe-year]"),month:this.element.querySelector("[data-swe-month]"),day:this.element.querySelector("[data-swe-day]"),hour:this.element.querySelector("[data-swe-hour]"),minute:this.element.querySelector("[data-swe-minute]"),second:this.element.querySelector("[data-swe-second]")}}},{key:"start",value:function(){if(!this.intervalId){switch(this.isPaused=!1,this.startTime=Date.now(),this.mode){case"countdown-end":this.startCountdownToDate();break;case"countdown-duration":this.startCountdownDuration();break;case"current":this.startCurrentTime()}this.dispatchEvent("start")}}},{key:"startCountdownToDate",value:function(){var t=new Date(this.options.countdownEnd||this.element.getAttribute("data-swe-countdown-end"));if(isNaN(t.getTime()))throw new Error("SWE: Invalid end date format");this.endTime=t.getTime(),this.updateTimer()}},{key:"startCountdownDuration",value:function(){var t=this.options.duration||parseInt(this.element.getAttribute("data-swe-countdown-duration"),10);if(isNaN(t)||t<0)throw new Error("SWE: Invalid duration");null!==this.pausedTimeRemaining?this.endTime=Date.now()+this.pausedTimeRemaining:this.endTime=Date.now()+1e3*t,this.updateTimer()}},{key:"updateTimer",value:function(){var t=this,e=function(){var e=Date.now(),n=t.endTime-e;if(n<=0)return t.stop(),t.updateDisplay(0),void t.dispatchEvent("end");t.updateDisplay(n),t.dispatchEvent("tick")};e(),this.intervalId=setInterval(e,1e3)}},{key:"startCurrentTime",value:function(){var t=this,e=function(){var e=new Date;t.updateCurrentTimeDisplay(e),t.dispatchEvent("tick")};e(),this.intervalId=setInterval(e,1e3)}},{key:"updateDisplay",value:function(t){var e=this,n=this.calculateTimeUnits(t);Object.entries(this.elements).forEach((function(t){var o=function(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var i,o,r,a,s=[],u=!0,d=!1;try{if(r=(n=n.call(t)).next,0===e){if(Object(n)!==n)return;u=!1}else for(;!(u=(i=r.call(n)).done)&&(s.push(i.value),s.length!==e);u=!0);}catch(t){d=!0,o=t}finally{try{if(!u&&null!=n.return&&(a=n.return(),Object(a)!==a))return}finally{if(d)throw o}}return s}}(t,e)||function(t,e){if(t){if("string"==typeof t)return i(t,e);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?i(t,e):void 0}}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}(t,2),r=o[0],a=o[1];a&&e.updateElement(a,n[r])}))}},{key:"updateCurrentTimeDisplay",value:function(t){this.elements.hour&&this.updateElement(this.elements.hour,t.getHours()),this.elements.minute&&this.updateElement(this.elements.minute,t.getMinutes()),this.elements.second&&this.updateElement(this.elements.second,t.getSeconds())}},{key:"updateElement",value:function(t,e){var n=t.getAttribute("data-swe-format");t.textContent=this.formatValue(e,n)}},{key:"formatValue",value:function(t,e){return e?t.toString().padStart(e.length,"0"):t.toString()}},{key:"calculateTimeUnits",value:function(t){var e=Math.floor(t/1e3),n=Math.floor(e/60),i=Math.floor(n/60),o=(Math.floor(i/24),new Date),r=new Date(o.getTime()+t),a=r.getFullYear()-o.getFullYear(),s=r.getMonth()-o.getMonth(),u=r.getDate()-o.getDate();return u<0&&(s--,u+=new Date(r.getFullYear(),r.getMonth(),0).getDate()),s<0&&(a--,s+=12),{year:a,month:s,day:u,hour:i%24,minute:n%60,second:e%60}}},{key:"dispatchEvent",value:function(t){var e="on".concat(t.charAt(0).toUpperCase()+t.slice(1));"function"==typeof this.options[e]&&this.options[e].call(this);var n=new CustomEvent("swe:".concat(t),{bubbles:!0,detail:{instance:this}});this.element.dispatchEvent(n)}},{key:"pause",value:function(){this.intervalId&&!this.isPaused&&(clearInterval(this.intervalId),this.intervalId=null,this.isPaused=!0,this.pausedTimeRemaining=this.endTime-Date.now(),this.dispatchEvent("pause"))}},{key:"resume",value:function(){if(this.isPaused){switch(this.isPaused=!1,this.startTime=Date.now(),this.mode){case"countdown-end":this.startCountdownToDate();break;case"countdown-duration":this.startCountdownDuration();break;case"current":this.startCurrentTime()}this.dispatchEvent("resume")}}},{key:"reset",value:function(){if(this.stop(),this.pausedTimeRemaining=null,this.endTime=null,"countdown-end"===this.mode&&this.options.countdownEnd){var t=new Date(this.options.countdownEnd),e=new Date,n=t.getTime()-e.getTime();this.updateDisplay(n>0?n:0)}else"countdown-duration"===this.mode&&this.options.duration&&this.updateDisplay(1e3*this.options.duration);this.dispatchEvent("reset"),this.options.autostart&&this.start()}},{key:"stop",value:function(){var t=null!==this.intervalId;this.intervalId&&(clearInterval(this.intervalId),this.intervalId=null),this.isPaused=!1,t&&this.dispatchEvent("stop")}}])&&o(t.prototype,e),Object.defineProperty(t,"prototype",{writable:!1}),t;var t,e}();document.addEventListener("DOMContentLoaded",(function(){document.querySelectorAll("[data-swe]").forEach((function(t){new a(t)}))}));const s=a;return"undefined"!=typeof window&&(window.SWE=a),e.default})()));
@@ -4,71 +4,450 @@
4
4
  <head>
5
5
  <meta charset="UTF-8">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>SenangWebs Epoch Demo</title>
7
+ <title>SenangWebs Epoch - Examples & Use Cases</title>
8
8
  <script src="https://cdn.tailwindcss.com"></script>
9
9
  <link rel="stylesheet" href="../dist/swe.css">
10
+ <link rel="stylesheet" href="https://unpkg.com/@bookklik/senangstart-icons/dist/senangstart.min.css" />
11
+ <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800&display=swap" rel="stylesheet">
12
+ <script>
13
+ tailwind.config = {
14
+ theme: {
15
+ extend: {
16
+ fontFamily: {
17
+ sans: ['Outfit', 'sans-serif'],
18
+ },
19
+ }
20
+ }
21
+ }
22
+ </script>
23
+ <style>
24
+ .gradient-text {
25
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
26
+ -webkit-background-clip: text;
27
+ -webkit-text-fill-color: transparent;
28
+ background-clip: text;
29
+ }
30
+ .glass-card {
31
+ background: rgba(255, 255, 255, 0.7);
32
+ backdrop-filter: blur(10px);
33
+ border: 1px solid rgba(255, 255, 255, 0.3);
34
+ }
35
+ .timer-unit {
36
+ transition: all 0.3s ease;
37
+ }
38
+ .timer-unit:hover {
39
+ transform: scale(1.05);
40
+ }
41
+ @keyframes pulse-glow {
42
+ 0%, 100% { box-shadow: 0 0 20px rgba(239, 68, 68, 0.3); }
43
+ 50% { box-shadow: 0 0 40px rgba(239, 68, 68, 0.6); }
44
+ }
45
+ .flash-sale-glow {
46
+ animation: pulse-glow 2s infinite;
47
+ }
48
+ </style>
10
49
  </head>
11
50
 
12
- <body class="min-h-screen bg-gray-100">
51
+ <body class="min-h-screen bg-gradient-to-br from-slate-50 via-white to-slate-100 font-sans">
52
+
53
+ <!-- Hero Header -->
54
+ <header class="bg-gradient-to-br from-[#00FF99] to-[#007370] text-white py-16">
55
+ <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
56
+ <h1 class="text-4xl lg:text-5xl font-extrabold mb-4 drop-shadow-lg">SenangWebs Epoch</h1>
57
+ <p class="text-xl text-white/90 max-w-2xl mx-auto">A lightweight JavaScript library for creating dynamic countdown timers and time displays. Perfect for any time-sensitive content.</p>
58
+ </div>
59
+ </header>
13
60
 
14
61
  <!-- Main Content -->
15
- <main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
16
- <h4 class="text-xl lg:text-2xl capitalize font-bold mb-4">SenangWebs Epoch</h4>
17
-
18
- <div class="flex flex-col gap-8">
19
- <!-- Countdown to a specific date-time -->
20
- <div data-swe data-swe-countdown-end="2025-01-01 00:00:00">
21
- <div data-swe-year data-swe-format="yyyy"></div>
22
- <div data-swe-month data-swe-format="mm"></div>
23
- <div data-swe-day data-swe-format="dd"></div>
24
- <div data-swe-hour data-swe-format="HH"></div>
25
- <div data-swe-minute data-swe-format="mm"></div>
26
- <div data-swe-second data-swe-format="ss"></div>
62
+ <main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
63
+
64
+ <!-- Section: Event Countdowns -->
65
+ <section class="mb-16">
66
+ <h2 class="text-2xl font-bold text-gray-800 mb-2 flex items-center gap-2"><span class="ss ss-calendar text-2xl"></span> Event Countdowns</h2>
67
+ <p class="text-gray-600 mb-6">Perfect for building anticipation for upcoming events, launches, or celebrations.</p>
68
+
69
+ <div class="grid md:grid-cols-2 gap-6">
70
+
71
+ <!-- New Year Countdown -->
72
+ <div class="glass-card rounded-2xl p-6 shadow-lg">
73
+ <div class="flex items-center gap-3 mb-4">
74
+ <span class="ss ss-star text-3xl text-amber-500"></span>
75
+ <div>
76
+ <h3 class="text-lg font-bold text-gray-800">New Year Countdown</h3>
77
+ <p class="text-sm text-gray-500">Count down to the new year celebration</p>
78
+ </div>
79
+ </div>
80
+ <div id="new-year" data-swe data-swe-countdown-end="2027-01-01 00:00:00" class="flex flex-wrap gap-3 justify-center">
81
+ <div class="timer-unit flex flex-col items-center bg-gradient-to-br from-amber-400 to-orange-500 text-white rounded-xl p-4 min-w-[70px] shadow-lg">
82
+ <span data-swe-day data-swe-format="ddd" class="text-2xl font-bold"></span>
83
+ <span class="text-xs uppercase tracking-wider opacity-90">Days</span>
84
+ </div>
85
+ <div class="timer-unit flex flex-col items-center bg-gradient-to-br from-amber-400 to-orange-500 text-white rounded-xl p-4 min-w-[70px] shadow-lg">
86
+ <span data-swe-hour data-swe-format="HH" class="text-2xl font-bold"></span>
87
+ <span class="text-xs uppercase tracking-wider opacity-90">Hours</span>
88
+ </div>
89
+ <div class="timer-unit flex flex-col items-center bg-gradient-to-br from-amber-400 to-orange-500 text-white rounded-xl p-4 min-w-[70px] shadow-lg">
90
+ <span data-swe-minute data-swe-format="mm" class="text-2xl font-bold"></span>
91
+ <span class="text-xs uppercase tracking-wider opacity-90">Mins</span>
92
+ </div>
93
+ <div class="timer-unit flex flex-col items-center bg-gradient-to-br from-amber-400 to-orange-500 text-white rounded-xl p-4 min-w-[70px] shadow-lg">
94
+ <span data-swe-second data-swe-format="ss" class="text-2xl font-bold"></span>
95
+ <span class="text-xs uppercase tracking-wider opacity-90">Secs</span>
96
+ </div>
97
+ </div>
98
+ </div>
99
+
100
+ <!-- Product Launch -->
101
+ <div class="glass-card rounded-2xl p-6 shadow-lg">
102
+ <div class="flex items-center gap-3 mb-4">
103
+ <span class="ss ss-bolt text-3xl text-blue-500"></span>
104
+ <div>
105
+ <h3 class="text-lg font-bold text-gray-800">Product Launch</h3>
106
+ <p class="text-sm text-gray-500">Building excitement for your next big release</p>
107
+ </div>
108
+ </div>
109
+ <div id="product-launch" data-swe data-swe-countdown-end="2026-06-15 09:00:00" class="flex flex-wrap gap-3 justify-center">
110
+ <div class="timer-unit flex flex-col items-center bg-gradient-to-br from-blue-500 to-cyan-400 text-white rounded-xl p-4 min-w-[70px] shadow-lg">
111
+ <span data-swe-month data-swe-format="mm" class="text-2xl font-bold"></span>
112
+ <span class="text-xs uppercase tracking-wider opacity-90">Months</span>
113
+ </div>
114
+ <div class="timer-unit flex flex-col items-center bg-gradient-to-br from-blue-500 to-cyan-400 text-white rounded-xl p-4 min-w-[70px] shadow-lg">
115
+ <span data-swe-day data-swe-format="dd" class="text-2xl font-bold"></span>
116
+ <span class="text-xs uppercase tracking-wider opacity-90">Days</span>
117
+ </div>
118
+ <div class="timer-unit flex flex-col items-center bg-gradient-to-br from-blue-500 to-cyan-400 text-white rounded-xl p-4 min-w-[70px] shadow-lg">
119
+ <span data-swe-hour data-swe-format="HH" class="text-2xl font-bold"></span>
120
+ <span class="text-xs uppercase tracking-wider opacity-90">Hours</span>
121
+ </div>
122
+ <div class="timer-unit flex flex-col items-center bg-gradient-to-br from-blue-500 to-cyan-400 text-white rounded-xl p-4 min-w-[70px] shadow-lg">
123
+ <span data-swe-minute data-swe-format="mm" class="text-2xl font-bold"></span>
124
+ <span class="text-xs uppercase tracking-wider opacity-90">Mins</span>
125
+ </div>
126
+ </div>
127
+ </div>
128
+
129
+ </div>
130
+ </section>
131
+
132
+ <!-- Section: E-Commerce -->
133
+ <section class="mb-16">
134
+ <h2 class="text-2xl font-bold text-gray-800 mb-2 flex items-center gap-2"><span class="ss ss-shopping-cart text-2xl"></span> E-Commerce & Sales</h2>
135
+ <p class="text-gray-600 mb-6">Create urgency and drive conversions with time-limited offers.</p>
136
+
137
+ <div class="grid md:grid-cols-2 gap-6">
138
+
139
+ <!-- Flash Sale -->
140
+ <div class="bg-gradient-to-br from-red-600 to-rose-700 rounded-2xl p-6 shadow-xl flash-sale-glow">
141
+ <div class="flex items-center gap-3 mb-4">
142
+ <span class="ss ss-thunder text-3xl text-yellow-300 animate-bounce"></span>
143
+ <div>
144
+ <h3 class="text-lg font-bold text-white">Flash Sale Ending Soon!</h3>
145
+ <p class="text-sm text-white/80">Up to 70% OFF - Limited Time</p>
146
+ </div>
147
+ </div>
148
+ <div id="flash-sale" class="flex flex-wrap gap-3 justify-center">
149
+ <div class="timer-unit flex flex-col items-center bg-white/20 backdrop-blur text-white rounded-xl p-4 min-w-[70px]">
150
+ <span data-swe-hour data-swe-format="HH" class="text-3xl font-bold"></span>
151
+ <span class="text-xs uppercase tracking-wider">Hours</span>
152
+ </div>
153
+ <div class="text-3xl font-bold text-white self-center">:</div>
154
+ <div class="timer-unit flex flex-col items-center bg-white/20 backdrop-blur text-white rounded-xl p-4 min-w-[70px]">
155
+ <span data-swe-minute data-swe-format="mm" class="text-3xl font-bold"></span>
156
+ <span class="text-xs uppercase tracking-wider">Mins</span>
157
+ </div>
158
+ <div class="text-3xl font-bold text-white self-center">:</div>
159
+ <div class="timer-unit flex flex-col items-center bg-white/20 backdrop-blur text-white rounded-xl p-4 min-w-[70px]">
160
+ <span data-swe-second data-swe-format="ss" class="text-3xl font-bold"></span>
161
+ <span class="text-xs uppercase tracking-wider">Secs</span>
162
+ </div>
163
+ </div>
164
+ <button class="mt-4 w-full bg-white text-red-600 font-bold py-3 px-6 rounded-xl hover:bg-gray-100 transition-colors">
165
+ Shop Now →
166
+ </button>
167
+ </div>
168
+
169
+ <!-- Limited Offer -->
170
+ <div class="bg-gradient-to-br from-emerald-500 to-teal-600 rounded-2xl p-6 shadow-xl">
171
+ <div class="flex items-center gap-3 mb-4">
172
+ <span class="ss ss-gift text-3xl text-white"></span>
173
+ <div>
174
+ <h3 class="text-lg font-bold text-white">Free Shipping Offer</h3>
175
+ <p class="text-sm text-white/80">Order now to get free delivery!</p>
176
+ </div>
177
+ </div>
178
+ <div id="shipping-offer" class="flex flex-wrap gap-3 justify-center">
179
+ <div class="timer-unit flex flex-col items-center bg-white/20 backdrop-blur text-white rounded-xl p-4 min-w-[70px]">
180
+ <span data-swe-hour data-swe-format="HH" class="text-3xl font-bold"></span>
181
+ <span class="text-xs uppercase tracking-wider">Hours</span>
182
+ </div>
183
+ <div class="timer-unit flex flex-col items-center bg-white/20 backdrop-blur text-white rounded-xl p-4 min-w-[70px]">
184
+ <span data-swe-minute data-swe-format="mm" class="text-3xl font-bold"></span>
185
+ <span class="text-xs uppercase tracking-wider">Mins</span>
186
+ </div>
187
+ <div class="timer-unit flex flex-col items-center bg-white/20 backdrop-blur text-white rounded-xl p-4 min-w-[70px]">
188
+ <span data-swe-second data-swe-format="ss" class="text-3xl font-bold"></span>
189
+ <span class="text-xs uppercase tracking-wider">Secs</span>
190
+ </div>
191
+ </div>
192
+ <div class="mt-4 text-center text-white/90 text-sm">
193
+ <span class="ss ss-truck mr-1"></span> Orders placed within this time ship FREE!
194
+ </div>
195
+ </div>
196
+
27
197
  </div>
198
+ </section>
199
+
200
+ <!-- Section: Productivity & Utility -->
201
+ <section class="mb-16">
202
+ <h2 class="text-2xl font-bold text-gray-800 mb-2 flex items-center gap-2"><span class="ss ss-cog-6-tooth text-2xl"></span> Productivity & Utility</h2>
203
+ <p class="text-gray-600 mb-6">Useful timers for sessions, focus work, and everyday tasks.</p>
204
+
205
+ <div class="grid md:grid-cols-3 gap-6">
206
+
207
+ <!-- Session Timer -->
208
+ <div class="glass-card rounded-2xl p-6 shadow-lg">
209
+ <div class="flex items-center gap-3 mb-4">
210
+ <span class="ss ss-lock-closed text-3xl text-gray-700"></span>
211
+ <div>
212
+ <h3 class="text-lg font-bold text-gray-800">Session Timeout</h3>
213
+ <p class="text-sm text-gray-500">Auto-logout warning timer</p>
214
+ </div>
215
+ </div>
216
+ <div id="session-timer" class="text-center">
217
+ <div class="inline-flex items-center gap-2 bg-yellow-100 text-yellow-800 rounded-full px-4 py-2 text-sm font-medium mb-3">
218
+ <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/></svg>
219
+ Session expires in
220
+ </div>
221
+ <div class="flex justify-center gap-2">
222
+ <div class="timer-unit bg-gray-800 text-white rounded-lg px-4 py-3 min-w-[60px]">
223
+ <span data-swe-minute data-swe-format="mm" class="text-2xl font-mono font-bold"></span>
224
+ </div>
225
+ <span class="text-2xl font-bold text-gray-400 self-center">:</span>
226
+ <div class="timer-unit bg-gray-800 text-white rounded-lg px-4 py-3 min-w-[60px]">
227
+ <span data-swe-second data-swe-format="ss" class="text-2xl font-mono font-bold"></span>
228
+ </div>
229
+ </div>
230
+ </div>
231
+ </div>
232
+
233
+ <!-- Pomodoro Timer -->
234
+ <div class="glass-card rounded-2xl p-6 shadow-lg">
235
+ <div class="flex items-center gap-3 mb-4">
236
+ <span class="ss ss-crosshair text-3xl text-red-500"></span>
237
+ <div>
238
+ <h3 class="text-lg font-bold text-gray-800">Pomodoro Timer</h3>
239
+ <p class="text-sm text-gray-500">25-minute focus sessions</p>
240
+ </div>
241
+ </div>
242
+ <div id="pomodoro" class="text-center">
243
+ <div class="relative inline-flex items-center justify-center w-32 h-32 rounded-full bg-gradient-to-br from-red-400 to-red-600 shadow-lg mb-3">
244
+ <div class="flex items-baseline gap-1 text-white">
245
+ <span data-swe-minute data-swe-format="mm" class="text-3xl font-bold"></span>
246
+ <span class="text-xl">:</span>
247
+ <span data-swe-second data-swe-format="ss" class="text-3xl font-bold"></span>
248
+ </div>
249
+ </div>
250
+ <div class="flex justify-center gap-2">
251
+ <button id="pomodoro-pause" class="bg-gray-200 hover:bg-gray-300 text-gray-700 px-4 py-2 rounded-lg text-sm font-medium transition-colors">Pause</button>
252
+ <button id="pomodoro-reset" class="bg-red-100 hover:bg-red-200 text-red-700 px-4 py-2 rounded-lg text-sm font-medium transition-colors">Reset</button>
253
+ </div>
254
+ </div>
255
+ </div>
256
+
257
+ <!-- Current Time Clock -->
258
+ <div class="glass-card rounded-2xl p-6 shadow-lg">
259
+ <div class="flex items-center gap-3 mb-4">
260
+ <span class="ss ss-clock text-3xl text-slate-700"></span>
261
+ <div>
262
+ <h3 class="text-lg font-bold text-gray-800">Live Clock</h3>
263
+ <p class="text-sm text-gray-500">Current local time display</p>
264
+ </div>
265
+ </div>
266
+ <div id="live-clock" data-swe data-swe-current class="text-center">
267
+ <div class="inline-flex items-center gap-1 bg-gradient-to-br from-slate-700 to-slate-900 text-white rounded-xl p-4 shadow-lg">
268
+ <span data-swe-hour data-swe-format="HH" class="text-4xl font-mono font-bold"></span>
269
+ <span class="text-4xl font-bold animate-pulse">:</span>
270
+ <span data-swe-minute data-swe-format="mm" class="text-4xl font-mono font-bold"></span>
271
+ <span class="text-4xl font-bold animate-pulse">:</span>
272
+ <span data-swe-second data-swe-format="ss" class="text-4xl font-mono font-bold"></span>
273
+ </div>
274
+ <p class="mt-3 text-gray-500 text-sm">Auto-updates every second</p>
275
+ </div>
276
+ </div>
28
277
 
29
- <!-- Countdown for 10 seconds -->
30
- <div data-swe data-swe-countdown-duration="10">
31
- <div data-swe-second data-swe-format="ss"></div>
32
278
  </div>
279
+ </section>
33
280
 
34
- <!-- Display current time -->
35
- <div data-swe data-swe-current>
36
- <div data-swe-hour data-swe-format="HH"></div>
37
- <div data-swe-minute data-swe-format="mm"></div>
38
- <div data-swe-second data-swe-format="ss"></div>
281
+ <!-- Section: Interactive Demo -->
282
+ <section class="mb-16">
283
+ <h2 class="text-2xl font-bold text-gray-800 mb-2 flex items-center gap-2"><span class="ss ss-controller text-2xl"></span> Interactive Controls</h2>
284
+ <p class="text-gray-600 mb-6">Demonstrates the full control API with pause, resume, and reset functionality.</p>
285
+
286
+ <div class="glass-card rounded-2xl p-8 shadow-lg max-w-xl mx-auto">
287
+ <div class="text-center mb-6">
288
+ <h3 class="text-lg font-bold text-gray-800 mb-2">Controllable Timer</h3>
289
+ <p class="text-sm text-gray-500">A 60-second timer with full controls</p>
290
+ </div>
291
+
292
+ <div id="interactive-timer" class="flex justify-center gap-4 mb-6">
293
+ <div class="timer-unit flex flex-col items-center bg-gradient-to-br from-violet-500 to-purple-600 text-white rounded-xl p-5 min-w-[80px] shadow-lg">
294
+ <span data-swe-minute data-swe-format="mm" class="text-4xl font-bold"></span>
295
+ <span class="text-xs uppercase tracking-wider opacity-90">Mins</span>
296
+ </div>
297
+ <div class="timer-unit flex flex-col items-center bg-gradient-to-br from-violet-500 to-purple-600 text-white rounded-xl p-5 min-w-[80px] shadow-lg">
298
+ <span data-swe-second data-swe-format="ss" class="text-4xl font-bold"></span>
299
+ <span class="text-xs uppercase tracking-wider opacity-90">Secs</span>
300
+ </div>
301
+ </div>
302
+
303
+ <div class="flex flex-wrap justify-center gap-3">
304
+ <button id="btn-start" class="flex items-center gap-2 bg-emerald-500 hover:bg-emerald-600 text-white px-5 py-2.5 rounded-xl font-medium transition-colors shadow-md">
305
+ <span class="ss ss-play text-lg"></span>
306
+ Start
307
+ </button>
308
+ <button id="btn-pause" class="flex items-center gap-2 bg-amber-500 hover:bg-amber-600 text-white px-5 py-2.5 rounded-xl font-medium transition-colors shadow-md">
309
+ <span class="ss ss-pause text-lg"></span>
310
+ Pause
311
+ </button>
312
+ <button id="btn-resume" class="flex items-center gap-2 bg-blue-500 hover:bg-blue-600 text-white px-5 py-2.5 rounded-xl font-medium transition-colors shadow-md">
313
+ <span class="ss ss-play-circle text-lg"></span>
314
+ Resume
315
+ </button>
316
+ <button id="btn-reset" class="flex items-center gap-2 bg-rose-500 hover:bg-rose-600 text-white px-5 py-2.5 rounded-xl font-medium transition-colors shadow-md">
317
+ <span class="ss ss-arrow-path text-lg"></span>
318
+ Reset
319
+ </button>
320
+ </div>
321
+
322
+ <div id="event-log" class="mt-6 bg-gray-900 text-green-400 font-mono text-xs p-4 rounded-xl max-h-32 overflow-y-auto">
323
+ <p class="text-gray-500"># Event log - interactions will appear here</p>
324
+ </div>
39
325
  </div>
326
+ </section>
40
327
 
41
- <!-- Timer for 15 seconds -->
42
- <div id="timer" class="flex gap-4 p-4 bg-gray-300 rounded-xl max-w-max">
43
- <div data-swe-hour data-swe-format="HH" class="w-12 bg-gray-200 aspect-square flex items-center justify-center rounded-lg"></div>
44
- <div data-swe-minute data-swe-format="mm" class="w-12 bg-gray-200 aspect-square flex items-center justify-center rounded-lg"></div>
45
- <div data-swe-second data-swe-format="ss" class="w-12 bg-gray-200 aspect-square flex items-center justify-center rounded-lg"></div>
328
+ <!-- Section: Code Examples -->
329
+ <section class="mb-16">
330
+ <h2 class="text-2xl font-bold text-gray-800 mb-2 flex items-center gap-2"><span class="ss ss-code text-2xl"></span> Quick Start Guide</h2>
331
+ <p class="text-gray-600 mb-6">Get started with SenangWebs Epoch in seconds.</p>
332
+
333
+ <div class="grid md:grid-cols-2 gap-6">
334
+ <div class="bg-gray-900 rounded-2xl p-6 shadow-xl">
335
+ <h4 class="text-white font-semibold mb-4 flex items-center gap-2">
336
+ <span class="bg-green-500 text-xs px-2 py-1 rounded">HTML</span>
337
+ Data Attribute Method
338
+ </h4>
339
+ <pre class="text-sm text-gray-300 overflow-x-auto"><code>&lt;!-- Countdown to date --&gt;
340
+ &lt;div data-swe data-swe-countdown-end="2026-12-31 00:00:00"&gt;
341
+ &lt;div data-swe-day data-swe-format="dd"&gt;&lt;/div&gt;
342
+ &lt;div data-swe-hour data-swe-format="HH"&gt;&lt;/div&gt;
343
+ &lt;div data-swe-minute data-swe-format="mm"&gt;&lt;/div&gt;
344
+ &lt;div data-swe-second data-swe-format="ss"&gt;&lt;/div&gt;
345
+ &lt;/div&gt;</code></pre>
346
+ </div>
347
+
348
+ <div class="bg-gray-900 rounded-2xl p-6 shadow-xl">
349
+ <h4 class="text-white font-semibold mb-4 flex items-center gap-2">
350
+ <span class="bg-yellow-500 text-xs px-2 py-1 rounded text-black">JS</span>
351
+ JavaScript Method
352
+ </h4>
353
+ <pre class="text-sm text-gray-300 overflow-x-auto"><code>const timer = new SWE(element, {
354
+ autostart: true,
355
+ duration: 300, // 5 minutes
356
+ onTick: () => console.log('Tick!'),
357
+ onEnd: () => alert('Time is up!')
358
+ });
359
+
360
+ // Control methods
361
+ timer.pause();
362
+ timer.resume();
363
+ timer.reset();</code></pre>
364
+ </div>
46
365
  </div>
47
- </div>
366
+ </section>
48
367
 
49
368
  </main>
50
369
 
51
370
  <script src="../dist/swe.js"></script>
52
371
 
53
372
  <script>
54
- let timer;
55
373
  document.addEventListener('DOMContentLoaded', () => {
56
- timer = new SWE(document.querySelector('#timer'), {
374
+
375
+ // Flash Sale - 2 hours countdown
376
+ const flashSale = new SWE(document.querySelector('#flash-sale'), {
57
377
  autostart: true,
58
- duration: 15,
59
- // countdownEnd: '2025-01-01 00:00:00',
60
- onTick: () => {
61
- console.log('Timer ticked!');
62
- },
378
+ duration: 7200, // 2 hours
63
379
  onEnd: () => {
64
- console.log('Timer finished!');
380
+ document.querySelector('#flash-sale').innerHTML = '<p class="text-white text-xl font-bold">Sale Ended!</p>';
65
381
  }
66
382
  });
67
383
 
68
- // Event listening
69
- timer.element.addEventListener('swe:end', () => {
70
- console.log('Timer finished! Event listening');
384
+ // Free Shipping Offer - 4 hours
385
+ const shippingOffer = new SWE(document.querySelector('#shipping-offer'), {
386
+ autostart: true,
387
+ duration: 14400, // 4 hours
71
388
  });
389
+
390
+ // Session Timer - 5 minutes
391
+ const sessionTimer = new SWE(document.querySelector('#session-timer'), {
392
+ autostart: true,
393
+ duration: 300,
394
+ onEnd: () => {
395
+ alert('Your session has expired! Please log in again.');
396
+ }
397
+ });
398
+
399
+ // Pomodoro Timer - 25 minutes
400
+ let pomodoroTimer = new SWE(document.querySelector('#pomodoro'), {
401
+ autostart: true,
402
+ duration: 1500, // 25 minutes
403
+ onEnd: () => {
404
+ alert('🍅 Pomodoro complete! Take a 5-minute break.');
405
+ }
406
+ });
407
+
408
+ document.querySelector('#pomodoro-pause').addEventListener('click', () => {
409
+ pomodoroTimer.isPaused ? pomodoroTimer.resume() : pomodoroTimer.pause();
410
+ document.querySelector('#pomodoro-pause').textContent = pomodoroTimer.isPaused ? 'Resume' : 'Pause';
411
+ });
412
+
413
+ document.querySelector('#pomodoro-reset').addEventListener('click', () => {
414
+ pomodoroTimer.reset();
415
+ });
416
+
417
+ // Interactive Timer - 60 seconds
418
+ const interactiveTimer = new SWE(document.querySelector('#interactive-timer'), {
419
+ autostart: false,
420
+ duration: 60,
421
+ onStart: () => logEvent('Timer started'),
422
+ onPause: () => logEvent('Timer paused'),
423
+ onResume: () => logEvent('Timer resumed'),
424
+ onReset: () => logEvent('Timer reset'),
425
+ onTick: () => {}, // Silent tick
426
+ onEnd: () => logEvent('⏰ Timer ended!')
427
+ });
428
+
429
+ // Control buttons
430
+ document.querySelector('#btn-start').addEventListener('click', () => interactiveTimer.start());
431
+ document.querySelector('#btn-pause').addEventListener('click', () => interactiveTimer.pause());
432
+ document.querySelector('#btn-resume').addEventListener('click', () => interactiveTimer.resume());
433
+ document.querySelector('#btn-reset').addEventListener('click', () => interactiveTimer.reset());
434
+
435
+ // Event log
436
+ function logEvent(message) {
437
+ const log = document.querySelector('#event-log');
438
+ const time = new Date().toLocaleTimeString();
439
+ log.innerHTML += `<p>[${time}] ${message}</p>`;
440
+ log.scrollTop = log.scrollHeight;
441
+ }
442
+
443
+ // Listen for events
444
+ const timerEl = document.querySelector('#interactive-timer');
445
+ ['start', 'pause', 'resume', 'reset', 'end'].forEach(event => {
446
+ timerEl.addEventListener(`swe:${event}`, () => {
447
+ logEvent(`Event: swe:${event} fired`);
448
+ });
449
+ });
450
+
72
451
  });
73
452
  </script>
74
453
 
package/index.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * SenangWebs Epoch (SWE) - Module Entry Point
3
+ * A lightweight JavaScript library for countdown timers and time display
4
+ */
5
+
6
+ // Export the main library
7
+ module.exports = require('./dist/swe.js');
package/package.json CHANGED
@@ -1,27 +1,28 @@
1
- {
2
- "name": "senangwebs-epoch",
3
- "version": "1.1.2",
4
- "description": "Lightweight JavaScript library for creating dynamic countdown timers and time displays.",
5
- "main": "index.js",
6
- "directories": {
7
- "example": "examples"
8
- },
9
- "scripts": {
10
- "build": "webpack --mode production",
11
- "dev": "webpack --mode development --watch",
12
- "test": "echo \"Error: no test specified\" && exit 1"
13
- },
14
- "keywords": ["image", "carousel", "web", "customizable"],
15
- "author": "a-hakim",
16
- "license": "MIT",
17
- "devDependencies": {
18
- "@babel/core": "^7.25.8",
19
- "@babel/preset-env": "^7.25.8",
20
- "babel-loader": "^9.2.1",
21
- "css-loader": "^7.1.2",
22
- "mini-css-extract-plugin": "^2.9.1",
23
- "style-loader": "^4.0.0",
24
- "webpack": "^5.95.0",
25
- "webpack-cli": "^5.1.4"
26
- }
27
- }
1
+ {
2
+ "name": "senangwebs-epoch",
3
+ "version": "1.1.3",
4
+ "description": "Lightweight JavaScript library for creating dynamic countdown timers and time displays.",
5
+ "main": "dist/swe.js",
6
+ "module": "dist/swe.js",
7
+ "directories": {
8
+ "example": "examples"
9
+ },
10
+ "scripts": {
11
+ "build": "webpack --mode production",
12
+ "dev": "webpack --mode development --watch",
13
+ "test": "echo \"Error: no test specified\" && exit 1"
14
+ },
15
+ "keywords": ["countdown", "timer", "time", "epoch", "javascript", "date", "clock"],
16
+ "author": "a-hakim",
17
+ "license": "MIT",
18
+ "devDependencies": {
19
+ "@babel/core": "^7.25.8",
20
+ "@babel/preset-env": "^7.25.8",
21
+ "babel-loader": "^9.2.1",
22
+ "css-loader": "^7.1.2",
23
+ "mini-css-extract-plugin": "^2.9.1",
24
+ "style-loader": "^4.0.0",
25
+ "webpack": "^5.95.0",
26
+ "webpack-cli": "^5.1.4"
27
+ }
28
+ }
package/src/js/swe.js CHANGED
@@ -1,8 +1,10 @@
1
1
  /**
2
2
  * SenangWebs Epoch (SWE) - A JavaScript library for countdown timers and time display
3
- * Version: 1.1.1
3
+ * Version: 1.1.2
4
4
  */
5
5
 
6
+ import '../css/swe.css';
7
+
6
8
  class SWE {
7
9
  constructor(element, options = {}) {
8
10
  this.element = element;
@@ -208,20 +210,38 @@ class SWE {
208
210
  }
209
211
 
210
212
  calculateTimeUnits(milliseconds) {
211
- const seconds = Math.floor(milliseconds / 1000);
212
- const minutes = Math.floor(seconds / 60);
213
- const hours = Math.floor(minutes / 60);
214
- const days = Math.floor(hours / 24);
215
- const months = Math.floor(days / 30);
216
- const years = Math.floor(days / 365);
213
+ // Calculate using proper date math for accuracy
214
+ const totalSeconds = Math.floor(milliseconds / 1000);
215
+ const totalMinutes = Math.floor(totalSeconds / 60);
216
+ const totalHours = Math.floor(totalMinutes / 60);
217
+ const totalDays = Math.floor(totalHours / 24);
218
+
219
+ // Use date-based calculation for months and years
220
+ const now = new Date();
221
+ const futureDate = new Date(now.getTime() + milliseconds);
222
+
223
+ let years = futureDate.getFullYear() - now.getFullYear();
224
+ let months = futureDate.getMonth() - now.getMonth();
225
+ let days = futureDate.getDate() - now.getDate();
226
+
227
+ // Normalize negative values
228
+ if (days < 0) {
229
+ months--;
230
+ const prevMonth = new Date(futureDate.getFullYear(), futureDate.getMonth(), 0);
231
+ days += prevMonth.getDate();
232
+ }
233
+ if (months < 0) {
234
+ years--;
235
+ months += 12;
236
+ }
217
237
 
218
238
  return {
219
239
  year: years,
220
- month: months % 12,
221
- day: days % 30,
222
- hour: hours % 24,
223
- minute: minutes % 60,
224
- second: seconds % 60
240
+ month: months,
241
+ day: days,
242
+ hour: totalHours % 24,
243
+ minute: totalMinutes % 60,
244
+ second: totalSeconds % 60
225
245
  };
226
246
  }
227
247
 
@@ -252,7 +272,21 @@ class SWE {
252
272
 
253
273
  resume() {
254
274
  if (this.isPaused) {
255
- this.start();
275
+ this.isPaused = false;
276
+ this.startTime = Date.now();
277
+
278
+ switch (this.mode) {
279
+ case 'countdown-end':
280
+ this.startCountdownToDate();
281
+ break;
282
+ case 'countdown-duration':
283
+ this.startCountdownDuration();
284
+ break;
285
+ case 'current':
286
+ this.startCurrentTime();
287
+ break;
288
+ }
289
+
256
290
  this.dispatchEvent('resume');
257
291
  }
258
292
  }
@@ -279,10 +313,13 @@ class SWE {
279
313
  }
280
314
 
281
315
  stop() {
316
+ const wasRunning = this.intervalId !== null;
282
317
  if (this.intervalId) {
283
318
  clearInterval(this.intervalId);
284
319
  this.intervalId = null;
285
- this.isPaused = false;
320
+ }
321
+ this.isPaused = false;
322
+ if (wasRunning) {
286
323
  this.dispatchEvent('stop');
287
324
  }
288
325
  }
package/webpack.config.js CHANGED
@@ -2,12 +2,9 @@ const path = require('path');
2
2
  const MiniCssExtractPlugin = require('mini-css-extract-plugin');
3
3
 
4
4
  module.exports = {
5
- entry: {
6
- swe: './src/js/swe.js',
7
- style: './src/css/swe.css',
8
- },
5
+ entry: './src/js/swe.js',
9
6
  output: {
10
- filename: '[name].js',
7
+ filename: 'swe.js',
11
8
  path: path.resolve(__dirname, 'dist'),
12
9
  library: {
13
10
  name: 'SWE',
package/dist/style.js DELETED
@@ -1 +0,0 @@
1
- !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.SWE=t():e.SWE=t()}(this,(()=>(()=>{"use strict";var e={};return e.default})()));