Skip to content

Commit b8e7822

Browse files
committed
Add support for collections
We currently just support tables + basic support for gallery view
1 parent eb6053f commit b8e7822

File tree

3 files changed

+198
-1
lines changed

3 files changed

+198
-1
lines changed

src/block.tsx

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,84 @@ export const Block: React.FC<Block> = props => {
267267
{renderChildText(blockValue.properties.title)}
268268
</blockquote>
269269
);
270+
case "collection_view":
271+
if (!block) return null;
272+
const collectionView = block?.collection?.types[0];
273+
274+
return (
275+
<div>
276+
<h3 className="notion-h3">
277+
{renderChildText(block.collection?.title!)}
278+
</h3>
279+
{collectionView?.type === "table" && (
280+
<div style={{ maxWidth: "100%", marginTop: 5 }}>
281+
<table className="notion-table">
282+
<thead>
283+
<tr className="notion-tr">
284+
{collectionView.format?.table_properties
285+
?.filter(p => p.visible)
286+
.map(gp => (
287+
<th
288+
className="notion-th"
289+
style={{ minWidth: gp.width }}
290+
>
291+
{block.collection?.schema[gp.property].name}
292+
</th>
293+
))}
294+
</tr>
295+
</thead>
296+
<tbody>
297+
{block?.collection?.data.map(row => (
298+
<tr className="notion-tr">
299+
{collectionView.format?.table_properties
300+
?.filter(p => p.visible)
301+
.map(gp => (
302+
<td
303+
className={
304+
"notion-td " +
305+
(gp.property === "title" ? "notion-bold" : "")
306+
}
307+
>
308+
{
309+
renderChildText(
310+
row[block.collection?.schema[gp.property].name!]
311+
)!
312+
}
313+
</td>
314+
))}
315+
</tr>
316+
))}
317+
</tbody>
318+
</table>
319+
</div>
320+
)}
321+
{collectionView?.type === "gallery" && (
322+
<div className="notion-gallery">
323+
{block.collection?.data.map((row, i) => (
324+
<div key={`col-${i}`} className="notion-gallery-card">
325+
<div className="notion-gallery-content">
326+
{collectionView.format?.gallery_properties
327+
?.filter(p => p.visible)
328+
.map((gp, idx) => (
329+
<p
330+
key={idx + "item"}
331+
className={
332+
"notion-gallery-data " +
333+
(idx === 0 ? "is-first" : "")
334+
}
335+
>
336+
{getTextContent(
337+
row[block.collection?.schema[gp.property].name!]
338+
)}
339+
</p>
340+
))}
341+
</div>
342+
</div>
343+
))}
344+
</div>
345+
)}
346+
</div>
347+
);
270348
case "callout":
271349
return (
272350
<div

src/styles.css

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,3 +470,88 @@ img.notion-page-icon {
470470
.notion-toggle > div {
471471
margin-left: 1.1em;
472472
}
473+
474+
.notion-table,
475+
.notion-th,
476+
.notion-td {
477+
border: 1px solid rgba(55, 53, 47, 0.09);
478+
border-collapse: collapse;
479+
}
480+
481+
.notion-table {
482+
border-left: none;
483+
border-right: none;
484+
border-spacing: 0px;
485+
white-space: nowrap;
486+
}
487+
488+
.notion-th,
489+
.notion-td {
490+
font-weight: normal;
491+
padding: 0.25em 0.5em;
492+
line-height: 1.5;
493+
min-height: 1.5em;
494+
text-align: left;
495+
font-size: 14px;
496+
}
497+
498+
.notion-td.notion-bold {
499+
font-weight: 500;
500+
}
501+
502+
.notion-th {
503+
color: rgba(55, 53, 47, 0.6);
504+
font-size: 14px;
505+
}
506+
507+
.notion-td:first-child,
508+
.notion-th:first-child {
509+
border-left: 0;
510+
}
511+
512+
.notion-td:last-child,
513+
.notion-th:last-child {
514+
border-right: 0;
515+
}
516+
517+
.notion-gallery {
518+
display: grid;
519+
position: relative;
520+
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
521+
grid-auto-rows: 1fr;
522+
gap: 16px;
523+
border-top: 1px solid rgba(55, 53, 47, 0.16);
524+
padding-top: 16px;
525+
padding-bottom: 4px;
526+
}
527+
.notion-gallery-card {
528+
display: block;
529+
color: inherit;
530+
text-decoration: none;
531+
box-shadow: rgba(15, 15, 15, 0.1) 0px 0px 0px 1px,
532+
rgba(15, 15, 15, 0.1) 0px 2px 4px;
533+
border-radius: 3px;
534+
background: white;
535+
overflow: hidden;
536+
transition: background 100ms ease-out 0s;
537+
position: static;
538+
height: 100%;
539+
}
540+
541+
.notion-gallery-content {
542+
padding: 8px 10px 6px;
543+
font-size: 12px;
544+
white-space: nowrap;
545+
}
546+
547+
.notion-gallery-data.is-first {
548+
white-space: nowrap;
549+
word-break: break-word;
550+
caret-color: rgb(55, 53, 47);
551+
font-size: 14px;
552+
line-height: 1.5;
553+
min-height: 21px;
554+
font-weight: 500;
555+
overflow: hidden;
556+
text-overflow: ellipsis;
557+
}

src/types.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,33 @@ interface CodeValueType extends BaseValueType {
223223
language: DecorationType[];
224224
};
225225
}
226+
interface CollectionValueType extends ContentValueType {
227+
type: "collection_view";
228+
}
229+
230+
interface TableGalleryType extends BaseValueType {
231+
type: "gallery";
232+
format: {
233+
gallery_cover: {
234+
type: "page_cover";
235+
};
236+
gallery_cover_aspect: "cover";
237+
gallery_properties: Array<{ visible: boolean; property: string }>;
238+
};
239+
}
240+
interface TableCollectionType extends BaseValueType {
241+
type: "table";
242+
format: {
243+
table_wrap: boolean;
244+
table_properties: Array<{
245+
visible: boolean;
246+
property: string;
247+
width: number;
248+
}>;
249+
};
250+
}
251+
252+
export type CollectionViewType = TableGalleryType | TableCollectionType;
226253

227254
/**
228255
* The different block values a block can have.
@@ -246,11 +273,18 @@ export type BlockValueType =
246273
| EmbedValueType
247274
| CalloutValueType
248275
| BookmarkValueType
249-
| ToggleValueType;
276+
| ToggleValueType
277+
| CollectionValueType;
250278

251279
export interface BlockType {
252280
role: string;
253281
value: BlockValueType;
282+
collection?: {
283+
title: DecorationType[];
284+
types: CollectionViewType[];
285+
data: Array<{ [key: string]: DecorationType[] }>;
286+
schema: { [key: string]: { name: string; type: string } };
287+
};
254288
}
255289

256290
export interface NotionUserType {

0 commit comments

Comments
 (0)