Skip to content

Commit 0ef5dc8

Browse files
authored
Update column width sizing (#3676)
1 parent 28adc9b commit 0ef5dc8

File tree

2 files changed

+63
-34
lines changed

2 files changed

+63
-34
lines changed

.changeset/mean-hornets-sip.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+
Update to column width sizing
Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,57 @@
11
import { tcls } from '@/lib/tailwind';
22
import { type DocumentBlockColumns, type Length, VerticalAlignment } from '@gitbook/api';
3+
import React from 'react';
34
import type { BlockProps } from '../Block';
45
import { Blocks } from '../Blocks';
56

67
export function Columns(props: BlockProps<DocumentBlockColumns>) {
78
const { block, style, ancestorBlocks, document, context } = props;
9+
10+
const columnWidths = React.useMemo(() => {
11+
const widths = block.nodes.map((block) => {
12+
const width = block.data.width;
13+
return width ? getFractionalWidth(width) : 0;
14+
});
15+
16+
const totalWidth = widths.reduce<number>((acc, width) => acc + width, 0);
17+
// If not all columns widths are set, distribute the remaining widths as equally as we can
18+
if (totalWidth < 1.0 && widths.some((width) => width === 0)) {
19+
const unsetWidths = widths.filter((width) => width === 0);
20+
let remainingWidth = 1.0 - totalWidth;
21+
let unsetWidthsLength = unsetWidths.length;
22+
widths.forEach((width, index) => {
23+
if (width === 0) {
24+
const calculatedWidth =
25+
Math.round((remainingWidth / unsetWidthsLength) * COLUMN_DIVISIONS) /
26+
COLUMN_DIVISIONS;
27+
widths[index] = calculatedWidth; // Assign width to empty columns
28+
unsetWidthsLength--;
29+
remainingWidth -= calculatedWidth;
30+
}
31+
});
32+
}
33+
return widths;
34+
}, [block.nodes]);
35+
836
return (
9-
<div className={tcls('flex flex-col gap-x-8 md:flex-row', style)}>
10-
{block.nodes.map((columnBlock) => {
37+
<div
38+
className={tcls(
39+
'grid w-full grid-cols-1 gap-x-8 gap-y-4 md:grid-flow-col md:grid-cols-[repeat(var(--grid-slices),minmax(0,1fr))] md:grid-rows-1',
40+
style
41+
)}
42+
style={{ '--grid-slices': COLUMN_DIVISIONS } as React.CSSProperties}
43+
>
44+
{block.nodes.map((columnBlock, index) => {
45+
const columnWidth = columnWidths[index];
1146
return (
1247
<Column
1348
key={columnBlock.key}
14-
width={columnBlock.data.width}
49+
width={
50+
columnBlock.data.width ??
51+
(columnWidth
52+
? { value: columnWidth * 100, unit: '%' }
53+
: { value: 0, unit: '%' })
54+
}
1555
verticalAlignment={columnBlock.data.verticalAlignment}
1656
>
1757
<Blocks
@@ -31,11 +71,11 @@ export function Columns(props: BlockProps<DocumentBlockColumns>) {
3171

3272
export function Column(props: {
3373
children?: React.ReactNode;
34-
width?: Length;
74+
width: Length;
3575
verticalAlignment?: VerticalAlignment;
3676
}) {
3777
const { width, verticalAlignment } = props;
38-
const { className, style } = transformLengthToCSS(width);
78+
const { className, style } = transformLengthToCSS(width) ?? {};
3979
return (
4080
<div
4181
className={tcls(
@@ -53,41 +93,25 @@ export function Column(props: {
5393
);
5494
}
5595

56-
function transformLengthToCSS(length: Length | undefined) {
57-
if (!length) {
58-
return { className: ['md:w-full'] }; // default to full width if no length is specified
59-
}
96+
const COLUMN_DIVISIONS = 12;
6097

98+
export function transformLengthToCSS(length: Length) {
6199
if (typeof length === 'number') {
62-
return { style: undefined }; // not implemented yet with non-percentage lengths
100+
return; // not implemented yet with non-percentage lengths
63101
}
64-
65102
if (length.unit === '%') {
66103
return {
67-
className: [
68-
'md:shrink-0',
69-
COLUMN_WIDTHS[Math.round(length.value * 0.01 * (COLUMN_WIDTHS.length - 1))],
70-
],
104+
className: 'md:flex-shrink-0 md:[grid-column:var(--grid-col)]',
105+
style: {
106+
'--grid-col': `auto / span ${Math.round(length.value * 0.01 * COLUMN_DIVISIONS)}`,
107+
} as React.CSSProperties,
71108
};
72109
}
73-
74-
return { style: undefined }; // not implemented yet with non-percentage lengths
75110
}
76111

77-
// Tailwind CSS classes for column widths.
78-
// The index of the array corresponds to the percentage width of the column.
79-
const COLUMN_WIDTHS = [
80-
'md:w-0',
81-
'md:w-1/12',
82-
'md:w-2/12',
83-
'md:w-3/12',
84-
'md:w-4/12',
85-
'md:w-5/12',
86-
'md:w-6/12',
87-
'md:w-7/12',
88-
'md:w-8/12',
89-
'md:w-9/12',
90-
'md:w-10/12',
91-
'md:w-11/12',
92-
'md:w-full',
93-
];
112+
function getFractionalWidth(length: Length) {
113+
if (typeof length === 'number') {
114+
return 0;
115+
}
116+
return length.value / 100;
117+
}

0 commit comments

Comments
 (0)