Skip to content

Commit 5b6a548

Browse files
feat: Implement Video block (#37)
1 parent 0a140e4 commit 5b6a548

File tree

7 files changed

+271
-3
lines changed

7 files changed

+271
-3
lines changed

packages/react-notion-custom/CONTRIBUTING-KR.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ fetchNotionPage();
656656
| Equation | ❌ No | `equation` | |
657657
| Code | ❌ No | `code` | |
658658
| Image | ❌ No | `image` | |
659-
| Video | ❌ No | `video` | |
659+
| Video | ✅ Yes | `video` | |
660660
| Bookmark | ❌ No | `bookmark` | |
661661
| Divider | ✅ Yes | `divider` | |
662662
| Table | ❌ No | `table` | |

packages/react-notion-custom/CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ Here's a list of Notion block types currently supported in react-notion-custom.
659659
| Equation | ❌ No | `equation` | |
660660
| Code | ❌ No | `code` | |
661661
| Image | ❌ No | `image` | |
662-
| Video | ❌ No | `video` | |
662+
| Video | ✅ Yes | `video` | |
663663
| Bookmark | ❌ No | `bookmark` | |
664664
| Divider | ✅ Yes | `divider` | |
665665
| Table | ❌ No | `table` | |

packages/react-notion-custom/src/lib/components/index.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,20 @@ import Quote from "./quote";
77
import Callout from "./callout";
88
import BulletedListItem from "./bulleted-list-item";
99
import Divider from "./divider";
10+
import Video from "./video";
1011

11-
export { Headings, Paragraph, Toggle, Equation, Quote, Callout, NumberedListItem, BulletedListItem, Divider };
12+
export {
13+
Headings,
14+
Paragraph,
15+
Toggle,
16+
Equation,
17+
Quote,
18+
Callout,
19+
NumberedListItem,
20+
BulletedListItem,
21+
Divider,
22+
Video,
23+
};
1224

1325
export default {
1426
heading_1: Headings,
@@ -22,4 +34,5 @@ export default {
2234
quote: Quote,
2335
callout: Callout,
2436
divider: Divider,
37+
video: Video,
2538
};
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React from "react";
2+
import RichText from "./internal/rich-text";
3+
import { VideoArgs } from "../types";
4+
import { getYoutubeId } from "../utils";
5+
6+
type VideoProps = VideoArgs;
7+
const Video: React.FC<VideoProps> = ({ ...props }) => {
8+
const {
9+
video: { type, file, external, caption },
10+
} = props;
11+
12+
const renderVideoContent = () => {
13+
if (type === "file" && file != null) {
14+
return <video playsInline controls preload="metadata" src={file.url} />;
15+
} else if (type === "external" && external != null) {
16+
const youtubeId = getYoutubeId(external.url);
17+
if (youtubeId) {
18+
return (
19+
<iframe
20+
style={{ width: "100%", aspectRatio: "560 / 315", border: "none" }}
21+
src={`https://www.youtube.com/embed/${youtubeId}`}
22+
title="YouTube video player"
23+
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
24+
allowFullScreen
25+
/>
26+
);
27+
} else {
28+
return <div>unsupported embedded video</div>;
29+
}
30+
} else {
31+
return <div>unsupported video</div>;
32+
}
33+
};
34+
35+
return (
36+
<div className="notion-block notion-video">
37+
<div className="notion-video-content">{renderVideoContent()}</div>
38+
{caption.length !== 0 && (
39+
<div className="notion-asset-caption">
40+
<RichText props={caption} />
41+
</div>
42+
)}
43+
</div>
44+
);
45+
};
46+
47+
export default Video;

packages/react-notion-custom/src/lib/index.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,3 +703,12 @@
703703
margin: 6px 0px;
704704
border-top: 1px solid rgba(223, 223, 222, 1);
705705
}
706+
707+
.notion-video {
708+
margin: 4px 0px;
709+
}
710+
711+
.notion-video-content {
712+
display: flex;
713+
flex-direction: column;
714+
}
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
{
2+
"object": "page",
3+
"id": "dffa6fc2-7f09-4640-9ab0-a6e26309140b",
4+
"created_time": "2023-01-27T13:59:00.000Z",
5+
"last_edited_time": "2023-03-17T16:08:00.000Z",
6+
"created_by": {
7+
"object": "user",
8+
"id": "95fc0174-8fc6-4114-8e45-f67eacd99f07"
9+
},
10+
"last_edited_by": {
11+
"object": "user",
12+
"id": "95fc0174-8fc6-4114-8e45-f67eacd99f07"
13+
},
14+
"cover": {},
15+
"icon": null,
16+
"parent": {
17+
"type": "database_id",
18+
"database_id": "be65d799-9e98-4426-86a6-72072991e27b"
19+
},
20+
"archived": false,
21+
"properties": {
22+
"HashTags": {
23+
"id": "Hhkx",
24+
"type": "multi_select",
25+
"multi_select": []
26+
},
27+
"생성 일시": {
28+
"id": "J%7C%3BZ",
29+
"type": "created_time",
30+
"created_time": "2023-01-27T13:59:00.000Z"
31+
},
32+
"Slug": {
33+
"id": "S%3A%7B%3E",
34+
"type": "rich_text",
35+
"rich_rich_text": [
36+
{
37+
"type": "text",
38+
"text": {
39+
"content": "asdf",
40+
"link": null
41+
},
42+
"annotations": {
43+
"bold": false,
44+
"italic": false,
45+
"strikethrough": false,
46+
"underline": false,
47+
"code": false,
48+
"color": "default"
49+
},
50+
"plain_text": "asdf",
51+
"href": null
52+
}
53+
]
54+
},
55+
"텍스트": {
56+
"id": "q%3CHh",
57+
"type": "rich_text",
58+
"rich_rich_text": []
59+
},
60+
"Description": {
61+
"id": "qTV%3E",
62+
"type": "rich_text",
63+
"rich_rich_text": []
64+
},
65+
"Status": {
66+
"id": "vu%7C%3B",
67+
"type": "select",
68+
"select": {
69+
"id": "|QrX",
70+
"name": "Publishable",
71+
"color": "green"
72+
}
73+
},
74+
"Name": {
75+
"id": "title",
76+
"type": "title",
77+
"title": [
78+
{
79+
"type": "text",
80+
"text": {
81+
"content": "Test",
82+
"link": null
83+
},
84+
"annotations": {
85+
"bold": false,
86+
"italic": false,
87+
"strikethrough": false,
88+
"underline": false,
89+
"code": false,
90+
"color": "default"
91+
},
92+
"plain_text": "Test",
93+
"href": null
94+
}
95+
]
96+
}
97+
},
98+
"url": "https://www.notion.so/Test-dffa6fc27f0946409ab0a6e26309140b",
99+
"blocks": [
100+
{
101+
"object": "block",
102+
"id": "eeacc1d6-d8d8-4d3a-a57f-6d2a30403074",
103+
"parent": {
104+
"type": "page_id",
105+
"page_id": "dffa6fc2-7f09-4640-9ab0-a6e26309140b"
106+
},
107+
"created_time": "2023-02-17T05:51:00.000Z",
108+
"last_edited_time": "2023-03-17T16:06:00.000Z",
109+
"created_by": {
110+
"object": "user",
111+
"id": "95fc0174-8fc6-4114-8e45-f67eacd99f07"
112+
},
113+
"last_edited_by": {
114+
"object": "user",
115+
"id": "95fc0174-8fc6-4114-8e45-f67eacd99f07"
116+
},
117+
"has_children": false,
118+
"archived": false,
119+
"type": "paragraph",
120+
"paragraph": {
121+
"color": "gray_background",
122+
"rich_text": []
123+
}
124+
},
125+
{
126+
"object": "block",
127+
"id": "f3eab6d3-fa21-4f62-b586-9fffc93c3fdd",
128+
"parent": {
129+
"type": "page_id",
130+
"page_id": "dffa6fc2-7f09-4640-9ab0-a6e26309140b"
131+
},
132+
"created_time": "2023-03-17T16:06:00.000Z",
133+
"last_edited_time": "2023-03-17T16:08:00.000Z",
134+
"created_by": {
135+
"object": "user",
136+
"id": "95fc0174-8fc6-4114-8e45-f67eacd99f07"
137+
},
138+
"last_edited_by": {
139+
"object": "user",
140+
"id": "95fc0174-8fc6-4114-8e45-f67eacd99f07"
141+
},
142+
"has_children": false,
143+
"archived": false,
144+
"type": "video",
145+
"video": {
146+
"caption": [],
147+
"type": "external",
148+
"external": {
149+
"url": "https://www.youtube.com/watch?v=S92KX8-Hmlc"
150+
}
151+
}
152+
},
153+
{
154+
"object": "block",
155+
"id": "31e85e09-1ffd-4754-825b-bf92ae63d5af",
156+
"parent": {
157+
"type": "page_id",
158+
"page_id": "dffa6fc2-7f09-4640-9ab0-a6e26309140b"
159+
},
160+
"created_time": "2023-02-17T05:51:00.000Z",
161+
"last_edited_time": "2023-03-17T16:06:00.000Z",
162+
"created_by": {
163+
"object": "user",
164+
"id": "95fc0174-8fc6-4114-8e45-f67eacd99f07"
165+
},
166+
"last_edited_by": {
167+
"object": "user",
168+
"id": "95fc0174-8fc6-4114-8e45-f67eacd99f07"
169+
},
170+
"has_children": false,
171+
"archived": false,
172+
"type": "paragraph",
173+
"paragraph": {
174+
"color": "gray_background",
175+
"rich_text": []
176+
}
177+
}
178+
]
179+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import type { Meta, StoryObj } from "@storybook/react";
2+
import Component from "../../lib/Notion";
3+
import json from "./video.json";
4+
5+
const blocks = json.blocks as any;
6+
7+
const meta: Meta<typeof Component> = {
8+
title: "Blocks/Video",
9+
component: Component,
10+
};
11+
12+
export default meta;
13+
type Story = StoryObj<typeof Component>;
14+
15+
export const Video: Story = {
16+
args: {
17+
title: "Video",
18+
blocks: blocks,
19+
},
20+
};

0 commit comments

Comments
 (0)