Skip to content

Commit

Permalink
Fix issue with user-defined autogenerated sidebar groups (#2702)
Browse files Browse the repository at this point in the history
  • Loading branch information
HiDeoo authored Dec 16, 2024
1 parent 2c3a4ad commit 02d16f3
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 18 deletions.
5 changes: 5 additions & 0 deletions .changeset/shaggy-toes-smile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/starlight': patch
---

Fixes an issue with autogenerated sidebars when using Starlight with Astro's new Content Layer API with directories containing spaces or special characters.
17 changes: 17 additions & 0 deletions packages/starlight/__tests__/sidebar/navigation-attributes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ vi.mock('astro:content', async () =>
},
],
['api/v1/users.md', { title: 'Users API' }],
['Deprecated API/users.md', { title: 'Deprecated Users API' }],
],
})
);
Expand Down Expand Up @@ -109,6 +110,22 @@ describe('getSidebar', () => {
"label": "API v1",
"type": "group",
},
{
"badge": undefined,
"collapsed": false,
"entries": [
{
"attrs": {},
"badge": undefined,
"href": "/deprecated-api/users/",
"isCurrent": false,
"label": "Deprecated Users API",
"type": "link",
},
],
"label": "API (deprecated)",
"type": "group",
},
]
`);
});
Expand Down
17 changes: 17 additions & 0 deletions packages/starlight/__tests__/sidebar/navigation-badges.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ vi.mock('astro:content', async () =>
['reference/frontmatter.md', { title: 'Frontmatter Reference', sidebar: { badge: 'New' } }],
['api/v1/users.md', { title: 'Users API' }],
['guides/project-structure.mdx', { title: 'Project Structure' }],
['Deprecated API/users.md', { title: 'Deprecated Users API' }],
],
})
);
Expand Down Expand Up @@ -127,6 +128,22 @@ describe('getSidebar', () => {
"label": "API v1",
"type": "group",
},
{
"badge": undefined,
"collapsed": false,
"entries": [
{
"attrs": {},
"badge": undefined,
"href": "/deprecated-api/users/",
"isCurrent": false,
"label": "Deprecated Users API",
"type": "link",
},
],
"label": "API (deprecated)",
"type": "group",
},
]
`);
});
Expand Down
17 changes: 17 additions & 0 deletions packages/starlight/__tests__/sidebar/navigation-hidden.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ vi.mock('astro:content', async () =>
['reference/frontmatter.md', { title: 'Frontmatter Reference', sidebar: { hidden: true } }],
['api/v1/users.md', { title: 'Users API' }],
['guides/project-structure.mdx', { title: 'Project Structure' }],
['Deprecated API/users.md', { title: 'Deprecated Users API' }],
],
})
);
Expand Down Expand Up @@ -102,6 +103,22 @@ describe('getSidebar', () => {
"label": "API v1",
"type": "group",
},
{
"badge": undefined,
"collapsed": false,
"entries": [
{
"attrs": {},
"badge": undefined,
"href": "/deprecated-api/users/",
"isCurrent": false,
"label": "Deprecated Users API",
"type": "link",
},
],
"label": "API (deprecated)",
"type": "group",
},
]
`);
});
Expand Down
17 changes: 17 additions & 0 deletions packages/starlight/__tests__/sidebar/navigation-order.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ vi.mock('astro:content', async () =>
['reference/frontmatter.md', { title: 'Frontmatter Reference', sidebar: { order: 1 } }],
['api/v1/users.md', { title: 'Users API' }],
['guides/project-structure.mdx', { title: 'Project Structure' }],
['Deprecated API/users.md', { title: 'Deprecated Users API' }],
],
})
);
Expand Down Expand Up @@ -110,6 +111,22 @@ describe('getSidebar', () => {
"label": "API v1",
"type": "group",
},
{
"badge": undefined,
"collapsed": false,
"entries": [
{
"attrs": {},
"badge": undefined,
"href": "/deprecated-api/users/",
"isCurrent": false,
"label": "Deprecated Users API",
"type": "link",
},
],
"label": "API (deprecated)",
"type": "group",
},
]
`);
});
Expand Down
17 changes: 17 additions & 0 deletions packages/starlight/__tests__/sidebar/navigation-unicode.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ vi.mock('astro:content', async () =>
['reference/frontmatter.md', { title: 'Frontmatter Reference' }],
['api/v1/用户.md', { title: 'Path with non-ASCII characters' }],
['guides/project-structure.mdx', { title: 'Project Structure' }],
['Deprecated API/用户.md', { title: 'Another path with non-ASCII characters' }],
],
})
);
Expand Down Expand Up @@ -110,6 +111,22 @@ describe('getSidebar', () => {
"label": "API v1",
"type": "group",
},
{
"badge": undefined,
"collapsed": false,
"entries": [
{
"attrs": {},
"badge": undefined,
"href": "/deprecated-api/用户/",
"isCurrent": false,
"label": "Another path with non-ASCII characters",
"type": "link",
},
],
"label": "API (deprecated)",
"type": "group",
},
]
`);
});
Expand Down
17 changes: 17 additions & 0 deletions packages/starlight/__tests__/sidebar/navigation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ vi.mock('astro:content', async () =>
['reference/frontmatter/foo.mdx', { title: 'Foo' }],
['api/v1/users.md', { title: 'Users API' }],
['guides/project-structure.mdx', { title: 'Project Structure' }],
['Deprecated API/users.md', { title: 'Deprecated Users API' }],
],
})
);
Expand Down Expand Up @@ -127,6 +128,22 @@ describe('getSidebar', () => {
"label": "API v1",
"type": "group",
},
{
"badge": undefined,
"collapsed": false,
"entries": [
{
"attrs": {},
"badge": undefined,
"href": "/deprecated-api/users/",
"isCurrent": false,
"label": "Deprecated Users API",
"type": "link",
},
],
"label": "API (deprecated)",
"type": "group",
},
]
`);
});
Expand Down
9 changes: 7 additions & 2 deletions packages/starlight/__tests__/sidebar/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,21 @@ export default defineVitestConfig({
},
],
},
// A group linking to all pages in the reference directory.
// A group linking to all pages in the `reference` directory.
{
label: 'Reference',
badge: 'Experimental',
autogenerate: { directory: 'reference' },
},
// A group linking to all pages in the api/v1 directory.
// A group linking to all pages in the `api/v1` directory.
{
label: 'API v1',
autogenerate: { directory: '/api/v1/' },
},
// A group linking to all pages in the `Deprecated API/` directory.
{
label: 'API (deprecated)',
autogenerate: { directory: '/Deprecated API/' },
},
],
});
34 changes: 18 additions & 16 deletions packages/starlight/utils/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const SlugKey = Symbol('SlugKey');

