Skip to content

Commit d1a26fc

Browse files
committed
2 parents 367b4ff + 9a7c5d1 commit d1a26fc

File tree

5 files changed

+237
-27
lines changed

5 files changed

+237
-27
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "0.6.1",
2+
"version": "0.7.2",
33
"license": "MIT",
44
"main": "dist/index.js",
55
"typings": "dist/index.d.ts",

src/block.tsx

+109-17
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
@@ -285,39 +363,53 @@ export const Block: React.FC<Block> = props => {
285363
</div>
286364
);
287365
case "bookmark":
366+
const link = blockValue.properties.link
367+
const title = blockValue.properties.title ?? link
368+
const description = blockValue.properties.description
369+
const block_color = blockValue.format?.block_color
370+
const bookmark_icon = blockValue.format?.bookmark_icon
371+
const bookmark_cover = blockValue.format?.bookmark_cover
372+
288373
return (
289374
<div className="notion-row">
290375
<a
291376
target="_blank"
292377
rel="noopener noreferrer"
293378
className={classNames(
294379
"notion-bookmark",
295-
blockValue.format.block_color &&
296-
`notion-${blockValue.format.block_color}`
380+
block_color &&
381+
`notion-${block_color}`
297382
)}
298-
href={blockValue.properties.link[0][0]}
383+
href={link[0][0]}
299384
>
300385
<div>
301386
<div className="notion-bookmark-title">
302-
{renderChildText(blockValue.properties.title)}
303-
</div>
304-
<div className="notion-bookmark-description">
305-
{renderChildText(blockValue.properties.description)}
387+
{renderChildText(title)}
306388
</div>
389+
{description && (
390+
<div className="notion-bookmark-description">
391+
{renderChildText(description)}
392+
</div>
393+
)}
394+
307395
<div className="notion-bookmark-link">
396+
{bookmark_icon && (
397+
<img
398+
src={bookmark_icon}
399+
alt={getTextContent(title)}
400+
/>
401+
)}
402+
<div>{renderChildText(link)}</div>
403+
</div>
404+
</div>
405+
{bookmark_cover && (
406+
<div className="notion-bookmark-image">
308407
<img
309-
src={blockValue.format.bookmark_icon}
310-
alt={getTextContent(blockValue.properties.title)}
408+
src={bookmark_cover}
409+
alt={getTextContent(title)}
311410
/>
312-
<div>{renderChildText(blockValue.properties.link)}</div>
313411
</div>
314-
</div>
315-
<div className="notion-bookmark-image">
316-
<img
317-
src={blockValue.format.bookmark_cover}
318-
alt={getTextContent(blockValue.properties.title)}
319-
/>
320-
</div>
412+
)}
321413
</a>
322414
</div>
323415
);

src/components/code.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ const Code: React.FC<{ code: string; language: string }> = ({
99
const prismLanguage =
1010
languages[language.toLowerCase()] || languages.javascript;
1111

12+
const langClass = `language-${language.toLowerCase()}`;
13+
1214
return (
13-
<pre className="notion-code">
15+
<pre className={`notion-code ${langClass}`}>
1416
<code
15-
className={`language-${language.toLowerCase()}`}
17+
className={langClass}
1618
dangerouslySetInnerHTML={{
1719
__html: highlight(code, prismLanguage, language)
1820
}}

src/styles.css

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

src/types.ts

+38-4
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,10 @@ interface BookmarkValueType extends BaseValueType {
110110
type: "bookmark";
111111
properties: {
112112
link: DecorationType[];
113-
title: DecorationType[];
114-
description: DecorationType[];
113+
title?: DecorationType[];
114+
description?: DecorationType[];
115115
};
116-
format: {
116+
format?: {
117117
block_color?: string;
118118
bookmark_icon: string;
119119
bookmark_cover: string;
@@ -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)