refactor: Redesign homepage and header with responsive layout and improved styling

This commit is contained in:
wood chen 2025-02-22 01:30:42 +08:00
parent 3bbf87d875
commit ce3baad450
3 changed files with 271 additions and 120 deletions

View File

@ -1,5 +1,5 @@
import Link from "next/link"; 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 { Button } from "@/components/ui/button";
import { import {
@ -25,20 +25,29 @@ export default function HomePage() {
<div className="flex min-h-screen flex-col"> <div className="flex min-h-screen flex-col">
<Header /> <Header />
<main className="flex-1"> <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> <Container>
<div className="flex flex-col items-center justify-center space-y-8 text-center"> <div className="relative 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"> <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 Q58 Connect
</TypographyH1> </h1>
<TypographyLead className="max-w-[600px]"> <div className="mx-auto max-w-[800px] px-4">
使 Q58 <p className="text-base text-gray-500 dark:text-gray-400 sm:text-lg md:text-xl">
</TypographyLead> OAuth 2.0 Q58
</p>
</div>
</div>
<div className="flex gap-4"> <div className="flex gap-4">
<Link href="/sign-in"> <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> </Button>
</Link> </Link>
</div> </div>
@ -46,18 +55,20 @@ export default function HomePage() {
</Container> </Container>
</Section> </Section>
<Section> {/* Features Section */}
<Section className="bg-white py-24 dark:bg-gray-900">
<Container> <Container>
<div className="grid gap-8 md:grid-cols-3"> <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> <CardHeader>
<CardTitle></CardTitle> <Code2 className="h-10 w-10 text-primary" />
<CardDescription> <CardTitle className="text-xl"></CardTitle>
<CardDescription className="text-base">
Q58 Q58
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<ul className="space-y-2"> <ul className="space-y-4 text-sm">
<li className="flex items-center gap-2"> <li className="flex items-center gap-2">
<CheckCircle2 className="h-5 w-5 text-green-500" /> <CheckCircle2 className="h-5 w-5 text-green-500" />
<span> OAuth 2.0 </span> <span> OAuth 2.0 </span>
@ -74,15 +85,16 @@ export default function HomePage() {
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card className="border-2 bg-white/50 transition-colors hover:border-primary/50 dark:bg-gray-800/50">
<CardHeader> <CardHeader>
<CardTitle></CardTitle> <Lock className="h-10 w-10 text-primary" />
<CardDescription> <CardTitle className="text-xl"></CardTitle>
<CardDescription className="text-base">
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<ul className="space-y-2"> <ul className="space-y-4 text-sm">
<li className="flex items-center gap-2"> <li className="flex items-center gap-2">
<CheckCircle2 className="h-5 w-5 text-green-500" /> <CheckCircle2 className="h-5 w-5 text-green-500" />
<span>HTTPS </span> <span>HTTPS </span>
@ -99,15 +111,16 @@ export default function HomePage() {
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card className="border-2 bg-white/50 transition-colors hover:border-primary/50 dark:bg-gray-800/50">
<CardHeader> <CardHeader>
<CardTitle></CardTitle> <Users className="h-10 w-10 text-primary" />
<CardDescription> <CardTitle className="text-xl"></CardTitle>
<CardDescription className="text-base">
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<ul className="space-y-2"> <ul className="space-y-4 text-sm">
<li className="flex items-center gap-2"> <li className="flex items-center gap-2">
<CheckCircle2 className="h-5 w-5 text-green-500" /> <CheckCircle2 className="h-5 w-5 text-green-500" />
<span></span> <span></span>
@ -127,16 +140,18 @@ export default function HomePage() {
</Container> </Container>
</Section> </Section>
<Section> {/* Documentation Section */}
<Section className="border-t bg-gray-50 py-24 dark:bg-gray-800">
<Container> <Container>
<Card> <div className="mx-auto max-w-4xl">
<CardHeader> <Card className="overflow-hidden border-2 p-6">
<CardTitle></CardTitle> <CardHeader className="bg-white dark:bg-gray-900">
<CardDescription> <CardTitle className="text-2xl"></CardTitle>
<CardDescription className="text-base">
Q58 Connect Q58 Connect
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent className="bg-white p-0 dark:bg-gray-900">
<Tabs defaultValue="auth" className="w-full"> <Tabs defaultValue="auth" className="w-full">
<TabsList className="grid w-full grid-cols-3"> <TabsList className="grid w-full grid-cols-3">
<TabsTrigger value="auth"></TabsTrigger> <TabsTrigger value="auth"></TabsTrigger>
@ -232,19 +247,23 @@ const { access_token, expires_in } = await response.json();`}
</Tabs> </Tabs>
</CardContent> </CardContent>
</Card> </Card>
</div>
</Container> </Container>
</Section> </Section>
<Section> {/* CTA Section */}
<Section className="bg-white py-24 dark:bg-gray-900">
<Container> <Container>
<div className="text-center"> <div className="text-center">
<TypographyH2></TypographyH2> <h2 className="text-3xl font-bold"></h2>
<TypographyMuted className="mt-2"> <p className="mt-2 text-gray-500 dark:text-gray-400">
使 Q58 Connect 使 Q58 Connect
</TypographyMuted> </p>
<div className="mt-4"> <div className="mt-8">
<Link href="/sign-in"> <Link href="/sign-in">
<Button size="lg"></Button> <Button size="lg" className="min-w-[200px]">
</Button>
</Link> </Link>
</div> </div>
</div> </div>
@ -252,9 +271,9 @@ const { access_token, expires_in } = await response.json();`}
</Section> </Section>
</main> </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> <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{" "} © 2024{" "}
<a <a
href="https://q58.club" href="https://q58.club"

View File

@ -3,7 +3,7 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import Link from "next/link"; import Link from "next/link";
import { usePathname, useRouter } from "next/navigation"; 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 { signOut } from "next-auth/react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
@ -38,7 +38,7 @@ export function HeaderClient({ initialUser }: HeaderClientProps) {
if (!user) return null; if (!user) return null;
return ( return (
<div className="ml-8 flex items-center space-x-1"> <div className="ml-8 hidden items-center space-x-1 md:flex">
<Link <Link
href="/dashboard" href="/dashboard"
className={cn( className={cn(
@ -155,12 +155,140 @@ 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 ( return (
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
{renderNavLinks()} {renderNavLinks()}
<ThemeToggle /> <ThemeToggle />
{user ? ( {user ? (
<div className="flex items-center gap-3"> <>
<div className="hidden items-center gap-3 md:flex">
<Avatar className="h-8 w-8"> <Avatar className="h-8 w-8">
<AvatarImage src={user.avatarUrl || undefined} /> <AvatarImage src={user.avatarUrl || undefined} />
<AvatarFallback> <AvatarFallback>
@ -176,6 +304,8 @@ export function HeaderClient({ initialUser }: HeaderClientProps) {
退 退
</Button> </Button>
</div> </div>
{renderMobileMenu()}
</>
) : ( ) : (
<Button <Button
variant="outline" variant="outline"

View File

@ -1,6 +1,7 @@
import Link from "next/link"; import Link from "next/link";
import { getCurrentUser } from "@/lib/session"; import { getCurrentUser } from "@/lib/session";
import DynamicLogo from "@/components/dynamic-logo";
import { HeaderClient } from "@/components/layout/header-client"; import { HeaderClient } from "@/components/layout/header-client";
export async function Header() { export async function Header() {
@ -12,7 +13,8 @@ export async function Header() {
<div className="flex h-14 items-center justify-between"> <div className="flex h-14 items-center justify-between">
<div className="flex items-center"> <div className="flex items-center">
<Link href="/" className="flex items-center space-x-3"> <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 Q58 Connect
</h1> </h1>
</Link> </Link>