Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save iannuttall/f9e4e5785d543bc3aa48ce265897cad0 to your computer and use it in GitHub Desktop.
Save iannuttall/f9e4e5785d543bc3aa48ce265897cad0 to your computer and use it in GitHub Desktop.
Countdown Timer w/Flip Animation (WIP)

Countdown Timer w/Flip Animation (WIP)

This project is part of the frontendmentor.io challenges. Adding the flip animation with the timer has proven to be a particular challenge. Although it looks to be working I am looking into a smoother animation effect to make it flip more reliably.

A Pen by Joseph Warren on CodePen.

License.

.container
.content-grid
.flip-card
%span.top{ "data-flip" => "false" }
%span.bottom{ "data-flip" => "false" }
.flip-card
%span.top{ "data-flip" => "false" }
%span.bottom{ "data-flip" => "false" }
.flip-card
%span.top{ "data-flip" => "false" }
%span.bottom{ "data-flip" => "false" }
.flip-card
%span.top{ "data-flip" => "false" }
%span.bottom{ "data-flip" => "false" }
.card-title
Days
.card-title
Hours
.card-title
Minutes
.card-title
Seconds
const flipCards = document.querySelectorAll('.flip-card');
const styles = getComputedStyle(flipCards[0]);
let days = parseInt(styles.getPropertyValue('--days'));
let hours = parseInt(styles.getPropertyValue('--hours'));
let minutes = parseInt(styles.getPropertyValue('--minutes'));
let seconds = parseInt(styles.getPropertyValue('--seconds'));
function updateDisplay(){
// const time = document.querySelector('.time');
// time.textContent = seconds;
flipCards[0].style.setProperty('--days', days);
flipCards[1].style.setProperty('--hours', hours);
flipCards[2].style.setProperty('--minutes', minutes);
flipCards[3].style.setProperty('--seconds', seconds);
}
function countdown() {
if (days === 0 && hours === 0 && minutes === 0 && seconds === 0){
return;
}
if (seconds === 0) {
seconds = 59;
if (minutes === 0) {
minutes = 59;
if (hours === 0) {
hours = 23;
if (days > 0) {
setTimeout(() => {
startAnimation(0);
}, 500);
days--;
}
} else {
setTimeout(() => {
startAnimation(1);
}, 500)
hours--;
}
} else {
setTimeout(() => {
startAnimation(2);
}, 500);
minutes--;
}
} else {
setTimeout(() => {
startAnimation(3);
}, 500);
seconds--;
}
updateDisplay();
}
function startAnimation(n) {
const flip = flipCards[n].querySelectorAll('[data-flip]');
const top = flip[0];
const bottom = flip[1];
console.log(flip)
top.dataset.flip = 'true';
bottom.dataset.flip = 'true';
top.addEventListener("animationend", () => {
bottom.dataset.flip = 'true';
bottom.addEventListener("animationend", () => {
top.dataset.flip = 'false';
bottom.dataset.flip = 'false';
}, { once: true });
}, { once: true });
}
function startCountdown() {
countdown();
setInterval(countdown, 1000);
}
startCountdown();
// For set date
//
// const today = new Date();
// const date = new Date('2023-08-10T06:25:00');
// let days = today.getDay() - date.getDay();
// let hours = Math.abs(today.getHours() - date.getHours());
// let minDiff = Math.abs(today.getMinutes() - date.getMinutes())
// let minutes = today.getMinutes() > date.getMinutes() ? 60 - today.getMinutes() + minDiff : minDiff;
// let seconds = today.getSeconds() - date.getSeconds();
@import url('https://api.fonts.coollabs.io/css2?family=Red+Hat+Text:wght@700&display=swap') cover;
:root {
// timer settings
--days: 0;
--hours: 1;
--minutes: 1;
--seconds: 0;
// colors variables
--grayish-blue: hsl(237, 18%, 59%);
--desaturated-blue: hsl(236, 21%, 26%);
--dark-blue-800: hsl(235, 16%, 14%);
--dark-blue-900: hsl(234, 17%, 12%);
--soft-red: hsl(345, 95%, 68%);
// global variables
--bg-clr-body: var(--dark-blue-800);
--bg-clr-card: var(--desaturated-blue);
--bg-clr-card-shadow: var(--dark-blue-900);
--txt-clr-card: var(--soft-red);
--txt-clr-card-title: var(--grayish-blue);
--txt-size-card: 4.5rem;
}
// resets
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background:
url('https://launch-countdown-timer-sebasec.vercel.app/images/bg-stars.svg'),
url('https://launch-countdown-timer-sebasec.vercel.app/images/pattern-hills.svg') bottom/100% no-repeat var(--bg-clr-body);
font-family: 'Red Hat Text', sans-serif;
}
// center content grid
.container {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
height: 100dvh;
}
.content-grid {
display: grid;
gap: 32px;
grid-template: repeat(2, 1fr) / repeat(4, 1fr);
}
.flip-card {
--_flip-card-size: 150px;
background:
linear-gradient(to bottom, #2F3047 50%, var(--bg-clr-card) 0);
border-radius: 0.5rem;
box-shadow: 0 1rem 0 var(--bg-clr-card-shadow);
color: var(--txt-clr-card);
display: inline-flex;
flex-direction: column;
font-size: var(--txt-size-card);
font-weight: 700;
position: relative;
perspective: 800px;
perspective-orgin: center;
height: var(--_flip-card-size);
width: var(--_flip-card-size);
&::before, &::after {
--_pivot-pt-size: 12px;
content: "";
background: var(--dark-blue-900);
border-radius: 50%;
height: var(--_pivot-pt-size);
width: var(--_pivot-pt-size);
top: 50%;
position: absolute;
transform: translateY(-50%);
z-index: 99;
}
// pivot positions
&::before {
left: calc(var(--_pivot-pt-size) / -2);
}
&::after {
right: calc(var(--_pivot-pt-size) / -2);
}
// top card shadow
.top::before {
content: '';
background: var(--bg-clr-card-shadow);
inset: 0;
opacity: 0.2;
z-index: 99;
}
}
// timer styles & settings
.flip-card {
.time {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
inset: 0;
z-index: -1;
}
.top,
.bottom {
--_flip-speed: 450ms;
background: var(--bg-clr-card);
display: flex;
justify-content: center;
position: absolute;
overflow: hidden;
height: 50%;
width: 100%;
transform-style: preserve-3d;
}
// top animation
.top[data-flip=true]{
animation: top-to-bottom var(--_flip-speed) ease-in;
}
// bottom animation
.bottom[data-flip=true]{
animation: bottom-to-top var(--_flip-speed) ease-out var(--_flip-speed);
}
.top {
border-radius: 0.5rem 0.5rem 0 0;
transform-origin: bottom;
}
.bottom {
border-radius: 0 0 0.5rem 0.5rem;
top: 50%;
transform-origin: top;
}
.top::after {
top: 50%;
}
.top::after,
.top::before,
.bottom::after {
position: absolute;
}
.bottom::after {
top: -50%;
}
&:nth-child(1) {
.top::after, .bottom::after {
counter-reset: days var(--days);
content: counter(days, decimal-leading-zero);
}
}
&:nth-child(2) {
.top::after, .bottom::after {
counter-reset: hours var(--hours);
content: counter(hours, decimal-leading-zero);
}
}
&:nth-child(3) {
.top::after, .bottom::after {
counter-reset: minutes var(--minutes);
content: counter(minutes, decimal-leading-zero);
}
}
&:nth-child(4) {
.top::after, .bottom::after {
counter-reset: seconds var(--seconds);
content: counter(seconds, decimal-leading-zero);
}
}
}
.card-title {
color: var(--txt-clr-card-title);
justify-self: center;
letter-spacing: 0.3em;
text-transform: uppercase;
}
@keyframes top-to-bottom {
100% {
transform: rotateX(-90deg);
}
}
@keyframes bottom-to-top {
0% {
transform: rotateX(90deg);
box-shadow: 0 5px 5px rgba(0, 0, 0, 0.3);
}
100% {
transform: rotateX(0deg);
box-shadow: 0 5px 5px rgba(0, 0, 0, 0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment