11import { useEffect , useRef } from 'react' ;
2+ import { MotionConfig } from 'motion/react' ;
23import { HashRouter as Router , Routes , Route , Navigate , useLocation } from 'react-router-dom' ;
34import { Navigation } from './components/Navigation' ;
45import { Footer } from './components/Footer' ;
@@ -56,11 +57,13 @@ function AppContent() {
5657 } ;
5758 } , [ location . pathname , isDetailPage ] ) ;
5859
59- // Disable right-click context menu on all pages
60+ // Scoped context menu prevention: only on images to avoid interfering with assistive tech
6061 useEffect ( ( ) => {
6162 const handleContextMenu = ( e : MouseEvent ) => {
62- e . preventDefault ( ) ;
63- return false ;
63+ const target = e . target as HTMLElement ;
64+ if ( target . closest ( 'img' ) ) {
65+ e . preventDefault ( ) ;
66+ }
6467 } ;
6568
6669 document . addEventListener ( 'contextmenu' , handleContextMenu ) ;
@@ -75,10 +78,49 @@ function AppContent() {
7578 preloadCriticalImages ( ) ;
7679 } , [ ] ) ;
7780
81+ // Page-specific document titles for screen reader users
82+ const titleMap : Record < string , string > = {
83+ '/' : 'Regan Maharjan Portfolio' ,
84+ '/about' : 'About | Regan Maharjan' ,
85+ '/experience' : 'Experience | Regan Maharjan' ,
86+ '/projects' : 'Projects | Regan Maharjan' ,
87+ '/impact' : 'Stories of Impact | Regan Maharjan' ,
88+ '/storiesofadventure' : 'Stories of Adventure | Regan Maharjan' ,
89+ '/accessibility' : 'Accessibility | Regan Maharjan' ,
90+ '/contact' : 'Contact | Regan Maharjan' ,
91+ '/photography' : 'Photography | Regan Maharjan' ,
92+ '/cms' : 'Content Management | Regan Maharjan' ,
93+ } ;
94+ useEffect ( ( ) => {
95+ const segments = location . pathname . split ( '/' ) . filter ( Boolean ) ;
96+ const basePath = segments [ 0 ] ? `/${ segments [ 0 ] } ` : '/' ;
97+ const title = titleMap [ basePath ] ?? titleMap [ location . pathname ] ?? 'Regan Maharjan Portfolio' ;
98+ document . title = title ;
99+ } , [ location . pathname ] ) ;
100+
101+ // Focus main content on route change (helps keyboard/screen reader users)
102+ useEffect ( ( ) => {
103+ const main = document . getElementById ( 'main-content' ) ;
104+ main ?. focus ( ) ;
105+ } , [ location . pathname ] ) ;
106+
78107 return (
79- < div className = "min-h-screen bg-background flex flex-col" >
108+ < div className = "min-h-screen bg-background flex flex-col relative" >
109+ { /* Skip link: first focusable element for keyboard users */ }
110+ < a
111+ href = "#main-content"
112+ className = "skip-link"
113+ onClick = { ( e ) => {
114+ e . preventDefault ( ) ;
115+ const main = document . getElementById ( 'main-content' ) ;
116+ main ?. focus ( ) ;
117+ main ?. scrollIntoView ( ) ;
118+ } }
119+ >
120+ Skip to main content
121+ </ a >
80122 { ! isHomePage && < Navigation /> }
81- < main className = "flex-1" >
123+ < main id = "main-content" className = "flex-1" tabIndex = { - 1 } >
82124 < Routes >
83125 < Route path = "/" element = {
84126 < div className = "min-h-screen flex flex-col items-center justify-center bg-background" >
@@ -108,8 +150,10 @@ function AppContent() {
108150
109151export default function App ( ) {
110152 return (
111- < Router >
112- < AppContent />
113- </ Router >
153+ < MotionConfig reducedMotion = "user" >
154+ < Router >
155+ < AppContent />
156+ </ Router >
157+ </ MotionConfig >
114158 ) ;
115159}
0 commit comments