Skip to content

RND-6843: columns block #3257

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Jun 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4219611
feat: add Columns block
BrettJephson May 22, 2025
734fdab
update api version
BrettJephson May 22, 2025
411c8ed
chore: format
BrettJephson May 22, 2025
2040557
Merge branch 'main' into brett/RND-6843-columns-block
BrettJephson May 22, 2025
5a10398
add columns block skeleton
BrettJephson May 22, 2025
2f13cdd
Merge branch 'main' into brett/RND-6843-columns-block
BrettJephson May 23, 2025
e135899
Merge branch 'main' into brett/RND-6843-columns-block
BrettJephson May 27, 2025
40969c0
feat: add Columns block
BrettJephson May 22, 2025
2274ff7
update api version
BrettJephson May 22, 2025
1871025
chore: format
BrettJephson May 22, 2025
2e5ff8a
add columns block skeleton
BrettJephson May 22, 2025
ec56296
mobile
BrettJephson May 28, 2025
a27041b
wip width
BrettJephson May 30, 2025
95466e8
Update @gitbook/api
emmerich Jun 4, 2025
8a192e5
wip
BrettJephson Jun 4, 2025
7c4071b
Merge branch 'brett/RND-6843-columns-block' of github.com:GitbookIO/g…
BrettJephson Jun 4, 2025
677520f
Columns with width settings
BrettJephson Jun 4, 2025
df53ef6
chore: formatting
BrettJephson Jun 4, 2025
5e15a4d
fix typescript
BrettJephson Jun 4, 2025
d03578c
Merge branch 'main' into brett/RND-6843-columns-block
BrettJephson Jun 4, 2025
c3cfbe6
chore: format
BrettJephson Jun 4, 2025
21abc41
Merge remote-tracking branch 'origin/main' into brett/RND-6843-column…
emmerich Jun 9, 2025
a6e0f91
Revert bun.lock
emmerich Jun 9, 2025
97bde38
Fix format
emmerich Jun 9, 2025
c7e2ad3
Merge branch 'main' into brett/RND-6843-columns-block
emmerich Jun 9, 2025
ac8c916
Comment
emmerich Jun 9, 2025
de4fea3
Default to full width
emmerich Jun 9, 2025
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
6 changes: 6 additions & 0 deletions .changeset/flat-wolves-poke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"gitbook-v2": patch
"gitbook": patch
---

Adds Columns layout block to GBO
1 change: 1 addition & 0 deletions packages/gitbook/e2e/internal.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,7 @@ const testCases: TestsCase[] = [
name: 'Stepper',
url: 'blocks/stepper',
},
{ name: 'Columns', url: 'blocks/columns' },
],
},
{
Expand Down
12 changes: 6 additions & 6 deletions packages/gitbook/src/components/DocumentView/Block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type { ClassValue } from '@/lib/tailwind';

import { BlockContentRef } from './BlockContentRef';
import { CodeBlock } from './CodeBlock';
import { Columns } from './Columns';
import { Divider } from './Divider';
import type { DocumentContextProps } from './DocumentView';
import { Drawing } from './Drawing';
Expand Down Expand Up @@ -68,6 +69,8 @@ export function Block<T extends DocumentBlock>(props: BlockProps<T>) {
return <List {...props} block={block} />;
case 'list-item':
return <ListItem {...props} block={block} />;
case 'columns':
return <Columns {...props} block={block} />;
case 'code':
return <CodeBlock {...props} block={block} />;
case 'hint':
Expand Down Expand Up @@ -112,10 +115,8 @@ export function Block<T extends DocumentBlock>(props: BlockProps<T>) {
case 'image':
case 'code-line':
case 'tabs-item':
throw new Error(`Blocks (${block.type}) should be directly rendered by parent`);
case 'columns':
case 'column':
return null;
throw new Error(`Blocks (${block.type}) should be directly rendered by parent`);
default:
return nullIfNever(block);
}
Expand Down Expand Up @@ -171,6 +172,7 @@ export function BlockSkeleton(props: { block: DocumentBlock; style: ClassValue }
case 'integration':
case 'stepper':
case 'reusable-content':
case 'columns':
return <SkeletonCard id={id} style={style} />;
case 'embed':
case 'images':
Expand All @@ -179,10 +181,8 @@ export function BlockSkeleton(props: { block: DocumentBlock; style: ClassValue }
case 'image':
case 'code-line':
case 'tabs-item':
throw new Error(`Blocks (${block.type}) should be directly rendered by parent`);
case 'columns':
case 'column':
return null;
throw new Error(`Blocks (${block.type}) should be directly rendered by parent`);
default:
return nullIfNever(block);
}
Expand Down
80 changes: 80 additions & 0 deletions packages/gitbook/src/components/DocumentView/Columns/Columns.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { type ClassValue, tcls } from '@/lib/tailwind';
import type { DocumentBlockColumns, Length } from '@gitbook/api';
import type { BlockProps } from '../Block';
import { Blocks } from '../Blocks';

export function Columns(props: BlockProps<DocumentBlockColumns>) {
const { block, style, ancestorBlocks, document, context } = props;
return (
<div className={tcls('flex flex-col gap-x-8 md:flex-row', style)}>
{block.nodes.map((columnBlock) => {
const width = columnBlock.data.width;
const { className, style } = transformLengthToCSS(width);
return (
<Column key={columnBlock.key} className={className} style={style}>
<Blocks
key={columnBlock.key}
nodes={columnBlock.nodes}
document={document}
ancestorBlocks={[...ancestorBlocks, block, columnBlock]}
context={context}
blockStyle="flip-heading-hash"
style="w-full space-y-4"
/>
</Column>
);
})}
</div>
);
}

export function Column(props: {
children?: React.ReactNode;
className?: ClassValue;
style?: React.CSSProperties;
}) {
return (
<div className={tcls('flex-col', props.className)} style={props.style}>
{props.children}
</div>
);
}

function transformLengthToCSS(length: Length | undefined) {
if (!length) {
return { className: ['md:w-full'] }; // default to full width if no length is specified
}

if (typeof length === 'number') {
return { style: undefined }; // not implemented yet with non-percentage lengths
}

if (length.unit === '%') {
return {
className: [
'md:flex-shrink-0',
COLUMN_WIDTHS[Math.round(length.value * 0.01 * (COLUMN_WIDTHS.length - 1))],
],
};
}

return { style: undefined }; // not implemented yet with non-percentage lengths
}

// Tailwind CSS classes for column widths.
// The index of the array corresponds to the percentage width of the column.
const COLUMN_WIDTHS = [
'md:w-0',
'md:w-1/12',
'md:w-2/12',
'md:w-3/12',
'md:w-4/12',
'md:w-5/12',
'md:w-6/12',
'md:w-7/12',
'md:w-8/12',
'md:w-9/12',
'md:w-10/12',
'md:w-11/12',
'md:w-full',
];
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Columns';