|
@@ -8,19 +8,29 @@ import { useAuth } from "@/providers/auth-provider";
|
|
|
import { ApiError } from "@/lib/api";
|
|
import { ApiError } from "@/lib/api";
|
|
|
import { isRegisterPasswordValid } from "@/lib/password-rules";
|
|
import { isRegisterPasswordValid } from "@/lib/password-rules";
|
|
|
import { sendRegisterVerificationCode } from "@/lib/register-api";
|
|
import { sendRegisterVerificationCode } from "@/lib/register-api";
|
|
|
-import { Eye, EyeOff, UserPlus, CheckCircle2, X } from "lucide-react";
|
|
|
|
|
|
|
+import { Eye, EyeOff, UserPlus, CheckCircle2 } from "lucide-react";
|
|
|
import { cn } from "@/lib/utils";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
|
+import {
|
|
|
|
|
+ AuthCard,
|
|
|
|
|
+ AuthCloseButton,
|
|
|
|
|
+ AuthHeader,
|
|
|
|
|
+ AuthIconBadge,
|
|
|
|
|
+ AuthPageScene,
|
|
|
|
|
+ authErrorCls,
|
|
|
|
|
+ authFooterLinkCls,
|
|
|
|
|
+ authHintsCls,
|
|
|
|
|
+ authInputCls,
|
|
|
|
|
+ authLabelCls,
|
|
|
|
|
+ authPrimaryBtnCls,
|
|
|
|
|
+ authSecondaryBtnCls,
|
|
|
|
|
+} from "@/components/auth/auth-ui";
|
|
|
|
|
|
|
|
const SEND_CODE_COOLDOWN_SEC = 60;
|
|
const SEND_CODE_COOLDOWN_SEC = 60;
|
|
|
-const inputCls =
|
|
|
|
|
- "mt-2 w-full rounded-xl border border-white/10 bg-black/20 px-4 py-3.5 text-sm text-white placeholder-slate-500 focus:border-[#b89458] focus:outline-none focus:ring-1 focus:ring-[#b89458] transition-all";
|
|
|
|
|
|
|
|
|
|
type Props = {
|
|
type Props = {
|
|
|
layout: "fullscreen" | "embedded";
|
|
layout: "fullscreen" | "embedded";
|
|
|
onDismiss?: () => void;
|
|
onDismiss?: () => void;
|
|
|
- /** 弹窗内:注册成功后回到登录 */
|
|
|
|
|
onRegisterComplete?: () => void;
|
|
onRegisterComplete?: () => void;
|
|
|
- /** 弹窗内:已有账号,返回登录 */
|
|
|
|
|
onBackToLogin?: () => void;
|
|
onBackToLogin?: () => void;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
@@ -37,6 +47,7 @@ export function RegisterFormPanel({
|
|
|
const [password, setPassword] = useState("");
|
|
const [password, setPassword] = useState("");
|
|
|
const [showPassword, setShowPassword] = useState(false);
|
|
const [showPassword, setShowPassword] = useState(false);
|
|
|
const [code, setCode] = useState("");
|
|
const [code, setCode] = useState("");
|
|
|
|
|
+ const [referralCode, setReferralCode] = useState("");
|
|
|
const [err, setErr] = useState<string | null>(null);
|
|
const [err, setErr] = useState<string | null>(null);
|
|
|
const [sendCooldown, setSendCooldown] = useState(0);
|
|
const [sendCooldown, setSendCooldown] = useState(0);
|
|
|
const [sendingCode, setSendingCode] = useState(false);
|
|
const [sendingCode, setSendingCode] = useState(false);
|
|
@@ -92,6 +103,7 @@ export function RegisterFormPanel({
|
|
|
password,
|
|
password,
|
|
|
name: "学员",
|
|
name: "学员",
|
|
|
code: code.trim(),
|
|
code: code.trim(),
|
|
|
|
|
+ referralCode: referralCode.trim() || undefined,
|
|
|
});
|
|
});
|
|
|
if (!r.ok) {
|
|
if (!r.ok) {
|
|
|
if (r.message) setErr(r.message);
|
|
if (r.message) setErr(r.message);
|
|
@@ -108,21 +120,17 @@ export function RegisterFormPanel({
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
if (registerSuccess) {
|
|
if (registerSuccess) {
|
|
|
- const successCard = (
|
|
|
|
|
|
|
+ const successBody = (
|
|
|
<div className="text-center">
|
|
<div className="text-center">
|
|
|
- <div className="mx-auto mb-6 flex h-20 w-20 items-center justify-center rounded-full bg-emerald-500/10 text-emerald-400">
|
|
|
|
|
|
|
+ <div className="mx-auto mb-6 flex h-20 w-20 items-center justify-center rounded-full border border-emerald-400/25 bg-emerald-500/10 text-emerald-400 shadow-[0_0_40px_rgba(16,185,129,0.15)]">
|
|
|
<CheckCircle2 size={40} />
|
|
<CheckCircle2 size={40} />
|
|
|
</div>
|
|
</div>
|
|
|
- <h1 className="mb-2 font-serif text-2xl font-bold text-white">{t("registerSuccessTitle")}</h1>
|
|
|
|
|
- <p className="text-sm text-slate-400">
|
|
|
|
|
|
|
+ <h1 className="auth-title mb-2 font-serif text-2xl font-bold">{t("registerSuccessTitle")}</h1>
|
|
|
|
|
+ <p className="text-sm leading-relaxed text-slate-400/95">
|
|
|
{embedded ? "请使用邮箱与密码登录以继续。" : t("registerSuccessHint")}
|
|
{embedded ? "请使用邮箱与密码登录以继续。" : t("registerSuccessHint")}
|
|
|
</p>
|
|
</p>
|
|
|
{embedded && onRegisterComplete ? (
|
|
{embedded && onRegisterComplete ? (
|
|
|
- <button
|
|
|
|
|
- type="button"
|
|
|
|
|
- onClick={onRegisterComplete}
|
|
|
|
|
- className="mt-6 w-full rounded-2xl bg-gradient-to-br from-[#f3deae] to-[#d9be88] py-3.5 text-sm font-bold text-[#5c461a] shadow-xl"
|
|
|
|
|
- >
|
|
|
|
|
|
|
+ <button type="button" onClick={onRegisterComplete} className={cn(authPrimaryBtnCls, "mt-6")}>
|
|
|
{t("loginBtn")}
|
|
{t("loginBtn")}
|
|
|
</button>
|
|
</button>
|
|
|
) : null}
|
|
) : null}
|
|
@@ -131,201 +139,147 @@ export function RegisterFormPanel({
|
|
|
|
|
|
|
|
if (layout === "fullscreen") {
|
|
if (layout === "fullscreen") {
|
|
|
return (
|
|
return (
|
|
|
- <div className="relative flex min-h-screen flex-col items-center justify-center overflow-hidden bg-[#050b14] p-4 font-sans">
|
|
|
|
|
- <div className="pointer-events-none fixed inset-0 z-0">
|
|
|
|
|
- <div className="absolute left-1/2 top-1/2 h-[600px] w-[600px] -translate-x-1/2 -translate-y-1/2 rounded-full bg-[#b89458]/10 blur-[150px]" />
|
|
|
|
|
- </div>
|
|
|
|
|
- <div className="relative z-10 w-full max-w-md rounded-[2.5rem] border border-white/10 bg-[#0a1120]/80 p-10 text-center backdrop-blur-2xl shadow-2xl">
|
|
|
|
|
- {successCard}
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <AuthPageScene layout="fullscreen">
|
|
|
|
|
+ <AuthCard layout="fullscreen" className="text-center">
|
|
|
|
|
+ {successBody}
|
|
|
|
|
+ </AuthCard>
|
|
|
|
|
+ </AuthPageScene>
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
<div className="relative w-full max-w-md">
|
|
<div className="relative w-full max-w-md">
|
|
|
- {onDismiss ? (
|
|
|
|
|
- <button
|
|
|
|
|
- type="button"
|
|
|
|
|
- onClick={onDismiss}
|
|
|
|
|
- className="absolute right-3 top-3 z-10 rounded-lg p-2 text-slate-400 transition-colors hover:bg-white/10 hover:text-white"
|
|
|
|
|
- aria-label="关闭"
|
|
|
|
|
- >
|
|
|
|
|
- <X size={18} />
|
|
|
|
|
- </button>
|
|
|
|
|
- ) : null}
|
|
|
|
|
- <div className="auth-modal-body rounded-2xl border border-white/10 bg-[#0a1120]/80 p-6 text-center backdrop-blur-2xl shadow-2xl sm:p-8">
|
|
|
|
|
- {successCard}
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ {onDismiss ? <AuthCloseButton onClick={onDismiss} /> : null}
|
|
|
|
|
+ <AuthCard layout="embedded" className="text-center">
|
|
|
|
|
+ {successBody}
|
|
|
|
|
+ </AuthCard>
|
|
|
</div>
|
|
</div>
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const card = (
|
|
|
|
|
- <div
|
|
|
|
|
- className={cn(
|
|
|
|
|
- "auth-modal-body relative border border-white/10 bg-[#0a1120]/80 backdrop-blur-2xl shadow-2xl",
|
|
|
|
|
- layout === "fullscreen" ? "rounded-[2.5rem] p-8 md:p-10" : "rounded-2xl p-6 sm:p-8",
|
|
|
|
|
- )}
|
|
|
|
|
- >
|
|
|
|
|
- {embedded && onDismiss ? (
|
|
|
|
|
- <button
|
|
|
|
|
- type="button"
|
|
|
|
|
- onClick={onDismiss}
|
|
|
|
|
- className="absolute right-3 top-3 rounded-lg p-2 text-slate-400 transition-colors hover:bg-white/10 hover:text-white"
|
|
|
|
|
- aria-label="关闭"
|
|
|
|
|
- >
|
|
|
|
|
- <X size={18} />
|
|
|
|
|
- </button>
|
|
|
|
|
- ) : null}
|
|
|
|
|
|
|
+ return (
|
|
|
|
|
+ <AuthPageScene layout={layout}>
|
|
|
|
|
+ <AuthCard layout={layout}>
|
|
|
|
|
+ {embedded && onDismiss ? <AuthCloseButton onClick={onDismiss} /> : null}
|
|
|
|
|
|
|
|
- {layout === "fullscreen" ? (
|
|
|
|
|
- <div className="mb-8 flex justify-center">
|
|
|
|
|
- <div className="flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-[#f3deae] to-[#d9be88] text-[#5c461a] shadow-lg shadow-[#b89458]/20">
|
|
|
|
|
- <UserPlus size={28} className="translate-x-[2px]" />
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- ) : (
|
|
|
|
|
- <div className="mb-6 flex justify-center">
|
|
|
|
|
- <div className="flex h-12 w-12 items-center justify-center rounded-xl bg-gradient-to-br from-[#f3deae] to-[#d9be88] text-[#5c461a] shadow-md shadow-[#b89458]/20">
|
|
|
|
|
- <UserPlus size={22} className="translate-x-[2px]" />
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- )}
|
|
|
|
|
-
|
|
|
|
|
- <div className={layout === "fullscreen" ? "mb-8 text-center" : "mb-6 text-center"}>
|
|
|
|
|
- <h1
|
|
|
|
|
- className={cn(
|
|
|
|
|
- "font-serif font-bold text-white",
|
|
|
|
|
- layout === "fullscreen" ? "text-2xl" : "text-xl",
|
|
|
|
|
- )}
|
|
|
|
|
- >
|
|
|
|
|
- {t("registerTitle")}
|
|
|
|
|
- </h1>
|
|
|
|
|
- <p className="mt-2 text-sm text-slate-400">{t("registerEmailOnlyHint")}</p>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <AuthIconBadge icon={UserPlus} layout={layout} />
|
|
|
|
|
+ <AuthHeader title={t("registerTitle")} subtitle={t("registerEmailOnlyHint")} layout={layout} />
|
|
|
|
|
|
|
|
- <form onSubmit={onSubmit} className="space-y-5">
|
|
|
|
|
- <div>
|
|
|
|
|
- <label className="ml-1 text-sm font-bold text-slate-300">{t("email")}</label>
|
|
|
|
|
- <input
|
|
|
|
|
- type="email"
|
|
|
|
|
- required
|
|
|
|
|
- value={email}
|
|
|
|
|
- onChange={(e) => {
|
|
|
|
|
- setEmail(e.target.value);
|
|
|
|
|
- if (err) setErr(null);
|
|
|
|
|
- }}
|
|
|
|
|
- onBlur={() => setEmail((v) => v.trim())}
|
|
|
|
|
- autoComplete="email"
|
|
|
|
|
- className={inputCls}
|
|
|
|
|
- placeholder="admin@example.com"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div>
|
|
|
|
|
- <label className="ml-1 text-sm font-bold text-slate-300">{t("code")}</label>
|
|
|
|
|
- <div className="mt-2 flex gap-3">
|
|
|
|
|
|
|
+ <form onSubmit={onSubmit} className="space-y-5">
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <label className={authLabelCls}>{t("email")}</label>
|
|
|
<input
|
|
<input
|
|
|
|
|
+ type="email"
|
|
|
required
|
|
required
|
|
|
- value={code}
|
|
|
|
|
|
|
+ value={email}
|
|
|
onChange={(e) => {
|
|
onChange={(e) => {
|
|
|
- setCode(e.target.value.replace(/\D/g, "").slice(0, 6));
|
|
|
|
|
|
|
+ setEmail(e.target.value);
|
|
|
if (err) setErr(null);
|
|
if (err) setErr(null);
|
|
|
}}
|
|
}}
|
|
|
- className={cn(inputCls, "mt-0 flex-1")}
|
|
|
|
|
- placeholder="000000"
|
|
|
|
|
- inputMode="numeric"
|
|
|
|
|
- autoComplete="one-time-code"
|
|
|
|
|
|
|
+ onBlur={() => setEmail((v) => v.trim())}
|
|
|
|
|
+ autoComplete="email"
|
|
|
|
|
+ className={authInputCls}
|
|
|
|
|
+ placeholder="admin@example.com"
|
|
|
/>
|
|
/>
|
|
|
- <button
|
|
|
|
|
- type="button"
|
|
|
|
|
- disabled={!canSendCode}
|
|
|
|
|
- onClick={onSendCode}
|
|
|
|
|
- className="shrink-0 rounded-xl border border-white/10 bg-white/5 px-4 text-xs font-bold text-white transition-colors hover:bg-white/10 disabled:cursor-not-allowed disabled:opacity-50"
|
|
|
|
|
- >
|
|
|
|
|
- {sendingCode ? `${t("sendCode")}...` : sendCooldown > 0 ? t("sendCodeCooldown", { sec: sendCooldown }) : t("sendCode")}
|
|
|
|
|
- </button>
|
|
|
|
|
</div>
|
|
</div>
|
|
|
- </div>
|
|
|
|
|
|
|
|
|
|
- <div>
|
|
|
|
|
- <label className="ml-1 text-sm font-bold text-slate-300">{t("password")}</label>
|
|
|
|
|
- <div className="relative mt-2">
|
|
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <label className={authLabelCls}>{t("code")}</label>
|
|
|
|
|
+ <div className="mt-2 flex gap-3">
|
|
|
|
|
+ <input
|
|
|
|
|
+ required
|
|
|
|
|
+ value={code}
|
|
|
|
|
+ onChange={(e) => {
|
|
|
|
|
+ setCode(e.target.value.replace(/\D/g, "").slice(0, 6));
|
|
|
|
|
+ if (err) setErr(null);
|
|
|
|
|
+ }}
|
|
|
|
|
+ className={cn(authInputCls, "mt-0 flex-1")}
|
|
|
|
|
+ placeholder="000000"
|
|
|
|
|
+ inputMode="numeric"
|
|
|
|
|
+ autoComplete="one-time-code"
|
|
|
|
|
+ />
|
|
|
|
|
+ <button type="button" disabled={!canSendCode} onClick={onSendCode} className={authSecondaryBtnCls}>
|
|
|
|
|
+ {sendingCode ? `${t("sendCode")}...` : sendCooldown > 0 ? t("sendCodeCooldown", { sec: sendCooldown }) : t("sendCode")}
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <label className={authLabelCls}>{t("password")}</label>
|
|
|
|
|
+ <div className="relative mt-2">
|
|
|
|
|
+ <input
|
|
|
|
|
+ type={showPassword ? "text" : "password"}
|
|
|
|
|
+ required
|
|
|
|
|
+ autoComplete="new-password"
|
|
|
|
|
+ value={password}
|
|
|
|
|
+ onChange={(e) => {
|
|
|
|
|
+ setPassword(e.target.value);
|
|
|
|
|
+ if (err) setErr(null);
|
|
|
|
|
+ }}
|
|
|
|
|
+ className={cn(authInputCls, "mt-0 pr-12")}
|
|
|
|
|
+ placeholder={t("setPasswordPlaceholder")}
|
|
|
|
|
+ />
|
|
|
|
|
+ <button
|
|
|
|
|
+ type="button"
|
|
|
|
|
+ onClick={() => setShowPassword((v) => !v)}
|
|
|
|
|
+ className="absolute right-3 top-1/2 -translate-y-1/2 rounded-md p-1 text-slate-400 hover:text-[#f3deae] focus:outline-none focus:ring-1 focus:ring-[#b89458]"
|
|
|
|
|
+ aria-label={showPassword ? "隐藏密码" : "显示密码"}
|
|
|
|
|
+ >
|
|
|
|
|
+ {showPassword ? <EyeOff size={18} /> : <Eye size={18} />}
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <ul className={authHintsCls}>
|
|
|
|
|
+ <li>{t("passwordRuleLen")}</li>
|
|
|
|
|
+ <li>{t("passwordRuleCase")}</li>
|
|
|
|
|
+ <li>{t("passwordRuleMix")}</li>
|
|
|
|
|
+ </ul>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <label className={authLabelCls}>
|
|
|
|
|
+ {t("referralCode")}
|
|
|
|
|
+ <span className="ml-1.5 font-normal text-slate-500">({t("optional")})</span>
|
|
|
|
|
+ </label>
|
|
|
<input
|
|
<input
|
|
|
- type={showPassword ? "text" : "password"}
|
|
|
|
|
- required
|
|
|
|
|
- autoComplete="new-password"
|
|
|
|
|
- value={password}
|
|
|
|
|
|
|
+ type="text"
|
|
|
|
|
+ value={referralCode}
|
|
|
onChange={(e) => {
|
|
onChange={(e) => {
|
|
|
- setPassword(e.target.value);
|
|
|
|
|
|
|
+ setReferralCode(e.target.value);
|
|
|
if (err) setErr(null);
|
|
if (err) setErr(null);
|
|
|
}}
|
|
}}
|
|
|
- className={`${inputCls} mt-0 pr-12`}
|
|
|
|
|
- placeholder="设置密码"
|
|
|
|
|
|
|
+ onBlur={() => setReferralCode((v) => v.trim())}
|
|
|
|
|
+ autoComplete="off"
|
|
|
|
|
+ className={authInputCls}
|
|
|
|
|
+ placeholder={t("referralCodePlaceholder")}
|
|
|
/>
|
|
/>
|
|
|
- <button
|
|
|
|
|
- type="button"
|
|
|
|
|
- onClick={() => setShowPassword((v) => !v)}
|
|
|
|
|
- className="absolute right-3 top-1/2 -translate-y-1/2 rounded-md p-1 text-slate-400 hover:text-white focus:outline-none focus:ring-1 focus:ring-[#b89458]"
|
|
|
|
|
- aria-label={showPassword ? "隐藏密码" : "显示密码"}
|
|
|
|
|
- >
|
|
|
|
|
- {showPassword ? <EyeOff size={18} /> : <Eye size={18} />}
|
|
|
|
|
- </button>
|
|
|
|
|
</div>
|
|
</div>
|
|
|
- <ul className="mt-3 list-disc space-y-1.5 pl-5 text-xs font-medium text-slate-500">
|
|
|
|
|
- <li>{t("passwordRuleLen")}</li>
|
|
|
|
|
- <li>{t("passwordRuleCase")}</li>
|
|
|
|
|
- <li>{t("passwordRuleMix")}</li>
|
|
|
|
|
- </ul>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
|
|
|
- {err ? (
|
|
|
|
|
- <div className="rounded-xl border border-rose-500/30 bg-rose-500/10 p-3 text-center text-sm font-medium text-rose-400" role="alert">
|
|
|
|
|
- {err}
|
|
|
|
|
- </div>
|
|
|
|
|
- ) : null}
|
|
|
|
|
|
|
+ {err ? (
|
|
|
|
|
+ <div className={authErrorCls} role="alert">
|
|
|
|
|
+ {err}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ ) : null}
|
|
|
|
|
|
|
|
- <button
|
|
|
|
|
- type="submit"
|
|
|
|
|
- disabled={!canSubmit}
|
|
|
|
|
- className="mt-6 w-full rounded-2xl bg-gradient-to-br from-[#f3deae] to-[#d9be88] py-4 text-sm font-bold text-[#5c461a] shadow-xl shadow-[#b89458]/10 transition-transform hover:scale-[1.02] disabled:opacity-50 disabled:hover:scale-100"
|
|
|
|
|
- >
|
|
|
|
|
- {submitting ? `${t("registerBtn")}中...` : t("registerBtn")}
|
|
|
|
|
- </button>
|
|
|
|
|
- </form>
|
|
|
|
|
|
|
+ <button type="submit" disabled={!canSubmit} className={authPrimaryBtnCls}>
|
|
|
|
|
+ {submitting ? `${t("registerBtn")}中...` : t("registerBtn")}
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </form>
|
|
|
|
|
|
|
|
- <p className="mt-8 text-center text-sm text-slate-400">
|
|
|
|
|
- {embedded && onBackToLogin ? (
|
|
|
|
|
- <>
|
|
|
|
|
- 已有账户?{" "}
|
|
|
|
|
- <button
|
|
|
|
|
- type="button"
|
|
|
|
|
- onClick={onBackToLogin}
|
|
|
|
|
- className="font-bold text-white transition-colors hover:text-[#f3deae]"
|
|
|
|
|
- >
|
|
|
|
|
- {t("loginBtn")}
|
|
|
|
|
- </button>
|
|
|
|
|
- </>
|
|
|
|
|
- ) : (
|
|
|
|
|
- <Link href="/auth/login" className="font-bold text-white transition-colors hover:text-[#f3deae]">
|
|
|
|
|
- {t("toLogin")}
|
|
|
|
|
- </Link>
|
|
|
|
|
- )}
|
|
|
|
|
- </p>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <p className="mt-8 text-center text-sm text-slate-400/90">
|
|
|
|
|
+ {embedded && onBackToLogin ? (
|
|
|
|
|
+ <>
|
|
|
|
|
+ 已有账户?{" "}
|
|
|
|
|
+ <button type="button" onClick={onBackToLogin} className={authFooterLinkCls}>
|
|
|
|
|
+ {t("loginBtn")}
|
|
|
|
|
+ </button>
|
|
|
|
|
+ </>
|
|
|
|
|
+ ) : (
|
|
|
|
|
+ <Link href="/auth/login" className={authFooterLinkCls}>
|
|
|
|
|
+ {t("toLogin")}
|
|
|
|
|
+ </Link>
|
|
|
|
|
+ )}
|
|
|
|
|
+ </p>
|
|
|
|
|
+ </AuthCard>
|
|
|
|
|
+ </AuthPageScene>
|
|
|
);
|
|
);
|
|
|
-
|
|
|
|
|
- if (layout === "fullscreen") {
|
|
|
|
|
- return (
|
|
|
|
|
- <div className="relative flex min-h-screen flex-col items-center justify-center overflow-hidden bg-[#050b14] p-4 py-16 font-sans">
|
|
|
|
|
- <div className="pointer-events-none fixed inset-0 z-0">
|
|
|
|
|
- <div className="absolute left-1/2 top-1/2 h-[600px] w-[600px] -translate-x-1/2 -translate-y-1/2 rounded-full bg-[#b89458]/10 blur-[150px]" />
|
|
|
|
|
- </div>
|
|
|
|
|
- <div className="relative z-10 w-full max-w-md">{card}</div>
|
|
|
|
|
- </div>
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return <div className="w-full max-w-md">{card}</div>;
|
|
|
|
|
}
|
|
}
|