const neverPathFormatter = createPathFormatter({ trailingSlash: 'never' });

const docsCollectionPathFromRoot = getCollectionPathFromRoot('docs', project);

export interface Link {
type: 'link';
label: string;
Expand Down Expand Up @@ -103,13 +105,15 @@ function groupFromAutogenerateConfig(
): Group {
const { collapsed: subgroupCollapsed, directory } = item.autogenerate;
const localeDir = locale ? locale + '/' + directory : directory;
const dirDocs = routes.filter(
(doc) =>
const dirDocs = routes.filter((doc) => {
const filePathFromContentDir = getRoutePathRelativeToCollectionRoot(doc, locale);
return (
// Match against `foo.md` or `foo/index.md`.
stripExtension(doc.id) === localeDir ||
stripExtension(filePathFromContentDir) === localeDir ||
// Match against `foo/anything/else.md`.
doc.id.startsWith(localeDir + '/')
);
filePathFromContentDir.startsWith(localeDir + '/')
);
});
const tree = treeify(dirDocs, locale, localeDir);
const label = pickLang(item.translations, localeToLang(locale)) || item.label;
return {
Expand Down Expand Up @@ -219,24 +223,22 @@ function getBreadcrumbs(path: string, baseDir: string): string[] {
return relativePath.split('/');
}

/** Return the path of a route relative to the root of the collection, which is equivalent to legacy IDs. */
function getRoutePathRelativeToCollectionRoot(route: Route, locale: string | undefined) {
return project.legacyCollections
? route.id
: // For collections with a loader, use a localized filePath relative to the collection
localizedId(route.entry.filePath.replace(`${docsCollectionPathFromRoot}/`, ''), locale);
}

/** Turn a flat array of routes into a tree structure. */
function treeify(routes: Route[], locale: string | undefined, baseDir: string): Dir {
const treeRoot: Dir = makeDir(baseDir);
const collectionPathFromRoot = getCollectionPathFromRoot('docs', project);
routes
// Remove any entries that should be hidden
.filter((doc) => !doc.entry.data.sidebar.hidden)
// Compute the path of each entry from the root of the collection ahead of time.
.map(
(doc) =>
[
project.legacyCollections
? doc.id
: // For collections with a loader, use a localized filePath relative to the collection
localizedId(doc.entry.filePath.replace(`${collectionPathFromRoot}/`, ''), locale),
doc,
] as const
)
.map((doc) => [getRoutePathRelativeToCollectionRoot(doc, locale), doc] as const)
// Sort by depth, to build the tree depth first.
.sort(([a], [b]) => b.split('/').length - a.split('/').length)
// Build the tree
Expand Down

0 comments on commit 02d16f3

Please sign in to comment.