├── LICENSE ├── index.html ├── script.js └── styles.css /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 WebDevSimplified 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 |
13 |
14 |
Hours
15 |
16 |
17 |
2
18 |
2
19 |
20 |
21 |
4
22 |
4
23 |
24 |
25 |
26 |
27 |
Minutes
28 |
29 |
30 |
0
31 |
0
32 |
33 |
34 |
0
35 |
0
36 |
37 |
38 |
39 |
40 |
Seconds
41 |
42 |
43 |
0
44 |
0
45 |
46 |
47 |
0
48 |
0
49 |
50 |
51 |
52 |
53 | 54 | -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | const countToDate = new Date().setHours(new Date().getHours() + 24) 2 | let previousTimeBetweenDates 3 | setInterval(() => { 4 | const currentDate = new Date() 5 | const timeBetweenDates = Math.ceil((countToDate - currentDate) / 1000) 6 | flipAllCards(timeBetweenDates) 7 | 8 | previousTimeBetweenDates = timeBetweenDates 9 | }, 250) 10 | 11 | function flipAllCards(time) { 12 | const seconds = time % 60 13 | const minutes = Math.floor(time / 60) % 60 14 | const hours = Math.floor(time / 3600) 15 | 16 | flip(document.querySelector("[data-hours-tens]"), Math.floor(hours / 10)) 17 | flip(document.querySelector("[data-hours-ones]"), hours % 10) 18 | flip(document.querySelector("[data-minutes-tens]"), Math.floor(minutes / 10)) 19 | flip(document.querySelector("[data-minutes-ones]"), minutes % 10) 20 | flip(document.querySelector("[data-seconds-tens]"), Math.floor(seconds / 10)) 21 | flip(document.querySelector("[data-seconds-ones]"), seconds % 10) 22 | } 23 | 24 | function flip(flipCard, newNumber) { 25 | const topHalf = flipCard.querySelector(".top") 26 | const startNumber = parseInt(topHalf.textContent) 27 | if (newNumber === startNumber) return 28 | 29 | const bottomHalf = flipCard.querySelector(".bottom") 30 | const topFlip = document.createElement("div") 31 | topFlip.classList.add("top-flip") 32 | const bottomFlip = document.createElement("div") 33 | bottomFlip.classList.add("bottom-flip") 34 | 35 | top.textContent = startNumber 36 | bottomHalf.textContent = startNumber 37 | topFlip.textContent = startNumber 38 | bottomFlip.textContent = newNumber 39 | 40 | topFlip.addEventListener("animationstart", e => { 41 | topHalf.textContent = newNumber 42 | }) 43 | topFlip.addEventListener("animationend", e => { 44 | topFlip.remove() 45 | }) 46 | bottomFlip.addEventListener("animationend", e => { 47 | bottomHalf.textContent = newNumber 48 | bottomFlip.remove() 49 | }) 50 | flipCard.append(topFlip, bottomFlip) 51 | } 52 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | *, *::after, *::before { 2 | box-sizing: border-box; 3 | font-family: Arial, Helvetica, sans-serif; 4 | font-size: 2.25rem; 5 | } 6 | 7 | body { 8 | background-color: #f2f1ed; 9 | color: #de4848; 10 | } 11 | 12 | .flip-card { 13 | position: relative; 14 | display: inline-flex; 15 | flex-direction: column; 16 | box-shadow: 0 2px 3px 0 rgba(0, 0, 0, .2); 17 | border-radius: .1em; 18 | } 19 | 20 | .top, 21 | .bottom, 22 | .flip-card .top-flip, 23 | .flip-card .bottom-flip { 24 | height: .75em; 25 | line-height: 1; 26 | padding: .25em; 27 | overflow: hidden; 28 | } 29 | 30 | .top, 31 | .flip-card .top-flip { 32 | background-color: #f7f7f7; 33 | border-top-right-radius: .1em; 34 | border-top-left-radius: .1em; 35 | border-bottom: 1px solid rgba(0, 0, 0, 0.1); 36 | } 37 | 38 | .bottom, 39 | .flip-card .bottom-flip { 40 | background-color: white; 41 | display: flex; 42 | align-items: flex-end; 43 | border-bottom-right-radius: .1em; 44 | border-bottom-left-radius: .1em; 45 | } 46 | 47 | .flip-card .top-flip { 48 | position: absolute; 49 | width: 100%; 50 | animation: flip-top 250ms ease-in; 51 | transform-origin: bottom; 52 | } 53 | 54 | @keyframes flip-top { 55 | 100% { 56 | transform: rotateX(90deg); 57 | } 58 | } 59 | 60 | .flip-card .bottom-flip { 61 | position: absolute; 62 | bottom: 0; 63 | width: 100%; 64 | animation: flip-bottom 250ms ease-out 250ms; 65 | transform-origin: top; 66 | transform: rotateX(90deg); 67 | } 68 | 69 | @keyframes flip-bottom { 70 | 100% { 71 | transform: rotateX(0deg); 72 | } 73 | } 74 | 75 | .container { 76 | display: flex; 77 | gap: .5em; 78 | justify-content: center; 79 | } 80 | 81 | .container-segment { 82 | display: flex; 83 | flex-direction: column; 84 | gap: .1em; 85 | align-items: center; 86 | } 87 | 88 | .segment { 89 | display: flex; 90 | gap: .1em; 91 | } 92 | 93 | .segment-title { 94 | font-size: 1rem; 95 | } --------------------------------------------------------------------------------