Skip to content

Commit 096289d

Browse files
committed
Migrate to BrowserRouter, clean URLs, and add GitHub Pages SPA 404.html fallback
1 parent a699873 commit 096289d

File tree

6 files changed

+126
-97
lines changed

6 files changed

+126
-97
lines changed

public/404.html

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" type="image/png" href="/Loopchargingmodule/logo.png" sizes="any" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>LCM - Loop Charging Module | Charging While Driving</title>
8+
<meta name="description" content="LCM is a breakthrough in-vehicle charging technology that generates power while you drive. Experience the future of EV charging with our innovative solution." />
9+
<link rel="preconnect" href="https://fonts.googleapis.com">
10+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Montserrat:wght@500;600;700&display=swap" rel="stylesheet">
12+
</head>
13+
<body>
14+
<div id="root"></div>
15+
<script type="module" src="/Loopchargingmodule/src/main.tsx"></script>
16+
<script>
17+
// GitHub Pages SPA redirect for BrowserRouter
18+
if (location.pathname !== '/Loopchargingmodule/' && !location.pathname.endsWith('.html')) {
19+
location.replace('/Loopchargingmodule/' + '?redirect=' + encodeURIComponent(location.pathname + location.search + location.hash));
20+
}
21+
</script>
22+
</body>
23+
</html>

