Navbar Link Activation
This commit is contained in:
parent
e2d5447a3c
commit
bc80fe14bf
@ -1,39 +1,10 @@
|
||||
import React from "react";
|
||||
import { Trophy, Brain, Star } from "lucide-react";
|
||||
import Navbar from "@/components/navbar";
|
||||
|
||||
function Layout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="relative flex min-h-screen flex-col items-center justify-center overflow-hidden bg-gradient-to-br from-indigo-900 via-purple-900 to-indigo-800">
|
||||
<Navbar />
|
||||
{/* Animated background elements */}
|
||||
{/* <div className="pointer-events-none absolute inset-0 overflow-hidden">
|
||||
{[...Array(20)].map((_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="absolute animate-pulse rounded-full bg-white/10"
|
||||
style={{
|
||||
width: `${Math.random() * 50 + 10}px`,
|
||||
height: `${Math.random() * 50 + 10}px`,
|
||||
top: `${Math.random() * 100}%`,
|
||||
left: `${Math.random() * 100}%`,
|
||||
animationDuration: `${Math.random() * 8 + 2}s`,
|
||||
opacity: Math.random() * 0.5,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="animate-float-slow absolute top-1/4 left-1/4 text-purple-300/20">
|
||||
<Brain size={80} />
|
||||
</div>
|
||||
<div className="animate-float absolute right-1/4 bottom-1/4 text-indigo-300/20">
|
||||
<Trophy size={60} />
|
||||
</div>
|
||||
<div className="animate-float-slow absolute top-1/3 right-1/3 text-pink-300/20">
|
||||
<Star size={70} />
|
||||
</div> */}
|
||||
{/* Main content */}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
function MePage() {
|
||||
return <div>MePage</div>;
|
||||
}
|
||||
|
||||
export default MePage;
|
||||
@ -29,7 +29,7 @@ export default async function QuizGameStartPage() {
|
||||
<Button
|
||||
size={"xxl"}
|
||||
variant={"party"}
|
||||
className="w-full cursor-pointer border-green-700 bg-gradient-to-r from-green-500 to-emerald-600 text-white shadow-green-600/30 hover:from-green-600 hover:to-emerald-700"
|
||||
className="w-full border-green-700 bg-gradient-to-r from-green-500 to-emerald-600 text-white shadow-green-600/30 hover:from-green-600 hover:to-emerald-700"
|
||||
>
|
||||
<>
|
||||
<Plus className="size-6" />
|
||||
|
||||
270
src/app/(routes)/profile/[id]/page.tsx
Normal file
270
src/app/(routes)/profile/[id]/page.tsx
Normal file
@ -0,0 +1,270 @@
|
||||
import Link from "next/link"
|
||||
import Image from "next/image"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Trophy, Brain, Star, Award, Medal, Clock, ArrowLeft, Settings, BarChart3, Users, Sparkles } from "lucide-react"
|
||||
import { auth } from "@/server/auth";
|
||||
|
||||
export default async function ProfilePage() {
|
||||
const session = await auth();
|
||||
// Mock user data - in a real app this would come from a database
|
||||
const user = {
|
||||
username: "QuizMaster42",
|
||||
level: 24,
|
||||
xp: 7840,
|
||||
xpToNextLevel: 10000,
|
||||
joinDate: "March 2023",
|
||||
gamesPlayed: 187,
|
||||
gamesWon: 112,
|
||||
winRate: 59.9,
|
||||
badges: [
|
||||
{ name: "Quiz Champion", icon: Trophy, color: "text-yellow-400" },
|
||||
{ name: "Knowledge Seeker", icon: Brain, color: "text-blue-400" },
|
||||
{ name: "Fast Thinker", icon: Clock, color: "text-green-400" },
|
||||
{ name: "Team Player", icon: Users, color: "text-purple-400" },
|
||||
],
|
||||
recentGames: [
|
||||
{ id: 1, topic: "Science", position: "1st", score: 950, date: "2 hours ago" },
|
||||
{ id: 2, topic: "Movies", position: "3rd", score: 720, date: "Yesterday" },
|
||||
{ id: 3, topic: "History", position: "1st", score: 880, date: "3 days ago" },
|
||||
],
|
||||
}
|
||||
|
||||
// Calculate XP progress percentage
|
||||
const xpProgress = (user.xp / user.xpToNextLevel) * 100
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col relative overflow-hidden">
|
||||
{/* Header with back button */}
|
||||
<header className="relative z-10 w-full p-4 flex items-center">
|
||||
<Link href="/" className="flex items-center text-indigo-200 hover:text-white transition-colors">
|
||||
<ArrowLeft className="mr-2 h-5 w-5" />
|
||||
<span>Back to Home</span>
|
||||
</Link>
|
||||
<div className="ml-auto">
|
||||
<Button variant="ghost" className="text-indigo-200 hover:text-white hover:bg-white/10">
|
||||
<Settings className="h-5 w-5" />
|
||||
<span className="sr-only">Settings</span>
|
||||
</Button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Main content */}
|
||||
<main className="relative z-10 flex-1 container max-w-4xl mx-auto px-4 py-8">
|
||||
<div className="grid gap-6 md:grid-cols-3">
|
||||
{/* Profile Card */}
|
||||
<div className="md:col-span-1">
|
||||
<div className="bg-white/10 backdrop-blur-md rounded-2xl p-6 shadow-[0_0_15px_rgba(124,58,237,0.5)] border border-white/20 flex flex-col items-center">
|
||||
<div className="relative">
|
||||
<div className="w-32 h-32 rounded-full bg-gradient-to-r from-pink-500 via-purple-500 to-indigo-500 p-1">
|
||||
<div className="w-full h-full rounded-full overflow-hidden bg-indigo-900 flex items-center justify-center">
|
||||
<Image
|
||||
src="/placeholder.svg?height=120&width=120"
|
||||
alt="Profile"
|
||||
width={120}
|
||||
height={120}
|
||||
className="object-cover"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute -bottom-2 -right-2 bg-yellow-400 text-indigo-900 rounded-full w-10 h-10 flex items-center justify-center font-bold border-2 border-indigo-900">
|
||||
{user.level}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1 className="mt-4 text-2xl font-bold text-white">{user.username}</h1>
|
||||
<p className="text-indigo-200 text-sm">Member since {user.joinDate}</p>
|
||||
|
||||
{/* XP Progress */}
|
||||
<div className="w-full mt-6">
|
||||
<div className="flex justify-between text-xs text-indigo-200 mb-1">
|
||||
<span>XP: {user.xp.toLocaleString()}</span>
|
||||
<span>{user.xpToNextLevel.toLocaleString()}</span>
|
||||
</div>
|
||||
<div className="w-full h-3 bg-indigo-900/50 rounded-full overflow-hidden">
|
||||
<div
|
||||
className="h-full bg-gradient-to-r from-pink-500 to-yellow-400 rounded-full"
|
||||
style={{ width: `${xpProgress}%` }}
|
||||
></div>
|
||||
</div>
|
||||
<div className="text-center text-xs text-indigo-200 mt-1">
|
||||
{Math.floor(user.xpToNextLevel - user.xp).toLocaleString()} XP to level {user.level + 1}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Stats */}
|
||||
<div className="grid grid-cols-3 gap-2 w-full mt-6">
|
||||
<div className="bg-white/5 rounded-lg p-2 text-center">
|
||||
<p className="text-2xl font-bold text-white">{user.gamesPlayed}</p>
|
||||
<p className="text-xs text-indigo-200">Games</p>
|
||||
</div>
|
||||
<div className="bg-white/5 rounded-lg p-2 text-center">
|
||||
<p className="text-2xl font-bold text-white">{user.gamesWon}</p>
|
||||
<p className="text-xs text-indigo-200">Wins</p>
|
||||
</div>
|
||||
<div className="bg-white/5 rounded-lg p-2 text-center">
|
||||
<p className="text-2xl font-bold text-white">{user.winRate}%</p>
|
||||
<p className="text-xs text-indigo-200">Win Rate</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button className="mt-6 w-full bg-gradient-to-r from-pink-500 to-purple-600 hover:from-pink-600 hover:to-purple-700 text-white rounded-xl shadow-lg shadow-purple-600/30 border-b-4 border-purple-700 hover:translate-y-1 hover:border-b-2 transition-all duration-200">
|
||||
Edit Profile
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Achievements and Recent Games */}
|
||||
<div className="md:col-span-2 space-y-6">
|
||||
{/* Achievements */}
|
||||
<div className="bg-white/10 backdrop-blur-md rounded-2xl p-6 shadow-[0_0_15px_rgba(124,58,237,0.5)] border border-white/20">
|
||||
<div className="flex items-center mb-4">
|
||||
<Award className="text-yellow-400 mr-2 h-6 w-6" />
|
||||
<h2 className="text-xl font-bold text-white">Achievements</h2>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{user.badges.map((badge, index) => (
|
||||
<div key={index} className="flex items-center bg-white/5 rounded-xl p-3 border border-white/10">
|
||||
<div className={`${badge.color} mr-3`}>
|
||||
<badge.icon size={24} />
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-medium text-white">{badge.name}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<div className="flex items-center bg-white/5 rounded-xl p-3 border border-white/10 border-dashed">
|
||||
<div className="text-indigo-300/50 mr-3">
|
||||
<Medal size={24} />
|
||||
</div>
|
||||
<div>
|
||||
<p className="font-medium text-indigo-300/50">Locked Achievement</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Stats Overview */}
|
||||
<div className="bg-white/10 backdrop-blur-md rounded-2xl p-6 shadow-[0_0_15px_rgba(124,58,237,0.5)] border border-white/20">
|
||||
<div className="flex items-center mb-4">
|
||||
<BarChart3 className="text-blue-400 mr-2 h-6 w-6" />
|
||||
<h2 className="text-xl font-bold text-white">Stats Overview</h2>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="bg-white/5 rounded-xl p-4 border border-white/10">
|
||||
<h3 className="text-indigo-200 text-sm mb-2">Top Categories</h3>
|
||||
<div className="space-y-2">
|
||||
<div>
|
||||
<div className="flex justify-between text-xs mb-1">
|
||||
<span className="text-white">Science</span>
|
||||
<span className="text-indigo-200">92%</span>
|
||||
</div>
|
||||
<div className="w-full h-2 bg-indigo-900/50 rounded-full overflow-hidden">
|
||||
<div className="h-full bg-green-500 rounded-full" style={{ width: "92%" }}></div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex justify-between text-xs mb-1">
|
||||
<span className="text-white">History</span>
|
||||
<span className="text-indigo-200">78%</span>
|
||||
</div>
|
||||
<div className="w-full h-2 bg-indigo-900/50 rounded-full overflow-hidden">
|
||||
<div className="h-full bg-blue-500 rounded-full" style={{ width: "78%" }}></div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex justify-between text-xs mb-1">
|
||||
<span className="text-white">Movies</span>
|
||||
<span className="text-indigo-200">65%</span>
|
||||
</div>
|
||||
<div className="w-full h-2 bg-indigo-900/50 rounded-full overflow-hidden">
|
||||
<div className="h-full bg-purple-500 rounded-full" style={{ width: "65%" }}></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-white/5 rounded-xl p-4 border border-white/10">
|
||||
<h3 className="text-indigo-200 text-sm mb-2">Response Time</h3>
|
||||
<div className="flex items-center justify-center h-24">
|
||||
<div className="text-center">
|
||||
<p className="text-3xl font-bold text-white">3.2s</p>
|
||||
<p className="text-xs text-indigo-200">Average response time</p>
|
||||
<p className="text-xs text-green-400 mt-1">Faster than 75% of players</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Recent Games */}
|
||||
<div className="bg-white/10 backdrop-blur-md rounded-2xl p-6 shadow-[0_0_15px_rgba(124,58,237,0.5)] border border-white/20">
|
||||
<div className="flex items-center mb-4">
|
||||
<Clock className="text-green-400 mr-2 h-6 w-6" />
|
||||
<h2 className="text-xl font-bold text-white">Recent Games</h2>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
{user.recentGames.map((game) => (
|
||||
<div key={game.id} className="bg-white/5 rounded-xl p-4 border border-white/10 flex items-center">
|
||||
<div className="flex-shrink-0 w-12 h-12 rounded-full bg-indigo-800/50 flex items-center justify-center mr-4">
|
||||
{game.position === "1st" ? (
|
||||
<Trophy className="text-yellow-400 h-6 w-6" />
|
||||
) : game.position === "2nd" ? (
|
||||
<Medal className="text-gray-300 h-6 w-6" />
|
||||
) : (
|
||||
<Medal className="text-amber-700 h-6 w-6" />
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="flex justify-between">
|
||||
<h3 className="font-medium text-white">{game.topic}</h3>
|
||||
<span className="text-sm text-indigo-200">{game.date}</span>
|
||||
</div>
|
||||
<div className="flex justify-between mt-1">
|
||||
<span className="text-sm text-indigo-300">
|
||||
Position: <span className="text-white">{game.position}</span>
|
||||
</span>
|
||||
<span className="text-sm text-indigo-300">
|
||||
Score: <span className="text-white">{game.score}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<Button variant="ghost" className="w-full text-indigo-200 hover:text-white hover:bg-white/10 mt-2">
|
||||
View All Games
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* Footer */}
|
||||
<footer className="relative z-10 w-full py-4 border-t border-white/10">
|
||||
<div className="container mx-auto px-4 flex justify-between items-center">
|
||||
<div className="flex items-center">
|
||||
<Sparkles className="text-yellow-400 h-5 w-5 mr-2" />
|
||||
<span className="text-indigo-200 text-sm">QUIZ MASTER</span>
|
||||
</div>
|
||||
<div className="flex space-x-4">
|
||||
<Link href="#" className="text-xs text-indigo-200 hover:text-white transition-colors">
|
||||
Help
|
||||
</Link>
|
||||
<Link href="#" className="text-xs text-indigo-200 hover:text-white transition-colors">
|
||||
Privacy
|
||||
</Link>
|
||||
<Link href="#" className="text-xs text-indigo-200 hover:text-white transition-colors">
|
||||
Terms
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
28
src/components/navbar-links.tsx
Normal file
28
src/components/navbar-links.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
"use client";
|
||||
|
||||
import React from 'react'
|
||||
import { Button } from './ui/button'
|
||||
import Link from 'next/link'
|
||||
import { Home } from 'lucide-react'
|
||||
import { usePathname } from 'next/navigation';
|
||||
|
||||
function NavbarLinks() {
|
||||
const pathname = usePathname()
|
||||
return (
|
||||
<><Button asChild {...(pathname === '/' ? { variant: 'rounded' } : { variant: 'ghost' })}>
|
||||
<Link href="/">
|
||||
<Home className="size-4" />
|
||||
<span>Home</span>
|
||||
</Link>
|
||||
</Button>
|
||||
<Button asChild {...(pathname === '/lobby' ? { variant: 'rounded' } : { variant: 'ghost' })}>
|
||||
<Link href="/lobby">Lobbies</Link>
|
||||
</Button>
|
||||
<Button asChild {...(pathname === '/games' ? { variant: 'rounded' } : { variant: 'ghost' })}>
|
||||
<Link href="/games">Games</Link>
|
||||
</Button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default NavbarLinks
|
||||
@ -4,36 +4,25 @@ import Avatar from "./avatar";
|
||||
import { Button } from "./ui/button";
|
||||
import Link from "next/link";
|
||||
import { Home } from "lucide-react";
|
||||
import NavbarLinks from "./navbar-links";
|
||||
|
||||
async function Navbar() {
|
||||
const session = await auth();
|
||||
|
||||
return (
|
||||
<nav className="absolute top-0 left-0 flex h-max w-full items-center justify-center p-4">
|
||||
<div className="bg-background flex w-max items-center gap-2 rounded-full border-2">
|
||||
<NavbarLinks />
|
||||
{/* Login Button or Profile Avatar */}
|
||||
{session ? (
|
||||
<Link href="/me">
|
||||
<Link href={`/profile/${session.user.id}`}>
|
||||
<Avatar src={session.user.image!} fb={session.user.name!} />
|
||||
</Link>
|
||||
) : (
|
||||
<Button asChild>
|
||||
<Button asChild variant={"rounded"} className="bg-red-800">
|
||||
<Link href="/api/auth/signin">Sign In</Link>
|
||||
</Button>
|
||||
)}
|
||||
<Button asChild variant="ghost">
|
||||
<Link href="/lobby">Lobbies</Link>
|
||||
</Button>
|
||||
<Button asChild variant="ghost">
|
||||
<Link href="/games">Games</Link>
|
||||
</Button>
|
||||
<Button asChild variant="ghost">
|
||||
<Link href="/me/friend">Friends</Link>
|
||||
</Button>
|
||||
<Button asChild className="rounded-full">
|
||||
<Link href="/">
|
||||
<Home className="size-4" />
|
||||
<span>Home</span>
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
|
||||
@ -11,6 +11,8 @@ const buttonVariants = cva(
|
||||
variant: {
|
||||
default:
|
||||
"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
||||
rounded:
|
||||
"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90 rounded-full",
|
||||
destructive:
|
||||
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
||||
outline:
|
||||
@ -18,7 +20,7 @@ const buttonVariants = cva(
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
||||
ghost:
|
||||
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
||||
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50 rounded-full",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
party:
|
||||
"bg-primary text-primary-foreground rounded-xl border-b-4 shadow-lg text-lg font-bold hover:translate-y-1 hover:border-b-2 ",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user