File size: 5,557 Bytes
0630ed4 050ab1a 0630ed4 050ab1a fd47a62 050ab1a 0630ed4 050ab1a 0630ed4 050ab1a 0630ed4 050ab1a 0630ed4 050ab1a 0630ed4 050ab1a 0630ed4 050ab1a 0630ed4 050ab1a 0630ed4 050ab1a 0630ed4 050ab1a 0630ed4 050ab1a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useTheme } from "next-themes";
import { useState, useEffect } from "react";
import { Sun, Moon, BrainCircuit, Menu, X } from "lucide-react";
import { useLanguage } from "@/app/providers";
import { Button } from "@/components/ui/button";
export default function Navbar() {
const { theme, setTheme } = useTheme();
const { lang, toggleLang } = useLanguage();
const pathname = usePathname();
const [isScrolled, setIsScrolled] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
const handleScroll = () => setIsScrolled(window.scrollY > 20);
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, []);
const getLinkVariant = (path: string) =>
pathname === path ? "secondary" : "ghost";
const navLinks = [
{ href: "/", label: lang === "en" ? "Home" : "Beranda" },
{ href: "/analyzer", label: lang === "en" ? "Analyzer" : "Analisis" },
{ href: "/quiz", label: lang === "en" ? "Quiz" : "Kuis" },
{ href: "/types", label: lang === "en" ? "Types" : "Tipe" },
{ href: "/chat", label: lang === "en" ? "Chat" : "Chat" },
];
return (
<>
<nav
className={`
fixed left-1/2 -translate-x-1/2 z-50
flex justify-between items-center px-4 py-3
/* GANTI BAGIAN TRANSISI DI SINI: */
transition-all duration-700 ease-[cubic-bezier(0.25,0.1,0.25,1.0)] will-change-[width,top,background]
${
isScrolled
? /* SCROLLED STATE:
- top-4: Turun dikit
- w-[92%]: Lebar di layar kecil
- md:w-[48rem]: KUNCI ANIMASI! Pake w-[48rem] (sama dengan max-w-3xl) biar transisi width-nya mulus.
Jangan pake max-w-3xl karena bakal crash sama transisi width.
- rounded-[12px]: Jadi kotak tumpul
*/
"top-4 w-[92%] md:w-[48rem] rounded-[12px] bg-white/40 dark:bg-black/40 backdrop-blur-xl border border-gray-200 dark:border-white/10 shadow-sm"
: /* DEFAULT STATE:
- top-0: Nempel atas
- w-full: Lebar penuh
*/
"top-0 w-full bg-transparent border-b border-transparent"
}
`}
>
{/* LOGO */}
<Link href="/" className="flex items-center gap-2 pl-2">
<div className="bg-orange-600 p-1.5 rounded-[8px]">
<BrainCircuit className="text-white w-5 h-5" />
</div>
<span className="font-bold text-lg tracking-tight text-gray-900 dark:text-white">
Sentimind<span className="text-orange-600">.</span>
</span>
</Link>
{/* DESKTOP MENU */}
<div className="hidden md:flex items-center gap-1">
{navLinks.map((link) => (
<Button
key={link.href}
asChild
variant={getLinkVariant(link.href)}
size="sm"
className={`cursor-pointer text-sm font-medium ${
pathname === link.href
? "text-orange-600 dark:text-orange-400 bg-orange-50 dark:bg-orange-950/30"
: "text-gray-600 dark:text-gray-400"
}`}
>
<Link href={link.href}>{link.label}</Link>
</Button>
))}
</div>
{/* KANAN: Lang + Theme */}
<div className="flex items-center gap-2 pr-2">
<Button
onClick={toggleLang}
variant="ghost"
size="sm"
className="w-9 h-9 p-0 text-xs font-bold text-gray-500"
>
{lang.toUpperCase()}
</Button>
<Button
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
variant="ghost"
size="icon"
className="w-9 h-9 rounded-full text-gray-500"
>
{!mounted ? (
<div className="w-4 h-4" />
) : theme === "dark" ? (
<Sun className="w-4 h-4" />
) : (
<Moon className="w-4 h-4" />
)}
</Button>
{/* Mobile Menu Button */}
<div className="md:hidden">
<Button
variant="ghost"
size="icon"
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
>
{isMobileMenuOpen ? (
<X className="w-5 h-5" />
) : (
<Menu className="w-5 h-5" />
)}
</Button>
</div>
</div>
</nav>
{/* MOBILE MENU */}
{isMobileMenuOpen && (
<div className="fixed inset-0 z-40 bg-white dark:bg-black pt-24 px-6 animate-in slide-in-from-top-10 fade-in duration-200">
<div className="flex flex-col gap-2">
{navLinks.map((link) => (
<Link
key={link.href}
href={link.href}
onClick={() => setIsMobileMenuOpen(false)}
>
<Button
variant="ghost"
size="lg"
className="w-full justify-start text-lg font-medium"
>
{link.label}
</Button>
</Link>
))}
</div>
</div>
)}
</>
);
}
|