summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHiDeoo2024-12-14 13:28:18 +0100
committerGitHub2024-12-14 13:28:18 +0100
commit5c6996cd248e9da735a14e7fcaf638b51f2796bc (patch)
tree8bb662e6fc8cfcf57dd21033a1b5d2a5ac780a41
parentd5719f8862fc6fbb7b98128cc4fde653fcbd836e (diff)
downloadIT.starlight-5c6996cd248e9da735a14e7fcaf638b51f2796bc.tar.gz
IT.starlight-5c6996cd248e9da735a14e7fcaf638b51f2796bc.tar.bz2
IT.starlight-5c6996cd248e9da735a14e7fcaf638b51f2796bc.zip
Fix autogenerated sidebar issue (#2688)
Co-authored-by: delucis <357379+delucis@users.noreply.github.com>
-rw-r--r--.changeset/wild-laws-play.md5
-rw-r--r--packages/starlight/__tests__/basics/navigation.test.ts29
-rw-r--r--packages/starlight/__tests__/test-utils.ts6
-rw-r--r--packages/starlight/utils/navigation.ts32
-rw-r--r--packages/starlight/utils/slugs.ts3
5 files changed, 62 insertions, 13 deletions
diff --git a/.changeset/wild-laws-play.md b/.changeset/wild-laws-play.md
new file mode 100644
index 00000000..d1d1ace2
--- /dev/null
+++ b/.changeset/wild-laws-play.md
@@ -0,0 +1,5 @@
+---
+'@astrojs/starlight': patch
+---
+
+Fixes an issue with autogenerated sidebars when using Starlight with Astro's new Content Layer API where group names would be sluggified.
diff --git a/packages/starlight/__tests__/basics/navigation.test.ts b/packages/starlight/__tests__/basics/navigation.test.ts
index 90676507..0b4e5bd7 100644
--- a/packages/starlight/__tests__/basics/navigation.test.ts
+++ b/packages/starlight/__tests__/basics/navigation.test.ts
@@ -9,6 +9,7 @@ vi.mock('astro:content', async () =>
['guides/authoring-content.mdx', { title: 'Authoring Markdown' }],
['reference/frontmatter.md', { title: 'Frontmatter Reference', sidebar: { hidden: true } }],
['guides/project-structure.mdx', { title: 'Project Structure' }],
+ ['Getting Started/intro.md', { title: 'Introduction' }],
],
})
);
@@ -40,6 +41,22 @@ describe('getSidebar', () => {
{
"attrs": {},
"badge": undefined,
+ "href": "/getting-started/intro/",
+ "isCurrent": false,
+ "label": "Introduction",
+ "type": "link",
+ },
+ ],
+ "label": "Getting Started",
+ "type": "group",
+ },
+ {
+ "badge": undefined,
+ "collapsed": false,
+ "entries": [
+ {
+ "attrs": {},
+ "badge": undefined,
"href": "/guides/authoring-content/",
"isCurrent": false,
"label": "Authoring Markdown",
@@ -155,6 +172,14 @@ describe('flattenSidebar', () => {
{
"attrs": {},
"badge": undefined,
+ "href": "/getting-started/intro/",
+ "isCurrent": false,
+ "label": "Introduction",
+ "type": "link",
+ },
+ {
+ "attrs": {},
+ "badge": undefined,
"href": "/guides/authoring-content/",
"isCurrent": false,
"label": "Authoring Markdown",
@@ -182,9 +207,9 @@ describe('getPrevNextLinks', () => {
"next": {
"attrs": {},
"badge": undefined,
- "href": "/guides/authoring-content/",
+ "href": "/getting-started/intro/",
"isCurrent": false,
- "label": "Authoring Markdown",
+ "label": "Introduction",
"type": "link",
},
"prev": {
diff --git a/packages/starlight/__tests__/test-utils.ts b/packages/starlight/__tests__/test-utils.ts
index 45dbde66..d6e3a711 100644
--- a/packages/starlight/__tests__/test-utils.ts
+++ b/packages/starlight/__tests__/test-utils.ts
@@ -28,7 +28,11 @@ function mockDoc(
data: z.input<typeof frontmatterSchema>,
body = ''
): StarlightDocsCollectionEntry {
- const slug = docsFilePath.replace(/\.[^\.]+$/, '').replace(/\/index$/, '');
+ const slug = docsFilePath
+ .replace(/\.[^\.]+$/, '')
+ .replace(/\s/, '-')
+ .replace(/\/index$/, '')
+ .toLowerCase();
const doc: StarlightDocsCollectionEntry = {
id: project.legacyCollections ? docsFilePath : slug,
diff --git a/packages/starlight/utils/navigation.ts b/packages/starlight/utils/navigation.ts
index 76608601..921dc2fe 100644
--- a/packages/starlight/utils/navigation.ts
+++ b/packages/starlight/utils/navigation.ts
@@ -1,5 +1,6 @@
import { AstroError } from 'astro/errors';
import config from 'virtual:starlight/user-config';
+import project from 'virtual:starlight/project-context';
import type { Badge, I18nBadge, I18nBadgeConfig } from '../schemas/badge';
import type { PrevNextLinkConfig } from '../schemas/prevNextLink';
import type {
@@ -14,8 +15,9 @@ import { formatPath } from './format-path';
import { BuiltInDefaultLocale, pickLang } from './i18n';
import { ensureLeadingSlash, ensureTrailingSlash, stripLeadingAndTrailingSlashes } from './path';
import { getLocaleRoutes, routes, type Route } from './routing';
-import { localeToLang, slugToPathname } from './slugs';
+import { localeToLang, localizedId, slugToPathname } from './slugs';
import type { StarlightConfig } from './user-config';
+import { getCollectionPathFromRoot } from './collection';
const DirKey = Symbol('DirKey');
const SlugKey = Symbol('SlugKey');
@@ -108,7 +110,7 @@ function groupFromAutogenerateConfig(
// Match against `foo/anything/else.md`.
doc.id.startsWith(localeDir + '/')
);
- const tree = treeify(dirDocs, localeDir);
+ const tree = treeify(dirDocs, locale, localeDir);
const label = pickLang(item.translations, localeToLang(locale)) || item.label;
return {
type: 'group',
@@ -205,8 +207,8 @@ function pathsMatch(pathA: string, pathB: string) {
function getBreadcrumbs(path: string, baseDir: string): string[] {
// Strip extension from path.
const pathWithoutExt = stripExtension(path);
- // Index paths will match `baseDir` but we still need to consider them as a single segment.
- if (pathWithoutExt === baseDir) return [path];
+ // Index paths will match `baseDir` and don’t include breadcrumbs.
+ if (pathWithoutExt === baseDir) return [];
// Ensure base directory ends in a trailing slash.
baseDir = ensureTrailingSlash(baseDir);
// Strip base directory from path if present.
@@ -218,16 +220,28 @@ function getBreadcrumbs(path: string, baseDir: string): string[] {
}
/** Turn a flat array of routes into a tree structure. */
-function treeify(routes: Route[], baseDir: string): Dir {
+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
+ )
// Sort by depth, to build the tree depth first.
- .sort((a, b) => b.id.split('/').length - a.id.split('/').length)
+ .sort(([a], [b]) => b.split('/').length - a.split('/').length)
// Build the tree
- .forEach((doc) => {
- const parts = getBreadcrumbs(doc.id, baseDir);
+ .forEach(([filePathFromContentDir, doc]) => {
+ const parts = getBreadcrumbs(filePathFromContentDir, baseDir);
let currentNode = treeRoot;
parts.forEach((part, index) => {
@@ -374,7 +388,7 @@ function getIntermediateSidebarFromConfig(
if (sidebarConfig) {
return sidebarConfig.map((group) => configItemToEntry(group, pathname, locale, routes));
} else {
- const tree = treeify(routes, locale || '');
+ const tree = treeify(routes, locale, locale || '');
return sidebarFromDir(tree, pathname, locale, false);
}
}
diff --git a/packages/starlight/utils/slugs.ts b/packages/starlight/utils/slugs.ts
index c811c550..c6b0b739 100644
--- a/packages/starlight/utils/slugs.ts
+++ b/packages/starlight/utils/slugs.ts
@@ -82,7 +82,8 @@ export function localizedSlug(slug: string, locale: string | undefined): string
}
/**
- * Convert a legacy collection entry ID to a different locale.
+ * Convert a legacy collection entry ID or filePath relative to the collection root to a different
+ * locale.
* For example, passing an ID of `en/home.md` and a locale of `fr` results in `fr/home.md`.
* An undefined locale is treated as the root locale, resulting in `home.md`.
* @param id A collection entry ID