diff --git a/package-lock.json b/package-lock.json index f1c1bfb..6683437 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,8 @@ "framer-motion": "^12.23.24", "lucide-react": "^0.553.0", "react": "^19.2.0", - "react-dom": "^19.2.0" + "react-dom": "^19.2.0", + "react-router-dom": "^7.10.1" }, "devDependencies": { "@eslint/js": "^9.39.1", @@ -2308,6 +2309,19 @@ "dev": true, "license": "MIT" }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3362,6 +3376,44 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.10.1.tgz", + "integrity": "sha512-gHL89dRa3kwlUYtRQ+m8NmxGI6CgqN+k4XyGjwcFoQwwCWF6xXpOCUlDovkXClS0d0XJN/5q7kc5W3kiFEd0Yw==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.10.1.tgz", + "integrity": "sha512-JNBANI6ChGVjA5bwsUIwJk7LHKmqB4JYnYfzFwyp2t12Izva11elds2jx7Yfoup2zssedntwU0oZ5DEmk5Sdaw==", + "license": "MIT", + "dependencies": { + "react-router": "7.10.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, "node_modules/readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -3501,6 +3553,12 @@ "semver": "bin/semver.js" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", diff --git a/package.json b/package.json index 1696ae1..3ea5673 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "framer-motion": "^12.23.24", "lucide-react": "^0.553.0", "react": "^19.2.0", - "react-dom": "^19.2.0" + "react-dom": "^19.2.0", + "react-router-dom": "^7.10.1" }, "devDependencies": { "@eslint/js": "^9.39.1", diff --git a/src/App.tsx b/src/App.tsx index 151cb9b..7ffae8d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,12 +1,11 @@ -import { useState, useEffect } from 'react'; +import { useState, useEffect } from 'react'; +import { BrowserRouter, Routes, Route } from 'react-router-dom'; import { LanguageProvider } from './contexts/LanguageContext'; import Header from './components/Header'; -import Hero from './components/Hero'; -import About from './components/About'; -import Skills from './components/Skills'; -import Projects from './components/Projects'; -import Education from './components/Education'; -import Contact from './components/Contact'; +import Footer from './components/Footer'; +import Home from './components/Home'; +import TravelMate from './components/TravelMate'; +import Policies from './components/Policies'; import './styles/main.scss'; function App() { @@ -17,7 +16,6 @@ function App() { if (savedTheme) { setDarkMode(JSON.parse(savedTheme)); } else { - // Détection automatique du thème préféré de l'utilisateur setDarkMode(window.matchMedia('(prefers-color-scheme: dark)').matches); } }, []); @@ -33,17 +31,19 @@ function App() { return ( -
-
-
- - - - - - -
-
+ +
+
+
+ + } /> + } /> + } /> + +
+
+
); } diff --git a/src/assets/app_icon.png b/src/assets/app_icon.png new file mode 100644 index 0000000..861b888 Binary files /dev/null and b/src/assets/app_icon.png differ diff --git a/src/components/Contact.tsx b/src/components/Contact.tsx index d95687b..fb525ec 100644 --- a/src/components/Contact.tsx +++ b/src/components/Contact.tsx @@ -105,7 +105,7 @@ const Contact = () => { { icon: , name: "GitHub", - url: "https://github.com/Dayron-HELHa", // Remplacez par votre profil + url: "https://git.xeewy.be/Xeewy", // Remplacez par votre profil color: "#333" }, { @@ -373,18 +373,6 @@ const Contact = () => { - {/* Footer */} - -

- © 2025 Dayron Van Leemput. -

-
); diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx new file mode 100644 index 0000000..dbebf91 --- /dev/null +++ b/src/components/Footer.tsx @@ -0,0 +1,28 @@ +import { motion } from 'framer-motion'; + +const Footer = () => { + return ( + +

+ © {new Date().getFullYear()} Dayron Van Leemput. +

+
+ ); +}; + +export default Footer; diff --git a/src/components/Header.tsx b/src/components/Header.tsx index b87d3c4..4502d28 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -2,6 +2,7 @@ import { useState } from 'react'; import { motion } from 'framer-motion'; import { Menu, X, Sun, Moon, Globe } from 'lucide-react'; import { useLanguage } from '../contexts/LanguageContext'; +import { useNavigate, useLocation, Link } from 'react-router-dom'; interface HeaderProps { darkMode: boolean; @@ -11,6 +12,8 @@ interface HeaderProps { const Header = ({ darkMode, toggleDarkMode }: HeaderProps) => { const [isMenuOpen, setIsMenuOpen] = useState(false); const { language, setLanguage, t } = useLanguage(); + const navigate = useNavigate(); + const location = useLocation(); const menuItems = [ { id: 'home', name: t('nav.home'), href: '#hero' }, @@ -21,12 +24,26 @@ const Header = ({ darkMode, toggleDarkMode }: HeaderProps) => { { id: 'contact', name: t('nav.contact'), href: '#contact' } ]; - const scrollToSection = (href: string) => { - const element = document.querySelector(href); - if (element) { - element.scrollIntoView({ behavior: 'smooth' }); - } + const handleNavigation = (href: string) => { setIsMenuOpen(false); + + if (location.pathname === '/') { + // Already on home, just scroll + const element = document.querySelector(href); + if (element) { + element.scrollIntoView({ behavior: 'smooth' }); + } + } else { + // Not on home, navigate then scroll (using a simple timeout for simplicity or hash) + navigate('/'); + // Small timeout to allow navigation to render Home before scrolling + setTimeout(() => { + const element = document.querySelector(href); + if (element) { + element.scrollIntoView({ behavior: 'smooth' }); + } + }, 100); + } }; const toggleLanguage = () => { @@ -46,9 +63,12 @@ const Header = ({ darkMode, toggleDarkMode }: HeaderProps) => { whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }} > - { e.preventDefault(); scrollToSection('#hero'); }}> + { + e.preventDefault(); + handleNavigation('#hero'); + }}> Dayron Van Leemput - + {/* Navigation desktop */} @@ -64,7 +84,7 @@ const Header = ({ darkMode, toggleDarkMode }: HeaderProps) => { href={item.href} onClick={(e) => { e.preventDefault(); - scrollToSection(item.href); + handleNavigation(item.href); }} > {item.name} @@ -123,7 +143,7 @@ const Header = ({ darkMode, toggleDarkMode }: HeaderProps) => { href={item.href} onClick={(e) => { e.preventDefault(); - scrollToSection(item.href); + handleNavigation(item.href); }} > {item.name} diff --git a/src/components/Hero.tsx b/src/components/Hero.tsx index 19bb335..327932b 100644 --- a/src/components/Hero.tsx +++ b/src/components/Hero.tsx @@ -5,7 +5,7 @@ import dvlPhoto from '../assets/dvl.jpg'; const Hero = () => { const { t } = useLanguage(); - + const handleDownloadCV = () => { // Ici, vous pouvez ajouter le lien vers votre CV const link = document.createElement('a'); @@ -32,7 +32,7 @@ const Hero = () => { > {t('hero.title')} - + { > {t('hero.subtitle')} - + { {t('btn.downloadCV')} - + { @@ -89,7 +89,7 @@ const Hero = () => { transition={{ duration: 0.8, delay: 1.2 }} > { > - + { whileHover={{ scale: 1.05, rotate: 5 }} transition={{ type: "spring", stiffness: 300, damping: 10 }} > - Dayron Van Leemput - Portrait diff --git a/src/components/Home.tsx b/src/components/Home.tsx new file mode 100644 index 0000000..33e9c05 --- /dev/null +++ b/src/components/Home.tsx @@ -0,0 +1,21 @@ +import Hero from './Hero'; +import About from './About'; +import Skills from './Skills'; +import Projects from './Projects'; +import Education from './Education'; +import Contact from './Contact'; + +const Home = () => { + return ( + <> + + + + + + + + ); +}; + +export default Home; diff --git a/src/components/Policies.tsx b/src/components/Policies.tsx new file mode 100644 index 0000000..ef2563f --- /dev/null +++ b/src/components/Policies.tsx @@ -0,0 +1,127 @@ +import { motion } from 'framer-motion'; +import { useLanguage } from '../contexts/LanguageContext'; +import { Link } from 'react-router-dom'; +import { ArrowLeft, Shield, Lock, Eye, Mail, Camera, MapPin, Bell } from 'lucide-react'; + +const Policies = () => { + const { t } = useLanguage(); + + const containerVariants = { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { + staggerChildren: 0.1 + } + } + }; + + const sectionVariants = { + hidden: { opacity: 0, y: 20 }, + visible: { opacity: 1, y: 0 } + }; + + return ( +
+
+ + + {t('policies.back')} + + + + {/* Header */} + + +

{t('policies.title')}

+

{t('policies.lastUpdated')}

+

{t('policies.intro')}

+
+ + {/* Section 1: Data & Permissions */} + +
+ +

{t('policies.data.title')}

+
+

{t('policies.data.intro')}

+ +
+ + {/* Camera */} +
+

+ {t('policies.data.camera')} +

+

{t('policies.data.camera.desc')}

+
+ + {/* GPS */} +
+

+ {t('policies.data.gps')} +

+

{t('policies.data.gps.desc')}

+
+ + {/* Notifications */} +
+

+ {t('policies.data.notif')} +

+

{t('policies.data.notif.desc')}

+
+ +
+
+ + {/* Section 2: Usage */} + +
+ +

{t('policies.usage.title')}

+
+

+ {t('policies.usage.content')} +

+
+ + {/* Section 3: Contact */} + +
+ +

{t('policies.contact.title')}

+
+
+

+ {t('policies.contact.content')} +

+ + dev.dayronvl@gmail.com + +
+
+ +
+
+
+ ); +}; + +export default Policies; diff --git a/src/components/Projects.tsx b/src/components/Projects.tsx index 6db6fa8..3a018fc 100644 --- a/src/components/Projects.tsx +++ b/src/components/Projects.tsx @@ -1,6 +1,7 @@ import { motion } from 'framer-motion'; import { ExternalLink, MapPin, Wine } from 'lucide-react'; import { useLanguage } from '../contexts/LanguageContext'; +import { Link } from 'react-router-dom'; const Projects = () => { const { t } = useLanguage(); @@ -20,7 +21,7 @@ const Projects = () => { color: "#4CAF50", icon: , links: { - demo: "#" + demo: "/travelmate" }, image: "/travel-mate-preview.png" // Ajoutez votre image dans le dossier public }, @@ -182,17 +183,30 @@ const Projects = () => {
{project.links.demo !== "#" && ( - - - {t('projects.btn.viewProject')} - + project.links.demo.startsWith('/') ? ( + + + + {t('projects.btn.viewProject')} + + + ) : ( + + + {t('projects.btn.viewProject')} + + ) )}
diff --git a/src/components/TravelMate.tsx b/src/components/TravelMate.tsx new file mode 100644 index 0000000..ad25dd1 --- /dev/null +++ b/src/components/TravelMate.tsx @@ -0,0 +1,266 @@ +import { motion } from 'framer-motion'; +import { useLanguage } from '../contexts/LanguageContext'; +import { Link, Outlet } from 'react-router-dom'; +import { Shield, Smartphone, Map, DollarSign, Users, Globe, Code } 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 }) => ( + +
+ +
+

+ {title} +

+

+ {description} +

+
+); + +const TravelMate = () => { + const { t } = useLanguage(); + + const containerVariants = { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { + staggerChildren: 0.2 + } + } + }; + + return ( +
+
+ + + {/* Header Section */} + + +

+ {t('travelmate.page.mainTitle')} +

+

+ {t('travelmate.page.subtitle')} +

+ + {/* View Code Button */} + + + {t('travelmate.viewCode') || "Voir le code"} + +
+ + {/* Description as Intro */} + +

+ "{t('travelmate.page.intro')}" +

+
+ + {/* Highlights Sections */} + +

{t('travelmate.highlights.title')}

+
+ + {[1, 2, 3, 4].map((num) => ( + + ))} + +
+
+ + {/* Conclusion */} + +

+ {t('travelmate.page.conclusion')} +

+
+ {/* Tech Stack */} + +

{t('travelmate.tech.title')}

+
+ + {/* Frontend */} +
+

+ {t('travelmate.tech.frontend')} +

+
    + {[1, 2, 3].map(i => ( +
  • + {t(`travelmate.tech.frontend.${i}`)} +
  • + ))} +
+
+ + {/* Backend */} +
+

+ {t('travelmate.tech.backend')} +

+
    + {[1, 2, 3, 4].map(i => ( +
  • + {t(`travelmate.tech.backend.${i}`)} +
  • + ))} +
+
+ + {/* API */} +
+

+ {t('travelmate.tech.api')} +

+
    + {[1, 2, 3].map(i => ( +
  • + {t(`travelmate.tech.api.${i}`)} +
  • + ))} +
+
+ +
+
+ + {/* Policies CTA */} + + +

+ {t('policies.title')} +

+ + {t('travelmate.policies.link')} + +
+
+ + +
+
+ ); +}; + +export default TravelMate; diff --git a/src/contexts/LanguageContext.tsx b/src/contexts/LanguageContext.tsx index 592bf62..400745d 100644 --- a/src/contexts/LanguageContext.tsx +++ b/src/contexts/LanguageContext.tsx @@ -139,6 +139,65 @@ const translations = { 'education.highschool.highlights.1': 'Sciences (Physique, Chimie, Biologie)', 'education.highschool.highlights.2': 'Langues', + // Travel Mate Page + 'travelmate.page.mainTitle': 'Travel Mate 🌍', + 'travelmate.page.subtitle': 'Le compagnon de voyage indispensable', + 'travelmate.page.intro': 'Redécouvrez le voyage en groupe avec Travel Mate. Plus qu\'une simple application, c\'est votre copilote pour des aventures sans friction. Oubliez les tableaux Excel complexes et les débats sur "qui doit combien". Concentrez-vous sur l\'essentiel : créer des souvenirs inoubliables.', + + 'travelmate.highlights.title': '✨ Points Forts', + 'travelmate.highlight.1.title': 'Gestion de Groupe Simplifiée', + 'travelmate.highlight.1.desc': 'Créez votre voyage et invitez vos compagnons en un clic via un lien unique. L\'organisation démarre instantanément.', + 'travelmate.highlight.2.title': 'Dépenses Maîtrisées (Split)', + 'travelmate.highlight.2.desc': 'Suivez les dépenses en temps réel et laissez l\'application équilibrer les comptes automatiquement. Fini les calculs compliqués !', + 'travelmate.highlight.3.title': 'Planification Collaborative', + 'travelmate.highlight.3.desc': 'Un agenda partagé et une carte interactive pour que chacun puisse proposer et visualiser les activités du groupe.', + 'travelmate.highlight.4.title': 'Communication Fluide', + 'travelmate.highlight.4.desc': 'Un chat intégré pour centraliser les discussions et garder tout le monde sur la même longueur d\'onde.', + + 'travelmate.page.conclusion': 'Prêt à partir ? Avec Travel Mate, l\'aventure commence dès l\'organisation. Voyagez l\'esprit léger, on s\'occupe du reste.', + + 'travelmate.tech.title': '🛠️ Technologies utilisées', + 'travelmate.tech.frontend': 'Frontend', + 'travelmate.tech.frontend.1': 'Flutter - Framework de développement mobile cross-platform', + 'travelmate.tech.frontend.2': 'Dart - Langage de programmation', + + 'travelmate.tech.frontend.3': 'BloC - Gestion d\'état', + + 'travelmate.tech.backend': 'Backend & Services', + 'travelmate.tech.backend.1': 'Firebase Authentication - Gestion des utilisateurs', + 'travelmate.tech.backend.2': 'Cloud Firestore - Base de données NoSQL', + 'travelmate.tech.backend.3': 'Firebase Storage - Stockage de fichiers (photos, documents)', + 'travelmate.tech.backend.4': 'Firebase Cloud Messaging - Notifications push', + + 'travelmate.tech.api': 'APIs externes', + 'travelmate.tech.api.1': 'Google Places API - Recherche de lieux et points d\'intérêt', + 'travelmate.tech.api.2': 'Google Maps API - Cartes et navigation', + 'travelmate.tech.api.3': 'Google Directions API - Calcul d\'itinéraires', + + 'travelmate.policies.link': 'Voir la politique de confidentialité', + + // Policies + 'policies.title': 'Politique de Confidentialité - Travel Mate', + 'policies.lastUpdated': 'Dernière mise à jour : 05/12/2025', + 'policies.intro': 'Cette politique de confidentialité explique comment l\'application Travel Mate utilise et protège vos données.', + + 'policies.data.title': '1. Données collectées et Permissions', + 'policies.data.intro': 'Pour fonctionner correctement, l\'application demande les permissions suivantes :', + 'policies.data.camera': 'Caméra et Galerie (Storage)', + 'policies.data.camera.desc': 'Pour vous permettre d\'ajouter des photos à vos lieux, activités et photos de profil. Ces images sont stockées sur nos serveurs sécurisés (Firebase).', + 'policies.data.gps': 'Localisation (GPS)', + 'policies.data.gps.desc': 'Pour vous montrer votre position sur la carte et calculer des itinéraires. Ces données de localisation ne sont pas enregistrées en permanence dans notre historique.', + 'policies.data.notif': 'Notifications', + 'policies.data.notif.desc': 'Pour vous alerter des nouveaux messages ou activités dans vos groupes de voyage.', + + 'policies.usage.title': '2. Utilisation des données', + 'policies.usage.content': 'Vos données (email, profil, voyages) sont stockées de manière sécurisée via les services Google Firebase. Elles ne sont utilisées que pour le fonctionnement de l\'application et ne sont jamais revendues à des tiers.', + + 'policies.contact.title': '3. Contact', + 'policies.contact.content': 'Pour toute question concernant vos données ou pour demander leur suppression, vous pouvez nous contacter à :', + + 'policies.back': 'Retour à Travel Mate', + // Contact 'contact.title': 'Contactez-moi', 'contact.subtitle': 'Une question, un projet ou simplement envie d\'échanger ? N\'hésitez pas à me contacter !', @@ -276,6 +335,65 @@ const translations = { 'education.highschool.highlights.1': 'Sciences (Physics, Chemistry, Biology)', 'education.highschool.highlights.2': 'Languages', + // Travel Mate Page + 'travelmate.page.mainTitle': 'Travel Mate 🌍', + 'travelmate.page.subtitle': 'The essential travel companion', + 'travelmate.page.intro': 'Rediscover group travel with Travel Mate. More than just an app, it\'s your essential co-pilot for friction-free adventures. Forget complex spreadsheets and debates about "who owes what". Focus on what matters: making unforgettable memories.', + + 'travelmate.highlights.title': '✨ Key Highlights', + 'travelmate.highlight.1.title': 'Simplified Group Management', + 'travelmate.highlight.1.desc': 'Create your trip and invite companions with a single click via a unique link. Organization starts instantly.', + 'travelmate.highlight.2.title': 'Mastered Expenses (Split)', + 'travelmate.highlight.2.desc': 'Track expenses in real-time and let the app balance accounts automatically. No more complicated math!', + 'travelmate.highlight.3.title': 'Collaborative Planning', + 'travelmate.highlight.3.desc': 'A shared agenda and interactive map so everyone can suggest and visualize group activities.', + 'travelmate.highlight.4.title': 'Seamless Communication', + 'travelmate.highlight.4.desc': 'An integrated chat to centralize discussions and keep everyone on the same page.', + + 'travelmate.page.conclusion': 'Ready to go? With Travel Mate, the adventure begins with the planning. Travel with peace of mind, we\'ll handle the rest.', + + 'travelmate.tech.title': '🛠️ Technologies Used', + 'travelmate.tech.frontend': 'Frontend', + 'travelmate.tech.frontend.1': 'Flutter - Cross-platform mobile development framework', + 'travelmate.tech.frontend.2': 'Dart - Programming language', + + 'travelmate.tech.frontend.3': 'BloC - State management', + + 'travelmate.tech.backend': 'Backend & Services', + 'travelmate.tech.backend.1': 'Firebase Authentication - User management', + 'travelmate.tech.backend.2': 'Cloud Firestore - NoSQL database', + 'travelmate.tech.backend.3': 'Firebase Storage - File storage (photos, documents)', + 'travelmate.tech.backend.4': 'Firebase Cloud Messaging - Push notifications', + + 'travelmate.tech.api': 'External APIs', + 'travelmate.tech.api.1': 'Google Places API - Places and POI search', + 'travelmate.tech.api.2': 'Google Maps API - Maps and navigation', + 'travelmate.tech.api.3': 'Google Directions API - Route selection', + + 'travelmate.policies.link': 'View Privacy Policy', + + // Policies + 'policies.title': 'Privacy Policy - Travel Mate', + 'policies.lastUpdated': 'Last updated: 05/12/2025', + 'policies.intro': 'This privacy policy explains how the Travel Mate application uses and protects your data.', + + 'policies.data.title': '1. Collected Data and Permissions', + 'policies.data.intro': 'To function correctly, the application requests the following permissions:', + 'policies.data.camera': 'Camera and Gallery (Storage)', + 'policies.data.camera.desc': 'To allow you to add photos to your places, activities, and profile pictures. These images are stored on our secure servers (Firebase).', + 'policies.data.gps': 'Location (GPS)', + 'policies.data.gps.desc': 'To show your position on the map and calculate routes. This location data is not permanently recorded in our history.', + 'policies.data.notif': 'Notifications', + 'policies.data.notif.desc': 'To alert you of new messages or activities in your travel groups.', + + 'policies.usage.title': '2. Data Usage', + 'policies.usage.content': 'Your data (email, profile, trips) is stored securely via Google Firebase services. It is used only for the application\'s operation and is never sold to third parties.', + + 'policies.contact.title': '3. Contact', + 'policies.contact.content': 'For any questions regarding your data or to request its deletion, you can contact us at:', + + 'policies.back': 'Back to Travel Mate', + // Contact 'contact.title': 'Contact me', 'contact.subtitle': 'A question, a project or just want to chat? Feel free to contact me!',