diff --git a/packages/gitbook/src/components/PageBody/PageBody.tsx b/packages/gitbook/src/components/PageBody/PageBody.tsx
index 6f1e8bfca9..4072c7234e 100644
--- a/packages/gitbook/src/components/PageBody/PageBody.tsx
+++ b/packages/gitbook/src/components/PageBody/PageBody.tsx
@@ -17,6 +17,7 @@ import { PageCover } from './PageCover';
import { PageFooterNavigation } from './PageFooterNavigation';
import { PageHeader } from './PageHeader';
import { PreservePageLayout } from './PreservePageLayout';
+import { hasVisibleCover } from './coverHeight';
const LINK_PREVIEW_MAX_COUNT = 100;
@@ -32,6 +33,7 @@ export function PageBody(props: {
const { customization } = context;
const contentFullWidth = document ? hasFullWidthBlock(document) : false;
+ const visibleCover = hasVisibleCover(page.cover);
// Render link previews only if there are less than LINK_PREVIEW_MAX_COUNT links in the document.
const withLinkPreviews = document
@@ -60,7 +62,7 @@ export function PageBody(props: {
)}
>
- {page.cover && page.layout.cover && page.layout.coverSize === 'hero' ? (
+ {visibleCover && page.layout.cover && page.layout.coverSize === 'hero' ? (
) : null}
diff --git a/packages/gitbook/src/components/PageBody/PageCover.tsx b/packages/gitbook/src/components/PageBody/PageCover.tsx
index 0623310519..8a547103c5 100644
--- a/packages/gitbook/src/components/PageBody/PageCover.tsx
+++ b/packages/gitbook/src/components/PageBody/PageCover.tsx
@@ -8,6 +8,7 @@ import { tcls } from '@/lib/tailwind';
import { assert } from 'ts-essentials';
import { PageCoverImage } from './PageCoverImage';
+import { getCoverHeight } from './coverHeight';
import defaultPageCoverSVG from './default-page-cover.svg';
const defaultPageCover = defaultPageCoverSVG as StaticImageData;
@@ -22,6 +23,12 @@ export async function PageCover(props: {
context: GitBookSiteContext;
}) {
const { as, page, cover, context } = props;
+ const height = getCoverHeight(cover);
+
+ if (height <= 0) {
+ return null;
+ }
+
const [resolved, resolvedDark] = await Promise.all([
cover.ref ? resolveContentRef(cover.ref, context) : null,
cover.refDark ? resolveContentRef(cover.refDark, context) : null,
@@ -78,8 +85,10 @@ export async function PageCover(props: {
@@ -61,9 +60,8 @@ export function PageCoverImage({ imgs, y }: { imgs: Images; y: number }) {
sizes={imgs.dark.sizes}
fetchPriority="low"
alt="Page cover"
- className={tcls('w-full', 'object-cover', 'dark:inline', 'hidden')}
+ className={tcls('h-full', 'w-full', 'object-cover', 'dark:inline', 'hidden')}
style={{
- aspectRatio: `${PAGE_COVER_SIZE.width}/${PAGE_COVER_SIZE.height}`,
objectPosition: `50% ${getTop(container, y, imgs.dark)}`,
}}
/>
diff --git a/packages/gitbook/src/components/PageBody/coverHeight.ts b/packages/gitbook/src/components/PageBody/coverHeight.ts
new file mode 100644
index 0000000000..76ca3d7456
--- /dev/null
+++ b/packages/gitbook/src/components/PageBody/coverHeight.ts
@@ -0,0 +1,31 @@
+import type { RevisionPageDocumentCover } from '@gitbook/api';
+
+export const DEFAULT_COVER_HEIGHT = 240;
+export const MIN_COVER_HEIGHT = 10;
+export const MAX_COVER_HEIGHT = 700;
+
+type CoverWithHeight = RevisionPageDocumentCover & { height?: number | null };
+
+export function clampCoverHeight(value: number): number {
+ return Math.min(MAX_COVER_HEIGHT, Math.max(MIN_COVER_HEIGHT, value));
+}
+
+export function normalizeCoverHeight(height: number | null | undefined): number {
+ if (typeof height !== 'number' || Number.isNaN(height)) {
+ return DEFAULT_COVER_HEIGHT;
+ }
+
+ return clampCoverHeight(height);
+}
+
+export function getCoverHeight(cover: RevisionPageDocumentCover | null | undefined): number {
+ if (!cover) {
+ return 0;
+ }
+
+ return normalizeCoverHeight((cover as CoverWithHeight).height);
+}
+
+export function hasVisibleCover(cover: RevisionPageDocumentCover | null | undefined): boolean {
+ return getCoverHeight(cover) > 0;
+}
diff --git a/packages/gitbook/src/components/SitePage/SitePage.tsx b/packages/gitbook/src/components/SitePage/SitePage.tsx
index 4f0643ceec..74c2cc3d64 100644
--- a/packages/gitbook/src/components/SitePage/SitePage.tsx
+++ b/packages/gitbook/src/components/SitePage/SitePage.tsx
@@ -11,6 +11,7 @@ import React from 'react';
import { PageAside } from '@/components/PageAside';
import { PageBody, PageCover } from '@/components/PageBody';
+import { hasVisibleCover } from '@/components/PageBody/coverHeight';
import { getPagePath } from '@/lib/pages';
import { isPageIndexable, isSiteIndexable } from '@/lib/seo';
@@ -169,10 +170,9 @@ export async function getSitePageData(props: SitePageProps) {
const { page, ancestors } = pageTarget;
const withTopHeader = customization.header.preset !== CustomizationHeaderPreset.None;
- const withFullPageCover = !!(
- page.cover &&
- page.layout.cover &&
- page.layout.coverSize === 'full'
+ const visibleCover = hasVisibleCover(page.cover);
+ const withFullPageCover = Boolean(
+ visibleCover && page.layout.cover && page.layout.coverSize === 'full'
);
const withPageFeedback = customization.feedback.enabled;