yjernite HF Staff commited on
Commit
8cb40d3
·
verified ·
1 Parent(s): cddcbaf

Upload router.js

Browse files
Files changed (1) hide show
  1. js/utils/router.js +93 -100
js/utils/router.js CHANGED
@@ -1,7 +1,7 @@
1
  // router.js - Simple SPA router
2
- import { renderHomePage, getHomePageSidebar } from '../pages/HomePage.js';
3
- import { renderAreaPage, getAreaPageSidebar } from '../pages/AreaPage.js';
4
- import { renderResourcesPage, getResourcesPageSidebar } from '../pages/ResourcesPage.js';
5
  import { scrollToSection } from './dom.js';
6
 
7
  class Router {
@@ -16,13 +16,15 @@ class Router {
16
  '/about': 'resources'
17
  };
18
 
 
19
  this.currentPage = null;
 
 
20
  this.init();
21
  }
22
 
23
  init() {
24
  // Handle initial page load
25
- console.log('Initializing router');
26
  this.loadPage(window.location.pathname);
27
 
28
  // Handle browser back/forward
@@ -32,7 +34,7 @@ class Router {
32
  const fullUrl = path + hash;
33
 
34
  // Use navigateToUrl to ensure proper scroll behavior
35
- this.navigateToUrl(fullUrl);
36
  });
37
 
38
  // Handle hash changes for navigation
@@ -55,21 +57,57 @@ class Router {
55
  }
56
 
