Skip to content

Commit d1976c0

Browse files
committed
feat: Modernize and fix documentation with hierarchical structure
✨ Features: - Complete documentation modernization with hierarchical navigation - Interactive UI with grid cards, tabs, dropdowns, and modern styling - Enhanced Sphinx configuration with advanced extensions - Custom CSS/JS for modern user experience and interactivity - Comprehensive module coverage with auto-generated API documentation 🐛 Bug Fixes: - Fixed all 38 Sphinx build warnings (now 0 warnings) - Resolved grid directive syntax errors - Removed references to non-existent modules - Fixed import errors with autodoc_mock_imports - Corrected title underlines and document references - Removed unsupported theme options 🔧 Technical Improvements: - Added sphinx-design for modern UI components - Implemented responsive design with mobile support - Enhanced code blocks with copy functionality - Added smooth scrolling and progressive disclosure - Integrated search highlighting and accessibility features - Updated CI/CD workflow for enhanced doc generation 📁 Files Added: - Complete module documentation (.rst files) - Missing __init__.py files for proper module structure - Enhanced static assets (custom.css, custom.js) - Modern Sphinx configuration 🏗️ Architecture: - Hierarchical documentation structure with clear navigation - Interactive architecture overview with component deep dives - Enhanced user experience with modern web standards - Production-ready documentation build system
1 parent e3418c4 commit d1976c0

37 files changed

+1068
-251
lines changed

doc/CodeDocs/_static/custom.js

