feat(theme): complete Minecraft overhaul for all pages including admin/utility

这个提交包含在:
X
2026-02-15 17:06:24 -08:00
父节点 e4742ff5ea
当前提交 3a98882a71
修改 24 个文件,包含 1203 行新增208 行删除

查看文件

@@ -1,6 +1,18 @@
"use client";
import { useEffect, useMemo, useState } from "react";
import {
ArrowRightLeft,
Calendar,
CheckCircle2,
History,
IdCard,
RefreshCw,
ShoppingBag,
TrendingUp,
TrendingDown,
Zap,
} from "lucide-react";
import { PixelAvatar } from "@/components/pixel-avatar";
import { apiFetch, listRatingHistory, type RatingHistoryItem } from "@/lib/api";
@@ -243,17 +255,19 @@ export default function MePage() {
Level {Math.floor(profile.rating / 100)}
</span>
</div>
<p className="text-xs text-[color:var(--mc-stone-dark)]">UID: {profile.id}</p>
</div>
<div className="mt-4 space-y-2 border-t border-black/20 pt-4">
<div className="flex justify-between text-sm">
<span className="text-zinc-800">{tx("绿宝石 (Rating)", "Emeralds (Rating)")}</span>
<span className="font-bold text-[color:var(--mc-green)] text-shadow-sm">{profile.rating}</span>
<div className="flex justify-between text-sm items-center">
<span className="text-zinc-800 flex items-center gap-1">
<IdCard size={14} className="text-zinc-500" />
UID
</span>
<span className="text-zinc-600 font-mono">{profile.id}</span>
</div>
<div className="flex justify-between text-sm">
<span className="text-zinc-800">{tx("加入时间", "Joined")}</span>
<span className="text-zinc-600">{new Date(profile.created_at * 1000).toLocaleDateString()}</span>
<div className="flex justify-between text-sm items-center">
<span className="text-zinc-800 flex items-center gap-1">
<Calendar size={14} className="text-zinc-500" />
{tx("加入时间", "Joined")}
</span>
<span className="text-zinc-600 font-mono">{new Date(profile.created_at * 1000).toLocaleDateString()}</span>
</div>
</div>
</section>
@@ -271,13 +285,16 @@ export default function MePage() {
<div key={idx} className="bg-[color:var(--mc-surface-soft)] p-3 border-2 border-[color:var(--mc-stone-dark)] relative group hover:border-[color:var(--mc-stone)] transition-colors">
<div className="flex items-start gap-3">
<div className={`w-5 h-5 border-2 border-[color:var(--mc-stone-dark)] flex items-center justify-center bg-black/30 mt-0.5 ${task.completed ? 'bg-[color:var(--mc-green)]/20' : ''}`}>
{task.completed && <span className="text-[color:var(--mc-green)] text-sm"></span>}
{task.completed && <CheckCircle2 size={16} className="text-[color:var(--mc-green)]" />}
</div>
<div className="flex-1">
<div className="flex justify-between items-start mb-1">
<h3 className="text-[color:var(--mc-plank-light)] text-lg font-bold leading-tight">
<h3 className="text-[color:var(--mc-plank-light)] text-lg font-bold leading-tight flex items-center gap-2">
{task.title}
<span className="ml-2 text-[color:var(--mc-gold)] text-base font-minecraft">+{task.reward} XP</span>
<span className="ml-2 text-[color:var(--mc-gold)] text-base font-minecraft flex items-center gap-1">
<Zap size={14} />
+{task.reward} XP
</span>
</h3>
</div>
<p className="text-[color:var(--mc-stone)] text-base leading-snug">
@@ -299,18 +316,21 @@ export default function MePage() {
<div className="grid gap-2">
<div className="flex gap-2 text-black">
<select
className="flex-1 rounded-none border-2 border-black bg-[color:var(--surface)] px-2 py-1 text-base font-bold"
value={selectedItemId}
onChange={(e) => setSelectedItemId(Number(e.target.value))}
>
<option value={0}>{tx("选择战利品...", "Select loot...")}</option>
{items.map((item) => (
<option key={item.id} value={item.id}>
{itemName(item.name)}
</option>
))}
</select>
<div className="relative flex-1">
<ShoppingBag className="absolute left-2 top-2 text-black/50 pointer-events-none" size={16} />
<select
className="w-full rounded-none border-2 border-black bg-[color:var(--surface)] px-2 py-1 pl-8 text-base font-bold appearance-none"
value={selectedItemId}
onChange={(e) => setSelectedItemId(Number(e.target.value))}
>
<option value={0}>{tx("选择战利品...", "Select loot...")}</option>
{items.map((item) => (
<option key={item.id} value={item.id}>
{itemName(item.name)}
</option>
))}
</select>
</div>
<input
className="w-20 rounded-none border-2 border-black bg-[color:var(--surface)] px-2 py-1 text-base font-bold text-center"
type="number"
@@ -340,10 +360,11 @@ export default function MePage() {
<option value="studyday">{tx("工作日价格", "Workday Price")}</option>
</select>
<button
className="mc-btn mc-btn-success text-xs px-4"
className="mc-btn mc-btn-success text-xs px-4 flex items-center gap-2"
onClick={() => void redeem()}
disabled={redeemLoading || !selectedItemId}
>
<ArrowRightLeft size={14} />
{tx("交易", "Trade")}
</button>
</div>
@@ -355,12 +376,16 @@ export default function MePage() {
{/* Rating History Section */}
<section className="mt-4 rounded-none border-[3px] border-black bg-[color:var(--mc-surface)] p-4 shadow-[4px_4px_0_rgba(0,0,0,0.5)]">
<h2 className="text-base font-bold text-black mb-2">{tx("积分变动记录", "Rating History")}</h2>
<h2 className="text-base font-bold text-black mb-2 flex items-center gap-2">
<History size={18} />
{tx("积分变动记录", "Rating History")}
</h2>
<div className="max-h-60 overflow-y-auto space-y-1">
{historyItems.map((item, idx) => (
<div key={idx} className="flex justify-between text-xs text-zinc-800 border-b border-zinc-200 pb-1">
<span>
<span className={`font-bold ${item.change > 0 ? 'text-[color:var(--mc-green)]' : 'text-[color:var(--mc-red)]'}`}>
<span className={`font-bold flex items-center gap-1 ${item.change > 0 ? 'text-[color:var(--mc-green)]' : 'text-[color:var(--mc-red)]'}`}>
{item.change > 0 ? <TrendingUp size={14} /> : <TrendingDown size={14} />}
{item.change > 0 ? `+${item.change}` : item.change}
</span>
<span className="ml-2">{item.note}</span>
@@ -381,10 +406,11 @@ export default function MePage() {
<div className="flex items-center justify-between gap-2 mb-2">
<h2 className="text-base font-bold text-black">{tx("交易记录", "Trade History")}</h2>
<button
className="text-xs text-[color:var(--mc-stone-dark)] underline"
className="text-xs text-[color:var(--mc-stone-dark)] underline flex items-center gap-1 hover:text-black"
onClick={() => void loadAll()}
disabled={loading}
>
<RefreshCw size={12} className={loading ? "animate-spin" : ""} />
{tx("刷新", "Refresh")}
</button>
</div>