Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions components/PremiumButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import { User } from '@supabase/supabase-js';
interface PremiumButtonProps {
user: User;
className?: string;
compact?: boolean;
}

export default function PremiumButton({ user, className = '' }: PremiumButtonProps) {
export default function PremiumButton({ user, className = '', compact = false }: PremiumButtonProps) {
const [isPremium, setIsPremium] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const supabase = createClient();
Expand Down Expand Up @@ -66,7 +67,7 @@ export default function PremiumButton({ user, className = '' }: PremiumButtonPro
{isPremium ? (
<button
onClick={handlePremiumClick}
className={`group relative inline-flex items-center px-3 py-1.5 text-sm font-semibold rounded-lg transition-all duration-300 bg-gradient-to-r from-yellow-400 via-yellow-500 to-orange-500 text-white shadow-lg hover:shadow-xl hover:scale-105 transform overflow-hidden ${className}`}
className={`group relative inline-flex items-center px-3 py-1.5 text-sm font-semibold rounded-lg transition-all duration-300 bg-gradient-to-r from-yellow-400 via-yellow-500 to-orange-500 text-white shadow-lg hover:shadow-xl hover:scale-105 transform overflow-hidden ${compact ? 'px-2.5 py-1 text-xs' : ''} ${className}`}
>
{/* Animated background effect */}
<div className="absolute inset-0 bg-gradient-to-r from-yellow-300 via-yellow-400 to-orange-400 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
Expand All @@ -78,25 +79,27 @@ export default function PremiumButton({ user, className = '' }: PremiumButtonPro
<div className="absolute -bottom-1 -left-2 w-1.5 h-1.5 bg-white rounded-full opacity-0 group-hover:opacity-100 group-hover:animate-ping" style={{ animationDelay: '0.4s' }}></div>
</div>

<Crown className="mr-1.5 h-4 w-4 relative z-10" />
<Crown className={`relative z-10 ${compact ? 'h-3.5 w-3.5 mr-1' : 'mr-1.5 h-4 w-4'}`} />
<span className="relative z-10">Premium</span>
</button>
) : (
<Link href="/premium">
<button
className={`group relative inline-flex items-center px-3 py-1.5 text-sm font-semibold rounded-lg transition-all duration-300 bg-gradient-to-r from-blue-500 via-purple-600 to-indigo-600 text-white hover:from-blue-600 hover:via-purple-700 hover:to-indigo-700 shadow-lg hover:shadow-xl hover:scale-105 transform overflow-hidden ${className}`}
className={`group relative inline-flex items-center px-3 py-1.5 text-sm font-semibold rounded-lg transition-all duration-300 bg-gradient-to-r from-blue-500 via-purple-600 to-indigo-600 text-white hover:from-blue-600 hover:via-purple-700 hover:to-indigo-700 shadow-lg hover:shadow-xl hover:scale-105 transform overflow-hidden ${compact ? 'px-2.5 py-1 text-xs' : ''} ${className}`}
>
{/* Animated background effect */}
<div className="absolute inset-0 bg-gradient-to-r from-blue-400 via-purple-500 to-indigo-500 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>

{/* Glow effect */}
<div className="absolute inset-0 bg-gradient-to-r from-blue-400 via-purple-500 to-indigo-500 blur-lg opacity-0 group-hover:opacity-50 transition-opacity duration-300"></div>

<Star className="mr-1.5 h-4 w-4 relative z-10" />
<Star className={`relative z-10 ${compact ? 'h-3.5 w-3.5 mr-1' : 'mr-1.5 h-4 w-4'}`} />
<span className="relative z-10">Premium</span>

{/* Arrow indicator */}
<Sparkles className="ml-1 h-3 w-3 relative z-10 opacity-0 group-hover:opacity-100 group-hover:translate-x-1 transition-all duration-300" />
{!compact && (
<Sparkles className="ml-1 h-3 w-3 relative z-10 opacity-0 group-hover:opacity-100 group-hover:translate-x-1 transition-all duration-300" />
)}
</button>
</Link>
)}
Expand Down
263 changes: 144 additions & 119 deletions components/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,137 +65,162 @@ export default function Header() {
]

return (
<header className="fixed top-0 z-50 w-full border-b bg-background/80 backdrop-blur-xl supports-[backdrop-filter]:bg-background/60 shadow-sm">
<div className="container flex h-14 sm:h-16 items-center justify-between px-3 sm:px-4">
{/* logo section - left */}
<div className="flex items-center flex-shrink-0">
<Link href="/" className="hover:scale-105 transition-transform duration-200">
<CodeuniaLogo size="md" noLink={true} showText={true} instanceId="header" />
</Link>
</div>

{/* desktop nav - center */}
<nav className="hidden md:flex items-center space-x-8 mx-auto">
{navItems.map((item) => (
<Link
key={item.href}
href={item.href}
className={`text-sm font-medium transition-colors relative group ${
isActive(item.href)
? "text-primary"
: "text-foreground hover:text-primary"
}`}
>
{item.label}
<span
className={`absolute -bottom-1 left-0 h-0.5 bg-primary transition-all duration-300 ${
<>
<header className="fixed top-0 z-50 w-full border-b bg-background/80 backdrop-blur-xl supports-[backdrop-filter]:bg-background/60 shadow-sm">
<div className="container flex h-14 sm:h-16 items-center justify-between px-2 sm:px-4">
{/* logo section - left */}
<div className="flex items-center flex-shrink-0">
<Link href="/" className="hover:scale-105 transition-transform duration-200">
<CodeuniaLogo size="md" noLink={true} showText={true} instanceId="header" />
</Link>
</div>

{/* desktop nav - center */}
<nav className="hidden md:flex items-center space-x-8 mx-auto">
{navItems.map((item) => (
<Link
key={item.href}
href={item.href}
className={`text-sm font-medium transition-colors relative group ${
isActive(item.href)
? "w-full"
: "w-0 group-hover:w-full"
? "text-primary"
: "text-foreground hover:text-primary"
}`}
></span>
</Link>
))}
</nav>

{/* desktop auth & theme - right */}
<div className="hidden md:flex items-center space-x-4 flex-shrink-0">
{/* <ThemeToggle /> */}
{loading ? (
<div className="text-sm text-muted-foreground">Loading...</div>
) : user ? (
<div className="flex items-center space-x-2">
<PremiumButton user={user} />
<UserDisplay userId={user.id} showCodeuniaId={false} />
<UserIcon />
</div>
) : (
<>
<Button variant="ghost" asChild className="hover:scale-105 transition-transform">
<Link href={`/auth/signin?returnUrl=${encodeURIComponent(pathname)}`}>Sign In</Link>
</Button>
<Button asChild className="glow-effect hover:scale-105 transition-all duration-300">
<Link href={`/auth/signup?returnUrl=${encodeURIComponent(pathname)}`}>Sign Up</Link>
</Button>
</>
)}
</div>
>
{item.label}
<span
className={`absolute -bottom-1 left-0 h-0.5 bg-primary transition-all duration-300 ${
isActive(item.href)
? "w-full"
: "w-0 group-hover:w-full"
}`}
></span>
</Link>
))}
</nav>

{/* mobile menu button */}
<div className="flex md:hidden items-center space-x-1">
{/* <ThemeToggle /> */}
{!loading && user && (
<div className="flex items-center space-x-1">
<PremiumButton user={user} />
<UserIcon />
</div>
)}
<Button
variant="ghost"
size="icon"
onClick={() => setIsMenuOpen(!isMenuOpen)}
className={`hover:scale-105 transition-all duration-200 ml-1 ${
isMenuOpen ? 'bg-muted/50' : ''
}`}
>
{isMenuOpen ? <X className="h-4 w-4" /> : <Menu className="h-4 w-4" />}
</Button>
{/* desktop auth & theme - right */}
<div className="hidden md:flex items-center space-x-3 flex-shrink-0">
{/* <ThemeToggle /> */}
{loading ? (
<div className="text-sm text-muted-foreground">Loading...</div>
) : user ? (
<div className="flex items-center space-x-3">
<PremiumButton user={user} />
<UserDisplay userId={user.id} showCodeuniaId={false} />
<UserIcon />
</div>
) : (
<>
<Button variant="ghost" asChild className="hover:scale-105 transition-transform px-3 py-1.5 h-auto text-sm">
<Link href={`/auth/signin?returnUrl=${encodeURIComponent(pathname)}`}>Sign In</Link>
</Button>
<Button asChild className="glow-effect hover:scale-105 transition-all duration-300 px-3 py-1.5 h-auto text-sm">
<Link href={`/auth/signup?returnUrl=${encodeURIComponent(pathname)}`}>Sign Up</Link>
</Button>
</>
)}
</div>

{/* mobile menu button */}
<div className="flex md:hidden items-center space-x-1">
{/* <ThemeToggle /> */}
{!loading && user && (
<div className="flex items-center space-x-1">
<PremiumButton user={user} compact />
<UserIcon />
</div>
)}
<Button
variant="ghost"
size="icon"
onClick={() => setIsMenuOpen(!isMenuOpen)}
className={`hover:scale-105 transition-all duration-200 ml-1 w-8 h-8 ${
isMenuOpen ? 'bg-muted/50' : ''
}`}
>
{isMenuOpen ? <X className="h-4 w-4" /> : <Menu className="h-4 w-4" />}
</Button>
</div>
</div>
</div>
</header>

{/* mobile nav*/}
{/* mobile nav - slide from right (outside header for full page overlay) */}
{isMenuOpen && (
<div className="mobile-menu-container md:hidden border-t bg-background/95 backdrop-blur-xl animate-in slide-in-from-top-2 duration-200">
<nav className="container px-4 py-4 space-y-3">
{/* Navigation Links */}
<div className="space-y-1">
{navItems.map((item) => (
<Link
key={item.href}
href={item.href}
className={`block text-sm font-medium transition-colors py-2.5 px-3 rounded-md relative ${
isActive(item.href)
? "text-primary font-semibold bg-primary/10"
: "text-foreground hover:text-primary hover:bg-muted/50"
}`}
<>
{/* Backdrop overlay */}
<div
className="fixed inset-0 bg-black/50 backdrop-blur-sm z-[60] md:hidden animate-in fade-in duration-200"
onClick={() => setIsMenuOpen(false)}
/>

{/* Side drawer */}
<div className="mobile-menu-container fixed top-0 right-0 bottom-0 w-[280px] max-w-[85vw] bg-background border-l shadow-2xl z-[70] md:hidden animate-in slide-in-from-right duration-300">
<nav className="flex flex-col h-full">
{/* Header with close button */}
<div className="flex items-center justify-between px-4 py-4 border-b">
<span className="text-sm font-semibold">Menu</span>
<Button
variant="ghost"
size="icon"
onClick={() => setIsMenuOpen(false)}
className="h-8 w-8 hover:bg-muted"
>
{item.label}
{isActive(item.href) && (
<span className="absolute left-0 top-1/2 -translate-y-1/2 w-1 h-6 bg-primary rounded-full"></span>
)}
</Link>
))}
</div>

{/* User Actions */}
{!loading && user && (
<div className="pt-3 border-t border-border">
<div className="flex items-center space-x-2 py-2 px-3">
<UserIcon />
<div className="flex-1 min-w-0">
<UserDisplay userId={user.id} showCodeuniaId={false} />
</div>
</div>
<X className="h-4 w-4" />
</Button>
</div>
)}

{/* Auth Buttons for non-authenticated users */}
{!loading && !user && (
<div className="pt-3 border-t border-border">
<div className="flex space-x-2">
<Button variant="ghost" asChild className="flex-1 text-sm">
<Link href={`/auth/signin?returnUrl=${encodeURIComponent(pathname)}`}>Sign In</Link>
</Button>
<Button asChild className="flex-1 glow-effect text-sm">
<Link href={`/auth/signup?returnUrl=${encodeURIComponent(pathname)}`}>Sign Up</Link>
</Button>
{/* Scrollable content */}
<div className="flex-1 overflow-y-auto px-4 py-4">
{/* Navigation Links */}
<div className="space-y-1">
{navItems.map((item) => (
<Link
key={item.href}
href={item.href}
className={`block text-sm font-medium transition-colors py-2.5 px-3 rounded-md relative ${
isActive(item.href)
? "text-primary font-semibold bg-primary/10"
: "text-foreground hover:text-primary hover:bg-muted/50"
}`}
onClick={() => setIsMenuOpen(false)}
>
{item.label}
{isActive(item.href) && (
<span className="absolute left-0 top-1/2 -translate-y-1/2 w-1 h-6 bg-primary rounded-full"></span>
)}
</Link>
))}
</div>

{/* User Actions */}
{!loading && user && (
<div className="pt-3 mt-3 border-t border-border">
<div className="flex items-center space-x-2 py-2 px-3">
<UserIcon />
<div className="flex-1 min-w-0">
<UserDisplay userId={user.id} showCodeuniaId={false} />
</div>
</div>
</div>
)}

{/* Auth Buttons for non-authenticated users */}
{!loading && !user && (
<div className="pt-3 mt-3 border-t border-border space-y-2">
<Button variant="ghost" asChild className="w-full text-sm">
<Link href={`/auth/signin?returnUrl=${encodeURIComponent(pathname)}`}>Sign In</Link>
</Button>
<Button asChild className="w-full glow-effect text-sm">
<Link href={`/auth/signup?returnUrl=${encodeURIComponent(pathname)}`}>Sign Up</Link>
</Button>
</div>
)}
</div>
)}
</nav>
</div>
</nav>
</div>
</>
)}
</header>
</>
)
}
Loading