Skip to content

Commit 0f53569

Browse files
committed
Add support for page links
1 parent 4262636 commit 0f53569

File tree

4 files changed

+65
-9
lines changed

4 files changed

+65
-9
lines changed

example/pages/[pageId].tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Head from "next/head";
33
import fetch from "node-fetch";
44

55
export async function getServerSideProps(context) {
6-
const pageId = context.params?.pageId.split("-").reverse()[0];
6+
const pageId = context.params?.pageId;
77

88
if (!pageId) {
99
return;
@@ -46,7 +46,10 @@ const NotionPage = ({ blockMap }) => {
4646
<Head>
4747
<title>{title}</title>
4848
</Head>
49-
<NotionRenderer blockMap={blockMap} />
49+
<NotionRenderer
50+
blockMap={blockMap}
51+
mapPageUrl={id => `/${title}--${id}`}
52+
/>
5053
<style jsx>{`
5154
div :global(.notion-code) {
5255
box-sizing: border-box;

src/block.tsx

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,39 @@ export const renderChildText = (properties: DecorationType[]) => {
4444
});
4545
};
4646

47+
export type MapPageUrl = (pageId: string) => string;
48+
4749
interface Block {
4850
block: BlockType;
4951
parentBlock: BlockType;
5052
level: number;
53+
mapPageUrl?: MapPageUrl;
5154
}
5255

5356
export const Block: React.FC<Block> = props => {
5457
const { block, parentBlock, children } = props;
5558
const blockValue = block?.value;
56-
switch (blockValue.type) {
59+
switch (blockValue?.type) {
5760
case "page":
58-
return <div className="notion">{children}</div>;
61+
if (props.level === 0) return <div className="notion">{children}</div>;
62+
else {
63+
if (!blockValue.properties) return null;
64+
return (
65+
<a
66+
className="notion-page-link"
67+
href={props.mapPageUrl?.(blockValue.id) || `/${blockValue.id}`}
68+
>
69+
{blockValue.format && (
70+
<div className="notion-page-icon">
71+
{blockValue.format.page_icon}
72+
</div>
73+
)}
74+
<div className="notion-page-text">
75+
{renderChildText(blockValue.properties.title)}
76+
</div>
77+
</a>
78+
);
79+
}
5980
case "header":
6081
if (!blockValue.properties) return null;
6182
return (
@@ -90,7 +111,7 @@ export const Block: React.FC<Block> = props => {
90111
);
91112
case "bulleted_list":
92113
case "numbered_list":
93-
const isTopLevel = block.value.type !== parentBlock.value.type;
114+
const isTopLevel = block.value.type !== parentBlock?.value?.type;
94115
const itemPosition =
95116
1 + (parentBlock.value.content?.indexOf(block.value.id) || 0);
96117
const wrapList = (content: React.ReactNode) =>

src/renderer.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,39 @@
11
import React from "react";
22
import { BlockMapType } from "./types";
3-
import { Block } from "./block";
3+
import { Block, MapPageUrl } from "./block";
44

5-
interface NotionRendererProps {
5+
export interface NotionRendererProps {
66
blockMap: BlockMapType;
77
currentId?: string;
88
level?: number;
9+
mapPageUrl?: MapPageUrl;
910
}
1011

1112
export const NotionRenderer: React.FC<NotionRendererProps> = ({
1213
level = 0,
1314
currentId,
14-
blockMap
15+
blockMap,
16+
mapPageUrl
1517
}) => {
1618
const id = currentId || Object.keys(blockMap)[0];
1719
const currentBlock = blockMap[id];
20+
if (!currentBlock) return null;
1821
const parentBlock = blockMap[currentBlock.value.parent_id];
19-
2022
return (
2123
<Block
2224
key={id}
2325
level={level}
2426
block={currentBlock}
2527
parentBlock={parentBlock}
28+
mapPageUrl={mapPageUrl}
2629
>
2730
{currentBlock?.value?.content?.map(contentId => (
2831
<NotionRenderer
2932
key={contentId}
3033
currentId={contentId}
3134
blockMap={blockMap}
3235
level={level + 1}
36+
mapPageUrl={mapPageUrl}
3337
/>
3438
))}
3539
</Block>

src/styles.css

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ h3 {
122122
fill: inherit;
123123
margin-top: 1.1em;
124124
margin-bottom: 1px;
125+
padding: 3px 2px;
125126
}
126127
.notion-h3 {
127128
font-weight: 600;
@@ -152,6 +153,33 @@ h3 {
152153
text-decoration-color: inherit;
153154
}
154155

156+
.notion-page-link {
157+
display: flex;
158+
color: rgb(55, 53, 47);
159+
text-decoration: none;
160+
height: 30px;
161+
margin: 1px 0px;
162+
transition: background 120ms ease-in 0s;
163+
}
164+
.notion-page-link:hover {
165+
background: rgba(55, 53, 47, 0.08);
166+
}
167+
168+
.notion-page-icon {
169+
padding: 0px 5px;
170+
margin-right: 4px;
171+
margin-top: 2px;
172+
}
173+
.notion-page-text {
174+
white-space: nowrap;
175+
overflow: hidden;
176+
text-overflow: ellipsis;
177+
font-weight: 500;
178+
line-height: 1.3;
179+
border-bottom: 1px solid rgba(55, 53, 47, 0.16);
180+
margin: 4px 0px;
181+
}
182+
155183
.notion-inline-code {
156184
color: #eb5757;
157185
padding: 0.2em 0.4em;

0 commit comments

Comments
 (0)