Skip to content

Commit 7af7d46

Browse files
committed
Revert 'only allow resizing for non-hero'
1 parent 9cd0359 commit 7af7d46

File tree

4 files changed

+102
-33
lines changed

4 files changed

+102
-33
lines changed

packages/gitbook/src/components/PageBody/PageCover.tsx

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,8 @@ export async function PageCover(props: {
2222
cover: RevisionPageDocumentCover;
2323
context: GitBookSiteContext;
2424
}) {
25-
const { as: coverType, page, cover, context } = props;
26-
27-
const height = getCoverHeight(cover, coverType);
25+
const { as, page, cover, context } = props;
26+
const height = getCoverHeight(cover);
2827

2928
if (!height) {
3029
return null;
@@ -35,18 +34,25 @@ export async function PageCover(props: {
3534
cover.refDark ? resolveContentRef(cover.refDark, context) : null,
3635
]);
3736

37+
// Calculate sizes based on cover type and page layout
38+
// Hero covers: max-w-3xl (768px) on regular pages, max-w-screen-2xl (1536px) on wide pages
39+
// Full covers: Can expand to full viewport width with negative margins (up to ~1920px+ on large screens)
40+
const isWidePage = page.layout.width === 'wide';
41+
const maxWidth = as === 'full' ? 1920 : isWidePage ? 1536 : 768;
42+
3843
const sizes = [
39-
// Cover takes the full width on mobile/table
44+
// Cover takes the full width on mobile
4045
{
4146
media: '(max-width: 768px)',
4247
width: 768,
4348
},
49+
// Tablet sizes
4450
{
4551
media: '(max-width: 1024px)',
4652
width: 1024,
4753
},
48-
// Maximum size of the cover
49-
{ width: 1248 },
54+
// Maximum size based on cover type and page layout
55+
{ width: maxWidth },
5056
];
5157

5258
const getImage = async (resolved: ResolvedContentRef | null, returnNull = false) => {
@@ -85,12 +91,12 @@ export async function PageCover(props: {
8591
return (
8692
<div
8793
id="page-cover"
88-
data-full={String(coverType === 'full')}
94+
data-full={String(as === 'full')}
8995
className={tcls(
9096
'overflow-hidden',
9197
// Negative margin to balance the container padding
9298
'-mx-4',
93-
coverType === 'full'
99+
as === 'full'
94100
? [
95101
'sm:-mx-6',
96102
'md:-mx-8',
@@ -117,7 +123,6 @@ export async function PageCover(props: {
117123
}}
118124
y={cover.yPos}
119125
height={height}
120-
coverType={coverType}
121126
/>
122127
</div>
123128
);

packages/gitbook/src/components/PageBody/PageCoverImage.tsx

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use client';
22
import { tcls } from '@/lib/tailwind';
33
import type { ImageSize } from '../utils';
4+
import { getRecommendedCoverDimensions } from './coverDimensions';
45
import { useCoverPosition } from './useCoverPosition';
56

67
interface ImageAttributes {
@@ -17,16 +18,15 @@ interface Images {
1718
dark?: ImageAttributes;
1819
}
1920

20-
const PAGE_COVER_SIZE: ImageSize = { width: 1990, height: 480 };
21-
22-
export function PageCoverImage({
23-
imgs,
24-
y,
25-
height,
26-
coverType,
27-
}: { imgs: Images; y: number; height: number; coverType: 'hero' | 'full' }) {
21+
export function PageCoverImage({ imgs, y, height }: { imgs: Images; y: number; height: number }) {
2822
const { containerRef, objectPositionY, isLoading } = useCoverPosition(imgs, y);
2923

24+
// Calculate the recommended aspect ratio for this height
25+
// This maintains the 4:1 ratio, allowing images to scale proportionally
26+
// and adapt their height when container width doesn't match the ideal ratio
27+
const recommendedDimensions = getRecommendedCoverDimensions(height);
28+
const aspectRatio = recommendedDimensions.width / recommendedDimensions.height;
29+
3030
if (isLoading) {
3131
return (
3232
<div className="h-full w-full overflow-hidden" ref={containerRef}>
@@ -36,23 +36,17 @@ export function PageCoverImage({
3636
}
3737

3838
return (
39-
<div className="h-full w-full overflow-hidden" ref={containerRef}>
39+
<div className="h-full w-full overflow-hidden" ref={containerRef} style={{ height }}>
4040
<img
4141
src={imgs.light.src}
4242
srcSet={imgs.light.srcSet}
4343
sizes={imgs.light.sizes}
4444
fetchPriority="high"
4545
alt="Page cover"
46-
className={tcls(
47-
'w-full',
48-
coverType === 'hero' ? 'object-contain' : 'object-cover',
49-
imgs.dark ? 'dark:hidden' : ''
50-
)}
46+
className={tcls('w-full', 'object-cover', imgs.dark ? 'dark:hidden' : '')}
5147
style={{
52-
aspectRatio:
53-
coverType === 'hero' ? `${height}/${PAGE_COVER_SIZE.height}` : undefined,
48+
aspectRatio: `${aspectRatio}`,
5449
objectPosition: `50% ${objectPositionY}%`,
55-
height: coverType === 'full' ? `${height}px` : undefined,
5650
}}
5751
/>
5852
{imgs.dark && (
@@ -64,7 +58,7 @@ export function PageCoverImage({
6458
alt="Page cover"
6559
className={tcls('w-full', 'object-cover', 'dark:inline', 'hidden')}
6660
style={{
67-
aspectRatio: `${PAGE_COVER_SIZE.width}/${PAGE_COVER_SIZE.height}`,
61+
aspectRatio: `${aspectRatio}`,
6862
objectPosition: `50% ${objectPositionY}%`,
6963
}}
7064
/>
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/**
2+
* Calculates the ideal cover image dimensions based on the cover type,
3+
* page layout, and viewport constraints.
4+
*
5+
* The dimensions are optimized for:
6+
* - Hero covers: max-w-3xl (768px) on regular pages, max-w-screen-2xl (1536px) on wide pages
7+
* - Full covers: Can expand to full viewport width with negative margins (up to ~1920px+ on large screens)
8+
* - Responsive sizes: 768px (mobile), 1024px (tablet), up to 1920px+ (large desktop)
9+
*
10+
* The recommended aspect ratio is optimized to work well across all these scenarios.
11+
*/
12+
13+
export const DEFAULT_COVER_HEIGHT = 240;
14+
15+
/**
16+
* Calculate recommended cover image dimensions based on actual rendering widths.
17+
*
18+
* Analysis of actual rendering widths:
19+
* - Hero, regular page: max-w-3xl = 768px
20+
* - Hero, wide page: max-w-screen-2xl = 1536px
21+
* - Full cover (mobile): ~768px (full viewport minus padding)
22+
* - Full cover (tablet): ~1024px (full viewport minus padding)
23+
* - Full cover (desktop): Can be 768px (hero regular) to ~1920px (full wide) on large screens
24+
*
25+
* The recommended aspect ratio (4:1) is a standard format that works well for:
26+
* - Default height of 240px → 960px width (close to tablet size of 1024px)
27+
* - Works well when cropped to 768px (hero regular), 1024px (tablet), 1536px (hero wide), and 1920px (full wide)
28+
* - With `object-cover`, images maintain their natural aspect ratio while filling the container,
29+
* so the 4:1 ratio provides good coverage across all scenarios
30+
*
31+
* This ratio ensures images look good across all scenarios (hero/full, regular/wide, all viewports)
32+
* while maintaining good image quality for responsive srcSet generation and being easy to remember.
33+
*
34+
* @param height - The cover height in pixels (default: 240)
35+
* @returns Recommended width and height for the cover image
36+
*/
37+
export function getRecommendedCoverDimensions(height: number = DEFAULT_COVER_HEIGHT): {
38+
width: number;
39+
height: number;
40+
} {
41+
// Standard 4:1 aspect ratio - a common and easy-to-work-with format
42+
// At 240px height: 960px width
43+
// This ratio works well for:
44+
// - Hero covers on regular pages (768px width) - image will scale to cover
45+
// - Hero covers on wide pages (1536px width) - image will scale to cover
46+
// - Full covers across all breakpoints (768px - 1920px+) - image will scale proportionally
47+
//
48+
// Since we use `object-cover`, the image will scale to fill the container while maintaining
49+
// its aspect ratio, so the 4:1 ratio provides excellent coverage across all scenarios.
50+
//
51+
// Examples for different heights:
52+
// - 240px height → 960px width (recommended for default)
53+
// - 400px height → 1600px width (recommended for taller covers)
54+
// - 500px height → 2000px width (recommended for very tall covers)
55+
const aspectRatio = 4;
56+
57+
return {
58+
width: Math.round(height * aspectRatio),
59+
height,
60+
};
61+
}
62+
63+
/**
64+
* Get the maximum cover width based on cover type and page layout.
65+
* Used for determining the upper bound of image dimensions.
66+
*/
67+
export function getMaxCoverWidth(coverType: 'hero' | 'full', isWidePage: boolean): number {
68+
if (coverType === 'hero') {
69+
// Hero covers: max-w-3xl (768px) or max-w-screen-2xl (1536px)
70+
return isWidePage ? 1536 : 768;
71+
}
72+
// Full covers can expand to viewport width, typically up to 1920px on large screens
73+
// Accounting for some margins, we use 1920px as the maximum
74+
return 1920;
75+
}

packages/gitbook/src/components/PageBody/coverHeight.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,12 @@ function clampCoverHeight(height: number | null | undefined): number {
1414
}
1515

1616
export function getCoverHeight(
17-
cover: RevisionPageDocumentCover | null | undefined,
18-
as: 'hero' | 'full'
17+
cover: RevisionPageDocumentCover | null | undefined
1918
): number | undefined {
2019
// Cover (and thus height) is not defined
2120
if (!cover) {
2221
return undefined;
2322
}
2423

25-
if (as === 'hero') {
26-
return DEFAULT_COVER_HEIGHT;
27-
}
28-
2924
return clampCoverHeight((cover as RevisionPageDocumentCover).height ?? DEFAULT_COVER_HEIGHT);
3025
}

0 commit comments

Comments
 (0)