Navbar Link Activation

This commit is contained in:
Vico 2025-03-26 12:10:46 +01:00
parent e2d5447a3c
commit bc80fe14bf
7 changed files with 308 additions and 55 deletions

View File

@ -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>
);

View File

@ -1,7 +0,0 @@
import React from "react";
function MePage() {
return <div>MePage</div>;
}
export default MePage;

View File

@ -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" />

View 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>
)
}

View 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

View File

@ -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>
);

View File

@ -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 ",