102 lines
3.9 KiB
TypeScript
Executable File
102 lines
3.9 KiB
TypeScript
Executable File
"use client";
|
||
// 回响星核 / Echo Nexus — 顶栏资源栏
|
||
import { useGameStore } from "@/store/gameStore";
|
||
import { formatNum, PRESTIGE } from "@/lib/game/config";
|
||
import { Gem, Lightbulb, Waves, RotateCcw } from "lucide-react";
|
||
import { Progress } from "@/components/ui/progress";
|
||
|
||
export function ResourceBar({ onPrestige }: { onPrestige: () => void }) {
|
||
const crystals = useGameStore((s) => s.crystals);
|
||
const crystalsPerSec = useGameStore((s) => s.crystalsPerSec);
|
||
const insights = useGameStore((s) => s.insights);
|
||
const contact = useGameStore((s) => s.contact);
|
||
const ascensions = useGameStore((s) => s.ascensions);
|
||
const blueprints = useGameStore((s) => s.blueprints);
|
||
|
||
return (
|
||
<div className="flex flex-wrap items-center gap-x-3 gap-y-2 sm:gap-x-4 px-3.5 py-2.5 rounded-2xl border border-white/10 bg-black/40 backdrop-blur-md">
|
||
{/* 晶体 */}
|
||
<Stat
|
||
icon={<Gem className="h-4 w-4 text-emerald-400" />}
|
||
label="记忆晶体"
|
||
value={formatNum(crystals)}
|
||
sub={`+${crystalsPerSec.toFixed(1)}/s`}
|
||
glow="rgba(52,211,153,0.4)"
|
||
/>
|
||
<div className="h-9 w-px bg-gradient-to-b from-transparent via-white/15 to-transparent hidden sm:block" />
|
||
{/* 洞见 */}
|
||
<Stat
|
||
icon={<Lightbulb className="h-4 w-4 text-amber-400" />}
|
||
label="技术洞见"
|
||
value={formatNum(insights)}
|
||
sub="解码产出"
|
||
glow="rgba(251,191,36,0.4)"
|
||
/>
|
||
<div className="h-9 w-px bg-gradient-to-b from-transparent via-white/15 to-transparent hidden sm:block" />
|
||
{/* 接触进度 */}
|
||
<div className="flex-1 min-w-[200px] flex flex-col gap-1.5">
|
||
<div className="flex items-center gap-2">
|
||
<Waves className="h-4 w-4 text-fuchsia-400 shrink-0" />
|
||
<span className="text-xs text-muted-foreground whitespace-nowrap">接触进度</span>
|
||
<span className="text-xs font-mono font-semibold text-fuchsia-300 ml-auto tabular-nums">
|
||
{contact.toFixed(1)}%
|
||
</span>
|
||
{contact >= 100 && (
|
||
<button
|
||
onClick={onPrestige}
|
||
className="text-[10px] px-2 py-0.5 rounded-full bg-fuchsia-500/20 border border-fuchsia-400/50 text-fuchsia-200 hover:bg-fuchsia-500/30 transition animate-pulse whitespace-nowrap ml-1"
|
||
>
|
||
飞升
|
||
</button>
|
||
)}
|
||
</div>
|
||
<Progress
|
||
value={contact}
|
||
className="h-1.5 bg-white/10 [&>div]:bg-gradient-to-r [&>div]:from-fuchsia-500 [&>div]:to-rose-400"
|
||
/>
|
||
</div>
|
||
<div className="h-9 w-px bg-gradient-to-b from-transparent via-white/15 to-transparent hidden sm:block" />
|
||
{/* 飞升 */}
|
||
<div className="flex items-center gap-2.5">
|
||
<RotateCcw className="h-4 w-4 text-rose-400 shrink-0" />
|
||
<div className="flex flex-col gap-0.5">
|
||
<span className="text-[10px] text-muted-foreground leading-none">飞升</span>
|
||
<div className="flex items-baseline gap-1.5">
|
||
<span className="text-sm font-mono font-semibold leading-none">
|
||
{ascensions}
|
||
</span>
|
||
<span className="text-amber-300 text-xs leading-none">×{blueprints.length}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
function Stat({
|
||
icon,
|
||
label,
|
||
value,
|
||
sub,
|
||
glow,
|
||
}: {
|
||
icon: React.ReactNode;
|
||
label: string;
|
||
value: string;
|
||
sub: string;
|
||
glow: string;
|
||
}) {
|
||
return (
|
||
<div className="flex items-center gap-2.5" style={{ filter: `drop-shadow(0 0 6px ${glow})` }}>
|
||
{icon}
|
||
<div className="flex flex-col gap-0.5">
|
||
<span className="text-[10px] text-muted-foreground leading-none">{label}</span>
|
||
<div className="flex items-baseline gap-1.5">
|
||
<span className="text-sm font-mono font-semibold leading-none tabular-nums">{value}</span>
|
||
<span className="text-[10px] text-muted-foreground/80 whitespace-nowrap">{sub}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|