Fix Page Transition and Mobile Version.
This commit is contained in:
+1
-1
@@ -82,7 +82,7 @@ define(['./workbox-4a2e5f00'], (function (workbox) { 'use strict';
|
|||||||
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
||||||
}, {
|
}, {
|
||||||
"url": "index.html",
|
"url": "index.html",
|
||||||
"revision": "0.vc3cdld58co"
|
"revision": "0.364nagk4too"
|
||||||
}], {});
|
}], {});
|
||||||
workbox.cleanupOutdatedCaches();
|
workbox.cleanupOutdatedCaches();
|
||||||
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
+1
-2
@@ -1,3 +1,4 @@
|
|||||||
|
// App.tsx
|
||||||
import { useEffect, Suspense } from 'react';
|
import { useEffect, Suspense } from 'react';
|
||||||
import { BrowserRouter } from 'react-router-dom';
|
import { BrowserRouter } from 'react-router-dom';
|
||||||
import { HelmetProvider } from 'react-helmet-async';
|
import { HelmetProvider } from 'react-helmet-async';
|
||||||
@@ -12,8 +13,6 @@ import './styles/scrollbar.css';
|
|||||||
function App() {
|
function App() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
logPageView();
|
logPageView();
|
||||||
|
|
||||||
// Stellt sicher, dass die Scrollbar von Anfang an konsistent ist
|
|
||||||
document.documentElement.classList.add('custom-scrollbar');
|
document.documentElement.classList.add('custom-scrollbar');
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// C:\Development\Damjan Savic\Portfolio\src\components\LanguageSwitcher.tsx
|
||||||
import React, { useRef, useState } from 'react';
|
import React, { useRef, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Globe } from 'lucide-react';
|
import { Globe } from 'lucide-react';
|
||||||
@@ -36,13 +37,13 @@ const LanguageSwitcher: React.FC = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative" ref={dropdownRef}>
|
<div className="relative inline-block" ref={dropdownRef}>
|
||||||
<motion.button
|
<motion.button
|
||||||
whileHover={{ scale: 1.05 }}
|
whileHover={{ scale: 1.05 }}
|
||||||
whileTap={{ scale: 0.95 }}
|
whileTap={{ scale: 0.95 }}
|
||||||
className="flex items-center space-x-2 text-zinc-400 hover:text-white
|
className="flex items-center space-x-2 text-zinc-400 hover:text-white
|
||||||
px-4 py-2 rounded-full transition-colors duration-200
|
px-4 py-2 rounded-full transition-colors duration-200
|
||||||
hover:bg-zinc-800/50 border border-transparent hover:border-zinc-800"
|
hover:bg-zinc-800/50 border border-transparent hover:border-zinc-800"
|
||||||
onClick={() => setIsOpen(!isOpen)}
|
onClick={() => setIsOpen(!isOpen)}
|
||||||
aria-expanded={isOpen}
|
aria-expanded={isOpen}
|
||||||
aria-haspopup="listbox"
|
aria-haspopup="listbox"
|
||||||
@@ -55,11 +56,11 @@ const LanguageSwitcher: React.FC = () => {
|
|||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: -10 }}
|
initial={{ opacity: 0, y: 10 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
exit={{ opacity: 0, y: -10 }}
|
exit={{ opacity: 0, y: 10 }}
|
||||||
transition={{ duration: 0.2 }}
|
transition={{ duration: 0.2 }}
|
||||||
className="absolute right-0 mt-2 w-48 rounded-lg overflow-hidden
|
className="absolute bottom-full right-0 mb-2 w-48 rounded-lg overflow-hidden
|
||||||
border border-zinc-800 bg-zinc-900/95 backdrop-blur-sm
|
border border-zinc-800 bg-zinc-900/95 backdrop-blur-sm
|
||||||
shadow-lg"
|
shadow-lg"
|
||||||
role="listbox"
|
role="listbox"
|
||||||
|
|||||||
+60
-30
@@ -1,14 +1,13 @@
|
|||||||
// components/Layout.tsx
|
// components/Layout.tsx
|
||||||
import { useEffect, useState, ReactNode } from "react";
|
import { useEffect, useState, ReactNode, useCallback } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { motion, AnimatePresence } from "framer-motion";
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
import { Menu, X, Home, User, Briefcase, BookOpen, Phone, LayoutDashboard } from "lucide-react";
|
import { Menu, X, Home, User, Briefcase, BookOpen, Phone, LayoutDashboard } from "lucide-react";
|
||||||
import { supabase } from "../utils/supabaseClient";
|
import { supabase } from "../utils/supabaseClient";
|
||||||
import { ContactInfo } from "../components/ContactInfo";
|
import { ContactInfo } from "./ContactInfo";
|
||||||
import { NavLink } from "../components/NavLink";
|
import { NavLink } from "./NavLink";
|
||||||
import LanguageSwitcher from "./LanguageSwitcher";
|
import LanguageSwitcher from "./LanguageSwitcher";
|
||||||
import { Link } from "react-router-dom";
|
import { Link, useLocation } from "react-router-dom";
|
||||||
import Footer from "./Footer";
|
|
||||||
|
|
||||||
interface LayoutProps {
|
interface LayoutProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@@ -19,6 +18,38 @@ const Layout = ({ children }: LayoutProps) => {
|
|||||||
const [isAdmin, setIsAdmin] = useState(false);
|
const [isAdmin, setIsAdmin] = useState(false);
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [scrolled, setScrolled] = useState(false);
|
const [scrolled, setScrolled] = useState(false);
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
|
// Memoized toggle function
|
||||||
|
const toggleMenu = useCallback((force?: boolean) => {
|
||||||
|
setIsOpen(prev => typeof force === 'boolean' ? force : !prev);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Route change handler
|
||||||
|
useEffect(() => {
|
||||||
|
toggleMenu(false);
|
||||||
|
}, [location.pathname, toggleMenu]);
|
||||||
|
|
||||||
|
// Scroll lock effect
|
||||||
|
useEffect(() => {
|
||||||
|
const body = document.body;
|
||||||
|
if (isOpen) {
|
||||||
|
const scrollY = window.scrollY;
|
||||||
|
body.style.position = 'fixed';
|
||||||
|
body.style.top = `-${scrollY}px`;
|
||||||
|
body.style.width = '100%';
|
||||||
|
body.style.overflow = 'hidden';
|
||||||
|
} else {
|
||||||
|
const scrollY = body.style.top;
|
||||||
|
body.style.position = '';
|
||||||
|
body.style.top = '';
|
||||||
|
body.style.width = '';
|
||||||
|
body.style.overflow = '';
|
||||||
|
if (scrollY) {
|
||||||
|
window.scrollTo(0, parseInt(scrollY || '0') * -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [isOpen]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const checkAdmin = async () => {
|
const checkAdmin = async () => {
|
||||||
@@ -71,7 +102,7 @@ const Layout = ({ children }: LayoutProps) => {
|
|||||||
<div className="min-h-screen bg-zinc-900 flex flex-col">
|
<div className="min-h-screen bg-zinc-900 flex flex-col">
|
||||||
<nav
|
<nav
|
||||||
className={`
|
className={`
|
||||||
fixed w-full z-50 transition-all duration-300
|
fixed w-full z-[80] transition-all duration-300
|
||||||
${scrolled
|
${scrolled
|
||||||
? "bg-zinc-900/80 backdrop-blur supports-[backdrop-filter]:bg-zinc-900/80"
|
? "bg-zinc-900/80 backdrop-blur supports-[backdrop-filter]:bg-zinc-900/80"
|
||||||
: "bg-transparent"
|
: "bg-transparent"
|
||||||
@@ -91,7 +122,6 @@ const Layout = ({ children }: LayoutProps) => {
|
|||||||
transition={{ type: "spring", stiffness: 400, damping: 10 }}
|
transition={{ type: "spring", stiffness: 400, damping: 10 }}
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<div className="hidden md:flex items-center gap-2">
|
<div className="hidden md:flex items-center gap-2">
|
||||||
{navigationLinks.map(({ path, label, icon }) => (
|
{navigationLinks.map(({ path, label, icon }) => (
|
||||||
<NavLink key={path} to={path} icon={icon} label={label} className="text-sm" />
|
<NavLink key={path} to={path} icon={icon} label={label} className="text-sm" />
|
||||||
@@ -100,10 +130,9 @@ const Layout = ({ children }: LayoutProps) => {
|
|||||||
<LanguageSwitcher />
|
<LanguageSwitcher />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<motion.button
|
<motion.button
|
||||||
className="md:hidden p-2 rounded-lg text-zinc-400 hover:text-white hover:bg-zinc-800/50 transition-colors"
|
className="md:hidden relative z-[85] p-2 rounded-lg text-zinc-400 hover:text-white hover:bg-zinc-800/50 transition-colors"
|
||||||
onClick={() => setIsOpen(!isOpen)}
|
onClick={() => toggleMenu()}
|
||||||
aria-expanded={isOpen}
|
aria-expanded={isOpen}
|
||||||
aria-controls="mobile-menu"
|
aria-controls="mobile-menu"
|
||||||
aria-label={isOpen ? "Close menu" : "Open menu"}
|
aria-label={isOpen ? "Close menu" : "Open menu"}
|
||||||
@@ -122,31 +151,33 @@ const Layout = ({ children }: LayoutProps) => {
|
|||||||
animate={{ opacity: 1 }}
|
animate={{ opacity: 1 }}
|
||||||
exit={{ opacity: 0 }}
|
exit={{ opacity: 0 }}
|
||||||
transition={{ duration: 0.2 }}
|
transition={{ duration: 0.2 }}
|
||||||
className="fixed inset-0 bg-black/50 md:hidden"
|
className="fixed inset-0 bg-black/50 md:hidden z-[75]"
|
||||||
onClick={() => setIsOpen(false)}
|
onClick={() => toggleMenu(false)}
|
||||||
/>
|
/>
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ x: "100%" }}
|
initial={{ x: "100%" }}
|
||||||
animate={{ x: 0 }}
|
animate={{ x: 0 }}
|
||||||
exit={{ x: "100%" }}
|
exit={{ x: "100%" }}
|
||||||
transition={{ type: "spring", stiffness: 300, damping: 30 }}
|
transition={{ type: "spring", stiffness: 300, damping: 30 }}
|
||||||
className="fixed right-0 top-16 h-[calc(100vh-4rem)] w-80 bg-zinc-900 shadow-xl md:hidden overflow-y-auto border-l border-zinc-800"
|
className="fixed right-0 top-0 h-full w-80 bg-zinc-900 shadow-xl md:hidden overflow-y-auto border-l border-zinc-800 z-[75]"
|
||||||
>
|
>
|
||||||
<div className="flex flex-col h-full">
|
<div className="flex flex-col h-full pt-16">
|
||||||
<ContactInfo />
|
<div className="flex-1 overflow-y-auto">
|
||||||
<div className="flex-1 py-4 px-4">
|
<ContactInfo />
|
||||||
{navigationLinks.map(({ path, label, icon }) => (
|
<div className="py-4 px-4">
|
||||||
<NavLink
|
{navigationLinks.map(({ path, label, icon }) => (
|
||||||
key={path}
|
<NavLink
|
||||||
to={path}
|
key={path}
|
||||||
icon={icon}
|
to={path}
|
||||||
label={label}
|
icon={icon}
|
||||||
onClick={() => setIsOpen(false)}
|
label={label}
|
||||||
className="flex items-center w-full mb-1"
|
onClick={() => toggleMenu(false)}
|
||||||
/>
|
className="flex items-center w-full mb-1"
|
||||||
))}
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="border-t border-zinc-800 p-6">
|
<div className="border-t border-zinc-800 p-6 mt-auto">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<span className="text-sm text-zinc-500">Sprache ändern</span>
|
<span className="text-sm text-zinc-500">Sprache ändern</span>
|
||||||
<LanguageSwitcher />
|
<LanguageSwitcher />
|
||||||
@@ -158,10 +189,9 @@ const Layout = ({ children }: LayoutProps) => {
|
|||||||
)}
|
)}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
</nav>
|
</nav>
|
||||||
<main className="flex-1 pt-16">{children}</main>
|
{children}
|
||||||
<Footer />
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Layout;
|
export default Layout;
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// components/PageContainer.tsx
|
||||||
|
import React from 'react';
|
||||||
|
import Footer from './Footer';
|
||||||
|
|
||||||
|
interface PageContainerProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PageContainer = ({ children }: PageContainerProps) => {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col min-h-screen">
|
||||||
|
<main className="flex-1 pt-16">
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PageContainer;
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
"use client"
|
"use client"
|
||||||
import type React from "react"
|
import React, { useEffect, useState } from "react"
|
||||||
import { useEffect, useState } from "react"
|
|
||||||
import { motion, AnimatePresence, cubicBezier } from "framer-motion"
|
import { motion, AnimatePresence, cubicBezier } from "framer-motion"
|
||||||
import { useLocation } from "react-router-dom"
|
import { useLocation } from "react-router-dom"
|
||||||
|
|
||||||
interface PageTransitionProps {
|
interface PageTransitionProps {
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
const customEase = cubicBezier(0.25, 0.1, 0.25, 1)
|
const customEase = cubicBezier(0.25, 0.1, 0.25, 1)
|
||||||
@@ -14,113 +13,83 @@ const Logo = () => (
|
|||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, scale: 0.8 }}
|
initial={{ opacity: 0, scale: 0.8 }}
|
||||||
animate={{
|
animate={{
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
scale: 1,
|
scale: 1,
|
||||||
transition: { duration: 0.3, ease: customEase },
|
transition: { duration: 0.4, ease: customEase },
|
||||||
}}
|
}}
|
||||||
exit={{
|
exit={{
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
scale: 1.2,
|
scale: 1.2,
|
||||||
transition: { duration: 0.3, ease: customEase },
|
transition: { duration: 0.3, ease: customEase },
|
||||||
}}
|
}}
|
||||||
className="w-16 h-16"
|
className="w-16 h-16"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src="/logo.png"
|
src="/logo.png"
|
||||||
alt="Logo"
|
alt="Logo"
|
||||||
className="w-full h-full object-contain filter brightness-200"
|
className="w-full h-full object-contain filter brightness-200"
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const PageTransition = ({ children }: PageTransitionProps) => {
|
const PageTransition = ({ children }: PageTransitionProps) => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const [isTransitioning, setIsTransitioning] = useState(true)
|
const [isAnimating, setIsAnimating] = useState(false)
|
||||||
const [isOverlayActive, setIsOverlayActive] = useState(true)
|
const [showContent, setShowContent] = useState(true)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsTransitioning(true)
|
setIsAnimating(true)
|
||||||
setIsOverlayActive(true)
|
setShowContent(false)
|
||||||
|
|
||||||
const overlayTimer = setTimeout(() => {
|
const contentTimer = setTimeout(() => {
|
||||||
setIsOverlayActive(false)
|
setShowContent(true)
|
||||||
}, 1200) // Overlay animation duration
|
}, 800)
|
||||||
|
|
||||||
const transitionTimer = setTimeout(() => {
|
const animationTimer = setTimeout(() => {
|
||||||
setIsTransitioning(false)
|
setIsAnimating(false)
|
||||||
}, 800)
|
}, 1000)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
clearTimeout(overlayTimer)
|
clearTimeout(contentTimer)
|
||||||
clearTimeout(transitionTimer)
|
clearTimeout(animationTimer)
|
||||||
}
|
}
|
||||||
}, [location])
|
}, [location.pathname])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AnimatePresence mode="wait">
|
<div className="relative min-h-screen bg-zinc-900">
|
||||||
<motion.div key={location.pathname} className="relative">
|
{/* Overlay mit Logo */}
|
||||||
{/* Transition Container */}
|
|
||||||
<div className={`fixed inset-0 pointer-events-none ${isOverlayActive ? 'z-50' : '-z-10'}`}>
|
|
||||||
{/* Overlay Animation */}
|
|
||||||
<motion.div
|
|
||||||
className="absolute inset-0 bg-zinc-900"
|
|
||||||
initial={{ opacity: 0 }}
|
|
||||||
animate={{
|
|
||||||
opacity: [0, 1, 1, 0],
|
|
||||||
transition: {
|
|
||||||
duration: 1.2,
|
|
||||||
times: [0, 0.3, 0.7, 1],
|
|
||||||
ease: customEase,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Logo */}
|
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{isTransitioning && (
|
{isAnimating && (
|
||||||
<motion.div
|
<motion.div
|
||||||
className="absolute inset-0 flex items-center justify-center"
|
key="overlay"
|
||||||
initial={{ opacity: 0 }}
|
className="fixed inset-0 z-[60] bg-zinc-900 flex items-center justify-center"
|
||||||
animate={{
|
initial={{ opacity: 0 }}
|
||||||
opacity: 1,
|
animate={{ opacity: 1 }}
|
||||||
transition: {
|
exit={{ opacity: 0 }}
|
||||||
delay: 0.3,
|
transition={{ duration: 0.3 }}
|
||||||
duration: 0.3,
|
>
|
||||||
},
|
<Logo />
|
||||||
}}
|
</motion.div>
|
||||||
exit={{
|
)}
|
||||||
opacity: 0,
|
|
||||||
transition: {
|
|
||||||
duration: 0.3,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Logo />
|
|
||||||
</motion.div>
|
|
||||||
)}
|
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Page Content */}
|
{/* Content */}
|
||||||
<motion.div
|
<AnimatePresence mode="wait">
|
||||||
className="relative"
|
{showContent && (
|
||||||
initial={{ opacity: 0, y: 20 }}
|
<motion.div
|
||||||
animate={{
|
key={location.pathname}
|
||||||
opacity: 1,
|
className="relative z-0"
|
||||||
y: 0,
|
initial={{ opacity: 0 }}
|
||||||
transition: {
|
animate={{ opacity: 1 }}
|
||||||
duration: 0.4,
|
exit={{ opacity: 0 }}
|
||||||
delay: 0.8,
|
transition={{ duration: 0.3 }}
|
||||||
ease: customEase,
|
>
|
||||||
},
|
{children}
|
||||||
}}
|
</motion.div>
|
||||||
exit={{ opacity: 0, y: -20, transition: { duration: 0.3 } }}
|
)}
|
||||||
>
|
</AnimatePresence>
|
||||||
{children}
|
</div>
|
||||||
</motion.div>
|
)
|
||||||
</motion.div>
|
|
||||||
</AnimatePresence>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PageTransition
|
export default PageTransition
|
||||||
+4
-7
@@ -1,5 +1,4 @@
|
|||||||
// Umbenennen zu main.tsx
|
// main.tsx
|
||||||
import { StrictMode } from 'react';
|
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
import { HelmetProvider } from 'react-helmet-async';
|
import { HelmetProvider } from 'react-helmet-async';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
@@ -14,11 +13,9 @@ if (!rootElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createRoot(rootElement).render(
|
createRoot(rootElement).render(
|
||||||
<StrictMode>
|
<HelmetProvider>
|
||||||
<HelmetProvider>
|
<App />
|
||||||
<App />
|
</HelmetProvider>
|
||||||
</HelmetProvider>
|
|
||||||
</StrictMode>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Register service worker
|
// Register service worker
|
||||||
|
|||||||
+12
-11
@@ -2,6 +2,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Routes, Route } from 'react-router-dom';
|
import { Routes, Route } from 'react-router-dom';
|
||||||
import RouteErrorBoundary from './components/RouteErrorBoundary';
|
import RouteErrorBoundary from './components/RouteErrorBoundary';
|
||||||
|
import PageContainer from './components/PageContainer';
|
||||||
|
|
||||||
// Lazy load components
|
// Lazy load components
|
||||||
const HomePage = React.lazy(() => import('./pages/home'));
|
const HomePage = React.lazy(() => import('./pages/home'));
|
||||||
@@ -19,17 +20,17 @@ const TermsPage = React.lazy(() => import('./pages/TermsPage'));
|
|||||||
const AppRoutes = () => {
|
const AppRoutes = () => {
|
||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<HomePage />} errorElement={<RouteErrorBoundary />} />
|
<Route path="/" element={<PageContainer><HomePage /></PageContainer>} errorElement={<RouteErrorBoundary />} />
|
||||||
<Route path="/about" element={<AboutPage />} errorElement={<RouteErrorBoundary />} />
|
<Route path="/about" element={<PageContainer><AboutPage /></PageContainer>} errorElement={<RouteErrorBoundary />} />
|
||||||
<Route path="/portfolio" element={<PortfolioPage />} errorElement={<RouteErrorBoundary />} />
|
<Route path="/portfolio" element={<PageContainer><PortfolioPage /></PageContainer>} errorElement={<RouteErrorBoundary />} />
|
||||||
<Route path="/portfolio/:slug" element={<ProjectPage />} errorElement={<RouteErrorBoundary />} />
|
<Route path="/portfolio/:slug" element={<PageContainer><ProjectPage /></PageContainer>} errorElement={<RouteErrorBoundary />} />
|
||||||
<Route path="/blog" element={<BlogPage />} errorElement={<RouteErrorBoundary />} />
|
<Route path="/blog" element={<PageContainer><BlogPage /></PageContainer>} errorElement={<RouteErrorBoundary />} />
|
||||||
<Route path="/blog/:slug" element={<BlogPostPage />} errorElement={<RouteErrorBoundary />} />
|
<Route path="/blog/:slug" element={<PageContainer><BlogPostPage /></PageContainer>} errorElement={<RouteErrorBoundary />} />
|
||||||
<Route path="/contact" element={<ContactPage />} errorElement={<RouteErrorBoundary />} />
|
<Route path="/contact" element={<PageContainer><ContactPage /></PageContainer>} errorElement={<RouteErrorBoundary />} />
|
||||||
<Route path="/login" element={<LoginPage />} errorElement={<RouteErrorBoundary />} />
|
<Route path="/login" element={<PageContainer><LoginPage /></PageContainer>} errorElement={<RouteErrorBoundary />} />
|
||||||
<Route path="/dashboard" element={<DashboardPage />} errorElement={<RouteErrorBoundary />} />
|
<Route path="/dashboard" element={<PageContainer><DashboardPage /></PageContainer>} errorElement={<RouteErrorBoundary />} />
|
||||||
<Route path="/privacy" element={<PrivacyPolicyPage />} errorElement={<RouteErrorBoundary />} />
|
<Route path="/privacy" element={<PageContainer><PrivacyPolicyPage /></PageContainer>} errorElement={<RouteErrorBoundary />} />
|
||||||
<Route path="/terms" element={<TermsPage />} errorElement={<RouteErrorBoundary />} />
|
<Route path="/terms" element={<PageContainer><TermsPage /></PageContainer>} errorElement={<RouteErrorBoundary />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user