Homepage Redesign

This commit is contained in:
Eric Gullickson
2025-11-03 14:06:54 -06:00
parent 54d97a98b5
commit eeb20543fa
71 changed files with 3925 additions and 1340 deletions

View File

@@ -29,9 +29,9 @@ const MaintenancePage = lazy(() => import('./features/maintenance/pages/Maintena
const VehiclesMobileScreen = lazy(() => import('./features/vehicles/mobile/VehiclesMobileScreen').then(m => ({ default: m.VehiclesMobileScreen })));
const VehicleDetailMobile = lazy(() => import('./features/vehicles/mobile/VehicleDetailMobile').then(m => ({ default: m.VehicleDetailMobile })));
const DocumentsMobileScreen = lazy(() => import('./features/documents/mobile/DocumentsMobileScreen'));
import { HomePage } from './pages/HomePage';
import { BottomNavigation, NavigationItem } from './shared-minimal/components/mobile/BottomNavigation';
import { GlassCard } from './shared-minimal/components/mobile/GlassCard';
import { Button } from './shared-minimal/components/Button';
import { RouteSuspense } from './components/SuspenseWrappers';
import { Vehicle } from './features/vehicles/types/vehicles.types';
import { FuelLogForm } from './features/fuel-logs/components/FuelLogForm';
@@ -234,7 +234,7 @@ const AddVehicleScreen: React.FC<AddVehicleScreenProps> = ({ onBack, onAdded })
};
function App() {
const { isLoading, isAuthenticated, loginWithRedirect, user } = useAuth0();
const { isLoading, isAuthenticated, user } = useAuth0();
const [_isPending, startTransition] = useTransition();
// Initialize data synchronization
@@ -368,41 +368,11 @@ function App() {
}
if (!isAuthenticated) {
if (mobileMode) {
return (
<ThemeProvider theme={md3Theme}>
<CssBaseline />
<Layout mobileMode={true}>
<div className="space-y-6 flex flex-col items-center justify-center min-h-[400px]">
<div className="text-center">
<h1 className="text-2xl font-bold text-slate-800 mb-3">Welcome to MotoVaultPro</h1>
<p className="text-slate-600 mb-6 text-sm">Your personal vehicle management platform</p>
<button
onClick={() => loginWithRedirect()}
className="h-12 px-8 rounded-2xl text-white font-medium shadow-lg active:scale-[0.99] transition bg-gradient-moto"
>
Login to Continue
</button>
</div>
</div>
<DebugInfo />
</Layout>
</ThemeProvider>
);
}
return (
<ThemeProvider theme={md3Theme}>
<CssBaseline />
<div className="flex items-center justify-center min-h-screen bg-gray-50">
<div className="text-center max-w-md mx-auto px-6">
<h1 className="text-4xl font-bold text-gray-900 mb-4">MotoVaultPro</h1>
<p className="text-gray-600 mb-8">Your personal vehicle management platform</p>
<Button onClick={() => loginWithRedirect()}>
Login to Continue
</Button>
</div>
<DebugInfo />
</div>
<HomePage />
<DebugInfo />
</ThemeProvider>
);
}

View File

@@ -32,40 +32,40 @@ export const vehiclesApi = {
await apiClient.delete(`/vehicles/${id}`);
},
// Dropdown API methods (authenticated)
// Dropdown API methods (authenticated) - using unified platform endpoints
getYears: async (): Promise<number[]> => {
const response = await apiClient.get('/vehicles/dropdown/years');
const response = await apiClient.get('/platform/years');
return response.data;
},
getMakes: async (year: number): Promise<DropdownOption[]> => {
const response = await apiClient.get(`/vehicles/dropdown/makes?year=${year}`);
const response = await apiClient.get(`/platform/makes?year=${year}`);
return response.data;
},
getModels: async (year: number, makeId: number): Promise<DropdownOption[]> => {
const response = await apiClient.get(`/vehicles/dropdown/models?year=${year}&make_id=${makeId}`);
const response = await apiClient.get(`/platform/models?year=${year}&make_id=${makeId}`);
return response.data;
},
getTransmissions: async (year: number, makeId: number, modelId: number): Promise<DropdownOption[]> => {
const response = await apiClient.get(`/vehicles/dropdown/transmissions?year=${year}&make_id=${makeId}&model_id=${modelId}`);
const response = await apiClient.get(`/platform/transmissions?year=${year}&make_id=${makeId}&model_id=${modelId}`);
return response.data;
},
getEngines: async (year: number, makeId: number, modelId: number, trimId: number): Promise<DropdownOption[]> => {
const response = await apiClient.get(`/vehicles/dropdown/engines?year=${year}&make_id=${makeId}&model_id=${modelId}&trim_id=${trimId}`);
const response = await apiClient.get(`/platform/engines?year=${year}&make_id=${makeId}&model_id=${modelId}&trim_id=${trimId}`);
return response.data;
},
getTrims: async (year: number, makeId: number, modelId: number): Promise<DropdownOption[]> => {
const response = await apiClient.get(`/vehicles/dropdown/trims?year=${year}&make_id=${makeId}&model_id=${modelId}`);
const response = await apiClient.get(`/platform/trims?year=${year}&make_id=${makeId}&model_id=${modelId}`);
return response.data;
},
// VIN decode method
// VIN decode method - using unified platform endpoint
decodeVIN: async (vin: string): Promise<VINDecodeResponse> => {
const response = await apiClient.post('/vehicles/decode-vin', { vin });
const response = await apiClient.get(`/platform/vehicle?vin=${vin}`);
return response.data;
},
};

View File

@@ -268,11 +268,15 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
<label className="block text-sm font-medium text-gray-700 mb-1">
VIN or License Plate <span className="text-red-500">*</span>
</label>
<div className="flex gap-2">
<p className="text-xs text-gray-600 mb-2">
Enter VIN to auto-fill vehicle details OR manually select from dropdowns below
</p>
<div className="flex flex-col sm:flex-row gap-2">
<input
{...register('vin')}
className="flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
className="flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 text-base"
placeholder="Enter 17-character VIN (optional if License Plate provided)"
style={{ fontSize: '16px' }}
/>
<Button
type="button"
@@ -280,8 +284,9 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
loading={decodingVIN}
disabled={!watchedVIN || watchedVIN.length !== 17}
variant="secondary"
className="w-full sm:w-auto min-h-[44px]"
>
Decode
Decode VIN
</Button>
</div>
{decodeSuccess && (
@@ -293,14 +298,15 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
</div>
{/* Vehicle Specification Dropdowns */}
<div className="grid grid-cols-3 gap-4">
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Year
</label>
<select
{...register('year', { valueAsNumber: true })}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
style={{ fontSize: '16px' }}
>
<option value="">Select Year</option>
{years.map((year) => (
@@ -317,8 +323,9 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
</label>
<select
{...register('make')}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
disabled={loadingDropdowns || !watchedYear}
style={{ fontSize: '16px' }}
>
<option value="">Select Make</option>
{makes.map((make) => (
@@ -335,8 +342,9 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
</label>
<select
{...register('model')}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
disabled={loadingDropdowns || !watchedMake || models.length === 0}
style={{ fontSize: '16px' }}
>
<option value="">Select Model</option>
{models.map((model) => (
@@ -348,7 +356,7 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
</div>
</div>
<div className="grid grid-cols-3 gap-4">
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
{/* Trim (left) */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
@@ -356,8 +364,9 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
</label>
<select
{...register('trimLevel')}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
disabled={loadingDropdowns || !watchedModel || trims.length === 0}
style={{ fontSize: '16px' }}
>
<option value="">Select Trim</option>
{trims.map((trim) => (
@@ -375,8 +384,9 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
</label>
<select
{...register('engine')}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
disabled={loadingDropdowns || !watchedModel || !selectedTrim || engines.length === 0}
style={{ fontSize: '16px' }}
>
<option value="">Select Engine</option>
{engines.map((engine) => (
@@ -394,7 +404,8 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
</label>
<select
{...register('transmission')}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
style={{ fontSize: '16px' }}
>
<option value="">Select Transmission</option>
<option value="Automatic">Automatic</option>
@@ -409,20 +420,22 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
</label>
<input
{...register('nickname')}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
placeholder="e.g., Family Car"
style={{ fontSize: '16px' }}
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Color
</label>
<input
{...register('color')}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
placeholder="e.g., Blue"
style={{ fontSize: '16px' }}
/>
</div>
@@ -432,8 +445,9 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
</label>
<input
{...register('licensePlate')}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
placeholder="e.g., ABC-123 (required if VIN omitted)"
style={{ fontSize: '16px' }}
/>
{errors.licensePlate && (
<p className="mt-1 text-sm text-red-600">{errors.licensePlate.message}</p>
@@ -448,8 +462,10 @@ export const VehicleForm: React.FC<VehicleFormProps> = ({
<input
{...register('odometerReading', { valueAsNumber: true })}
type="number"
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500"
inputMode="numeric"
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary-500 min-h-[44px]"
placeholder="e.g., 50000"
style={{ fontSize: '16px' }}
/>
</div>

View File

@@ -0,0 +1,221 @@
import { useState } from 'react';
import { useAuth0 } from '@auth0/auth0-react';
import { HeroCarousel } from './HomePage/HeroCarousel';
import { FeaturesGrid } from './HomePage/FeaturesGrid';
import { motion } from 'framer-motion';
export const HomePage = () => {
const { loginWithRedirect } = useAuth0();
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const handleGetStarted = () => {
loginWithRedirect();
};
return (
<div className="min-h-screen bg-white">
{/* Navigation Bar */}
<nav className="bg-white shadow-md sticky top-0 z-50">
<div className="max-w-7xl mx-auto px-4 md:px-8">
<div className="flex justify-between items-center h-16">
{/* Logo */}
<div className="flex-shrink-0">
<h1 className="text-2xl font-bold text-primary-500">MotoVaultPro</h1>
</div>
{/* Desktop Menu */}
<div className="hidden md:flex items-center space-x-8">
<a href="#home" className="text-gray-700 hover:text-primary-500 transition-colors">
Home
</a>
<a
href="#features"
className="text-gray-700 hover:text-primary-500 transition-colors"
>
Features
</a>
<a href="#about" className="text-gray-700 hover:text-primary-500 transition-colors">
About
</a>
<button
onClick={handleGetStarted}
className="bg-primary-500 hover:bg-primary-700 text-white font-semibold py-2 px-6 rounded-lg transition-colors duration-300"
>
Get Started
</button>
</div>
{/* Mobile Menu Button */}
<div className="md:hidden">
<button
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
className="text-gray-700 hover:text-primary-500 focus:outline-none"
>
<svg
className="h-6 w-6"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
stroke="currentColor"
>
{mobileMenuOpen ? (
<path d="M6 18L18 6M6 6l12 12" />
) : (
<path d="M4 6h16M4 12h16M4 18h16" />
)}
</svg>
</button>
</div>
</div>
{/* Mobile Menu */}
{mobileMenuOpen && (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
exit={{ opacity: 0, height: 0 }}
className="md:hidden py-4 space-y-3"
>
<a
href="#home"
className="block text-gray-700 hover:text-primary-500 transition-colors py-2"
>
Home
</a>
<a
href="#features"
className="block text-gray-700 hover:text-primary-500 transition-colors py-2"
>
Features
</a>
<a
href="#about"
className="block text-gray-700 hover:text-primary-500 transition-colors py-2"
>
About
</a>
<button
onClick={handleGetStarted}
className="w-full bg-primary-500 hover:bg-primary-700 text-white font-semibold py-2 px-6 rounded-lg transition-colors duration-300"
>
Get Started
</button>
</motion.div>
)}
</div>
</nav>
{/* Hero Carousel */}
<section id="home">
<HeroCarousel />
</section>
{/* Welcome Section */}
<section className="py-16 px-4 md:px-8 bg-white">
<div className="max-w-4xl mx-auto text-center">
<p className="text-primary-500 text-sm font-semibold uppercase tracking-wide mb-4">
Welcome
</p>
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-6">
Thank you for your interest in MotoVaultPro!
</h2>
<p className="text-lg text-gray-600 leading-relaxed mb-8">
We are pleased to provide comprehensive vehicle management solutions including Vehicle
Tracking, Fuel Log Management, Maintenance Records, Document Storage, Service Station
Locations, and detailed Analytics for all your vehicles. A combination of these features
can create a perfect management system for your fleet. Based on your specific needs, our
platform will help you determine the best approach to managing your vehicles.
</p>
<p className="text-lg text-gray-600 leading-relaxed mb-8">
Do not hesitate to reach out for assistance in creating a custom workflow that best fits
your needs.
</p>
<button
onClick={handleGetStarted}
className="bg-primary-500 hover:bg-primary-700 text-white font-semibold py-3 px-8 rounded-lg transition-colors duration-300"
>
Get Started
</button>
</div>
</section>
{/* About Section */}
<section id="about" className="py-16 px-4 md:px-8 bg-gray-100">
<div className="max-w-6xl mx-auto">
<div className="grid md:grid-cols-2 gap-12 items-center">
<div>
<h3 className="text-sm font-semibold text-primary-500 uppercase tracking-wide mb-4">
About Us
</h3>
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-6">
Overall, our goal is to meet each individual&apos;s needs with quality, passion, and
professionalism.
</h2>
<p className="text-lg text-gray-600 leading-relaxed mb-6">
Most importantly, we treat each and every vehicle as if it were our own and strive to
achieve perfection in vehicle management. If you are unsure of what you need for your
vehicles, we are happy to help talk you through the best options for comprehensive
tracking.
</p>
<p className="text-lg text-gray-600 leading-relaxed">
We are proud to use the finest technology and best practices to provide quality and
satisfaction for our users.
</p>
</div>
<div className="flex justify-center">
<div className="w-64 h-64 bg-primary-500 rounded-lg flex items-center justify-center">
<div className="text-center text-white p-8">
<svg
className="w-32 h-32 mx-auto mb-4"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M9 2a1 1 0 000 2h2a1 1 0 100-2H9z" />
<path
fillRule="evenodd"
d="M4 5a2 2 0 012-2 3 3 0 003 3h2a3 3 0 003-3 2 2 0 012 2v11a2 2 0 01-2 2H6a2 2 0 01-2-2V5zm3 4a1 1 0 000 2h.01a1 1 0 100-2H7zm3 0a1 1 0 000 2h3a1 1 0 100-2h-3zm-3 4a1 1 0 100 2h.01a1 1 0 100-2H7zm3 0a1 1 0 100 2h3a1 1 0 100-2h-3z"
clipRule="evenodd"
/>
</svg>
<p className="text-xl font-bold">Trusted Platform</p>
</div>
</div>
</div>
</div>
</div>
</section>
{/* Features Grid */}
<section id="features">
<FeaturesGrid />
</section>
{/* Bottom CTA */}
<section className="py-16 px-4 md:px-8 bg-primary-500 text-white">
<div className="max-w-4xl mx-auto text-center">
<h2 className="text-2xl md:text-3xl font-bold mb-6">
We are a cloud-based platform accessible anywhere, anytime.
</h2>
<button
onClick={handleGetStarted}
className="bg-white text-primary-500 hover:bg-gray-100 font-semibold py-3 px-8 rounded-lg transition-colors duration-300"
>
Get Started
</button>
</div>
</section>
{/* Footer */}
<footer className="bg-gray-900 text-white py-8 px-4 md:px-8">
<div className="max-w-7xl mx-auto text-center">
<p className="text-gray-400">
&copy; {new Date().getFullYear()} MotoVaultPro. All rights reserved.
</p>
</div>
</footer>
</div>
);
};

View File

@@ -0,0 +1,35 @@
import { motion } from 'framer-motion';
interface FeatureCardProps {
title: string;
description: string;
imageSrc: string;
imageAlt: string;
}
export const FeatureCard = ({ title, description, imageSrc, imageAlt }: FeatureCardProps) => {
return (
<motion.div
className="group cursor-pointer"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-50px' }}
transition={{ duration: 0.5 }}
whileHover={{ y: -5 }}
>
<div className="overflow-hidden rounded-lg shadow-lg hover:shadow-xl transition-shadow duration-300">
<div className="relative h-56 overflow-hidden">
<img
src={imageSrc}
alt={imageAlt}
className="w-full h-full object-cover group-hover:scale-110 transition-transform duration-500"
/>
</div>
<div className="bg-white p-6">
<h3 className="text-xl font-bold text-gray-900 mb-2">{title}</h3>
<p className="text-gray-600 leading-relaxed">{description}</p>
</div>
</div>
</motion.div>
);
};

View File

@@ -0,0 +1,79 @@
import { FeatureCard } from './FeatureCard';
const features = [
{
title: 'Vehicle Management',
description: 'Track all your vehicles in one centralized location with detailed information and history.',
imageSrc: 'https://images.unsplash.com/photo-1503376780353-7e6692767b70?w=600&h=400&fit=crop',
imageAlt: 'Vehicle Management',
},
{
title: 'Fuel Log Tracking',
description: 'Monitor fuel consumption, costs, and efficiency across all your vehicles.',
imageSrc: 'https://images.unsplash.com/photo-1529369623266-f5264b696110?w=600&h=400&fit=crop',
imageAlt: 'Fuel Log Tracking',
},
{
title: 'Maintenance Records',
description: 'Keep detailed maintenance logs and never miss scheduled service appointments.',
imageSrc: 'https://images.unsplash.com/photo-1486262715619-67b85e0b08d3?w=600&h=400&fit=crop',
imageAlt: 'Maintenance Records',
},
{
title: 'Document Storage',
description: 'Store and organize all vehicle documents, receipts, and important paperwork.',
imageSrc: 'https://images.unsplash.com/photo-1568605117036-5fe5e7bab0b7?w=600&h=400&fit=crop',
imageAlt: 'Document Storage',
},
{
title: 'Service Stations',
description: 'Find and track your favorite service stations and fuel locations.',
imageSrc: 'https://images.unsplash.com/photo-1594940887841-4996b7f80874?w=600&h=400&fit=crop',
imageAlt: 'Service Stations',
},
{
title: 'Reports & Analytics',
description: 'Generate detailed reports on costs, mileage, and vehicle performance.',
imageSrc: 'https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=600&h=400&fit=crop',
imageAlt: 'Reports & Analytics',
},
{
title: 'Reminders',
description: 'Set up automated reminders for maintenance, registration, and insurance renewals.',
imageSrc: 'https://images.unsplash.com/photo-1434494878577-86c23bcb06b9?w=600&h=400&fit=crop',
imageAlt: 'Reminders',
},
{
title: 'Data Export',
description: 'Export your data in various formats for reporting and record keeping.',
imageSrc: 'https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=600&h=400&fit=crop',
imageAlt: 'Data Export',
},
];
export const FeaturesGrid = () => {
return (
<section className="py-16 px-4 md:px-8 bg-gray-50">
<div className="max-w-7xl mx-auto">
<div className="text-center mb-12">
<p className="text-primary-500 text-sm font-semibold uppercase tracking-wide mb-2">
Our Features
</p>
<h2 className="text-3xl md:text-4xl font-bold text-gray-900">What We Offer</h2>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{features.map((feature) => (
<FeatureCard key={feature.title} {...feature} />
))}
</div>
<div className="text-center mt-12">
<p className="text-lg text-gray-600 mb-6">
We are a cloud-based platform accessible anywhere, anytime.
</p>
</div>
</div>
</section>
);
};

View File

@@ -0,0 +1,134 @@
import { useRef } from 'react';
import Slider from 'react-slick';
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
interface HeroSlide {
id: number;
imageSrc: string;
imageAlt: string;
}
const heroSlides: HeroSlide[] = [
{
id: 1,
imageSrc: 'https://images.unsplash.com/photo-1492144534655-ae79c964c9d7?w=1920&h=1080&fit=crop',
imageAlt: 'Luxury Sports Car',
},
{
id: 2,
imageSrc: 'https://images.unsplash.com/photo-1503376780353-7e6692767b70?w=1920&h=1080&fit=crop',
imageAlt: 'Red Sports Car',
},
{
id: 3,
imageSrc: 'https://images.unsplash.com/photo-1552519507-da3b142c6e3d?w=1920&h=1080&fit=crop',
imageAlt: 'Green Performance Car',
},
{
id: 4,
imageSrc: 'https://images.unsplash.com/photo-1544636331-e26879cd4d9b?w=1920&h=1080&fit=crop',
imageAlt: 'Black Luxury Vehicle',
},
{
id: 5,
imageSrc: 'https://images.unsplash.com/photo-1549317661-bd32c8ce0db2?w=1920&h=1080&fit=crop',
imageAlt: 'SUV on Road',
},
{
id: 6,
imageSrc: 'https://images.unsplash.com/photo-1520031441872-265e4ff70366?w=1920&h=1080&fit=crop',
imageAlt: 'Luxury Sedan',
},
];
export const HeroCarousel = () => {
const sliderRef = useRef<Slider>(null);
const settings = {
dots: true,
infinite: true,
speed: 1000,
slidesToShow: 1,
slidesToScroll: 1,
autoplay: true,
autoplaySpeed: 5000,
fade: true,
cssEase: 'cubic-bezier(0.4, 0, 0.2, 1)',
pauseOnHover: true,
arrows: true,
};
return (
<div className="relative w-full hero-carousel">
<Slider ref={sliderRef} {...settings}>
{heroSlides.map((slide) => (
<div key={slide.id} className="relative">
<div className="relative h-[500px] md:h-[600px] lg:h-[700px]">
<img
src={slide.imageSrc}
alt={slide.imageAlt}
className="w-full h-full object-cover"
/>
<div className="absolute inset-0 bg-gradient-to-b from-black/60 via-black/40 to-black/60" />
<div className="absolute inset-0 flex flex-col items-center justify-center text-center px-4">
<p className="text-white text-sm md:text-base font-semibold uppercase tracking-widest mb-4">
Welcome to
</p>
<h1 className="text-white text-4xl md:text-6xl lg:text-7xl font-bold mb-6 leading-tight">
MOTOVAULTPRO
</h1>
<button className="bg-primary-500 hover:bg-primary-700 text-white font-semibold py-3 px-8 rounded-lg transition-colors duration-300">
Learn More
</button>
</div>
</div>
</div>
))}
</Slider>
<style>{`
.hero-carousel .slick-dots {
bottom: 25px;
}
.hero-carousel .slick-dots li button:before {
font-size: 12px;
color: white;
opacity: 0.5;
}
.hero-carousel .slick-dots li.slick-active button:before {
color: #7A212A;
opacity: 1;
}
.hero-carousel .slick-prev,
.hero-carousel .slick-next {
z-index: 10;
width: 50px;
height: 50px;
}
.hero-carousel .slick-prev {
left: 25px;
}
.hero-carousel .slick-next {
right: 25px;
}
.hero-carousel .slick-prev:before,
.hero-carousel .slick-next:before {
font-size: 50px;
opacity: 0.75;
}
.hero-carousel .slick-prev:hover:before,
.hero-carousel .slick-next:hover:before {
opacity: 1;
}
`}</style>
</div>
);
};