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

104
App.tsx Normal file
View File

@@ -0,0 +1,104 @@
import React, { useEffect } from 'react';
import { Routes, Route, Navigate, Outlet } from 'react-router-dom';
import { Header } from './components/Header';
import { Login } from './components/Admin/Login';
import { Dashboard } from './components/Admin/Dashboard';
import { useData } from './contexts/DataContext';
import { Footer } from './components/AppContent';
// Páginas
import {
HomePage,
AboutPage,
ServicesPage,
PromotionsPage,
BlogPage,
BlogPostPage,
ContactPage
} from './components/Pages';
// Layout do site público com Tema Dinâmico e Estrutura Fixa
const PublicLayout = () => {
const { data, getWhatsAppLink } = useData();
// Aplica cor primária dinamicamente
useEffect(() => {
document.documentElement.style.setProperty('--primary-color', data.settings.primaryColor);
// Atualiza Favicon
if (data.settings.faviconUrl) {
const link = document.querySelector("link[rel~='icon']") as HTMLLinkElement;
if (link) {
link.href = data.settings.faviconUrl;
} else {
const newLink = document.createElement('link');
newLink.rel = 'icon';
newLink.href = data.settings.faviconUrl;
document.head.appendChild(newLink);
}
}
// Atualiza Título
document.title = data.settings.siteName;
}, [data.settings]);
return (
<div className="bg-zinc-950 min-h-screen font-sans text-gray-100 selection:bg-primary selection:text-white flex flex-col">
<Header />
<main className="flex-1">
<Outlet />
</main>
<Footer />
<a
href={getWhatsAppLink("Olá! Gostaria de mais informações.")}
target="_blank"
rel="noopener noreferrer"
className="fixed bottom-8 right-8 z-50 bg-green-500 text-white p-4 rounded-full shadow-lg hover:scale-110 transition-transform hover:bg-green-600 flex items-center justify-center"
aria-label="Contato WhatsApp"
>
<svg viewBox="0 0 24 24" fill="white" width="32" height="32">
<path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/>
</svg>
</a>
</div>
);
};
// Proteção de rota simples
const ProtectedRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const isAuth = localStorage.getItem('admin_auth') === 'true';
return isAuth ? <>{children}</> : <Navigate to="/admin" replace />;
};
function App() {
return (
<Routes>
{/* Rotas Públicas */}
<Route path="/" element={<PublicLayout />}>
<Route index element={<HomePage />} />
<Route path="sobre" element={<AboutPage />} />
<Route path="servicos" element={<ServicesPage />} />
<Route path="promocoes" element={<PromotionsPage />} />
<Route path="blog" element={<BlogPage />} />
<Route path="blog/:id" element={<BlogPostPage />} />
<Route path="contato" element={<ContactPage />} />
</Route>
{/* Rotas Administrativas */}
<Route path="/admin" element={<Login />} />
<Route
path="/admin/dashboard"
element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
}
/>
{/* Rota Catch-all para redirecionar para Home se nada corresponder */}
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
);
}
export default App;