JSFiddle - React, Tailwind, and code Playground
by David Simpson
HTML
<script src="https://codepen.io/shshaw/pen/BzObXp"></script>
<script src="https://cdn.rawgit.com/vuejs/vue/v1.0.24/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.15.1/moment.min.js"></script>
<script>console.clear();</script>
CSS
/**
* @see: https://codepen.io/shshaw/pen/BzObXp
*/
html {
height: 100%;
font-family: sans-serif;
}
body {
min-height: 100%;
display: flex;
justify-content: center;
align-items: center;
background: #EEE;
}
.flip-clock {
text-align: center;
perspective: 600px;
margin: 0 auto;
}
.flip-clock *,
.flip-clock *:before,
.flip-clock *:after {
box-sizing: border-box;
}
.flip-clock__piece {
display: inline-block;
margin: 0 0.2vw;
}
@media (min-width: 1000px) {
.flip-clock__piece {
margin: 0 5px;
}
}
.flip-clock__slot {
font-size: 1rem;
line-height: 1.5;
display: block;
/*
//position: relative;
//top: -1.6em;
z-index: 10;
//color: #FFF;
*/
}
.flip-card {
display: block;
position: relative;
padding-bottom: 0.72em;
font-size: 2.25rem;
line-height: 0.95;
}
@media (min-width: 1000px) {
.flip-clock__slot {
font-size: 1.2rem;
}
.flip-card {
font-size: 3rem;
}
}
/*////////////////////////////////////////*/
.flip-card__top,
.flip-card__bottom,
.flip-card__back-bottom,
.flip-card__back::before,
.flip-card__back::after {
display: block;
height: 0.72em;
color: #ccc;
background: #222;
padding: 0.23em 0.25em 0.4em;
border-radius: 0.15em 0.15em 0 0;
backface-visiblity: hidden;
transform-style: preserve-3d;
width: 2.1em;
}
.flip-card__bottom,
.flip-card__back-bottom {
color: #FFF;
position: absolute;
top: 50%;
left: 0;
border-top: solid 1px #000;
background: #393939;
border-radius: 0 0 0.15em 0.15em;
pointer-events: none;
overflow: hidden;
z-index: 2;
}
.flip-card__back-bottom {
z-index: 1;
}
.flip-card__bottom::after,
.flip-card__back-bottom::after {
display: block;
margin-top: -0.72em;
}
.flip-card__back::before,
.flip-card__bottom::after,
.flip-card__back-bottom::after {
content: attr(data-value);
}
.flip-card__back {
position: absolute;
top: 0;
height: 100%;
left: 0%;
pointer-events: none;
}
.flip-card__back::before {
position: relative;
overflow:...
Vue
var targetDate = '2022-11-22 15:21:00'
Vue.filter('zerofill', function (value) {
//value = ( value < 0 ? 0 : value );
return (value < 10 && value > -1 ? '0' : '') + value;
});
var Tracker = Vue.extend({
template: `
<span v-show="show" class="flip-clock__piece">
<span class="flip-clock__card flip-card">
<b class="flip-card__top">{{current | zerofill}}</b>
<b class="flip-card__bottom" data-value="{{current | zerofill}}"></b>
<b class="flip-card__back" data-value="{{previous | zerofill}}"></b>
<b class="flip-card__back-bottom" data-value="{{previous | zerofill}}"></b>
</span>
<span class="flip-clock__slot">{{property}}</span>
</span>`,
props: ['property', 'time'],
data: () => ({
current: 0,
previous: 0,
show: false }),
events: {
time(newValue) {
if (newValue[this.property] === undefined) {
this.show = false;
return;
}
var val = newValue[this.property];
this.show = true;
val = val < 0 ? 0 : val;
if (val !== this.current) {
this.previous = this.current;
this.current = val;
this.$el.classList.remove('flip');
void this.$el.offsetWidth;
this.$el.classList.add('flip');
}
} } });
var el = document.createElement('div');
document.body.appendChild(el);
var Countdown = new Vue({
el: el,
template: `
<div class="flip-clock" data-date="2021-10-11" @click="update">
<tracker
v-for="tracker in trackers"
:property="tracker"
:time="time"
v-ref:trackers
></tracker>
</div>
`,
props: ['date', 'callback'],
data: () => ({
time: {},
i: 0,
trackers: ['Days', 'Hours', 'Minutes', 'Seconds'] //'Random',
}),
components: {
Tracker },
beforeDestroy() {
if (window['cancelAnimationFrame']) {
cancelAnimationFrame(this.frame);
}
},
watch: {
'date': function (newVal) {
this.setCountdown(newVal);
} },
...