This commit is contained in:
2026-03-20 21:17:26 +01:00
parent 1a62fcb81d
commit 29c3ff8572
229 changed files with 13147 additions and 2577 deletions

View File

@@ -0,0 +1,34 @@
import React from 'react'
const TONES = {
1: 'border-slate-500/30 bg-slate-500/10 text-slate-200',
2: 'border-sky-400/35 bg-sky-500/10 text-sky-200',
3: 'border-emerald-400/35 bg-emerald-500/10 text-emerald-200',
4: 'border-fuchsia-400/35 bg-fuchsia-500/10 text-fuchsia-200',
5: 'border-amber-400/35 bg-amber-500/10 text-amber-100',
6: 'border-rose-400/35 bg-rose-500/10 text-rose-100',
7: 'border-violet-400/35 bg-violet-500/10 text-violet-100',
}
function cx(...parts) {
return parts.filter(Boolean).join(' ')
}
export default function LevelBadge({ level = 1, rank = 'Newbie', compact = false, className = '' }) {
const numericLevel = Number(level || 1)
const tone = TONES[numericLevel] || TONES[1]
return (
<span
className={cx(
'inline-flex items-center gap-1 rounded-full border px-2.5 py-1 font-semibold tracking-[0.08em]',
compact ? 'text-[10px] uppercase' : 'text-[11px] uppercase',
tone,
className,
)}
>
<span>LVL {numericLevel}</span>
<span className="text-current/75">{rank}</span>
</span>
)
}

View File

@@ -0,0 +1,43 @@
import React from 'react'
function formatXp(value) {
return new Intl.NumberFormat().format(Number(value || 0))
}
function clampPercent(value) {
const numeric = Number(value || 0)
if (!Number.isFinite(numeric)) return 0
return Math.max(0, Math.min(100, numeric))
}
function cx(...parts) {
return parts.filter(Boolean).join(' ')
}
export default function XPProgressBar({
xp = 0,
currentLevelXp = 0,
nextLevelXp = 100,
progressPercent = 0,
maxLevel = false,
className = '',
}) {
const percent = maxLevel ? 100 : clampPercent(progressPercent)
return (
<div className={cx('space-y-2', className)}>
<div className="flex items-center justify-between gap-3 text-xs text-slate-300">
<span>{formatXp(xp)} XP</span>
<span>
{maxLevel ? 'Max level reached' : `${formatXp(currentLevelXp)} / ${formatXp(nextLevelXp)} XP`}
</span>
</div>
<div className="h-2.5 overflow-hidden rounded-full bg-white/10 ring-1 ring-white/10">
<div
className="h-full rounded-full bg-[linear-gradient(90deg,#38bdf8_0%,#a78bfa_55%,#f59e0b_100%)] transition-[width] duration-500"
style={{ width: `${percent}%` }}
/>
</div>
</div>
)
}