first commit
This commit is contained in:
46
components/layout/Footer.tsx
Normal file
46
components/layout/Footer.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
"use client";
|
||||
import Link from "next/link";
|
||||
import { useLanguage } from "@/context/LanguageContext";
|
||||
|
||||
export const Footer = () => {
|
||||
const { t } = useLanguage();
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
return (
|
||||
<footer className="w-full bg-white pt-20 pb-10 border-t border-crisp mt-auto">
|
||||
<div className="max-w-7xl mx-auto px-6 lg:px-12">
|
||||
|
||||
<div className="flex flex-col md:flex-row justify-between items-start md:items-center pb-12 mb-8">
|
||||
{/* Logo / Brand */}
|
||||
<div className="text-[32px] font-extrabold text-navy tracking-tight mb-8 md:mb-0">
|
||||
ITEM OPINA.
|
||||
</div>
|
||||
|
||||
{/* Nav Links Traducidos */}
|
||||
<div className="flex flex-col sm:flex-row gap-6 sm:gap-12 text-[14px] font-bold text-navy/60">
|
||||
<Link href="/legal" className="hover:text-ocean transition-colors">
|
||||
{t.footer.legal}
|
||||
</Link>
|
||||
<Link href="/privacidad" className="hover:text-ocean transition-colors">
|
||||
{t.footer.privacy}
|
||||
</Link>
|
||||
<Link href="/cookies" className="hover:text-ocean transition-colors">
|
||||
{t.footer.cookies}
|
||||
</Link>
|
||||
<Link href="/contacto" className="hover:text-ocean transition-colors">
|
||||
{t.footer.contact}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom Credits Traducidos */}
|
||||
<div className="flex flex-col sm:flex-row justify-between items-center text-[13px] text-navy/40 font-semibold uppercase tracking-wider">
|
||||
<p>
|
||||
{t.footer.rights.replace("2026", currentYear.toString())}
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
145
components/layout/Navbar.tsx
Normal file
145
components/layout/Navbar.tsx
Normal file
@@ -0,0 +1,145 @@
|
||||
"use client";
|
||||
import { useState, useEffect } from "react";
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { Button } from "../ui/Button";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { FiMenu, FiX, FiGlobe } from "react-icons/fi";
|
||||
import { useLanguage } from "@/context/LanguageContext";
|
||||
|
||||
export const Navbar = () => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const pathname = usePathname();
|
||||
const { locale, setLocale, t } = useLanguage();
|
||||
|
||||
const isActive = (path: string) => pathname === path;
|
||||
|
||||
useEffect(() => {
|
||||
setIsOpen(false);
|
||||
}, [pathname]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
document.body.style.overflow = "hidden";
|
||||
} else {
|
||||
document.body.style.overflow = "unset";
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
const navLinks = [
|
||||
{ name: t.navbar.consultora, href: "/nosotros" },
|
||||
{ name: t.navbar.servicios, href: "/servicios" },
|
||||
{ name: t.navbar.participa, href: "/participa" },
|
||||
{ name: t.navbar.insights, href: "/insights" },
|
||||
];
|
||||
|
||||
return (
|
||||
<nav className="w-full h-[80px] bg-white/80 backdrop-blur-md border-b border-crisp sticky top-0 z-[100]">
|
||||
<div className="max-w-7xl mx-auto px-6 lg:px-12 h-full flex justify-between items-center">
|
||||
{/* Logo */}
|
||||
<Link href="/" className="text-[20px] md:text-[22px] font-extrabold tracking-tight text-navy uppercase">
|
||||
Item Opina.
|
||||
</Link>
|
||||
|
||||
{/* Menú Central (Escritorio) */}
|
||||
<div className="hidden md:flex space-x-8 lg:space-x-10 text-[13px] lg:text-[14px] font-bold uppercase tracking-wider">
|
||||
{navLinks.map((link) => (
|
||||
<Link
|
||||
key={link.href}
|
||||
href={link.href}
|
||||
className={`${isActive(link.href) ? "text-ocean" : "text-navy/60"} hover:text-ocean transition-colors`}
|
||||
>
|
||||
{link.name}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Idiomas y Acción (Escritorio) */}
|
||||
<div className="hidden md:flex items-center space-x-6">
|
||||
{/* Selector de Idiomas */}
|
||||
<div className="flex items-center gap-3 pr-6">
|
||||
{(["es", "ca", "en"] as const).map((lang) => (
|
||||
<button
|
||||
key={lang}
|
||||
onClick={() => setLocale(lang)}
|
||||
className={`text-[11px] font-black uppercase transition-all ${
|
||||
locale === lang ? "text-ocean scale-110" : "text-navy/30 hover:text-navy"
|
||||
}`}
|
||||
>
|
||||
{lang}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Link href="/contacto">
|
||||
<Button
|
||||
variant={isActive("/contacto") ? "primary" : "outline"}
|
||||
className="!py-2.5 !px-6 text-[12px]"
|
||||
>
|
||||
{t.navbar.contacto}
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Botón Hamburguesa (Móvil) */}
|
||||
<button
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
className="md:hidden text-navy p-2 outline-none focus:outline-none ring-0"
|
||||
aria-label="Toggle Menu"
|
||||
>
|
||||
{isOpen ? <FiX size={28} /> : <FiMenu size={28} />}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Menú Móvil (Overlay) */}
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: 20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
exit={{ opacity: 0, x: 20 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
className="fixed inset-0 top-[80px] w-full h-[calc(100vh-80px)] bg-white z-[90] flex flex-col p-8 md:hidden"
|
||||
>
|
||||
<div className="flex flex-col space-y-6 mt-6">
|
||||
{navLinks.map((link) => (
|
||||
<Link
|
||||
key={link.href}
|
||||
href={link.href}
|
||||
className={`text-[32px] font-extrabold uppercase tracking-tighter ${
|
||||
isActive(link.href) ? "text-ocean" : "text-navy"
|
||||
}`}
|
||||
>
|
||||
{link.name}
|
||||
</Link>
|
||||
))}
|
||||
|
||||
<div className="pt-8 border-t border-crisp flex flex-col gap-8">
|
||||
{/* Selector de Idiomas Móvil */}
|
||||
<div className="flex gap-6">
|
||||
{(["es", "ca", "en"] as const).map((lang) => (
|
||||
<button
|
||||
key={lang}
|
||||
onClick={() => setLocale(lang)}
|
||||
className={`text-[16px] font-bold uppercase ${
|
||||
locale === lang ? "text-ocean border-b-2 border-ocean" : "text-navy/40"
|
||||
}`}
|
||||
>
|
||||
{lang === "es" ? "Español" : lang === "ca" ? "Català" : "English"}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Link href="/contacto">
|
||||
<Button variant="primary" className="w-full !py-5 text-[16px] uppercase tracking-widest font-bold">
|
||||
{t.navbar.contacto}
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user