refactor: 提取 Button 组件,统一按钮变体、尺寸和加载状态

新增 Button.tsx 支持 5 种变体(primary/secondary/danger/ghost/purple)、
3 种尺寸(sm/md/lg)、pill/rounded 形状及内置 loading 状态,
替换 8 个文件中 16 处重复的按钮样板代码。
This commit is contained in:
2026-02-26 18:39:14 +08:00
parent 19edcaeeb5
commit 455b9e04d8
9 changed files with 178 additions and 115 deletions
+25 -21
View File
@@ -10,11 +10,11 @@ import {
LogIn,
Users,
Sparkles,
Loader2,
ChevronRight,
} from "lucide-react";
import { getCachedProfile, isRegistered } from "@/lib/userId";
import AuthModal from "@/components/AuthModal";
import Button from "@/components/Button";
import { BlindboxListSkeleton } from "@/components/Skeleton";
import type { UserProfile } from "@/types";
@@ -256,14 +256,15 @@ export default function BlindboxLobbyPage() {
maxLength={30}
className="h-11 flex-1 rounded-xl border-none bg-surface px-4 text-sm text-foreground outline-none ring-1 ring-border transition-all placeholder:text-dim focus:ring-2 focus:ring-purple-600"
/>
<button
<Button
onClick={handleCreate}
disabled={creating}
className="flex h-11 items-center gap-1.5 rounded-xl bg-purple-600 px-4 text-sm font-bold text-white transition-colors hover:bg-purple-500 disabled:opacity-50"
variant="purple"
size="lg"
loading={creating}
icon={<Plus size={16} />}
>
{creating ? <Loader2 size={16} className="animate-spin" /> : <Plus size={16} />}
</button>
</Button>
</div>
{/* Join alternative */}
@@ -286,14 +287,16 @@ export default function BlindboxLobbyPage() {
maxLength={6}
className="h-11 flex-1 rounded-xl border-none bg-surface px-4 text-center font-mono text-sm tracking-[0.15em] text-foreground outline-none ring-1 ring-border transition-all placeholder:text-dim focus:ring-2 focus:ring-purple-600"
/>
<button
<Button
onClick={handleJoin}
disabled={joining || joinCode.trim().length < 6}
className="flex h-11 items-center gap-1.5 rounded-xl bg-surface px-4 text-sm font-semibold text-secondary ring-1 ring-border transition-colors hover:bg-elevated disabled:opacity-40"
variant="secondary"
size="lg"
disabled={joinCode.trim().length < 6}
loading={joining}
icon={<LogIn size={16} />}
>
{joining ? <Loader2 size={16} className="animate-spin" /> : <LogIn size={16} />}
</button>
</Button>
</div>
{error && (
@@ -330,14 +333,14 @@ export default function BlindboxLobbyPage() {
maxLength={30}
className="h-10 flex-1 rounded-xl border-none bg-surface px-3 text-sm text-foreground outline-none ring-1 ring-border transition-all placeholder:text-dim focus:ring-2 focus:ring-purple-600"
/>
<button
<Button
onClick={handleCreate}
disabled={creating}
className="flex h-10 items-center gap-1.5 rounded-xl bg-purple-600 px-4 text-xs font-bold text-white transition-colors hover:bg-purple-500 disabled:opacity-50"
variant="purple"
loading={creating}
icon={<Plus size={14} />}
>
{creating ? <Loader2 size={14} className="animate-spin" /> : <Plus size={14} />}
</button>
</Button>
</div>
{/* Join row */}
@@ -354,14 +357,15 @@ export default function BlindboxLobbyPage() {
maxLength={6}
className="h-10 flex-1 rounded-xl border-none bg-surface px-3 text-center font-mono text-sm tracking-[0.15em] text-foreground outline-none ring-1 ring-border transition-all placeholder:font-sans placeholder:tracking-normal placeholder:text-dim focus:ring-2 focus:ring-purple-600"
/>
<button
<Button
onClick={handleJoin}
disabled={joining || joinCode.trim().length < 6}
className="flex h-10 items-center gap-1.5 rounded-xl bg-surface px-4 text-xs font-semibold text-secondary ring-1 ring-border transition-colors hover:bg-elevated disabled:opacity-40"
variant="secondary"
disabled={joinCode.trim().length < 6}
loading={joining}
icon={<LogIn size={14} />}
>
{joining ? <Loader2 size={14} className="animate-spin" /> : <LogIn size={14} />}
</button>
</Button>
</div>
{error && (