summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHiDeoo2024-12-16 12:23:04 +0100
committerGitHub2024-12-16 12:23:04 +0100
commit02d16f3638db609501897c5e3647cc20eb5ec142 (patch)
tree3ac42896d9e488caf7ae8d4de765198632c74e39
parent2c3a4ad9c71f4f0bfb8c6c6d4512d173f31ac615 (diff)
downloadIT.starlight-02d16f3638db609501897c5e3647cc20eb5ec142.tar.gz
IT.starlight-02d16f3638db609501897c5e3647cc20eb5ec142.tar.bz2
IT.starlight-02d16f3638db609501897c5e3647cc20eb5ec142.zip
Fix issue with user-defined autogenerated sidebar groups (#2702)
-rw-r--r--.changeset/shaggy-toes-smile.md5
-rw-r--r--packages/starlight/__tests__/sidebar/navigation-attributes.test.ts17
-rw-r--r--packages/starlight/__tests__/sidebar/navigation-badges.test.ts17
-rw-r--r--packages/starlight/__tests__/sidebar/navigation-hidden.test.ts17
-rw-r--r--packages/starlight/__tests__/sidebar/navigation-order.test.ts17
-rw-r--r--packages/starlight/__tests__/sidebar/navigation-unicode.test.ts17
-rw-r--r--packages/starlight/__tests__/sidebar/navigation.test.ts17
-rw-r--r--packages/starlight/__tests__/sidebar/vitest.config.ts9
-rw-r--r--packages/starlight/utils/navigation.ts34
9 files changed, 132 insertions, 18 deletions
diff --git a/.changeset/shaggy-toes-smile.md b/.changeset/shaggy-toes-smile.md
new file mode 100644
index 00000000..9ffdd68d
--- /dev/null
+++ b/.changeset/shaggy-toes-smile.md
@@ -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.
diff --git a/packages/starlight/__tests__/sidebar/navigation-attributes.test.ts b/packages/starlight/__tests__/sidebar/navigation-attributes.test.ts
index 3ce50a76..2dda3324 100644
--- a/packages/starlight/__tests__/sidebar/navigation-attributes.test.ts
+++ b/packages/starlight/__tests__/sidebar/navigation-attributes.test.ts
@@ -14,6 +14,7 @@ vi.mock('astro:content', async () =>
},
],
['api/v1/users.md', { title: 'Users API' }],
+ ['Deprecated API/users.md', { title: 'Deprecated Users API' }],
],
})
);
@@ -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",
+ },
]
`);
});
diff --git a/packages/starlight/__tests__/sidebar/navigation-badges.test.ts b/packages/starlight/__tests__/sidebar/navigation-badges.test.ts
index 2f48330d..d0963c2c 100644
--- a/packages/starlight/__tests__/sidebar/navigation-badges.test.ts
+++ b/packages/starlight/__tests__/sidebar/navigation-badges.test.ts
@@ -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' }],
],
})
);
@@ -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",
+ },
]
`);
});
diff --git a/packages/starlight/__tests__/sidebar/navigation-hidden.test.ts b/packages/starlight/__tests__/sidebar/navigation-hidden.test.ts
index dc46686c..ee5cc0c5 100644
--- a/packages/starlight/__tests__/sidebar/navigation-hidden.test.ts
+++ b/packages/starlight/__tests__/sidebar/navigation-hidden.test.ts
@@ -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' }],
],
})
);
@@ -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",
+ },
]
`);
});
diff --git a/packages/starlight/__tests__/sidebar/navigation-order.test.ts b/packages/starlight/__tests__/sidebar/navigation-order.test.ts
index aa1396c5..cce9a694 100644
--- a/packages/starlight/__tests__/sidebar/navigation-order.test.ts
+++ b/packages/starlight/__tests__/sidebar/navigation-order.test.ts
@@ -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' }],
],
})
);
@@ -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",
+ },
]
`);
});
diff --git a/packages/starlight/__tests__/sidebar/navigation-unicode.test.ts b/packages/starlight/__tests__/sidebar/navigation-unicode.test.ts
index e74f7f6c..02c16bb4 100644
--- a/packages/starlight/__tests__/sidebar/navigation-unicode.test.ts
+++ b/packages/starlight/__tests__/sidebar/navigation-unicode.test.ts
@@ -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' }],
],
})
);
@@ -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",
+ },
]
`);
});
diff --git a/packages/starlight/__tests__/sidebar/navigation.test.ts b/packages/starlight/__tests__/sidebar/navigation.test.ts
index bda1c680..f113d431 100644
--- a/packages/starlight/__tests__/sidebar/navigation.test.ts
+++ b/packages/starlight/__tests__/sidebar/navigation.test.ts
@@ -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' }],
],
})
);
@@ -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",
+ },
]
`);
});
diff --git a/packages/starlight/__tests__/sidebar/vitest.config.ts b/packages/starlight/__tests__/sidebar/vitest.config.ts
index a33f9541..8eceebbc 100644
--- a/packages/starlight/__tests__/sidebar/vitest.config.ts
+++ b/packages/starlight/__tests__/sidebar/vitest.config.ts
@@ -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/' },
+ },
],
});
diff --git a/packages/starlight/utils/navigation.ts b/packages/starlight/utils/navigation.ts
index 921dc2fe..0944eb5d 100644
--- a/packages/starlight/utils/navigation.ts
+++ b/packages/starlight/utils/navigation.ts
@@ -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;
@@ -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 {
@@ -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