diff --git a/.changeset/quiet-groups-link.md b/.changeset/quiet-groups-link.md new file mode 100644 index 000000000..4f1fb7398 --- /dev/null +++ b/.changeset/quiet-groups-link.md @@ -0,0 +1,5 @@ +--- +"gitbook": patch +--- + +Stop page group breadcrumbs from linking to a URL that redirects to the group's first page. diff --git a/packages/gitbook/src/components/PageBody/PageHeader.tsx b/packages/gitbook/src/components/PageBody/PageHeader.tsx index f406d619a..d63ff3535 100644 --- a/packages/gitbook/src/components/PageBody/PageHeader.tsx +++ b/packages/gitbook/src/components/PageBody/PageHeader.tsx @@ -222,9 +222,14 @@ export async function PageHeader(props: { ))} {ancestors.map((breadcrumb, index) => { const parentPages = ancestors[index - 1]?.pages ?? revision.pages; + // A group's own URL redirects to its first document, so link straight to it. + const target = + breadcrumb.type === 'group' + ? (resolveFirstDocument([breadcrumb], [])?.page ?? breadcrumb) + : breadcrumb; const href = linker.toPathForPage({ pages: revision.pages, - page: breadcrumb, + page: target, }); return (
  • @@ -483,15 +488,16 @@ function getPageSiblings( if (page.hidden && page.id !== activeId) { continue; } - // A group whose subtree has no document resolves to no page — the sidebar renders it as a - // non-clickable label, so don't offer it as a navigable sibling (its path would 404). - if (page.type === 'group' && page.id !== activeId && !resolveFirstDocument([page], [])) { + // A group's own URL redirects to its first document, so link straight to it. A group whose + // subtree has no document resolves to no page, so don't offer it (its path would 404). + const target = page.type === 'group' ? resolveFirstDocument([page], [])?.page : page; + if (!target) { continue; } result.push({ id: page.id, title: page.linkTitle || page.title, - href: context.linker.toPathForPage({ pages: context.revision.pages, page }), + href: context.linker.toPathForPage({ pages: context.revision.pages, page: target }), emoji: page.emoji, icon: page.icon, isActive: page.id === activeId, diff --git a/packages/gitbook/src/lib/references.test.ts b/packages/gitbook/src/lib/references.test.ts index db8c0e6d8..d8bce5bc4 100644 --- a/packages/gitbook/src/lib/references.test.ts +++ b/packages/gitbook/src/lib/references.test.ts @@ -627,12 +627,11 @@ describe('resolveContentRef for direct space links', () => { { label: 'API guides' }, { label: 'Authentification' }, { label: 'Référence', href: targetSiteSpace.urls.published }, - { label: 'Getting started', icon: null, href: expect.any(String) }, + { label: 'Getting started', icon: null, href: result?.href }, ]); expect(result?.ancestors?.[0]?.href).toBeUndefined(); expect(result?.ancestors?.[1]?.href).toBeUndefined(); expect(result?.ancestors?.[2]?.href).toBeUndefined(); - expect(result?.ancestors?.[4]?.href).toBeTruthy(); }); it('uses the first document as the target for a page-group reference', async () => { diff --git a/packages/gitbook/src/lib/references.tsx b/packages/gitbook/src/lib/references.tsx index e174a2bc3..7ee2db0a0 100644 --- a/packages/gitbook/src/lib/references.tsx +++ b/packages/gitbook/src/lib/references.tsx @@ -23,7 +23,7 @@ import { findGitPageURLTarget, findPageForGitPageURLTarget, } from './gitPageURL'; -import { resolvePageId } from './pages'; +import { resolveFirstDocument, resolvePageId } from './pages'; import { findSiteSpaceBy, getFallbackSiteSpacePath, @@ -276,7 +276,14 @@ export async function resolveContentRef( style={iconStyle} /> ) : null, - href: linker.toPathForPage({ page: ancestor, pages: revision.pages }), + // A group's own URL redirects to its first document, so link straight to it. + href: linker.toPathForPage({ + page: + ancestor.type === 'group' + ? (resolveFirstDocument([ancestor], [])?.page ?? ancestor) + : ancestor, + pages: revision.pages, + }), })) ?? []; if (!page) { return null;