mirror of
https://github.com/JetSprow/J-Board-Lite.git
synced 2026-05-01 01:14:10 +05:30
feat: polish lite auth entry points
This commit is contained in:
@@ -3,6 +3,7 @@ import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { PublicNotice } from "../public-notice";
|
||||
import { SiteFooter } from "@/components/shared/site-footer";
|
||||
import { PRODUCT_EDITION } from "@/lib/product";
|
||||
|
||||
export function AuthShell({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
@@ -36,7 +37,7 @@ export function AuthCard({
|
||||
{(title || description) && (
|
||||
<CardHeader className="space-y-2 pt-6 text-center">
|
||||
<div className="mx-auto flex size-10 items-center justify-center rounded-lg bg-primary text-sm font-bold text-primary-foreground">
|
||||
S
|
||||
{PRODUCT_EDITION.slice(0, 1)}
|
||||
</div>
|
||||
{title && <h1 className="text-display text-2xl font-semibold">{title}</h1>}
|
||||
{description && <p className="text-sm leading-6 text-muted-foreground">{description}</p>}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ForgotPasswordClient } from "./forgot-password-client";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "找回密码",
|
||||
description: "通过邮箱重设 J-Board 账户密码。",
|
||||
description: "通过邮箱重设 J-Board Lite 账户密码。",
|
||||
};
|
||||
|
||||
export default function ForgotPasswordPage() {
|
||||
|
||||
@@ -7,10 +7,10 @@ import { PageTransition } from "@/components/shared/page-transition";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: {
|
||||
default: "登录与注册",
|
||||
template: "%s | J-Board",
|
||||
default: "账户入口",
|
||||
template: "%s | J-Board Lite",
|
||||
},
|
||||
description: "登录或注册 J-Board 账号。",
|
||||
description: "登录 J-Board Lite 账号,或通过邮箱找回密码。",
|
||||
};
|
||||
|
||||
export default async function AuthLayout({
|
||||
|
||||
@@ -9,9 +9,16 @@ import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { TurnstileWidget } from "@/components/shared/turnstile-widget";
|
||||
import { PRODUCT_NAME } from "@/lib/product";
|
||||
import { AuthCard, AuthErrorMessage, AuthShell } from "../_components/auth-shell";
|
||||
|
||||
export function LoginPageClient({ siteKey }: { siteKey?: string | null }) {
|
||||
export function LoginPageClient({
|
||||
siteKey,
|
||||
allowRegistration,
|
||||
}: {
|
||||
siteKey?: string | null;
|
||||
allowRegistration: boolean;
|
||||
}) {
|
||||
const router = useRouter();
|
||||
const [error, setError] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -43,7 +50,7 @@ export function LoginPageClient({ siteKey }: { siteKey?: string | null }) {
|
||||
|
||||
return (
|
||||
<AuthShell>
|
||||
<AuthCard title="J-Board" description="登录你的 JB面板账户">
|
||||
<AuthCard title={PRODUCT_NAME} description="登录你的面板账户">
|
||||
<form onSubmit={onSubmit} className="space-y-4">
|
||||
<AuthErrorMessage message={error} />
|
||||
<div className="space-y-2">
|
||||
@@ -63,6 +70,8 @@ export function LoginPageClient({ siteKey }: { siteKey?: string | null }) {
|
||||
<Link href="/forgot-password" className="font-medium text-primary hover:underline">
|
||||
忘记密码
|
||||
</Link>
|
||||
{allowRegistration && (
|
||||
<>
|
||||
<span className="h-1 w-1 rounded-full bg-muted-foreground/30" aria-hidden />
|
||||
<span>
|
||||
没有账户?{" "}
|
||||
@@ -70,6 +79,8 @@ export function LoginPageClient({ siteKey }: { siteKey?: string | null }) {
|
||||
注册
|
||||
</Link>
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
{error === "邮箱尚未验证,请先查收验证邮件" && (
|
||||
<>
|
||||
<span className="h-1 w-1 rounded-full bg-muted-foreground/30" aria-hidden />
|
||||
|
||||
@@ -4,10 +4,10 @@ import { LoginPageClient } from "./login-page-client";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "登录",
|
||||
description: "登录 J-Board 账户并进入用户中心。",
|
||||
description: "登录 J-Board Lite 账户并进入用户中心。",
|
||||
};
|
||||
|
||||
export default async function LoginPage() {
|
||||
const config = await getAppConfig();
|
||||
return <LoginPageClient siteKey={config.turnstileSiteKey} />;
|
||||
return <LoginPageClient siteKey={config.turnstileSiteKey} allowRegistration={config.allowRegistration} />;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import type { Metadata } from "next";
|
||||
import { redirect } from "next/navigation";
|
||||
import { getAppConfig } from "@/services/app-config";
|
||||
import { RegisterPageClient } from "./register-page-client";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "注册",
|
||||
description: "创建 J-Board 新账户并开始订阅服务。",
|
||||
description: "创建 J-Board Lite 新账户并开始订阅服务。",
|
||||
};
|
||||
|
||||
export default async function RegisterPage() {
|
||||
const config = await getAppConfig();
|
||||
if (!config.allowRegistration) redirect("/login");
|
||||
return <RegisterPageClient siteKey={config.turnstileSiteKey} />;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { TurnstileWidget } from "@/components/shared/turnstile-widget";
|
||||
import { getErrorMessage } from "@/lib/errors";
|
||||
import { PRODUCT_NAME } from "@/lib/product";
|
||||
import { AuthCard, AuthErrorMessage, AuthShell } from "../_components/auth-shell";
|
||||
|
||||
export function RegisterPageClient({ siteKey }: { siteKey?: string | null }) {
|
||||
@@ -80,7 +81,7 @@ export function RegisterPageClient({ siteKey }: { siteKey?: string | null }) {
|
||||
|
||||
return (
|
||||
<AuthShell>
|
||||
<AuthCard title="J-Board" description="创建 JB面板账户">
|
||||
<AuthCard title={PRODUCT_NAME} description="创建面板账户">
|
||||
<form onSubmit={onSubmit} className="space-y-4">
|
||||
<AuthErrorMessage message={error} />
|
||||
<div className="space-y-2">
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Toaster } from "@/components/ui/sonner";
|
||||
import { ThemeProvider } from "@/components/shared/theme-provider";
|
||||
import { PRODUCT_NAME } from "@/lib/product";
|
||||
import "./globals.css";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: {
|
||||
default: "J-Board - JB面板",
|
||||
template: "%s | J-Board",
|
||||
default: `${PRODUCT_NAME} - JB面板轻量版`,
|
||||
template: `%s | ${PRODUCT_NAME}`,
|
||||
},
|
||||
description: "J-Board(JB面板)订阅共享与节点管理平台",
|
||||
description: "J-Board Lite(JB面板轻量版)订阅共享与节点管理平台",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
|
||||
@@ -1,23 +1,28 @@
|
||||
import { GitFork } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ThemeToggle } from "./theme-toggle";
|
||||
|
||||
const GITHUB_URL = "https://github.com/JetSprow/J-Board";
|
||||
import { PRODUCT_EDITION, PRODUCT_NAME, PRODUCT_REPOSITORY_URL, PRODUCT_VERSION } from "@/lib/product";
|
||||
|
||||
export function SiteFooter({ className }: { className?: string }) {
|
||||
return (
|
||||
<footer
|
||||
className={cn(
|
||||
"mx-auto flex w-full max-w-md items-center justify-center gap-2 text-xs text-muted-foreground/70",
|
||||
"mx-auto flex w-full max-w-md flex-wrap items-center justify-center gap-2 text-xs text-muted-foreground/70",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<span>J-Board</span>
|
||||
<span className="h-1 w-1 rounded-full bg-muted-foreground/30" aria-hidden />
|
||||
<div className="inline-flex min-h-8 items-center gap-2 rounded-lg border border-border/70 bg-card/80 px-2.5 py-1 text-foreground shadow-sm">
|
||||
<span className="text-muted-foreground">当前版本</span>
|
||||
<span className="font-semibold">{PRODUCT_NAME}</span>
|
||||
<span className="rounded-md bg-primary/10 px-1.5 py-0.5 text-[0.68rem] font-semibold uppercase text-primary">
|
||||
{PRODUCT_EDITION}
|
||||
</span>
|
||||
<span className="font-mono text-[0.72rem] text-muted-foreground">v{PRODUCT_VERSION}</span>
|
||||
</div>
|
||||
<ThemeToggle className="size-7 rounded-md border-transparent bg-transparent" />
|
||||
<span className="h-1 w-1 rounded-full bg-muted-foreground/30" aria-hidden />
|
||||
<a
|
||||
href={GITHUB_URL}
|
||||
href={PRODUCT_REPOSITORY_URL}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="inline-flex items-center gap-1.5 rounded-md px-1.5 py-1 font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/15"
|
||||
|
||||
6
src/lib/product.ts
Normal file
6
src/lib/product.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import packageJson from "../../package.json";
|
||||
|
||||
export const PRODUCT_NAME = "J-Board Lite";
|
||||
export const PRODUCT_EDITION = "Lite";
|
||||
export const PRODUCT_VERSION = packageJson.version;
|
||||
export const PRODUCT_REPOSITORY_URL = "https://github.com/JetSprow/J-Board";
|
||||
Reference in New Issue
Block a user