├── assets └── favicon.png ├── css ├── countdown.css ├── github.css └── main.css ├── index.html ├── readme.md └── js └── index.js /assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LucaCuello/CircularCountdownTemplate/HEAD/assets/favicon.png -------------------------------------------------------------------------------- /css/countdown.css: -------------------------------------------------------------------------------- 1 | @keyframes progress { 2 | 100% { 3 | stroke-dashoffset: 1256.12939453125; 4 | } 5 | } -------------------------------------------------------------------------------- /css/github.css: -------------------------------------------------------------------------------- 1 | .github { 2 | position: absolute; 3 | font-size: 40px; 4 | bottom: 10px; 5 | transition: transform 300ms ease-in-out; 6 | } 7 | 8 | .github a { 9 | color: #dcbeee; 10 | } 11 | 12 | .github:hover { 13 | transform: scale(1.1); 14 | transition: transform 300ms ease-in-out; 15 | } -------------------------------------------------------------------------------- /css/main.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,300;0,400;0,700;0,900;1,300;1,400;1,700;1,900&display=swap'); 2 | @import url(github.css); 3 | 4 | * { 5 | margin: 0; 6 | padding: 0; 7 | box-sizing: border-box; 8 | } 9 | 10 | html { 11 | font-family: 'Lato', sans-serif; 12 | } 13 | 14 | body { 15 | position: relative; 16 | display: flex; 17 | justify-content: center; 18 | align-items: center; 19 | height: 100vh; 20 | width: 100%; 21 | background-color: rgb(19, 16, 16); 22 | } -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/js/index.js:
--------------------------------------------------------------------------------
1 | // Injecting the countdown into HTML document
2 |
3 | const countdownContainer = document.querySelector(".countdown-container");
4 |
5 | countdownContainer.innerHTML = `
6 |
9 |
10 | `;
11 | countdownContainer.style.position = "relative";
12 |
13 | const span = document.querySelector(".seconds");
14 |
15 | span.style.position = "absolute";
16 | span.style.color = "#e8deee";
17 | span.style.fontWeight = "900";
18 | span.style.top = "50%";
19 | span.style.left = "50%";
20 | span.style.transform = "translate(-50%, -50%)";
21 |
22 | const progressWrapper = document.getElementById("progress-wrapper"),
23 | progress = document.getElementById("progress"),
24 | timeSpan = document.getElementById("seconds");
25 |
26 | // Countdown functions
27 |
28 | const options = {
29 | duration: +countdownContainer.dataset.duration,
30 | transition: countdownContainer.dataset.transition,
31 | color: countdownContainer.dataset.color,
32 | size: +countdownContainer.dataset.size,
33 | initialPosition: countdownContainer.dataset.position,
34 | };
35 |
36 | const circularCountdown = ({
37 | duration,
38 | transition,
39 | color,
40 | size,
41 | initialPosition,
42 | }) => {
43 | // Rendering countdown on HTML
44 | renderSeconds(duration);
45 | // Adjusting timer font-size depending of countdown size
46 | adjustFontSize(size);
47 | // Adjusting circular countdown size
48 | adjustCircleSize(size);
49 | // Setting initial position of countdown
50 | setInitialPosition(initialPosition);
51 | // Starting animation (setting transition, color and duration)
52 | animationStart(color, transition, duration);
53 | };
54 |
55 | const renderSeconds = (duration) => {
56 | timeSpan.innerHTML = duration;
57 | const secondsCountdown = setInterval(() => {
58 | duration--;
59 | timeSpan.innerHTML = duration;
60 | if (duration === 0) {
61 | clearInterval(secondsCountdown);
62 | timeSpan.innerHTML = ``;
63 | }
64 | }, 1000);
65 | };
66 |
67 | const adjustFontSize = (size) => {
68 | timeSpan.style.fontSize = `${size / 5}px`;
69 | };
70 |
71 | const adjustCircleSize = (size) => {
72 | progressWrapper.style.width = size;
73 | progressWrapper.style.height = size;
74 | };
75 |
76 | const setInitialPosition = (initialPosition) => {
77 | if (initialPosition === "up") {
78 | progressWrapper.style.transform = "rotate(270deg)";
79 | } else if (initialPosition === "left") {
80 | progressWrapper.style.transform = "rotate(180deg)";
81 | } else if (initialPosition === "down") {
82 | progressWrapper.style.transform = "rotate(90deg)";
83 | }
84 | };
85 |
86 | const animationStart = (color, transition, duration) => {
87 | let length = progress.getTotalLength();
88 | progress.style.stroke = color;
89 | progressWrapper.style.strokeDasharray = length;
90 | progressWrapper.style.animation = `progress ${transition} ${duration}s forwards`;
91 | };
92 |
93 | const initCountdown = () => {
94 | circularCountdown(options);
95 | };
96 |
97 | initCountdown();
98 |
--------------------------------------------------------------------------------