Skip to content

Commit 1d92dc1

Browse files
authored
Update site layout and blocks with container queries (#3780)
1 parent e4ba35f commit 1d92dc1

File tree

20 files changed

+212
-149
lines changed

20 files changed

+212
-149
lines changed

.changeset/sour-cobras-grab.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"gitbook": minor
3+
---
4+
5+
Update site layout and blocks with container queries and better transitions

packages/gitbook/src/components/AIChat/AIChat.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { t, tString, useLanguage } from '@/intl/client';
44
import type { TranslationLanguage } from '@/intl/translations';
5+
import { tcls } from '@/lib/tailwind';
56
import { Icon } from '@gitbook/icons';
67
import React from 'react';
78
import { useHotkeys } from 'react-hotkeys-hook';
@@ -65,16 +66,17 @@ export function AIChat(props: { trademark: boolean }) {
6566
}
6667
}, [chat.opened, trackEvent]);
6768

68-
if (!chat.opened) {
69-
return null;
70-
}
71-
7269
return (
7370
<div
7471
data-testid="ai-chat"
75-
className="ai-chat inset-y-0 right-0 z-40 mx-auto flex max-w-3xl animate-present scroll-mt-36 px-4 py-4 transition-all duration-300 sm:px-6 lg:fixed lg:w-80 lg:animate-enter-from-right lg:pr-4 lg:pl-0 xl:w-96"
72+
className={tcls(
73+
'ai-chat inset-y-0 right-0 z-40 mx-auto flex max-w-3xl scroll-mt-36 px-4 py-4 transition-[width,opacity,margin,display] transition-discrete duration-300 sm:px-6 lg:fixed lg:w-80 lg:pr-4 lg:pl-0 xl:w-96',
74+
chat.opened
75+
? 'lg:starting:ml-0 lg:starting:w-0 lg:starting:opacity-0'
76+
: 'hidden lg:ml-0 lg:w-0! lg:opacity-0'
77+
)}
7678
>
77-
<EmbeddableFrame className="relative circular-corners:rounded-3xl rounded-corners:rounded-md depth-subtle:shadow-lg shadow-tint ring-1 ring-tint-subtle">
79+
<EmbeddableFrame className="relative shrink-0 circular-corners:rounded-3xl rounded-corners:rounded-md border border-tint-subtle depth-subtle:shadow-lg shadow-tint transition-all duration-300 lg:w-76 xl:w-92">
7880
<EmbeddableFrameHeader>
7981
<AIChatDynamicIcon trademark={trademark} />
8082
<EmbeddableFrameHeaderMain>

packages/gitbook/src/components/AIChat/AIChatButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export function AIChatButton(props: {
2323
iconOnly={!showLabel}
2424
size="medium"
2525
variant="header"
26-
className="h-9 px-2.5 max-md:[&_.button-content]:hidden"
26+
className="h-9 px-2.5 @max-2xl:[&_.button-content]:hidden"
2727
label={
2828
<div className="flex items-center gap-2">
2929
{t(language, 'ai_chat_ask', assistant.label)}

packages/gitbook/src/components/DocumentView/Columns/Columns.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export function Column(props: {
8080
<div
8181
className={tcls(
8282
'flex flex-col',
83+
'@container/column',
8384
(verticalAlignment === VerticalAlignment.Top || !verticalAlignment) &&
8485
'justify-start',
8586
verticalAlignment === VerticalAlignment.Middle && 'justify-center',

packages/gitbook/src/components/DocumentView/Table/RecordCard.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export async function RecordCard(
6060
'overflow-hidden',
6161
'[&_.heading>div:first-child]:hidden',
6262
'[&_.heading>div]:text-[.8em]',
63-
'md:[&_.heading>div]:text-[1em]',
63+
'@xl:[&_.heading>div]:text-[1em]',
6464
'[&_.blocks:first-child_.heading]:pt-0', // Remove padding-top on first heading in card
6565

6666
// On mobile, check if we can display the cover responsively or not:
@@ -69,10 +69,10 @@ export async function RecordCard(
6969
lightCoverIsSquareOrPortrait || darkCoverIsSquareOrPortrait
7070
? [
7171
lightCoverIsSquareOrPortrait
72-
? 'grid-cols-[40%__1fr] min-[432px]:grid-cols-none min-[432px]:grid-rows-[auto_1fr]'
72+
? '@sm:grid-cols-none grid-cols-[40%__1fr] @sm:grid-rows-[auto_1fr]'
7373
: '',
7474
darkCoverIsSquareOrPortrait
75-
? 'dark:grid-cols-[40%__1fr] dark:min-[432px]:grid-cols-none dark:min-[432px]:grid-rows-[auto_1fr]'
75+
? 'dark:@sm:grid-cols-none dark:grid-cols-[40%__1fr] dark:@sm:grid-rows-[auto_1fr]'
7676
: '',
7777
].filter(Boolean)
7878
: 'grid-rows-[auto_1fr]'
@@ -112,11 +112,9 @@ export async function RecordCard(
112112
'bg-tint-subtle',
113113
lightCoverIsSquareOrPortrait || darkCoverIsSquareOrPortrait
114114
? [
115-
lightCoverIsSquareOrPortrait
116-
? 'min-[432px]:aspect-video min-[432px]:h-auto'
117-
: '',
115+
lightCoverIsSquareOrPortrait ? '@sm:aspect-video @sm:h-auto' : '',
118116
darkCoverIsSquareOrPortrait
119-
? 'dark:min-[432px]:aspect-video dark:min-[432px]:h-auto'
117+
? 'dark:@sm:aspect-video dark:@sm:h-auto'
120118
: '',
121119
].filter(Boolean)
122120
: ['h-auto', 'aspect-video'],

packages/gitbook/src/components/DocumentView/Table/ViewCards.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ export function ViewCards(props: TableViewProps<DocumentTableViewCards>) {
1515
'inline-grid',
1616
'gap-4',
1717
'grid-cols-1',
18-
'min-[432px]:grid-cols-2',
19-
view.cardSize === 'large' ? 'md:grid-cols-2' : 'md:grid-cols-3',
18+
'@sm:grid-cols-2',
19+
view.cardSize === 'large' ? '@xl:grid-cols-2' : '@xl:grid-cols-3',
2020
block.data.fullWidth ? 'large:flex-column' : null
2121
)}
2222
>

packages/gitbook/src/components/DocumentView/spacing.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,19 @@ export function getBlockTextStyle(block: DocumentBlock): {
1919
};
2020
case 'heading-1':
2121
return {
22-
textSize: 'text-3xl font-semibold',
22+
textSize: 'text-xl @xs:text-2xl @lg:text-3xl font-semibold',
2323
lineHeight: 'leading-tight',
2424
marginTop: 'column-first-of-type:pt-0 pt-[1em]',
2525
};
2626
case 'heading-2':
2727
return {
28-
textSize: 'text-2xl font-semibold',
28+
textSize: 'text-lg @xs:text-xl @lg:text-2xl font-semibold',
2929
lineHeight: 'leading-snug',
3030
marginTop: 'column-first-of-type:pt-0 pt-[0.75em]',
3131
};
3232
case 'heading-3':
3333
return {
34-
textSize: 'text-xl font-semibold',
34+
textSize: 'text-base @xs:text-lg @lg:text-xl font-semibold',
3535
lineHeight: 'leading-snug',
3636
marginTop: 'column-first-of-type:pt-0 pt-[0.5em]',
3737
};

packages/gitbook/src/components/Embeddable/EmbeddableFrame.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export const EmbeddableFrame = React.forwardRef<HTMLDivElement, EmbeddableFrameP
1717
<div
1818
{...divProps}
1919
className={tcls(
20-
'flex h-full grow animate-fade-in-slow flex-col overflow-hidden bg-tint-base text-sm text-tint',
20+
'flex h-full grow flex-col overflow-hidden bg-tint-base text-sm text-tint',
2121
divProps.className
2222
)}
2323
ref={ref}

packages/gitbook/src/components/Footer/Footer.tsx

Lines changed: 106 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -29,112 +29,123 @@ export function Footer(props: { context: GitBookSiteContext }) {
2929
className={tcls(
3030
'border-tint-subtle border-t',
3131
// If the footer only contains a mode toggle, we only show it on smaller screens
32-
mobileOnly ? 'xl:hidden' : null
32+
mobileOnly ? '@7xl:hidden' : null
3333
)}
3434
>
35-
<div className={tcls(CONTAINER_STYLE, 'px-4', 'py-8', 'lg:py-12', 'mx-auto')}>
35+
<div className="motion-safe:transition-[padding] motion-safe:duration-300 lg:chat-open:pr-80 xl:chat-open:pr-96">
3636
<div
3737
className={tcls(
38-
'mx-auto grid max-w-3xl site-width-wide:max-w-screen-2xl justify-between gap-12 lg:max-w-none!',
39-
'grid-cols-[auto_auto]',
40-
'lg:grid-cols-[18rem_minmax(auto,48rem)_auto]',
41-
'xl:grid-cols-[18rem_minmax(auto,48rem)_14rem]',
42-
'lg:site-width-wide:grid-cols-[18rem_minmax(auto,80rem)_auto]',
43-
'xl:site-width-wide:grid-cols-[18rem_minmax(auto,80rem)_14rem]',
44-
'lg:page-no-toc:grid-cols-[minmax(auto,48rem)_auto]',
45-
'xl:page-no-toc:grid-cols-[14rem_minmax(auto,48rem)_14rem]',
46-
'lg:[body:has(.site-width-wide,.page-no-toc)_&]:grid-cols-[minmax(auto,90rem)_auto]',
47-
'xl:[body:has(.site-width-wide,.page-no-toc)_&]:grid-cols-[14rem_minmax(auto,90rem)_14rem]'
38+
CONTAINER_STYLE,
39+
'px-4',
40+
'py-8',
41+
'@4xl:py-12',
42+
'mx-auto',
43+
'@container/footer'
4844
)}
4945
>
50-
{
51-
// Footer Logo
52-
customization.footer.logo ? (
53-
<div className="col-start-1 row-start-1">
54-
<Image
55-
alt="Logo"
56-
resize={context.imageResizer}
57-
sources={{
58-
light: {
59-
src: customization.footer.logo.light,
60-
},
61-
dark: customization.footer.logo.dark
62-
? {
63-
src: customization.footer.logo.dark,
64-
}
65-
: null,
66-
}}
67-
loading="lazy"
68-
style={[
69-
'w-auto',
70-
'max-w-40',
71-
'lg:max-w-64',
72-
'max-h-10',
73-
'lg:max-h-12',
74-
'object-contain',
75-
'object-left',
76-
'rounded-sm',
77-
'straight-corners:rounded-xs',
78-
]}
79-
sizes={[
80-
{
81-
width: 320,
82-
},
83-
]}
84-
/>
85-
</div>
86-
) : null
87-
}
46+
<div
47+
className={tcls(
48+
'mx-auto flex @xs:grid @4xl:max-w-none! max-w-3xl site-width-wide:max-w-screen-2xl flex-col justify-between gap-12',
49+
'grid-cols-[auto_auto]',
50+
'@4xl:grid-cols-[18rem_minmax(auto,48rem)_auto]',
51+
'@7xl:grid-cols-[18rem_minmax(auto,48rem)_14rem]',
52+
'@4xl:site-width-wide:grid-cols-[18rem_minmax(auto,80rem)_auto]',
53+
'@7xl:site-width-wide:grid-cols-[18rem_minmax(auto,80rem)_14rem]',
54+
'@4xl:page-no-toc:grid-cols-[minmax(auto,48rem)_auto]',
55+
'@7xl:page-no-toc:grid-cols-[14rem_minmax(auto,48rem)_14rem]',
56+
'@4xl:[body:has(.site-width-wide,.page-no-toc)_&]:grid-cols-[minmax(auto,90rem)_auto]',
57+
'@7xl:[body:has(.site-width-wide,.page-no-toc)_&]:grid-cols-[14rem_minmax(auto,90rem)_14rem]'
58+
)}
59+
>
60+
{
61+
// Footer Logo
62+
customization.footer.logo ? (
63+
<div className="col-start-1 row-start-1">
64+
<Image
65+
alt="Logo"
66+
resize={context.imageResizer}
67+
sources={{
68+
light: {
69+
src: customization.footer.logo.light,
70+
},
71+
dark: customization.footer.logo.dark
72+
? {
73+
src: customization.footer.logo.dark,
74+
}
75+
: null,
76+
}}
77+
loading="lazy"
78+
style={[
79+
'w-auto',
80+
'max-w-40',
81+
'@4xl:max-w-64',
82+
'max-h-10',
83+
'@4xl:max-h-12',
84+
'object-contain',
85+
'object-left',
86+
'rounded-sm',
87+
'straight-corners:rounded-xs',
88+
]}
89+
sizes={[
90+
{
91+
width: 320,
92+
},
93+
]}
94+
/>
95+
</div>
96+
) : null
97+
}
8898

89-
{
90-
// Theme Toggle
91-
customization.themes.toggeable ? (
92-
<div className="-col-start-2 row-start-1 flex items-start justify-end xl:hidden">
93-
<React.Suspense fallback={null}>
94-
<ThemeToggler />
95-
</React.Suspense>
96-
</div>
97-
) : null
98-
}
99+
{
100+
// Theme Toggle
101+
customization.themes.toggeable ? (
102+
<div className="-col-start-2 row-start-1 flex items-start @xs:justify-end xl:hidden">
103+
<React.Suspense fallback={null}>
104+
<ThemeToggler />
105+
</React.Suspense>
106+
</div>
107+
) : null
108+
}
99109

100-
{
101-
// Navigation groups (split into equal columns)
102-
customization.footer.groups?.length > 0 ? (
103-
<div
104-
className={tcls(
105-
'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'
106-
)}
107-
>
108-
<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">
109-
{partition(customization.footer.groups, FOOTER_COLUMNS).map(
110-
(column, columnIndex) => (
111-
<div
112-
key={columnIndex}
113-
className="flex flex-1 grow flex-col gap-10"
114-
>
115-
{column.map((group, groupIndex) => (
116-
<FooterLinksGroup
117-
key={groupIndex}
118-
group={group}
119-
context={context}
120-
/>
121-
))}
122-
</div>
123-
)
110+
{
111+
// Navigation groups (split into equal columns)
112+
customization.footer.groups?.length > 0 ? (
113+
<div
114+
className={tcls(
115+
'@4xl:page-has-toc:col-span-1 @7xl:page-no-toc:col-span-1 col-span-2 @4xl:page-has-toc:col-start-2 @7xl:page-no-toc:col-start-2'
124116
)}
117+
>
118+
<div className="mx-auto flex max-w-3xl site-width-wide:max-w-screen-2xl @xl:flex-row flex-col @xl:gap-6 gap-10">
119+
{partition(customization.footer.groups, FOOTER_COLUMNS).map(
120+
(column, columnIndex) => (
121+
<div
122+
key={columnIndex}
123+
className="flex flex-1 grow flex-col gap-10"
124+
>
125+
{column.map((group, groupIndex) => (
126+
<FooterLinksGroup
127+
key={groupIndex}
128+
group={group}
129+
context={context}
130+
/>
131+
))}
132+
</div>
133+
)
134+
)}
135+
</div>
125136
</div>
126-
</div>
127-
) : null
128-
}
137+
) : null
138+
}
129139

130-
{
131-
// Legal
132-
customization.footer.copyright ? (
133-
<div className="order-last col-span-full flex w-full grow flex-col items-center gap-2 text-center text-tint text-xs">
134-
<p>{customization.footer.copyright}</p>
135-
</div>
136-
) : null
137-
}
140+
{
141+
// Legal
142+
customization.footer.copyright ? (
143+
<div className="order-last col-span-full flex w-full grow flex-col items-center gap-2 text-center text-tint text-xs">
144+
<p>{customization.footer.copyright}</p>
145+
</div>
146+
) : null
147+
}
148+
</div>
138149
</div>
139150
</div>
140151
</footer>

0 commit comments

Comments
 (0)