57
  async loadPage(path) {
58
- const route = this.routes[path] || 'home';
 
 
59
 
60
- if (this.currentPage === route) {
61
- // Same page, no need to reload
62
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  }
64
 
 
65
  this.currentPage = route;
66
-
67
- console.log('Loading page:', route);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  // Handle background for all pages
69
  await this.setPageBackground(route);
70
 
71
- console.log('Background set for:', route);
72
-
73
  try {
74
  switch (route) {
75
  case 'home':
@@ -79,7 +117,7 @@ class Router {
79
  case 'personal':
80
  case 'rights':
81
  case 'ecosystems':
82
- await this.loadAreaPage(route);
83
  break;
84
  case 'resources':
85
  await this.loadResourcesPage();
@@ -94,13 +132,10 @@ class Router {
94
  await this.loadHomePage();
95
  }
96
 
97
- console.log('Page loaded:', route);
98
-
99
  return Promise.resolve();
100
  }
101
 
102
  async setPageBackground(route) {
103
- console.log('Setting background for route:', route);
104
  // Clear any existing background
105
  this.clearBackground();
106
 
@@ -131,7 +166,7 @@ class Router {
131
 
132
  backgroundDiv.innerHTML = `
133
  <!-- Background Image Main Content -->
134
- <img src="images/${backgroundImage}" alt="" class="w-full h-full object-cover pointer-events-none">
135
  <div id="bg-attribution" class="absolute bottom-4 right-4 bg-black bg-opacity-75 text-white text-xs px-2 py-1 rounded opacity-0 transition-opacity duration-200 max-w-xs z-50">
136
  <a href="${sourceUrl}" target="_blank" class="text-blue-300 hover:text-blue-100">
137
  ${attribution}
@@ -167,39 +202,28 @@ class Router {
167
 
168
  async loadHomePage() {
169
  const mainContent = document.getElementById('main-content');
170
- const leftSidebar = document.getElementById('left-sidebar');
171
 
172
  if (!mainContent) {
173
  return;
174
  }
175
 
176
  try {
177
- // Get page content and sidebar
178
  const homePage = renderHomePage();
179
 
180
- // Update content
181
- const contentContainer = mainContent.querySelector('.max-w-4xl') || mainContent;
182
- contentContainer.innerHTML = homePage.content;
183
-
184
- // Update sidebar if it exists
185
- if (leftSidebar) {
186
- leftSidebar.innerHTML = getHomePageSidebar();
187
- }
188
 
189
  // Initialize page
190
  if (homePage.init) {
191
  homePage.init();
192
  }
193
-
194
- // Initialize left sidebar attribution after content is loaded
195
- initializeLeftSidebarAttribution();
196
 
197
  // Update navigation state
198
  this.updateNavigation('home');
199
  } catch (error) {
200
  // Fallback to error content
201
- const contentContainer = mainContent.querySelector('.max-w-4xl') || mainContent;
202
- contentContainer.innerHTML = `
203
  <div class="bg-white rounded-lg shadow-sm p-8">
204
  <h1 class="text-3xl font-bold text-red-600 mb-6">Error Loading Page</h1>
205
  <p class="text-gray-700">Sorry, there was an error loading the home page.</p>
@@ -208,42 +232,34 @@ class Router {
208
  }
209
  }
210
 
211
- async loadAreaPage(area) {
212
  const mainContent = document.getElementById('main-content');
213
- const leftSidebar = document.getElementById('left-sidebar');
214
 
215
  if (!mainContent) {
216
  return;
217
  }
218
 
219
  try {
220
- // Get area page content and sidebar
221
- const areaPage = renderAreaPage(area);
222
 
223
- // Update content
224
- const contentContainer = mainContent.querySelector('.max-w-4xl') || mainContent;
225
- contentContainer.innerHTML = areaPage.content;
226
-
227
- // Update sidebar
228
- if (leftSidebar) {
229
- leftSidebar.innerHTML = getAreaPageSidebar(area);
230
- }
231
 
232
  // Initialize page
233
  if (areaPage.init) {
234
  areaPage.init();
235
  }
236
 
237
- // Initialize left sidebar attribution after content is loaded
238
- initializeLeftSidebarAttribution();
239
 
240
  } catch (error) {
241
  console.error(`Error loading ${area} page:`, error);
242
 
243
  // Fallback content
244
- const contentContainer = mainContent.querySelector('.max-w-4xl') || mainContent;
245
- contentContainer.innerHTML = `
246
- <div class="bg-white rounded-lg shadow-sm p-8">
247
  <h1 class="text-3xl font-bold text-red-600 mb-6">Error Loading Page</h1>
248
  <p class="text-gray-700">Sorry, there was an error loading the ${area} page.</p>
249
  </div>
@@ -255,36 +271,25 @@ class Router {
255
 
256
  async loadResourcesPage() {
257
  const mainContent = document.getElementById('main-content');
258
- const leftSidebar = document.getElementById('left-sidebar');
259
 
260
  if (!mainContent) return;
261
 
262
  try {
263
- // Get resources page content and sidebar
264
  const resourcesPage = renderResourcesPage();
265
 
266
- // Update content
267
- const contentContainer = mainContent.querySelector('.max-w-4xl') || mainContent;
268
- contentContainer.innerHTML = resourcesPage.content;
269
-
270
- // Update sidebar
271
- if (leftSidebar) {
272
- leftSidebar.innerHTML = getResourcesPageSidebar();
273
- }
274
 
275
  // Initialize page
276
  if (resourcesPage.init) {
277
  resourcesPage.init();
278
  }
279
-
280
- // Initialize left sidebar attribution after content is loaded
281
- initializeLeftSidebarAttribution();
282
 
283
  } catch (error) {
284
  // Fallback content
285
- const contentContainer = mainContent.querySelector('.max-w-4xl') || mainContent;
286
- contentContainer.innerHTML = `
287
- <div class="bg-white rounded-lg shadow-sm p-8">
288
  <h1 class="text-3xl font-bold text-red-600 mb-6">Error Loading Page</h1>
289
  <p class="text-gray-700">Sorry, there was an error loading the resources page.</p>
290
  </div>
@@ -298,15 +303,15 @@ class Router {
298
  // Update header navigation active states
299
  const navLinks = document.querySelectorAll('header nav a');
300
  navLinks.forEach(link => {
301
- link.classList.remove('text-blue-600', 'bg-blue-50');
302
- link.classList.add('text-gray-700');
303
 
304
  const href = link.getAttribute('href');
 
305
  if ((currentPage === 'home' && (href === '/' || href === '/home')) ||
306
  (currentPage === 'resources' && href === '/about') ||
307
  (currentPage !== 'home' && currentPage !== 'resources' && href === `/${currentPage}`)) {
308
- link.classList.remove('text-gray-700');
309
- link.classList.add('text-blue-600', 'bg-blue-50');
310
  }
311
  });
312
  }
@@ -323,9 +328,13 @@ class Router {
323
 
324
  // Handle different types of links
325
  if (href.startsWith('/') && !href.startsWith('/js/') && !href.startsWith('/css/') && !href.startsWith('/images/')) {
326
- // Check if this is a known SPA route
327
  const path = href.split('#')[0];
328
- if (this.routes[path]) {
 
 
 
 
329
  e.preventDefault();
330
  this.navigateToUrl(href);
331
  }
@@ -338,12 +347,14 @@ class Router {
338
  });
339
  }
340
 
341
- navigateToUrl(fullUrl) {
342
  // Parse URL into path and hash
343
  const [path, hash] = fullUrl.split('#');
344
 
345
- // Update browser URL
346
- window.history.pushState({}, '', fullUrl);
 
 
347
 
348
  // Load page and then handle hash
349
  this.loadPage(path).then(() => {
@@ -363,47 +374,29 @@ class Router {
363
  // Export router instance
364
  export const router = new Router();
365
 
 
 
 
366
  // New function to update the position and size of the page background
367
  function updatePageBackgroundPosition() {
368
  const backgroundDiv = document.getElementById('page-background');
369
  if (!backgroundDiv) return;
370
 
371
  const headerHeight = getComputedStyle(document.documentElement).getPropertyValue('--header-height');
372
- const leftSidebar = document.getElementById('left-sidebar');
373
  const searchSidebar = document.getElementById('search-sidebar');
374
 
375
- const leftSidebarWidth = leftSidebar.classList.contains('-translate-x-full') ? 0 : leftSidebar.offsetWidth;
376
- const rightSidebarWidth = searchSidebar.classList.contains('translate-x-full') ? 0 : searchSidebar.offsetWidth;
377
 
378
  backgroundDiv.style.cssText = `
379
  top: ${headerHeight};
380
- left: ${leftSidebarWidth}px;
381
  right: ${rightSidebarWidth}px;
382
  bottom: 0;
383
- width: calc(100% - ${leftSidebarWidth + rightSidebarWidth}px);
384
  height: calc(100vh - ${headerHeight});
385
- transition: left 0.3s ease-in-out, width 0.3s ease-in-out, right 0.3s ease-in-out; /* Add transition for smooth movement */
386
  `;
387
  }
388
 
389
  // Export the new function so main.js can call it
390
  export { updatePageBackgroundPosition };
391
-
392
- // Function to initialize the attribution hover for the left sidebar
393
- function initializeLeftSidebarAttribution() {
394
- const leftSidebarContainer = document.getElementById('left-sidebar');
395
- const attribution = document.getElementById('left-sidebar-attribution');
396
-
397
- if (!leftSidebarContainer || !attribution) return;
398
-
399
- leftSidebarContainer.addEventListener('mouseenter', () => {
400
- attribution.style.opacity = '1';
401
- });
402
-
403
- leftSidebarContainer.addEventListener('mouseleave', () => {
404
- attribution.style.opacity = '0';
405
- });
406
- }
407
-
408
- // Export the new function as well
409
- export { initializeLeftSidebarAttribution };
 
1
  // router.js - Simple SPA router
2
+ import { renderHomePage } from '../pages/HomePage.js';
3
+ import { renderAreaPage } from '../pages/AreaPage.js';
4
+ import { renderResourcesPage } from '../pages/ResourcesPage.js';
5
  import { scrollToSection } from './dom.js';
6
 
7
  class Router {
 
16
  '/about': 'resources'
17
  };
18
 
19
+ this.areas = ['efficiency', 'personal', 'rights', 'ecosystems'];
20
  this.currentPage = null;
21
+ this.currentArea = null;
22
+ this.currentTopic = null;
23
  this.init();
24
  }
25
 
26
  init() {
27
  // Handle initial page load
 
28
  this.loadPage(window.location.pathname);
29
 
30
  // Handle browser back/forward
 
34
  const fullUrl = path + hash;
35
 
36
  // Use navigateToUrl to ensure proper scroll behavior
37
+ this.navigateToUrl(fullUrl, false); // false = don't push to history
38
  });
39
 
40
  // Handle hash changes for navigation
 
57
  }
58
 
59
  async loadPage(path) {
60
+ // Parse path to support /area/topic format
61
+ const pathParts = path.split('/').filter(p => p);
62
+ let route, area, topic;
63
 
64
+ if (pathParts.length === 0) {
65
+ // Root path
66
+ route = 'home';
67
+ } else if (pathParts.length === 1) {
68
+ // Single segment: /efficiency or /home
69
+ route = this.routes[path] || 'home';
70
+ if (this.areas.includes(pathParts[0])) {
71
+ area = pathParts[0];
72
+ }
73
+ } else if (pathParts.length === 2 && this.areas.includes(pathParts[0])) {
74
+ // Two segments: /efficiency/environment
75
+ area = pathParts[0];
76
+ topic = pathParts[1];
77
+ route = area;
78
+ } else {
79
+ // Unknown route, default to home
80
+ route = 'home';
81
  }
82
 
83
+ // Update current state
84
  this.currentPage = route;
85
+ this.currentArea = area || null;
86
+ this.currentTopic = topic || null;
87
+
88
+ // Update Alpine.js store if available
89
+ if (window.Alpine && window.Alpine.store) {
90
+ const navStore = window.Alpine.store('navigation');
91
+ if (navStore) {
92
+ navStore.currentPage = this.currentPage;
93
+ navStore.currentArea = this.currentArea;
94
+ navStore.currentTopic = this.currentTopic;
95
+ navStore.updateTopicNav();
96
+ }
97
+ }
98
+
99
+ // Dispatch event for header and other components
100
+ window.dispatchEvent(new CustomEvent('navigation-changed', {
101
+ detail: {
102
+ currentPage: this.currentPage,
103
+ currentArea: this.currentArea,
104
+ currentTopic: this.currentTopic
105
+ }
106
+ }));
107
+
108
  // Handle background for all pages
109
  await this.setPageBackground(route);
110
 
 
 
111
  try {
112
  switch (route) {
113
  case 'home':
 
117
  case 'personal':
118
  case 'rights':
119
  case 'ecosystems':
120
+ await this.loadAreaPage(route, topic);
121
  break;
122
  case 'resources':
123
  await this.loadResourcesPage();
 
132
  await this.loadHomePage();
133
  }
134
 
 
 
135
  return Promise.resolve();
136
  }
137
 
138
  async setPageBackground(route) {
 
139
  // Clear any existing background
140
  this.clearBackground();
141
 
 
166
 
167
  backgroundDiv.innerHTML = `
168
  <!-- Background Image Main Content -->
169
+ <img src="/images/${backgroundImage}" alt="" class="w-full h-full object-cover pointer-events-none">
170
  <div id="bg-attribution" class="absolute bottom-4 right-4 bg-black bg-opacity-75 text-white text-xs px-2 py-1 rounded opacity-0 transition-opacity duration-200 max-w-xs z-50">
171
  <a href="${sourceUrl}" target="_blank" class="text-blue-300 hover:text-blue-100">
172
  ${attribution}
 
202
 
203
  async loadHomePage() {
204
  const mainContent = document.getElementById('main-content');
 
205
 
206
  if (!mainContent) {
207
  return;
208
  }
209
 
210
  try {
211
+ // Get page content
212
  const homePage = renderHomePage();
213
 
214
+ // Update content - render directly to main content
215
+ mainContent.innerHTML = homePage.content;
 
 
 
 
 
 
216
 
217
  // Initialize page
218
  if (homePage.init) {
219
  homePage.init();
220
  }
 
 
 
221
 
222
  // Update navigation state
223
  this.updateNavigation('home');
224
  } catch (error) {
225
  // Fallback to error content
226
+ mainContent.innerHTML = `
 
227
  <div class="bg-white rounded-lg shadow-sm p-8">
228
  <h1 class="text-3xl font-bold text-red-600 mb-6">Error Loading Page</h1>
229
  <p class="text-gray-700">Sorry, there was an error loading the home page.</p>
 
232
  }
233
  }
234
 
235
+ async loadAreaPage(area, topic = null) {
236
  const mainContent = document.getElementById('main-content');
 
237
 
238
  if (!mainContent) {
239
  return;
240
  }
241
 
242
  try {
243
+ // Get area page content (pass topic parameter)
244
+ const areaPage = renderAreaPage(area, topic);
245
 
246
+ // Update content - render directly to main content (no wrapper needed)
247
+ mainContent.innerHTML = areaPage.content;
 
 
 
 
 
 
248
 
249
  // Initialize page
250
  if (areaPage.init) {
251
  areaPage.init();
252
  }
253
 
254
+ // Scroll to top of page after content loads
255
+ window.scrollTo({ top: 0, behavior: 'smooth' });
256
 
257
  } catch (error) {
258
  console.error(`Error loading ${area} page:`, error);
259
 
260
  // Fallback content
261
+ mainContent.innerHTML = `
262
+ <div class="bg-white rounded-lg shadow-sm p-8 mx-4">
 
263
  <h1 class="text-3xl font-bold text-red-600 mb-6">Error Loading Page</h1>
264
  <p class="text-gray-700">Sorry, there was an error loading the ${area} page.</p>
265
  </div>
 
271
 
272
  async loadResourcesPage() {
273
  const mainContent = document.getElementById('main-content');
 
274
 
275
  if (!mainContent) return;
276
 
277
  try {
278
+ // Get resources page content
279
  const resourcesPage = renderResourcesPage();
280
 
281
+ // Update content - render directly to main content
282
+ mainContent.innerHTML = resourcesPage.content;
 
 
 
 
 
 
283
 
284
  // Initialize page
285
  if (resourcesPage.init) {
286
  resourcesPage.init();
287
  }
 
 
 
288
 
289
  } catch (error) {
290
  // Fallback content
291
+ mainContent.innerHTML = `
292
+ <div class="bg-white rounded-lg shadow-sm p-8 mx-4">
 
293
  <h1 class="text-3xl font-bold text-red-600 mb-6">Error Loading Page</h1>
294
  <p class="text-gray-700">Sorry, there was an error loading the resources page.</p>
295
  </div>
 
303
  // Update header navigation active states
304
  const navLinks = document.querySelectorAll('header nav a');
305
  navLinks.forEach(link => {
306
+ // Remove active state
307
+ link.classList.remove('text-blue-600', 'bg-blue-50', 'font-semibold');
308
 
309
  const href = link.getAttribute('href');
310
+ // Add active state to current page
311
  if ((currentPage === 'home' && (href === '/' || href === '/home')) ||
312
  (currentPage === 'resources' && href === '/about') ||
313
  (currentPage !== 'home' && currentPage !== 'resources' && href === `/${currentPage}`)) {
314
+ link.classList.add('text-blue-600', 'bg-blue-50', 'font-semibold');
 
315
  }
316
  });
317
  }
 
328
 
329
  // Handle different types of links
330
  if (href.startsWith('/') && !href.startsWith('/js/') && !href.startsWith('/css/') && !href.startsWith('/images/')) {
331
+ // Check if this is a known SPA route or area/topic route
332
  const path = href.split('#')[0];
333
+ const pathParts = path.split('/').filter(p => p);
334
+ const isKnownRoute = this.routes[path] ||
335
+ (pathParts.length === 2 && this.areas.includes(pathParts[0]));
336
+
337
+ if (isKnownRoute) {
338
  e.preventDefault();
339
  this.navigateToUrl(href);
340
  }
 
347
  });
348
  }
349
 
350
+ navigateToUrl(fullUrl, pushState = true) {
351
  // Parse URL into path and hash
352
  const [path, hash] = fullUrl.split('#');
353
 
354
+ // Update browser URL if needed
355
+ if (pushState) {
356
+ window.history.pushState({}, '', fullUrl);
357
+ }
358
 
359
  // Load page and then handle hash
360
  this.loadPage(path).then(() => {
 
374
  // Export router instance
375
  export const router = new Router();
376
 
377
+ // Make router globally accessible for Alpine.js and other scripts
378
+ window.router = router;
379
+
380
  // New function to update the position and size of the page background
381
  function updatePageBackgroundPosition() {
382
  const backgroundDiv = document.getElementById('page-background');
383
  if (!backgroundDiv) return;
384
 
385
  const headerHeight = getComputedStyle(document.documentElement).getPropertyValue('--header-height');
 
386
  const searchSidebar = document.getElementById('search-sidebar');
387
 
388
+ const rightSidebarWidth = searchSidebar && !searchSidebar.classList.contains('translate-x-full') ? searchSidebar.offsetWidth : 0;
 
389
 
390
  backgroundDiv.style.cssText = `
391
  top: ${headerHeight};
392
+ left: 0;
393
  right: ${rightSidebarWidth}px;
394
  bottom: 0;
395
+ width: calc(100% - ${rightSidebarWidth}px);
396
  height: calc(100vh - ${headerHeight});
397
+ transition: width 0.3s ease-in-out, right 0.3s ease-in-out;
398
  `;
399
  }
400
 
401
  // Export the new function so main.js can call it
402
  export { updatePageBackgroundPosition };