Docs
Live score
Live score widget that displays the score of a match.
Installation
Run the following command
It will create a new file called live-score.tsx
inside the components/animata/widget
directory.
mkdir -p components/animata/widget && touch components/animata/widget/live-score.tsx
Paste the code
Open the newly created file and paste the following code:
"use client";
import { useEffect, useState } from "react";
import { Circle, Triangle } from "lucide-react";
import { cn } from "@/lib/utils";
interface Team {
score: number;
win: number;
name: string;
icon: string;
}
interface GameInfo {
teamOne: Team;
teamTwo: Team;
lap: number;
}
// #region placeholder functions
const maxScore = 10;
const lapCount = 5;
const getScore = (lastScore?: GameInfo): GameInfo => {
const teamOneScore = (lastScore?.teamOne.score ?? 0) + Math.floor(Math.random() * 3) + 1;
const teamTwoScore = (lastScore?.teamTwo.score ?? 0) + Math.floor(Math.random() * 3) + 1;
return {
lap: (lastScore?.lap ?? 1) + 1,
...lastScore,
teamOne: {
icon: "🇳🇵",
name: "NPL",
score: teamOneScore % maxScore,
win:
teamOneScore >= maxScore ? (lastScore?.teamOne.win ?? 0) + 1 : lastScore?.teamOne.win ?? 0,
},
teamTwo: {
name: "USA",
icon: "🇺🇸",
score: teamTwoScore % maxScore,
win:
teamTwoScore >= maxScore ? (lastScore?.teamTwo.win ?? 0) + 1 : lastScore?.teamTwo.win ?? 0,
},
};
};
// #endregion
const Header = ({ game }: { game: GameInfo }) => (
<div className="flex items-center justify-between p-4">
<div className="flex gap-1">
<div className="h-6 w-6">{game.teamOne.icon}</div>
<p className="font-bold">{game.teamOne.name}</p>
</div>
<div className="flex gap-1">
<p className="font-bold">{game.teamTwo.name}</p>
<div className="h-6 w-6">{game.teamTwo.icon}</div>
</div>
</div>
);
const Score = ({ score }: { score: string }) => (
<div className="relative flex h-20 w-10 items-center justify-center rounded-lg border-4 border-black bg-neutral-800">
<p className="text-5xl font-semibold">{score}</p>
<div className="absolute w-full border border-black"></div>
</div>
);
const Diamond = ({ style }: { style: string }) => (
<div className={cn("absolute h-1.5 w-1.5 rotate-45 transform bg-gray-500", style)} />
);
export default function LiveScore() {
// #region state
const [game, updateGame] = useState<GameInfo>({
teamOne: {
score: Math.floor(Math.random() * maxScore),
win: Math.floor(Math.random() * 3),
name: "NPL",
icon: "🇳🇵",
},
teamTwo: {
score: Math.floor(Math.random() * maxScore),
win: Math.floor(Math.random() * 3),
name: "USA",
icon: "🇺🇸",
},
lap: Math.floor(Math.random() * 3) + 1,
});
useEffect(() => {
let timer: NodeJS.Timeout;
const updateScore = () => {
const now = new Date();
const secondsUntilNextMinute = 60 - now.getSeconds();
timer = setTimeout(updateScore, secondsUntilNextMinute * 1000);
updateGame((current) => {
const next = getScore(current);
if (next.lap === lapCount) {
clearTimeout(timer);
}
return next;
});
};
updateScore();
return () => clearTimeout(timer);
}, []);
// #endregion
return (
<div className="group flex size-52 flex-col rounded-3xl bg-zinc-800 text-white">
<Header game={game} />
<div className="flex w-full flex-1 items-center justify-center gap-2 px-4">
<div className="flex">
<Score score={String(game.teamOne.score).padStart(2, "0").charAt(0)} />
<Score score={String(game.teamOne.score).padStart(2, "0").charAt(1)} />
</div>
<div className="flex">
<Score score={String(game.teamTwo.score).padStart(2, "0").charAt(0)} />
<Score score={String(game.teamTwo.score).padStart(2, "0").charAt(1)} />
</div>
</div>
<div className="relative h-14 overflow-hidden rounded-b-3xl bg-zinc-950 text-white">
<div className="flex h-14 items-center justify-around overflow-hidden p-4 font-medium transition-all group-hover:-translate-y-full">
<div className="flex items-center gap-1 tabular-nums">
<Triangle fill="white" size={6} />
<p>
{game.lap}
<sup>{["st", "nd", "rd"][game.lap - 1] ?? "th"}</sup>
</p>
</div>
<div className="flex flex-col items-center justify-center">
<div className="relative h-3 w-3">
<Diamond style="bg-yellow-500 -top-1/4 left-1/4 " />
<Diamond style="-left-1/4 top-1/4 " />
<Diamond style="-right-1/4 top-1/4 " />
</div>
<div className="flex pt-1">
<Circle size={8} fill="white" />
<Circle size={8} color="grey" />
<Circle size={8} color="grey" />
</div>
</div>
<div className="tabular-nums">
{game.teamOne.win} - {game.teamTwo.win}
</div>
</div>
<div className="flex h-14 items-center justify-center bg-green-500 text-sm transition-all group-hover:-translate-y-full">
Some other information.
</div>
</div>
</div>
);
}
Credits
Built by Aashish Katila