Remove scroll-nojump utility and update layout structure (#3494)

Co-authored-by: Zeno Kapitein <zeno@gitbook.io>
This commit is contained in:
Nolann B.
2025-08-29 11:22:55 +02:00
committed by GitHub
parent 1b8609ac60
commit abbae3ec4d
10 changed files with 414 additions and 426 deletions
@@ -187,7 +187,7 @@ async function DescriptionForSearchToolCall(props: {
) : null}
</summary>
{hasResults ? (
<div className="mt-1 max-h-0 overflow-y-auto circular-corners:rounded-2xl rounded-corners:rounded-lg border border-tint-subtle p-2 opacity-0 transition-all transition-discrete duration-500 group-open:max-h-96 group-open:opacity-11">
<div className="hide-scrollbar mt-1 max-h-0 overflow-y-auto circular-corners:rounded-2xl rounded-corners:rounded-lg border border-tint-subtle p-2 opacity-0 transition-all transition-discrete duration-500 group-open:max-h-96 group-open:opacity-11">
<ol className="space-y-1">
{searchResultsWithHrefs.map((result, index) => (
<li
@@ -213,7 +213,7 @@ export function AIChatBody(props: {
<>
<div
ref={scrollContainerRef}
className="flex grow scroll-pt-4 flex-col gap-4 overflow-y-auto p-4"
className="gutter-stable flex grow scroll-pt-4 flex-col gap-4 overflow-y-auto p-4"
style={{
paddingBottom: `${inputHeight}px`,
}}
@@ -34,69 +34,67 @@ export function AnnouncementBanner(props: {
className="theme-bold:bg-header-background pt-4 pb-2"
data-nosnippet=""
>
<div className="scroll-nojump">
<div className="transition-all duration-300 lg:chat-open:pr-80 xl:chat-open:pr-96">
<div className={tcls('relative', CONTAINER_STYLE)}>
<Tag
href={contentRef?.href ?? ''}
className={tcls(
'flex w-full items-start justify-center overflow-hidden circular-corners:rounded-xl rounded-md straight-corners:rounded-none px-4 py-3 text-neutral-strong text-sm theme-bold:ring-1 theme-gradient:ring-1 ring-inset transition-colors',
style.container,
closeable && 'pr-12',
hasLink && style.hover
)}
insights={
announcement.link
? {
type: 'link_click',
link: {
target: announcement.link.to,
position: SiteInsightsLinkPosition.Announcement,
},
}
: undefined
}
>
<Icon
icon={style.icon as IconName}
className={`mt-0.5 mr-3 size-4 shrink-0 ${style.iconColor}`}
/>
<div>
{announcement.message}
{hasLink ? (
<div className={tcls(LinkStyles, style.link, 'ml-1 inline')}>
{contentRef?.icon ? (
<span className="mr-1 ml-2 *:inline">
{contentRef?.icon}
</span>
) : null}
{announcement.link?.title && (
<span className="mr-1">{announcement.link?.title}</span>
)}
<Icon
icon={
announcement.link?.to.kind === 'url'
? 'arrow-up-right'
: 'chevron-right'
}
className={tcls('mb-0.5 inline size-3')}
/>
</div>
) : null}
</div>
</Tag>
{closeable ? (
<Button
iconOnly
icon="close"
label={tString(language, 'close')}
variant="blank"
size="default"
onClick={dismissAnnouncement}
className={`absolute top-0 right-4 mt-2 mr-2 circular-corners:rounded-lg rounded-sm straight-corners:rounded-none p-1.5 transition-all hover:ring-1 sm:right-6 md:right-8 ${style.close}`}
/>
) : null}
</div>
<div className="transition-all duration-300 lg:chat-open:pr-80 xl:chat-open:pr-96">
<div className={tcls('relative', CONTAINER_STYLE)}>
<Tag
href={contentRef?.href ?? ''}
className={tcls(
'flex w-full items-start justify-center overflow-hidden circular-corners:rounded-xl rounded-md straight-corners:rounded-none px-4 py-3 text-neutral-strong text-sm theme-bold:ring-1 theme-gradient:ring-1 ring-inset transition-colors',
style.container,
closeable && 'pr-12',
hasLink && style.hover
)}
insights={
announcement.link
? {
type: 'link_click',
link: {
target: announcement.link.to,
position: SiteInsightsLinkPosition.Announcement,
},
}
: undefined
}
>
<Icon
icon={style.icon as IconName}
className={`mt-0.5 mr-3 size-4 shrink-0 ${style.iconColor}`}
/>
<div>
{announcement.message}
{hasLink ? (
<div className={tcls(LinkStyles, style.link, 'ml-1 inline')}>
{contentRef?.icon ? (
<span className="mr-1 ml-2 *:inline">
{contentRef?.icon}
</span>
) : null}
{announcement.link?.title && (
<span className="mr-1">{announcement.link?.title}</span>
)}
<Icon
icon={
announcement.link?.to.kind === 'url'
? 'arrow-up-right'
: 'chevron-right'
}
className={tcls('mb-0.5 inline size-3')}
/>
</div>
) : null}
</div>
</Tag>
{closeable ? (
<Button
iconOnly
icon="close"
label={tString(language, 'close')}
variant="blank"
size="default"
onClick={dismissAnnouncement}
className={`absolute top-0 right-4 mt-2 mr-2 circular-corners:rounded-lg rounded-sm straight-corners:rounded-none p-1.5 transition-all hover:ring-1 sm:right-6 md:right-8 ${style.close}`}
/>
) : null}
</div>
</div>
</div>
+98 -100
View File
@@ -32,111 +32,109 @@ export function Footer(props: { context: GitBookSiteContext }) {
mobileOnly ? 'xl:hidden' : null
)}
>
<div className="scroll-nojump">
<div className={tcls(CONTAINER_STYLE, 'px-4', 'py-8', 'lg:py-12', 'mx-auto')}>
<div
className={tcls(
'mx-auto grid max-w-3xl site-width-wide:max-w-screen-2xl justify-between gap-12 lg:max-w-none!',
'grid-cols-[auto_auto]',
'lg:grid-cols-[18rem_minmax(auto,48rem)_auto]',
'xl:grid-cols-[18rem_minmax(auto,48rem)_14rem]',
'lg:site-width-wide:grid-cols-[18rem_minmax(auto,80rem)_auto]',
'xl:site-width-wide:grid-cols-[18rem_minmax(auto,80rem)_14rem]',
'lg:page-no-toc:grid-cols-[minmax(auto,48rem)_auto]',
'xl:page-no-toc:grid-cols-[14rem_minmax(auto,48rem)_14rem]',
'lg:[body:has(.site-width-wide,.page-no-toc)_&]:grid-cols-[minmax(auto,90rem)_auto]',
'xl:[body:has(.site-width-wide,.page-no-toc)_&]:grid-cols-[14rem_minmax(auto,90rem)_14rem]'
)}
>
{
// Footer Logo
customization.footer.logo ? (
<div className="col-start-1 row-start-1">
<Image
alt="Logo"
resize={context.imageResizer}
sources={{
light: {
src: customization.footer.logo.light,
},
dark: customization.footer.logo.dark
? {
src: customization.footer.logo.dark,
}
: null,
}}
priority="lazy"
style={[
'w-auto',
'max-w-40',
'lg:max-w-64',
'max-h-10',
'lg:max-h-12',
'object-contain',
'object-left',
'rounded-sm',
'straight-corners:rounded-xs',
]}
sizes={[
{
width: 320,
},
]}
/>
</div>
) : null
}
<div className={tcls(CONTAINER_STYLE, 'px-4', 'py-8', 'lg:py-12', 'mx-auto')}>
<div
className={tcls(
'mx-auto grid max-w-3xl site-width-wide:max-w-screen-2xl justify-between gap-12 lg:max-w-none!',
'grid-cols-[auto_auto]',
'lg:grid-cols-[18rem_minmax(auto,48rem)_auto]',
'xl:grid-cols-[18rem_minmax(auto,48rem)_14rem]',
'lg:site-width-wide:grid-cols-[18rem_minmax(auto,80rem)_auto]',
'xl:site-width-wide:grid-cols-[18rem_minmax(auto,80rem)_14rem]',
'lg:page-no-toc:grid-cols-[minmax(auto,48rem)_auto]',
'xl:page-no-toc:grid-cols-[14rem_minmax(auto,48rem)_14rem]',
'lg:[body:has(.site-width-wide,.page-no-toc)_&]:grid-cols-[minmax(auto,90rem)_auto]',
'xl:[body:has(.site-width-wide,.page-no-toc)_&]:grid-cols-[14rem_minmax(auto,90rem)_14rem]'
)}
>
{
// Footer Logo
customization.footer.logo ? (
<div className="col-start-1 row-start-1">
<Image
alt="Logo"
resize={context.imageResizer}
sources={{
light: {
src: customization.footer.logo.light,
},
dark: customization.footer.logo.dark
? {
src: customization.footer.logo.dark,
}
: null,
}}
priority="lazy"
style={[
'w-auto',
'max-w-40',
'lg:max-w-64',
'max-h-10',
'lg:max-h-12',
'object-contain',
'object-left',
'rounded-sm',
'straight-corners:rounded-xs',
]}
sizes={[
{
width: 320,
},
]}
/>
</div>
) : null
}
{
// Theme Toggle
customization.themes.toggeable ? (
<div className="-col-start-2 row-start-1 flex items-start justify-end xl:hidden">
<React.Suspense fallback={null}>
<ThemeToggler />
</React.Suspense>
</div>
) : null
}
{
// Theme Toggle
customization.themes.toggeable ? (
<div className="-col-start-2 row-start-1 flex items-start justify-end xl:hidden">
<React.Suspense fallback={null}>
<ThemeToggler />
</React.Suspense>
</div>
) : null
}
{
// Navigation groups (split into equal columns)
customization.footer.groups?.length > 0 ? (
<div
className={tcls(
'col-span-2 lg:page-has-toc:col-span-1 lg:page-has-toc:col-start-2 xl:page-no-toc:col-span-1 xl:page-no-toc:col-start-2'
{
// Navigation groups (split into equal columns)
customization.footer.groups?.length > 0 ? (
<div
className={tcls(
'col-span-2 lg:page-has-toc:col-span-1 lg:page-has-toc:col-start-2 xl:page-no-toc:col-span-1 xl:page-no-toc:col-start-2'
)}
>
<div className="mx-auto flex max-w-3xl site-width-wide:max-w-screen-2xl flex-col gap-10 sm:flex-row sm:gap-6">
{partition(customization.footer.groups, FOOTER_COLUMNS).map(
(column, columnIndex) => (
<div
key={columnIndex}
className="flex flex-1 grow flex-col gap-10"
>
{column.map((group, groupIndex) => (
<FooterLinksGroup
key={groupIndex}
group={group}
context={context}
/>
))}
</div>
)
)}
>
<div className="mx-auto flex max-w-3xl site-width-wide:max-w-screen-2xl flex-col gap-10 sm:flex-row sm:gap-6">
{partition(customization.footer.groups, FOOTER_COLUMNS).map(
(column, columnIndex) => (
<div
key={columnIndex}
className="flex flex-1 grow flex-col gap-10"
>
{column.map((group, groupIndex) => (
<FooterLinksGroup
key={groupIndex}
group={group}
context={context}
/>
))}
</div>
)
)}
</div>
</div>
) : null
}
</div>
) : null
}
{
// Legal
customization.footer.copyright ? (
<div className="order-last col-span-full flex w-full grow flex-col items-center gap-2 text-center text-tint text-xs">
<p>{customization.footer.copyright}</p>
</div>
) : null
}
</div>
{
// Legal
customization.footer.copyright ? (
<div className="order-last col-span-full flex w-full grow flex-col items-center gap-2 text-center text-tint text-xs">
<p>{customization.footer.copyright}</p>
</div>
) : null
}
</div>
</div>
</footer>
+114 -118
View File
@@ -56,141 +56,137 @@ export function Header(props: {
'theme-bold:shadow-tint-12/2'
)}
>
<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
className={tcls(
'gap-4',
'lg:gap-6',
'flex',
'items-center',
'justify-between',
'w-full',
'py-3',
'min-h-16',
'sm:h-16',
CONTAINER_STYLE
)}
>
<div
className={tcls(
'gap-4',
'lg:gap-6',
'flex',
'items-center',
'justify-between',
'w-full',
'py-3',
'min-h-16',
'sm:h-16',
CONTAINER_STYLE
'flex max-w-full lg:basis-72',
'min-w-0 shrink items-center justify-start gap-2 lg:gap-4'
)}
>
<div
<HeaderMobileMenu
className={tcls(
'flex max-w-full lg:basis-72',
'min-w-0 shrink items-center justify-start gap-2 lg:gap-4'
'lg:hidden',
'-ml-2',
'text-tint-strong',
'theme-bold:text-header-link',
'hover:bg-tint-hover',
'hover:theme-bold:bg-header-link/3',
'page-no-toc:hidden'
)}
>
<HeaderMobileMenu
className={tcls(
'lg:hidden',
'-ml-2',
'text-tint-strong',
'theme-bold:text-header-link',
'hover:bg-tint-hover',
'hover:theme-bold:bg-header-link/3',
'page-no-toc:hidden'
)}
/>
<HeaderLogo context={context} />
</div>
<div
className={tcls(
'flex',
'grow-0',
'shrink-0',
'md:basis-56',
'justify-self-end',
'items-center',
'gap-2',
'search' in customization.styling &&
customization.styling.search === 'prominent'
? [
'md:grow-[0.8]',
'lg:basis-40',
'md:max-w-[40%]',
'lg:max-w-lg',
'lg:ml-[max(calc((100%-18rem-48rem)/2),1.5rem)]', // container (100%) - sidebar (18rem) - content (48rem)
'xl:ml-[max(calc((100%-18rem-48rem-14rem-3rem)/2),1.5rem)]', // container (100%) - sidebar (18rem) - content (48rem) - outline (14rem) - margin (3rem)
'md:mr-auto',
'order-last',
'md:order-[unset]',
]
: ['order-last']
)}
>
<SearchContainer
style={customization.styling.search}
isMultiVariants={siteSpaces.length > 1}
spaceTitle={siteSpace.title}
siteSpaceId={siteSpace.id}
viewport={!withTopHeader ? 'mobile' : undefined}
/>
</div>
{customization.header.links.length > 0 && (
<HeaderLinks>
{customization.header.links.map((link) => {
return (
<HeaderLink
key={link.title}
link={link}
context={context}
/>
);
})}
<HeaderLinkMore
label={t(getSpaceLanguage(context), 'more')}
links={customization.header.links}
context={context}
/>
</HeaderLinks>
)}
/>
<HeaderLogo context={context} />
</div>
<div
className={tcls(
'flex',
'grow-0',
'shrink-0',
'md:basis-56',
'justify-self-end',
'items-center',
'gap-2',
'search' in customization.styling &&
customization.styling.search === 'prominent'
? [
'md:grow-[0.8]',
'lg:basis-40',
'md:max-w-[40%]',
'lg:max-w-lg',
'lg:ml-[max(calc((100%-18rem-48rem)/2),1.5rem)]', // container (100%) - sidebar (18rem) - content (48rem)
'xl:ml-[max(calc((100%-18rem-48rem-14rem-3rem)/2),1.5rem)]', // container (100%) - sidebar (18rem) - content (48rem) - outline (14rem) - margin (3rem)
'md:mr-auto',
'order-last',
'md:order-[unset]',
]
: ['order-last']
)}
>
<SearchContainer
style={customization.styling.search}
isMultiVariants={siteSpaces.length > 1}
spaceTitle={siteSpace.title}
siteSpaceId={siteSpace.id}
viewport={!withTopHeader ? 'mobile' : undefined}
/>
</div>
{customization.header.links.length > 0 && (
<HeaderLinks>
{customization.header.links.map((link) => {
return (
<HeaderLink
key={link.title}
link={link}
context={context}
/>
);
})}
<HeaderLinkMore
label={t(getSpaceLanguage(context), 'more')}
links={customization.header.links}
context={context}
/>
</HeaderLinks>
)}
</div>
</div>
</div>
{sections || siteSpaces.length > 1 ? (
<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
className={tcls(
'w-full',
'overflow-x-auto',
'no-scrollbar',
'-mb-4 pb-4', // Positive padding / negative margin allows the navigation menu indicator to show in a scroll viewƒ
!sections ? ['hidden', 'page-no-toc:flex'] : 'flex'
)}
>
<div
className={tcls(
'w-full',
'overflow-x-auto',
'no-scrollbar',
'-mb-4 pb-4', // Positive padding / negative margin allows the navigation menu indicator to show in a scroll viewƒ
!sections ? ['hidden', 'page-no-toc:flex'] : 'flex'
CONTAINER_STYLE,
'grow',
'flex',
'items-end',
'page-default-width:2xl:px-[calc((100%-1536px+4rem)/2)]'
)}
>
<div
className={tcls(
CONTAINER_STYLE,
'grow',
'flex',
'items-end',
'page-default-width:2xl:px-[calc((100%-1536px+4rem)/2)]'
{siteSpaces.length > 1 && (
<div
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"
>
<SpacesDropdown
context={context}
siteSpace={siteSpace}
siteSpaces={siteSpaces}
className="w-full grow py-1"
/>
</div>
)}
{sections &&
(sections.list.some((s) => s.object === 'site-section-group') || // If there's even a single group, show the tabs
sections.list.length > 1) && ( // Otherwise, show the tabs if there's more than one section
<SiteSectionTabs
sections={encodeClientSiteSections(context, sections)}
/>
)}
>
{siteSpaces.length > 1 && (
<div
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"
>
<SpacesDropdown
context={context}
siteSpace={siteSpace}
siteSpaces={siteSpaces}
className="w-full grow py-1"
/>
</div>
)}
{sections &&
(sections.list.some((s) => s.object === 'site-section-group') || // If there's even a single group, show the tabs
sections.list.length > 1) && ( // Otherwise, show the tabs if there's more than one section
<SiteSectionTabs
sections={encodeClientSiteSections(context, sections)}
/>
)}
</div>
</div>
</div>
</div>
@@ -20,8 +20,7 @@
}
}
@utility hide-scroll {
/* hide scroll bar but still scroll */
@utility no-scrollbar {
&::-webkit-scrollbar {
display: none;
}
@@ -29,6 +28,22 @@
-ms-overflow-style: none;
}
@utility hide-scrollbar {
/* Hide scrollbar by default */
scrollbar-color: transparent transparent;
transition: scrollbar-color 0.2s ease-in-out;
&:hover {
/* Show scrollbar on hover */
scrollbar-color: unset;
}
@media (prefers-contrast: more) {
/* Always show scrollbar in high contrast mode */
scrollbar-color: unset;
}
}
@utility linear-mask-gradient {
mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1) 96px, rgba(0, 0, 0, 0));
mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1) 96px, rgba(0, 0, 0, 0));
@@ -143,47 +158,6 @@
@apply bg-linear-to-bl from-tint-4 to-tint-base to-60% bg-fixed;
}
@utility scroll-nojump {
/**
* Utility to prevent horizontal jumps when the vertical scrollbar appears
* It should be used on main containers of the layout, while preserving horizontal delimiters.
* It basically adds a margin-left with the width of the scrollbar, and a width that compensates for it; when a scrollbar is displayed.
* Inspired by https://aykevl.nl/2014/09/fix-jumping-scrollbar, but adapted to work on child elements of "html"
*/
width: 100%;
@media screen and (min-width: 1536px) {
margin-left: var(--scrollbar-width);
margin-right: 0;
width: calc(100% - var(--scrollbar-width));
body:has(.page-full-width) & {
margin-left: 0;
width: 100%;
}
}
/**
* Utility to prevent horizontal jumps when the vertical scrollbar appears
* It should be used on main containers of the layout, while preserving horizontal delimiters.
* It basically adds a margin-left with the width of the scrollbar, and a width that compensates for it; when a scrollbar is displayed.
* Inspired by https://aykevl.nl/2014/09/fix-jumping-scrollbar, but adapted to work on child elements of "html"
*/
width: 100%;
@media screen and (min-width: 1536px) {
margin-left: var(--scrollbar-width);
margin-right: 0;
width: calc(100% - var(--scrollbar-width));
}
}
@utility page-full-width {
@media screen and (min-width: 1536px) {
body:has(&) .scroll-nojump {
margin-left: 0;
width: 100%;
}
}
}
@utility elevate-link {
& a[href]:not(.link-overlay) {
position: relative;
@@ -211,15 +185,59 @@
@layer base {
:root {
--scrollbar-width: calc(100vw - 100%);
@apply leading-relaxed;
interpolate-size: allow-keywords; /* Opt-in for modern browsers to interpolate "auto" values in transitions/animations. */
}
/* Modern browsers with `scrollbar-*` support */
@supports (scrollbar-color: auto) {
* {
scrollbar-color: theme("colors.tint.7") transparent;
scrollbar-width: thin;
}
@media (prefers-contrast: more) {
* {
scrollbar-color: theme("colors.tint.11") transparent;
scrollbar-width: auto;
}
}
}
/* Otherwise, use `::-webkit-scrollbar-*` pseudo-elements */
@supports selector(::-webkit-scrollbar) {
::-webkit-scrollbar {
background: transparent;
max-width: 8px;
}
::-webkit-scrollbar-thumb {
background: theme("colors.tint.7");
border-radius: 8px;
transition: background 0.2s ease-in-out;
}
::-webkit-scrollbar-thumb:hover {
background: theme("colors.tint.8");
}
@media (prefers-contrast: more) {
::-webkit-scrollbar-thumb {
background: theme("colors.tint.11");
}
::-webkit-scrollbar-thumb:hover {
background: theme("colors.tint.12");
}
}
}
body {
@apply text-tint-strong antialiased;
}
html {
@apply gutter-stable;
scrollbar-width: auto;
}
h1 {
@apply tracking-[-0.025em] text-tint-strong text-balance;
@@ -250,22 +268,6 @@
@apply subpixel-antialiased;
}
/* Light mode */
::-webkit-scrollbar {
@apply bg-tint-subtle;
width: 8px;
height: 8px;
}
::-webkit-scrollbar-thumb {
@apply bg-tint-7;
border-radius: 8px;
}
::-webkit-scrollbar-thumb:hover {
@apply bg-tint-8;
}
.flip-heading-hash {
@apply [h1,h2,h3,h4]:content-start;
@apply [h1,h2,h3,h4]:auto-cols-[auto_1fr];
@@ -194,7 +194,7 @@ export function SearchContainer(props: SearchContainerProps) {
onOpenAutoFocus: (event) => event.preventDefault(),
align: 'start',
className:
'bg-tint-base has-[.empty]:hidden scroll-py-2 w-128 p-2 max-h-[min(32rem,var(--radix-popover-content-available-height))] max-w-[min(var(--radix-popover-content-available-width),32rem)]',
'bg-tint-base has-[.empty]:hidden gutter-stable scroll-py-2 w-128 p-2 pr-1 max-h-[min(32rem,var(--radix-popover-content-available-height))] max-w-[min(var(--radix-popover-content-available-width),32rem)]',
onInteractOutside: (event) => {
// Don't close if clicking on the search input itself
if (searchInputRef.current?.contains(event.target as Node)) {
@@ -38,7 +38,7 @@ export function SiteSectionList(props: { sections: ClientSiteSections; className
>
<TOCScrollContainer
style={{ maxHeight: `${MAX_ITEMS * 3 + 2}rem` }}
className="gutter-stable overflow-y-auto px-2 pb-6"
className="overflow-y-auto px-2 pb-6"
>
{sectionsAndGroups.map((item) => {
if (item.object === 'site-section-group') {
@@ -81,82 +81,81 @@ export function SpaceLayout(props: {
{customization.ai?.mode === CustomizationAIMode.Assistant ? (
<AIChat trademark={customization.trademark.enabled} />
) : null}
<div className="scroll-nojump">
<div className="motion-safe:transition-all motion-safe:duration-300 lg:chat-open:mr-80 xl:chat-open:mr-96">
<div
className={tcls(
'flex',
'flex-col',
'lg:flex-row',
CONTAINER_STYLE,
'site-width-wide:max-w-full',
// Ensure the footer is display below the viewport even if the content is not enough
withFooter && [
'site-header:min-h-[calc(100vh-64px)]',
'site-header-sections:min-h-[calc(100vh-108px)]',
],
withTopHeader ? null : 'lg:min-h-screen'
)}
>
<TableOfContents
context={context}
header={
withTopHeader ? null : (
<div
className={tcls(
'hidden',
'pr-4',
'lg:flex',
'grow-0',
'flex-wrap',
'dark:shadow-light/1',
'text-base/tight'
<div className="motion-safe:transition-all motion-safe:duration-300 lg:chat-open:mr-80 xl:chat-open:mr-96">
<div
className={tcls(
'flex',
'flex-col',
'lg:flex-row',
CONTAINER_STYLE,
'site-width-wide:max-w-full',
// Ensure the footer is display below the viewport even if the content is not enough
withFooter && [
'site-header:min-h-[calc(100vh-64px)]',
'site-header-sections:min-h-[calc(100vh-108px)]',
],
withTopHeader ? null : 'lg:min-h-screen'
)}
>
<TableOfContents
context={context}
header={
withTopHeader ? null : (
<div
className={tcls(
'hidden',
'pr-4',
'lg:flex',
'grow-0',
'flex-wrap',
'dark:shadow-light/1',
'text-base/tight'
)}
>
<HeaderLogo context={context} />
</div>
)
}
innerHeader={
// displays the search button and/or the space dropdown in the ToC according to the header/variant settings. E.g if there is no header, the search button will be displayed in the ToC.
<>
{!withTopHeader && (
<SearchContainer
style={CustomizationSearchStyle.Subtle}
isMultiVariants={siteSpaces.length > 1}
spaceTitle={siteSpace.title}
siteSpaceId={siteSpace.id}
className="max-lg:hidden"
viewport="desktop"
/>
)}
{!withTopHeader && withSections && sections && (
<SiteSectionList
className={tcls('hidden', 'lg:block')}
sections={encodeClientSiteSections(
context,
sections
)}
>
<HeaderLogo context={context} />
</div>
)
}
innerHeader={
// displays the search button and/or the space dropdown in the ToC according to the header/variant settings. E.g if there is no header, the search button will be displayed in the ToC.
<>
{!withTopHeader && (
<SearchContainer
style={CustomizationSearchStyle.Subtle}
isMultiVariants={siteSpaces.length > 1}
spaceTitle={siteSpace.title}
siteSpaceId={siteSpace.id}
className="max-lg:hidden"
viewport="desktop"
/>
)}
{!withTopHeader && withSections && sections && (
<SiteSectionList
className={tcls('hidden', 'lg:block')}
sections={encodeClientSiteSections(
context,
sections
)}
/>
)}
{isMultiVariants && !sections && (
<SpacesDropdown
context={context}
siteSpace={siteSpace}
siteSpaces={siteSpaces}
className={tcls(
'w-full',
'page-no-toc:hidden',
'page-no-toc:site-header-none:flex'
)}
/>
)}
</>
}
/>
<div className="flex min-w-0 flex-1 flex-col">{children}</div>
</div>
/>
)}
{isMultiVariants && !sections && (
<SpacesDropdown
context={context}
siteSpace={siteSpace}
siteSpaces={siteSpaces}
className={tcls(
'w-full',
'page-no-toc:hidden',
'page-no-toc:site-header-none:flex'
)}
/>
)}
</>
}
/>
<div className="flex min-w-0 flex-1 flex-col">{children}</div>
</div>
</div>
@@ -101,12 +101,7 @@ export async function TableOfContents(props: {
className={tcls(
'flex grow flex-col p-2',
customization.trademark.enabled && 'lg:pb-20',
'lg:gutter-stable overflow-y-auto',
'[&::-webkit-scrollbar]:bg-transparent',
'[&::-webkit-scrollbar-thumb]:bg-transparent',
'[&::-webkit-scrollbar]:group-hover:bg-tint-subtle',
'[&::-webkit-scrollbar-thumb]:group-hover:bg-tint-7',
'[&::-webkit-scrollbar-thumb:hover]:group-hover:bg-tint-8'
'hide-scrollbar overflow-y-auto'
)}
>
<PagesList