A Clockwork Tailwind
While designing the detail page for projects that I've been working on (available from my portfolio-page), I also implemented a simple animated analog clock that is rendered next to the project's duration.
Because I didn't want to use any new external libraries or videos, I decided to implement the clock via Tailwind.css and its great animation utilities.
Code examples
There's not much to say else, as I thought that it would be most useful to you when I simply provide some code examples for reusability.
The layout in every example is almost the same any very similar. I just render some div-boxes via absolute positioning on top of each other. As each box only has the smallest width available, they appear to be the cursors visible in the clock.
The last example demonstrates how to start at 12 o'clock. The first two example each start at 3 o'clock, as they're laid out in the row.
Example 1: Most simple clock
export function Clock() {
return (
<div className="flex justify-center py-10 group">
<div className="relative flex items-center justify-end w-20 h-20 overflow-hidden bg-gray-900 rounded-full ">
<div className="absolute w-1/2 h-1 bg-white rounded-full origin-left -rotate-12 group-hover:rotate-[215deg] duration-1000 ease-in-out" />
<div className="absolute w-1/2 h-1 origin-left rotate-[70] group-hover:rotate-[340deg] duration-1000 ease-in-out">
<div className="w-2/3 h-full bg-white rounded-full" />
</div>
<div className="absolute flex justify-center flex-1 w-full">
<div className="w-1 h-1 bg-white rounded-full" />
</div>
</div>
</div>
);
}
Example 2: clock with border and indicators
import React from "react";
// Note that I'm using 'clsx' for
// composing classnames.
import clsx from "clsx";
export function Clock() {
return (
<div className="relative flex items-center justify-end w-20 h-20 overflow-hidden rounded-full ring-gray-600 ring-1">
{Array.from({ length: 8 }, (_, i) => (
<div
key={i}
style={{ height: 1 }}
className={clsx("absolute w-1/2 origin-left flex justify-end", {
"rotate-0": i === 0,
"rotate-45": i === 1,
"rotate-90": i === 2,
"rotate-[135deg]": i === 3,
"rotate-180": i === 4,
"rotate-[225deg]": i === 5,
"rotate-[270deg]": i === 6,
"rotate-[315deg]": i === 7,
})}>
<div className="w-1/3 h-full bg-gray-600 rounded-full" />
</div>
))}
<div className="absolute w-1/2 h-1 bg-gray-300 rounded-full origin-left -rotate-12 group-hover:rotate-[215deg] duration-1000 ease-in-out" />
<div className="absolute w-1/2 h-1 origin-left rotate-[85deg] group-hover:rotate-[340deg] duration-1000 ease-in-out">
<div className="w-2/3 h-full bg-gray-300 rounded-full" />
</div>
<div className="absolute flex justify-center flex-1 w-full">
<div className="w-1 h-1 bg-gray-300 rounded-full" />
</div>
</div>
);
}
Example 3: clock that starts at midnight
export function Clock() {
return (
<div className="flex justify-center py-10 group">
<div className="relative flex flex-col items-center justify-start w-20 h-20 overflow-hidden bg-gray-900 rounded-full ">
<div className="absolute w-1 duration-1000 ease-in-out origin-bottom bg-gradient-to-t from-white to-red-400 rounded-full h-1/2 group-hover:rotate-[200deg]" />
<div className="absolute h-1/2 w-1 origin-bottom rotate-[55deg] group-hover:rotate-[340deg] duration-1000 ease-in-out flex flex-col justify-end">
<div className="w-full rounded-full bg-gradient-to-t from-white to-blue-400 h-2/3" />
</div>
<div className="absolute flex items-center justify-center flex-1 w-full h-full">
<div className="w-1 h-1 bg-white rounded-full" />
</div>
</div>
</div>
);
}