Skip to content

Commit d6c28a0

Browse files
authored
Update header styling of sections, variant selector, and button links (#2543)
1 parent a7af3ca commit d6c28a0

File tree

9 files changed

+101
-65
lines changed

9 files changed

+101
-65
lines changed

.changeset/young-mails-itch.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
'gitbook': patch
3+
---
4+
5+
Update header styling of sections, variant selector, and button links
6+
7+
- Change position of variant selector depending on context (next to logo or in table of contents)
8+
- Update section tab styling and animation
9+
- Make header buttons smaller with a new `medium` button size

packages/gitbook/src/components/Header/CompactHeader.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,12 @@ export function CompactHeader(props: {
5050
'grow-0',
5151
'md:grow',
5252
'sm:max-w-xs',
53-
'lg:my-4',
53+
'lg:mt-2',
54+
'lg:mb-8',
5455
'lg:max-w-full',
5556
'justify-self-end',
5657
)}
5758
>
58-
{isMultiVariants ? (
59-
<div className={tcls('mb-2')}>
60-
<SpacesDropdown space={space} spaces={spaces} buttonKind="bordered" />
61-
</div>
62-
) : null}
6359
<React.Suspense fallback={null}>
6460
<SearchButton>
6561
<span className={tcls('flex-1')}>

packages/gitbook/src/components/Header/Header.tsx

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { CustomizationSettings, Site, SiteCustomizationSettings, Space } from '@gitbook/api';
1+
import {
2+
CustomizationSettings,
3+
Site,
4+
SiteCustomizationSettings,
5+
SiteSection,
6+
Space,
7+
} from '@gitbook/api';
28
import { CustomizationHeaderPreset } from '@gitbook/api';
39
import { Suspense } from 'react';
410

@@ -13,21 +19,25 @@ import { HeaderLinks } from './HeaderLinks';
1319
import { HeaderLogo } from './HeaderLogo';
1420
import { SpacesDropdown } from './SpacesDropdown';
1521
import { SearchButton } from '../Search';
22+
import { SiteSectionTabs } from '../SiteSectionTabs';
1623
/**
1724
* Render the header for the space.
1825
*/
1926
export function Header(props: {
2027
space: Space;
2128
site: Site | null;
2229
spaces: Space[];
30+
sections: { list: SiteSection[]; section: SiteSection } | null;
2331
context: ContentRefContext;
2432
customization: CustomizationSettings | SiteCustomizationSettings;
2533
withTopHeader?: boolean;
2634
children?: React.ReactNode;
2735
}) {
28-
const { children, context, space, site, spaces, customization, withTopHeader } = props;
36+
const { children, context, space, site, spaces, sections, customization, withTopHeader } =
37+
props;
2938
const isCustomizationDefault =
3039
customization.header.preset === CustomizationHeaderPreset.Default;
40+
const hasSiteSections = sections && sections.list.length > 1;
3141
const isMultiVariants = site && spaces.length > 1;
3242

3343
return (
@@ -70,7 +80,9 @@ export function Header(props: {
7080
>
7181
<HeaderLogo site={site} space={space} customization={customization} />
7282
<span>
73-
{isMultiVariants ? <SpacesDropdown space={space} spaces={spaces} /> : null}
83+
{!hasSiteSections && isMultiVariants ? (
84+
<SpacesDropdown space={space} spaces={spaces} />
85+
) : null}
7486
</span>
7587
<HeaderLinks>
7688
{customization.header.links.map((link, index) => {
@@ -134,7 +146,17 @@ export function Header(props: {
134146
</div>
135147
</div>
136148
</div>
137-
{children}
149+
{sections ? (
150+
<div
151+
className={tcls(
152+
'w-full shadow-thintop dark:shadow-light/1 bg-light dark:bg-dark z-[9] mt-0.5',
153+
)}
154+
>
155+
<div className={tcls(CONTAINER_STYLE)}>
156+
<SiteSectionTabs sections={sections.list} section={sections.section} />
157+
</div>
158+
</div>
159+
) : null}
138160
</header>
139161
);
140162
}

packages/gitbook/src/components/Header/HeaderLink.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export async function HeaderLink(props: {
5454
<Button
5555
href={target.href}
5656
variant={variant}
57+
size="medium"
5758
className={tcls(
5859
{
5960
'button-primary':

packages/gitbook/src/components/Header/SpacesDropdown.tsx

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,45 +5,37 @@ import { tcls } from '@/lib/tailwind';
55
import { Dropdown, DropdownChevron, DropdownMenu } from './Dropdown';
66
import { SpacesDropdownMenuItem } from './SpacesDropdownMenuItem';
77

8-
export function SpacesDropdown(props: {
9-
space: Space;
10-
spaces: Space[];
11-
buttonKind?: 'default' | 'bordered';
12-
}) {
13-
const { space, spaces, buttonKind = 'default' } = props;
8+
export function SpacesDropdown(props: { space: Space; spaces: Space[] }) {
9+
const { space, spaces } = props;
1410

1511
return (
1612
<Dropdown
17-
className={buttonKind === 'bordered' ? tcls('w-full') : undefined}
1813
button={(buttonProps) => (
1914
<div
2015
{...buttonProps}
2116
data-testid="space-dropdown-button"
2217
className={tcls(
23-
'justify-self-start',
2418
'flex',
2519
'flex-row',
2620
'items-center',
21+
'rounded-2xl',
22+
'straight-corners:rounded-none',
23+
'bg-light-2',
24+
'border',
25+
'border-light-3',
26+
'text-dark-4',
27+
'text-sm',
2728
'px-3',
28-
'py-1.5',
29-
'text-header-link-500',
30-
buttonKind === 'bordered'
31-
? [
32-
'ring-1',
33-
'ring-inset',
34-
'ring-dark/2',
35-
'pointer-events-auto',
36-
'justify-between',
37-
'bg-light',
38-
'dark:bg-dark',
39-
'rounded-lg',
40-
'straight-corners:rounded-none',
41-
'lg:ring-0',
42-
'border',
43-
'border-dark/2',
44-
'dark:border-light/2',
45-
]
46-
: [],
29+
'py-1',
30+
'contrast-more:border-dark',
31+
'contrast-more:bg-light',
32+
'contrast-more:text-dark',
33+
'dark:bg-dark-3',
34+
'dark:border-dark-4',
35+
'dark:text-light-4',
36+
'contrast-more:dark:border-light',
37+
'contrast-more:dark:bg-dark',
38+
'contrast-more:dark:text-light',
4739
)}
4840
>
4941
{space.title}

packages/gitbook/src/components/SiteSectionTabs/SiteSectionTabs.tsx

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,24 @@ export function SiteSectionTabs(props: { sections: SiteSection[]; section: SiteS
6969
>
7070
<div
7171
className={tcls(
72-
'relative flex gap-2 bg-transparent',
72+
'relative',
73+
'flex',
74+
'gap-2',
75+
'bg-transparent',
7376
/* add a pseudo element for active tab indicator */
74-
"after:block after:content-[''] after:origin-left after:absolute after:-bottom-px after:left-0 after:scale-x-[--tab-scale] after:transition-transform after:translate-x-[var(--tab-start)] after:h-0.5 after:w-[100px] after:bg-primary dark:after:bg-primary-500",
77+
'after:block',
78+
"after:content-['']",
79+
'after:origin-left',
80+
'after:absolute',
81+
'after:-bottom-px',
82+
'after:left-0',
83+
'after:scale-x-[--tab-scale]',
84+
'after:transition-transform',
85+
'after:translate-x-[var(--tab-start)]',
86+
'after:h-0.5',
87+
'after:w-[100px]',
88+
'after:bg-primary',
89+
'dark:after:bg-primary-400',
7590
)}
7691
role="tablist"
7792
>
@@ -82,6 +97,7 @@ export function SiteSectionTabs(props: { sections: SiteSection[]; section: SiteS
8297
label={tab.label}
8398
href={tab.path}
8499
ref={currentIndex === index ? currentTabRef : null}
100+
onClick={() => setCurrentIndex(index)}
85101
/>
86102
))}
87103
</div>
@@ -101,9 +117,9 @@ const Tab = React.forwardRef<
101117
return (
102118
<Link
103119
className={tcls(
104-
'px-3 py-3.5 rounded',
105-
active && 'text-primary dark:text-primary-500',
106-
!active && 'hover:text-primary dark:hover:text-primary-500 transition-colors',
120+
'px-3 py-1 my-2 rounded straight-corners:rounded-none transition-colors',
121+
active && 'text-primary dark:text-primary-400',
122+
!active && ' hover:bg-light-2 dark:hover:bg-dark-3',
107123
)}
108124
role="tab"
109125
href={href}

packages/gitbook/src/components/SpaceLayout/SpaceLayout.tsx

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { ContentTarget, SiteContentPointer } from '@/lib/api';
2121
import { ContentRefContext } from '@/lib/references';
2222
import { tcls } from '@/lib/tailwind';
2323

24-
import { SiteSectionTabs } from '../SiteSectionTabs';
24+
import { SpacesDropdown } from '../Header/SpacesDropdown';
2525

2626
/**
2727
* Render the entire content of the space (header, table of contents, footer, and page content).
@@ -61,6 +61,7 @@ export function SpaceLayout(props: {
6161
};
6262

6363
const withSections = Boolean(sections && sections.list.length > 0);
64+
const withVariants = Boolean(site && spaces.length > 1);
6465
const headerOffset = { sectionsHeader: withSections, topHeader: withTopHeader };
6566

6667
return (
@@ -71,21 +72,10 @@ export function SpaceLayout(props: {
7172
space={space}
7273
site={site}
7374
spaces={spaces}
75+
sections={sections}
7476
context={contentRefContext}
7577
customization={customization}
76-
>
77-
{sections ? (
78-
<div
79-
className={tcls(
80-
'w-full shadow-thintop dark:shadow-light/1 bg-light dark:bg-dark z-[9] mt-0.5',
81-
)}
82-
>
83-
<div className={tcls(CONTAINER_STYLE)}>
84-
<SiteSectionTabs sections={sections.list} section={sections.section} />
85-
</div>
86-
</div>
87-
) : null}
88-
</Header>
78+
/>
8979
<div className={tcls('scroll-nojump')}>
9080
<div
9181
className={tcls(
@@ -116,6 +106,11 @@ export function SpaceLayout(props: {
116106
/>
117107
)
118108
}
109+
innerHeader={
110+
sections || (!withTopHeader && withVariants) ? (
111+
<SpacesDropdown space={space} spaces={spaces} />
112+
) : null
113+
}
119114
headerOffset={headerOffset}
120115
/>
121116
<div className={tcls('flex-1', 'flex', 'flex-col')}>{children}</div>

packages/gitbook/src/components/TableOfContents/TableOfContents.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ export function TableOfContents(props: {
3333
context: ContentRefContext;
3434
pages: Revision['pages'];
3535
ancestors: Array<RevisionPageDocument | RevisionPageGroup>;
36-
header?: React.ReactNode;
36+
header?: React.ReactNode; // Displayed outside the scrollable TOC as a sticky header
3737
headerOffset: { sectionsHeader: boolean; topHeader: boolean };
38+
innerHeader?: React.ReactNode; // Displayed inside the scrollable TOC, directly above the page list
3839
}) {
39-
const { space, customization, pages, ancestors, header, context, headerOffset } = props;
40+
const { innerHeader, space, customization, pages, ancestors, header, context, headerOffset } =
41+
props;
4042

4143
const withHeaderOffset = headerOffset.sectionsHeader || headerOffset.topHeader;
4244
const topOffset = getTopOffset(headerOffset);
@@ -91,6 +93,7 @@ export function TableOfContents(props: {
9193
customization.trademark.enabled ? 'lg:pb-20' : 'lg:pb-4',
9294
)}
9395
>
96+
{innerHeader && <div className={tcls('ms-5', 'mb-4')}>{innerHeader}</div>}
9497
<PagesList
9598
rootPages={pages}
9699
pages={pages}

packages/gitbook/src/components/primitives/Button.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ type ButtonProps = {
99
onClick?: () => void;
1010
children: React.ReactNode;
1111
variant?: 'primary' | 'secondary';
12-
size?: 'default' | 'small';
12+
size?: 'default' | 'medium' | 'small';
1313
className?: ClassValue;
1414
};
1515

@@ -43,12 +43,13 @@ export function Button({
4343
'dark:hover:bg-light/3',
4444
];
4545

46-
const sizeClasses =
47-
size === 'default'
48-
? // DEFAULT
49-
['text-base', 'px-4', 'py-2']
50-
: // SMALL
51-
['text-xs', 'px-3 py-2'];
46+
const sizes = {
47+
default: ['text-base', 'px-4', 'py-2'],
48+
medium: ['text-base', 'px-3', 'py-1'],
49+
small: ['text-xs', 'px-3 py-2'],
50+
};
51+
52+
const sizeClasses = sizes[size] || sizes.default;
5253

5354
const domClassName = tcls(
5455
'inline-block',
@@ -60,6 +61,7 @@ export function Button({
6061
'grow-0',
6162
'shrink-0',
6263
'truncate',
64+
'transition-colors',
6365
variantClasses,
6466
sizeClasses,
6567
className,

0 commit comments

Comments
 (0)