From: Lady Date: Sat, 23 Sep 2023 23:19:59 +0000 (-0400) Subject: Support “timeline” definition lists X-Git-Tag: 0.4.1~2 X-Git-Url: https://git.ladys.computer/GitWikiWeb/commitdiff_plain/87a2b5d184d577cdce9611e7f7563126dae359e6?ds=inline Support “timeline” definition lists These make it easier to construct timelines by just doing {.timeline} : 1972-01-01 - Here is a thing which happened on Jan 01 1972 : 1972-12-31 - Here is a thing which happened on Dec 31 1972 There’s a lot of work which could be done to style these, but it’s at least semantically appropriate. --- diff --git a/build.js b/build.js index fa0b836..2381a51 100644 --- a/build.js +++ b/build.js @@ -42,7 +42,7 @@ import { JSON_SCHEMA, parse as parseYaml, } from "https://deno.land/std@0.196.0/yaml/mod.ts"; -import djot from "npm:@djot/djot@0.2.3"; +import djot from "npm:@djot/djot@0.2.4"; import { Parser } from "npm:htmlparser2@9.0.0"; import { DomHandler, Element, Text } from "npm:domhandler@5.0.3"; import * as domutils from "npm:domutils@3.1.0"; @@ -229,6 +229,115 @@ class GitWikiWebPage { djot.applyFilter(ast, () => { let titleSoFar = null; // used to collect strs from headings return { + definition_list: { + enter: (e) => { + const attributes = e.attributes ?? {}; + if ( + (attributes.class ?? "").split(/\s/gu).includes( + "timeline", + ) + ) { + const years = new Map(); + for ( + const { children: [{ children: termChildren }, defn] } + of e.children + ) { + const { label, year } = (() => { + if (termChildren.length != 1) { + return { label: termChildren, year: termChildren }; + } else { + const str = termChildren[0]; + if (str.tag != "str") { + return { + label: termChildren, + year: termChildren, + }; + } else { + const { text } = str; + return { + label: text, + year: + /^([0-9X]{4})(?:-[0-9X]{2}(?:-[0-9X]{2})?)?$/u + .exec(text)?.[1] ?? text, + }; + } + } + })(); + const yearList = (() => { + const result = { + tag: "bullet_list", + tight: false, + style: "-", + children: [], + }; + if (years.has(year)) { + const yearMap = years.get(year); + if (yearMap.has(label)) { + return yearMap.get(label); + } else { + yearMap.set(label, result); + return result; + } + } else { + years.set(year, new Map([[label, result]])); + return result; + } + })(); + const misc = { tag: "list_item", children: [] }; + for (const child of defn.children) { + if (child.tag == "bullet_list") { + yearList.children.push(...child.children); + } else { + misc.children.push(child); + } + } + if (misc.children.length > 0) { + yearList.children.unshift(misc); + } else { + /* do nothing */ + } + } + const sorted = [...years].sort(([a], [b]) => + typeof a != "string" || isNaN(a) || + typeof b != "string" || isNaN(b) || +a == +b + ? 0 + : 1 - 2 * (+a < b) + ); + sorted.forEach((pair) => + pair[1] = [...pair[1]].sort(([a], [b]) => + 1 - 2 * (a < b) + ) + ); + return { + tag: "div", + attributes, + children: sorted.flatMap(([year, yearDef]) => [ + rawBlock`
`, + rawBlock``, + ...(Array.isArray(year) ? year : [str`${year}`]), + rawBlock``, + rawBlock`
`, + ...yearDef.map(([label, list]) => ({ + tag: "div", + children: [ + rawBlock`
`, + ...(Array.isArray(label) ? label : [str`${label}`]), + rawBlock`
`, + rawBlock`
`, + list, + rawBlock`
`, + ], + })), + rawBlock`
`, + rawBlock`
`, + ]), + }; + } else { + /* do nothing */ + } + }, + exit: (_) => {}, + }, hard_break: { enter: (_) => { if (titleSoFar != null) {