@@ -114,29 +114,6 @@ class Router {
114114 return ;
115115 }
116116
117- // Create a transition container
118- const transitionContainer = document . createElement ( 'div' ) ;
119- transitionContainer . className = 'route-transition-container' ;
120- transitionContainer . style . position = 'absolute' ;
121- transitionContainer . style . top = '0' ;
122- transitionContainer . style . left = '0' ;
123- transitionContainer . style . width = '100%' ;
124- transitionContainer . style . height = '100%' ;
125- transitionContainer . style . backgroundColor = 'var(--background-color)' ;
126- transitionContainer . style . color = 'var(--text-primary)' ;
127- transitionContainer . style . opacity = '0' ;
128- transitionContainer . style . transition = 'opacity 150ms ease-in-out' ;
129- transitionContainer . innerHTML = '<div class="loading">Loading...</div>' ;
130-
131- // Add the transition container to the root element
132- rootElement . style . position = 'relative' ;
133- rootElement . appendChild ( transitionContainer ) ;
134-
135- // Fade in the transition container
136- setTimeout ( ( ) => {
137- transitionContainer . style . opacity = '1' ;
138- } , 0 ) ;
139-
140117 try {
141118 // Handle route
142119 if ( route ) {
@@ -145,6 +122,18 @@ class Router {
145122 // Set current route
146123 this . currentRoute = route ;
147124
125+ // Create a container for the new view that will be invisible at first
126+ const newViewContainer = document . createElement ( 'div' ) ;
127+ newViewContainer . className = 'new-route-container' ;
128+ newViewContainer . style . position = 'absolute' ;
129+ newViewContainer . style . top = '0' ;
130+ newViewContainer . style . left = '0' ;
131+ newViewContainer . style . width = '100%' ;
132+ newViewContainer . style . height = '100%' ;
133+ newViewContainer . style . opacity = '0' ;
134+ newViewContainer . style . zIndex = '5' ;
135+ newViewContainer . style . transition = 'opacity 200ms ease-in-out' ;
136+
148137 // Get view content
149138 let content ;
150139
@@ -167,54 +156,146 @@ class Router {
167156 content = '' ;
168157 }
169158
170- // Prepare the new content in the background
171- const tempContainer = document . createElement ( 'div' ) ;
172- tempContainer . innerHTML = content ;
159+ // Set the content of the new view container
160+ newViewContainer . innerHTML = content ;
161+
162+ // Make the root element a positioned container if it's not already
163+ const rootPosition = window . getComputedStyle ( rootElement ) . position ;
164+ if ( rootPosition === 'static' ) {
165+ rootElement . style . position = 'relative' ;
166+ }
167+
168+ // Add the new view container to the DOM but keep it invisible
169+ rootElement . appendChild ( newViewContainer ) ;
173170
174- // Apply theme-related styles to ensure proper coloring
175- const themeStyles = document . createElement ( 'style' ) ;
176- themeStyles . textContent = `
177- * {
178- color: var(--text-primary);
179- background-color: var(--background-color);
180- transition: none !important;
171+ // Create a wrapper for the current content
172+ const currentContent = document . createElement ( 'div' ) ;
173+ currentContent . className = 'current-route-container' ;
174+ currentContent . style . position = 'relative' ;
175+ currentContent . style . zIndex = '1' ;
176+ currentContent . style . opacity = '1' ;
177+ currentContent . style . transition = 'opacity 200ms ease-in-out' ;
178+
179+ // Move all current children (except the new view container) into the wrapper
180+ Array . from ( rootElement . children ) . forEach ( child => {
181+ if ( child !== newViewContainer ) {
182+ currentContent . appendChild ( child ) ;
181183 }
182- ` ;
183- tempContainer . appendChild ( themeStyles ) ;
184+ } ) ;
184185
185- // Fade out the transition container
186- transitionContainer . style . opacity = '0' ;
186+ // Add the current content wrapper back to the root
187+ rootElement . appendChild ( currentContent ) ;
187188
188- // Wait for the fade out transition to complete
189- setTimeout ( ( ) => {
190- // Update the DOM with the prepared content
191- console . log ( 'Updating DOM with content' ) ;
192- rootElement . innerHTML = content ;
189+ // Wait a frame to ensure DOM is updated
190+ requestAnimationFrame ( ( ) => {
191+ // Start the transition - fade out current content and fade in new content
192+ currentContent . style . opacity = '0' ;
193+ newViewContainer . style . opacity = '1' ;
193194
194- // Call afterRender if provided
195- if ( route . afterRender ) {
196- console . log ( 'Calling afterRender function' ) ;
197- setTimeout ( ( ) => {
198- try {
199- route . afterRender ( ) ;
200- } catch ( error ) {
201- console . error ( 'Error in afterRender:' , error ) ;
202- }
203- } , 0 ) ;
195+ // After transition completes, swap the content
196+ setTimeout ( ( ) => {
197+ // Remove the old content
198+ rootElement . removeChild ( currentContent ) ;
199+
200+ // Move the new content from the container to the root
201+ const newContent = Array . from ( newViewContainer . children ) ;
202+ newContent . forEach ( child => rootElement . appendChild ( child ) ) ;
203+
204+ // Remove the now-empty container
205+ rootElement . removeChild ( newViewContainer ) ;
206+
207+ // Call afterRender if provided
208+ if ( route . afterRender ) {
209+ console . log ( 'Calling afterRender function' ) ;
210+ setTimeout ( ( ) => {
211+ try {
212+ route . afterRender ( ) ;
213+ } catch ( error ) {
214+ console . error ( 'Error in afterRender:' , error ) ;
215+ }
216+ } , 0 ) ;
217+ }
218+
219+ // Dispatch route changed event
220+ window . dispatchEvent ( new CustomEvent ( 'route-changed' , {
221+ detail : { path, route }
222+ } ) ) ;
223+ } , 200 ) ; // Match the transition duration
224+ } ) ;
225+ } else {
226+ // Handle 404 with the same transition approach
227+ const newViewContainer = document . createElement ( 'div' ) ;
228+ newViewContainer . className = 'new-route-container' ;
229+ newViewContainer . style . position = 'absolute' ;
230+ newViewContainer . style . top = '0' ;
231+ newViewContainer . style . left = '0' ;
232+ newViewContainer . style . width = '100%' ;
233+ newViewContainer . style . height = '100%' ;
234+ newViewContainer . style . opacity = '0' ;
235+ newViewContainer . style . zIndex = '5' ;
236+ newViewContainer . style . transition = 'opacity 200ms ease-in-out' ;
237+
238+ // Call the error handler to get the 404 content
239+ this . errorHandler ( path , newViewContainer ) ;
240+
241+ // Make the root element a positioned container if it's not already
242+ const rootPosition = window . getComputedStyle ( rootElement ) . position ;
243+ if ( rootPosition === 'static' ) {
244+ rootElement . style . position = 'relative' ;
245+ }
246+
247+ // Add the new view container to the DOM but keep it invisible
248+ rootElement . appendChild ( newViewContainer ) ;
249+
250+ // Create a wrapper for the current content
251+ const currentContent = document . createElement ( 'div' ) ;
252+ currentContent . className = 'current-route-container' ;
253+ currentContent . style . position = 'relative' ;
254+ currentContent . style . zIndex = '1' ;
255+ currentContent . style . opacity = '1' ;
256+ currentContent . style . transition = 'opacity 200ms ease-in-out' ;
257+
258+ // Move all current children (except the new view container) into the wrapper
259+ Array . from ( rootElement . children ) . forEach ( child => {
260+ if ( child !== newViewContainer ) {
261+ currentContent . appendChild ( child ) ;
204262 }
263+ } ) ;
264+
265+ // Add the current content wrapper back to the root
266+ rootElement . appendChild ( currentContent ) ;
267+
268+ // Wait a frame to ensure DOM is updated
269+ requestAnimationFrame ( ( ) => {
270+ // Start the transition - fade out current content and fade in new content
271+ currentContent . style . opacity = '0' ;
272+ newViewContainer . style . opacity = '1' ;
205273
206- // Dispatch route changed event
207- window . dispatchEvent ( new CustomEvent ( 'route-changed' , {
208- detail : { path, route }
209- } ) ) ;
210- } , 150 ) ; // Match the transition duration
211- } else {
212- // Handle 404
213- this . errorHandler ( path , rootElement ) ;
274+ // After transition completes, swap the content
275+ setTimeout ( ( ) => {
276+ // Remove the old content
277+ rootElement . removeChild ( currentContent ) ;
278+
279+ // Move the new content from the container to the root
280+ const newContent = Array . from ( newViewContainer . children ) ;
281+ newContent . forEach ( child => rootElement . appendChild ( child ) ) ;
282+
283+ // Remove the now-empty container
284+ rootElement . removeChild ( newViewContainer ) ;
285+ } , 200 ) ; // Match the transition duration
286+ } ) ;
214287 }
215288 } catch ( error ) {
216289 console . error ( 'Error rendering route:' , error ) ;
217- rootElement . innerHTML = `<div class="error">Error loading page: ${ error . message } </div>` ;
290+
291+ // Handle errors with the same transition approach
292+ const errorContainer = document . createElement ( 'div' ) ;
293+ errorContainer . className = 'error' ;
294+ errorContainer . innerHTML = `<div class="error">Error loading page: ${ error . message } </div>` ;
295+
296+ // Replace the content with the error message
297+ rootElement . innerHTML = '' ;
298+ rootElement . appendChild ( errorContainer ) ;
218299 } finally {
219300 // Clear loading state
220301 this . loading = false ;
@@ -269,16 +350,24 @@ class Router {
269350 /**
270351 * Default 404 error handler
271352 * @param {string } path - Route path
272- * @param {HTMLElement } rootElement - Root element
353+ * @param {HTMLElement } container - Container element for the error content
273354 */
274- defaultErrorHandler ( path , rootElement ) {
275- rootElement . innerHTML = `
276- <div class="error-page">
355+ defaultErrorHandler ( path , container ) {
356+ // Create error content
357+ const errorContent = document . createElement ( 'div' ) ;
358+ errorContent . className = 'error-page' ;
359+ errorContent . innerHTML = `
360+ <pf-header></pf-header>
361+ <div class="error-content">
277362 <h1>404 - Page Not Found</h1>
278363 <p>The page "${ path } " could not be found.</p>
279364 <a href="/" class="back-link">Go back to home</a>
280365 </div>
366+ <pf-footer></pf-footer>
281367 ` ;
368+
369+ // Add to container
370+ container . appendChild ( errorContent ) ;
282371 }
283372}
284373
0 commit comments