Files
got-gaming/components/PlayerStats.tsx

134 lines
4.0 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
interface PlayerStatsProps {
username?: string;
avatar?: string;
hp?: number;
maxHp?: number;
xp?: number;
maxXp?: number;
level?: number;
}
// Format number with consistent locale to avoid hydration mismatch
const formatNumber = (num: number): string => {
return num.toLocaleString("en-US");
};
export default function PlayerStats({
username = "DragonSlayer99",
avatar = "/got-2.jpg",
hp = 750,
maxHp = 1000,
xp = 3250,
maxXp = 5000,
level = 42,
}: PlayerStatsProps) {
const [hpPercentage, setHpPercentage] = useState(0);
const [xpPercentage, setXpPercentage] = useState(0);
useEffect(() => {
// Animate HP bar
const hpTimer = setTimeout(() => {
setHpPercentage((hp / maxHp) * 100);
}, 100);
// Animate XP bar
const xpTimer = setTimeout(() => {
setXpPercentage((xp / maxXp) * 100);
}, 200);
return () => {
clearTimeout(hpTimer);
clearTimeout(xpTimer);
};
}, [hp, maxHp, xp, maxXp]);
const hpColor =
hpPercentage > 60
? "from-green-600 to-green-700"
: hpPercentage > 30
? "from-yellow-600 to-orange-700"
: "from-red-700 to-red-900";
return (
<div className="flex items-center gap-3">
{/* Avatar */}
<div className="w-10 h-10 rounded-full border border-pixel-gold/20 overflow-hidden bg-gray-900">
<img
src={avatar}
alt={username}
className="w-full h-full object-cover"
/>
</div>
{/* Stats */}
<div className="flex flex-col gap-1.5 min-w-[200px]">
{/* Username & Level */}
<div className="flex items-center gap-2">
<div className="text-pixel-gold font-gaming font-bold text-sm tracking-wider">
{username}
</div>
<div className="text-gray-400 font-pixel text-xs uppercase border border-pixel-gold/30 px-1.5 py-0.5 bg-black/40">
Lv.{level}
</div>
</div>
{/* Bars side by side */}
<div className="flex flex-col gap-1">
<div className="flex items-center gap-2">
{/* HP Bar */}
<div className="relative h-2 flex-1 bg-gray-900 border border-gray-700 rounded overflow-hidden">
<div
className={`absolute inset-0 bg-gradient-to-r ${hpColor} transition-all duration-1000 ease-out`}
style={{ width: `${hpPercentage}%` }}
>
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-white/10 to-transparent animate-shimmer"></div>
</div>
{hpPercentage < 30 && (
<div className="absolute inset-0 border border-red-500 rounded animate-pulse"></div>
)}
</div>
{/* XP Bar */}
<div className="relative h-2 flex-1 bg-gray-900 border border-pixel-gold/30 rounded overflow-hidden">
<div
className="absolute inset-0 bg-gradient-to-r from-pixel-gold/80 via-pixel-gold/70 to-pixel-gold/80 transition-all duration-1000 ease-out"
style={{ width: `${xpPercentage}%` }}
>
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-white/10 to-transparent animate-shimmer"></div>
</div>
</div>
</div>
{/* Labels */}
<div className="flex items-center gap-2 text-[8px] font-pixel text-gray-400">
<div className="flex-1 text-left">
HP {hp} / {maxHp}
</div>
<div className="flex-1 text-right">
XP {formatNumber(xp)} / {formatNumber(maxXp)}
</div>
</div>
</div>
</div>
<style jsx>{`
@keyframes shimmer {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
.animate-shimmer {
animation: shimmer 2s infinite;
}
`}</style>
</div>
);
}