developer-guide.md

15.79 KB
01/10/2025 12:35
MD
developer-guide.md
# คู่มือนักพัฒนา - Documentation System

## ภาพรวมระบบ

ระบบเอกสารนี้เป็น Single Page Application (SPA) ที่ใช้ JavaScript ในการโหลดและแสดงผลไฟล์ Markdown แบบเรียลไทม์

## สถาปัตยกรรมระบบ

### โครงสร้างไฟล์

```
documentation/
├── index.html              # หน้าหลัก (SPA)
├── docs/                   # เอกสาร Markdown
│   ├── th/                # ภาษาไทย
│   └── en/                # ภาษาอังกฤษ
└── README.md              # คู่มือโปรเจ็ค
```

### เทคโนโลยีที่ใช้

- **HTML5** - โครงสร้างหน้าเว็บ
- **CSS3** - การจัดรูปแบบ (CSS Variables, Flexbox, Grid)
- **JavaScript ES6+** - ตรรกะการทำงาน
- **Marked.js** - แปลง Markdown เป็น HTML
- **Highlight.js** - เน้นสีโค้ด

## โครงสร้างโค้ด

### 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;
}
```

## การพัฒนาฟีเจอร์ใหม่

### 1. เพิ่มปุ่มใหม่

```javascript
// สร้างปุ่มใหม่
function createNewButton() {
    const button = document.createElement('button');
    button.className = 'btn';
    button.innerHTML = '🆕 ฟีเจอร์ใหม่';
    button.id = 'newFeatureBtn';

    // เพิ่ม event listener
    button.addEventListener('click', handleNewFeature);

    // เพิ่มเข้า header
    document.querySelector('.header-controls').appendChild(button);
}

function handleNewFeature() {
    // ตรรกะการทำงาน
    console.log('New feature activated');
}
```

### 2. เพิ่มเมนูใหม่

```javascript
// เพิ่มเมนูใน sidebar
function addCustomMenu() {
    const menu = document.getElementById('fileTree');
    const menuItem = document.createElement('div');
    menuItem.className = 'file-item';
    menuItem.innerHTML = '<span class="file-icon">📄</span>เมนูใหม่';
    menuItem.onclick = () => loadCustomContent();
    menu.appendChild(menuItem);
}

function loadCustomContent() {
    const content = `
        <h1>เมนูใหม่</h1>
        <p>เนื้อหาของเมนูใหม่</p>
    `;
    document.getElementById('content').innerHTML = content;
}
```

### 3. เพิ่มฟีเจอร์ค้นหา

```javascript
// สร้าง search input
function addSearchFeature() {
    const searchContainer = document.createElement('div');
    searchContainer.className = 'search-container';

    const searchInput = document.createElement('input');
    searchInput.type = 'text';
    searchInput.placeholder = 'ค้นหาเอกสาร...';
    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. เพิ่มฟีเจอร์พิมพ์

```javascript
// เพิ่มปุ่มพิมพ์
function addPrintFeature() {
    const printBtn = document.createElement('button');
    printBtn.className = 'btn';
    printBtn.innerHTML = '🖨️ พิมพ์';
    printBtn.onclick = () => {
        window.print();
    };
    document.querySelector('.header-controls').appendChild(printBtn);
}

// CSS สำหรับการพิมพ์
const printStyles = `
@media print {
    .header, .sidebar {
        display: none;
    }
    .main-content {
        margin: 0;
        padding: 0;
    }
}
`;
```

## การปรับแต่ง UI

### 1. เปลี่ยนสี

```css
/* เพิ่มสีใหม่ */
:root {
    --primary-color: #007bff;
    --secondary-color: #6c757d;
    --success-color: #28a745;
    --warning-color: #ffc107;
    --danger-color: #dc3545;
}

/* ใช้สีใหม่ */
.btn-primary {
    background-color: var(--primary-color);
}

.btn-secondary {
    background-color: var(--secondary-color);
}
```

### 2. เปลี่ยนฟอนต์

```css
/* เพิ่มฟอนต์ใหม่ */
@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;
}

/* ฟอนต์สำหรับโค้ด */
code, pre {
    font-family: 'Fira Code', 'Monaco', 'Consolas', monospace;
}
```

### 3. เพิ่ม Animation

```css
/* เพิ่ม transition */
.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

### 1. Local Storage

```javascript
// บันทึก state
function saveState() {
    localStorage.setItem('currentLang', currentLang);
    localStorage.setItem('currentTheme', currentTheme);
    localStorage.setItem('currentDoc', currentDoc);
}

// โหลด state
function loadState() {
    currentLang = localStorage.getItem('currentLang') || 'th';
    currentTheme = localStorage.getItem('currentTheme') || 'light';
    currentDoc = localStorage.getItem('currentDoc');

    // ใช้ state ที่โหลดมา
    document.documentElement.setAttribute('data-theme', currentTheme);
    if (currentDoc) {
        loadDocument(currentDoc);
    }
}
```

### 2. Session Storage

```javascript
// บันทึก session data
function saveSessionData() {
    sessionStorage.setItem('lastVisit', new Date().toISOString());
    sessionStorage.setItem('visitedDocs', JSON.stringify(visitedDocs));
}

// โหลด 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

### 1. Error Handling

```javascript
// Global error handler
window.addEventListener('error', (event) => {
    console.error('Global error:', event.error);
    showErrorMessage('เกิดข้อผิดพลาดในระบบ');
});

// 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(`ไม่สามารถโหลดเอกสาร: ${error.message}`);
    }
}
```

### 2. Loading States

```javascript
// แสดง loading state
function showLoading() {
    content.innerHTML = `
        <div class="loading-state">
            <div class="loading-spinner"></div>
            <p>กำลังโหลด...</p>
        </div>
    `;
}

// ซ่อน loading state
function hideLoading() {
    const loadingState = document.querySelector('.loading-state');
    if (loadingState) {
        loadingState.remove();
    }
}
```

## การทดสอบ

### 1. Unit Testing

```javascript
// ตัวอย่าง 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
// ตัวอย่าง integration test
async function testFullWorkflow() {
    // 1. โหลดเอกสาร
    await loadDocsFromFolder();

    // 2. เปลี่ยนภาษา
    toggleLanguage();

    // 3. เปลี่ยนธีม
    toggleTheme();

    // 4. ตรวจสอบผลลัพธ์
    assert(document.documentElement.getAttribute('data-theme') === 'dark');
    assert(currentLang === 'en');
}
```

## การ Deploy

### 1. Build Process

```bash
#!/bin/bash
# build.sh

# สร้าง 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/
```

## การบำรุงรักษา

### 1. Performance Monitoring

```javascript
// วัดประสิทธิภาพ
function measurePerformance() {
    const startTime = performance.now();

    loadDocument('index');

    const endTime = performance.now();
    console.log(`Document load time: ${endTime - startTime}ms`);
}

// ตรวจสอบ 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
// ติดตามการใช้งาน
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() })
    });
}

// ติดตามการเปลี่ยนภาษา
function trackLanguageChange(lang) {
    trackUsage('language_change', { language: lang });
}

// ติดตามการเปลี่ยนธีม
function trackThemeChange(theme) {
    trackUsage('theme_change', { theme: theme });
}
```

## การพัฒนาต่อ

### 1. เพิ่ม 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. เพิ่ม 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))
    );
});
```

---

**หมายเหตุ**: คู่มือนี้ครอบคลุมการพัฒนาระบบเอกสาร สำหรับข้อมูลเพิ่มเติมโปรดดูที่ [Usage Guide](usage-guide.md)