From 2796853b0193e336908f44a387c1b63729cfb883 Mon Sep 17 00:00:00 2001 From: Ryan-slither Date: Fri, 14 Feb 2025 02:22:01 -0500 Subject: [PATCH] Created Clock Animation --- src/apps/boards/components/FlipClock.scss | 264 ++++++++++++---------- src/apps/boards/components/FlipClock.tsx | 78 ++++--- src/hooks/use-time.tsx | 1 + 3 files changed, 187 insertions(+), 156 deletions(-) diff --git a/src/apps/boards/components/FlipClock.scss b/src/apps/boards/components/FlipClock.scss index 4122234..f17ba75 100644 --- a/src/apps/boards/components/FlipClock.scss +++ b/src/apps/boards/components/FlipClock.scss @@ -1,144 +1,164 @@ +.flip-clock-container { + display: flex; + flex-direction: column; + justify-content: center; + height: 85%; +} + .flip-clock { + display: flex; + align-items: center; + justify-content: center; + perspective: 400px; + border-radius: 10px; + background-color: var(--color-surface-accent); color: var(--color-surface-accent-on); - + font-family: Termina; - font-size: 54px; + font-size: 50px; font-style: normal; font-weight: 700; - line-height: normal; letter-spacing: -0.54px; - - width: 90%; - height: 20rem; - + + width: 657px; + height: 257px; + + *, + *:before, + *:after { + box-sizing: border-box; + } +} + +time { display: flex; + align-items: center; justify-content: center; + height: 100%; + width: 100%; + text-align: center; +} + +.flip-clock__colon { + display: inline-flex; align-items: center; - - & time, - & span { - display: inline-block; - } - - &__digit { - display: inline-block; - padding: 2rem 1rem; - background-color: var(--color-surface-accent-bright); - - margin: 0 0.2rem; - min-width: 6rem; - display: flex; - justify-content: center; - text-align: center; - position: relative; - // color: orange; - // overflow: hidden; - - perspective: 40rem; - - // height: 10rem; - - - &::before, &::after { - content: attr(data-value); - color: var(--color-surface-accent-on); - font-size: inherit; - // height: 50%; - - // height: 5rem; - // line-height: 5rem; - - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - - display: flex; - justify-content: center; - align-items: center; - overflow: hidden; - - transform: translateZ(0rem); - backface-visibility: hidden; - transform-style: preserve-3d; - animation-fill-mode: both; - } - &::before { - // color: green; - // clip-path: polygon(0 0, 100% 0, 100% 50%, 0 50%); - top: 0; - bottom: auto; - background-color: rgba(0, 0, 0, 0.3); - - // margin-bottom: -15rem; - - - transform-origin: center; - // animation: flip-top 0.3s cubic-bezier(.37,.01,.94,.35); - - } - &::after { - // color: blue; - clip-path: polygon(0 50%, 100% 50%, 100% 100%, 0 100%); - top: auto; - bottom: 0; - - transform-origin: center top; - } - - - } - - &.flip { + justify-content: center; + box-sizing: border-box; + height: 100%; + vertical-align: middle; + padding-bottom: 15px; +} - .flip-clock__digit::before { - animation: flip-top 1s cubic-bezier(.15,.45,.28,1); - } - .flip-clock__digit::after { - animation: flip-bottom 0.3s cubic-bezier(.15,.45,.28,1); - } +.flip-clock__piece { + padding-top: 30px; + display: inline-block; + margin: 0 5px; +} - } - +$halfHeight: 0.72em; +$borderRadius: 0.15em; + +.card { + display: block; + position: relative; + padding-bottom: $halfHeight; + font-size: 3vw; + line-height: 0.95; } -@keyframes flip-top { +.card__top, +.card__bottom, +.card__back::before, +.card__back::after { + display: block; + height: $halfHeight; + color: #ccc; + background: #295258; + padding: 0.25em 0.25em; + border-radius: $borderRadius $borderRadius 0 0; + backface-visibility: hidden; + transform-style: preserve-3d; + width: 1.5em; + transform: translateZ(0); +} + +.card__bottom { + color: #fff; + position: absolute; + top: 50%; + left: 0; + border-top: solid 1px #fff; + background: #295258; + border-radius: 0 0 $borderRadius $borderRadius; + pointer-events: none; + overflow: hidden; +} + +.card__bottom::after { + display: block; + margin-top: -$halfHeight; +} + +.card__back::before, +.card__bottom::after { + content: attr(data-value); +} + +.card__back { + position: absolute; + top: 0; + height: 100%; + left: 0%; + pointer-events: none; +} + +.card__back::before { + position: relative; + z-index: -1; + overflow: hidden; +} + +.flip .card__back::before { + animation: flipTop 0.3s cubic-bezier(0.37, 0.01, 0.94, 0.35); + animation-fill-mode: both; + transform-origin: center bottom; +} + +.flip .card__back .card__bottom { + transform-origin: center top; + animation-fill-mode: both; + animation: flipBottom 0.6s cubic-bezier(0.15, 0.45, 0.28, 1); // 0.3s; +} + +@keyframes flipTop { 0% { transform: rotateX(0deg); + z-index: 2; + } + 0%, + 99% { + opacity: 0.99; } 100% { transform: rotateX(-90deg); + opacity: 0; } - // 0% { - // transform: rotateX(0deg); - // z-index: 2; - // } - // 0%, 99% { - // opacity: 0.99; - // } - // 100% { - // transform: rotateX(-90deg); - // opacity: 0; - // } -} - - -@keyframes flip-bottom { - // 0%, 50% { - // z-index: -1; - // transform: rotateX(90deg); - // opacity: 0; - // } - // 51% { - // opacity: 0.99; - // } - // 100% { - // opacity: 0.99; - // transform: rotateX(0deg); - // z-index: 5; - // } } - +@keyframes flipBottom { + 0%, + 50% { + z-index: -1; + transform: rotateX(90deg); + opacity: 0; + } + 51% { + opacity: 0.99; + } + 100% { + opacity: 0.99; + transform: rotateX(0deg); + z-index: 5; + } +} diff --git a/src/apps/boards/components/FlipClock.tsx b/src/apps/boards/components/FlipClock.tsx index 556cee6..91c601c 100644 --- a/src/apps/boards/components/FlipClock.tsx +++ b/src/apps/boards/components/FlipClock.tsx @@ -4,54 +4,64 @@ */ import { useEffect, useState } from 'react' import { useTime } from 'src/hooks' -import { sleep } from 'src/utils' import './FlipClock.scss' // ANIMATION IS WORK-IN-PROGRESS export const FlipClock = () => { const { date, hours: currentHours, minutes: currentMinutes } = useTime() - const [hours, setHours] = useState(currentHours) - const [minutes, setMinutes] = useState(currentMinutes) - const [flip, setFlip] = useState(false) + const [hour1, setHour1] = useState(currentHours[0]) + const [minute1, setMinute1] = useState(currentMinutes[0]) + const [hour2, setHour2] = useState(currentHours[1]) + const [minute2, setMinute2] = useState(currentMinutes[1]) useEffect(() => { - // setFlip(true) - setMinutes(currentMinutes) - setHours(currentHours) + console.log(hour1, hour2, minute1, minute2) - // sleep(1000).then(() => setFlip(false)) + if (currentMinutes[0] !== minute1) setMinute1(currentMinutes[0]) + if (currentMinutes[1] !== minute2) setMinute2(currentMinutes[1]) + if (currentHours[0] !== hour1) setHour1(currentHours[0]) + if (currentHours[1] !== hour2) setHour2(currentHours[1]) }, [date]) - // useEffect(() => { - // const interval = setInterval(() => { - // setFlip(true) - // sleep(1000).then(() => setFlip(false)) - // }, 5000) + return ( +
+
+ +
+
+ ) +} - // return () => clearInterval(interval) - // }, []) +const FlipPiece = (props: { integer: number; isFirst: boolean }) => { + const { integer, isFirst } = props + const [num, setNum] = useState(integer) + const [isFlip, setIsFlip] = useState(false) + useEffect(() => { + console.log(num) + setIsFlip(true) + setTimeout(() => { + setNum(integer) + setIsFlip(false) + }, 300) + }, [integer]) return ( -
- -
+ + ) } diff --git a/src/hooks/use-time.tsx b/src/hooks/use-time.tsx index b942f2d..7169981 100644 --- a/src/hooks/use-time.tsx +++ b/src/hooks/use-time.tsx @@ -15,6 +15,7 @@ export const useTime = (interval: number = 1000) => { date, hours: String(date.getHours()).padStart(2, '0'), minutes: String(date.getMinutes()).padStart(2, '0'), + seconds: String(date.getSeconds()).padStart(2, '0'), amOrPm: date .toLocaleTimeString([], { hour: 'numeric',