feat(docs): Implement custom item ordering in documentation navigation

- Added ITEM_ORDER constant to define custom sorting for specific items within categories.
- Updated the sorting logic in generateDocsNavigation to prioritize custom order before alphabetical sorting.
- Enhanced comments for clarity in both English and Vietnamese regarding the sorting process.
This commit is contained in:
Ho Ngoc Hai
2026-01-08 15:10:55 +07:00
parent 11169246ac
commit 07e97449f2
2 changed files with 224 additions and 3 deletions

View File

@@ -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

View File

@@ -29,6 +29,28 @@ const CATEGORY_CONFIG: Record<string, { order: number; label: { en: string; vi:
'onboarding': { order: 7, label: { en: 'Onboarding', vi: 'Hướng dẫn mới' } },
};
// EN: Custom ordering for specific items within categories
// VI: Thứ tự tùy chỉnh cho các items cụ thể trong mỗi category
// Items not listed here will be sorted alphabetically after the ordered ones
const ITEM_ORDER: Record<string, string[]> = {
'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,