mirror of
https://github.com/Techtonic-Fault/homepage.git
synced 2026-01-23 05:26:30 +00:00
105 lines
3.8 KiB
TypeScript
105 lines
3.8 KiB
TypeScript
|
|
"use client"
|
||
|
|
|
||
|
|
import { useState } from "react"
|
||
|
|
import Link from "next/link"
|
||
|
|
import { Button } from "@/components/ui/button"
|
||
|
|
import { Menu, X } from "lucide-react"
|
||
|
|
import { ThemeToggle } from "@/components/theme-toggle"
|
||
|
|
import { motion } from "framer-motion"
|
||
|
|
import { Logo } from "@/components/logo"
|
||
|
|
|
||
|
|
export function Navbar() {
|
||
|
|
const [isMenuOpen, setIsMenuOpen] = useState(false)
|
||
|
|
|
||
|
|
const navItems = [
|
||
|
|
{ name: "Servizi", href: "/#services" },
|
||
|
|
{ name: "Progetti", href: "/portfolio" },
|
||
|
|
{ name: "Storia", href: "/#about" },
|
||
|
|
{ name: "Blog", href: "/blog" },
|
||
|
|
{ name: "Testimonianze", href: "/#testimonials" },
|
||
|
|
]
|
||
|
|
|
||
|
|
return (
|
||
|
|
<motion.header
|
||
|
|
className="sticky top-0 z-50 w-full border-b bg-white dark:bg-gray-950 dark:border-gray-800"
|
||
|
|
initial={{ y: -100 }}
|
||
|
|
animate={{ y: 0 }}
|
||
|
|
transition={{ duration: 0.5, ease: "easeOut" }}
|
||
|
|
>
|
||
|
|
<div className="container flex h-16 items-center px-4 md:px-6">
|
||
|
|
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 0.5, delay: 0.2 }}>
|
||
|
|
<Logo showText={true} className="hidden md:block" />
|
||
|
|
<Logo showText={false} className="block md:hidden" />
|
||
|
|
</motion.div>
|
||
|
|
<nav className="hidden md:flex ml-auto gap-6">
|
||
|
|
{navItems.map((item, index) => (
|
||
|
|
<motion.div
|
||
|
|
key={item.name}
|
||
|
|
initial={{ opacity: 0, y: -20 }}
|
||
|
|
animate={{ opacity: 1, y: 0 }}
|
||
|
|
transition={{ duration: 0.3, delay: 0.1 * (index + 1) }}
|
||
|
|
>
|
||
|
|
<Link
|
||
|
|
href={item.href}
|
||
|
|
className="text-sm font-medium hover:text-primary-900 dark:hover:text-primary-300 transition-colors"
|
||
|
|
>
|
||
|
|
{item.name}
|
||
|
|
</Link>
|
||
|
|
</motion.div>
|
||
|
|
))}
|
||
|
|
</nav>
|
||
|
|
<div className="ml-auto flex items-center gap-2">
|
||
|
|
<motion.div
|
||
|
|
initial={{ opacity: 0, scale: 0.8 }}
|
||
|
|
animate={{ opacity: 1, scale: 1 }}
|
||
|
|
transition={{ duration: 0.3, delay: 0.6 }}
|
||
|
|
>
|
||
|
|
<ThemeToggle />
|
||
|
|
</motion.div>
|
||
|
|
<motion.div
|
||
|
|
initial={{ opacity: 0, scale: 0.8 }}
|
||
|
|
animate={{ opacity: 1, scale: 1 }}
|
||
|
|
transition={{ duration: 0.3, delay: 0.7 }}
|
||
|
|
>
|
||
|
|
<Button asChild className="bg-primary-900 hover:bg-primary-800 dark:bg-primary-700 dark:hover:bg-primary-600 dark:text-primary-50">
|
||
|
|
<Link href="/#contact">Contattaci</Link>
|
||
|
|
</Button>
|
||
|
|
</motion.div>
|
||
|
|
</div>
|
||
|
|
<Button variant="ghost" size="icon" className="ml-2 md:hidden" onClick={() => setIsMenuOpen(!isMenuOpen)}>
|
||
|
|
{isMenuOpen ? <X className="h-6 w-6" /> : <Menu className="h-6 w-6" />}
|
||
|
|
<span className="sr-only">Apri o chiudi il menu</span>
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
{isMenuOpen && (
|
||
|
|
<motion.div
|
||
|
|
className="container md:hidden"
|
||
|
|
initial={{ opacity: 0, height: 0 }}
|
||
|
|
animate={{ opacity: 1, height: "auto" }}
|
||
|
|
exit={{ opacity: 0, height: 0 }}
|
||
|
|
transition={{ duration: 0.3 }}
|
||
|
|
>
|
||
|
|
<nav className="flex flex-col gap-4 p-4">
|
||
|
|
{navItems.map((item, index) => (
|
||
|
|
<motion.div
|
||
|
|
key={item.name}
|
||
|
|
initial={{ opacity: 0, x: -20 }}
|
||
|
|
animate={{ opacity: 1, x: 0 }}
|
||
|
|
transition={{ duration: 0.3, delay: 0.05 * (index + 1) }}
|
||
|
|
>
|
||
|
|
<Link
|
||
|
|
href={item.href}
|
||
|
|
className="text-sm font-medium hover:text-primary-900 dark:hover:text-primary-300 transition-colors"
|
||
|
|
onClick={() => setIsMenuOpen(false)}
|
||
|
|
>
|
||
|
|
{item.name}
|
||
|
|
</Link>
|
||
|
|
</motion.div>
|
||
|
|
))}
|
||
|
|
</nav>
|
||
|
|
</motion.div>
|
||
|
|
)}
|
||
|
|
</motion.header>
|
||
|
|
)
|
||
|
|
}
|