src/App.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useEffect, Suspense, lazy } from 'react';
2-
import { HashRouter as Router, Routes, Route, useLocation, useNavigate } from 'react-router-dom';
2+
import { BrowserRouter as Router, Routes, Route, useLocation, useNavigate } from 'react-router-dom';
33
import { AnimatePresence } from 'framer-motion';
44
import Layout from './components/layout/Layout';
55
import HeroSection from './components/home/HeroSection';
@@ -167,7 +167,7 @@ function App() {
167167

168168
export default function WrappedApp() {
169169
return (
170-
<Router>
170+
<Router basename="/Loopchargingmodule">
171171
<App />
172172
</Router>
173173
);

src/components/layout/Footer.tsx

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,30 @@ import { Link } from 'react-router-dom';
33
import { Facebook, Twitter, Linkedin, Mail } from 'lucide-react';
44
import logo from '../../assets/logo.png';
55
import { handleNavigation } from '../../utils/navigation';
6+
import { useLocation, useNavigate } from 'react-router-dom';
7+
8+
const sectionLinks = [
9+
{ name: 'Technology', href: '/#technology' },
10+
{ name: 'Benefits', href: '/#benefits' },
11+
{ name: 'Integration', href: '/#integration' },
12+
];
13+
const pageLinks = [
14+
{ name: 'Team', href: '/team' },
15+
{ name: 'Careers', href: '/careers' },
16+
{ name: 'FAQ', href: '/faq' },
17+
];
618

719
const Footer: React.FC = () => {
20+
const location = useLocation();
21+
const navigate = useNavigate();
22+
823
return (
924
<footer className="bg-dark-800 border-t border-white/10">
1025
<div className="container mx-auto px-4 py-12">
1126
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
1227
{/* Logo and Description */}
1328
<div className="space-y-4 text-center md:text-left">
14-
<Link to="/#/" className="inline-block">
29+
<Link to="/" className="inline-block">
1530
<img
1631
src={logo}
1732
alt="LCM Logo"
@@ -28,25 +43,15 @@ const Footer: React.FC = () => {
2843
<div>
2944
<h3 className="font-display text-lg font-semibold text-white mb-4">Quick Links</h3>
3045
<ul className="space-y-2">
46+
{sectionLinks.map(link => (
47+
<li key={link.name}>
48+
<Link to={link.href} onClick={e => handleNavigation(link.href, e, location, navigate)} className="text-white/70 hover:text-white transition-colors">
49+
{link.name}
50+
</Link>
51+
</li>
52+
))}
3153
<li>
32-
<Link to="/#technology" onClick={(e) => handleNavigation('/#technology', e)} className="text-white/70 hover:text-white transition-colors">
33-
Technology
34-
</Link>
35-
</li>
36-
<li>
37-
<Link to="/#benefits" onClick={(e) => handleNavigation('/#benefits', e)} className="text-white/70 hover:text-white transition-colors">
38-
Benefits
39-
</Link>
40-
</li>
41-
<li>
42-
<Link to="/#integration" onClick={(e) => handleNavigation('/#integration', e)} className="text-white/70 hover:text-white transition-colors">
43-
Integration
44-
</Link>
45-
</li>
46-
<li>
47-
<Link to="#/team" className="text-white/70 hover:text-white transition-colors">
48-
Team
49-
</Link>
54+
<Link to="/team" className="text-white/70 hover:text-white transition-colors">Team</Link>
5055
</li>
5156
</ul>
5257
</div>
@@ -56,19 +61,13 @@ const Footer: React.FC = () => {
5661
<h3 className="font-display text-lg font-semibold text-white mb-4">Company</h3>
5762
<ul className="space-y-2">
5863
<li>
59-
<Link to="#/careers" className="text-white/70 hover:text-white transition-colors">
60-
Careers
61-
</Link>
64+
<Link to="/careers" className="text-white/70 hover:text-white transition-colors">Careers</Link>
6265
</li>
6366
<li>
64-
<Link to="#/faq" className="text-white/70 hover:text-white transition-colors">
65-
FAQ
66-
</Link>
67+
<Link to="/faq" className="text-white/70 hover:text-white transition-colors">FAQ</Link>
6768
</li>
6869
<li>
69-
<Link to="/#contact" onClick={(e) => handleNavigation('/#contact', e)} className="text-white/70 hover:text-white transition-colors">
70-
Contact
71-
</Link>
70+
<Link to="/#contact" onClick={e => handleNavigation('/#contact', e, location, navigate)} className="text-white/70 hover:text-white transition-colors">Contact</Link>
7271
</li>
7372
</ul>
7473
</div>

src/components/layout/Header.tsx

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
import React, { useState, useEffect, useCallback } from 'react';
2-
import { Link, useLocation } from 'react-router-dom';
2+
import { Link, useLocation, useNavigate } from 'react-router-dom';
33
import { Menu, X } from 'lucide-react';
44
import { motion, AnimatePresence } from 'framer-motion';
55
import logo from '../../assets/logo.png';
66
import { handleNavigation } from '../../utils/navigation';
77

88
const navLinks = [
9-
{ name: 'Technology', href: '/#technology' },
10-
{ name: 'Benefits', href: '/#benefits' },
11-
{ name: 'Integration', href: '/#integration' },
12-
{ name: 'Timeline', href: '#/timeline' },
13-
{ name: 'Team', href: '#/team' },
14-
{ name: 'Careers', href: '#/careers' },
15-
{ name: 'FAQ', href: '#/faq' },
9+
{ name: 'Technology', href: '/#technology', isSection: true },
10+
{ name: 'Benefits', href: '/#benefits', isSection: true },
11+
{ name: 'Integration', href: '/#integration', isSection: true },
12+
{ name: 'Timeline', href: '/timeline', isSection: false },
13+
{ name: 'Team', href: '/team', isSection: false },
14+
{ name: 'Careers', href: '/careers', isSection: false },
15+
{ name: 'FAQ', href: '/faq', isSection: false },
1616
];
1717

1818
const Header: React.FC = () => {
1919
const [isOpen, setIsOpen] = useState(false);
2020
const [scrolled, setScrolled] = useState(false);
2121
const location = useLocation();
22+
const navigate = useNavigate();
2223

2324
const toggleMobileMenu = useCallback(() => {
2425
setIsOpen(!isOpen);
@@ -73,18 +74,28 @@ const Header: React.FC = () => {
7374
{/* Desktop Navigation */}
7475
<nav className="hidden md:flex items-center space-x-6">
7576
{navLinks.map((link) => (
76-
<Link
77-
key={link.name}
78-
to={link.href}
79-
className="text-sm font-medium text-white/70 hover:text-white transition-colors"
80-
onClick={(e) => handleNavigation(link.href, e)}
81-
>
82-
{link.name}
83-
</Link>
77+
link.isSection ? (
78+
<Link
79+
key={link.name}
80+
to={link.href}
81+
className="text-sm font-medium text-white/70 hover:text-white transition-colors"
82+
onClick={(e) => handleNavigation(link.href, e, location, navigate)}
83+
>
84+
{link.name}
85+
</Link>
86+
) : (
87+
<Link
88+
key={link.name}
89+
to={link.href}
90+
className="text-sm font-medium text-white/70 hover:text-white transition-colors"
91+
>
92+
{link.name}
93+
</Link>
94+
)
8495
))}
8596
<Link
8697
to="/#contact"
87-
onClick={(e) => handleNavigation('/#contact', e)}
98+
onClick={(e) => handleNavigation('/#contact', e, location, navigate)}
8899
className="px-4 py-2 bg-primary-500 hover:bg-primary-600 text-white rounded-full text-sm font-medium transition-colors"
89100
>
90101
Contact Us
@@ -116,22 +127,33 @@ const Header: React.FC = () => {
116127
<nav className="container mx-auto px-4 py-4">
117128
<div className="flex flex-col space-y-4">
118129
{navLinks.map((link) => (
119-
<Link
120-
key={link.name}
121-
to={link.href}
122-
className="text-base font-medium text-white/70 hover:text-white transition-colors"
123-
onClick={(e) => {
124-
handleNavigation(link.href, e);
125-
closeMobileMenu();
126-
}}
127-
>
128-
{link.name}
129-
</Link>
130+
link.isSection ? (
131+
<Link
132+
key={link.name}
133+
to={link.href}
134+
className="text-base font-medium text-white/70 hover:text-white transition-colors"
135+
onClick={(e) => {
136+
handleNavigation(link.href, e, location, navigate);
137+
closeMobileMenu();
138+
}}
139+
>
140+
{link.name}
141+
</Link>
142+
) : (
143+
<Link
144+
key={link.name}
145+
to={link.href}
146+
className="text-base font-medium text-white/70 hover:text-white transition-colors"
147+
onClick={closeMobileMenu}
148+
>
149+
{link.name}
150+
</Link>
151+
)
130152
))}
131153
<Link
132154
to="/#contact"
133155
onClick={(e) => {
134-
handleNavigation('/#contact', e);
156+
handleNavigation('/#contact', e, location, navigate);
135157
closeMobileMenu();
136158
}}
137159
className="text-base font-medium text-primary-500 hover:text-primary-400 transition-colors"

src/pages/Team.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { motion } from 'framer-motion';
22
import { Users, Rocket, Mail, Linkedin } from 'lucide-react';
3+
import { Link } from 'react-router-dom';
34

45
// Import team images
56
import WesImage from '../assets/Wes.webp';
@@ -246,14 +247,18 @@ const Team: React.FC = () => (
246247
<p className="text-white/70 text-lg mb-8 max-w-2xl mx-auto">
247248
Join our team of innovators and help revolutionize how electric vehicles charge.
248249
</p>
249-
<motion.a
250-
href="#/careers"
250+
<Link
251+
to="/careers"
251252
className="inline-block bg-primary-500 hover:bg-primary-600 text-white px-8 py-3 rounded-full font-medium transition-colors"
252-
whileHover={{ scale: 1.05 }}
253-
whileTap={{ scale: 0.95 }}
254253
>
255-
Join the Team
256-
</motion.a>
254+
<motion.span
255+
whileHover={{ scale: 1.05 }}
256+
whileTap={{ scale: 0.95 }}
257+
className="inline-block"
258+
>
259+
Join the Team
260+
</motion.span>
261+
</Link>
257262
</motion.div>
258263
</div>
259264
</section>

src/utils/navigation.ts

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,51 +3,31 @@ export const scrollToSection = (sectionId: string, offset: number = 80): void =>
33
if (element) {
44
const elementPosition = element.getBoundingClientRect().top;
55
const offsetPosition = elementPosition + window.pageYOffset - offset;
6-
76
window.scrollTo({
87
top: offsetPosition,
9-
behavior: 'smooth'
8+
behavior: 'smooth',
109
});
1110
}
1211
};
1312

14-
export const handleNavigation = (href: string, e: React.MouseEvent): void => {
15-
// Only act on hash links that are for same-page section scrolling.
16-
// These typically look like "#section-id" or "/#section-id".
17-
// HashRouter page links look like "#/page-route".
18-
if (href.startsWith('#') && href.indexOf('/') === -1) { // No slash after #
19-
e.preventDefault();
20-
const sectionId = href.substring(1);
21-
scrollToSection(sectionId);
22-
} else if (href.startsWith('/#') && href.indexOf('/', 2) === -1) { // For links like /#section-id from other pages
13+
// For BrowserRouter: only intercept /#section links for scrolling
14+
export const handleNavigation = (href: string, e: React.MouseEvent, location?: any, navigate?: any): void => {
15+
if (href.startsWith('/#')) {
2316
e.preventDefault();
24-
// First, navigate to homepage if not already there (HashRouter handles this with Link to="/")
25-
// Then, scroll to section. This part needs care with HashRouter and Link component.
26-
// The Link component should handle going to "/" (which becomes /#/) and then ScrollToTop/useEffect can handle the actual scroll.
27-
// For now, let's ensure it correctly scrolls if already on the homepage or if the Link component itself handles the root navigation.
28-
const sectionId = href.substring(href.lastIndexOf('#') + 1);
29-
const targetPath = href.substring(0, href.lastIndexOf('#'));
30-
31-
// If Link is to "/#section", and current path is already "/" (or "/#/")
32-
// Allow Link to navigate to "/#/". The ScrollToTop or a similar mechanism should handle the scroll to sectionId.
33-
// The main goal here is NOT to preventDefault for full page hash navigations like '#/careers'.
34-
if (window.location.hash === '#/' || window.location.hash === '' || window.location.pathname === '/') {
35-
scrollToSection(sectionId);
17+
const sectionId = href.split('#')[1];
18+
if (location && location.pathname !== '/') {
19+
// If not on homepage, navigate to homepage then scroll after navigation
20+
if (navigate) navigate('/');
21+
setTimeout(() => scrollToSection(sectionId), 100); // Delay to allow navigation
22+
} else {
23+
scrollToSection(sectionId);
3624
}
37-
// If it's a link like "/#contact" from a page like "/team" (i.e. current hash is "#/team")
38-
// the <Link to="/#contact"> will correctly change the hash to "/#contact".
39-
// Then ScrollToTop logic in App.tsx needs to pick up the section from the hash state after the page potentially re-renders.
40-
// The `handleNavigation` itself doesn't need to do much more for these `/#[section]` links when using React Router's <Link>
4125
}
42-
// If it's a link like "#/careers", the conditions above won't match, so default Link behavior proceeds.
26+
// Otherwise, let React Router handle navigation
4327
};
4428

4529
export const scrollToContact = (inquiryType?: string): void => {
46-
// Ensure we scroll to the contact section on the current page (expected to be homepage)
47-
// If called from another page, the navigation to homepage + section scroll should be handled by a Link component.
48-
// This utility is best used when already on the page with the contact section.
4930
scrollToSection('contact');
50-
5131
if (inquiryType) {
5232
const selectElement = document.getElementById('inquiryType') as HTMLSelectElement;
5333
if (selectElement) {

0 commit comments

Comments
 (0)