feat: Initialize CAR Auto Center project with Vite and React

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.
This commit is contained in:
MMrp89
2026-02-19 16:22:10 -03:00
parent 638c7c3eef
commit c0bd6d7e3d
20 changed files with 3181 additions and 8 deletions

108
components/Header.tsx Normal file
View File

@@ -0,0 +1,108 @@
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>
);
};