Lines changed: 391 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,391 @@
1+
// Modern Interactive Documentation JavaScript
2+
// ===========================================
3+
4+
document.addEventListener('DOMContentLoaded', function() {
5+
'use strict';
6+
7+
// Initialize all interactive features
8+
initializeInteractiveFeatures();
9+
initializeSearchHighlighting();
10+
initializeCodeCopyButtons();
11+
initializeProgressiveDisclosure();
12+
initializeSmoothScrolling();
13+
initializeThemeToggle();
14+
15+
console.log('Enhanced documentation JavaScript loaded successfully');
16+
});
17+
18+
/**
19+
* Initialize all interactive features
20+
*/
21+
function initializeInteractiveFeatures() {
22+
// Add loading animations for heavy content
23+
const heavyContent = document.querySelectorAll('.architecture-diagram, .call-tree-diagram');
24+
heavyContent.forEach(element => {
25+
element.style.opacity = '0';
26+
element.style.transition = 'opacity 0.5s ease-in-out';
27+
28+
// Simulate loading and fade in
29+
setTimeout(() => {
30+
element.style.opacity = '1';
31+
}, 100);
32+
});
33+
34+
// Add hover effects for interactive elements
35+
const interactiveElements = document.querySelectorAll('.sd-card, .admonition, details.sd-dropdown');
36+
interactiveElements.forEach(element => {
37+
element.addEventListener('mouseenter', function() {
38+
this.style.transition = 'all 0.3s ease';
39+
});
40+
});
41+
}
42+
43+
/**
44+
* Enhanced search term highlighting
45+
*/
46+
function initializeSearchHighlighting() {
47+
// Get search terms from URL parameters
48+
const urlParams = new URLSearchParams(window.location.search);
49+
const searchTerm = urlParams.get('highlight');
50+
51+
if (searchTerm) {
52+
highlightSearchTerm(searchTerm);
53+
}
54+
}
55+
56+
/**
57+
* Highlight search terms in the document
58+
*/
59+
function highlightSearchTerm(term) {
60+
const walker = document.createTreeWalker(
61+
document.body,
62+
NodeFilter.SHOW_TEXT,
63+
{
64+
acceptNode: function(node) {
65+
// Skip script and style elements
66+
const parentTag = node.parentElement.tagName.toLowerCase();
67+
if (['script', 'style', 'noscript'].includes(parentTag)) {
68+
return NodeFilter.FILTER_REJECT;
69+
}
70+
return NodeFilter.FILTER_ACCEPT;
71+
}
72+
}
73+
);
74+
75+
const textNodes = [];
76+
let node;
77+
78+
while (node = walker.nextNode()) {
79+
textNodes.push(node);
80+
}
81+
82+
const regex = new RegExp(`(${term})`, 'gi');
83+
84+
textNodes.forEach(textNode => {
85+
if (regex.test(textNode.textContent)) {
86+
const parent = textNode.parentNode;
87+
const wrapper = document.createElement('span');
88+
wrapper.innerHTML = textNode.textContent.replace(regex, '<mark class="search-highlight">$1</mark>');
89+
parent.replaceChild(wrapper, textNode);
90+
}
91+
});
92+
93+
// Add CSS for search highlighting
94+
if (!document.getElementById('search-highlight-styles')) {
95+
const style = document.createElement('style');
96+
style.id = 'search-highlight-styles';
97+
style.textContent = `
98+
.search-highlight {
99+
background-color: #ffeb3b;
100+
color: #333;
101+
padding: 2px 4px;
102+
border-radius: 3px;
103+
font-weight: 600;
104+
animation: highlight-pulse 2s ease-in-out;
105+
}
106+
107+
@keyframes highlight-pulse {
108+
0% { background-color: #ffeb3b; }
109+
50% { background-color: #ff9800; }
110+
100% { background-color: #ffeb3b; }
111+
}
112+
`;
113+
document.head.appendChild(style);
114+
}
115+
}
116+
117+
/**
118+
* Enhanced copy buttons for code blocks
119+
*/
120+
function initializeCodeCopyButtons() {
121+
const codeBlocks = document.querySelectorAll('.highlight pre');
122+
123+
codeBlocks.forEach(codeBlock => {
124+
// Skip if copy button already exists
125+
if (codeBlock.parentNode.querySelector('.copy-button')) {
126+
return;
127+
}
128+
129+
const copyButton = document.createElement('button');
130+
copyButton.className = 'copy-button';
131+
copyButton.innerHTML = `
132+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
133+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
134+
<path d="m5 15-4 4c-1-5 0-7 4-11 4-4 8-3 11 0l4 4c3 3 4 7 0 11-4 4-8 3-11 0z"></path>
135+
</svg>
136+
Copy
137+
`;
138+
copyButton.title = 'Copy code to clipboard';
139+
140+
copyButton.addEventListener('click', async function() {
141+
const code = codeBlock.textContent;
142+
143+
try {
144+
await navigator.clipboard.writeText(code);
145+
146+
// Visual feedback
147+
copyButton.innerHTML = `
148+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
149+
<polyline points="20,6 9,17 4,12"></polyline>
150+
</svg>
151+
Copied!
152+
`;
153+
copyButton.style.background = '#28a745';
154+
copyButton.style.color = 'white';
155+
156+
setTimeout(() => {
157+
copyButton.innerHTML = `
158+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
159+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
160+
<path d="m5 15-4 4c-1-5 0-7 4-11 4-4 8-3 11 0l4 4c3 3 4 7 0 11-4 4-8 3-11 0z"></path>
161+
</svg>
162+
Copy
163+
`;
164+
copyButton.style.background = '';
165+
copyButton.style.color = '';
166+
}, 2000);
167+
168+
} catch (err) {
169+
console.error('Failed to copy code:', err);
170+
copyButton.innerHTML = 'Failed to copy';
171+
setTimeout(() => {
172+
copyButton.innerHTML = `
173+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
174+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
175+
<path d="m5 15-4 4c-1-5 0-7 4-11 4-4 8-3 11 0l4 4c3 3 4 7 0 11-4 4-8 3-11 0z"></path>
176+
</svg>
177+
Copy
178+
`;
179+
}, 2000);
180+
}
181+
});
182+
183+
// Position the button
184+
const container = codeBlock.parentNode;
185+
container.style.position = 'relative';
186+
container.appendChild(copyButton);
187+
});
188+
189+
// Add CSS for copy buttons
190+
if (!document.getElementById('copy-button-styles')) {
191+
const style = document.createElement('style');
192+
style.id = 'copy-button-styles';
193+
style.textContent = `
194+
.copy-button {
195+
position: absolute;
196+
top: 10px;
197+
right: 10px;
198+
background: rgba(255, 255, 255, 0.1);
199+
border: 1px solid rgba(255, 255, 255, 0.2);
200+
color: rgba(255, 255, 255, 0.8);
201+
padding: 6px 12px;
202+
border-radius: 4px;
203+
font-size: 12px;
204+
cursor: pointer;
205+
display: flex;
206+
align-items: center;
207+
gap: 4px;
208+
transition: all 0.2s ease;
209+
backdrop-filter: blur(10px);
210+
z-index: 10;
211+
}
212+
213+
.copy-button:hover {
214+
background: rgba(255, 255, 255, 0.2);
215+
border-color: rgba(255, 255, 255, 0.3);
216+
color: white;
217+
}
218+
219+
.copy-button svg {
220+
width: 16px;
221+
height: 16px;
222+
}
223+
`;
224+
document.head.appendChild(style);
225+
}
226+
}
227+
228+
/**
229+
* Progressive disclosure for large sections
230+
*/
231+
function initializeProgressiveDisclosure() {
232+
// Auto-collapse large sections on mobile
233+
if (window.innerWidth < 768) {
234+
const largeSections = document.querySelectorAll('details.sd-dropdown');
235+
largeSections.forEach((section, index) => {
236+
if (index > 2) { // Keep first 3 open, collapse rest
237+
section.removeAttribute('open');
238+
}
239+
});
240+
}
241+
242+
// Add expand/collapse all functionality
243+
const navSection = document.querySelector('.sidebar-navigation') || document.querySelector('nav');
244+
if (navSection) {
245+
const expandAllBtn = document.createElement('button');
246+
expandAllBtn.textContent = 'Expand All Sections';
247+
expandAllBtn.className = 'expand-all-btn';
248+
expandAllBtn.style.cssText = `
249+
margin: 10px 0;
250+
padding: 8px 16px;
251+
background: var(--primary-color, #0066cc);
252+
color: white;
253+
border: none;
254+
border-radius: 4px;
255+
cursor: pointer;
256+
font-size: 12px;
257+
width: 100%;
258+
`;
259+
260+
let allExpanded = false;
261+
expandAllBtn.addEventListener('click', function() {
262+
const dropdowns = document.querySelectorAll('details.sd-dropdown');
263+
264+
if (allExpanded) {
265+
dropdowns.forEach(dropdown => dropdown.removeAttribute('open'));
266+
expandAllBtn.textContent = 'Expand All Sections';
267+
allExpanded = false;
268+
} else {
269+
dropdowns.forEach(dropdown => dropdown.setAttribute('open', ''));
270+
expandAllBtn.textContent = 'Collapse All Sections';
271+
allExpanded = true;
272+
}
273+
});
274+
275+
navSection.appendChild(expandAllBtn);
276+
}
277+
}
278+
279+
/**
280+
* Smooth scrolling for internal links
281+
*/
282+
function initializeSmoothScrolling() {
283+
const internalLinks = document.querySelectorAll('a[href^="#"]');
284+
285+
internalLinks.forEach(link => {
286+
link.addEventListener('click', function(e) {
287+
const targetId = this.getAttribute('href').substring(1);
288+
const targetElement = document.getElementById(targetId);
289+
290+
if (targetElement) {
291+
e.preventDefault();
292+
293+
targetElement.scrollIntoView({
294+
behavior: 'smooth',
295+
block: 'start'
296+
});
297+
298+
// Update URL without triggering scroll
299+
history.pushState(null, null, `#${targetId}`);
300+
301+
// Highlight the target element briefly
302+
targetElement.style.transition = 'background-color 0.3s ease';
303+
targetElement.style.backgroundColor = 'rgba(0, 102, 204, 0.1)';
304+
305+
setTimeout(() => {
306+
targetElement.style.backgroundColor = '';
307+
}, 1500);
308+
}
309+
});
310+
});
311+
}
312+
313+
/**
314+
* Theme toggle functionality (if supported)
315+
*/
316+
function initializeThemeToggle() {
317+
// Check if theme toggle is supported by the current theme
318+
const themeToggle = document.querySelector('.theme-toggle');
319+
320+
if (themeToggle || window.matchMedia) {
321+
// Add theme preference handling
322+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
323+
324+
if (prefersDark.matches) {
325+
document.body.classList.add('dark-theme');
326+
}
327+
328+
// Listen for theme changes
329+
prefersDark.addListener((e) => {
330+
if (e.matches) {
331+
document.body.classList.add('dark-theme');
332+
} else {
333+
document.body.classList.remove('dark-theme');
334+
}
335+
});
336+
}
337+
}
338+
339+
/**
340+
* Lazy loading for images and heavy content
341+
*/
342+
function initializeLazyLoading() {
343+
if ('IntersectionObserver' in window) {
344+
const imageObserver = new IntersectionObserver((entries, observer) => {
345+
entries.forEach(entry => {
346+
if (entry.isIntersecting) {
347+
const img = entry.target;
348+
if (img.dataset.src) {
349+
img.src = img.dataset.src;
350+
img.classList.remove('lazy');
351+
observer.unobserve(img);
352+
}
353+
}
354+
});
355+
});
356+
357+
const lazyImages = document.querySelectorAll('img[data-src]');
358+
lazyImages.forEach(img => imageObserver.observe(img));
359+
}
360+
}
361+
362+
/**
363+
* Performance monitoring
364+
*/
365+
function initializePerformanceMonitoring() {
366+
if ('PerformanceObserver' in window) {
367+
const perfObserver = new PerformanceObserver((list) => {
368+
list.getEntries().forEach((entry) => {
369+
if (entry.entryType === 'navigation') {
370+
console.log(`Page load time: ${entry.loadEventEnd - entry.loadEventStart}ms`);
371+
}
372+
});
373+
});
374+
375+
perfObserver.observe({ entryTypes: ['navigation'] });
376+
}
377+
}
378+
379+
// Initialize additional features when the page is fully loaded
380+
window.addEventListener('load', function() {
381+
initializeLazyLoading();
382+
initializePerformanceMonitoring();
383+
});
384+
385+
// Export functions for external use
386+
window.DocumentationEnhancements = {
387+
highlightSearchTerm,
388+
initializeCodeCopyButtons,
389+
initializeProgressiveDisclosure,
390+
initializeSmoothScrolling
391+
};

0 commit comments

Comments
 (0)