feat: add wallet login modal

This commit is contained in:
TerryM
2026-06-02 00:32:46 +08:00
parent 71dac8373e
commit 43700d9fdc
12 changed files with 584 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
import { useEffect, useRef, useState } from "react";
import { useI18n } from "../i18n";
import { shortenAddress, useWallet } from "./WalletProvider";
export function WalletButton({ compact = false }: { compact?: boolean }) {
const { t } = useI18n();
const wallet = useWallet();
const [open, setOpen] = useState(false);
const rootRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!open) return;
const closeOnOutside = (event: MouseEvent | TouchEvent) => {
if (!rootRef.current?.contains(event.target as Node)) setOpen(false);
};
const closeOnEscape = (event: KeyboardEvent) => {
if (event.key === "Escape") setOpen(false);
};
document.addEventListener("mousedown", closeOnOutside);
document.addEventListener("touchstart", closeOnOutside);
window.addEventListener("keydown", closeOnEscape);
return () => {
document.removeEventListener("mousedown", closeOnOutside);
document.removeEventListener("touchstart", closeOnOutside);
window.removeEventListener("keydown", closeOnEscape);
};
}, [open]);
if (wallet.status === "loggedIn" && wallet.address) {
return (
<div ref={rootRef} className="relative">
<button
type="button"
onClick={() => setOpen((value) => !value)}
className={[
"inline-flex h-10 items-center justify-center rounded-full border border-ark-gold/45 bg-ark-gold/10 px-3 text-sm font-semibold text-ark-gold2 outline-none transition hover:bg-ark-gold/15 focus-visible:ring-2 focus-visible:ring-ark-gold/80 focus-visible:ring-offset-2 focus-visible:ring-offset-ark-bg",
compact ? "w-full" : "",
].join(" ")}
aria-label={t("walletConnectedAs")}
aria-expanded={open}
>
<span className="mr-2 h-2 w-2 rounded-full bg-emerald-400" />
{shortenAddress(wallet.address)}
</button>
{open ? (
<div className="absolute right-0 top-[calc(100%+0.5rem)] z-50 w-52 rounded-2xl border border-white/10 bg-[#1c1c21]/95 p-2 shadow-2xl shadow-black/70 ring-1 ring-ark-line/80 backdrop-blur-xl">
<div className="truncate px-3 py-2 text-xs text-neutral-400">
{wallet.address}
</div>
<button
type="button"
onClick={() => {
setOpen(false);
wallet.logout();
}}
className="w-full rounded-xl px-3 py-2 text-left text-sm font-medium text-red-200 transition hover:bg-red-500/10"
>
{t("walletDisconnect")}
</button>
</div>
) : null}
</div>
);
}
return (
<button
type="button"
onClick={wallet.openLoginModal}
className={[
"inline-flex h-10 items-center justify-center rounded-full border border-ark-gold/50 bg-ark-gold px-4 text-sm font-bold text-black outline-none transition hover:bg-ark-gold2 focus-visible:ring-2 focus-visible:ring-ark-gold/80 focus-visible:ring-offset-2 focus-visible:ring-offset-ark-bg",
compact ? "w-full" : "",
].join(" ")}
>
{wallet.status === "loading" ? t("loading") : t("walletConnect")}
</button>
);
}