From 1be920ecbe81513a573a0db7da9f830d7973c406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samy=20Pess=C3=A9?= Date: Thu, 12 Jun 2025 08:51:22 +0200 Subject: [PATCH 1/3] Preserve current variant when navigating between sections --- .../src/components/Header/SpacesDropdown.tsx | 18 ++--------- .../SiteSections/encodeClientSiteSections.ts | 29 +++++++++++++++--- packages/gitbook/src/lib/sites.ts | 30 +++++++++++++++++++ 3 files changed, 57 insertions(+), 20 deletions(-) diff --git a/packages/gitbook/src/components/Header/SpacesDropdown.tsx b/packages/gitbook/src/components/Header/SpacesDropdown.tsx index 1523774493..f0a40bd23c 100644 --- a/packages/gitbook/src/components/Header/SpacesDropdown.tsx +++ b/packages/gitbook/src/components/Header/SpacesDropdown.tsx @@ -1,8 +1,7 @@ import type { SiteSpace } from '@gitbook/api'; +import { getSiteSpaceURL } from '@/lib/sites'; import { tcls } from '@/lib/tailwind'; - -import { joinPath } from '@/lib/paths'; import type { GitBookSiteContext } from '@v2/lib/context'; import { DropdownChevron, DropdownMenu } from './DropdownMenu'; import { SpacesDropdownMenuItem } from './SpacesDropdownMenuItem'; @@ -73,9 +72,7 @@ export function SpacesDropdown(props: { variantSpace={{ id: otherSiteSpace.id, title: otherSiteSpace.title, - url: otherSiteSpace.urls.published - ? linker.toLinkForContent(otherSiteSpace.urls.published) - : getFallbackSiteSpaceURL(otherSiteSpace, context), + url: getSiteSpaceURL(context, otherSiteSpace), }} active={otherSiteSpace.id === siteSpace.id} /> @@ -83,14 +80,3 @@ export function SpacesDropdown(props: { ); } - -/** - * When the site is not published yet, `urls.published` is not available. - * To ensure navigation works in preview, we compute a relative URL from the siteSpace path. - */ -function getFallbackSiteSpaceURL(siteSpace: SiteSpace, context: GitBookSiteContext) { - const { linker, sections } = context; - return linker.toPathInSite( - sections?.current ? joinPath(sections.current.path, siteSpace.path) : siteSpace.path - ); -} diff --git a/packages/gitbook/src/components/SiteSections/encodeClientSiteSections.ts b/packages/gitbook/src/components/SiteSections/encodeClientSiteSections.ts index 49b73a8e1a..1c8cd09899 100644 --- a/packages/gitbook/src/components/SiteSections/encodeClientSiteSections.ts +++ b/packages/gitbook/src/components/SiteSections/encodeClientSiteSections.ts @@ -1,3 +1,4 @@ +import { getSectionURL, getSiteSpaceURL } from '@/lib/sites'; import type { SiteSection, SiteSectionGroup } from '@gitbook/api'; import type { GitBookSiteContext, SiteSections } from '@v2/lib/context'; @@ -46,15 +47,35 @@ export function encodeClientSiteSections(context: GitBookSiteContext, sections: } function encodeSection(context: GitBookSiteContext, section: SiteSection) { - const { linker } = context; return { id: section.id, title: section.title, description: section.description, icon: section.icon, object: section.object, - url: section.urls.published - ? linker.toLinkForContent(section.urls.published) - : linker.toPathInSite(section.path), + url: findBestTargetURL(context, section), }; } + +/** + * Find the best default site space to navigate to for a givent section: + * 1. If we are on the default, continue on the default. + * 2. If a site space has the same path as the current one, return it. + * 3. Otherwise, return the default one. + */ +function findBestTargetURL(context: GitBookSiteContext, section: SiteSection) { + const { siteSpace: currentSiteSpace } = context; + + if (section.siteSpaces.length === 1 || currentSiteSpace.default) { + return getSectionURL(context, section); + } + + const bestMatch = section.siteSpaces.find( + (siteSpace) => siteSpace.path === currentSiteSpace.path + ); + if (bestMatch) { + return getSiteSpaceURL(context, bestMatch); + } + + return getSectionURL(context, section); +} diff --git a/packages/gitbook/src/lib/sites.ts b/packages/gitbook/src/lib/sites.ts index 88d63e75d3..1827683e48 100644 --- a/packages/gitbook/src/lib/sites.ts +++ b/packages/gitbook/src/lib/sites.ts @@ -1,4 +1,6 @@ import type { SiteSection, SiteSectionGroup, SiteSpace, SiteStructure } from '@gitbook/api'; +import type { GitBookSiteContext } from '@v2/lib/context'; +import { joinPath } from './paths'; /** * Get all sections from a site structure. @@ -64,6 +66,34 @@ export function findSiteSpaceById(siteStructure: SiteStructure, spaceId: string) return null; } +/** + * Get the URL to navigate to for a section. + * When the site is not published yet, `urls.published` is not available. + * To ensure navigation works in preview, we compute a relative URL from the siteSection path. + */ +export function getSectionURL(context: GitBookSiteContext, section: SiteSection) { + const { linker } = context; + return section.urls.published + ? linker.toLinkForContent(section.urls.published) + : linker.toPathInSite(section.path); +} + +/** + * Get the URL to navigate to for a site space. + * When the site is not published yet, `urls.published` is not available. + * To ensure navigation works in preview, we compute a relative URL from the siteSpace path. + */ +export function getSiteSpaceURL(context: GitBookSiteContext, siteSpace: SiteSpace) { + const { linker, sections } = context; + if (siteSpace.urls.published) { + return linker.toLinkForContent(siteSpace.urls.published); + } + + return linker.toPathInSite( + sections?.current ? joinPath(sections.current.path, siteSpace.path) : siteSpace.path + ); +} + function findSiteSpaceByIdInSections(sections: SiteSection[], spaceId: string): SiteSpace | null { for (const section of sections) { const siteSpace = From fe91fd4ad15c80cd222dc348259f1945e655ad04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samy=20Pess=C3=A9?= Date: Thu, 12 Jun 2025 08:52:23 +0200 Subject: [PATCH 2/3] Changeset --- .changeset/hip-bobcats-cover.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/hip-bobcats-cover.md diff --git a/.changeset/hip-bobcats-cover.md b/.changeset/hip-bobcats-cover.md new file mode 100644 index 0000000000..9bd789f85d --- /dev/null +++ b/.changeset/hip-bobcats-cover.md @@ -0,0 +1,5 @@ +--- +"gitbook": minor +--- + +Best effort at preserving current variant when navigating between sections by matching the pathname against site spaces in the new section. From 0aa984d3201ca76ab3a6b83972b0c8f15c676611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samy=20Pess=C3=A9?= Date: Thu, 12 Jun 2025 08:54:52 +0200 Subject: [PATCH 3/3] Format --- packages/gitbook/src/components/Header/SpacesDropdown.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/gitbook/src/components/Header/SpacesDropdown.tsx b/packages/gitbook/src/components/Header/SpacesDropdown.tsx index f0a40bd23c..dd6887d955 100644 --- a/packages/gitbook/src/components/Header/SpacesDropdown.tsx +++ b/packages/gitbook/src/components/Header/SpacesDropdown.tsx @@ -13,7 +13,6 @@ export function SpacesDropdown(props: { className?: string; }) { const { context, siteSpace, siteSpaces, className } = props; - const { linker } = context; return (