Skip to content

Commit c5f3838

Browse files
committed
Fix (Project Routing Issue)
1 parent 0241511 commit c5f3838

File tree

5 files changed

+62
-33
lines changed

5 files changed

+62
-33
lines changed

src/components/common/PageTransition.jsx

+17-5
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,40 @@ const PageTransition = ({ children }) => {
99
const containerRef = useRef(null);
1010
const contentRef = useRef(null);
1111
const { reducedMotion } = useAnimationContext();
12+
const previousScrollY = useRef(0);
13+
14+
// Save scroll position before transition
15+
useEffect(() => {
16+
previousScrollY.current = window.scrollY;
17+
}, [location.pathname]);
1218

1319
// Apply enter animation when the component mounts or location changes
1420
useEffect(() => {
1521
if (!containerRef.current || !contentRef.current) return;
1622

1723
// Reset positions
1824
gsap.set(containerRef.current, { perspective: 1000 });
19-
gsap.set(contentRef.current, { opacity: 0, y: 30 });
25+
gsap.set(contentRef.current, { opacity: 0 });
2026

2127
// Create timeline for entrance animation
2228
const timeline = gsap.timeline({
2329
defaults: {
2430
duration: reducedMotion ? 0.2 : 0.5,
2531
ease: 'power2.out',
2632
},
33+
onComplete: () => {
34+
// Restore scroll position if needed (for browser back button)
35+
if (window.history.scrollRestoration === 'manual' && previousScrollY.current > 0) {
36+
window.scrollTo(0, previousScrollY.current);
37+
}
38+
}
2739
});
2840

2941
// Simple fade in for reduced motion, more complex animation otherwise
3042
if (reducedMotion) {
31-
timeline.to(contentRef.current, { opacity: 1, y: 0 });
43+
timeline.to(contentRef.current, { opacity: 1 });
3244
} else {
33-
timeline.to(contentRef.current, { opacity: 1, y: 0 });
45+
timeline.to(contentRef.current, { opacity: 1 });
3446

3547
// Find and animate headings and elements with animate-in class if they exist
3648
const animateElements = contentRef.current.querySelectorAll('h1, h2, h3, .animate-in');
@@ -56,10 +68,10 @@ const PageTransition = ({ children }) => {
5668
}, [location.pathname, reducedMotion]);
5769

5870
return (
59-
<Box ref={containerRef} sx={{ width: '100%', minHeight: '80vh' }}>
71+
<Box ref={containerRef} sx={{ width: '100%', minHeight: '80vh', position: 'relative' }}>
6072
<Box ref={contentRef}>{children}</Box>
6173
</Box>
6274
);
6375
};
6476

65-
export default PageTransition;
77+
export default PageTransition;

src/components/projects/ProjectDetail.jsx

+5-4
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,15 @@ const ProjectDetail = ({ project, onBack }) => {
3838
// Animate entrance
3939
useEffect(() => {
4040
if (!containerRef.current || reducedMotion) return;
41-
41+
4242
const elements = containerRef.current.querySelectorAll('.animate-in');
43-
43+
4444
gsap.fromTo(
4545
elements,
46-
{ opacity: 0, y: 30 },
47-
{ opacity: 1, y: 0, stagger: 0.1, duration: 0.5, ease: 'power3.out' }
46+
{ opacity: 0 },
47+
{ opacity: 1, stagger: 0.1, duration: 0.5, ease: 'power3.out' }
4848
);
49+
4950
}, [project, reducedMotion]);
5051

5152
if (!project) return null;

src/context/AnimationContext.jsx

+15-6
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,11 @@ export function AnimationProvider({ children }) {
5252
let lastScrollTop = window.pageYOffset;
5353
let lastScrollTime = performance.now();
5454
let frameId = null;
55+
let scrolling = false;
5556

5657
const updateScroll = () => {
58+
if (!scrolling) return;
59+
5760
const currentScrollTop = window.pageYOffset;
5861
const currentTime = performance.now();
5962
const timeDelta = currentTime - lastScrollTime;
@@ -77,15 +80,21 @@ export function AnimationProvider({ children }) {
7780

7881
lastScrollTop = currentScrollTop;
7982
lastScrollTime = currentTime;
83+
84+
// Reset the frame ID and scrolling flag
85+
frameId = null;
86+
scrolling = false;
8087
};
8188

8289
const handleScroll = () => {
83-
// Use requestAnimationFrame for performance
84-
if (frameId) {
85-
cancelAnimationFrame(frameId);
90+
// Mark that we're scrolling but don't do anything else to prevent
91+
// interfering with the native scroll
92+
scrolling = true;
93+
94+
// Use requestAnimationFrame for performance, but only if we don't have one pending
95+
if (!frameId) {
96+
frameId = requestAnimationFrame(updateScroll);
8697
}
87-
88-
frameId = requestAnimationFrame(updateScroll);
8998
};
9099

91100
// Initial call
@@ -145,4 +154,4 @@ export function AnimationProvider({ children }) {
145154
}
146155

147156
// eslint-disable-next-line react-refresh/only-export-components
148-
export const useAnimationContext = () => useContext(AnimationContext);
157+
export const useAnimationContext = () => useContext(AnimationContext);

src/hooks/useProjectDetail.jsx

+1-7
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,7 @@ export const useProjectDetail = () => {
4747
const returnToGallery = () => {
4848
setViewMode('gallery');
4949

50-
// Delay clearing the selected project to allow for transition
51-
setTimeout(() => {
52-
setSelectedProject(null);
53-
}, 300);
54-
55-
// Scroll to top when returning to gallery
56-
window.scrollTo({ top: 0, behavior: 'smooth' });
50+
setSelectedProject(null);
5751
};
5852

5953
return {

src/pages/Projects.jsx

+24-11
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import ProjectDetail from '../components/projects/ProjectDetail';
1616
import ProjectModal from '../components/projects/ProjectModal';
1717

1818
const Projects = () => {
19-
const { _reducedMotion } = useAnimationContext();
19+
const { reducedMotion } = useAnimationContext();
2020
const [isLoading, setIsLoading] = useState(true);
2121
const [error, setError] = useState(null);
2222
const navigate = useNavigate();
@@ -56,7 +56,7 @@ const Projects = () => {
5656
(projectId, action = 'page') => {
5757
if (action === 'reset') {
5858
resetFilters();
59-
navigate('/projects');
59+
navigate('/projects', { replace: true });
6060
return;
6161
}
6262

@@ -78,25 +78,38 @@ const Projects = () => {
7878
[navigate, location.search, resetFilters, openProjectModal, projectsData, viewProjectDetails]
7979
);
8080

81-
// Initialize project data and hooks
81+
// Check for direct project link in URL or reset view mode
8282
useEffect(() => {
83-
if (!projectsLoading) {
84-
setIsLoading(false);
83+
// If we're not on a specific project page, ensure we're in gallery mode
84+
if (!location.search && viewMode !== 'gallery') {
85+
returnToGallery();
8586
}
86-
87+
8788
// Check for direct project link in URL
8889
const urlParams = new URLSearchParams(location.search);
8990
const projectId = urlParams.get('project');
91+
9092
if (projectId && projectsData && projectsData.length > 0) {
93+
// If we have a project ID in the URL and data is loaded, show the project
9194
handleViewDetails(projectId);
9295
}
93-
}, [projectsLoading, projectsData, location.search, handleViewDetails]);
96+
97+
// Set loading state based on projects data
98+
if (!projectsLoading) {
99+
setIsLoading(false);
100+
}
101+
}, [projectsLoading, projectsData, location.search, handleViewDetails, viewMode, returnToGallery]);
94102

95-
// Handle back to gallery
103+
// Handle back to gallery with proper state management
96104
const handleBackToGallery = () => {
97-
// Update URL to remove project parameter
98-
navigate('/projects');
105+
// First reset state - this is important to do BEFORE navigation
99106
returnToGallery();
107+
108+
// Then update URL (after state is reset)
109+
// This prevents the temporary blank page
110+
setTimeout(() => {
111+
navigate('/projects', { replace: true });
112+
}, 0);
100113
};
101114

102115
return (
@@ -276,4 +289,4 @@ const Projects = () => {
276289
);
277290
};
278291

279-
export default Projects;
292+
export default Projects;

0 commit comments

Comments
 (0)