Skip to content

Commit

Permalink
feat: Code block support in PDF & DOCX exporters (#1367)
Browse files Browse the repository at this point in the history
* feat: Support for code blocks in PDF exporter

* feat: Support for code blocks in DOCX exporter

* fix: Use Geist Mono for inline code tags in DOCX export

* fix: Background color, example formatting, style definition

* Removed TODO

---------

Co-authored-by: matthewlipski <matthewlipski@gmail.com>
  • Loading branch information
areknawo and matthewlipski authored Jan 17, 2025
1 parent c0bc5d0 commit 9a8f957
Show file tree
Hide file tree
Showing 15 changed files with 170 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,15 @@ export default function App() {
],
},
},
{
type: "codeBlock",
props: {
language: "javascript",
},
content: `const helloWorld = (message) => {
console.log("Hello World", message);
};`,
},
],
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,15 @@ export default function App() {
],
},
},
{
type: "codeBlock",
props: {
language: "javascript",
},
content: `const helloWorld = (message) => {
console.log("Hello World", message);
};`,
},
],
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,6 @@
<w:t xml:space="preserve">justified paragraph. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="Codeblock"/>
</w:pPr>
<w:r>
<w:t xml:space="preserve">Code Block
Line 2</w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="ListParagraph"/>
Expand Down Expand Up @@ -675,6 +666,23 @@ Line 2</w:t>
</w:tc>
</w:tr>
</w:tbl>
<w:p>
<w:pPr>
<w:pStyle w:val="Codeblock"/>
<w:shd w:fill="161616" w:color="161616" w:val="solid"/>
</w:pPr>
<w:r>
<w:t xml:space="preserve">const helloWorld = (message) =&gt; {</w:t>
</w:r>
<w:r>
<w:br/>
<w:t xml:space="preserve"> console.log(&quot;Hello World&quot;, message);</w:t>
</w:r>
<w:r>
<w:br/>
<w:t xml:space="preserve">};</w:t>
</w:r>
</w:p>
<w:sectPr>
<w:pgSz w:w="11906" w:h="16838" w:orient="portrait"/>
<w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="708" w:footer="708" w:gutter="0"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -953,8 +953,8 @@
<w:basedOn w:val="Normal"/>
<w:rPr>
<w:noProof/>
<w:color w:val="e1e4e8"/>
<w:shd w:fill="161616"/>
<w:color w:val="ffffff"/>
<w:rFonts w:ascii="GeistMono" w:cs="GeistMono" w:eastAsia="GeistMono" w:hAnsi="GeistMono"/>
</w:rPr>
</w:style>
</w:styles>
26 changes: 17 additions & 9 deletions packages/xl-docx-exporter/src/docx/defaultSchema/blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
COLORS_DEFAULT,
DefaultBlockSchema,
DefaultProps,
StyledText,
UnreachableCaseError,
} from "@blocknote/core";
import {
Expand Down Expand Up @@ -131,17 +132,24 @@ export const docxBlockMappingForDefaultSchema: BlockMapping<
...caption(block.props, exporter),
];
},
// TODO
codeBlock: (block, exporter) => {
codeBlock: (block) => {
const textContent = (block.content as StyledText<any>[])[0]?.text || "";

return new Paragraph({
// ...blockPropsToStyles(block.props, exporter.options.colors),
style: "Codeblock",
children: exporter.transformInlineContent(block.content),
// children: [
// new TextRun({
// text: block..type + " not implemented",
// }),
// ],
shading: {
type: ShadingType.SOLID,
fill: "161616",
color: "161616",
},
children: [
...textContent.split("\n").map((line, index) => {
return new TextRun({
text: line,
break: index > 0 ? 1 : 0,
});
}),
],
});
},
image: async (block, exporter) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/xl-docx-exporter/src/docx/defaultSchema/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const docxStyleMappingForDefaultSchema: StyleMapping<
return {};
}
return {
font: "Courier New",
font: "GeistMono",
};
},
};
28 changes: 23 additions & 5 deletions packages/xl-docx-exporter/src/docx/docxExporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,17 +142,35 @@ export class DOCXExporter<
// Unfortunately, loading the variable font doesn't work
// "./src/fonts/Inter-VariableFont_opsz,wght.ttf",

