diff --git a/apps/web-docs/SIDEBAR_ORDERING.md b/apps/web-docs/SIDEBAR_ORDERING.md new file mode 100644 index 00000000..1347e86e --- /dev/null +++ b/apps/web-docs/SIDEBAR_ORDERING.md @@ -0,0 +1,178 @@ +# Hướng dẫn sắp xếp Documentation Sidebar + +## 📋 Tổng quan + +Sidebar navigation có 2 cấp độ sắp xếp: +1. **Categories** (Guides, Architecture, Skills, v.v.) +2. **Items** trong mỗi category (các file docs) + +## 🎯 Cách sắp xếp + +### 1. Sắp xếp Categories + +Chỉnh sửa trong file: `apps/web-docs/src/lib/docs-generator.ts` + +```typescript +const CATEGORY_CONFIG = { + 'guides': { order: 1, label: { en: 'Guides', vi: 'Hướng dẫn' } }, + 'architecture': { order: 2, label: { en: 'Architecture', vi: 'Kiến trúc' } }, + 'skills': { order: 3, label: { en: 'Skills', vi: 'Kỹ năng' } }, + // ... +}; +``` + +**Cách thay đổi:** +- Thay đổi `order` để điều chỉnh vị trí (số nhỏ hơn = cao hơn) +- Thêm category mới với order tương ứng +- Categories không có trong config sẽ có `order: 999` (xuất hiện cuối) + +### 2. Sắp xếp Items trong Category + +Có 2 loại sắp xếp: + +#### A. Custom Order (Ưu tiên) + +Định nghĩa thứ tự cố định cho items quan trọng: + +```typescript +const ITEM_ORDER = { + 'guides': [ + 'getting-started', // Xuất hiện đầu tiên + 'local-development', // Thứ hai + 'deployment', // Thứ ba + // Các file khác sẽ được sắp xếp alphabetically + ], + 'architecture': [ + 'system-design', + 'service-communication', + ], + 'skills': [ + 'project-rules', + 'comment-code', + 'api-design', + ], +}; +``` + +**Lưu ý:** +- Dùng **filename** (không có extension `.md`) +- Chỉ liệt kê các file quan trọng cần ưu tiên +- Các file không có trong danh sách sẽ tự động sắp xếp alphabetically ở cuối + +#### B. Alphabetical (Mặc định) + +Items không được liệt kê trong `ITEM_ORDER` sẽ tự động sắp xếp theo alphabet (A-Z). + +## 📝 Ví dụ thực tế + +### Ví dụ 1: Thêm doc mới "Quick Start" + +1. Tạo file: `docs/en/guides/quick-start.md` +2. Muốn nó xuất hiện đầu tiên? Thêm vào `ITEM_ORDER`: + +```typescript +const ITEM_ORDER = { + 'guides': [ + 'quick-start', // ← Thêm dòng này + 'getting-started', + 'local-development', + 'deployment', + ], +}; +``` + +### Ví dụ 2: Thay đổi thứ tự categories + +Muốn Skills xuất hiện trước Architecture: + +```typescript +const CATEGORY_CONFIG = { + 'guides': { order: 1, ... }, + 'skills': { order: 2, ... }, // ← Từ 3 → 2 + 'architecture': { order: 3, ... }, // ← Từ 2 → 3 +}; +``` + +### Ví dụ 3: Category mới "Tutorials" + +```typescript +const CATEGORY_CONFIG = { + // ... existing categories + 'tutorials': { + order: 8, + label: { en: 'Tutorials', vi: 'Hướng dẫn chi tiết' } + }, +}; + +const ITEM_ORDER = { + // ... existing orders + 'tutorials': [ + 'beginner-tutorial', + 'intermediate-tutorial', + 'advanced-tutorial', + ], +}; +``` + +## 🔄 Kết quả + +``` +Sidebar sẽ hiển thị: + +📁 Guides (order: 1) + └─ Getting Started (custom order 0) + └─ Local Development (custom order 1) + └─ Deployment (custom order 2) + └─ Advanced Features (alphabetical) + └─ Best Practices (alphabetical) + +📁 Architecture (order: 2) + └─ System Design (custom order 0) + └─ Service Communication (custom order 1) + └─ Database Design (alphabetical) + +📁 Skills (order: 3) + └─ Project Rules (custom order 0) + └─ Comment Code (custom order 1) + └─ API Design (custom order 2) + └─ Testing Patterns (alphabetical) +``` + +## ⚡ Reload để xem thay đổi + +Sau khi chỉnh sửa `docs-generator.ts`: +1. Lưu file +2. Refresh trang web (Ctrl/Cmd + R) +3. Navigation cache sẽ tự động rebuild + +## 🎨 Tips + +1. **Giữ custom order ngắn gọn**: Chỉ liệt kê 3-5 items quan trọng nhất +2. **Đặt tên file có ý nghĩa**: Alphabetical sorting sẽ hợp lý hơn +3. **Consistency**: Dùng cùng naming convention cho tất cả files +4. **Documentation**: Thêm comment giải thích tại sao sắp xếp như vậy + +## 📌 Checklist + +Khi thêm doc mới: +- [ ] Tạo file `.md` trong thư mục category phù hợp +- [ ] Kiểm tra xem có cần custom order không +- [ ] Nếu cần, thêm vào `ITEM_ORDER` +- [ ] Test bằng cách refresh trang +- [ ] Kiểm tra cả EN và VI locale + +## ❓ Troubleshooting + +### Doc không xuất hiện trong sidebar +- Kiểm tra file có extension `.md` không +- File không được đặt tên là `README.md` (bị exclude) +- Thư mục category có trong `CATEGORY_CONFIG` không + +### Thứ tự không đúng +- Kiểm tra typo trong filename ở `ITEM_ORDER` +- Đảm bảo dùng filename (không có `.md`) +- Clear browser cache và hard refresh + +### Category mới không xuất hiện +- Thêm vào `CATEGORY_CONFIG` với order phù hợp +- Đảm bảo có ít nhất 1 file `.md` trong thư mục diff --git a/apps/web-docs/src/lib/docs-generator.ts b/apps/web-docs/src/lib/docs-generator.ts index a1e626d4..aba6633f 100644 --- a/apps/web-docs/src/lib/docs-generator.ts +++ b/apps/web-docs/src/lib/docs-generator.ts @@ -29,6 +29,28 @@ const CATEGORY_CONFIG: Record = { + 'guides': [ + 'getting-started', // EN: Always show getting started first / VI: Luôn hiển thị getting started đầu tiên + 'local-development', // EN: Then local setup / VI: Sau đó là local setup + 'deployment', // EN: Then deployment / VI: Sau đó là deployment + // EN: Other items will be alphabetically sorted / VI: Các items khác sẽ được sắp xếp theo alphabet + ], + 'architecture': [ + 'system-design', // EN: Overview first / VI: Overview trước + 'service-communication', // EN: Then communication / VI: Sau đó là communication + ], + 'skills': [ + 'project-rules', // EN: Project rules first / VI: Project rules trước + 'comment-code', // EN: Then coding standards / VI: Sau đó là coding standards + 'api-design', // EN: Then API design / VI: Sau đó là API design + ], +}; + + /** * EN: Extract title from markdown file * VI: Trích xuất tiêu đề từ file markdown @@ -170,9 +192,30 @@ export function generateDocsNavigation(): NavGroup[] { label: { en: category.charAt(0).toUpperCase() + category.slice(1), vi: category.charAt(0).toUpperCase() + category.slice(1) } }; - // EN: Sort items alphabetically - // VI: Sắp xếp items theo thứ tự bảng chữ cái - items.sort((a, b) => a.label.en.localeCompare(b.label.en)); + // EN: Sort items by custom order first, then alphabetically + // VI: Sắp xếp items theo thứ tự tùy chỉnh trước, sau đó theo alphabet + const customOrder = ITEM_ORDER[category] || []; + + items.sort((a, b) => { + const aSlugName = a.slug.split('/')[1]; // EN: Get filename from slug / VI: Lấy filename từ slug + const bSlugName = b.slug.split('/')[1]; + + const aIndex = customOrder.indexOf(aSlugName); + const bIndex = customOrder.indexOf(bSlugName); + + // EN: If both have custom order, use that / VI: Nếu cả hai có thứ tự tùy chỉnh, dùng nó + if (aIndex !== -1 && bIndex !== -1) { + return aIndex - bIndex; + } + + // EN: Items with custom order come first / VI: Items có thứ tự tùy chỉnh xuất hiện trước + if (aIndex !== -1) return -1; + if (bIndex !== -1) return 1; + + // EN: Otherwise sort alphabetically / VI: Ngược lại sắp xếp theo alphabet + return a.label.en.localeCompare(b.label.en); + }); + navGroups.push({ id: category,