Sets up the foundational structure for the CAR Auto Center application using Vite and React. Includes project dependencies, basic HTML structure, TypeScript configuration, and initial README content. This commit establishes the project's build tool, core libraries, and essential configuration files.
108 lines
3.9 KiB
TypeScript
108 lines
3.9 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { Menu, X, Phone } from 'lucide-react';
|
|
import { Link, useLocation } from 'react-router-dom';
|
|
import { Button, Container } from './Shared';
|
|
import { useData } from '../contexts/DataContext';
|
|
|
|
export const Header: React.FC = () => {
|
|
const { data, getWhatsAppLink } = useData();
|
|
const [isScrolled, setIsScrolled] = useState(false);
|
|
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
|
const location = useLocation();
|
|
|
|
useEffect(() => {
|
|
const handleScroll = () => {
|
|
setIsScrolled(window.scrollY > 50);
|
|
};
|
|
window.addEventListener('scroll', handleScroll);
|
|
return () => window.removeEventListener('scroll', handleScroll);
|
|
}, []);
|
|
|
|
const handleCtaClick = () => {
|
|
const { url } = data.header.ctaButton;
|
|
if (url && url.trim() !== '') {
|
|
window.open(url, '_blank');
|
|
} else {
|
|
window.open(getWhatsAppLink("Olá! Gostaria de agendar um horário."), '_blank');
|
|
}
|
|
};
|
|
|
|
return (
|
|
<header
|
|
className={`fixed w-full z-50 transition-all duration-300 ${
|
|
isScrolled ? 'bg-black/90 backdrop-blur-md py-4 shadow-lg border-b border-zinc-800' : 'bg-transparent py-6'
|
|
}`}
|
|
>
|
|
<Container>
|
|
<div className="flex items-center justify-between">
|
|
<Link to="/" className="flex items-center gap-2">
|
|
{data.settings.logoUrl ? (
|
|
<img src={data.settings.logoUrl} alt={data.settings.siteName} className="h-10 object-contain" />
|
|
) : (
|
|
<div className="text-2xl font-black italic tracking-tighter text-white">
|
|
{data.settings.siteName}<span className="text-primary">.</span>
|
|
</div>
|
|
)}
|
|
</Link>
|
|
|
|
{/* Desktop Nav */}
|
|
<nav className="hidden lg:flex items-center gap-8">
|
|
{data.header.items.map((item, index) => (
|
|
<Link
|
|
key={index}
|
|
to={item.href}
|
|
className={`text-sm font-medium transition-colors ${
|
|
location.pathname === item.href
|
|
? 'text-primary'
|
|
: 'text-gray-300 hover:text-primary'
|
|
}`}
|
|
>
|
|
{item.label}
|
|
</Link>
|
|
))}
|
|
</nav>
|
|
|
|
<div className="hidden lg:flex items-center gap-4">
|
|
<div className="flex items-center gap-2 text-white mr-4">
|
|
<Phone size={18} className="text-primary" />
|
|
<span className="font-semibold text-sm">{data.settings.contactPhoneDisplay}</span>
|
|
</div>
|
|
{data.header.ctaButton.show && (
|
|
<Button size="sm" onClick={handleCtaClick}>{data.header.ctaButton.text}</Button>
|
|
)}
|
|
</div>
|
|
|
|
{/* Mobile Toggle */}
|
|
<button
|
|
className="lg:hidden text-white"
|
|
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
|
>
|
|
{isMobileMenuOpen ? <X size={28} /> : <Menu size={28} />}
|
|
</button>
|
|
</div>
|
|
|
|
{/* Mobile Menu */}
|
|
{isMobileMenuOpen && (
|
|
<div className="absolute top-full left-0 w-full bg-zinc-900 border-t border-zinc-800 p-6 lg:hidden flex flex-col gap-4 shadow-2xl">
|
|
{data.header.items.map((item, index) => (
|
|
<Link
|
|
key={index}
|
|
to={item.href}
|
|
className={`text-lg font-medium hover:text-primary ${
|
|
location.pathname === item.href ? 'text-primary' : 'text-gray-200'
|
|
}`}
|
|
onClick={() => setIsMobileMenuOpen(false)}
|
|
>
|
|
{item.label}
|
|
</Link>
|
|
))}
|
|
<hr className="border-zinc-800 my-2"/>
|
|
{data.header.ctaButton.show && (
|
|
<Button className="w-full" onClick={handleCtaClick}>{data.header.ctaButton.text}</Button>
|
|
)}
|
|
</div>
|
|
)}
|
|
</Container>
|
|
</header>
|
|
);
|
|
}; |