Skip to content

Commit a7af3ca

Browse files
authored
Improving the new tabs (#2537)
1 parent cda08a9 commit a7af3ca

File tree

9 files changed

+78
-41
lines changed

9 files changed

+78
-41
lines changed

.changeset/wet-houses-grab.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'gitbook': patch
3+
---
4+
5+
Improving the look and feel of new section tabs

packages/gitbook/src/app/(site)/(content)/[[...pathname]]/page.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export default async function Page(props: {
2929
const {
3030
content: contentPointer,
3131
contentTarget,
32+
sections,
3233
space,
3334
site,
3435
customization,
@@ -72,6 +73,9 @@ export default async function Page(props: {
7273
page,
7374
};
7475

76+
const withSections = Boolean(sections && sections.length > 0);
77+
const headerOffset = { sectionsHeader: withSections, topHeader: withTopHeader };
78+
7579
return (
7680
<>
7781
{withFullPageCover && page.cover ? (
@@ -86,7 +90,7 @@ export default async function Page(props: {
8690
customization={customization}
8791
page={page}
8892
document={document}
89-
withHeaderOffset={withTopHeader}
93+
withHeaderOffset={headerOffset}
9094
withFullPageCover={withFullPageCover}
9195
withPageFeedback={withPageFeedback}
9296
context={contentRefContext}

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ export function Header(props: {
2323
context: ContentRefContext;
2424
customization: CustomizationSettings | SiteCustomizationSettings;
2525
withTopHeader?: boolean;
26+
children?: React.ReactNode;
2627
}) {
27-
const { context, space, site, spaces, customization, withTopHeader } = props;
28+
const { children, context, space, site, spaces, customization, withTopHeader } = props;
2829
const isCustomizationDefault =
2930
customization.header.preset === CustomizationHeaderPreset.Default;
3031
const isMultiVariants = site && spaces.length > 1;
@@ -33,7 +34,7 @@ export function Header(props: {
3334
<header
3435
className={tcls(
3536
'flex',
36-
'flex-row',
37+
'flex-col',
3738
`h-[${HEADER_HEIGHT_DESKTOP}px]`,
3839
'sticky',
3940
'top-0',
@@ -133,6 +134,7 @@ export function Header(props: {
133134
</div>
134135
</div>
135136
</div>
137+
{children}
136138
</header>
137139
);
138140
}

packages/gitbook/src/components/PageAside/PageAside.tsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ import { ScrollSectionsList } from './ScrollSectionsList';
2222
import { Ad } from '../Ads';
2323
import { PageFeedbackForm } from '../PageFeedback';
2424

25+
function getTopOffset(props: { sectionsHeader: boolean; topHeader: boolean }) {
26+
if (props.sectionsHeader && props.topHeader) {
27+
return 'lg:max-h-[calc(100vh_-_8rem)] top-32 page-api-block:xl:max-2xl:top-32';
28+
}
29+
if (props.sectionsHeader || props.topHeader) {
30+
return 'lg:max-h-[calc(100vh_-_4rem)] top-16 page-api-block:xl:max-2xl:top-16';
31+
}
32+
return 'lg:max-h-screen top-0 page-api-block:xl:max-2xl:top-0';
33+
}
34+
2535
/**
2636
* Aside listing the headings in the document.
2737
*/
@@ -32,7 +42,7 @@ export function PageAside(props: {
3242
page: RevisionPageDocument;
3343
document: JSONDocument | null;
3444
context: ContentRefContext;
35-
withHeaderOffset: boolean;
45+
withHeaderOffset: { sectionsHeader: boolean; topHeader: boolean };
3646
withFullPageCover: boolean;
3747
withPageFeedback: boolean;
3848
}) {
@@ -48,6 +58,7 @@ export function PageAside(props: {
4858
} = props;
4959
const language = getSpaceLanguage(customization);
5060

61+
const topOffset = getTopOffset(withHeaderOffset);
5162
return (
5263
<aside
5364
className={tcls(
@@ -62,10 +73,8 @@ export function PageAside(props: {
6273
'py-8',
6374
'break-anywhere', // To prevent long words in headings from breaking the layout
6475
'lg:h-full',
65-
withHeaderOffset ? 'lg:max-h-[calc(100vh_-_4rem)]' : 'lg:max-h-[100vh]',
66-
withHeaderOffset ? 'top-16' : 'top-0',
6776
'h-[100vh]',
68-
77+
'page-api-block:xl:max-2xl:z-[1]',
6978
// When in api page mode, we display it as an overlay on non-large resolutions
7079
'page-api-block:xl:max-2xl:backdrop-blur-md',
7180
'page-api-block:xl:max-2xl:fixed',
@@ -77,9 +86,7 @@ export function PageAside(props: {
7786
'page-api-block:xl:max-2xl:py-0',
7887
'page-api-block:xl:max-2xl:mt-3',
7988
'dark:page-api-block:xl:max-2xl:bg-dark-2/8',
80-
withHeaderOffset
81-
? 'page-api-block:xl:max-2xl:top-16'
82-
: 'page-api-block:xl:max-2xl:top-0',
89+
topOffset,
8390
)}
8491
>
8592
<div

packages/gitbook/src/components/SiteSectionTabs/SiteSectionTab.tsx renamed to packages/gitbook/src/components/SiteSectionTabs/SiteSectionTabs.tsx

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export function SiteSectionTabs(props: { sections: SiteSection[]; section: SiteS
2323
const navRef = React.useRef<HTMLDivElement>(null);
2424

2525
const [currentIndex, setCurrentIndex] = React.useState(
26-
sections.findIndex((section) => section.id === currentSection?.id) || 0,
26+
sections.findIndex((section) => section.id === currentSection?.id),
2727
);
2828
const [tabDimensions, setTabDimensions] = React.useState<{
2929
left: number;
@@ -57,8 +57,9 @@ export function SiteSectionTabs(props: { sections: SiteSection[]; section: SiteS
5757

5858
return tabs.length > 0 ? (
5959
<nav
60+
aria-label="Sections"
6061
ref={navRef}
61-
className="sm:mx-0 md:-mx-2 flex flex-nowrap items-center my-4 max-w-screen"
62+
className="flex flex-nowrap items-center max-w-screen mb-px"
6263
style={
6364
{
6465
'--tab-scale': `${scale}`,
@@ -68,9 +69,9 @@ export function SiteSectionTabs(props: { sections: SiteSection[]; section: SiteS
6869
>
6970
<div
7071
className={tcls(
71-
'relative flex gap-2',
72+
'relative flex gap-2 bg-transparent',
7273
/* add a pseudo element for active tab indicator */
73-
"after:block after:content-[''] after:origin-left after:absolute after:bottom-0 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",
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",
7475
)}
7576
role="tablist"
7677
>
@@ -80,9 +81,6 @@ export function SiteSectionTabs(props: { sections: SiteSection[]; section: SiteS
8081
key={index + tab.path}
8182
label={tab.label}
8283
href={tab.path}
83-
onClick={() => {
84-
setCurrentIndex(index);
85-
}}
8684
ref={currentIndex === index ? currentTabRef : null}
8785
/>
8886
))}
@@ -96,27 +94,25 @@ export function SiteSectionTabs(props: { sections: SiteSection[]; section: SiteS
9694
* The tab item - a link to a site section
9795
*/
9896
const Tab = React.forwardRef<
99-
HTMLAnchorElement,
100-
{ active: boolean; href: string; label: string; onClick: any }
97+
HTMLSpanElement,
98+
{ active: boolean; href: string; label: string; onClick?: () => void }
10199
>(function Tab(props, ref) {
102100
const { active, href, label, onClick } = props;
103101
return (
104-
<div
102+
<Link
105103
className={tcls(
106-
'my-0.5 px-2 py-1 rounded',
107-
!active && 'hover:bg-dark/1 dark:hover:bg-light/2 transition-colors',
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',
108107
)}
108+
role="tab"
109+
href={href}
110+
onClick={onClick}
109111
>
110-
<Link
111-
ref={ref}
112-
onClick={onClick}
113-
className={tcls('inline-flex w-full truncate')}
114-
role="tab"
115-
href={href}
116-
>
112+
<span ref={ref} className={tcls('inline-flex w-full truncate')}>
117113
{label}
118-
</Link>
119-
</div>
114+
</span>
115+
</Link>
120116
);
121117
});
122118

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export * from './SiteSectionTab';
1+
export * from './SiteSectionTabs';

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

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ export function SpaceLayout(props: {
6060
pages,
6161
};
6262

63+
const withSections = Boolean(sections && sections.list.length > 0);
64+
const headerOffset = { sectionsHeader: withSections, topHeader: withTopHeader };
65+
6366
return (
6467
<>
6568
{/* <ColorDebugger /> */}
@@ -70,13 +73,20 @@ export function SpaceLayout(props: {
7073
spaces={spaces}
7174
context={contentRefContext}
7275
customization={customization}
73-
/>
74-
<div className={tcls('scroll-nojump')}>
76+
>
7577
{sections ? (
76-
<div className={tcls(CONTAINER_STYLE)}>
77-
<SiteSectionTabs sections={sections.list} section={sections.section} />
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>
7886
</div>
7987
) : null}
88+
</Header>
89+
<div className={tcls('scroll-nojump')}>
8090
<div
8191
className={tcls(
8292
'flex',
@@ -106,7 +116,7 @@ export function SpaceLayout(props: {
106116
/>
107117
)
108118
}
109-
withHeaderOffset={withTopHeader}
119+
headerOffset={headerOffset}
110120
/>
111121
<div className={tcls('flex-1', 'flex', 'flex-col')}>{children}</div>
112122
</div>

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

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ import { PagesList } from './PagesList';
1616
import { TOCScrollContainer } from './TOCScroller';
1717
import { Trademark } from './Trademark';
1818

19+
function getTopOffset(props: { sectionsHeader: boolean; topHeader: boolean }) {
20+
if (props.sectionsHeader && props.topHeader) {
21+
return 'lg:top-32 lg:h-[calc(100vh_-_8rem)]';
22+
}
23+
if (props.sectionsHeader || props.topHeader) {
24+
return 'lg:top-16 lg:h-[calc(100vh_-_4rem)]';
25+
}
26+
return 'lg:top-0 lg:h-[100vh]';
27+
}
28+
1929
export function TableOfContents(props: {
2030
space: Space;
2131
customization: CustomizationSettings | SiteCustomizationSettings;
@@ -24,9 +34,12 @@ export function TableOfContents(props: {
2434
pages: Revision['pages'];
2535
ancestors: Array<RevisionPageDocument | RevisionPageGroup>;
2636
header?: React.ReactNode;
27-
withHeaderOffset: boolean;
37+
headerOffset: { sectionsHeader: boolean; topHeader: boolean };
2838
}) {
29-
const { space, customization, pages, ancestors, header, context, withHeaderOffset } = props;
39+
const { space, customization, pages, ancestors, header, context, headerOffset } = props;
40+
41+
const withHeaderOffset = headerOffset.sectionsHeader || headerOffset.topHeader;
42+
const topOffset = getTopOffset(headerOffset);
3043

3144
return (
3245
<aside
@@ -50,9 +63,8 @@ export function TableOfContents(props: {
5063
'lg:sticky',
5164
'dark:bg-dark',
5265
'dark:navigation-open:shadow-light/2',
53-
withHeaderOffset ? 'lg:h-[calc(100vh_-_4rem)]' : 'lg:h-[100vh]',
54-
withHeaderOffset ? 'lg:top-16' : 'lg:top-0',
5566
'page-no-toc:hidden',
67+
topOffset,
5668
)}
5769
>
5870
{header ? header : null}

packages/gitbook/tailwind.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ const config: Config = {
192192
},
193193
boxShadow: {
194194
thinbottom: '0px 1px 0px rgba(0, 0, 0, 0.05)',
195+
thintop: '0px -1px 0px rgba(0, 0, 0, 0.05)',
195196
'1xs': '0px 1px 1px rgba(0, 0, 0, 0.09), 0px 3.267px 2.754px rgb(0, 0, 0, 0.05), 0px 6.278px 6.63px rgb(0, 0, 0, 0.05), 0px 14px 22px rgb(0, 0, 0, 0.04)',
196197
},
197198
},

0 commit comments

Comments
 (0)