Skip to content

Commit 9b0a55c

Browse files
committed
feat: add code block component
1 parent dd30dd7 commit 9b0a55c

File tree

5 files changed

+147
-6
lines changed

5 files changed

+147
-6
lines changed

README.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
Enhance your React-Notion-X projects with a versatile code block component.
2+
This component offers out-of-the-box support for multiple programming languages and automatically adapts to light and dark themes,
3+
powered by [Shiki](https://github.com/shikijs/shiki).
4+
5+
## Install
6+
7+
You can install the react-notion-x-code-block package using npm, yarn, or pnpm:
8+
9+
```shell
10+
npm install react-notion-x-code-block
11+
12+
yarn add react-notion-x-code-block
13+
14+
pnpm install react-notion-x-code-block
15+
```
16+
17+
## How to use
18+
19+
To use the component, import Code from the package and include it in your NotionRenderer components object:
20+
21+
```tsx
22+
import { Code } from "react-notion-x-code-block";
23+
24+
<NotionRenderer
25+
// ...
26+
components={{
27+
Code
28+
}}
29+
/>;
30+
```
31+
32+
### Adapting to Theme Changes
33+
34+
To ensure the code block styles automatically adjust to your theme mode (light or dark), define CSS style according to the method you use to achieve dark mode.
35+
36+
```css
37+
/* file: style.css */
38+
@media (prefers-color-scheme: dark) {
39+
.shiki,
40+
.shiki span {
41+
color: var(--shiki-dark) !important;
42+
background-color: var(--shiki-dark-bg) !important;
43+
/* Optional, if you also want font styles */
44+
font-style: var(--shiki-dark-font-style) !important;
45+
font-weight: var(--shiki-dark-font-weight) !important;
46+
text-decoration: var(--shiki-dark-text-decoration) !important;
47+
}
48+
```
49+
50+
Class-based Dark Mode
51+
52+
```css
53+
/* file: style.css */
54+
html.dark .shiki,
55+
html.dark .shiki span {
56+
color: var(--shiki-dark) !important;
57+
background-color: var(--shiki-dark-bg) !important;
58+
/* Optional, if you also want font styles */
59+
font-style: var(--shiki-dark-font-style) !important;
60+
font-weight: var(--shiki-dark-font-weight) !important;
61+
text-decoration: var(--shiki-dark-text-decoration) !important;
62+
}
63+
```
64+
65+
And then import it to the page:
66+
67+
```tsx
68+
import { Code } from "react-notion-x-code-block";
69+
import "./style.css";
70+
71+
<NotionRenderer
72+
// ...
73+
components={{
74+
Code
75+
}}
76+
/>;
77+
```

src/Button.tsx

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/code.module.css

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.codeBlock pre {
2+
padding: 34px 16px 32px 32px;
3+
overflow: auto;
4+
margin: 4px 0;
5+
border-radius: 3px;
6+
}
7+
8+
.codeBlock {
9+
width: 100%;
10+
font-size: 85%;
11+
}

src/code.tsx

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { getBlockTitle } from "notion-utils";
2+
import React, { useEffect, useState } from "react";
3+
import { cs, useNotionContext } from "react-notion-x";
4+
import { codeToHtml } from "shiki";
5+
import { BundledTheme } from "shiki/themes";
6+
7+
import styles from "./code.module.css";
8+
9+
import type { CodeBlock } from "notion-types";
10+
11+
export const Code: React.FC<{
12+
block: CodeBlock;
13+
defaultLanguage?: string;
14+
className?: string;
15+
themes?: {
16+
light: BundledTheme;
17+
dark: BundledTheme;
18+
};
19+
}> = ({
20+
block,
21+
defaultLanguage = "typescript",
22+
themes = {
23+
light: "catppuccin-latte",
24+
dark: "dracula"
25+
},
26+
className
27+
}) => {
28+
const { recordMap } = useNotionContext();
29+
const content = getBlockTitle(block, recordMap);
30+
31+
const [code, setCode] = useState<string | undefined>(undefined);
32+
33+
const language = (
34+
block.properties?.language?.[0]?.[0] || defaultLanguage
35+
).toLowerCase();
36+
37+
useEffect(() => {
38+
async function renderCodeToHtml() {
39+
const htmlCode = await codeToHtml(content, {
40+
lang: language,
41+
themes
42+
});
43+
setCode(htmlCode);
44+
}
45+
content && renderCodeToHtml();
46+
}, [content, language, themes]);
47+
48+
return code ? (
49+
<div
50+
className={cs(styles.codeBlock, className)}
51+
dangerouslySetInnerHTML={{ __html: code }}
52+
/>
53+
) : (
54+
<div className={cs(styles.codeBlock, className)}>
55+
<pre>{content}</pre>
56+
</div>
57+
);
58+
};

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export * from "./Button";
1+
export * from "./code";

0 commit comments

Comments
 (0)