Mass guide editor changes #18
@@ -1281,13 +1281,19 @@ class GuideEditor {
|
|||||||
|
|
||||||
async selectStep(stepId) {
|
async selectStep(stepId) {
|
||||||
if (!this.stepMap.has(stepId)) return;
|
if (!this.stepMap.has(stepId)) return;
|
||||||
|
// Persist any unsaved edits on the outgoing step before switching, so a
|
||||||
|
// later guide-wide reload (e.g. applyStyleAcross('guide')) doesn't
|
||||||
|
// discard them by re-fetching a stale on-disk copy.
|
||||||
|
if (this.pendingSave) await this.flushStep();
|
||||||
this.selectedStepId = stepId;
|
this.selectedStepId = stepId;
|
||||||
this.selectedAnnotationId = null;
|
this.selectedAnnotationId = null;
|
||||||
this.canvas.select(null);
|
this.canvas.select(null);
|
||||||
this.syncStepFields();
|
this.syncStepFields();
|
||||||
|
this.syncFocusedControls();
|
||||||
this.renderStepList();
|
this.renderStepList();
|
||||||
this.renderCanvas();
|
this.renderCanvas();
|
||||||
this.renderAnnotationPanel();
|
this.renderAnnotationPanel();
|
||||||
|
this.renderBlocksPanel();
|
||||||
this.emitMeta();
|
this.emitMeta();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,20 @@ function stepBlocks(step) {
|
|||||||
return step.blocks || orderedBlocks(step);
|
return step.blocks || orderedBlocks(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split a step's blocks into the groups exporters lay out around the
|
||||||
|
* description/image: text blocks pinned to 'before-description', and
|
||||||
|
* everything else (code/table blocks plus 'after-description' and
|
||||||
|
* 'after-image' text blocks) in the same relative order they appear in the
|
||||||
|
* editor's Blocks list.
|
||||||
|
*/
|
||||||
|
function stepContentGroups(step) {
|
||||||
|
const all = stepBlocks(step);
|
||||||
|
const before = all.filter((b) => b.kind === 'text' && b.position === 'before-description');
|
||||||
|
const rest = all.filter((b) => !(b.kind === 'text' && b.position === 'before-description'));
|
||||||
|
return { before, rest };
|
||||||
|
}
|
||||||
|
|
||||||
function codeBlockText(block) {
|
function codeBlockText(block) {
|
||||||
return blockText(block);
|
return blockText(block);
|
||||||
}
|
}
|
||||||
@@ -67,6 +81,7 @@ module.exports = {
|
|||||||
writeStepImages,
|
writeStepImages,
|
||||||
renderAllImages,
|
renderAllImages,
|
||||||
stepBlocks,
|
stepBlocks,
|
||||||
|
stepContentGroups,
|
||||||
codeBlockText,
|
codeBlockText,
|
||||||
LEVEL_LABEL,
|
LEVEL_LABEL,
|
||||||
};
|
};
|
||||||
|
|||||||
+7
-11
@@ -4,7 +4,7 @@ const fs = require('node:fs');
|
|||||||
const path = require('node:path');
|
const path = require('node:path');
|
||||||
const { slugify, escapeXml } = require('../core/util');
|
const { slugify, escapeXml } = require('../core/util');
|
||||||
const { encodePng } = require('../core/png');
|
const { encodePng } = require('../core/png');
|
||||||
const { guideSlug, renderAllImages, stepBlocks, codeBlockText } = require('./common');
|
const { guideSlug, renderAllImages, stepContentGroups, codeBlockText } = require('./common');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Confluence storage-format export. Writes a single XHTML document plus a
|
* Confluence storage-format export. Writes a single XHTML document plus a
|
||||||
@@ -67,7 +67,8 @@ function exportConfluence(ast, outDir, template = {}) {
|
|||||||
const parts = [`<a id="${anchorFor(step)}"></a>`, `<h2>${escapeXml(step.number)}. ${escapeXml(step.title || 'Untitled step')}</h2>`];
|
const parts = [`<a id="${anchorFor(step)}"></a>`, `<h2>${escapeXml(step.number)}. ${escapeXml(step.title || 'Untitled step')}</h2>`];
|
||||||
if (step.skipped) parts.push('<p><em>(skipped)</em></p>');
|
if (step.skipped) parts.push('<p><em>(skipped)</em></p>');
|
||||||
|
|
||||||
for (const tb of stepBlocks(step).filter((block) => block.kind === 'text' && block.position === 'before-description')) {
|
const { before, rest } = stepContentGroups(step);
|
||||||
|
for (const tb of before) {
|
||||||
parts.push(blockMacro(tb, ast));
|
parts.push(blockMacro(tb, ast));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,8 +81,10 @@ function exportConfluence(ast, outDir, template = {}) {
|
|||||||
parts.push(`<p><ac:image><ri:attachment ri:filename="${escapeXml(attachment)}" /></ac:image></p>`);
|
parts.push(`<p><ac:image><ri:attachment ri:filename="${escapeXml(attachment)}" /></ac:image></p>`);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const block of stepBlocks(step).filter((item) => item.kind !== 'text')) {
|
for (const block of rest) {
|
||||||
if (block.kind === 'code') {
|
if (block.kind === 'text') {
|
||||||
|
parts.push(blockMacro(block, ast));
|
||||||
|
} else if (block.kind === 'code') {
|
||||||
const lang = block.language ? `<ac:parameter ac:name="language">${escapeXml(block.language)}</ac:parameter>` : '';
|
const lang = block.language ? `<ac:parameter ac:name="language">${escapeXml(block.language)}</ac:parameter>` : '';
|
||||||
parts.push(`<ac:structured-macro ac:name="code">${lang}<ac:plain-text-body>${cdata(codeBlockText(block))}</ac:plain-text-body></ac:structured-macro>`);
|
parts.push(`<ac:structured-macro ac:name="code">${lang}<ac:plain-text-body>${cdata(codeBlockText(block))}</ac:plain-text-body></ac:structured-macro>`);
|
||||||
} else if (block.kind === 'table') {
|
} else if (block.kind === 'table') {
|
||||||
@@ -97,13 +100,6 @@ function exportConfluence(ast, outDir, template = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const tb of stepBlocks(step).filter((block) => block.kind === 'text' && block.position === 'after-description')) {
|
|
||||||
parts.push(blockMacro(tb, ast));
|
|
||||||
}
|
|
||||||
for (const tb of stepBlocks(step).filter((block) => block.kind === 'text' && block.position === 'after-image')) {
|
|
||||||
parts.push(blockMacro(tb, ast));
|
|
||||||
}
|
|
||||||
|
|
||||||
return `<div class="step">${parts.join('\n')}</div>`;
|
return `<div class="step">${parts.join('\n')}</div>`;
|
||||||
}).join('\n');
|
}).join('\n');
|
||||||
|
|
||||||
|
|||||||
+8
-9
@@ -5,7 +5,7 @@ const path = require('node:path');
|
|||||||
const { zipSync } = require('../core/zip');
|
const { zipSync } = require('../core/zip');
|
||||||
const { escapeXml } = require('../core/util');
|
const { escapeXml } = require('../core/util');
|
||||||
const { encodePng } = require('../core/png');
|
const { encodePng } = require('../core/png');
|
||||||
const { guideSlug, renderAllImages, LEVEL_LABEL, stepBlocks, codeBlockText } = require('./common');
|
const { guideSlug, renderAllImages, LEVEL_LABEL, stepContentGroups, codeBlockText } = require('./common');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DOCX exporter: WordprocessingML built directly (no dependency), one
|
* DOCX exporter: WordprocessingML built directly (no dependency), one
|
||||||
@@ -99,7 +99,8 @@ function exportDocx(ast, outDir, template = {}) {
|
|||||||
body.push(p(run(`${step.number}. ${step.title || 'Untitled step'}`, { bold: true, size: headSize }),
|
body.push(p(run(`${step.number}. ${step.title || 'Untitled step'}`, { bold: true, size: headSize }),
|
||||||
step.forceNewPage ? '<w:pageBreakBefore/>' : ''));
|
step.forceNewPage ? '<w:pageBreakBefore/>' : ''));
|
||||||
|
|
||||||
emitTextBlocks(step, 'before-description');
|
const { before, rest } = stepContentGroups(step);
|
||||||
|
for (const tb of before) emitTextBlock(tb);
|
||||||
if (step.descriptionText) body.push(p(run(step.descriptionText)));
|
if (step.descriptionText) body.push(p(run(step.descriptionText)));
|
||||||
|
|
||||||
const img = images.get(step.stepId);
|
const img = images.get(step.stepId);
|
||||||
@@ -111,20 +112,19 @@ function exportDocx(ast, outDir, template = {}) {
|
|||||||
body.push(p(drawing(relCounter, img.width, img.height, tpl.imageWidthTwips)));
|
body.push(p(drawing(relCounter, img.width, img.height, tpl.imageWidthTwips)));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const block of stepBlocks(step).filter((item) => item.kind !== 'text')) {
|
for (const block of rest) {
|
||||||
if (block.kind === 'code') {
|
if (block.kind === 'text') {
|
||||||
|
emitTextBlock(block);
|
||||||
|
} else if (block.kind === 'code') {
|
||||||
body.push(p(run(codeBlockText(block), { size: 18, font: 'Courier New', color: '1F2937' }),
|
body.push(p(run(codeBlockText(block), { size: 18, font: 'Courier New', color: '1F2937' }),
|
||||||
'<w:shd w:val="clear" w:fill="F3F4F6"/>'));
|
'<w:shd w:val="clear" w:fill="F3F4F6"/>'));
|
||||||
} else if (block.kind === 'table') {
|
} else if (block.kind === 'table') {
|
||||||
if (block.rows && block.rows.length) body.push(table(block.rows), p(''));
|
if (block.rows && block.rows.length) body.push(table(block.rows), p(''));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emitTextBlocks(step, 'after-description');
|
|
||||||
emitTextBlocks(step, 'after-image');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitTextBlocks(step, position) {
|
function emitTextBlock(tb) {
|
||||||
for (const tb of stepBlocks(step).filter((b) => b.kind === 'text' && b.position === position)) {
|
|
||||||
const label = `${LEVEL_LABEL[tb.level] || 'Note'}${tb.title ? `: ${tb.title}` : ''}`;
|
const label = `${LEVEL_LABEL[tb.level] || 'Note'}${tb.title ? `: ${tb.title}` : ''}`;
|
||||||
const style = LEVEL_STYLE[tb.level] || LEVEL_STYLE.info;
|
const style = LEVEL_STYLE[tb.level] || LEVEL_STYLE.info;
|
||||||
body.push(p(
|
body.push(p(
|
||||||
@@ -132,7 +132,6 @@ function exportDocx(ast, outDir, template = {}) {
|
|||||||
`<w:shd w:val="clear" w:fill="${style.fill}"/><w:pBdr><w:left w:val="single" w:sz="24" w:space="4" w:color="${style.color}"/></w:pBdr>`
|
`<w:shd w:val="clear" w:fill="${style.fill}"/><w:pBdr><w:left w:val="single" w:sz="24" w:space="4" w:color="${style.color}"/></w:pBdr>`
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const documentXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
const documentXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||||
|
|||||||
+11
-13
@@ -4,7 +4,7 @@ const fs = require('node:fs');
|
|||||||
const path = require('node:path');
|
const path = require('node:path');
|
||||||
const { escapeHtml } = require('../core/util');
|
const { escapeHtml } = require('../core/util');
|
||||||
const { encodePng } = require('../core/png');
|
const { encodePng } = require('../core/png');
|
||||||
const { guideSlug, renderAllImages, LEVEL_LABEL, stepBlocks, codeBlockText } = require('./common');
|
const { guideSlug, renderAllImages, LEVEL_LABEL, stepContentGroups, codeBlockText } = require('./common');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTML exporters. Both variants are fully self-contained single files:
|
* HTML exporters. Both variants are fully self-contained single files:
|
||||||
@@ -38,34 +38,32 @@ function stepLinkRewrite(html, ast) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function blocksHtml(step, position) {
|
function blockHtml(tb) {
|
||||||
return stepBlocks(step)
|
return `<div class="block block-${tb.level}"><strong>${escapeHtml(LEVEL_LABEL[tb.level] || 'Note')}${tb.title ? `: ${escapeHtml(tb.title)}` : ''}</strong>${tb.descriptionHtml ? `<div>${tb.descriptionHtml}</div>` : ''}</div>`;
|
||||||
.filter((tb) => tb.position === position)
|
|
||||||
.map((tb) => `<div class="block block-${tb.level}"><strong>${escapeHtml(LEVEL_LABEL[tb.level] || 'Note')}${tb.title ? `: ${escapeHtml(tb.title)}` : ''}</strong>${tb.descriptionHtml ? `<div>${tb.descriptionHtml}</div>` : ''}</div>`)
|
|
||||||
.join('\n');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function stepBodyHtml(step, ast, images, tpl) {
|
function stepBodyHtml(step, ast, images, tpl) {
|
||||||
const parts = [];
|
const parts = [];
|
||||||
parts.push(blocksHtml(step, 'before-description'));
|
const { before, rest } = stepContentGroups(step);
|
||||||
|
for (const tb of before) parts.push(blockHtml(tb));
|
||||||
if (step.descriptionHtml) parts.push(`<div class="desc">${stepLinkRewrite(step.descriptionHtml, ast)}</div>`);
|
if (step.descriptionHtml) parts.push(`<div class="desc">${stepLinkRewrite(step.descriptionHtml, ast)}</div>`);
|
||||||
const img = images.get(step.stepId);
|
const img = images.get(step.stepId);
|
||||||
if (img && tpl.includeImages) {
|
if (img && tpl.includeImages) {
|
||||||
parts.push(`<img class="shot" alt="Step ${escapeHtml(step.number)}" src="${dataUri(img)}" width="${img.width}">`);
|
parts.push(`<img class="shot" alt="Step ${escapeHtml(step.number)}" src="${dataUri(img)}" width="${img.width}">`);
|
||||||
}
|
}
|
||||||
for (const block of stepBlocks(step).filter((item) => item.kind !== 'text')) {
|
for (const block of rest) {
|
||||||
if (block.kind === 'code') {
|
if (block.kind === 'text') {
|
||||||
|
parts.push(blockHtml(block));
|
||||||
|
} else if (block.kind === 'code') {
|
||||||
parts.push(`<pre class="code"><code>${escapeHtml(codeBlockText(block))}</code></pre>`);
|
parts.push(`<pre class="code"><code>${escapeHtml(codeBlockText(block))}</code></pre>`);
|
||||||
} else if (block.kind === 'table') {
|
} else if (block.kind === 'table') {
|
||||||
if (!block.rows || !block.rows.length) continue;
|
if (!block.rows || !block.rows.length) continue;
|
||||||
const [head, ...rest] = block.rows;
|
const [head, ...bodyRows] = block.rows;
|
||||||
parts.push('<table><thead><tr>' + head.map((c) => `<th>${escapeHtml(c)}</th>`).join('') + '</tr></thead><tbody>'
|
parts.push('<table><thead><tr>' + head.map((c) => `<th>${escapeHtml(c)}</th>`).join('') + '</tr></thead><tbody>'
|
||||||
+ rest.map((r) => '<tr>' + r.map((c) => `<td>${escapeHtml(c)}</td>`).join('') + '</tr>').join('')
|
+ bodyRows.map((r) => '<tr>' + r.map((c) => `<td>${escapeHtml(c)}</td>`).join('') + '</tr>').join('')
|
||||||
+ '</tbody></table>');
|
+ '</tbody></table>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parts.push(blocksHtml(step, 'after-description'));
|
|
||||||
parts.push(blocksHtml(step, 'after-image'));
|
|
||||||
return parts.filter(Boolean).join('\n');
|
return parts.filter(Boolean).join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-10
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const fs = require('node:fs');
|
const fs = require('node:fs');
|
||||||
const path = require('node:path');
|
const path = require('node:path');
|
||||||
const { guideSlug, writeStepImages, LEVEL_LABEL, stepBlocks, codeBlockText } = require('./common');
|
const { guideSlug, writeStepImages, LEVEL_LABEL, stepContentGroups, codeBlockText } = require('./common');
|
||||||
const { htmlToMarkdown } = require('./htmlmd');
|
const { htmlToMarkdown } = require('./htmlmd');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,7 +45,8 @@ function exportMarkdown(ast, outDir, template = {}) {
|
|||||||
lines.push(`${heading} ${step.number}. ${step.title || 'Untitled step'}`, '');
|
lines.push(`${heading} ${step.number}. ${step.title || 'Untitled step'}`, '');
|
||||||
if (step.skipped) lines.push('*(skipped)*', '');
|
if (step.skipped) lines.push('*(skipped)*', '');
|
||||||
|
|
||||||
emitBlocks(lines, step, 'before-description');
|
const { before, rest } = stepContentGroups(step);
|
||||||
|
for (const tb of before) emitBlock(lines, tb);
|
||||||
|
|
||||||
if (step.descriptionHtml) lines.push(htmlToMarkdown(step.descriptionHtml), '');
|
if (step.descriptionHtml) lines.push(htmlToMarkdown(step.descriptionHtml), '');
|
||||||
|
|
||||||
@@ -58,8 +59,10 @@ function exportMarkdown(ast, outDir, template = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const block of stepBlocks(step).filter((item) => item.kind !== 'text')) {
|
for (const block of rest) {
|
||||||
if (block.kind === 'code') {
|
if (block.kind === 'text') {
|
||||||
|
emitBlock(lines, block);
|
||||||
|
} else if (block.kind === 'code') {
|
||||||
lines.push(`\`\`\`${block.language || ''}`, codeBlockText(block), '```', '');
|
lines.push(`\`\`\`${block.language || ''}`, codeBlockText(block), '```', '');
|
||||||
} else if (block.kind === 'table') {
|
} else if (block.kind === 'table') {
|
||||||
if (!block.rows || !block.rows.length) continue;
|
if (!block.rows || !block.rows.length) continue;
|
||||||
@@ -71,9 +74,6 @@ function exportMarkdown(ast, outDir, template = {}) {
|
|||||||
lines.push('');
|
lines.push('');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emitBlocks(lines, step, 'after-description');
|
|
||||||
emitBlocks(lines, step, 'after-image');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const file = path.join(outDir, `${guideSlug(ast)}.md`);
|
const file = path.join(outDir, `${guideSlug(ast)}.md`);
|
||||||
@@ -81,8 +81,7 @@ function exportMarkdown(ast, outDir, template = {}) {
|
|||||||
return { file, imageCount: images.size };
|
return { file, imageCount: images.size };
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitBlocks(lines, step, position) {
|
function emitBlock(lines, tb) {
|
||||||
for (const tb of stepBlocks(step).filter((b) => b.kind === 'text' && b.position === position)) {
|
|
||||||
const label = LEVEL_LABEL[tb.level] || 'Note';
|
const label = LEVEL_LABEL[tb.level] || 'Note';
|
||||||
// GitHub-Flavored Markdown alert syntax — renders with a colored,
|
// GitHub-Flavored Markdown alert syntax — renders with a colored,
|
||||||
// icon-labeled box on GitHub/Azure DevOps wikis and several other
|
// icon-labeled box on GitHub/Azure DevOps wikis and several other
|
||||||
@@ -92,7 +91,6 @@ function emitBlocks(lines, step, position) {
|
|||||||
const body = htmlToMarkdown(tb.descriptionHtml);
|
const body = htmlToMarkdown(tb.descriptionHtml);
|
||||||
if (body) lines.push(`> ${body.replace(/\n/g, '\n> ')}`);
|
if (body) lines.push(`> ${body.replace(/\n/g, '\n> ')}`);
|
||||||
lines.push('');
|
lines.push('');
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { exportMarkdown, DEFAULT_TEMPLATE, anchorFor };
|
module.exports = { exportMarkdown, DEFAULT_TEMPLATE, anchorFor };
|
||||||
|
|||||||
+8
-9
@@ -3,7 +3,7 @@
|
|||||||
const fs = require('node:fs');
|
const fs = require('node:fs');
|
||||||
const path = require('node:path');
|
const path = require('node:path');
|
||||||
const { PdfBuilder } = require('../core/pdf');
|
const { PdfBuilder } = require('../core/pdf');
|
||||||
const { guideSlug, renderAllImages, LEVEL_LABEL, stepBlocks, codeBlockText } = require('./common');
|
const { guideSlug, renderAllImages, LEVEL_LABEL, stepContentGroups, codeBlockText } = require('./common');
|
||||||
const { htmlToText } = require('../core/util');
|
const { htmlToText } = require('../core/util');
|
||||||
const { htmlToBlocks } = require('../core/htmlblocks');
|
const { htmlToBlocks } = require('../core/htmlblocks');
|
||||||
|
|
||||||
@@ -207,7 +207,8 @@ function exportPdf(ast, outDir, template = {}) {
|
|||||||
pdf.rect(M, y, usableW, 0.8, { fill: [225, 228, 232] });
|
pdf.rect(M, y, usableW, 0.8, { fill: [225, 228, 232] });
|
||||||
y += 8;
|
y += 8;
|
||||||
|
|
||||||
emitBlocks(step, 'before-description');
|
const { before, rest } = stepContentGroups(step);
|
||||||
|
for (const tb of before) emitBlock(tb);
|
||||||
if (step.descriptionHtml) writeDescription(step.descriptionHtml);
|
if (step.descriptionHtml) writeDescription(step.descriptionHtml);
|
||||||
|
|
||||||
const img = images.get(step.stepId);
|
const img = images.get(step.stepId);
|
||||||
@@ -221,8 +222,10 @@ function exportPdf(ast, outDir, template = {}) {
|
|||||||
y += h + 10;
|
y += h + 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const block of stepBlocks(step).filter((item) => item.kind !== 'text')) {
|
for (const block of rest) {
|
||||||
if (block.kind === 'code') {
|
if (block.kind === 'text') {
|
||||||
|
emitBlock(block);
|
||||||
|
} else if (block.kind === 'code') {
|
||||||
const lines = String(codeBlockText(block) || '').split('\n');
|
const lines = String(codeBlockText(block) || '').split('\n');
|
||||||
const lineH = 9 * 1.3;
|
const lineH = 9 * 1.3;
|
||||||
ensure(Math.min(lines.length, 4) * lineH + 12);
|
ensure(Math.min(lines.length, 4) * lineH + 12);
|
||||||
@@ -255,13 +258,10 @@ function exportPdf(ast, outDir, template = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emitBlocks(step, 'after-description');
|
|
||||||
emitBlocks(step, 'after-image');
|
|
||||||
y += 10;
|
y += 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitBlocks(step, position) {
|
function emitBlock(tb) {
|
||||||
for (const tb of stepBlocks(step).filter((b) => b.kind === 'text' && b.position === position)) {
|
|
||||||
const label = `${LEVEL_LABEL[tb.level] || 'Note'}${tb.title ? `: ${tb.title}` : ''}`;
|
const label = `${LEVEL_LABEL[tb.level] || 'Note'}${tb.title ? `: ${tb.title}` : ''}`;
|
||||||
const { items, height: bodyH } = tb.descriptionHtml
|
const { items, height: bodyH } = tb.descriptionHtml
|
||||||
? layoutDescription(pdf, tb.descriptionHtml, usableW - 18, 9.5)
|
? layoutDescription(pdf, tb.descriptionHtml, usableW - 18, 9.5)
|
||||||
@@ -294,7 +294,6 @@ function exportPdf(ast, outDir, template = {}) {
|
|||||||
}
|
}
|
||||||
y += blockH + 6;
|
y += blockH + 6;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fs.mkdirSync(outDir, { recursive: true });
|
fs.mkdirSync(outDir, { recursive: true });
|
||||||
const file = path.join(outDir, `${guideSlug(ast)}.pdf`);
|
const file = path.join(outDir, `${guideSlug(ast)}.pdf`);
|
||||||
|
|||||||
Reference in New Issue
Block a user