mirror of
https://github.com/woodchen-ink/Q58Connect.git
synced 2025-07-18 05:51:55 +08:00
refactor: Redesign homepage and header with responsive layout and improved styling
This commit is contained in:
parent
3bbf87d875
commit
ce3baad450
@ -1,5 +1,5 @@
|
||||
import Link from "next/link";
|
||||
import { ArrowRight, CheckCircle2 } from "lucide-react";
|
||||
import { ArrowRight, CheckCircle2, Code2, Lock, Users } from "lucide-react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
@ -25,20 +25,29 @@ export default function HomePage() {
|
||||
<div className="flex min-h-screen flex-col">
|
||||
<Header />
|
||||
<main className="flex-1">
|
||||
<Section className="pb-0">
|
||||
{/* Hero Section */}
|
||||
<Section className="relative overflow-hidden bg-gradient-to-b from-white to-gray-50 pb-16 pt-24 dark:from-gray-900 dark:to-gray-800">
|
||||
<div className="absolute inset-0">
|
||||
<div className="bg-grid-black/[0.02] dark:bg-grid-white/[0.02] absolute inset-0" />
|
||||
</div>
|
||||
<Container>
|
||||
<div className="flex flex-col items-center justify-center space-y-8 text-center">
|
||||
<TypographyH1 className="text-4xl font-bold tracking-tighter sm:text-5xl md:text-6xl lg:text-7xl">
|
||||
Q58 Connect
|
||||
</TypographyH1>
|
||||
<TypographyLead className="max-w-[600px]">
|
||||
使用 Q58 论坛账号,一键登录您的应用
|
||||
</TypographyLead>
|
||||
<div className="relative flex flex-col items-center justify-center space-y-8 text-center">
|
||||
<div className="space-y-6">
|
||||
<h1 className="text-4xl font-bold tracking-tighter text-gray-900 dark:text-white sm:text-5xl md:text-6xl lg:text-7xl">
|
||||
Q58 Connect
|
||||
</h1>
|
||||
<div className="mx-auto max-w-[800px] px-4">
|
||||
<p className="text-base text-gray-500 dark:text-gray-400 sm:text-lg md:text-xl">
|
||||
基于 OAuth 2.0 协议,为您的应用快速接入 Q58
|
||||
论坛统一身份认证,实现一键登录
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-4">
|
||||
<Link href="/sign-in">
|
||||
<Button size="lg">
|
||||
<Button size="lg" className="gap-2">
|
||||
开始使用
|
||||
<ArrowRight className="ml-2 h-5 w-5" />
|
||||
<ArrowRight className="h-5 w-5" />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
@ -46,18 +55,20 @@ export default function HomePage() {
|
||||
</Container>
|
||||
</Section>
|
||||
|
||||
<Section>
|
||||
{/* Features Section */}
|
||||
<Section className="bg-white py-24 dark:bg-gray-900">
|
||||
<Container>
|
||||
<div className="grid gap-8 md:grid-cols-3">
|
||||
<Card>
|
||||
<Card className="border-2 bg-white/50 transition-colors hover:border-primary/50 dark:bg-gray-800/50">
|
||||
<CardHeader>
|
||||
<CardTitle>简单集成</CardTitle>
|
||||
<CardDescription>
|
||||
<Code2 className="h-10 w-10 text-primary" />
|
||||
<CardTitle className="text-xl">简单集成</CardTitle>
|
||||
<CardDescription className="text-base">
|
||||
只需几行代码,即可为您的应用添加 Q58 论坛账号登录功能
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2">
|
||||
<ul className="space-y-4 text-sm">
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle2 className="h-5 w-5 text-green-500" />
|
||||
<span>标准 OAuth 2.0 协议</span>
|
||||
@ -74,15 +85,16 @@ export default function HomePage() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<Card className="border-2 bg-white/50 transition-colors hover:border-primary/50 dark:bg-gray-800/50">
|
||||
<CardHeader>
|
||||
<CardTitle>安全可靠</CardTitle>
|
||||
<CardDescription>
|
||||
<Lock className="h-10 w-10 text-primary" />
|
||||
<CardTitle className="text-xl">安全可靠</CardTitle>
|
||||
<CardDescription className="text-base">
|
||||
采用业界最佳实践,确保您的应用和用户数据安全
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2">
|
||||
<ul className="space-y-4 text-sm">
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle2 className="h-5 w-5 text-green-500" />
|
||||
<span>HTTPS 加密传输</span>
|
||||
@ -99,15 +111,16 @@ export default function HomePage() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<Card className="border-2 bg-white/50 transition-colors hover:border-primary/50 dark:bg-gray-800/50">
|
||||
<CardHeader>
|
||||
<CardTitle>功能丰富</CardTitle>
|
||||
<CardDescription>
|
||||
<Users className="h-10 w-10 text-primary" />
|
||||
<CardTitle className="text-xl">功能丰富</CardTitle>
|
||||
<CardDescription className="text-base">
|
||||
提供完整的用户信息和权限管理功能
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ul className="space-y-2">
|
||||
<ul className="space-y-4 text-sm">
|
||||
<li className="flex items-center gap-2">
|
||||
<CheckCircle2 className="h-5 w-5 text-green-500" />
|
||||
<span>用户基本信息</span>
|
||||
@ -127,34 +140,36 @@ export default function HomePage() {
|
||||
</Container>
|
||||
</Section>
|
||||
|
||||
<Section>
|
||||
{/* Documentation Section */}
|
||||
<Section className="border-t bg-gray-50 py-24 dark:bg-gray-800">
|
||||
<Container>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>快速开始</CardTitle>
|
||||
<CardDescription>
|
||||
按照以下步骤,快速接入 Q58 Connect
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Tabs defaultValue="auth" className="w-full">
|
||||
<TabsList className="grid w-full grid-cols-3">
|
||||
<TabsTrigger value="auth">发起授权</TabsTrigger>
|
||||
<TabsTrigger value="callback">处理回调</TabsTrigger>
|
||||
<TabsTrigger value="userinfo">获取用户</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="auth" className="mt-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>1. 发起授权请求</CardTitle>
|
||||
<CardDescription>
|
||||
将用户重定向到授权页面
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<pre className="overflow-x-auto rounded-lg bg-gray-100 p-4 dark:bg-gray-800">
|
||||
<code className="text-sm">
|
||||
{`const authUrl = 'https://connect.q58.club/oauth/authorize?' +
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<Card className="overflow-hidden border-2 p-6">
|
||||
<CardHeader className="bg-white dark:bg-gray-900">
|
||||
<CardTitle className="text-2xl">快速开始</CardTitle>
|
||||
<CardDescription className="text-base">
|
||||
按照以下步骤,快速接入 Q58 Connect
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="bg-white p-0 dark:bg-gray-900">
|
||||
<Tabs defaultValue="auth" className="w-full">
|
||||
<TabsList className="grid w-full grid-cols-3">
|
||||
<TabsTrigger value="auth">发起授权</TabsTrigger>
|
||||
<TabsTrigger value="callback">处理回调</TabsTrigger>
|
||||
<TabsTrigger value="userinfo">获取用户</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="auth" className="mt-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>1. 发起授权请求</CardTitle>
|
||||
<CardDescription>
|
||||
将用户重定向到授权页面
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<pre className="overflow-x-auto rounded-lg bg-gray-100 p-4 dark:bg-gray-800">
|
||||
<code className="text-sm">
|
||||
{`const authUrl = 'https://connect.q58.club/oauth/authorize?' +
|
||||
new URLSearchParams({
|
||||
response_type: 'code', // 必填,固定值
|
||||
client_id: 'your_client_id', // 必填,您的应用ID
|
||||
@ -164,23 +179,23 @@ export default function HomePage() {
|
||||
});
|
||||
|
||||
window.location.href = authUrl;`}
|
||||
</code>
|
||||
</pre>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
<TabsContent value="callback" className="mt-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>2. 处理授权回调</CardTitle>
|
||||
<CardDescription>
|
||||
在回调地址处理授权结果
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<pre className="overflow-x-auto rounded-lg bg-gray-100 p-4 dark:bg-gray-800">
|
||||
<code className="text-sm">
|
||||
{`// 获取访问令牌
|
||||
</code>
|
||||
</pre>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
<TabsContent value="callback" className="mt-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>2. 处理授权回调</CardTitle>
|
||||
<CardDescription>
|
||||
在回调地址处理授权结果
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<pre className="overflow-x-auto rounded-lg bg-gray-100 p-4 dark:bg-gray-800">
|
||||
<code className="text-sm">
|
||||
{`// 获取访问令牌
|
||||
const response = await fetch('https://connect.q58.club/api/oauth/access_token', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@ -193,23 +208,23 @@ const response = await fetch('https://connect.q58.club/api/oauth/access_token',
|
||||
});
|
||||
|
||||
const { access_token, expires_in } = await response.json();`}
|
||||
</code>
|
||||
</pre>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
<TabsContent value="userinfo" className="mt-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>3. 获取用户信息</CardTitle>
|
||||
<CardDescription>
|
||||
使用访问令牌获取用户数据
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<pre className="overflow-x-auto rounded-lg bg-gray-100 p-4 dark:bg-gray-800">
|
||||
<code className="text-sm">
|
||||
{`const userInfo = await fetch('https://connect.q58.club/api/oauth/user', {
|
||||
</code>
|
||||
</pre>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
<TabsContent value="userinfo" className="mt-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>3. 获取用户信息</CardTitle>
|
||||
<CardDescription>
|
||||
使用访问令牌获取用户数据
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<pre className="overflow-x-auto rounded-lg bg-gray-100 p-4 dark:bg-gray-800">
|
||||
<code className="text-sm">
|
||||
{`const userInfo = await fetch('https://connect.q58.club/api/oauth/user', {
|
||||
headers: {
|
||||
'Authorization': \`Bearer \${access_token}\`
|
||||
}
|
||||
@ -224,27 +239,31 @@ const { access_token, expires_in } = await response.json();`}
|
||||
"avatar_url": "https://...",
|
||||
"groups": ["group1", "group2"]
|
||||
}`}
|
||||
</code>
|
||||
</pre>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</code>
|
||||
</pre>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</Container>
|
||||
</Section>
|
||||
|
||||
<Section>
|
||||
{/* CTA Section */}
|
||||
<Section className="bg-white py-24 dark:bg-gray-900">
|
||||
<Container>
|
||||
<div className="text-center">
|
||||
<TypographyH2>准备好了吗?</TypographyH2>
|
||||
<TypographyMuted className="mt-2">
|
||||
<h2 className="text-3xl font-bold">准备好了吗?</h2>
|
||||
<p className="mt-2 text-gray-500 dark:text-gray-400">
|
||||
创建一个应用,开始使用 Q58 Connect
|
||||
</TypographyMuted>
|
||||
<div className="mt-4">
|
||||
</p>
|
||||
<div className="mt-8">
|
||||
<Link href="/sign-in">
|
||||
<Button size="lg">立即开始</Button>
|
||||
<Button size="lg" className="min-w-[200px]">
|
||||
立即开始
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
@ -252,9 +271,9 @@ const { access_token, expires_in } = await response.json();`}
|
||||
</Section>
|
||||
</main>
|
||||
|
||||
<footer className="border-t bg-white py-8 dark:bg-gray-800">
|
||||
<footer className="border-t bg-white py-12 dark:bg-gray-900">
|
||||
<Container>
|
||||
<div className="text-center text-gray-600 dark:text-gray-400">
|
||||
<div className="text-center text-sm text-gray-500 dark:text-gray-400">
|
||||
© 2024{" "}
|
||||
<a
|
||||
href="https://q58.club"
|
||||
|
@ -3,7 +3,7 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import { ChevronDown, User } from "lucide-react";
|
||||
import { ChevronDown, Menu, User } from "lucide-react";
|
||||
import { signOut } from "next-auth/react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
@ -38,7 +38,7 @@ export function HeaderClient({ initialUser }: HeaderClientProps) {
|
||||
if (!user) return null;
|
||||
|
||||
return (
|
||||
<div className="ml-8 flex items-center space-x-1">
|
||||
<div className="ml-8 hidden items-center space-x-1 md:flex">
|
||||
<Link
|
||||
href="/dashboard"
|
||||
className={cn(
|
||||
@ -155,27 +155,157 @@ export function HeaderClient({ initialUser }: HeaderClientProps) {
|
||||
);
|
||||
};
|
||||
|
||||
// 移动端导航菜单
|
||||
const renderMobileMenu = () => {
|
||||
if (!user) return null;
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon" className="md:hidden">
|
||||
<Menu className="h-5 w-5" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-64">
|
||||
<div className="flex items-center gap-3 border-b px-2 py-3">
|
||||
<Avatar className="h-8 w-8">
|
||||
<AvatarImage src={user.avatarUrl || undefined} />
|
||||
<AvatarFallback>
|
||||
{user.name?.charAt(0) || user.username?.charAt(0)}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-sm font-medium">
|
||||
{user.name || user.username}
|
||||
</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{user.email}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link
|
||||
href="/dashboard"
|
||||
className={cn("w-full", pathname === "/dashboard" && "bg-accent")}
|
||||
>
|
||||
控制台
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link
|
||||
href="/dashboard/clients"
|
||||
className={cn(
|
||||
"w-full",
|
||||
pathname.startsWith("/dashboard/clients") && "bg-accent",
|
||||
)}
|
||||
>
|
||||
应用管理
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link
|
||||
href="/dashboard/settings"
|
||||
className={cn(
|
||||
"w-full",
|
||||
pathname === "/dashboard/settings" && "bg-accent",
|
||||
)}
|
||||
>
|
||||
设置
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
{user.role === "ADMIN" && (
|
||||
<>
|
||||
<div className="my-1 h-px bg-border" />
|
||||
<DropdownMenuItem asChild>
|
||||
<Link
|
||||
href="/admin"
|
||||
className={cn("w-full", pathname === "/admin" && "bg-accent")}
|
||||
>
|
||||
管理后台
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link
|
||||
href="/admin/users"
|
||||
className={cn(
|
||||
"w-full",
|
||||
pathname === "/admin/users" && "bg-accent",
|
||||
)}
|
||||
>
|
||||
用户列表
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link
|
||||
href="/admin/clients"
|
||||
className={cn(
|
||||
"w-full",
|
||||
pathname === "/admin/clients" && "bg-accent",
|
||||
)}
|
||||
>
|
||||
应用管理
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link
|
||||
href="/admin/authorizations"
|
||||
className={cn(
|
||||
"w-full",
|
||||
pathname === "/admin/authorizations" && "bg-accent",
|
||||
)}
|
||||
>
|
||||
授权管理
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link
|
||||
href="/admin/logs"
|
||||
className={cn(
|
||||
"w-full",
|
||||
pathname === "/admin/logs" && "bg-accent",
|
||||
)}
|
||||
>
|
||||
系统日志
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
</>
|
||||
)}
|
||||
<div className="my-1 h-px bg-border" />
|
||||
<DropdownMenuItem
|
||||
onClick={handleSignOut}
|
||||
className="text-red-600 focus:bg-red-50 focus:text-red-600 dark:focus:bg-red-950"
|
||||
>
|
||||
退出登录
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex items-center space-x-4">
|
||||
{renderNavLinks()}
|
||||
<ThemeToggle />
|
||||
{user ? (
|
||||
<div className="flex items-center gap-3">
|
||||
<Avatar className="h-8 w-8">
|
||||
<AvatarImage src={user.avatarUrl || undefined} />
|
||||
<AvatarFallback>
|
||||
{user.name?.charAt(0) || user.username?.charAt(0)}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={handleSignOut}
|
||||
className="text-muted-foreground hover:text-red-600"
|
||||
>
|
||||
退出
|
||||
</Button>
|
||||
</div>
|
||||
<>
|
||||
<div className="hidden items-center gap-3 md:flex">
|
||||
<Avatar className="h-8 w-8">
|
||||
<AvatarImage src={user.avatarUrl || undefined} />
|
||||
<AvatarFallback>
|
||||
{user.name?.charAt(0) || user.username?.charAt(0)}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={handleSignOut}
|
||||
className="text-muted-foreground hover:text-red-600"
|
||||
>
|
||||
退出
|
||||
</Button>
|
||||
</div>
|
||||
{renderMobileMenu()}
|
||||
</>
|
||||
) : (
|
||||
<Button
|
||||
variant="outline"
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Link from "next/link";
|
||||
|
||||
import { getCurrentUser } from "@/lib/session";
|
||||
import DynamicLogo from "@/components/dynamic-logo";
|
||||
import { HeaderClient } from "@/components/layout/header-client";
|
||||
|
||||
export async function Header() {
|
||||
@ -12,7 +13,8 @@ export async function Header() {
|
||||
<div className="flex h-14 items-center justify-between">
|
||||
<div className="flex items-center">
|
||||
<Link href="/" className="flex items-center space-x-3">
|
||||
<h1 className="text-2xl font-bold text-[#25263A] dark:text-white">
|
||||
<DynamicLogo />
|
||||
<h1 className="hidden text-2xl font-bold text-[#25263A] dark:text-white sm:block">
|
||||
Q58 Connect
|
||||
</h1>
|
||||
</Link>
|
||||
|
Loading…
x
Reference in New Issue
Block a user