let font = await loadFileBuffer(
let interFont = await loadFileBuffer(
await import("@shared/assets/fonts/inter/Inter_18pt-Regular.ttf")
);
let geistMonoFont = await loadFileBuffer(
await import("@shared/assets/fonts/GeistMono-Regular.ttf")
);

if (font instanceof ArrayBuffer) {
// conversionw with Polyfill needed because docxjs requires Buffer
if (
interFont instanceof ArrayBuffer ||
geistMonoFont instanceof Uint8Array
) {
// conversion with Polyfill needed because docxjs requires Buffer
const Buffer = (await import("buffer")).Buffer;
font = Buffer.from(font);

if (interFont instanceof ArrayBuffer) {
interFont = Buffer.from(interFont);
}
if (geistMonoFont instanceof ArrayBuffer) {
geistMonoFont = Buffer.from(geistMonoFont);
}
}

return [{ name: "Inter", data: font as Buffer }];
return [
{ name: "Inter", data: interFont as Buffer },
{
name: "GeistMono",
data: geistMonoFont as Buffer,
},
];
}

protected async createDefaultDocumentOptions(): Promise<DocumentOptions> {
Expand Down
4 changes: 2 additions & 2 deletions packages/xl-docx-exporter/src/docx/template/word/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -983,8 +983,8 @@
<w:basedOn w:val="Normal" />
<w:rPr>
<w:noProof />
<w:color w:val="e1e4e8" />
<w:shd w:fill="161616" />
<w:color w:val="ffffff"/>
<w:rFonts w:ascii="GeistMono" w:cs="GeistMono" w:eastAsia="GeistMono" w:hAnsi="GeistMono"/>
</w:rPr>
</w:style>
</w:styles>
26 changes: 21 additions & 5 deletions packages/xl-pdf-exporter/src/pdf/__snapshots__/example.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,6 @@
</text>
</text>
</view>
<view>
<text>
codeBlock not implemented
</text>
</view>
<view
style="text-align: left;"
>
Expand Down Expand Up @@ -586,6 +581,27 @@
</view>
</view>
</view>
<view>
<view
style="padding: 18px; background-color: rgb(22, 22, 22); color: rgb(255, 255, 255); line-height: 1.25; font-size: 12px; font-family: GeistMono;"
>
<text
style="margin-left: 0px;"
>
const helloWorld = (message) =&gt; {
</text>
<text
style="margin-left: 14.25px;"
>
console.log("Hello World", message);
</text>
<text
style="margin-left: 0px;"
>
};
</text>
</view>
</view>
</view>
</page>
</document>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,6 @@
</text>
</text>
</view>
<view>
<text>
codeBlock not implemented
</text>
</view>
<view
style="text-align: left;"
>
Expand Down Expand Up @@ -591,6 +586,27 @@
</view>
</view>
</view>
<view>
<view
style="padding: 18px; background-color: rgb(22, 22, 22); color: rgb(255, 255, 255); line-height: 1.25; font-size: 12px; font-family: GeistMono;"
>
<text
style="margin-left: 0px;"
>
const helloWorld = (message) =&gt; {
</text>
<text
style="margin-left: 14.25px;"
>
console.log("Hello World", message);
</text>
<text
style="margin-left: 0px;"
>
};
</text>
</view>
</view>
</view>
<view>
<text>
Expand Down
31 changes: 30 additions & 1 deletion packages/xl-pdf-exporter/src/pdf/defaultSchema/blocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
BlockMapping,
DefaultBlockSchema,
DefaultProps,
StyledText,
} from "@blocknote/core";
import { Image, Link, Path, Svg, Text, View } from "@react-pdf/renderer";
import {
Expand Down Expand Up @@ -69,7 +70,35 @@ export const pdfBlockMappingForDefaultSchema: BlockMapping<
);
},
codeBlock: (block) => {
return <Text>{block.type + " not implemented"}</Text>;
const textContent = (block.content as StyledText<any>[])[0]?.text || "";
const lines = textContent.split("\n").map((line, index) => {
const indent = line.match(/^\s*/)?.[0].length || 0;

return (
<Text
key={`line_${index}`}
style={{
marginLeft: indent * 9.5 * PIXELS_PER_POINT,
}}>
{line.trimStart() || <>&nbsp;</>}
</Text>
);
});

return (
<View
wrap={false}
style={{
padding: 24 * PIXELS_PER_POINT,
backgroundColor: "#161616",
color: "#ffffff",
lineHeight: 1.25,
fontSize: FONT_SIZE * PIXELS_PER_POINT,
fontFamily: "GeistMono",
}}>
{lines}
</View>
);
},
audio: (block, exporter) => {
return (
Expand Down
2 changes: 1 addition & 1 deletion packages/xl-pdf-exporter/src/pdf/defaultSchema/styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export const pdfStyleMappingForDefaultSchema: StyleMapping<
return {};
}
return {
fontFamily: "Courier",
fontFamily: "GeistMono",
};
},
};
8 changes: 8 additions & 0 deletions packages/xl-pdf-exporter/src/pdf/pdfExporter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,14 @@ export class PDFExporter<
fontWeight: "bold",
});

font = await loadFontDataUrl(
await import("@shared/assets/fonts/GeistMono-Regular.ttf")
);
Font.register({
family: "GeistMono",
src: font,
});

this.fontsRegistered = true;
}

Expand Down
Binary file added shared/assets/fonts/GeistMono-Regular.ttf
Binary file not shown.
13 changes: 9 additions & 4 deletions shared/testDocument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,6 @@ export const testDocument = partialBlocksToBlocksForTesting(
textAlignment: "justify",
},
},
{
type: "codeBlock",
content: "Code Block\nLine 2",
},
{
type: "bulletListItem",
content:
Expand Down Expand Up @@ -270,5 +266,14 @@ export const testDocument = partialBlocksToBlocksForTesting(
],
},
},
{
type: "codeBlock",
props: {
language: "javascript",
},
content: `const helloWorld = (message) => {
console.log("Hello World", message);
};`,
},
]
);

0 comments on commit 9a8f957

Please sign in to comment.