diff options
author | HiDeoo | 2024-12-14 13:28:18 +0100 |
---|---|---|
committer | GitHub | 2024-12-14 13:28:18 +0100 |
commit | 5c6996cd248e9da735a14e7fcaf638b51f2796bc (patch) | |
tree | 8bb662e6fc8cfcf57dd21033a1b5d2a5ac780a41 | |
parent | d5719f8862fc6fbb7b98128cc4fde653fcbd836e (diff) | |
download | IT.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.md | 5 | ||||
-rw-r--r-- | packages/starlight/__tests__/basics/navigation.test.ts | 29 | ||||
-rw-r--r-- | packages/starlight/__tests__/test-utils.ts | 6 | ||||
-rw-r--r-- | packages/starlight/utils/navigation.ts | 32 | ||||
-rw-r--r-- | packages/starlight/utils/slugs.ts | 3 |
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 |