My theme for forester (+plugins)
1import 'ninja-keys';
2import 'katex';
3
4import autoRenderMath from 'katex/contrib/auto-render';
5
6function partition(array, isValid) {
7 return array.reduce(([pass, fail], elem) => {
8 return isValid(elem) ? [[...pass, elem], fail] : [pass, [...fail, elem]];
9 }, [[], []]);
10}
11
12window.addEventListener("load", (event) => {
13 autoRenderMath(document.body)
14
15 const openAllDetailsAbove = elt => {
16 while (elt != null) {
17 if (elt.nodeName == 'DETAILS') {
18 elt.open = true
19 }
20
21 elt = elt.parentNode;
22 }
23 }
24
25 const jumpToSubtree = evt => {
26 if (evt.target.tagName === "A") {
27 return;
28 }
29
30 const link = evt.target.closest('span[data-target]')
31 const selector = link.getAttribute('data-target')
32 const tree = document.querySelector(selector)
33 openAllDetailsAbove(tree)
34 window.location = selector
35 }
36
37
38 [...document.querySelectorAll("[data-target^='#']")].forEach(
39 el => el.addEventListener("click", jumpToSubtree)
40 );
41});
42
43const ninja = document.querySelector('ninja-keys');
44
45fetch("./forest.json")
46 .then((res) => res.json())
47 .then((data) => {
48 const items = []
49
50 const editIcon = '<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M480-120v-71l216-216 71 71-216 216h-71ZM120-330v-60h300v60H120Zm690-49-71-71 29-29q8-8 21-8t21 8l29 29q8 8 8 21t-8 21l-29 29ZM120-495v-60h470v60H120Zm0-165v-60h470v60H120Z"/></svg>'
51 const bookmarkIcon = '<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M120-40v-700q0-24 18-42t42-18h480q24 0 42.5 18t18.5 42v700L420-167 120-40Zm60-91 240-103 240 103v-609H180v609Zm600 1v-730H233v-60h547q24 0 42 18t18 42v730h-60ZM180-740h480-480Z"/></svg>'
52
53 if (window.sourcePath) {
54 items.push({
55 id: 'edit',
56 title: 'Edit current tree in Visual Studio Code',
57 section: 'Commands',
58 hotkey: 'cmd+e',
59 icon: editIcon,
60 handler: () => {
61 window.location.href = `vscode://file/${window.sourcePath}`
62 }
63 })
64 }
65
66 const isTopTree = (addr) => {
67 const item = data[addr]
68 return item.tags ? item.tags.includes('top') : false
69 }
70
71 const addItemToSection = (addr, section, icon) => {
72 const item = data[addr]
73 const title =
74 item.taxon
75 ? (item.title ? `${item.taxon}. ${item.title}` : item.taxon)
76 : (item.title ? item.title : "Untitled")
77 const fullTitle = `${title} [${addr}]`
78 items.push({
79 id: addr,
80 title: fullTitle,
81 section: section,
82 icon: icon,
83 handler: () => {
84 window.location.href = item.route
85 }
86 })
87 }
88
89 const [top, rest] = partition(Object.keys(data), isTopTree)
90 top.forEach((addr) => addItemToSection(addr, "Top Trees", bookmarkIcon))
91 rest.forEach((addr) => addItemToSection(addr, "All Trees", null))
92
93 ninja.data = items
94 });
95
96