From 62ca6d3ce53528df0d369555c5554e76fa1dd49a Mon Sep 17 00:00:00 2001 From: Zeno Kapitein Date: Fri, 3 Jul 2026 12:36:07 +0200 Subject: [PATCH] Show a "Back to [space]" shortcut when a link leads to another space (#4358) Co-authored-by: Claude Opus 4.8 --- .changeset/back-to-space-toc.md | 5 + .../Header/SpacesDropdownMenuItem.tsx | 19 +- .../src/components/SitePage/SitePage.tsx | 27 +-- .../SiteSections/SiteSectionList.tsx | 3 +- .../SiteSections/SiteSectionTabs.tsx | 2 + .../TableOfContents/BackToSpaceButton.tsx | 56 ++++++ .../TableOfContents/TableOfContents.tsx | 8 + .../gitbook/src/components/hooks/index.ts | 1 + .../components/hooks/useBackToSpace.test.ts | 104 ++++++++++ .../src/components/hooks/useBackToSpace.tsx | 178 ++++++++++++++++++ packages/gitbook/src/intl/translations/ar.ts | 1 + packages/gitbook/src/intl/translations/bg.ts | 1 + packages/gitbook/src/intl/translations/cs.ts | 1 + packages/gitbook/src/intl/translations/da.ts | 1 + packages/gitbook/src/intl/translations/de.ts | 1 + packages/gitbook/src/intl/translations/el.ts | 1 + packages/gitbook/src/intl/translations/en.ts | 1 + packages/gitbook/src/intl/translations/es.ts | 1 + packages/gitbook/src/intl/translations/et.ts | 1 + packages/gitbook/src/intl/translations/fi.ts | 1 + packages/gitbook/src/intl/translations/fr.ts | 1 + packages/gitbook/src/intl/translations/he.ts | 1 + packages/gitbook/src/intl/translations/hi.ts | 1 + packages/gitbook/src/intl/translations/hr.ts | 1 + packages/gitbook/src/intl/translations/hu.ts | 1 + packages/gitbook/src/intl/translations/id.ts | 1 + packages/gitbook/src/intl/translations/it.ts | 1 + packages/gitbook/src/intl/translations/ja.ts | 1 + packages/gitbook/src/intl/translations/ko.ts | 1 + packages/gitbook/src/intl/translations/lt.ts | 1 + packages/gitbook/src/intl/translations/lv.ts | 1 + packages/gitbook/src/intl/translations/ms.ts | 1 + packages/gitbook/src/intl/translations/nl.ts | 1 + packages/gitbook/src/intl/translations/no.ts | 1 + packages/gitbook/src/intl/translations/pl.ts | 1 + .../gitbook/src/intl/translations/pt-br.ts | 1 + packages/gitbook/src/intl/translations/pt.ts | 1 + packages/gitbook/src/intl/translations/ro.ts | 1 + packages/gitbook/src/intl/translations/ru.ts | 1 + packages/gitbook/src/intl/translations/sk.ts | 1 + packages/gitbook/src/intl/translations/sl.ts | 1 + packages/gitbook/src/intl/translations/sv.ts | 1 + packages/gitbook/src/intl/translations/th.ts | 1 + packages/gitbook/src/intl/translations/tr.ts | 1 + packages/gitbook/src/intl/translations/uk.ts | 1 + packages/gitbook/src/intl/translations/vi.ts | 1 + packages/gitbook/src/intl/translations/yue.ts | 1 + .../gitbook/src/intl/translations/zh-tw.ts | 1 + packages/gitbook/src/intl/translations/zh.ts | 1 + packages/gitbook/src/lib/sites.ts | 27 +++ 50 files changed, 440 insertions(+), 29 deletions(-) create mode 100644 .changeset/back-to-space-toc.md create mode 100644 packages/gitbook/src/components/TableOfContents/BackToSpaceButton.tsx create mode 100644 packages/gitbook/src/components/hooks/useBackToSpace.test.ts create mode 100644 packages/gitbook/src/components/hooks/useBackToSpace.tsx diff --git a/.changeset/back-to-space-toc.md b/.changeset/back-to-space-toc.md new file mode 100644 index 000000000..fc502837a --- /dev/null +++ b/.changeset/back-to-space-toc.md @@ -0,0 +1,5 @@ +--- +"gitbook": patch +--- + +Show a "Back to [space]" shortcut at the top of the table of contents when a reader follows a link into a different space, so they don't lose track of where they were browsing from. diff --git a/packages/gitbook/src/components/Header/SpacesDropdownMenuItem.tsx b/packages/gitbook/src/components/Header/SpacesDropdownMenuItem.tsx index 68c28b8fc..6ca5aa50a 100644 --- a/packages/gitbook/src/components/Header/SpacesDropdownMenuItem.tsx +++ b/packages/gitbook/src/components/Header/SpacesDropdownMenuItem.tsx @@ -1,7 +1,11 @@ 'use client'; import { joinPath } from '@/lib/paths'; -import { useCurrentPageMetadata, useCurrentPagePath } from '../hooks'; +import { + markSpaceNavigationFromPickerOnClick, + useCurrentPageMetadata, + useCurrentPagePath, +} from '../hooks'; import { DropdownMenuItem } from '../primitives/DropdownMenu'; interface VariantSpace { @@ -60,7 +64,18 @@ export function SpacesDropdownMenuItem(props: { const variantHref = useVariantSpaceHref(variantSpace, currentSpacePath, active); return ( - + { + // Switching variant/translation through the picker shouldn't offer to + // navigate "back" to the space we're leaving. + if (!active) { + markSpaceNavigationFromPickerOnClick(event); + } + }} + > {variantSpace.title} ); diff --git a/packages/gitbook/src/components/SitePage/SitePage.tsx b/packages/gitbook/src/components/SitePage/SitePage.tsx index 073717f49..684115f3b 100644 --- a/packages/gitbook/src/components/SitePage/SitePage.tsx +++ b/packages/gitbook/src/components/SitePage/SitePage.tsx @@ -25,7 +25,7 @@ import { } from '@/lib/icons/inline'; import { getResizedImageURL } from '@/lib/images'; import { resolveContentRef } from '@/lib/references'; -import { getLocalizedTitle } from '@/lib/sites'; +import { getSiteStructureTitle } from '@/lib/sites'; import { tcls } from '@/lib/tailwind'; import { getPageRSSURL } from '@/routes/rss'; import { PageContextProvider } from '../PageContext'; @@ -149,31 +149,6 @@ export async function generateSitePageViewport(context: GitBookSiteContext): Pro }; } -/** - * A string concatenation of the site structure (sections and variants) titles. - */ -function getSiteStructureTitle(context: GitBookSiteContext): string | null { - const { visibleSections: sections, siteSpace, visibleSiteSpaces: siteSpaces } = context; - const currentLanguage = context.locale; - - const title = []; - if ( - sections && - sections.current.default === false && // Only if the current section is not the default one - sections.list.filter((section) => section.object === 'site-section').length > 1 // Only if there are multiple sections - ) { - title.push(getLocalizedTitle(sections.current, currentLanguage)); - } - if ( - siteSpaces.length > 1 && // Only if there are multiple variants - siteSpace.default === false && // Only if the variant is not the default one - siteSpaces.filter((space) => space.space.language === siteSpace.space.language).length > 1 // Only if there are multiple variants *for the current language*. This filters out spaces that are "just" translations of each other, not versions. - ) { - title.push(getLocalizedTitle(siteSpace, siteSpace.space.language)); - } - return title.join(' '); -} - export async function generateSitePageMetadata(props: SitePageProps): Promise { const { context, pageTarget, pageMetaLinks } = await getPageDataWithFallback({ context: props.context, diff --git a/packages/gitbook/src/components/SiteSections/SiteSectionList.tsx b/packages/gitbook/src/components/SiteSections/SiteSectionList.tsx index 399525a07..213325f44 100644 --- a/packages/gitbook/src/components/SiteSections/SiteSectionList.tsx +++ b/packages/gitbook/src/components/SiteSections/SiteSectionList.tsx @@ -6,7 +6,7 @@ import React from 'react'; import { type ClassValue, tcls } from '@/lib/tailwind'; import { findSectionInGroup } from '@/lib/utils'; -import { useToggleAnimation } from '../hooks'; +import { markSpaceNavigationFromPickerOnClick, useToggleAnimation } from '../hooks'; import { Link, ToggleChevron } from '../primitives'; import { ScrollContainer } from '../primitives/ScrollContainer'; import { SectionIcon } from './SectionIcon'; @@ -31,6 +31,7 @@ export function SiteSectionList(props: { sections: ClientSiteSections; className sectionsAndGroups.length > 0 && (