Compare commits

...

4 Commits

Author SHA1 Message Date
Zeno Kapitein 3a37591bd4 Fix double display on no-toc 2025-08-14 20:09:19 +02:00
Zeno Kapitein b9b5887b5f Mobile considerations 2025-08-14 20:02:17 +02:00
Zeno Kapitein 6ecdfc695a Moves language picker to bottom right 2025-08-14 19:40:31 +02:00
Zeno Kapitein a9d011aa2e Move variant selector to sidebar & support translations 2025-08-14 19:21:13 +02:00
6 changed files with 72 additions and 29 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"gitbook": patch
---
Move variant selector to sidebar & support translations
@@ -17,9 +17,10 @@ import { SpacesDropdown } from './SpacesDropdown';
export function Header(props: { export function Header(props: {
context: GitBookSiteContext; context: GitBookSiteContext;
withTopHeader?: boolean; withTopHeader?: boolean;
withVariants?: 'generic' | 'translations';
search?: React.ReactNode; search?: React.ReactNode;
}) { }) {
const { context, withTopHeader, search } = props; const { context, withTopHeader, withVariants, search } = props;
const { siteSpace, siteSpaces, sections, customization } = context; const { siteSpace, siteSpaces, sections, customization } = context;
return ( return (
@@ -143,7 +144,7 @@ export function Header(props: {
</div> </div>
</div> </div>
{sections || siteSpaces.length > 1 ? ( {sections || withVariants ? (
<div className="scroll-nojump"> <div className="scroll-nojump">
<div className="transition-all duration-300 lg:chat-open:pr-80 xl:chat-open:pr-96"> <div className="transition-all duration-300 lg:chat-open:pr-80 xl:chat-open:pr-96">
<div <div
@@ -164,10 +165,13 @@ export function Header(props: {
'page-default-width:2xl:px-[calc((100%-1536px+4rem)/2)]' 'page-default-width:2xl:px-[calc((100%-1536px+4rem)/2)]'
)} )}
> >
{siteSpaces.length > 1 && ( {withVariants ? (
<div <div
id="variants" id="variants"
className="my-2 mr-5 grow border-tint border-r pr-5 *:grow only:mr-0 only:border-none only:pr-0 sm:max-w-64" className={tcls(
'my-2 mr-5 page-no-toc:flex hidden grow border-tint border-r pr-5 *:grow only:mr-0 only:border-none only:pr-0 sm:max-w-64',
withVariants === 'translations' ? 'xl:hidden!' : ''
)}
> >
<SpacesDropdown <SpacesDropdown
context={context} context={context}
@@ -176,14 +180,17 @@ export function Header(props: {
className="w-full grow py-1" className="w-full grow py-1"
/> />
</div> </div>
)} ) : null}
{sections && {sections
(sections.list.some((s) => s.object === 'site-section-group') || // If there's even a single group, show the tabs ? (sections.list.some(
sections.list.length > 1) && ( // Otherwise, show the tabs if there's more than one section (s) => s.object === 'site-section-group'
<SiteSectionTabs ) || // If there's even a single group, show the tabs
sections={encodeClientSiteSections(context, sections)} sections.list.length > 1) && ( // Otherwise, show the tabs if there's more than one section
/> <SiteSectionTabs
)} sections={encodeClientSiteSections(context, sections)}
/>
)
: null}
</div> </div>
</div> </div>
</div> </div>
@@ -44,18 +44,18 @@ export function SpacesDropdown(props: {
'hover:text-tint-strong', 'hover:text-tint-strong',
'data-[state=open]:text-tint-strong', 'data-[state=open]:text-tint-strong',
'ring-1', 'border',
'ring-tint-subtle', 'border-tint-subtle',
'hover:ring-tint-hover', 'hover:border-tint-hover',
'data-[state=open]:ring-tint-hover', 'data-[state=open]:border-tint-hover',
'contrast-more:bg-tint-base', 'contrast-more:bg-tint-base',
'contrast-more:ring-1', 'contrast-more:border',
'contrast-more:hover:ring-2', 'contrast-more:hover:border-2',
'contrast-more:data-[state=open]:ring-2', 'contrast-more:data-[state=open]:border-2',
'contrast-more:ring-tint', 'contrast-more:border-tint',
'contrast-more:hover:ring-tint-hover', 'contrast-more:hover:border-tint-hover',
'contrast-more:data-[state=open]:ring-tint-hover', 'contrast-more:data-[state=open]:border-tint-hover',
className className
)} )}
@@ -15,6 +15,7 @@ import { getDocumentSections } from '@/lib/document-sections';
import { tcls } from '@/lib/tailwind'; import { tcls } from '@/lib/tailwind';
import { Ad } from '../Ads'; import { Ad } from '../Ads';
import { SpacesDropdown } from '../Header/SpacesDropdown';
import { getPDFURLSearchParams } from '../PDF'; import { getPDFURLSearchParams } from '../PDF';
import { PageFeedbackForm } from '../PageFeedback'; import { PageFeedbackForm } from '../PageFeedback';
import { ThemeToggler } from '../ThemeToggler'; import { ThemeToggler } from '../ThemeToggler';
@@ -292,6 +293,18 @@ async function PageAsideFooter(props: { context: GitBookSiteContext }) {
ignore={process.env.NODE_ENV !== 'production'} ignore={process.env.NODE_ENV !== 'production'}
style={site?.ads ? 'mt-4' : undefined} style={site?.ads ? 'mt-4' : undefined}
/> />
{context.siteSpaces.some(
(space) =>
space.space.language &&
space.space.language !== context.siteSpace.space.language
) ? (
<SpacesDropdown
context={context}
siteSpace={context.siteSpace}
siteSpaces={context.siteSpaces}
className="mt-2 w-full grow py-2"
/>
) : null}
</div> </div>
); );
} }
@@ -18,7 +18,7 @@ import { useSearch } from './useSearch';
interface SearchContainerProps { interface SearchContainerProps {
siteSpaceId: string; siteSpaceId: string;
spaceTitle: string; spaceTitle: string;
isMultiVariants: boolean; withVariants: boolean;
aiMode: CustomizationAIMode; aiMode: CustomizationAIMode;
className?: string; className?: string;
} }
@@ -27,7 +27,7 @@ interface SearchContainerProps {
* Client component to render the search input and results. * Client component to render the search input and results.
*/ */
export function SearchContainer(props: SearchContainerProps) { export function SearchContainer(props: SearchContainerProps) {
const { siteSpaceId, spaceTitle, isMultiVariants, aiMode, className } = props; const { siteSpaceId, spaceTitle, withVariants, aiMode, className } = props;
const withAIChat = aiMode === CustomizationAIMode.Assistant; const withAIChat = aiMode === CustomizationAIMode.Assistant;
const [state, setSearchState] = useSearch(withAIChat); const [state, setSearchState] = useSearch(withAIChat);
@@ -142,7 +142,7 @@ export function SearchContainer(props: SearchContainerProps) {
// Only show content if there's a query or Ask is enabled // Only show content if there's a query or Ask is enabled
(state?.query || aiMode !== CustomizationAIMode.None) && open ? ( (state?.query || aiMode !== CustomizationAIMode.None) && open ? (
<React.Suspense fallback={null}> <React.Suspense fallback={null}>
{isMultiVariants && !showAsk ? ( {withVariants && !showAsk ? (
<SearchScopeToggle spaceTitle={spaceTitle} /> <SearchScopeToggle spaceTitle={spaceTitle} />
) : null} ) : null}
{state !== null && !showAsk ? ( {state !== null && !showAsk ? (
@@ -44,8 +44,18 @@ export function SpaceLayout(props: {
const withTopHeader = customization.header.preset !== CustomizationHeaderPreset.None; const withTopHeader = customization.header.preset !== CustomizationHeaderPreset.None;
const currentLanguage =
siteSpace.space.language ?? context.customization.internationalization.locale;
const withSections = Boolean(sections && sections.list.length > 1); const withSections = Boolean(sections && sections.list.length > 1);
const isMultiVariants = Boolean(siteSpaces.length > 1); const withVariants: 'generic' | 'translations' | undefined =
siteSpaces.length > 1
? siteSpaces.some(
(space) => space.space.language && space.space.language !== currentLanguage
)
? 'translations'
: 'generic'
: undefined;
const withFooter = const withFooter =
customization.themes.toggeable || customization.themes.toggeable ||
@@ -60,7 +70,7 @@ export function SpaceLayout(props: {
<React.Suspense fallback={null}> <React.Suspense fallback={null}>
<SearchContainer <SearchContainer
aiMode={aiMode} aiMode={aiMode}
isMultiVariants={siteSpaces.length > 1} withVariants={Boolean(withVariants)}
spaceTitle={siteSpace.title} spaceTitle={siteSpace.title}
siteSpaceId={siteSpace.id} siteSpaceId={siteSpace.id}
/> />
@@ -96,7 +106,12 @@ export function SpaceLayout(props: {
visitorCookieTrackingEnabled={customization.insights?.trackingCookie} visitorCookieTrackingEnabled={customization.insights?.trackingCookie}
> >
<Announcement context={context} /> <Announcement context={context} />
<Header withTopHeader={withTopHeader} context={context} search={searchAndAI} /> <Header
withVariants={withVariants}
withTopHeader={withTopHeader}
context={context}
search={searchAndAI}
/>
{aiMode === CustomizationAIMode.Assistant ? ( {aiMode === CustomizationAIMode.Assistant ? (
<AIChat trademark={customization.trademark.enabled} /> <AIChat trademark={customization.trademark.enabled} />
) : null} ) : null}
@@ -147,13 +162,16 @@ export function SpaceLayout(props: {
)} )}
/> />
)} )}
{isMultiVariants && !sections && ( {withVariants && (
<SpacesDropdown <SpacesDropdown
context={context} context={context}
siteSpace={siteSpace} siteSpace={siteSpace}
siteSpaces={siteSpaces} siteSpaces={siteSpaces}
className={tcls( className={tcls(
'w-full', 'w-full',
withVariants === 'translations'
? 'xl:hidden'
: '',
'page-no-toc:hidden', 'page-no-toc:hidden',
'page-no-toc:site-header-none:flex' 'page-no-toc:site-header-none:flex'
)} )}