From 205c512cb643db5fbaf2a05c38b05690097389e3 Mon Sep 17 00:00:00 2001 From: Nicolas Dorseuil Date: Tue, 16 Jun 2026 16:53:32 +0200 Subject: [PATCH] Refactor variant categorization in StructurePreview to utilize categorizeVariants function for improved clarity and maintainability --- .../SpaceLayout/categorizeVariants.ts | 7 ++- .../StructurePreview/StructurePreview.tsx | 7 ++- .../components/StructurePreview/state.test.ts | 61 ++++++++++++++++++- .../src/components/StructurePreview/state.ts | 24 +------- 4 files changed, 73 insertions(+), 26 deletions(-) diff --git a/packages/gitbook/src/components/SpaceLayout/categorizeVariants.ts b/packages/gitbook/src/components/SpaceLayout/categorizeVariants.ts index fc31fd1e9..5ef00382a 100644 --- a/packages/gitbook/src/components/SpaceLayout/categorizeVariants.ts +++ b/packages/gitbook/src/components/SpaceLayout/categorizeVariants.ts @@ -2,10 +2,15 @@ import { languages } from '@/intl/translations'; import type { GitBookSiteContext } from '@/lib/context'; import { getSiteSpaceLanguages, normalizeLanguage } from '@/lib/sites'; +type SiteSpaceVariantsContext = Pick< + GitBookSiteContext, + 'locale' | 'siteSpace' | 'siteSpaces' | 'visibleSiteSpaces' +>; + /** * Categorize the variants of the space into generic and translation variants. */ -export function categorizeVariants(context: GitBookSiteContext) { +export function categorizeVariants(context: SiteSpaceVariantsContext) { const { siteSpace } = context; // By default, variants only include visible spaces. diff --git a/packages/gitbook/src/components/StructurePreview/StructurePreview.tsx b/packages/gitbook/src/components/StructurePreview/StructurePreview.tsx index 61bdaa7b7..1c45abdf5 100644 --- a/packages/gitbook/src/components/StructurePreview/StructurePreview.tsx +++ b/packages/gitbook/src/components/StructurePreview/StructurePreview.tsx @@ -121,6 +121,9 @@ function StructurePreviewHeader(props: { snapshot: StructurePreviewSnapshot }) { (sections.list.length > 1 || sections.list.some((section) => section.object === 'site-section-group')) ); + const translationSiteSpace = + variants.translations.find((space) => space.id === snapshot.siteSpace.id) ?? + snapshot.siteSpace; return ( 1 ? ( @@ -201,7 +204,7 @@ function StructurePreviewHeader(props: { snapshot: StructurePreviewSnapshot }) { {variants.translations.length > 1 ? ( diff --git a/packages/gitbook/src/components/StructurePreview/state.test.ts b/packages/gitbook/src/components/StructurePreview/state.test.ts index eeefde970..fd1e89dc4 100644 --- a/packages/gitbook/src/components/StructurePreview/state.test.ts +++ b/packages/gitbook/src/components/StructurePreview/state.test.ts @@ -1,8 +1,10 @@ import { describe, expect, it } from 'bun:test'; +import { languages } from '@/intl/translations'; import { defaultCustomization } from '@/lib/utils'; +import { TranslationLanguage } from '@gitbook/api'; -import { encodePreviewSiteSections, isStructurePreviewMessage } from './state'; +import { encodePreviewSiteSections, getPreviewVariants, isStructurePreviewMessage } from './state'; import type { StructurePreviewSnapshot } from './types'; function createSnapshot( @@ -98,4 +100,61 @@ describe('structure preview state', () => { expect(encoded?.current.url).toBe('#'); expect(encoded?.list[0]?.object).toBe('site-section-group'); }); + + it('categorizes translation variants like the rendered header', () => { + const currentSiteSpace = { + id: 'v15-it', + title: 'v15', + path: '', + default: false, + hidden: false, + urls: {}, + space: { + id: 'space-v15-it', + revision: 'revision-v15-it', + language: TranslationLanguage.It, + }, + }; + const siteSpaces = [ + { id: 'v20-en', title: 'v20', language: TranslationLanguage.En }, + { id: 'v20-fr', title: 'v20', language: TranslationLanguage.Fr }, + { id: 'v20-it', title: 'v20', language: TranslationLanguage.It }, + { id: 'v15-en', title: 'v15', language: TranslationLanguage.En }, + { id: 'v15-fr', title: 'v15', language: TranslationLanguage.Fr }, + currentSiteSpace, + ].map((siteSpace) => + 'space' in siteSpace + ? siteSpace + : { + id: siteSpace.id, + title: siteSpace.title, + path: '', + default: false, + hidden: false, + urls: {}, + space: { + id: `space-${siteSpace.id}`, + revision: `revision-${siteSpace.id}`, + language: siteSpace.language, + }, + } + ); + const snapshot = createSnapshot({ + locale: TranslationLanguage.It, + siteSpace: currentSiteSpace, + siteSpaces, + visibleSiteSpaces: siteSpaces, + } as unknown as Partial); + + const variants = getPreviewVariants(snapshot); + + expect(variants.generic.map((space) => space.id)).toEqual(['v20-it', 'v15-it']); + expect( + variants.translations.map((space) => ({ id: space.id, title: space.title })) + ).toEqual([ + { id: 'v15-en', title: languages.en.language }, + { id: 'v15-fr', title: languages.fr.language }, + { id: 'v15-it', title: languages.it.language }, + ]); + }); }); diff --git a/packages/gitbook/src/components/StructurePreview/state.ts b/packages/gitbook/src/components/StructurePreview/state.ts index a281cc8e2..1821ec87a 100644 --- a/packages/gitbook/src/components/StructurePreview/state.ts +++ b/packages/gitbook/src/components/StructurePreview/state.ts @@ -13,6 +13,7 @@ import type { ClientSiteSectionGroup, ClientSiteSections, } from '@/components/SiteSections/encodeClientSiteSections'; +import { categorizeVariants } from '@/components/SpaceLayout/categorizeVariants'; import { getLocalizedDescription, getLocalizedTitle } from '@/lib/sites'; import type { StructurePreviewMessage, StructurePreviewSnapshot } from './types'; @@ -108,28 +109,7 @@ function encodePreviewSection( } export function getPreviewVariants(snapshot: StructurePreviewSnapshot) { - const siteSpaces = - snapshot.visibleSiteSpaces.length > 0 ? snapshot.visibleSiteSpaces : snapshot.siteSpaces; - const currentLanguage = snapshot.locale ?? snapshot.siteSpace.space.language ?? 'en'; - const languages = [...new Set(siteSpaces.map((space) => space.space.language ?? 'en'))]; - const isMultiLanguage = languages.length > 1; - - return { - generic: isMultiLanguage - ? siteSpaces.filter( - (space) => - space.id === snapshot.siteSpace.id || - (space.space.language ?? 'en') === currentLanguage - ) - : siteSpaces, - translations: isMultiLanguage - ? siteSpaces.filter( - (space) => - space.id === snapshot.siteSpace.id || - (space.space.language ?? 'en') !== currentLanguage - ) - : [], - }; + return categorizeVariants(snapshot); } export function getHeaderSocialAccounts(customization: SiteCustomizationSettings) {