From a5586d702be92534cd736775c9aede7abfe8fd1b Mon Sep 17 00:00:00 2001 From: Franklin Koch Date: Wed, 20 Nov 2024 20:46:28 -0700 Subject: [PATCH 1/7] Allow overriding default breakable value for typst figures --- .changeset/beige-ways-learn.md | 5 +++++ packages/myst-to-typst/src/container.ts | 11 ++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 .changeset/beige-ways-learn.md diff --git a/.changeset/beige-ways-learn.md b/.changeset/beige-ways-learn.md new file mode 100644 index 000000000..108ac2013 --- /dev/null +++ b/.changeset/beige-ways-learn.md @@ -0,0 +1,5 @@ +--- +'myst-to-typst': patch +--- + +Allow overriding default breakable value for typst figures diff --git a/packages/myst-to-typst/src/container.ts b/packages/myst-to-typst/src/container.ts index 49d7ed8d4..4580a87c4 100644 --- a/packages/myst-to-typst/src/container.ts +++ b/packages/myst-to-typst/src/container.ts @@ -99,7 +99,10 @@ export const containerHandler: Handler = (node, state) => { nonCaptions.filter((item: GenericNode) => item.type === 'container').length === nonCaptions.length; state.useMacro('#import "@preview/subpar:0.1.1"'); - state.write(`#show figure: set block(breakable: ${allSubFigs ? 'false' : 'true'})\n`); + state.useMacro('#let breakableDefault = true'); + state.write( + `#show figure: set block(breakable: ${allSubFigs ? 'false' : 'breakableDefault'})\n`, + ); state.write('#subpar.grid('); let columns = nonCaptions.length <= 3 ? nonCaptions.length : 2; // TODO: allow this to be customized nonCaptions.forEach((item: GenericNode) => { @@ -123,12 +126,14 @@ export const containerHandler: Handler = (node, state) => { label = undefined; } } else if (nonCaptions && nonCaptions.length === 1) { - state.write('#show figure: set block(breakable: true)\n'); + state.useMacro('#let breakableDefault = true'); + state.write('#show figure: set block(breakable: breakableDefault)\n'); state.write('#figure('); renderFigureChild(nonCaptions[0], state); state.write(','); } else { - state.write('#show figure: set block(breakable: true)\n'); + state.useMacro('#let breakableDefault = true'); + state.write('#show figure: set block(breakable: breakableDefault)\n'); state.write('#figure([\n '); state.renderChildren(node, 1); state.write('],'); From 8daa519f8f70042b3a03e9a7f07b81ff3368b715 Mon Sep 17 00:00:00 2001 From: Franklin Koch Date: Wed, 20 Nov 2024 20:47:07 -0700 Subject: [PATCH 2/7] Support table cell background color in typst --- .changeset/unlucky-adults-fry.md | 5 +++++ packages/myst-to-typst/src/table.ts | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 .changeset/unlucky-adults-fry.md diff --git a/.changeset/unlucky-adults-fry.md b/.changeset/unlucky-adults-fry.md new file mode 100644 index 000000000..0afac5b91 --- /dev/null +++ b/.changeset/unlucky-adults-fry.md @@ -0,0 +1,5 @@ +--- +'myst-to-typst': patch +--- + +Support table cell background color in typst diff --git a/packages/myst-to-typst/src/table.ts b/packages/myst-to-typst/src/table.ts index 81915eb13..aa37774b8 100644 --- a/packages/myst-to-typst/src/table.ts +++ b/packages/myst-to-typst/src/table.ts @@ -48,7 +48,7 @@ export const tableRowHandler: Handler = (node, state) => { }; export const tableCellHandler: Handler = (node, state) => { - if (node.rowspan || node.colspan || node.align) { + if (node.rowspan || node.colspan || node.align || node.style?.backgroundColor) { state.write('cellx('); if (node.rowspan) { state.write(`rowspan: ${node.rowspan}, `); @@ -59,6 +59,9 @@ export const tableCellHandler: Handler = (node, state) => { if (node.align) { state.write(`align: ${node.align}, `); } + if (node.style?.backgroundColor) { + state.write(`fill: rgb("${node.style.backgroundColor}"), `); + } state.write(')'); } state.write('[\n'); From 4323744e76c9a8e0d4b4035a71886d75ff01d466 Mon Sep 17 00:00:00 2001 From: Franklin Koch Date: Wed, 20 Nov 2024 21:13:16 -0700 Subject: [PATCH 3/7] Render table legends below tables in typst --- .changeset/heavy-melons-count.md | 5 +++++ packages/myst-to-typst/src/container.ts | 22 ++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 .changeset/heavy-melons-count.md diff --git a/.changeset/heavy-melons-count.md b/.changeset/heavy-melons-count.md new file mode 100644 index 000000000..fc5081bce --- /dev/null +++ b/.changeset/heavy-melons-count.md @@ -0,0 +1,5 @@ +--- +'myst-to-typst': patch +--- + +Render table legends below tables in typst diff --git a/packages/myst-to-typst/src/container.ts b/packages/myst-to-typst/src/container.ts index 4580a87c4..4634c1766 100644 --- a/packages/myst-to-typst/src/container.ts +++ b/packages/myst-to-typst/src/container.ts @@ -35,6 +35,11 @@ export function determineCaptionKind(node: GenericNode): CaptionKind | null { function renderFigureChild(node: GenericNode, state: ITypstSerializer) { const useBrackets = node.type !== 'image' && node.type !== 'table'; + if (node.type === 'legend') { + state.useMacro('#let legendStyle = (fill: black.lighten(20%), size: 8pt, style: "italic")'); + state.write('text(..legendStyle)'); + node.type = 'paragraph'; + } if (useBrackets) state.write('[\n'); else state.write('\n '); state.renderChildren({ children: [node] }); @@ -60,12 +65,17 @@ export const containerHandler: Handler = (node, state) => { state.data.isInFigure = true; const { identifier, kind } = node; let label: string | undefined = identifier; - const captions = node.children?.filter( - (child: GenericNode) => child.type === 'caption' || child.type === 'legend', - ); - const nonCaptions = node.children?.filter( - (child: GenericNode) => child.type !== 'caption' && child.type !== 'legend', - ); + const captionTypes = node.kind === 'table' ? ['caption'] : ['caption', 'legend']; + const captions: GenericNode[] = node.children?.filter((child: GenericNode) => { + return captionTypes.includes(child.type); + }); + let nonCaptions: GenericNode[] = node.children?.filter((child: GenericNode) => { + return !captionTypes.includes(child.type); + }); + nonCaptions = [ + ...nonCaptions.filter((child) => child.type !== 'legend'), + ...nonCaptions.filter((child) => child.type === 'legend'), + ]; if (!nonCaptions || nonCaptions.length === 0) { fileError(state.file, `Figure with no non-caption content: ${label}`, { node, From 662ea214a387e2446c3baf4a360019968a12d375 Mon Sep 17 00:00:00 2001 From: Franklin Koch Date: Wed, 20 Nov 2024 21:24:42 -0700 Subject: [PATCH 4/7] Support lists that do not start at 1 in typst --- .changeset/soft-shrimps-brake.md | 5 +++++ packages/myst-to-typst/src/index.ts | 9 ++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 .changeset/soft-shrimps-brake.md diff --git a/.changeset/soft-shrimps-brake.md b/.changeset/soft-shrimps-brake.md new file mode 100644 index 000000000..5cc6a45d0 --- /dev/null +++ b/.changeset/soft-shrimps-brake.md @@ -0,0 +1,5 @@ +--- +'myst-to-typst': patch +--- + +Support lists that do not start at 1 in typst diff --git a/packages/myst-to-typst/src/index.ts b/packages/myst-to-typst/src/index.ts index 4970e0980..9d9f5f247 100644 --- a/packages/myst-to-typst/src/index.ts +++ b/packages/myst-to-typst/src/index.ts @@ -189,10 +189,17 @@ const handlers: Record = { state.addNewLine(); }, list(node, state) { + const setStart = node.ordered && node.start && node.start !== 1; + if (setStart) { + state.write(`#set enum(start: ${node.start})`); + } state.data.list ??= { env: [] }; state.data.list.env.push(node.ordered ? '+' : '-'); - state.renderChildren(node, 2); + state.renderChildren(node, setStart ? 1 : 2); state.data.list.env.pop(); + if (setStart) { + state.write('#set enum(start: 1)\n\n'); + } }, listItem(node, state) { const listEnv = state.data.list?.env ?? []; From c08e26ed48834b5224f29f298e45fa90fb5b2101 Mon Sep 17 00:00:00 2001 From: Franklin Koch Date: Wed, 20 Nov 2024 21:25:38 -0700 Subject: [PATCH 5/7] Render cross-references with correct text in typst --- .changeset/tidy-crabs-rhyme.md | 5 +++++ packages/myst-to-typst/src/index.ts | 11 ++++------- 2 files changed, 9 insertions(+), 7 deletions(-) create mode 100644 .changeset/tidy-crabs-rhyme.md diff --git a/.changeset/tidy-crabs-rhyme.md b/.changeset/tidy-crabs-rhyme.md new file mode 100644 index 000000000..a8c4b03bd --- /dev/null +++ b/.changeset/tidy-crabs-rhyme.md @@ -0,0 +1,5 @@ +--- +'myst-to-typst': patch +--- + +Render cross-references with correct text in typst diff --git a/packages/myst-to-typst/src/index.ts b/packages/myst-to-typst/src/index.ts index 9d9f5f247..a6aeb7504 100644 --- a/packages/myst-to-typst/src/index.ts +++ b/packages/myst-to-typst/src/index.ts @@ -352,7 +352,7 @@ const handlers: Record = { caption: captionHandler, legend: captionHandler, captionNumber: () => undefined, - crossReference(node: CrossReference, state, parent) { + crossReference(node: CrossReference, state) { if (node.remote) { // We don't want to handle remote references, treat them as links const url = @@ -362,13 +362,10 @@ const handlers: Record = { linkHandler({ ...node, url: url }, state); return; } - // Look up reference and add the text - // const usedTemplate = node.template?.includes('%s') ? node.template : undefined; - // const text = (usedTemplate ?? toText(node))?.replace(/\s/g, '~') || '%s'; const id = node.identifier; - // state.write(text.replace(/%s/g, `@${id}`)); - const next = nextCharacterIsText(parent, node); - state.write(next ? `#[@${id}]` : `@${id}`); + state.write(`#link(<${id}>)[`); + state.renderChildren(node); + state.write(']'); }, citeGroup(node, state) { state.renderChildren(node, 0, { delim: ' ' }); From 1b1a89c2c58f02da6654975af576fbf508bdaed2 Mon Sep 17 00:00:00 2001 From: Franklin Koch Date: Wed, 20 Nov 2024 21:59:15 -0700 Subject: [PATCH 6/7] Add hook for customizing table columns in typst --- .changeset/clean-toys-work.md | 5 +++++ packages/myst-to-typst/src/table.ts | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 .changeset/clean-toys-work.md diff --git a/.changeset/clean-toys-work.md b/.changeset/clean-toys-work.md new file mode 100644 index 000000000..9c905600a --- /dev/null +++ b/.changeset/clean-toys-work.md @@ -0,0 +1,5 @@ +--- +'myst-to-typst': patch +--- + +Add hook for customizing table columns in typst diff --git a/packages/myst-to-typst/src/table.ts b/packages/myst-to-typst/src/table.ts index aa37774b8..802ea5877 100644 --- a/packages/myst-to-typst/src/table.ts +++ b/packages/myst-to-typst/src/table.ts @@ -35,8 +35,9 @@ export const tableHandler: Handler = (node, state) => { } state.useMacro('#import "@preview/tablex:0.0.9": tablex, cellx, hlinex, vlinex'); state.useMacro('#let tableStyle = (:)'); + state.useMacro('#let columnStyle = (:)'); state.write( - `${command}(columns: ${columns}, header-rows: ${countHeaderRows(node)}, repeat-header: true, ..tableStyle,\n`, + `${command}(columns: ${columns}, header-rows: ${countHeaderRows(node)}, repeat-header: true, ..tableStyle, ..columnStyle,\n`, ); state.renderChildren(node, 1); state.write(')\n'); From 955f794aacc767f7d45e82398e0c608917c93a2a Mon Sep 17 00:00:00 2001 From: Franklin Koch Date: Wed, 20 Nov 2024 22:35:23 -0700 Subject: [PATCH 7/7] Comment about typst table styles --- packages/myst-to-typst/src/table.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/myst-to-typst/src/table.ts b/packages/myst-to-typst/src/table.ts index 802ea5877..96fa774f6 100644 --- a/packages/myst-to-typst/src/table.ts +++ b/packages/myst-to-typst/src/table.ts @@ -34,6 +34,8 @@ export const tableHandler: Handler = (node, state) => { return; } state.useMacro('#import "@preview/tablex:0.0.9": tablex, cellx, hlinex, vlinex'); + // These two separate style hooks are somewhat redundant, but they allow defining + // article-wide styles and single-table styles separately state.useMacro('#let tableStyle = (:)'); state.useMacro('#let columnStyle = (:)'); state.write(