mirror of
https://github.com/myronblair/epic-download
synced 2026-07-27 20:46:22 -05:00
visual_edit_1773685489407
This commit is contained in:
+79
-79
@@ -27,9 +27,9 @@ const Home = () => {
|
|||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const [destinationsData, specialsData] = await Promise.all([
|
const [destinationsData, specialsData] = await Promise.all([
|
||||||
destinationsAPI.getAll(),
|
destinationsAPI.getAll(),
|
||||||
specialsAPI.getAll()
|
specialsAPI.getAll()]
|
||||||
]);
|
);
|
||||||
setDestinations(destinationsData);
|
setDestinations(destinationsData);
|
||||||
setSpecials(specialsData);
|
setSpecials(specialsData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -41,8 +41,8 @@ const Home = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Get special destinations
|
// Get special destinations
|
||||||
const specialDestinations = specials.map(special => {
|
const specialDestinations = specials.map((special) => {
|
||||||
const dest = destinations.find(d => d.id === special.destination_id);
|
const dest = destinations.find((d) => d.id === special.destination_id);
|
||||||
if (!dest) return null;
|
if (!dest) return null;
|
||||||
return {
|
return {
|
||||||
...dest,
|
...dest,
|
||||||
@@ -54,10 +54,10 @@ const Home = () => {
|
|||||||
}).filter(Boolean);
|
}).filter(Boolean);
|
||||||
|
|
||||||
// Filter destinations
|
// Filter destinations
|
||||||
const filteredDestinations = destinations.filter(dest => {
|
const filteredDestinations = destinations.filter((dest) => {
|
||||||
const matchesCategory = selectedCategory === 'All' || dest.category === selectedCategory;
|
const matchesCategory = selectedCategory === 'All' || dest.category === selectedCategory;
|
||||||
const matchesSearch = dest.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
const matchesSearch = dest.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||||
dest.location.toLowerCase().includes(searchQuery.toLowerCase());
|
dest.location.toLowerCase().includes(searchQuery.toLowerCase());
|
||||||
return matchesCategory && matchesSearch;
|
return matchesCategory && matchesSearch;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -92,9 +92,9 @@ const Home = () => {
|
|||||||
style={{
|
style={{
|
||||||
backgroundImage: 'url(https://images.unsplash.com/photo-1488646953014-85cb44e25828?w=1600&q=80)',
|
backgroundImage: 'url(https://images.unsplash.com/photo-1488646953014-85cb44e25828?w=1600&q=80)',
|
||||||
backgroundSize: 'cover',
|
backgroundSize: 'cover',
|
||||||
backgroundPosition: 'center',
|
backgroundPosition: 'center'
|
||||||
}}
|
}}>
|
||||||
>
|
|
||||||
<div className="absolute inset-0 bg-gradient-to-r from-cyan-900/80 to-blue-900/70"></div>
|
<div className="absolute inset-0 bg-gradient-to-r from-cyan-900/80 to-blue-900/70"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -102,23 +102,23 @@ const Home = () => {
|
|||||||
<h1 className="text-5xl md:text-7xl font-bold mb-6 animate-in fade-in slide-in-from-bottom duration-700">
|
<h1 className="text-5xl md:text-7xl font-bold mb-6 animate-in fade-in slide-in-from-bottom duration-700">
|
||||||
Discover Your Next Adventure
|
Discover Your Next Adventure
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-xl md:text-2xl mb-8 text-cyan-50 animate-in fade-in slide-in-from-bottom duration-700 delay-100">
|
<p className="text-xl md:text-2xl mb-8 text-cyan-50 animate-in fade-in slide-in-from-bottom duration-700 delay-100">Explore breathtaking destinations around the world with Epic Travel & Expeditions
|
||||||
Explore breathtaking destinations around the world with Epic Travel
|
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-col sm:flex-row gap-4 justify-center animate-in fade-in slide-in-from-bottom duration-700 delay-200">
|
<div className="flex flex-col sm:flex-row gap-4 justify-center animate-in fade-in slide-in-from-bottom duration-700 delay-200">
|
||||||
<Button
|
<Button
|
||||||
size="lg"
|
size="lg"
|
||||||
className="bg-cyan-600 hover:bg-cyan-700 text-white px-8 py-6 text-lg"
|
className="bg-cyan-600 hover:bg-cyan-700 text-white px-8 py-6 text-lg"
|
||||||
onClick={() => document.getElementById('destinations').scrollIntoView({ behavior: 'smooth' })}
|
onClick={() => document.getElementById('destinations').scrollIntoView({ behavior: 'smooth' })}>
|
||||||
>
|
|
||||||
Explore Destinations
|
Explore Destinations
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="lg"
|
size="lg"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="border-2 border-white text-white hover:bg-white hover:text-cyan-600 px-8 py-6 text-lg"
|
className="border-2 border-white text-white hover:bg-white hover:text-cyan-600 px-8 py-6 text-lg"
|
||||||
onClick={() => document.getElementById('specials').scrollIntoView({ behavior: 'smooth' })}
|
onClick={() => document.getElementById('specials').scrollIntoView({ behavior: 'smooth' })}>
|
||||||
>
|
|
||||||
View Specials
|
View Specials
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -138,24 +138,24 @@ const Home = () => {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{loading ? (
|
{loading ?
|
||||||
<div className="text-center py-12">
|
<div className="text-center py-12">
|
||||||
<p className="text-gray-600">Loading specials...</p>
|
<p className="text-gray-600">Loading specials...</p>
|
||||||
</div>
|
</div> :
|
||||||
) : specialDestinations.length === 0 ? (
|
specialDestinations.length === 0 ?
|
||||||
<div className="text-center py-12">
|
<div className="text-center py-12">
|
||||||
<p className="text-gray-600">No special offers available at the moment.</p>
|
<p className="text-gray-600">No special offers available at the moment.</p>
|
||||||
</div>
|
</div> :
|
||||||
) : (
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||||
{specialDestinations.map((special) => (
|
{specialDestinations.map((special) =>
|
||||||
<Card key={special.id} className="overflow-hidden hover:shadow-2xl transition-shadow duration-300 group">
|
<Card key={special.id} className="overflow-hidden hover:shadow-2xl transition-shadow duration-300 group">
|
||||||
<div className="relative overflow-hidden">
|
<div className="relative overflow-hidden">
|
||||||
<img
|
<img
|
||||||
src={special.image}
|
src={special.image}
|
||||||
alt={special.name}
|
alt={special.name}
|
||||||
className="w-full h-64 object-cover group-hover:scale-110 transition-transform duration-500"
|
className="w-full h-64 object-cover group-hover:scale-110 transition-transform duration-500" />
|
||||||
/>
|
|
||||||
<div className="absolute top-4 right-4 bg-red-500 text-white px-4 py-2 rounded-full font-bold text-lg shadow-lg">
|
<div className="absolute top-4 right-4 bg-red-500 text-white px-4 py-2 rounded-full font-bold text-lg shadow-lg">
|
||||||
{special.discount}% OFF
|
{special.discount}% OFF
|
||||||
</div>
|
</div>
|
||||||
@@ -174,12 +174,12 @@ const Home = () => {
|
|||||||
<CardContent>
|
<CardContent>
|
||||||
<p className="text-gray-600 mb-4">{special.description}</p>
|
<p className="text-gray-600 mb-4">{special.description}</p>
|
||||||
<div className="space-y-2 mb-4">
|
<div className="space-y-2 mb-4">
|
||||||
{special.highlights.map((highlight, idx) => (
|
{special.highlights.map((highlight, idx) =>
|
||||||
<div key={idx} className="flex items-start space-x-2 text-sm text-gray-700">
|
<div key={idx} className="flex items-start space-x-2 text-sm text-gray-700">
|
||||||
<Tag className="w-4 h-4 text-cyan-600 mt-0.5 flex-shrink-0" />
|
<Tag className="w-4 h-4 text-cyan-600 mt-0.5 flex-shrink-0" />
|
||||||
<span>{highlight}</span>
|
<span>{highlight}</span>
|
||||||
</div>
|
</div>
|
||||||
))}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between mb-4">
|
<div className="flex items-center justify-between mb-4">
|
||||||
<div>
|
<div>
|
||||||
@@ -198,9 +198,9 @@ const Home = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
))}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -225,38 +225,38 @@ const Home = () => {
|
|||||||
placeholder="Search destinations..."
|
placeholder="Search destinations..."
|
||||||
value={searchQuery}
|
value={searchQuery}
|
||||||
onChange={(e) => setSearchQuery(e.target.value)}
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
className="pl-10"
|
className="pl-10" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2 flex-wrap justify-center">
|
<div className="flex gap-2 flex-wrap justify-center">
|
||||||
{categories.map(category => (
|
{categories.map((category) =>
|
||||||
<Button
|
<Button
|
||||||
key={category}
|
key={category}
|
||||||
variant={selectedCategory === category ? "default" : "outline"}
|
variant={selectedCategory === category ? "default" : "outline"}
|
||||||
onClick={() => setSelectedCategory(category)}
|
onClick={() => setSelectedCategory(category)}
|
||||||
className={selectedCategory === category ? "bg-cyan-600 hover:bg-cyan-700" : ""}
|
className={selectedCategory === category ? "bg-cyan-600 hover:bg-cyan-700" : ""}>
|
||||||
>
|
|
||||||
{category}
|
{category}
|
||||||
</Button>
|
</Button>
|
||||||
))}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Destinations Grid */}
|
{/* Destinations Grid */}
|
||||||
{loading ? (
|
{loading ?
|
||||||
<div className="text-center py-12">
|
<div className="text-center py-12">
|
||||||
<p className="text-gray-600">Loading destinations...</p>
|
<p className="text-gray-600">Loading destinations...</p>
|
||||||
</div>
|
</div> :
|
||||||
) : (
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||||
{filteredDestinations.map((destination) => (
|
{filteredDestinations.map((destination) =>
|
||||||
<Card key={destination.id} className="overflow-hidden hover:shadow-xl transition-shadow duration-300 group cursor-pointer">
|
<Card key={destination.id} className="overflow-hidden hover:shadow-xl transition-shadow duration-300 group cursor-pointer">
|
||||||
<div className="relative overflow-hidden">
|
<div className="relative overflow-hidden">
|
||||||
<img
|
<img
|
||||||
src={destination.image}
|
src={destination.image}
|
||||||
alt={destination.name}
|
alt={destination.name}
|
||||||
className="w-full h-64 object-cover group-hover:scale-110 transition-transform duration-500"
|
className="w-full h-64 object-cover group-hover:scale-110 transition-transform duration-500" />
|
||||||
/>
|
|
||||||
<div className="absolute top-4 left-4 bg-white/95 backdrop-blur-sm px-3 py-1 rounded-full flex items-center space-x-1">
|
<div className="absolute top-4 left-4 bg-white/95 backdrop-blur-sm px-3 py-1 rounded-full flex items-center space-x-1">
|
||||||
<Star className="w-4 h-4 fill-yellow-400 text-yellow-400" />
|
<Star className="w-4 h-4 fill-yellow-400 text-yellow-400" />
|
||||||
<span className="font-semibold">{destination.rating}</span>
|
<span className="font-semibold">{destination.rating}</span>
|
||||||
@@ -285,9 +285,9 @@ const Home = () => {
|
|||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
))}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -304,29 +304,29 @@ const Home = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||||
{testimonials.map((testimonial) => (
|
{testimonials.map((testimonial) =>
|
||||||
<Card key={testimonial.id} className="hover:shadow-xl transition-shadow duration-300">
|
<Card key={testimonial.id} className="hover:shadow-xl transition-shadow duration-300">
|
||||||
<CardContent className="pt-6">
|
<CardContent className="pt-6">
|
||||||
<div className="flex items-center mb-4">
|
<div className="flex items-center mb-4">
|
||||||
<img
|
<img
|
||||||
src={testimonial.image}
|
src={testimonial.image}
|
||||||
alt={testimonial.name}
|
alt={testimonial.name}
|
||||||
className="w-16 h-16 rounded-full object-cover mr-4"
|
className="w-16 h-16 rounded-full object-cover mr-4" />
|
||||||
/>
|
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-semibold text-lg">{testimonial.name}</h4>
|
<h4 className="font-semibold text-lg">{testimonial.name}</h4>
|
||||||
<p className="text-sm text-gray-500">{testimonial.location}</p>
|
<p className="text-sm text-gray-500">{testimonial.location}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex mb-3">
|
<div className="flex mb-3">
|
||||||
{[...Array(testimonial.rating)].map((_, i) => (
|
{[...Array(testimonial.rating)].map((_, i) =>
|
||||||
<Star key={i} className="w-4 h-4 fill-yellow-400 text-yellow-400" />
|
<Star key={i} className="w-4 h-4 fill-yellow-400 text-yellow-400" />
|
||||||
))}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-gray-600 italic">"{testimonial.text}"</p>
|
<p className="text-gray-600 italic">"{testimonial.text}"</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
))}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -350,8 +350,8 @@ const Home = () => {
|
|||||||
placeholder="Your Name"
|
placeholder="Your Name"
|
||||||
value={contactForm.name}
|
value={contactForm.name}
|
||||||
onChange={(e) => setContactForm({ ...contactForm, name: e.target.value })}
|
onChange={(e) => setContactForm({ ...contactForm, name: e.target.value })}
|
||||||
required
|
required />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Input
|
<Input
|
||||||
@@ -359,8 +359,8 @@ const Home = () => {
|
|||||||
placeholder="Your Email"
|
placeholder="Your Email"
|
||||||
value={contactForm.email}
|
value={contactForm.email}
|
||||||
onChange={(e) => setContactForm({ ...contactForm, email: e.target.value })}
|
onChange={(e) => setContactForm({ ...contactForm, email: e.target.value })}
|
||||||
required
|
required />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Textarea
|
<Textarea
|
||||||
@@ -368,8 +368,8 @@ const Home = () => {
|
|||||||
value={contactForm.message}
|
value={contactForm.message}
|
||||||
onChange={(e) => setContactForm({ ...contactForm, message: e.target.value })}
|
onChange={(e) => setContactForm({ ...contactForm, message: e.target.value })}
|
||||||
rows={5}
|
rows={5}
|
||||||
required
|
required />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<Button type="submit" className="w-full bg-cyan-600 hover:bg-cyan-700" size="lg">
|
<Button type="submit" className="w-full bg-cyan-600 hover:bg-cyan-700" size="lg">
|
||||||
<Send className="w-5 h-5 mr-2" />
|
<Send className="w-5 h-5 mr-2" />
|
||||||
@@ -408,8 +408,8 @@ const Home = () => {
|
|||||||
value={newsletterEmail}
|
value={newsletterEmail}
|
||||||
onChange={(e) => setNewsletterEmail(e.target.value)}
|
onChange={(e) => setNewsletterEmail(e.target.value)}
|
||||||
className="bg-white/20 border-white/30 text-white placeholder:text-cyan-100"
|
className="bg-white/20 border-white/30 text-white placeholder:text-cyan-100"
|
||||||
required
|
required />
|
||||||
/>
|
|
||||||
<Button type="submit" className="w-full bg-white text-cyan-600 hover:bg-cyan-50" size="lg">
|
<Button type="submit" className="w-full bg-white text-cyan-600 hover:bg-cyan-50" size="lg">
|
||||||
Subscribe Now
|
Subscribe Now
|
||||||
</Button>
|
</Button>
|
||||||
@@ -421,8 +421,8 @@ const Home = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>);
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Home;
|
export default Home;
|
||||||
Reference in New Issue
Block a user