Add NotFound page with picture

- Create NotFound component that displays not-found.png
- Add SCSS styles for the NotFound page
- Update App.jsx to show NotFound page for invalid routes instead of redirecting

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
2026-08-09 21:29:43 +03:00
parent 666a53592d
commit fca87f49d9
3 changed files with 73 additions and 9 deletions

View File

@@ -7,6 +7,7 @@ import Hero from './components/Hero';
import About from './components/About'; import About from './components/About';
import Projects from './components/Projects'; import Projects from './components/Projects';
import Contact from './components/Contact'; import Contact from './components/Contact';
import NotFound from './components/NotFound';
import Footer from './components/Footer'; import Footer from './components/Footer';
import styles from './App.module.scss'; import styles from './App.module.scss';
@@ -27,18 +28,15 @@ export default function App() {
const [displayedSection, setDisplayedSection] = useState(activeSection); const [displayedSection, setDisplayedSection] = useState(activeSection);
const timerRef = useRef(null); const timerRef = useRef(null);
const path = location.pathname.substring(1) || 'home';
const notFound = !Object.keys(SECTIONS).includes(path);
// Sync URL path with activeSection // Sync URL path with activeSection
useEffect(() => { useEffect(() => {
const path = location.pathname.substring(1) || 'home'; if (!notFound && path !== activeSection) {
if (Object.keys(SECTIONS).includes(path)) {
if (path !== activeSection) {
setActiveSection(path); setActiveSection(path);
} }
} else { }, [location.pathname, activeSection, setActiveSection, navigate, path, notFound]);
// Invalid path, redirect to home
navigate('/');
}
}, [location.pathname, activeSection, setActiveSection, navigate]);
useEffect(() => { useEffect(() => {
if (theme === 'light') { if (theme === 'light') {
@@ -59,6 +57,18 @@ export default function App() {
const isExiting = activeSection !== displayedSection; const isExiting = activeSection !== displayedSection;
const Section = SECTIONS[displayedSection] ?? Hero; const Section = SECTIONS[displayedSection] ?? Hero;
if (notFound) {
return (
<>
<Navbar />
<main className={styles.enter}>
<NotFound />
</main>
<Footer />
</>
);
}
return ( return (
<> <>
<Navbar /> <Navbar />

View File

@@ -0,0 +1,15 @@
import styles from '../styles/components/NotFound.module.scss';
export default function NotFound() {
return (
<section id="not-found" className={styles.notFound}>
<div className={styles.inner}>
<div className={styles.imageContainer}>
<img src="/not-found.png" alt="Not found" className={styles.image} />
</div>
<h1 className={styles.title}>Page Not Found</h1>
<p className={styles.message}>The page you're looking for doesn't exist.</p>
</div>
</section>
);
}

View File

@@ -0,0 +1,39 @@
@use '../variables' as *;
.notFound {
padding: $space-24 $space-6;
min-height: 70vh;
display: flex;
align-items: center;
justify-content: center;
}
.inner {
max-width: $max-width;
margin: 0 auto;
text-align: center;
}
.imageContainer {
margin-bottom: $space-8;
}
.image {
max-width: 100%;
height: auto;
border-radius: $radius-lg;
box-shadow: 0 0 30px rgb(var(--color-primary-mid) / 0.2);
}
.title {
font-size: $text-4xl;
font-weight: 700;
color: $color-text;
margin-bottom: $space-4;
}
.message {
font-size: $text-lg;
color: $color-text-muted;
line-height: 1.6;
}