# Developer Guide - Documentation System ## System Overview This documentation system is a Single Page Application (SPA) that uses JavaScript to load and display Markdown files in real-time. ## System Architecture ### File Structure ``` documentation/ ├── index.html # Main page (SPA) ├── docs/ # Markdown documentation │ ├── th/ # Thai language │ └── en/ # English language └── README.md # Project guide ``` ### Technologies Used - **HTML5** - Web page structure - **CSS3** - Styling (CSS Variables, Flexbox, Grid) - **JavaScript ES6+** - Application logic - **Marked.js** - Markdown to HTML conversion - **Highlight.js** - Code syntax highlighting ## Code Structure ### HTML Structure ```html
``` ### CSS Architecture #### CSS Variables ```css :root { --bg-primary: #ffffff; --bg-secondary: #f8f9fa; --text-primary: #212529; --accent: #0d6efd; } [data-theme="dark"] { --bg-primary: #1a1d23; --bg-secondary: #22252b; --text-primary: #e9ecef; --accent: #4dabf7; } ``` #### Component-based CSS ```css /* Header */ .header { /* styles */ } .logo { /* styles */ } .btn { /* styles */ } /* Sidebar */ .sidebar { /* styles */ } .file-item { /* styles */ } /* Main Content */ .main-content { /* styles */ } .markdown-content { /* styles */ } ``` ### JavaScript Architecture #### State Management ```javascript // Global state let currentLang = 'th'; let currentTheme = 'light'; let docs = {}; let currentDoc = null; ``` #### Core Functions ##### 1. Document Loading ```javascript async function loadDocsFromFolder() { try { const thFiles = await loadMarkdownFiles('docs/th/'); const enFiles = await loadMarkdownFiles('docs/en/'); docs = {}; // Process Thai files Object.keys(thFiles).forEach(fileName => { if (!docs[fileName]) docs[fileName] = {}; docs[fileName]['th'] = thFiles[fileName]; }); // Process English files Object.keys(enFiles).forEach(fileName => { if (!docs[fileName]) docs[fileName] = {}; docs[fileName]['en'] = enFiles[fileName]; }); renderFileTree(); loadFirstDocument(); } catch (error) { showNoDocsError(); } } ``` ##### 2. Markdown Processing ```javascript function loadDocument(docName) { currentDoc = docName; const docContent = docs[docName][currentLang] || docs[docName]['en'] || docs[docName]['th']; if (!docContent) { showDocumentNotFound(); return; } // Convert markdown to HTML const html = marked.parse(docContent); content.innerHTML = html; // Highlight code blocks content.querySelectorAll('pre code').forEach((block) => { hljs.highlightElement(block); }); updateActiveState(); } ``` ##### 3. Theme Management ```javascript function toggleTheme() { currentTheme = currentTheme === 'light' ? 'dark' : 'light'; document.documentElement.setAttribute('data-theme', currentTheme); localStorage.setItem('theme', currentTheme); } // Load saved theme const savedTheme = localStorage.getItem('theme'); if (savedTheme) { currentTheme = savedTheme; document.documentElement.setAttribute('data-theme', currentTheme); } ``` ##### 4. Language Management ```javascript function toggleLanguage() { currentLang = currentLang === 'th' ? 'en' : 'th'; localStorage.setItem('language', currentLang); if (currentDoc) { loadDocument(currentDoc); } } // Load saved language const savedLang = localStorage.getItem('language'); if (savedLang) { currentLang = savedLang; } ``` ## Adding New Features ### 1. Adding New Buttons ```javascript // Create new button function createNewButton() { const button = document.createElement('button'); button.className = 'btn'; button.innerHTML = '🆕 New Feature'; button.id = 'newFeatureBtn'; // Add event listener button.addEventListener('click', handleNewFeature); // Add to header document.querySelector('.header-controls').appendChild(button); } function handleNewFeature() { // Feature logic console.log('New feature activated'); } ``` ### 2. Adding New Menus ```javascript // Add menu to sidebar function addCustomMenu() { const menu = document.getElementById('fileTree'); const menuItem = document.createElement('div'); menuItem.className = 'file-item'; menuItem.innerHTML = '📄New Menu'; menuItem.onclick = () => loadCustomContent(); menu.appendChild(menuItem); } function loadCustomContent() { const content = `

New Menu

Custom menu content

`; document.getElementById('content').innerHTML = content; } ``` ### 3. Adding Search Feature ```javascript // Create search input function addSearchFeature() { const searchContainer = document.createElement('div'); searchContainer.className = 'search-container'; const searchInput = document.createElement('input'); searchInput.type = 'text'; searchInput.placeholder = 'Search documents...'; searchInput.className = 'search-input'; searchInput.addEventListener('input', handleSearch); searchContainer.appendChild(searchInput); document.querySelector('.header-controls').appendChild(searchContainer); } function handleSearch(event) { const query = event.target.value.toLowerCase(); const fileItems = document.querySelectorAll('.file-item'); fileItems.forEach(item => { const text = item.textContent.toLowerCase(); if (text.includes(query)) { item.style.display = 'block'; } else { item.style.display = 'none'; } }); } ``` ### 4. Adding Print Feature ```javascript // Add print button function addPrintFeature() { const printBtn = document.createElement('button'); printBtn.className = 'btn'; printBtn.innerHTML = '🖨️ Print'; printBtn.onclick = () => { window.print(); }; document.querySelector('.header-controls').appendChild(printBtn); } // CSS for printing const printStyles = ` @media print { .header, .sidebar { display: none; } .main-content { margin: 0; padding: 0; } } `; ``` ## UI Customization ### 1. Changing Colors ```css /* Add new colors */ :root { --primary-color: #007bff; --secondary-color: #6c757d; --success-color: #28a745; --warning-color: #ffc107; --danger-color: #dc3545; } /* Use new colors */ .btn-primary { background-color: var(--primary-color); } .btn-secondary { background-color: var(--secondary-color); } ``` ### 2. Changing Fonts ```css /* Add new fonts */ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; } /* Font for code */ code, pre { font-family: 'Fira Code', 'Monaco', 'Consolas', monospace; } ``` ### 3. Adding Animations ```css /* Add transitions */ .file-item { transition: all 0.3s ease; } .file-item:hover { transform: translateX(4px); background-color: var(--accent); } /* Loading animation */ .loading { animation: spin 1s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } ``` ## State Management ### 1. Local Storage ```javascript // Save state function saveState() { localStorage.setItem('currentLang', currentLang); localStorage.setItem('currentTheme', currentTheme); localStorage.setItem('currentDoc', currentDoc); } // Load state function loadState() { currentLang = localStorage.getItem('currentLang') || 'th'; currentTheme = localStorage.getItem('currentTheme') || 'light'; currentDoc = localStorage.getItem('currentDoc'); // Use loaded state document.documentElement.setAttribute('data-theme', currentTheme); if (currentDoc) { loadDocument(currentDoc); } } ``` ### 2. Session Storage ```javascript // Save session data function saveSessionData() { sessionStorage.setItem('lastVisit', new Date().toISOString()); sessionStorage.setItem('visitedDocs', JSON.stringify(visitedDocs)); } // Load session data function loadSessionData() { const lastVisit = sessionStorage.getItem('lastVisit'); const visitedDocs = JSON.parse(sessionStorage.getItem('visitedDocs') || '[]'); console.log('Last visit:', lastVisit); console.log('Visited docs:', visitedDocs); } ``` ## Error Handling ### 1. Error Handling ```javascript // Global error handler window.addEventListener('error', (event) => { console.error('Global error:', event.error); showErrorMessage('System error occurred'); }); // Promise error handling async function loadDocument(docName) { try { const docContent = docs[docName][currentLang]; if (!docContent) { throw new Error(`Document not found: ${docName}`); } const html = marked.parse(docContent); content.innerHTML = html; } catch (error) { console.error('Error loading document:', error); showErrorMessage(`Cannot load document: ${error.message}`); } } ``` ### 2. Loading States ```javascript // Show loading state function showLoading() { content.innerHTML = `

Loading...

`; } // Hide loading state function hideLoading() { const loadingState = document.querySelector('.loading-state'); if (loadingState) { loadingState.remove(); } } ``` ## Testing ### 1. Unit Testing ```javascript // Example unit test function testLoadDocument() { const mockDocs = { 'test': { 'th': '# ทดสอบ\nเนื้อหาทดสอบ', 'en': '# Test\nTest content' } }; docs = mockDocs; currentLang = 'th'; loadDocument('test'); const content = document.getElementById('content'); assert(content.innerHTML.includes('ทดสอบ')); } function testThemeToggle() { currentTheme = 'light'; toggleTheme(); assert(currentTheme === 'dark'); assert(document.documentElement.getAttribute('data-theme') === 'dark'); } ``` ### 2. Integration Testing ```javascript // Example integration test async function testFullWorkflow() { // 1. Load documents await loadDocsFromFolder(); // 2. Change language toggleLanguage(); // 3. Change theme toggleTheme(); // 4. Check results assert(document.documentElement.getAttribute('data-theme') === 'dark'); assert(currentLang === 'en'); } ``` ## Deployment ### 1. Build Process ```bash #!/bin/bash # build.sh # Create production build echo "Building production version..." # Copy files cp -r docs/ dist/ cp index.html dist/ cp README.md dist/ # Minify CSS (optional) # npx clean-css-cli -o dist/styles.min.css styles.css # Minify JS (optional) # npx terser dist/script.js -o dist/script.min.js echo "Build completed!" ``` ### 2. Docker Deployment ```dockerfile # Dockerfile FROM nginx:alpine COPY . /usr/share/nginx/html EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] ``` ```bash # Build and run docker build -t documentation-system . docker run -p 80:80 documentation-system ``` ### 3. CI/CD Pipeline ```yaml # .github/workflows/deploy.yml name: Deploy Documentation on: push: branches: [ main ] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Deploy to server run: | rsync -avz --delete . user@server:/var/www/docs/ ``` ## Maintenance ### 1. Performance Monitoring ```javascript // Measure performance function measurePerformance() { const startTime = performance.now(); loadDocument('index'); const endTime = performance.now(); console.log(`Document load time: ${endTime - startTime}ms`); } // Check memory usage function checkMemoryUsage() { if (performance.memory) { console.log('Memory usage:', { used: performance.memory.usedJSHeapSize, total: performance.memory.totalJSHeapSize, limit: performance.memory.jsHeapSizeLimit }); } } ``` ### 2. Analytics ```javascript // Track usage function trackUsage(action, data) { // Google Analytics if (typeof gtag !== 'undefined') { gtag('event', action, data); } // Custom analytics fetch('/api/analytics', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action, data, timestamp: Date.now() }) }); } // Track language changes function trackLanguageChange(lang) { trackUsage('language_change', { language: lang }); } // Track theme changes function trackThemeChange(theme) { trackUsage('theme_change', { theme: theme }); } ``` ## Further Development ### 1. Adding PWA Support ```javascript // Service Worker if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js') .then(registration => console.log('SW registered')) .catch(error => console.log('SW registration failed')); } // Manifest const manifest = { "name": "Kotchasan Documentation", "short_name": "Docs", "start_url": "/", "display": "standalone", "theme_color": "#0d6efd", "background_color": "#ffffff" }; ``` ### 2. Adding Offline Support ```javascript // Cache resources const CACHE_NAME = 'docs-v1'; const urlsToCache = [ '/', '/index.html', '/docs/th/index.md', '/docs/en/index.md' ]; self.addEventListener('install', event => { event.waitUntil( caches.open(CACHE_NAME) .then(cache => cache.addAll(urlsToCache)) ); }); ``` --- **Note**: This guide covers the documentation system development. For more information, please refer to the [Usage Guide](usage-guide.md)