Skip to content

Rework full-width layout, add support for full-width page option #3293

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jun 11, 2025
5 changes: 5 additions & 0 deletions .changeset/long-cameras-protect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"gitbook": minor
---

Rework full-width layout, add support for full-width page option
10 changes: 5 additions & 5 deletions packages/gitbook/e2e/customers.spec.ts
Original file line number Diff line number Diff line change
@@ -204,11 +204,11 @@ const testCases: TestsCase[] = [
contentBaseURL: 'https://sosovalue-white-paper.gitbook.io',
tests: [{ name: 'Home', url: '/' }],
},
{
name: 'docs.revrobotics.com',
contentBaseURL: 'https://docs.revrobotics.com',
tests: [{ name: 'Home', url: '/', run: waitForCookiesDialog }],
},
// {
// name: 'docs.revrobotics.com',
// contentBaseURL: 'https://docs.revrobotics.com',
// tests: [{ name: 'Home', url: '/', run: waitForCookiesDialog }],
// },
{
name: 'chartschool.stockcharts.com',
contentBaseURL: 'https://chartschool.stockcharts.com',
4 changes: 2 additions & 2 deletions packages/gitbook/src/components/DocumentView/Blocks.tsx
Original file line number Diff line number Diff line change
@@ -70,8 +70,8 @@ export function UnwrappedBlocks<TBlock extends DocumentBlock>(props: UnwrappedBl
style={[
'mx-auto w-full decoration-primary/6',
node.data && 'fullWidth' in node.data && node.data.fullWidth
? 'max-w-screen-xl'
: 'max-w-3xl',
? 'max-w-screen-2xl'
: 'page-full-width:ml-0 max-w-3xl',
blockStyle,
]}
isEstimatedOffscreen={isOffscreen}
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ export function Columns(props: BlockProps<DocumentBlockColumns>) {
ancestorBlocks={[...ancestorBlocks, block, columnBlock]}
context={context}
blockStyle="flip-heading-hash"
style="w-full space-y-4"
style="w-full space-y-4 *:max-w-full"
/>
</Column>
);
2 changes: 1 addition & 1 deletion packages/gitbook/src/components/DocumentView/Divider.tsx
Original file line number Diff line number Diff line change
@@ -7,5 +7,5 @@ import type { BlockProps } from './Block';
export function Divider(props: BlockProps<DocumentBlockDivider>) {
const { style } = props;

return <hr className={tcls(style, 'border-tint-subtle')} />;
return <hr className={tcls(style, 'page-full-width:max-w-full border-tint-subtle')} />;
}
10 changes: 7 additions & 3 deletions packages/gitbook/src/components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
@@ -36,12 +36,16 @@ export function Footer(props: { context: GitBookSiteContext }) {
<div className={tcls(CONTAINER_STYLE, 'px-4', 'py-8', 'lg:py-12', 'mx-auto')}>
<div
className={tcls(
'mx-auto grid max-w-3xl justify-between gap-12 lg:max-w-none',
'lg:!max-w-none mx-auto grid max-w-3xl site-full-width:max-w-screen-2xl justify-between gap-12',
'grid-cols-[auto_auto]',
'lg:grid-cols-[18rem_minmax(auto,_48rem)_auto]',
'xl:grid-cols-[18rem_minmax(auto,_48rem)_14rem]',
'site-full-width:lg:grid-cols-[18rem_minmax(auto,_80rem)_auto]',
'site-full-width:xl:grid-cols-[18rem_minmax(auto,_80rem)_14rem]',
'page-no-toc:lg:grid-cols-[minmax(auto,_48rem)_auto]',
'page-no-toc:xl:grid-cols-[14rem_minmax(auto,_48rem)_14rem]'
'page-no-toc:xl:grid-cols-[14rem_minmax(auto,_48rem)_14rem]',
'[body:has(.site-full-width,.page-no-toc)_&]:lg:grid-cols-[minmax(auto,_90rem)_auto]',
'[body:has(.site-full-width,.page-no-toc)_&]:xl:grid-cols-[14rem_minmax(auto,_90rem)_14rem]'
)}
>
{
@@ -102,7 +106,7 @@ export function Footer(props: { context: GitBookSiteContext }) {
'col-span-2 page-has-toc:lg:col-span-1 page-has-toc:lg:col-start-2 page-no-toc:xl:col-span-1 page-no-toc:xl:col-start-2'
)}
>
<div className="mx-auto flex max-w-3xl flex-col gap-10 sm:flex-row sm:gap-6">
<div className="mx-auto flex max-w-3xl site-full-width:max-w-screen-2xl flex-col gap-10 sm:flex-row sm:gap-6">
{partition(customization.footer.groups, FOOTER_COLUMNS).map(
(column, columnIndex) => (
<div
5 changes: 1 addition & 4 deletions packages/gitbook/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -104,11 +104,9 @@ export function Header(props: { context: GitBookSiteContext; withTopHeader?: boo
'lg:basis-40',
'md:max-w-[40%]',
'lg:max-w-lg',
'lg:ml-[max(calc((100%-18rem-48rem-3rem)/2),1.5rem)]', // container (100%) - sidebar (18rem) - content (48rem) - margin (3rem)
'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)
'page-no-toc:lg:ml-[max(calc((100%-18rem-48rem-18rem-3rem)/2),0rem)]',
'page-full-width:lg:ml-[max(calc((100%-18rem-103rem-3rem)/2),1.5rem)]',
'page-full-width:2xl:ml-[max(calc((100%-18rem-96rem-14rem+3rem)/2),1.5rem)]',
'md:mr-auto',
'order-last',
'md:order-[unset]',
@@ -195,7 +193,6 @@ export function Header(props: { context: GitBookSiteContext; withTopHeader?: boo
<div
className={tcls(
CONTAINER_STYLE,
'page-default-width:max-w-[unset]',
'grow',
'flex',
'items-end',
4 changes: 1 addition & 3 deletions packages/gitbook/src/components/PageAside/PageAside.tsx
Original file line number Diff line number Diff line change
@@ -48,11 +48,9 @@ export function PageAside(props: {
'group/aside',
'hidden',
'xl:flex',
// 'page-no-toc:lg:flex',
'flex-col',
'basis-56',
// 'page-no-toc:basis-40',
// 'page-no-toc:xl:basis-56',
'xl:ml-12',
'grow-0',
'shrink-0',
'break-anywhere', // To prevent long words in headings from breaking the layout
16 changes: 7 additions & 9 deletions packages/gitbook/src/components/PageBody/PageBody.tsx
Original file line number Diff line number Diff line change
@@ -27,7 +27,9 @@ export function PageBody(props: {
const { page, context, ancestors, document, withPageFeedback } = props;
const { customization } = context;

const asFullWidth = document ? hasFullWidthBlock(document) : false;
const contentFullWidth = document ? hasFullWidthBlock(document) : false;
const pageFullWidth = page.id === 'wtthNFMqmEQmnt5LKR0q';
const asFullWidth = pageFullWidth || contentFullWidth;
const language = getSpaceLanguage(customization);
const updatedAt = page.updatedAt ?? page.createdAt;

@@ -36,15 +38,11 @@ export function PageBody(props: {
<main
className={tcls(
'relative min-w-0 flex-1',
'py-8 lg:px-12',
'mx-auto max-w-screen-2xl py-8',
// Allow words to break if they are too long.
'break-anywhere',
// When in api page mode without the aside, we align with the border of the main content
'page-api-block:xl:max-2xl:pr-0',
// Max size to ensure one column in api is aligned with rest of content (2 x 3xl) + (gap-3 + 2) * px-12
'page-api-block:mx-auto page-api-block:max-w-screen-2xl',
// page.layout.tableOfContents ? null : 'xl:ml-56',
asFullWidth ? 'page-full-width' : 'page-default-width',
pageFullWidth ? 'page-full-width 2xl:px-8' : 'page-default-width',
asFullWidth ? 'site-full-width' : 'site-default-width',
page.layout.tableOfContents ? 'page-has-toc' : 'page-no-toc'
)}
>
@@ -81,7 +79,7 @@ export function PageBody(props: {
<PageFooterNavigation context={context} page={page} />
) : null}

<div className="mx-auto mt-6 page-api-block:ml-0 flex max-w-3xl flex-row flex-wrap items-center gap-4 text-tint contrast-more:text-tint-strong">
<div className="mx-auto mt-6 page-api-block:ml-0 flex max-w-3xl page-full-width:max-w-screen-2xl flex-row flex-wrap items-center gap-4 text-tint contrast-more:text-tint-strong">
{updatedAt ? (
<p className="mr-auto text-sm">
{t(language, 'page_last_modified', <DateRelative value={updatedAt} />)}
14 changes: 10 additions & 4 deletions packages/gitbook/src/components/PageBody/PageCover.tsx
Original file line number Diff line number Diff line change
@@ -34,14 +34,20 @@ export async function PageCover(props: {
? [
'sm:-mx-6',
'md:-mx-8',
'-lg:mr-8',
'lg:ml-0',
'lg:-mr-8',
'lg:-ml-12',
!page.layout.tableOfContents &&
context.customization.header.preset !== 'none'
? 'xl:-ml-64'
? 'xl:-ml-[19rem]'
: null,
]
: ['sm:mx-auto', 'max-w-3xl', 'sm:rounded-md', 'mb-8']
: [
'sm:mx-auto',
'max-w-3xl ',
'page-full-width:max-w-screen-2xl',
'sm:rounded-md',
'mb-8',
]
)}
>
<Image
Original file line number Diff line number Diff line change
@@ -32,8 +32,8 @@ export async function PageFooterNavigation(props: {
'mt-6',
'gap-2',
'max-w-3xl',
'page-full-width:max-w-screen-2xl',
'mx-auto',
'page-api-block:ml-0',
'text-tint'
)}
>
9 changes: 8 additions & 1 deletion packages/gitbook/src/components/PageBody/PageHeader.tsx
Original file line number Diff line number Diff line change
@@ -23,7 +23,14 @@ export async function PageHeader(props: {

return (
<header
className={tcls('max-w-3xl', 'mx-auto', 'mb-6', 'space-y-3', 'page-api-block:ml-0')}
className={tcls(
'max-w-3xl',
'page-full-width:max-w-screen-2xl',
'mx-auto',
'mb-6',
'space-y-3',
'page-api-block:ml-0'
)}
>
{ancestors.length > 0 && (
<nav>
12 changes: 6 additions & 6 deletions packages/gitbook/src/components/PageBody/PreservePageLayout.tsx
Original file line number Diff line number Diff line change
@@ -3,12 +3,12 @@ import * as React from 'react';

/**
* This component preserves the layout of the page while loading a new one.
* This approach is needed as page layout (full width block) is done using CSS (`body:has(.page-full-width)`),
* This approach is needed as page layout (full width block) is done using CSS (`body:has(.full-width)`),
* which becomes false while transitioning between the 2 page states:
*
* 1. Page 1 with full width block: `body:has(.page-full-width)` is true
* 2. Loading skeleton while transitioning to page 2: `body:has(.page-full-width)` is false
* 3. Page 2 with full width block: `body:has(.page-full-width)` is true
* 1. Page 1 with full width block: `body:has(.site-full-width)` is true
* 2. Loading skeleton while transitioning to page 2: `body:has(.site-full-width)` is false
* 3. Page 2 with full width block: `body:has(.site-full-width)` is true
*
* This component ensures that the layout is preserved while transitioning between the 2 page states (in step 2).
*/
@@ -24,9 +24,9 @@ export function PreservePageLayout(props: { asFullWidth: boolean }) {
}

if (asFullWidth) {
header.classList.add('page-full-width');
header.classList.add('site-full-width');
} else {
header.classList.remove('page-full-width');
header.classList.remove('site-full-width');
}
}, [asFullWidth]);

4 changes: 0 additions & 4 deletions packages/gitbook/src/components/RootLayout/globals.css
Original file line number Diff line number Diff line change
@@ -143,10 +143,6 @@
margin-right: 0;
width: calc(100% - var(--scrollbar-width));
}
body:has(.page-full-width) .scroll-nojump {
margin-left: 0;
width: 100%;
}
}

.elevate-link {
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ export function SitePageSkeleton() {
'lg:items-start'
)}
>
<div className={tcls('flex-1', 'max-w-3xl', 'mx-auto', 'page-full-width:mx-0')}>
<div className={tcls('flex-1', 'max-w-3xl', 'mx-auto', 'site-full-width:mx-0')}>
<SkeletonHeading style={tcls('mb-8')} />
<SkeletonParagraph style={tcls('mb-4')} />
</div>
Original file line number Diff line number Diff line change
@@ -73,6 +73,7 @@ export function SpaceLayout(props: {
'flex-col',
'lg:flex-row',
CONTAINER_STYLE,
'site-full-width:max-w-full',

// Ensure the footer is display below the viewport even if the content is not enough
withFooter && 'min-h-[calc(100vh-64px)]',
Original file line number Diff line number Diff line change
@@ -35,6 +35,7 @@ export function TableOfContents(props: {
'relative',
'z-[1]',
'lg:sticky',
'lg:mr-12',

// Server-side static positioning
'lg:top-0',
2 changes: 1 addition & 1 deletion packages/gitbook/src/components/layout.ts
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ export const CONTAINER_STYLE: ClassValue = [
'md:px-8',
'max-w-screen-2xl',
'mx-auto',
'page-full-width:max-w-full',
// 'site-full-width:max-w-full',
];

/**
10 changes: 9 additions & 1 deletion packages/gitbook/tailwind.config.ts
Original file line number Diff line number Diff line change
@@ -447,6 +447,13 @@ const config: Config = {
},
},
opacity: opacity(),
screens: {
sm: '640px',
md: '768px',
lg: '1024px',
xl: '1280px',
'2xl': '1536px',
},
},
plugins: [
plugin(({ addVariant }) => {
@@ -514,8 +521,9 @@ const config: Config = {
/**
* Variant when the page contains a block that will be rendered in full-width mode.
*/
addVariant('site-full-width', 'body:has(.site-full-width) &');
addVariant('site-default-width', 'body:has(.site-default-width) &');
addVariant('page-full-width', 'body:has(.page-full-width) &');
addVariant('page-default-width', 'body:has(.page-default-width) &');

/**
* Variant when the page is configured to hide the table of content.
Loading
Oops, something went wrong.