index.html

15.39 KB
01/10/2025 12:39
HTML
<!DOCTYPE html>
<html lang="th">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Kotchasan PHP Framework - Documentation</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/php.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/11.1.1/marked.min.js"></script>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    :root {
      --bg-primary: #ffffff;
      --bg-secondary: #f8f9fa;
      --bg-tertiary: #e9ecef;
      --text-primary: #212529;
      --text-secondary: #6c757d;
      --border-color: #dee2e6;
      --accent: #0d6efd;
      --accent-hover: #0b5ed7;
      --sidebar-width: 280px;
      --header-height: 64px;
    }

    [data-theme="dark"] {
      --bg-primary: #1a1d23;
      --bg-secondary: #22252b;
      --bg-tertiary: #2d3139;
      --text-primary: #e9ecef;
      --text-secondary: #adb5bd;
      --border-color: #3d4149;
      --accent: #4dabf7;
      --accent-hover: #339af0;
    }

    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
      background: var(--bg-primary);
      color: var(--text-primary);
      transition: background 0.3s, color 0.3s;
    }

    /* Header */
    .header {
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      height: var(--header-height);
      background: var(--bg-secondary);
      border-bottom: 1px solid var(--border-color);
      display: flex;
      align-items: center;
      padding: 0 2rem;
      z-index: 1000;
      gap: 2rem;
    }

    .logo {
      font-size: 1.5rem;
      font-weight: 700;
      color: var(--accent);
      text-decoration: none;
      display: flex;
      align-items: center;
      gap: 0.5rem;
    }

    .logo-icon {
      width: 32px;
      height: 32px;
      background: linear-gradient(135deg, var(--accent), var(--accent-hover));
      border-radius: 8px;
      display: flex;
      align-items: center;
      justify-content: center;
      color: white;
      font-weight: bold;
    }

    .header-controls {
      margin-left: auto;
      display: flex;
      gap: 1rem;
      align-items: center;
    }

    .btn {
      padding: 0.5rem 1rem;
      border: none;
      border-radius: 8px;
      cursor: pointer;
      font-size: 0.9rem;
      transition: all 0.3s;
      background: var(--bg-tertiary);
      color: var(--text-primary);
      display: flex;
      align-items: center;
      gap: 0.5rem;
    }

    .btn:hover {
      background: var(--accent);
      color: white;
      transform: translateY(-2px);
    }

    /* Sidebar */
    .sidebar {
      position: fixed;
      left: 0;
      top: var(--header-height);
      width: var(--sidebar-width);
      height: calc(100vh - var(--header-height));
      background: var(--bg-secondary);
      border-right: 1px solid var(--border-color);
      overflow-y: auto;
      padding: 1.5rem;
    }

    .file-tree {
      list-style: none;
    }

    .file-item {
      padding: 0.5rem 1rem;
      margin: 0.25rem 0;
      border-radius: 8px;
      cursor: pointer;
      transition: all 0.2s;
      color: var(--text-primary);
      display: flex;
      align-items: center;
      gap: 0.5rem;
    }

    .file-item:hover {
      background: var(--bg-tertiary);
      transform: translateX(4px);
    }

    .file-item.active {
      background: var(--accent);
      color: white;
    }

    .file-icon {
      width: 16px;
      height: 16px;
    }

    /* Main Content */
    .main-content {
      margin-left: var(--sidebar-width);
      margin-top: var(--header-height);
      padding: 3rem;
      max-width: 1200px;
    }

    .content-wrapper {
      background: var(--bg-secondary);
      border-radius: 12px;
      padding: 3rem;
      box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
    }

    /* Markdown Styles */
    .markdown-content h1 {
      font-size: 2.5rem;
      margin-bottom: 1rem;
      color: var(--text-primary);
      border-bottom: 2px solid var(--border-color);
      padding-bottom: 0.5rem;
    }

    .markdown-content h2 {
      font-size: 2rem;
      margin: 2rem 0 1rem;
      color: var(--text-primary);
    }

    .markdown-content h3 {
      font-size: 1.5rem;
      margin: 1.5rem 0 1rem;
      color: var(--text-primary);
    }

    .markdown-content p {
      line-height: 1.8;
      margin-bottom: 1rem;
      color: var(--text-secondary);
    }

    .markdown-content code {
      background: var(--bg-tertiary);
      padding: 0.2rem 0.4rem;
      border-radius: 4px;
      font-family: 'Courier New', monospace;
      font-size: 0.9em;
    }

    .markdown-content pre {
      background: #282c34;
      border-radius: 8px;
      padding: 1.5rem;
      overflow-x: auto;
      margin: 1.5rem 0;
    }

    .markdown-content pre code {
      background: none;
      padding: 0;
      color: #abb2bf;
    }

    .markdown-content ul,
    .markdown-content ol {
      margin: 1rem 0 1rem 2rem;
      color: var(--text-secondary);
    }

    .markdown-content li {
      margin: 0.5rem 0;
      line-height: 1.8;
    }

    .markdown-content a {
      color: var(--accent);
      text-decoration: none;
    }

    .markdown-content a:hover {
      text-decoration: underline;
    }

    .markdown-content blockquote {
      border-left: 4px solid var(--accent);
      padding-left: 1rem;
      margin: 1rem 0;
      color: var(--text-secondary);
      font-style: italic;
    }

    .markdown-content table {
      width: 100%;
      border-collapse: collapse;
      margin: 1.5rem 0;
    }

    .markdown-content th,
    .markdown-content td {
      border: 1px solid var(--border-color);
      padding: 0.75rem;
      text-align: left;
    }

    .markdown-content th {
      background: var(--bg-tertiary);
      font-weight: 600;
    }

    /* Empty State */
    .empty-state {
      text-align: center;
      padding: 4rem 2rem;
      color: var(--text-secondary);
    }

    .empty-state-icon {
      font-size: 4rem;
      margin-bottom: 1rem;
      opacity: 0.5;
    }

    .empty-state h2 {
      margin-bottom: 1rem;
    }

    .file-upload {
      margin-top: 2rem;
      padding: 2rem;
      border: 2px dashed var(--border-color);
      border-radius: 12px;
      cursor: pointer;
      transition: all 0.3s;
    }

    .file-upload:hover {
      border-color: var(--accent);
      background: var(--bg-tertiary);
    }

    .file-upload input {
      display: none;
    }

    /* Scrollbar */
    ::-webkit-scrollbar {
      width: 8px;
      height: 8px;
    }

    ::-webkit-scrollbar-track {
      background: var(--bg-secondary);
    }

    ::-webkit-scrollbar-thumb {
      background: var(--border-color);
      border-radius: 4px;
    }

    ::-webkit-scrollbar-thumb:hover {
      background: var(--text-secondary);
    }

    /* Responsive */
    @media (max-width: 768px) {
      .sidebar {
        transform: translateX(-100%);
        transition: transform 0.3s;
      }

      .sidebar.open {
        transform: translateX(0);
      }

      .main-content {
        margin-left: 0;
        padding: 1.5rem;
      }

      .content-wrapper {
        padding: 1.5rem;
      }

      .header {
        padding: 0 1rem;
      }
    }
  </style>
