diff --git a/.changeset/metal-ghosts-move.md b/.changeset/metal-ghosts-move.md new file mode 100644 index 0000000000..4707c7d988 --- /dev/null +++ b/.changeset/metal-ghosts-move.md @@ -0,0 +1,5 @@ +--- +"gitbook": minor +--- + +Rework page layout diff --git a/packages/gitbook/e2e/internal.spec.ts b/packages/gitbook/e2e/internal.spec.ts index 0b1f5ac8f0..d8ea413bc4 100644 --- a/packages/gitbook/e2e/internal.spec.ts +++ b/packages/gitbook/e2e/internal.spec.ts @@ -781,7 +781,9 @@ const testCases: TestsCase[] = [ run: async (page) => { await expect(page.locator('[data-testid="table-of-contents"]')).toBeVisible(); // Trademark exists by default - await expect(page.getByTestId('gb-trademark')).toHaveCount(1); + expect(await page.getByTestId('gb-trademark').count()).toBeGreaterThanOrEqual( + 1 + ); // Go to another page with the customization query to disable the trademark const pageBlocks = new URL(page.url()); diff --git a/packages/gitbook/src/components/DocumentView/Blocks.tsx b/packages/gitbook/src/components/DocumentView/Blocks.tsx index fcd6b292ee..5868156390 100644 --- a/packages/gitbook/src/components/DocumentView/Blocks.tsx +++ b/packages/gitbook/src/components/DocumentView/Blocks.tsx @@ -2,6 +2,7 @@ import type { DocumentBlock, JSONDocument } from '@gitbook/api'; import { type ClassValue, tcls } from '@/lib/tailwind'; +import { CONTENT_STYLE, CONTENT_STYLE_REDUCED } from '../layout'; import { Block } from './Block'; import type { DocumentContextProps } from './DocumentView'; import { isBlockOffscreen } from './utils'; @@ -63,7 +64,7 @@ const FULL_WIDTH_BLOCKS: DocumentBlock['type'][] = [ 'columns', 'code', 'content-ref', - 'hint', + 'divider', ]; const LIST_BLOCKS: DocumentBlock['type'][] = ['list-ordered', 'list-tasks', 'list-unordered']; @@ -89,12 +90,10 @@ export function UnwrappedBlocks(props: UnwrappedBl key={node.key || `${node.type}-${index}`} block={node} style={[ - 'mx-auto page-width-wide:mx-0 w-full decoration-primary/6', - node.data && 'fullWidth' in node.data && node.data.fullWidth - ? 'max-w-screen-xl' - : 'max-w-3xl', + 'decoration-primary/6', + FULL_WIDTH_BLOCKS.includes(node.type) ? CONTENT_STYLE : CONTENT_STYLE_REDUCED, + !LIST_BLOCKS.includes(node.type) && 'print:break-inside-avoid', - FULL_WIDTH_BLOCKS.includes(node.type) && 'page-width-wide:max-w-full', blockStyle, ]} isEstimatedOffscreen={isOffscreen} diff --git a/packages/gitbook/src/components/DocumentView/Divider.tsx b/packages/gitbook/src/components/DocumentView/Divider.tsx index 15302df475..8f18593e2f 100644 --- a/packages/gitbook/src/components/DocumentView/Divider.tsx +++ b/packages/gitbook/src/components/DocumentView/Divider.tsx @@ -7,5 +7,5 @@ import type { BlockProps } from './Block'; export function Divider(props: BlockProps) { const { style } = props; - return
; + return
; } diff --git a/packages/gitbook/src/components/DocumentView/DocumentView.tsx b/packages/gitbook/src/components/DocumentView/DocumentView.tsx index 152bd6f78e..9d5f45eacc 100644 --- a/packages/gitbook/src/components/DocumentView/DocumentView.tsx +++ b/packages/gitbook/src/components/DocumentView/DocumentView.tsx @@ -93,7 +93,7 @@ export function DocumentViewSkeleton(props: { document: JSONDocument; blockStyle style={[ 'mx-auto w-full decoration-primary/6', block.data && 'fullWidth' in block.data && block.data.fullWidth - ? 'max-w-screen-xl' + ? 'max-w-6xl' : 'max-w-3xl', blockStyle, ]} diff --git a/packages/gitbook/src/components/DocumentView/StepperStep.tsx b/packages/gitbook/src/components/DocumentView/StepperStep.tsx index c2cc62e988..1abdfe9170 100644 --- a/packages/gitbook/src/components/DocumentView/StepperStep.tsx +++ b/packages/gitbook/src/components/DocumentView/StepperStep.tsx @@ -32,7 +32,7 @@ export function StepperStep(props: BlockProps) { })(); return ( -
+
- + 1 ? 'has-sidebar' : 'no-sidebar'} + >
- + {context.site.title} @@ -105,6 +108,7 @@ export async function EmbeddableDocsPage( trailing={{ fade: false, button: true }} > ) { - const { children, ...rest } = props; +export function EmbeddableFrameMain( + props: React.ComponentProps<'div'> & { className?: ClassValue } +) { + const { children, className, ...rest } = props; return ( -
+
{children}
); diff --git a/packages/gitbook/src/components/Footer/Footer.tsx b/packages/gitbook/src/components/Footer/Footer.tsx index d305ef2221..ef848a690c 100644 --- a/packages/gitbook/src/components/Footer/Footer.tsx +++ b/packages/gitbook/src/components/Footer/Footer.tsx @@ -6,7 +6,7 @@ import { partition } from '@/lib/arrays'; import { tcls } from '@/lib/tailwind'; import { ThemeToggler } from '../ThemeToggler'; -import { CONTAINER_STYLE } from '../layout'; +import { CONTAINER_STYLE, CONTENT_STYLE } from '../layout'; import { FooterLinksGroup } from './FooterLinksGroup'; import { SocialAccountButton } from './SocialAccounts'; @@ -48,16 +48,11 @@ export function Footer(props: { context: GitBookSiteContext }) { >
{ @@ -113,12 +108,8 @@ export function Footer(props: { context: GitBookSiteContext }) { { // Navigation groups (split into equal columns) customization.footer.groups?.length > 0 ? ( -
-
+
+
{partition(customization.footer.groups, FOOTER_COLUMNS).map( (column, columnIndex) => (
1 ? 'lg:hidden' - : 'page-no-toc:hidden lg:hidden' + : 'no-sidebar:hidden lg:hidden' )} /> diff --git a/packages/gitbook/src/components/PageAside/PageAside.tsx b/packages/gitbook/src/components/PageAside/PageAside.tsx index a69a2e56e5..f39f5a925f 100644 --- a/packages/gitbook/src/components/PageAside/PageAside.tsx +++ b/packages/gitbook/src/components/PageAside/PageAside.tsx @@ -1,20 +1,21 @@ +import { getSpaceLanguage, t } from '@/intl/server'; import type { GitBookSiteContext } from '@/lib/context'; +import { getDocumentSections } from '@/lib/document-sections'; +import { tcls } from '@/lib/tailwind'; import { type JSONDocument, type RevisionPageDocument, SiteAdsStatus, SiteInsightsAdPlacement, } from '@gitbook/api'; -import { Icon } from '@gitbook/icons'; import React from 'react'; -import { getSpaceLanguage, t } from '@/intl/server'; -import { getDocumentSections } from '@/lib/document-sections'; -import { tcls } from '@/lib/tailwind'; - +import { Icon } from '@gitbook/icons'; import { Ad } from '../Ads'; import { PageFeedbackForm } from '../PageFeedback'; import { ThemeToggler } from '../ThemeToggler'; +import { SideSheet } from '../primitives/SideSheet'; +import { PageAsideCloseButton } from './PageAsideButton'; import { ScrollSectionsList } from './ScrollSectionsList'; /** @@ -30,46 +31,20 @@ export function PageAside(props: { }) { const { page, document, withPageFeedback, context } = props; const { customization, site } = context; + const language = getSpaceLanguage(context); return ( - - ); -} - -function PageAsideHeader(props: { context: GitBookSiteContext }) { - const { context } = props; - const language = getSpaceLanguage(context); - - return ( -
- - {t(language, 'on_this_page')} - -
+ ); } @@ -170,7 +133,7 @@ async function PageAsideSections(props: { document: JSONDocument; context: GitBo const sections = await getDocumentSections(context, document); return sections.length > 1 ? ( -
+
) : null; @@ -187,7 +150,7 @@ function PageAsideActions(props: { className={tcls( 'flex flex-col gap-3', 'border-tint-subtle border-t first:border-none', - 'sidebar-list-default:px-3 pt-5 first:pt-0 xl:max-2xl:page-api-block:p-5', + 'sidebar-list-default:px-3 pt-5 first:pt-0', 'empty:hidden' )} > @@ -208,8 +171,7 @@ async function PageAsideFooter(props: { context: GitBookSiteContext }) {
diff --git a/packages/gitbook/src/components/PageAside/PageAsideButton.tsx b/packages/gitbook/src/components/PageAside/PageAsideButton.tsx new file mode 100644 index 0000000000..9a0ad6e5e8 --- /dev/null +++ b/packages/gitbook/src/components/PageAside/PageAsideButton.tsx @@ -0,0 +1,59 @@ +'use client'; +import { useLanguage } from '@/intl/client'; +import { tString } from '@/intl/translate'; +import { usePathname } from 'next/navigation'; +import { useEffect } from 'react'; +import { Button } from '../primitives'; + +const globalClassName = 'outline-open'; + +export function PageAsideToggleButton() { + const language = useLanguage(); + + const pathname = usePathname(); + + // Close the navigation when navigating to a page + useEffect(() => { + document.body.classList.remove(globalClassName); + }, [pathname]); + + return ( + <> +