developer-guide.md

14.14 KB
01/10/2025 12:35
MD
developer-guide.md
# 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
<!DOCTYPE html>
<html lang="th">
<head>
    <!-- Meta tags, CSS, External libraries -->
</head>
<body>
    <header class="header">
        <!-- Logo, Language/Theme toggles -->
    </header>
    <aside class="sidebar" id="sidebar">
        <!-- File tree navigation -->
    </aside>
    <main class="main-content">
        <!-- Markdown content display -->
    </main>
</body>
</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 = '<span class="file-icon">📄</span>New Menu';
    menuItem.onclick = () => loadCustomContent();
    menu.appendChild(menuItem);
}

function loadCustomContent() {
    const content = `
        <h1>New Menu</h1>
        <p>Custom menu content</p>
    `;
    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 = `
        <div class="loading-state">
            <div class="loading-spinner"></div>
            <p>Loading...</p>
        </div>
    `;
}

// 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)