Skip to content

Commit bdc32d1

Browse files
committed
Allow using 'environment' variables in mdx
1 parent 8e2bdea commit bdc32d1

8 files changed

Lines changed: 28 additions & 8 deletions

File tree

api/book.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ export const getBook = async (id: number): Promise<BookProps> => {
105105
title: book.title, subTitle: book.subtitle,
106106
requireLogin: book.requireLogin === 1, quizThreshold: book.quizThreshold,
107107
unlockChaptersOnAnswers: UnlockChaptersOnAnswersOptions[book.unlockChaptersOnAnswers],
108+
env: JSON.parse(book.env || "{}") as Record<string, any>,
108109
public: book.public === 1, coverImg: book.coverImg,
109110
groups,
110111
tocInHeader: book.tocInHeader === 1, language: book.language,

components/Book/Book.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@ import { usePublicProvider } from "@/hooks/usePublicProvider";
2525
import { ChapterDef, LinkDesc, UnlockChaptersOnAnswersType } from "@/types";
2626

2727

28-
const Chapters = ({chapters: allChapters, bookId, chapterNumbers, unlockChaptersOnAnswers, setIsChapterIndexVisible, allAnswers}:
28+
const Chapters = ({chapters: allChapters, bookId, chapterNumbers, unlockChaptersOnAnswers, env, setIsChapterIndexVisible, allAnswers}:
2929
{chapters: ChapterDef[],
3030
bookId: number,
3131
chapterNumbers: Record<number, number>,
3232
unlockChaptersOnAnswers: UnlockChaptersOnAnswersType,
33+
env: Record<string, any>,
3334
setIsChapterIndexVisible: React.Dispatch<React.SetStateAction<Record<number, boolean>>>,
3435
allAnswers?: AnswersInBook}
3536
) => {
@@ -55,6 +56,7 @@ const Chapters = ({chapters: allChapters, bookId, chapterNumbers, unlockChapters
5556
index={index}
5657
setIsChapterIndexVisible={setIsChapterIndexVisible}
5758
chapterNumber={chapterNumbers[index]}
59+
env={env}
5860
allAnswers={allAnswers}
5961
/>
6062
))}
@@ -307,7 +309,7 @@ export const Book = (
307309
<h1 className="mb-0 font-medium">{frontmatter.title}</h1>
308310
<p className="subtitle">{frontmatter.subTitle}</p>
309311

310-
<MdxContent content={content} bookId={bookId} t={t}/>
312+
<MdxContent content={content} bookId={bookId} t={t} env={frontmatter.env}/>
311313

312314
{!frontmatter.tocInHeader && chapters.length > 1 &&
313315
<ContentIndexControl
@@ -321,6 +323,7 @@ export const Book = (
321323
bookId={bookId}
322324
chapterNumbers={chapterNumbers}
323325
unlockChaptersOnAnswers={frontmatter.unlockChaptersOnAnswers}
326+
env={frontmatter.env}
324327
setIsChapterIndexVisible={setIsChapterIndexVisible}
325328
allAnswers={showAnswers && allAnswers || undefined}
326329
/>

components/Book/Chapter.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export const Chapter = ({
1717
index,
1818
setIsChapterIndexVisible,
1919
chapterNumber,
20+
env,
2021
bookId,
2122
chapterId,
2223
allAnswers,
@@ -26,6 +27,7 @@ export const Chapter = ({
2627
React.SetStateAction<{ [key: number]: boolean }>
2728
>;
2829
chapterNumber: number;
30+
env: Record<string, any>
2931
bookId: number;
3032
allAnswers?: AnswersInBook;
3133
}) => {
@@ -44,6 +46,7 @@ export const Chapter = ({
4446
bookId={bookId}
4547
chapterId={chapterId}
4648
t = {t}
49+
env={env}
4750
allAnswers={allAnswers}
4851
/>
4952
);

components/MdxContent.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ export interface QuestionProps extends QuizPropsBase {
2424
attempts?: number;
2525
}
2626

27-
export const MdxContent = ({content, chapterId, bookId, t, allAnswers}: {
27+
export const MdxContent = ({content, chapterId, bookId, t, env, allAnswers}: {
2828
content: string;
2929
bookId?: number;
3030
chapterId?: number;
3131
t: (key: string) => string;
32+
env?: Record<string, any>;
3233
allAnswers?: AnswersInBook;
3334
}) => {
3435
if (!content) {
@@ -167,13 +168,17 @@ export const MdxContent = ({content, chapterId, bookId, t, allAnswers}: {
167168
}, [children]),
168169
}
169170

170-
const fn = new Function('mdx', content);
171+
const fn = new Function('mdx', 'env',
172+
(env ? `const { ${Object.keys(env).join(', ')} } = env;\n`: "")
173+
+ content
174+
);
171175
const { default: Content } = fn({
172176
jsxs: runtime.jsxs,
173177
jsx: runtime.jsx,
174178
Fragment: runtime.Fragment,
175179
useMDXComponents: () => components,
176-
});
180+
},
181+
env ?? {});
177182
return (
178183
<MDXProvider>
179184
<Content components={components}/>

ingest/book.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const bookFrontmatterDefaults: RawBookFrontmatter = {
2424
requireLogin: false,
2525
quizThreshold: 0,
2626
unlockChaptersOnAnswers: UnlockChaptersOnAnswersOptions[0],
27+
env: {},
2728
} satisfies RawBookFrontmatter & Record<string, unknown>;
2829

2930
const extraBookMatter = {
@@ -49,6 +50,8 @@ export const bookMatter = (indexMd: string, slug: string, defaults: Partial<RawB
4950
admins: isListOfStrings,
5051
unlockChaptersOnAnswers: (value) => !["none", "attempt", "correct"].includes(value)
5152
&& `'unlockChaptersOnAnswers' must be one of 'none', 'attempt', or 'correct'`,
53+
env: (value) => typeof(value) !== "object"
54+
&& "'env' must be a mapping"
5255
}
5356
);
5457

ingest/updatePaths.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ const insertBook = async (
394394
mdxContent, chapters, slug,
395395
frontmatter: {
396396
title, subTitle, public: isPublic, language, tocInHeader,
397-
coverImg, requireLogin, quizThreshold, unlockChaptersOnAnswers, groups, tokens
397+
coverImg, requireLogin, quizThreshold, unlockChaptersOnAnswers, env, groups, tokens
398398
}
399399
} = book;
400400
const content = await serializedContent(mdxContent, language, slug);
@@ -404,9 +404,9 @@ const insertBook = async (
404404
INSERT INTO books (lastBuildId,
405405
path, title, subtitle,
406406
public, language, tocInHeader,
407-
coverImg, requireLogin, quizThreshold, unlockChaptersOnAnswers,
407+
coverImg, requireLogin, quizThreshold, unlockChaptersOnAnswers, env,
408408
content)
409-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
409+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
410410
ON CONFLICT DO UPDATE SET lastBuildId = excluded.lastBuildId,
411411
title = excluded.title,
412412
subtitle = excluded.subtitle,
@@ -417,6 +417,7 @@ const insertBook = async (
417417
requireLogin = excluded.requireLogin,
418418
quizThreshold = excluded.quizThreshold,
419419
unlockChaptersOnAnswers = excluded.unlockChaptersOnAnswers,
420+
env = excluded.env,
420421
content = excluded.content
421422
RETURNING id
422423
`,
@@ -426,6 +427,7 @@ const insertBook = async (
426427
isPublic, language, tocInHeader,
427428
coverImg, requireLogin, quizThreshold,
428429
UnlockChaptersOnAnswersOptions.indexOf(unlockChaptersOnAnswers),
430+
JSON.stringify(env ?? {}),
429431
content
430432
]
431433
);

types/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export interface BookFrontmatterBase {
4747
requireLogin: boolean;
4848
quizThreshold?: number;
4949
unlockChaptersOnAnswers: UnlockChaptersOnAnswersType;
50+
env: Record<string, string>;
5051
chapters?: string[];
5152
}
5253

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ALTER TABLE books
2+
ADD env TEXT;

0 commit comments

Comments
 (0)