Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fluffy-clouds-tap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"gitbook": patch
---

Support nested site section groups
4 changes: 2 additions & 2 deletions bun.lock
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@
"react-dom": "^19.0.0",
},
"catalog": {
"@gitbook/api": "^0.141.0",
"@gitbook/api": "^0.142.0",
"bidc": "^0.0.2",
},
"packages": {
Expand Down Expand Up @@ -675,7 +675,7 @@

"@fortawesome/fontawesome-svg-core": ["@fortawesome/fontawesome-svg-core@6.6.0", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "6.6.0" } }, "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg=="],

"@gitbook/api": ["@gitbook/api@0.141.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-KViAAUUStITbNGqDydUjZhxGdG4lJrS3ll8eQI5Tvs0j+Wvb4x1lxGvnm/LgtrhW+FoEgrFuRKZWVga1bI1Qmg=="],
"@gitbook/api": ["@gitbook/api@0.142.0", "", { "dependencies": { "event-iterator": "^2.0.0", "eventsource-parser": "^3.0.0" } }, "sha512-Lq1IbepAykHNG8y0fBvC7hQj3i/f1XATX58wLYXWCL3W1x6Z9f6Rs5K2qCOONswJh3l2NrX3ujrbxx3D8goRdw=="],

"@gitbook/browser-types": ["@gitbook/browser-types@workspace:packages/browser-types"],

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"workspaces": {
"packages": ["packages/*"],
"catalog": {
"@gitbook/api": "^0.141.0",
"@gitbook/api": "^0.142.0",
"bidc": "^0.0.2"
}
},
Expand Down
46 changes: 31 additions & 15 deletions packages/gitbook/src/components/SiteSections/SiteSectionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { motion } from 'framer-motion';
import React from 'react';

import { type ClassValue, tcls } from '@/lib/tailwind';
import { findSectionInGroup } from '@/lib/utils';
import { useToggleAnimation } from '../hooks';
import { Link } from '../primitives';
import { ScrollContainer } from '../primitives/ScrollContainer';
Expand All @@ -15,7 +16,7 @@ import type {
ClientSiteSections,
} from './encodeClientSiteSections';

const MAX_ITEMS = 5; // If there are more sections than this, they'll be shown below the fold in a scrollview.
const MAX_ITEMS = 6; // If there are more sections than this, they'll be shown below the fold in a scrollview.

/**
* A list of items representing site sections for multi-section sites
Expand Down Expand Up @@ -72,8 +73,9 @@ export function SiteSectionListItem(props: {
section: ClientSiteSection;
isActive: boolean;
className?: string;
style?: React.CSSProperties;
}) {
const { section, isActive, className, ...otherProps } = props;
const { section, isActive, className, style, ...otherProps } = props;

return (
<Link
Expand Down Expand Up @@ -101,6 +103,7 @@ export function SiteSectionListItem(props: {
: null,
className
)}
style={style}
{...otherProps}
>
<div
Expand All @@ -127,11 +130,12 @@ export function SiteSectionListItem(props: {
export function SiteSectionGroupItem(props: {
group: ClientSiteSectionGroup;
currentSection: ClientSiteSection;
level?: number;
}) {
const { group, currentSection } = props;
const { group, currentSection, level = 0 } = props;

const hasDescendants = group.sections.length > 0;
const isActiveGroup = group.sections.some((section) => section.id === currentSection.id);
const hasDescendants = group.children.length > 0;
const isActiveGroup = Boolean(findSectionInGroup(group, currentSection.id));
const shouldOpen = hasDescendants && isActiveGroup;
const [isOpen, setIsOpen] = React.useState(shouldOpen);

Expand Down Expand Up @@ -161,7 +165,7 @@ export function SiteSectionGroupItem(props: {
className={tcls(
'flex size-8 shrink-0 items-center justify-center rounded-md straight-corners:rounded-none bg-tint-subtle text-lg text-tint leading-none shadow-tint shadow-xs ring-1 ring-tint-subtle transition-transform group-hover/section-link:scale-110 group-hover/section-link:ring-tint-hover group-active/section-link:scale-90 group-active/section-link:shadow-none contrast-more:text-tint-strong dark:shadow-none',
isActiveGroup
? 'bg-primary tint:bg-primary-solid text-primary tint:text-contrast-primary-solid shadow-md shadow-primary ring-primary group-hover/section-link:ring-primary-hover, contrast-more:text-primary-strong contrast-more:ring-2 contrast-more:ring-primary'
? 'bg-primary text-primary shadow-md shadow-primary ring-primary group-hover/section-link:ring-primary-hover, contrast-more:text-primary-strong contrast-more:ring-2 contrast-more:ring-primary'
: null
)}
>
Expand Down Expand Up @@ -216,14 +220,26 @@ export function SiteSectionGroupItem(props: {
</button>
{hasDescendants ? (
<Descendants isVisible={isOpen}>
{group.sections.map((section) => (
<SiteSectionListItem
section={section}
isActive={section.id === currentSection.id}
key={section.id}
className="pl-5"
/>
))}
{group.children.map((child) => {
if (child.object === 'site-section') {
return (
<SiteSectionListItem
section={child}
isActive={child.id === currentSection.id}
key={child.id}
/>
);
}

return (
<SiteSectionGroupItem
group={child}
currentSection={currentSection}
key={child.id}
level={level + 1}
/>
);
})}
</Descendants>
) : null}
</>
Expand All @@ -239,7 +255,7 @@ function Descendants(props: {
return (
<motion.div
ref={scope}
className={isVisible ? undefined : '[&_ul>li]:opacity-1'}
className={isVisible ? 'pl-3' : 'pl-3 [&_ul>li]:opacity-1'}
initial={isVisible ? show : hide}
>
{children}
Expand Down
Loading