Skip to content

Commit f3af32c

Browse files
committed
fix: better handling of callouts (BL-11548)
1 parent 40346d4 commit f3af32c

File tree

2 files changed

+136
-38
lines changed

2 files changed

+136
-38
lines changed

src/CustomTranformers.ts

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,145 @@ export function setupCustomTransformers(
7676
}
7777
);
7878

79+
// types copied from notion-to-md to allow compilation of copied code.
80+
type TextRequest = string;
81+
82+
type Annotations = {
83+
bold: boolean;
84+
italic: boolean;
85+
strikethrough: boolean;
86+
underline: boolean;
87+
code: boolean;
88+
color:
89+
| "default"
90+
| "gray"
91+
| "brown"
92+
| "orange"
93+
| "yellow"
94+
| "green"
95+
| "blue"
96+
| "purple"
97+
| "pink"
98+
| "red"
99+
| "gray_background"
100+
| "brown_background"
101+
| "orange_background"
102+
| "yellow_background"
103+
| "green_background"
104+
| "blue_background"
105+
| "purple_background"
106+
| "pink_background"
107+
| "red_background";
108+
};
109+
type Text = {
110+
type: "text";
111+
text: {
112+
content: string;
113+
link: {
114+
url: TextRequest;
115+
} | null;
116+
};
117+
annotations: Annotations;
118+
plain_text: string;
119+
href: string | null;
120+
};
121+
122+
// In Notion, you can make a callout and change its emoji. We map 5 of these
123+
// to the 5 Docusaurus admonition styles.
124+
// This is mostly a copy of the callout code from notion-to-md. The change is to output docusaurus
125+
// admonitions instead of emulating a callout with markdown > syntax.
126+
// Note: I haven't yet tested this with any emoji except "💡"/"tip", nor the case where the
127+
// callout has-children. Not even sure what that would mean, since the document I was testing
128+
// with has quite complex markup inside the callout, but still takes the no-children branch.
129+
notionToMarkdown.setCustomTransformer(
130+
"callout",
131+
async (block: ListBlockChildrenResponseResult) => {
132+
// In this case typescript is not able to index the types properly, hence ignoring the error
133+
// @ts-ignore
134+
const blockContent = block.callout.text || block.callout.rich_text || [];
135+
// @ts-ignore
136+
const icon = block.callout.icon;
137+
let parsedData = "";
138+
blockContent.map((content: Text) => {
139+
const annotations = content.annotations;
140+
let plain_text = content.plain_text;
141+
142+
plain_text = notionToMarkdown.annotatePlainText(
143+
plain_text,
144+
annotations
145+
);
146+
147+
// if (content["href"])
148+
// plain_text = md.link(plain_text, content["href"]);
149+
150+
parsedData += plain_text;
151+
});
152+
153+
let callout_string = "";
154+
const { id, has_children } = block as any;
155+
if (!has_children) {
156+
const result1 = callout(parsedData, icon);
157+
return result1;
158+
}
159+
160+
const callout_children_object = await getBlockChildren(
161+
notionClient,
162+
id,
163+
100
164+
);
165+
166+
// // parse children blocks to md object
167+
const callout_children = await notionToMarkdown.blocksToMarkdown(
168+
callout_children_object
169+
);
170+
171+
callout_string += `${parsedData}\n`;
172+
callout_children.map(child => {
173+
callout_string += `${child.parent}\n\n`;
174+
});
175+
176+
const result = callout(callout_string.trim(), icon);
177+
return result;
178+
}
179+
);
180+
79181
// Note: Pull.ts also adds an image transformer, but has to do that for each
80182
// page so we don't do it here.
81183
}
82184

185+
const calloutsToAdmonitions = {
186+
/* prettier-ignore */ "ℹ️": "note",
187+
"💡": "tip",
188+
"❗": "info",
189+
"⚠️": "caution",
190+
"🔥": "danger",
191+
};
192+
193+
// This is the main change from the notion-to-md code.
194+
function callout(text: string, icon?: CalloutIcon) {
195+
let emoji: string | undefined;
196+
if (icon?.type === "emoji") {
197+
emoji = icon.emoji;
198+
}
199+
let docusaurusAdmonition = "note";
200+
if (emoji) {
201+
// the keyof typeof magic persuades typescript that it really is OK to use emoji as a key into calloutsToAdmonitions
202+
docusaurusAdmonition =
203+
calloutsToAdmonitions[emoji as keyof typeof calloutsToAdmonitions] ??
204+
// For Notion callouts with other emojis, pass them through using hte emoji as the name.
205+
// For this to work on a Docusaurus site, it will need to define that time on the remark-admonitions options in the docusaurus.config.js.
206+
// See https://github.com/elviswolcott/remark-admonitions and https://docusaurus.io/docs/using-plugins#using-presets.
207+
emoji;
208+
}
209+
return `:::${docusaurusAdmonition}\n\n${text}\n\n:::\n\n`;
210+
}
211+
212+
type CalloutIcon =
213+
| { type: "emoji"; emoji?: string }
214+
| { type: "external"; external?: { url: string } }
215+
| { type: "file"; file: { url: string; expiry_time: string } }
216+
| null;
217+
83218
async function notionColumnListToMarkdown(
84219
notionToMarkdown: NotionToMarkdown,
85220
notionClient: Client,

src/DocusaurusTweaks.ts

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ export function tweakForDocusaurus(input: string): {
44
body: string;
55
imports: string;
66
} {
7-
const output = notionCalloutsToAdmonitions(input);
8-
const { body, imports } = notionEmbedsToMDX(output);
7+
const { body, imports } = notionEmbedsToMDX(input);
98
return { body, imports };
109
}
1110
// In Notion, you can embed videos & such. To show these
@@ -101,39 +100,3 @@ function notionEmbedsToMDX(input: string): {
101100

102101
return { body, imports: [...imports].join("\n") };
103102
}
104-
105-
// In Notion, you can make a callout and change its emoji. We map 5 of these
106-
// to the 5 Docusaurus admonition styles.
107-
function notionCalloutsToAdmonitions(input: string): string {
108-
const notionCalloutPattern = />\s(||💡||🔥|.)\s(.*)\n/gmu;
109-
const calloutsToAdmonitions = {
110-
/* prettier-ignore */ "ℹ️": "note",
111-
"💡": "tip",
112-
"❗": "info",
113-
"⚠️": "caution",
114-
"🔥": "danger",
115-
};
116-
let output = input;
117-
let match;
118-
while ((match = notionCalloutPattern.exec(input)) !== null) {
119-
const string = match[0];
120-
const emoji = match[1] as keyof typeof calloutsToAdmonitions;
121-
const content = match[2];
122-
123-
const docusaurusAdmonition = calloutsToAdmonitions[emoji];
124-
if (docusaurusAdmonition) {
125-
output = output.replace(
126-
string,
127-
`:::${docusaurusAdmonition}\n\n${content}\n\n:::\n\n`
128-
);
129-
}
130-
// For Notion callouts with other emojis, pass them through using hte emoji as the name.
131-
// For this to work on a Docusaurus site, it will need to define that time on the remark-admonitions options in the docusaurus.config.js.
132-
// See https://github.com/elviswolcott/remark-admonitions and https://docusaurus.io/docs/using-plugins#using-presets.
133-
else {
134-
output = output.replace(string, `:::${emoji}\n\n${content}\n\n:::\n\n`);
135-
}
136-
}
137-
138-
return output;
139-
}

0 commit comments

Comments
 (0)