Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 45 additions & 20 deletions docs/.vitepress/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import path from 'path';
import matter from 'gray-matter';

export function generateDocumentationSidebar(): any {
const sidebar = generateSidebar({
const sidebar = generateSidebar([{
documentRootPath: 'docs',
scanStartPath: '',
resolvePath: '/',
Expand All @@ -17,26 +17,49 @@ export function generateDocumentationSidebar(): any {
sortMenusByFrontmatterOrder: true,
frontmatterOrderDefaultValue: 999,
prefixSeparator: '/',
});
}]);

// Post-process sidebar to fix folder titles and extract descriptions from frontmatter
const fixFolderTitles = (items: any[]): any[] => {
return items.map(item => {
let frontmatter: Record<string, any> | undefined;

if (item.link && item.link.endsWith('/')) {
// This is a folder link - read frontmatter from its index.md
const indexPath = path.join('docs', item.link, 'index.md');
if (fs.existsSync(indexPath)) {
try {
const content = fs.readFileSync(indexPath, 'utf-8');
frontmatter = matter(content).data;
if (frontmatter?.title) {
item.text = frontmatter.title;
}
} catch (err) {
// Ignore errors, keep the original text
// Fix folder links for proper active state detection
// VitePress normalizes "/tutorials/index.md" to "/tutorials/" (WITH trailing slash)
// The regex /(?:(^|\/)index)?\.(?:md|html)$/ captures the "/" before "index"
// So we must ensure sidebar links for index pages also have trailing slashes

// IMPORTANT: Don't add leading slash - VitePress adds base path
// If we have "/tutorials/", VitePress makes it "//tutorials/" (external link!)

if (item.link && item.link.endsWith('/index.md')) {
// Convert "tutorials/index.md" to "tutorials/"
item.link = item.link.replace(/\/index\.md$/, '/');
} else if (item.link && item.link.startsWith('/')) {
// Remove leading slash that vitepress-sidebar added
item.link = item.link.substring(1);
}

// Now check if link needs trailing slash
if (item.link && !item.link.endsWith('/')) {
const possibleIndexPath = path.join('docs', item.link, 'index.md');
if (fs.existsSync(possibleIndexPath)) {
// Add trailing slash: "tutorials" to "tutorials/"
item.link = item.link + '/';
}
}

// Check if this is a folder with index.md to read its frontmatter
const possibleIndexPath = path.join('docs', item.link, 'index.md');
if (item.link && fs.existsSync(possibleIndexPath)) {
try {
const content = fs.readFileSync(possibleIndexPath, 'utf-8');
frontmatter = matter(content).data;
if (frontmatter?.title) {
item.text = frontmatter.title;
}
} catch (err) {
// Ignore errors, keep the original text
}
} else if (item.link && item.link.endsWith('.md')) {
// This is a file link - read frontmatter from the page
Expand Down Expand Up @@ -76,11 +99,13 @@ export function generateDocumentationSidebar(): any {
});
};

const fixedSidebar = fixFolderTitles(sidebar);
const fixedSidebar: Record<string, any> = {};
for (const [key, section] of Object.entries(sidebar)) {
fixedSidebar[key] = {
...section,
items: fixFolderTitles(section.items),
};
}

// vitepress-sidebar returns an array, but we need an object with path keys
// Wrap the array result in an object with the root path
return {
'/': fixedSidebar
};
return fixedSidebar;
}
38 changes: 30 additions & 8 deletions docs/.vitepress/theme/components/SectionIndex.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,17 @@ interface TreeNode {
const showDescriptions = computed(() => frontmatter.value.overviewDescriptions !== false);

// Get the current directory path from the current page
// e.g., 'how-to/' for how-to/index.md or 'how-to/platform-specific/' for how-to/platform-specific/index.md
// e.g., '/how-to/' for how-to/index.md or '/how-to/platform-specific/' for how-to/platform-specific/index.md
const currentDirectory = computed(() => {
const path = page.value.relativePath;
// Remove /index.md or .md and get directory path
const dirPath = path.replace(/\/index\.md$/, "").replace(/\.md$/, "");
// If it's a directory, add trailing slash
return dirPath ? dirPath + "/" : "";
// If it's a directory, add trailing slash and leading slash
if (dirPath) {
const normalized = dirPath.startsWith('/') ? dirPath : '/' + dirPath;
return normalized.endsWith('/') ? normalized : normalized + '/';
}
return "/";
});

// Find items in the current section/subsection from sidebar and build a tree structure
Expand All @@ -38,7 +42,9 @@ const sectionItems = computed(() => {
return [];
}

const sidebarGroups = sidebar["/"];
// Handle both array format and { base, items } format
const sidebarData = sidebar["/"];
const sidebarGroups = Array.isArray(sidebarData) ? sidebarData : (sidebarData.items || []);
const currentPagePath = page.value.relativePath.replace(/\.md$/, "");
const targetPath = currentDirectory.value;

Expand All @@ -50,8 +56,16 @@ const sectionItems = computed(() => {
for (const item of items) {
// Check if this item's link matches our target path
if (item.link) {
const itemPath =
item.link.replace(/\.md$/, "").replace(/\/index$/, "") + "/";
// Normalize the link - ensure it starts with / and ends with /
let itemPath = item.link;
if (!itemPath.startsWith('/')) {
itemPath = '/' + itemPath;
}
itemPath = itemPath.replace(/\.md$/, "").replace(/\/index$/, "");
if (!itemPath.endsWith('/')) {
itemPath = itemPath + '/';
}

if (itemPath === searchPath) {
return item;
}
Expand All @@ -72,8 +86,16 @@ const sectionItems = computed(() => {
for (const group of sidebarGroups) {
// Check if the group itself matches
if (group.link) {
const groupPath =
group.link.replace(/\.md$/, "").replace(/\/index$/, "") + "/";
// Normalize the link - ensure it starts with / and ends with /
let groupPath = group.link;
if (!groupPath.startsWith('/')) {
groupPath = '/' + groupPath;
}
groupPath = groupPath.replace(/\.md$/, "").replace(/\/index$/, "");
if (!groupPath.endsWith('/')) {
groupPath = groupPath + '/';
}

if (groupPath === targetPath) {
matchingNode = group;
break;
Expand Down
5 changes: 5 additions & 0 deletions docs/.vitepress/theme/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ img[src="/search.png"] {
color: var(--vp-c-text-1);
}

/* Allow active state to override the text color for sections */
#VPSidebarNav section.VPSidebarItem.is-active > .item .link > .text {
color: var(--vp-c-brand-1);
}

#VPSidebarNav div.VPSidebarItem > .item .text {
font-weight: 500;
}
Expand Down
8 changes: 4 additions & 4 deletions repos-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"docs_path": "docs",
"target_path": "projects/gardenlinux",
"ref": "docs-ng",
"commit": "7615fe00399f8bb8a6d5b7c36d6a8023747420fa",
"commit": "900bdf88b9e29d97e3a100338fe43be46d333610",
"root_files": [
"CONTRIBUTING.md",
"SECURITY.md",
Expand All @@ -33,7 +33,7 @@
"docs_path": "docs",
"target_path": "projects/builder",
"ref": "docs-ng",
"commit": "ff29b1c4a5abddf855e6b4b7e14bf985a790779e",
"commit": "7a7c3430ba21794d7f30876df8850e1424768149",
"media_directories": [
".media",
"assets",
Expand All @@ -46,7 +46,7 @@
"docs_path": "docs",
"target_path": "projects/python-gardenlinux-lib",
"ref": "docs-ng",
"commit": "be7fd063d1b440f490d9a1e3054179b35a7abc23",
"commit": "73a16adcc674e43ad9b811c399fa5af1b698d62f",
"structure": "sphinx",
"media_directories": [
".media",
Expand All @@ -73,7 +73,7 @@
"docs_path": "docs",
"target_path": "projects/glrd",
"ref": "docs-ng",
"commit": "b855783938aad5cf3238fef9b5dc12190e0b7207",
"commit": "b5262e0bf409065ee1b9d62f4d0270695d9081a2",
"media_directories": [
".media",
"assets",
Expand Down
Loading