|
28 | 28 |
|
29 | 29 | handleRoute() { |
30 | 30 | const hash = window.location.hash.slice(1) || '/'; |
31 | | - const path = hash === '/' ? 'overview.md' : hash; |
| 31 | + // Remove leading slash if present |
| 32 | + const cleanHash = hash.startsWith('/') ? hash.slice(1) : hash; |
| 33 | + const path = (hash === '/' || cleanHash === '') ? 'overview.md' : cleanHash; |
32 | 34 | this.loadMarkdown(path); |
33 | 35 | this.updateBreadcrumbs(path); |
34 | 36 | } |
35 | 37 |
|
36 | 38 | async loadMarkdown(filename) { |
| 39 | + const content = document.getElementById('markdown-content'); |
| 40 | + |
| 41 | + // Show loading state |
| 42 | + content.innerHTML = '<div class="loading">Loading...</div>'; |
| 43 | + |
37 | 44 | try { |
38 | 45 | const response = await fetch(filename); |
39 | | - if (!response.ok) throw new Error(`Failed to load ${filename}`); |
| 46 | + if (!response.ok) { |
| 47 | + throw new Error(`HTTP ${response.status}: ${response.statusText}`); |
| 48 | + } |
40 | 49 | const markdown = await response.text(); |
41 | 50 | this.renderMarkdown(markdown); |
| 51 | + this.updateActiveLink(filename); |
42 | 52 | } catch (error) { |
43 | 53 | console.error('Error loading markdown:', error); |
44 | | - const content = document.getElementById('markdown-content'); |
45 | | - content.innerHTML = `<h1>Error</h1><p>Could not load ${filename}</p>`; |
| 54 | + content.innerHTML = ` |
| 55 | + <h1>📄 Document Not Found</h1> |
| 56 | + <p>Could not load <code>${filename}</code></p> |
| 57 | + <p style="color: #6a737d; font-size: 0.9rem;"> |
| 58 | + ${error.message} |
| 59 | + </p> |
| 60 | + <p> |
| 61 | + <a href="#/" style="color: #0366d6;">← Back to Overview</a> |
| 62 | + </p> |
| 63 | + `; |
46 | 64 | } |
47 | 65 | } |
48 | 66 |
|
| 67 | + updateActiveLink(filename) { |
| 68 | + // Update active state on navigation links |
| 69 | + document.querySelectorAll('.nav-link').forEach(link => { |
| 70 | + link.classList.remove('active'); |
| 71 | + const linkPath = link.getAttribute('href').replace('#/', '').replace('#', ''); |
| 72 | + const currentPath = filename; |
| 73 | + if (linkPath === currentPath || (linkPath === '' && filename === 'overview.md')) { |
| 74 | + link.classList.add('active'); |
| 75 | + } |
| 76 | + }); |
| 77 | + } |
| 78 | + |
49 | 79 | renderMarkdown(markdown) { |
50 | 80 | const html = marked.parse(markdown); |
51 | 81 | const content = document.getElementById('markdown-content'); |
|
70 | 100 |
|
71 | 101 | updateBreadcrumbs(path) { |
72 | 102 | const breadcrumbs = document.getElementById('breadcrumbs'); |
| 103 | + |
| 104 | + // Handle overview case |
| 105 | + if (path === 'overview.md') { |
| 106 | + breadcrumbs.innerHTML = '<a href="#/">Home</a>'; |
| 107 | + return; |
| 108 | + } |
| 109 | + |
73 | 110 | const parts = path.split('/').filter(p => p); |
74 | 111 |
|
75 | 112 | let html = '<a href="#/">Home</a>'; |
76 | 113 | let currentPath = ''; |
77 | 114 |
|
78 | 115 | for (const part of parts) { |
79 | | - currentPath += '/' + part; |
| 116 | + currentPath += (currentPath ? '/' : '') + part; |
80 | 117 | html += ' <span class="separator">›</span> '; |
81 | | - html += `<a href="#${currentPath}">${part.replace('.md', '')}</a>`; |
| 118 | + const displayName = formatModuleName(part.replace('.md', '')); |
| 119 | + html += `<a href="#/${currentPath}">${displayName}</a>`; |
82 | 120 | } |
83 | 121 |
|
84 | 122 | breadcrumbs.innerHTML = html; |
|
102 | 140 | link.textContent = formatModuleName(moduleName); |
103 | 141 | link.className = 'nav-link'; |
104 | 142 |
|
105 | | - // Highlight active link |
106 | | - link.addEventListener('click', function() { |
107 | | - document.querySelectorAll('.nav-link').forEach(l => l.classList.remove('active')); |
108 | | - this.classList.add('active'); |
109 | | - }); |
| 143 | + // Active link highlighting is handled by updateActiveLink in the router |
110 | 144 |
|
111 | 145 | item.appendChild(link); |
112 | 146 | container.appendChild(item); |
|
210 | 244 | const overviewLink = document.createElement('a'); |
211 | 245 | overviewLink.href = '#/'; |
212 | 246 | overviewLink.textContent = 'Overview'; |
213 | | - overviewLink.className = 'nav-link active'; |
| 247 | + overviewLink.className = 'nav-link'; // Active state will be set by router |
214 | 248 | overviewItem.appendChild(overviewLink); |
215 | 249 | navTree.appendChild(overviewItem); |
216 | 250 |
|
|
0 commit comments