Merge branch 'main' of git.learnjsthehardway.com:learn-javascript-the-hard-way/bandolier-template

main
Zed A. Shaw 10 months ago
commit a09a9a5766
  1. 2
      admin/bando/demos/StackLayer.svelte
  2. 90
      commands/pdfpresgen.js
  3. 1
      commands/templates/emails/config.js

@ -6,8 +6,6 @@
display {
width: 100%;
border: 1px solid var(--value0);
display: flex;
flex-direction: row;
}
first {

@ -1,12 +1,11 @@
// you may not need all of these but they come up a lot
import fs from "fs";
import assert from "assert";
import logging from '../lib/logging.js';
import glob from "fast-glob";
import path from "path";
import template from "lodash/template.js";
import { defer } from "../lib/api.js";
import PDFDocument from "pdfkit";
import assert from "assert";
import { mkdir_to, glob, changed } from "../lib/builderator.js";
const log = logging.create(import.meta.url);
@ -14,7 +13,7 @@ const title_box = { x: 17, y: 415, width: 405, align: "center" };
const summary_box = { width: 405, height: 540 };
const main_title = { align: "center", width: 1196, height: 883, x: 586, y: 99};
const main_box = { width: 928, height: 535, x: 720, y: 323};
const FORCE = false;
export const description = "Generates a PDF presentation from an input .md file and a background template."
@ -22,23 +21,16 @@ export const description = "Generates a PDF presentation from an input .md file
export const options = [
["--heading-font <path>", "Font file to use for headings.", "static/fonts/VictorMono-Bold.ttf"],
["--body-font <path>", "Font file to use for body text.", "static/fonts/VictorMono-Medium.ttf"],
["--output <path>", "The output .pdf file to write. Defaults to <input>.pdf"],
["--no-exit", "Normally only used when called directly from other commands."],
["--force", "Force the generation no matter what.", FORCE]
]
// put required options in the required variable
export const required = [
["--input <path>", "The input .md file for the generated presentation."],
["--input <path>", "The input .md file _GLOB_ for the source files."],
["--template <path>", "The background template image to use."],
]
// handy function for checking things are good and aborting
const check = (test, fail_message) => {
if(!test) {
log.error(fail_message);
process.exit(1);
}
}
export const start_pdf = (opts) => {
const doc = new PDFDocument({
font: "Courier",
@ -60,6 +52,16 @@ export const start_pdf = (opts) => {
return [doc, out_stream];
}
const valign = (doc, text, options) => {
assert(options.y !== undefined, "Missing y in options");
assert(options.height !== undefined, "Missing height in options");
const h = doc.heightOfString(text, options);
const start = options.y + (0.5 * (options.height - h));
return start;
}
const write_page = (doc, template, content) => {
// place the background image
doc.image(template, 0, 0, {
@ -100,19 +102,43 @@ const write_page = (doc, template, content) => {
} else if(content.type == "title-only") {
// it's a title only slide
doc.fontSize(160);
doc.font("heading").text(content.slide_title, main_title.x, main_title.y + (main_title.height / 3.5), main_title);
const title_start = valign(doc, content.slide_title, main_title);
doc.font("heading").text(content.slide_title, main_title.x, title_start, main_title);
} else {
// this handles title-text slides, and anything else
// if I put a # I want this to be a subtitle
doc.fontSize(120);
// add the title/body text
doc.font("heading").text(content.slide_title, main_title.x, main_title.y, main_title);
doc.font("heading");
// if I put a # I want this to be a subtitle
if(content.slide_body.startsWith("#")) {
// calculate the title height
let title_start = valign(doc, content.slide_title, main_title);
// calculate 1 line for the move down
doc.fontSize(100);
doc.font("body");
title_start -= doc.heightOfString("H", main_title);
doc.fontSize(120);
// add the title/body text
doc.font("heading").text(content.slide_title, main_title.x, title_start, main_title);
doc.fontSize(100);
const trim_body = content.slide_body.slice(1).trim();
doc.font("body").text(trim_body, main_box.x, main_box.y, {align: "center", ...main_box});
doc.moveDown(1);
doc.font("body").text(trim_body, {
align: "center",
});
} else {
doc.fontSize(120);
// add the title/body text
doc.font("heading").text(content.slide_title, main_title.x, main_title.y, main_title);
doc.moveDown(1);
doc.fontSize(60);
doc.font("body").text(content.slide_body, main_box.x, main_box.y, main_box);
}
@ -168,16 +194,13 @@ const parse_input = (input) => {
const make_pdf_path = (input) => {
const result = path.parse(input);
return path.join(result.dir, `${result.name}.pdf`);
const target = path.join(result.dir, `${result.name}.pdf`);
mkdir_to(target);
return target;
}
const generate_presentation = (opts, waiting) => {
try {
if(!opts.output) {
opts.output = make_pdf_path(opts.input);
}
const [doc, out_stream] = start_pdf(opts);
out_stream.on("finish", () => waiting.resolve());
@ -203,16 +226,21 @@ const generate_presentation = (opts, waiting) => {
}
export const main = async (opts) => {
const in_files = glob.sync(opts.input);
const in_files = glob(opts.input);
for(let file of in_files) {
console.log(file);
const waiting = defer(file);
const settings = {...opts};
settings.input = file;
generate_presentation(settings, waiting);
await waiting;
settings.output = make_pdf_path(settings.input);
if(opts.force || changed(settings.input, settings.output)) {
const waiting = defer(file);
generate_presentation(settings, waiting);
await waiting;
} else {
console.log("SKIP", settings.input);
}
}
process.exit(0);
if(!opts.noExit) process.exit(0);
}

@ -1,3 +1,4 @@
/* __FOOTGUN__ Don't put anything secret in here. */
export const company = {
owner: 'Cool Coder',
product: 'Super Product',

Loading…
Cancel
Save