338 lines
18 KiB
TypeScript
338 lines
18 KiB
TypeScript
import { useEffect } from 'react';
|
|
import { motion } from 'framer-motion';
|
|
import { useLanguage } from '../contexts/LanguageContext';
|
|
import { Link } from 'react-router-dom';
|
|
import { Shield, Smartphone, Map, DollarSign, Users, Globe, Code, ArrowLeft } from 'lucide-react';
|
|
import appIcon from '../assets/app_icon.png';
|
|
|
|
const itemVariants = {
|
|
hidden: { opacity: 0, y: 20 },
|
|
visible: { opacity: 1, y: 0 }
|
|
};
|
|
|
|
const FeatureCard = ({ title, icon: Icon, description }: { title: string, icon: any, description: string }) => (
|
|
<motion.div
|
|
variants={itemVariants}
|
|
className="feature-card"
|
|
style={{
|
|
background: 'var(--card-bg, rgba(255, 255, 255, 0.03))', // Slightly more transparent for glass effect
|
|
backdropFilter: 'blur(10px)', // Glassmorphism
|
|
padding: '2rem',
|
|
borderRadius: '1.5rem',
|
|
border: '1px solid var(--border-color, rgba(255, 255, 255, 0.08))',
|
|
height: '100%',
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
alignItems: 'center', // Center items horizontally
|
|
textAlign: 'center', // Center text
|
|
transition: 'transform 0.3s ease, box-shadow 0.3s ease',
|
|
boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)'
|
|
}}
|
|
whileHover={{
|
|
y: -5,
|
|
boxShadow: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
|
|
borderColor: 'var(--primary-color, #4f46e5)'
|
|
}}
|
|
>
|
|
<div style={{
|
|
marginBottom: '1.5rem',
|
|
background: 'var(--primary-color-alpha, rgba(79, 70, 229, 0.1))',
|
|
width: 'fit-content',
|
|
padding: '12px',
|
|
borderRadius: '12px'
|
|
}}>
|
|
<Icon size={32} color="var(--primary-color)" />
|
|
</div>
|
|
<h3 style={{
|
|
marginBottom: '1rem',
|
|
fontSize: '1.5rem',
|
|
fontWeight: '600',
|
|
color: 'var(--text-color)' // Explicit color for dark mode
|
|
}}>
|
|
{title}
|
|
</h3>
|
|
<p style={{
|
|
opacity: 0.8,
|
|
lineHeight: '1.7',
|
|
flex: 1,
|
|
fontSize: '1rem',
|
|
color: 'var(--text-color)' // Explicit color
|
|
}}>
|
|
{description}
|
|
</p>
|
|
</motion.div>
|
|
);
|
|
|
|
const TravelMate = () => {
|
|
const { t, language } = useLanguage();
|
|
|
|
const containerVariants = {
|
|
hidden: { opacity: 0 },
|
|
visible: {
|
|
opacity: 1,
|
|
transition: {
|
|
staggerChildren: 0.2
|
|
}
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
document.title = "Travel Mate";
|
|
}, []);
|
|
|
|
return (
|
|
<div className="travel-mate-page" style={{ paddingTop: '100px', minHeight: '100vh', paddingBottom: '50px' }}>
|
|
<div className="container" style={{ maxWidth: '1400px', margin: '0 auto', padding: '0 20px' }}>
|
|
|
|
<motion.div
|
|
variants={containerVariants}
|
|
initial="hidden"
|
|
animate="visible"
|
|
>
|
|
{/* Header Section */}
|
|
<motion.div variants={itemVariants} style={{ textAlign: 'center', marginBottom: '4rem', display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
|
|
<motion.img
|
|
src={appIcon}
|
|
alt="Travel Mate Icon"
|
|
style={{ width: '120px', height: '120px', borderRadius: '24px', marginBottom: '2rem', boxShadow: '0 10px 30px rgba(0,0,0,0.2)' }}
|
|
whileHover={{ scale: 1.05, rotate: 5 }}
|
|
transition={{ type: "spring", stiffness: 300 }}
|
|
/>
|
|
<h1 className="gradient-text" style={{ fontSize: '4rem', fontWeight: '800', marginBottom: '1rem' }}>
|
|
{t('travelmate.page.mainTitle')}
|
|
</h1>
|
|
<p style={{ fontSize: '1.5rem', opacity: 0.7, maxWidth: '600px', margin: '0 auto 2rem auto' }}>
|
|
{t('travelmate.page.subtitle')}
|
|
</p>
|
|
|
|
{/* View Code Button */}
|
|
<motion.a
|
|
href="https://git.xeewy.be/Xeewy/TravelMate"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="btn btn-primary"
|
|
style={{
|
|
display: 'inline-flex',
|
|
alignItems: 'center',
|
|
gap: '10px',
|
|
textDecoration: 'none',
|
|
fontSize: '1.1rem',
|
|
padding: '0.8rem 1.5rem',
|
|
borderRadius: '50px'
|
|
}}
|
|
whileHover={{ scale: 1.05 }}
|
|
whileTap={{ scale: 0.95 }}
|
|
>
|
|
<Code size={20} />
|
|
{t('travelmate.viewCode') || "Voir le code"}
|
|
</motion.a>
|
|
</motion.div>
|
|
|
|
{/* Description as Intro */}
|
|
<motion.div variants={itemVariants} style={{ marginBottom: '5rem', maxWidth: '800px', margin: '0 auto 5rem auto', textAlign: 'center' }}>
|
|
<p style={{
|
|
lineHeight: '1.8',
|
|
fontSize: '1.4rem',
|
|
opacity: 0.9,
|
|
fontStyle: 'italic',
|
|
color: 'var(--text-color)'
|
|
}}>
|
|
"{t('travelmate.page.intro')}"
|
|
</p>
|
|
</motion.div>
|
|
|
|
{/* Highlights Sections */}
|
|
<motion.div variants={itemVariants} style={{ marginBottom: '6rem' }}>
|
|
<h2 style={{
|
|
textAlign: 'center',
|
|
marginBottom: '4rem',
|
|
fontSize: '2.5rem',
|
|
fontWeight: '700',
|
|
color: 'var(--text-color)'
|
|
}}>{t('travelmate.highlights.title')}</h2>
|
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))', gap: '2.5rem' }}>
|
|
|
|
{[1, 2, 3, 4].map((num) => (
|
|
<FeatureCard
|
|
key={num}
|
|
title={t(`travelmate.highlight.${num}.title`)}
|
|
description={t(`travelmate.highlight.${num}.desc`)}
|
|
icon={
|
|
num === 1 ? Users :
|
|
num === 2 ? DollarSign :
|
|
num === 3 ? Map :
|
|
Smartphone
|
|
}
|
|
/>
|
|
))}
|
|
|
|
</div>
|
|
</motion.div>
|
|
|
|
{/* Conclusion */}
|
|
<motion.div variants={itemVariants} style={{ marginBottom: '6rem', textAlign: 'center', maxWidth: '800px', margin: '0 auto 6rem auto' }}>
|
|
<p style={{
|
|
fontSize: '1.8rem',
|
|
fontWeight: 'bold',
|
|
color: 'var(--primary-color)',
|
|
lineHeight: '1.4'
|
|
}}>
|
|
{t('travelmate.page.conclusion')}
|
|
</p>
|
|
</motion.div>
|
|
{/* Tech Stack */}
|
|
<motion.div variants={itemVariants} style={{ marginBottom: '5rem' }}>
|
|
<h2 style={{ textAlign: 'center', marginBottom: '3rem' }}>{t('travelmate.tech.title')}</h2>
|
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))', gap: '2rem' }}>
|
|
|
|
{/* Frontend */}
|
|
<div style={{ padding: '1.5rem' }}>
|
|
<h3 style={{ display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '1.5rem', color: 'var(--primary-color)' }}>
|
|
<Smartphone /> {t('travelmate.tech.frontend')}
|
|
</h3>
|
|
<ul style={{ listStyle: 'none', padding: 0 }}>
|
|
{[1, 2, 3].map(i => (
|
|
<li key={i} style={{ marginBottom: '0.8rem', paddingLeft: '1rem', borderLeft: '2px solid var(--primary-color)' }}>
|
|
{t(`travelmate.tech.frontend.${i}`)}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
|
|
{/* Backend */}
|
|
<div style={{ padding: '1.5rem' }}>
|
|
<h3 style={{ display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '1.5rem', color: 'var(--primary-color)' }}>
|
|
<Globe /> {t('travelmate.tech.backend')}
|
|
</h3>
|
|
<ul style={{ listStyle: 'none', padding: 0 }}>
|
|
{[1, 2, 3, 4].map(i => (
|
|
<li key={i} style={{ marginBottom: '0.8rem', paddingLeft: '1rem', borderLeft: '2px solid var(--primary-color)' }}>
|
|
{t(`travelmate.tech.backend.${i}`)}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
|
|
{/* API */}
|
|
<div style={{ padding: '1.5rem' }}>
|
|
<h3 style={{ display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '1.5rem', color: 'var(--primary-color)' }}>
|
|
<Code /> {t('travelmate.tech.api')}
|
|
</h3>
|
|
<ul style={{ listStyle: 'none', padding: 0 }}>
|
|
{[1, 2].map(i => (
|
|
<li key={i} style={{ marginBottom: '0.8rem', paddingLeft: '1rem', borderLeft: '2px solid var(--primary-color)' }}>
|
|
{t(`travelmate.tech.api.${i}`)}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
|
|
</div>
|
|
</motion.div>
|
|
|
|
{/* Legal & Support Section */}
|
|
<motion.div variants={itemVariants} style={{ marginBottom: '6rem' }}>
|
|
<h2 style={{
|
|
textAlign: 'center',
|
|
marginBottom: '4rem',
|
|
fontSize: '2.5rem',
|
|
fontWeight: '700',
|
|
color: 'var(--text-color)'
|
|
}}>{t('travelmate.legal.title')}</h2>
|
|
|
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))', gap: '2rem' }}>
|
|
{/* Privacy Policy Card */}
|
|
<Link to={`/${language}/travelmate/policies`} style={{ textDecoration: 'none', color: 'inherit' }}>
|
|
<motion.div
|
|
whileHover={{ y: -5, boxShadow: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)', borderColor: 'var(--primary-color)' }}
|
|
style={{
|
|
background: 'var(--card-bg, rgba(255, 255, 255, 0.03))',
|
|
backdropFilter: 'blur(10px)',
|
|
padding: '2rem',
|
|
borderRadius: '1.5rem',
|
|
border: '1px solid var(--border-color, rgba(255, 255, 255, 0.08))',
|
|
height: '100%',
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
alignItems: 'flex-start',
|
|
transition: 'all 0.3s ease'
|
|
}}
|
|
>
|
|
<Shield size={32} style={{ color: 'var(--primary-color)', marginBottom: '1.5rem' }} />
|
|
<h3 style={{ fontSize: '1.25rem', fontWeight: '600', marginBottom: '1rem' }}>{t('policies.title')}</h3>
|
|
<p style={{ opacity: 0.7, marginBottom: '2rem', flex: 1, lineHeight: '1.6' }}>
|
|
{t('travelmate.legal.privacy.desc')}
|
|
</p>
|
|
<span style={{ color: 'var(--primary-color)', fontWeight: '500', display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
{t('travelmate.policies.link')} <ArrowLeft size={16} style={{ rotate: '180deg' }} />
|
|
</span>
|
|
</motion.div>
|
|
</Link>
|
|
|
|
{/* Erase Data Card */}
|
|
<Link to={`/${language}/travelmate/erasedata`} style={{ textDecoration: 'none', color: 'inherit' }}>
|
|
<motion.div
|
|
whileHover={{ y: -5, boxShadow: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)', borderColor: '#EF4444' }}
|
|
style={{
|
|
background: 'var(--card-bg, rgba(255, 255, 255, 0.03))',
|
|
backdropFilter: 'blur(10px)',
|
|
padding: '2rem',
|
|
borderRadius: '1.5rem',
|
|
border: '1px solid var(--border-color, rgba(255, 255, 255, 0.08))',
|
|
height: '100%',
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
alignItems: 'flex-start',
|
|
transition: 'all 0.3s ease'
|
|
}}
|
|
>
|
|
<Shield size={32} style={{ color: '#EF4444', marginBottom: '1.5rem' }} />
|
|
<h3 style={{ fontSize: '1.25rem', fontWeight: '600', marginBottom: '1rem' }}>{t('erasedata.title').split(' ').slice(0, 2).join(' ')}...</h3> {/* Truncate title or use specific one */}
|
|
<p style={{ opacity: 0.7, marginBottom: '2rem', flex: 1, lineHeight: '1.6' }}>
|
|
{t('travelmate.legal.erasedata.desc')}
|
|
</p>
|
|
<span style={{ color: '#EF4444', fontWeight: '500', display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
{t('travelmate.erasedata.link')} <ArrowLeft size={16} style={{ rotate: '180deg' }} />
|
|
</span>
|
|
</motion.div>
|
|
</Link>
|
|
|
|
{/* Support Card */}
|
|
<Link to={`/${language}/travelmate/support`} style={{ textDecoration: 'none', color: 'inherit' }}>
|
|
<motion.div
|
|
whileHover={{ y: -5, boxShadow: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)', borderColor: '#10B981' }}
|
|
style={{
|
|
background: 'var(--card-bg, rgba(255, 255, 255, 0.03))',
|
|
backdropFilter: 'blur(10px)',
|
|
padding: '2rem',
|
|
borderRadius: '1.5rem',
|
|
border: '1px solid var(--border-color, rgba(255, 255, 255, 0.08))',
|
|
height: '100%',
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
alignItems: 'flex-start',
|
|
transition: 'all 0.3s ease'
|
|
}}
|
|
>
|
|
<Users size={32} style={{ color: '#10B981', marginBottom: '1.5rem' }} />
|
|
<h3 style={{ fontSize: '1.25rem', fontWeight: '600', marginBottom: '1rem' }}>{t('support.title')}</h3>
|
|
<p style={{ opacity: 0.7, marginBottom: '2rem', flex: 1, lineHeight: '1.6' }}>
|
|
{t('travelmate.legal.support.desc')}
|
|
</p>
|
|
<span style={{ color: '#10B981', fontWeight: '500', display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
{t('travelmate.support.link')} <ArrowLeft size={16} style={{ rotate: '180deg' }} />
|
|
</span>
|
|
</motion.div>
|
|
</Link>
|
|
</div>
|
|
</motion.div>
|
|
</motion.div>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default TravelMate;
|