|
3 | 3 | (function() { |
4 | 4 | 'use strict'; |
5 | 5 |
|
6 | | - // Simple markdown parser (GitHub-flavored) |
7 | | - function parseMarkdown(markdown) { |
8 | | - let html = markdown; |
9 | | - |
10 | | - // Escape HTML |
11 | | - html = html.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); |
12 | | - |
13 | | - // Headers |
14 | | - html = html.replace(/^##### (.*$)/gim, '<h5>$1</h5>'); |
15 | | - html = html.replace(/^#### (.*$)/gim, '<h4>$1</h4>'); |
16 | | - html = html.replace(/^### (.*$)/gim, '<h3>$1</h3>'); |
17 | | - html = html.replace(/^## (.*$)/gim, '<h2>$1</h2>'); |
18 | | - html = html.replace(/^# (.*$)/gim, '<h1>$1</h1>'); |
19 | | - |
20 | | - // Bold |
21 | | - html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>'); |
22 | | - html = html.replace(/__(.+?)__/g, '<strong>$1</strong>'); |
23 | | - |
24 | | - // Italic |
25 | | - html = html.replace(/\*(.+?)\*/g, '<em>$1</em>'); |
26 | | - html = html.replace(/_(.+?)_/g, '<em>$1</em>'); |
27 | | - |
28 | | - // Code blocks with language support (including mermaid) |
29 | | - html = html.replace(/```(\w+)?\n([\s\S]*?)```/g, function(match, lang, code) { |
30 | | - code = code.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); |
31 | | - if (lang === 'mermaid') { |
32 | | - return '<div class="mermaid">' + code + '</div>'; |
33 | | - } |
34 | | - return '<pre><code class="language-' + (lang || 'plaintext') + '">' + code.replace(/</g, '<').replace(/>/g, '>') + '</code></pre>'; |
| 6 | + // Configure marked |
| 7 | + if (typeof marked !== 'undefined') { |
| 8 | + marked.setOptions({ |
| 9 | + gfm: true, |
| 10 | + breaks: true |
35 | 11 | }); |
36 | | - |
37 | | - // Inline code |
38 | | - html = html.replace(/`([^`]+)`/g, '<code>$1</code>'); |
39 | | - |
40 | | - // Links |
41 | | - html = html.replace(/\[([^\]]+)\]\(([^\)]+)\)/g, '<a href="$2">$1</a>'); |
42 | | - |
43 | | - // Images |
44 | | - html = html.replace(/!\[([^\]]*)\]\(([^\)]+)\)/g, '<img src="$2" alt="$1" />'); |
45 | | - |
46 | | - // Blockquotes |
47 | | - html = html.replace(/^\> (.+)$/gim, '<blockquote>$1</blockquote>'); |
48 | | - |
49 | | - // Horizontal rules |
50 | | - html = html.replace(/^---$/gim, '<hr>'); |
51 | | - html = html.replace(/^\*\*\*$/gim, '<hr>'); |
52 | | - |
53 | | - // Unordered lists |
54 | | - html = html.replace(/^\* (.+)$/gim, '<li>$1</li>'); |
55 | | - html = html.replace(/^- (.+)$/gim, '<li>$1</li>'); |
56 | | - html = html.replace(/(<li>.*<\/li>)/s, '<ul>$1</ul>'); |
57 | | - |
58 | | - // Ordered lists |
59 | | - html = html.replace(/^\d+\. (.+)$/gim, '<li>$1</li>'); |
60 | | - |
61 | | - // Tables (basic support) |
62 | | - html = html.replace(/\|(.+)\|/g, function(match) { |
63 | | - const cells = match.split('|').filter(cell => cell.trim()); |
64 | | - return '<tr>' + cells.map(cell => '<td>' + cell.trim() + '</td>').join('') + '</tr>'; |
65 | | - }); |
66 | | - html = html.replace(/(<tr>.*<\/tr>)/s, '<table>$1</table>'); |
67 | | - |
68 | | - // Paragraphs |
69 | | - html = html.replace(/\n\n/g, '</p><p>'); |
70 | | - html = '<p>' + html + '</p>'; |
71 | | - |
72 | | - // Clean up |
73 | | - html = html.replace(/<p><\/p>/g, ''); |
74 | | - html = html.replace(/<p>(<h[1-6]>)/g, '$1'); |
75 | | - html = html.replace(/(<\/h[1-6]>)<\/p>/g, '$1'); |
76 | | - html = html.replace(/<p>(<table>)/g, '$1'); |
77 | | - html = html.replace(/(<\/table>)<\/p>/g, '$1'); |
78 | | - html = html.replace(/<p>(<ul>)/g, '$1'); |
79 | | - html = html.replace(/(<\/ul>)<\/p>/g, '$1'); |
80 | | - html = html.replace(/<p>(<pre>)/g, '$1'); |
81 | | - html = html.replace(/(<\/pre>)<\/p>/g, '$1'); |
82 | | - html = html.replace(/<p>(<div class="mermaid">)/g, '$1'); |
83 | | - html = html.replace(/(<\/div>)<\/p>/g, '$1'); |
84 | | - html = html.replace(/<p>(<hr>)<\/p>/g, '$1'); |
85 | | - html = html.replace(/<p>(<blockquote>)/g, '$1'); |
86 | | - html = html.replace(/(<\/blockquote>)<\/p>/g, '$1'); |
87 | | - |
88 | | - return html; |
89 | 12 | } |
90 | 13 |
|
91 | 14 | // Initialize mermaid |
|
181 | 104 | } |
182 | 105 |
|
183 | 106 | async renderMarkdown(markdown) { |
184 | | - const html = parseMarkdown(markdown); |
185 | 107 | const content = document.getElementById('markdown-content'); |
| 108 | + |
| 109 | + // Parse markdown to HTML |
| 110 | + const html = marked.parse(markdown); |
186 | 111 | content.innerHTML = html; |
187 | 112 |
|
188 | | - // Process mermaid diagrams |
| 113 | + // Convert mermaid code blocks to mermaid divs |
| 114 | + const mermaidBlocks = content.querySelectorAll('code.language-mermaid'); |
| 115 | + mermaidBlocks.forEach((block) => { |
| 116 | + const div = document.createElement('div'); |
| 117 | + div.className = 'mermaid'; |
| 118 | + div.textContent = block.textContent; |
| 119 | + block.parentElement.replaceWith(div); |
| 120 | + }); |
| 121 | + |
| 122 | + // Render mermaid diagrams |
189 | 123 | const mermaidDivs = content.querySelectorAll('.mermaid'); |
190 | 124 | if (mermaidDivs.length > 0) { |
191 | 125 | try { |
|
202 | 136 | } |
203 | 137 | } |
204 | 138 |
|
205 | | - // Navigation tree renderer with proper subsection support |
| 139 | + // Navigation tree renderer |
206 | 140 | function renderNavTree(tree, container, depth = 0) { |
207 | 141 | if (!tree || typeof tree !== 'object') return; |
208 | 142 |
|
209 | 143 | for (const [moduleName, moduleData] of Object.entries(tree)) { |
| 144 | + // Skip metadata fields |
210 | 145 | if (moduleName === 'description' || moduleName === 'components') continue; |
211 | 146 |
|
212 | | - // Check if this has components (is a page) or just children (is a section) |
213 | | - const hasComponents = moduleData && moduleData.components && moduleData.components.length > 0; |
214 | | - const hasChildren = moduleData && moduleData.children && Object.keys(moduleData.children).length > 0; |
215 | | - |
216 | | - if (hasComponents) { |
217 | | - // This is a page - render as link |
218 | | - const item = document.createElement('div'); |
219 | | - item.className = depth > 0 ? 'nav-subsection' : 'nav-item'; |
220 | | - |
221 | | - const link = document.createElement('a'); |
222 | | - link.href = `#/${moduleName}.md`; |
223 | | - link.textContent = formatModuleName(moduleName); |
224 | | - link.className = 'nav-link'; |
225 | | - |
226 | | - item.appendChild(link); |
227 | | - container.appendChild(item); |
228 | | - } else if (hasChildren) { |
229 | | - // This is a section header - render as text |
230 | | - const sectionHeader = document.createElement('div'); |
231 | | - sectionHeader.className = 'nav-section-header'; |
232 | | - sectionHeader.textContent = formatModuleName(moduleName); |
233 | | - if (depth > 0) { |
234 | | - sectionHeader.style.fontSize = `${14 - (depth * 1)}px`; |
235 | | - sectionHeader.style.textTransform = 'none'; |
236 | | - } |
237 | | - container.appendChild(sectionHeader); |
| 147 | + // Create navigation item |
| 148 | + const item = document.createElement('div'); |
| 149 | + if (depth > 0) { |
| 150 | + item.className = 'nav-subsection'; |
| 151 | + } else { |
| 152 | + item.className = 'nav-item'; |
238 | 153 | } |
239 | 154 |
|
240 | | - // Render children recursively |
241 | | - if (hasChildren) { |
242 | | - const subsection = document.createElement('div'); |
243 | | - subsection.className = 'nav-subsection'; |
244 | | - container.appendChild(subsection); |
245 | | - renderNavTree(moduleData.children, subsection, depth + 1); |
| 155 | + const link = document.createElement('a'); |
| 156 | + link.href = `#/${moduleName}.md`; |
| 157 | + link.textContent = formatModuleName(moduleName); |
| 158 | + link.className = 'nav-link'; |
| 159 | + |
| 160 | + item.appendChild(link); |
| 161 | + container.appendChild(item); |
| 162 | + |
| 163 | + // Render children recursively if they exist |
| 164 | + if (moduleData && moduleData.children && Object.keys(moduleData.children).length > 0) { |
| 165 | + renderNavTree(moduleData.children, container, depth + 1); |
246 | 166 | } |
247 | 167 | } |
248 | 168 | } |
|
0 commit comments