</head>

<body>
  <header class="header">
    <a href="#" class="logo">
      <div class="logo-icon">K</div>
      Kotchasan Framework
    </a>
    <div class="header-controls">
      <button class="btn" id="langBtn">🌐 TH</button>
      <button class="btn" id="themeBtn">🌙 Dark</button>
    </div>
  </header>

  <aside class="sidebar" id="sidebar">
    <div class="file-tree" id="fileTree">
      <div class="empty-state">
        <div class="empty-state-icon">📁</div>
        <p>ไม่พบไฟล์เอกสาร</p>
      </div>
    </div>
  </aside>

  <main class="main-content">
    <div class="content-wrapper">
      <div class="markdown-content" id="content">
        <div class="empty-state">
          <div class="empty-state-icon">📚</div>
          <h2>ยินดีต้อนรับสู่ Kotchasan PHP Framework</h2>
          <p>กรุณาอัปโหลดไฟล์ .md จากโฟลเดอร์ docs/ เพื่อแสดงเอกสาร</p>
          <div class="file-upload" onclick="document.getElementById('fileInput').click()">
            <p>📤 คลิกเพื่ออัปโหลดไฟล์ .md</p>
            <input type="file" id="fileInput" accept=".md" multiple>
          </div>
        </div>
      </div>
    </div>
  </main>

  <script>
    // State
    let currentLang = 'th';
    let currentTheme = 'light';
    let docs = {};
    let currentDoc = null;

    // Elements
    const themeBtn = document.getElementById('themeBtn');
    const langBtn = document.getElementById('langBtn');
    const fileInput = document.getElementById('fileInput');
    const fileTree = document.getElementById('fileTree');
    const content = document.getElementById('content');

    // Theme Toggle
    themeBtn.addEventListener('click', () => {
      currentTheme = currentTheme === 'light' ? 'dark' : 'light';
      document.documentElement.setAttribute('data-theme', currentTheme);
      themeBtn.textContent = currentTheme === 'light' ? '🌙 Dark' : '☀️ Light';
    });

    // Language Toggle
    langBtn.addEventListener('click', () => {
      currentLang = currentLang === 'th' ? 'en' : 'th';
      langBtn.textContent = currentLang === 'th' ? '🌐 TH' : '🌐 EN';
      if (currentDoc) {
        loadDocument(currentDoc);
      }
    });

    // File Upload
    fileInput.addEventListener('change', async (e) => {
      const files = Array.from(e.target.files);

      for (const file of files) {
        if (file.name.endsWith('.md')) {
          const text = await file.text();
          const fileName = file.name.replace('.md', '');

          // Store with language detection
          const lang = fileName.includes('.th') || fileName.includes('_th') ? 'th' : 'en';
          const baseName = fileName.replace(/[._](th|en)$/, '');

          if (!docs[baseName]) {
            docs[baseName] = {};
          }
          docs[baseName][lang] = text;
        }
      }

      renderFileTree();

      // Load first document
      const firstDoc = Object.keys(docs)[0];
      if (firstDoc) {
        loadDocument(firstDoc);
      }
    });

    // Render File Tree
    function renderFileTree() {
      const docNames = Object.keys(docs);

      if (docNames.length === 0) {
        fileTree.innerHTML = `
                    <div class="empty-state">
                        <div class="empty-state-icon">📁</div>
                        <p>ไม่พบไฟล์เอกสาร</p>
                    </div>
                `;
        return;
      }

      fileTree.innerHTML = docNames.map(name => `
                <div class="file-item" onclick="loadDocument('${name}')">
                    <span class="file-icon">📄</span>
                    ${name}
                </div>
            `).join('');
    }

    // Load Document
    function loadDocument(docName) {
      currentDoc = docName;
      const docContent = docs[docName][currentLang] || docs[docName]['en'] || docs[docName]['th'];

      if (!docContent) {
        content.innerHTML = `
                    <div class="empty-state">
                        <div class="empty-state-icon">❌</div>
                        <h2>ไม่พบเอกสาร</h2>
                        <p>ไม่มีเอกสารภาษา ${currentLang} สำหรับ ${docName}</p>
                    </div>
                `;
        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);
      });

      // Update active state
      document.querySelectorAll('.file-item').forEach(item => {
        item.classList.remove('active');
        if (item.textContent.trim() === docName) {
          item.classList.add('active');
        }
      });
    }

    // Load documentation from docs folder
    async function loadDocsFromFolder() {
      try {
        // Load Thai documentation
        const thFiles = await loadMarkdownFiles('docs/th/');
        // Load English documentation
        const enFiles = await loadMarkdownFiles('docs/en/');

        // Merge documentation
        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();

        // Load first available document
        const firstDoc = Object.keys(docs)[0];
        if (firstDoc) {
          loadDocument(firstDoc);
        } else {
          // No documents found
          showNoDocsError();
        }
      } catch (error) {
        console.error('Error loading documentation:', error);
        // Show error message
        showNoDocsError();
      }
    }

    // Load markdown files from a directory
    async function loadMarkdownFiles(directory) {
      const files = {};

      try {
        // Try to load common documentation files
        const commonFiles = ['index', 'installation', 'getting-started', 'api-reference', 'usage-guide', 'developer-guide'];

        for (const fileName of commonFiles) {
          try {
            const response = await fetch(`${directory}${fileName}.md`);
            if (response.ok) {
              const content = await response.text();
              files[fileName] = content;
            }
          } catch (error) {
            console.warn(`Could not load ${directory}${fileName}.md:`, error);
          }
        }
      } catch (error) {
        console.warn(`Could not load files from ${directory}:`, error);
      }

      return files;
    }

    // Show error message when no documentation is found
    function showNoDocsError() {
      content.innerHTML = `
        <div class="empty-state">
          <div class="empty-state-icon">❌</div>
          <h2>ไม่พบเอกสาร</h2>
          <p>ไม่พบไฟล์เอกสารในโฟลเดอร์ docs/</p>
          <p>กรุณาตรวจสอบว่า:</p>
          <ul style="text-align: left; max-width: 400px; margin: 1rem auto;">
            <li>มีไฟล์ .md ในโฟลเดอร์ docs/th/ และ docs/en/</li>
            <li>ชื่อไฟล์ถูกต้อง (ใช้ภาษาอังกฤษ, เครื่องหมาย - แทนช่องว่าง)</li>
            <li>ไฟล์มีสิทธิ์การอ่าน</li>
          </ul>
        </div>
      `;

      fileTree.innerHTML = `
        <div class="empty-state">
          <div class="empty-state-icon">📁</div>
          <p>ไม่พบไฟล์เอกสาร</p>
        </div>
      `;
    }

    // Initialize documentation
    loadDocsFromFolder();
  </script>
</body>

</html>