Preserve current variant when navigating between sections (#3306)

This commit is contained in:
Samy Pessé
2025-06-12 09:30:08 +02:00
committed by GitHub
parent 7a00880e5b
commit c3b620e975
4 changed files with 62 additions and 21 deletions
+5
View File
@@ -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.
@@ -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';
@@ -14,7 +13,6 @@ export function SpacesDropdown(props: {
className?: string;
}) {
const { context, siteSpace, siteSpaces, className } = props;
const { linker } = context;
return (
<DropdownMenu
@@ -73,9 +71,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 +79,3 @@ export function SpacesDropdown(props: {
</DropdownMenu>
);
}
/**
* 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
);
}
@@ -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);
}
+30
View File
@@ -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 =