typst rewrite part 1

This commit is contained in:
2026-01-18 16:45:36 +01:00
commit 556672f7b7
58 changed files with 1396 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
# dependencies for build.ts and other related nonsense
node_modules
bun.lock
# VSCode configuration
.vscode
# Generated output
public_html

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

9
assets/scripts/fuse.min.js vendored Normal file

File diff suppressed because one or more lines are too long

47
assets/scripts/search.js Normal file
View File

@ -0,0 +1,47 @@
window.onload = async function (ev) {
let data_req = await fetch("/index.json")
let data = await data_req.json()
let fuse = new Fuse(data, {keys: [
"tags",
"id",
"title",
"body"
]
})
async function search(args) {
try {
let x = fuse.search(args)
return x
} catch {
return null
}
}
document.getElementById('searchbox').addEventListener("input",
async function(e) {
let results = document.getElementById('results') // .innerHTML = idx.search(e.target.value))
if (e.target.value == "") {
results.innerHTML = ""
} else {
Promise.race([
search(e.target.value),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(-1)
}, 3000);
})
]).then((r) => {
if (r == null) {
results.innerHTML = "<ul class='sresult'><li class='sresult'><strong>Search results</strong></li><li class='sresult'>An error occured</li></ul>"
} else if (r == -1) {
results.innerHTML = "<ul class='sresult'><li class='sresult'><strong>Search results</strong></li><li class='sresult'>Query timed out</li></ul>"
} else if (r.length == 0) {
results.innerHTML = "<ul class='sresult'><li class='sresult'><strong>Search results</strong></li><li class='sresult'>No result</li></ul>"
} else {
results.innerHTML = "<ul class='sresult'>" + r.map((it) => "<li class='sresult'>" + "<a href=\"/" + it.item.id + ".html\">" + it.item.title + "</a></li>").reduce((a, b) => a + b) + "</ul>"
}
})
}
}
)
}

147
assets/style/common.css Normal file
View File

@ -0,0 +1,147 @@
@import url(/assets/style/fonts.css);
:root {
--bg: #282828;
--bg-accent: #504945;
--fg: #ebdbb2;
--fg-disabled: #bdae93;
--accent: #fe8019;
--note: #b8bb26;
--info: #83a598;
--warn: #fabd2f;
--error: #fb4934;
--font-main: Andika, sans-serif;
--font-mono: Iosevka, monospace;
}
* {
font-family: var(--font-main);
font-feature-settings: "ss13" on;
padding: 0pt;
margin: 0pt;
}
body {
background-color: var(--bg);
color: var(--fg);
}
header {
width: 100%;
background-color: var(--bg-accent);
text-align: center;
}
header h1 a {
text-decoration: none;
}
header nav {
width: 100%;
padding: 0pt, 10pt;
background-color: var(--bg-accent);
justify-items: stretch;
justify-content: space-evenly;
align-items: stretch;
display: flex;
}
nav input {
width: 25vw;
background-color: var(--bg);
margin: 10pt;
color: var(--fg);
}
aside, aside * {
background-color: var(--bg-accent);
}
a {
display: inline;
color: var(--accent)
}
ul.sresult {
width: 50vw;
height: 50vw;
overflow: scroll;
justify-content: center;
position: absolute;
top: 25%;
left: 50%;
transform: translate(-50%, 0%);
background-color: var(--bg-accent);
padding: 10pt
}
li.sresult {
list-style: none;
font-size: 1.5em;
}
aside {
padding: 10pt;
height: min-content;
}
main {
padding: 25pt 10pt;
}
@media (min-width: 800px) {
#main-body {display: flex;}
main {
width: calc(100% - 10em);
}
aside {
margin: 10pt 10pt 10pt 0pt;
width: 10em;
}
}
@media (max-width: 800px) {
main {
width: 100% - 20pt
}
aside { width: 100% - 20pt }
}
/****** Main body styling ******/
main h1 {
font-size: 2em;
font-weight: bold;
}
main li {
list-style-position: inside;
padding: 0 0 0 10pt;
}
main table {
margin: 1em;
}
main table, main td, main tr {
text-align: center;
border-collapse: collapse;
border: 2px solid var(--fg);
}
main td {
padding: 0em 1em;
margin: 0;
}
main .low {
color: var(--fg-disabled);
font-style: italic;
}
main .high {
color: var(--accent);
font-family: inherit;
}
main em {
color: var(--accent)
}
/****** GLOSSES ******/
.gloss, .gloss tr, .gloss td {
stroke: none;
border: none;
text-align: left;
padding: 0 .25em;
}
/****** SCRIPTS ******/
.scr-nahan {
font-family: AndikaAmbNaran;
}

55
assets/style/fonts.css Normal file
View File

@ -0,0 +1,55 @@
/* Andika with the nahan script */
@font-face {
font-family: AndikaAmbNaran;
src: url("../fonts/AndikaAmbNaran.ttf") format("truetype");
}
/* Andika for the rest */
@font-face {
font-family: Andika;
src: url("../fonts/Andika-Bold.ttf") format("truetype");
font-weight: 700;
font-style: normal;
}
@font-face {
font-family: Andika;
src: url("../fonts/Andika-BoldItalic.ttf") format("truetype");
font-weight: 700;
font-style: italic;
}
@font-face {
font-family: Andika;
src: url("../fonts/Andika-Italic.ttf") format("truetype");
font-weight: 400;
font-style: italic;
}
@font-face {
font-family: Andika;
src: url("../fonts/Andika-Medium.ttf") format("truetype");
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: Andika;
src: url("../fonts/Andika-MediumItalic.ttf") format("truetype");
font-weight: 500;
font-style: italic;
}
@font-face {
font-family: Andika;
src: url("../fonts/Andika-Regular.ttf") format("truetype");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: Andika;
src: url("../fonts/Andika-SemiBold.ttf") format("truetype");
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: Andika;
src: url("../fonts/Andika-SemiBoldItalic.ttf") format("truetype");
font-weight: 600;
font-style: italic;
}

96
build.ts Executable file
View File

@ -0,0 +1,96 @@
#!/usr/bin/env -S bun run
import { $ } from "bun";
import { readdir } from "node:fs/promises"
import { parseArgs } from "util";
import { JSDOM } from "jsdom";
import { Dirent } from "node:fs";
import { mkdir, stat } from "node:fs/promises";
function out_path(path: string) {
}
type LogLevel = "INFO"|"WARN"|"ERROR"|"FATAL"
function log(level: LogLevel, message: any) {
const p = Bun.argv[1]?.split("/").slice(-1)[0] ?? "build script";
switch (level) {
case "INFO": console.log(`\x1b[90m${p}: \x1b[1;42;97m [INFO] \x1b[0m ${message}`); break;
case "WARN": console.log(`\x1b[90m${p}: \x1b[1;48;5;208;97m [WARN] \x1b[0m ${message}`); break;
case "ERROR": console.log(`\x1b[90m${p}: \x1b[1;41;97m [ERROR] \x1b[0m ${message}`); break;
case "FATAL": console.log(`\x1b[90m${p}: \x1b[1;41;97m [FATAL] ${message} \x1b[0m`); process.exit(); break;
}
}
async function build_typst_file(file: Dirent) {
let path = file.parentPath + "/" + file.name
let dir = "public_html" + file.parentPath.slice(3)
let slug = path.slice(4, -4)
let outfile = `public_html/${slug}.html`
log("INFO", `Building ${path}`)
await mkdir(dir, {recursive: true})
await $`typst c --features html --format html --root . ${path} ${outfile}`
log("INFO", `Built ${path}`)
}
async function build_all_typst() {
let files = await readdir("src", {withFileTypes: true, recursive: true});
let promises: Promise<void>[] = [];
for (let f of files) {
if (f.isFile() && f.name.endsWith(".typ"))
promises.push(build_typst_file(f))
}
await Promise.all(promises)
}
async function copy_assets() {
log("INFO", "Updating assets")
await $`rm -rf public_html/assets/`
await $`cp -r assets/ public_html/`
}
type IndexEntry = { id: string; title: string; body: string; tags: string;}
async function collect_data(f:string) : Promise<IndexEntry> {
let id = f.slice(12, -5)
log("INFO", `collecting metadata for ${id}`)
let dom = await JSDOM.fromFile(f)
let body = ""
let things = dom.window.document.getElementsByTagName("main")
for (let thing of things) body += thing.textContent;
let title = dom.window.document.getElementById("search-title")?.getAttribute("content") ?? ""
let tags = dom.window.document.getElementById("search-tags")?.getAttribute("content") ?? ""
return {id, title, body, tags}
}
async function gen_index() {
let files = await readdir("public_html", {withFileTypes: true, recursive: true})
let promises : Promise<IndexEntry>[] = [];
for (let f of files) {
if (f.isFile() && f.name.endsWith(".html")) {
promises.push(collect_data(f.parentPath + "/" + f.name));
}
}
let data : IndexEntry[] = await Promise.all(promises)
await Bun.write("public_html/index.json", JSON.stringify(data), {mode: 0o644, createPath: true})
}
const args = parseArgs({
args: Bun.argv,
options: {
"build": {type: "boolean", short: "b"},
"assets": {type: "boolean", short: "a"},
"index": {
short: "i", type: "boolean"
}
},
allowPositionals: true
}).values
if (!args.build && !args.assets && !args.index) {
await build_all_typst()
await copy_assets()
await gen_index()
}
if (args.build) await build_all_typst();
if (args.assets) await copy_assets();
if (args.index) await gen_index();

14
package.json Normal file
View File

@ -0,0 +1,14 @@
{
"name": "wiki-build-tools",
"private": true,
"devDependencies": {
},
"peerDependencies": {
"typescript": "^5"
},
"dependencies": {
"@types/jsdom": "^27.0.0",
"jsdom": "^27.4.0",
"@types/bun": "latest"
}
}

14
src/dict/-ala.typ Normal file
View File

@ -0,0 +1,14 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "-ala")
%dict %word
= Mosici <mos>
%mos
From [[/worlds/Asteron/Classical Nyelaf]] #wl("/dict/ala", mos-cit(""),"cln")
=== Pronunciation <mos-1-pro>
#mos-pro[\*aʟa]
=== Affix <mos-1-affix>
%mos/affix
#mos-cit("")
1. Noun #low[x] arrow Verb "causing the existence of #low[x]"

20
src/dict/ain.typ Normal file
View File

@ -0,0 +1,20 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "ain")
%dict %word
= Mosici <mos>
%mos
From [[/worlds/Asteron/Classical Nyelaf]] #wl("/dict/ainy", [#sn[]], "cln") #low[ainy]
=== Pronunciation <mos-1-pro>
#mos-pro[ɛ̃]
=== Pronoun <mos-1-pronoun>
%mos/pronoun
#mos-cit("")
1. Third person inannimate pronoun
#mos-pron("")
=== Noun <mos-1-noun>
%mos/noun
#mos-cit("")
1. Thing, object
#mos-n("")

15
src/dict/ainilapil.typ Normal file
View File

@ -0,0 +1,15 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "ainilapil")
%dict %word
= Mosici <mos>
%mos
From #wl("/dict/ain", mos-cit(""), "mos-1-noun") + #wl("/dict/ilapil", mos-cit(""), "mos")
=== Pronunciation <mos-1-p>
#mos-pro[ɛ̃neʎapeẅ]
=== Noun <mos-1-noun>
%mos/noun
#mos-cit("") (plural #wl("/dict/ainilapiltee", mos-cit(""), "mos"))
1. Noun, substantive
#mos-n("", pl: "")

13
src/dict/ainilapiltee.typ Normal file
View File

@ -0,0 +1,13 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "ainilapiltee")
%dict
= Mosici <mos>
%mos
=== Pronunciation <mos-1-p>
#mos-pro[ɛ̃neʎapeẅdi]
=== Moun <mos-1-noun>
%mos/noun
#mos-cit("")
1. plural form of #wl("/dict/ainilapil", mos-cit(""), "mos"))

13
src/dict/ainy.typ Normal file
View File

@ -0,0 +1,13 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "ainy")
%dict %word
= Classical Nyelaf <cln>
%cln
=== Pronounciation <cln-1-p>
- /a.inə/
=== Noun <cln-1-noun>
%cln/noun
#sn[] #low[ainy]
1. Thing, object

8
src/dict/ala.typ Normal file
View File

@ -0,0 +1,8 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "ala")
%dict %word
= Classical Nyelaf <cln>
%cln
#sn[] #low[ala] [aɫa]

View File

@ -0,0 +1,13 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "an·oreaiác ila")
%word %dict
= Mosici <mos>
From [[/worlds/Asteron/Classical Nyelaf]] #wl("/dict/oheaiā", sn[], "cln") #low[oheaiā] and the regular formation for language names
=== Pronunciation <mos-1-p>
#mos-pro[ãdoʀeç eʎa]
=== Proper noun <mos-1-proper>
#mos-cit(" ")
1. #reg[Out of Universe] #link("https://www.laghariportals.com/78h")[Oeaiā]
#mos-n(" ", pl: false)

8
src/dict/cihyty.typ Normal file
View File

@ -0,0 +1,8 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "cihyty")
%dict %word
= Classical Nyelaf <cln>
%cln
#sn[] #low[cihyty] [kixətə]

16
src/dict/cirts.typ Normal file
View File

@ -0,0 +1,16 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "cirts")
%word %dict
= Mosici <mos>
%mos
From [[/worlds/Asteron/Classical Nyelaf]] #wl("/dict/cihyty", sn[], "cln") #low[cihyty]
=== Pronunciation <mos-1-p>
#mos-pro[ceɐ̯ts]
=== Noun <mos-1-noun>
%mos/noun
#mos-cit("")
1. Writing, text
2. Document, book
#mos-n("")

16
src/dict/contse.typ Normal file
View File

@ -0,0 +1,16 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "contse")
%word %dict
= Mosici <mos>
%mos
From [[/worlds/Asteron/Classical Nyelaf]] #wl("/dict/contysse", sn[], "cln") #low[contysse]
=== Pronunciation <mos-1-p>
#mos-pro[qõtsɛ]
=== Noun <mos-1-noun>
%mos/noun
#mos-cit("")
1. Novelty, innovation
#mos-n("")

15
src/dict/contseila.typ Normal file
View File

@ -0,0 +1,15 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "contseila")
%word %dict
= Mosici <mos>
%mos
From #wl("/dict/contse", sn[], "mos-1-noun") #low[contse] + #wl("/dict/ila", sn[], "mos-1-verb") #low[ila]
=== Pronunciation <mos-1-p>
#mos-pro[qõtsiʎa]
=== Verb <mos-1-verb>
%mos/verb
#mos-cit("")
1. To present, to announce
#mos-v("")

8
src/dict/contysse.typ Normal file
View File

@ -0,0 +1,8 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "contysse")
%word %dict
= Classical Nyelaf <cln>
%cln
#sn[] #low[contysse] [kontəsːə]

8
src/dict/effyha.typ Normal file
View File

@ -0,0 +1,8 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "effyha")
%word %dict
= Classical Nyelaf <cln>
%cln
#sn[] #low[effyha] [efːəxa]

View File

@ -0,0 +1,15 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "Entec R. Tzietz")
%dict %word
= Mosici <mos>
%mos
=== Pronunciation <mos-1-p>
#mos-pro[ɛ̃dɛx aɐ̯ dʑɛdz]
=== Proper Noun <mos-1-proper>
%mos/proper
#mos-cit("  ")
1. Enderjed, the man, the myth, the legend
#mos-n("  ", pl: false)

21
src/dict/i.typ Normal file
View File

@ -0,0 +1,21 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "i")
%dict
%word
= Mosici <mos>
%mos
From [[/worlds/Asteron/Classical Nyelaf]] #wl("/dict/i", sn[], "cln") #low[i]
=== Pronunciation <mos-1-p>
#mos-pro[e]
=== Particle <mos-1-part>
%mos/particle
#mos-cit("")
1. and
2. also
= Classical Nyelaf <cln>
%cln
#mos-cit("") [i]

28
src/dict/ila.typ Normal file
View File

@ -0,0 +1,28 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "ila")
%dict
%word
= Mosici <mos>
%mos
From [[/worlds/Asteron/Classical Nyelaf]] #wl("/dict/ila", mos-cit(""), "cln")
=== Prononciation <mos-1-pro>
#mos-pro[eʎa]
=== Noun <mos-1-noun>
%mos/noun
#mos-cit("")
1. Language, especially spoken
2. Speech, announcement
3. #poet word
#mos-n("")
=== Verb <mos-1-verb>
%mos/verb
#mos-cit("")
1. #arch to speak, to tell
#mos-v("")
= Classical Nyelaf <cln>
%cln
#mos-cit("") [iɫa]

17
src/dict/ilaala.typ Normal file
View File

@ -0,0 +1,17 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "ilaala")
%dict
%word
= Mosici <mos>
%mos
From #wl("/dict/ila", sn[], "mos") #low[ila] + #wl("/dict/-ala", sn[], "mos") #low[-ala]
=== Pronunciation <mos-1-pro>
#mos-pro[eʎɔʟa]
=== Verb <mos-1-verb>
%mos/verb
#mos-cit("")
1. To speak
#mos-v("")

16
src/dict/ilamócirts.typ Normal file
View File

@ -0,0 +1,16 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "ilamócirts")
%dict
%word
= Mosici <mos>
%mos
From #wl("/dict/ilamós", sn[], "mos") #low[ilamós] + #wl("/dict/cirts", sn[], "mos") #low[cirts]
=== Pronunciation <mos-1-pro>
#mos-pro[eʎamuceɐ̯ts]
=== Noun <mos-1-noun>
%mos/noun
#mos-cit("")
1. Grammar (book)
#mos-n("")

16
src/dict/ilamós.typ Normal file
View File

@ -0,0 +1,16 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "ilamós")
%dict
%word
= Mosici <mos>
%mos
From #wl("/dict/ila", sn[], "mos") #low[ila] + [[/worlds/Asteron/Classical Nyelaf]] #wl("/dict/mōssy", sn[], "cln") #low[mōssy] (see also #wl("/dict/mósnier", sn[], "mos") #low[mósnier])
=== Pronunciation <mos-1-p>
#mos-pro[eʎamus]
=== Noun
%mos/noun
#mos-cit("")
1. Grammar, language rules
#mos-n("")

16
src/dict/ilapil.typ Normal file
View File

@ -0,0 +1,16 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "ilapil")
%dict
%word
= Mosici <mos>
%mos
From [[/worlds/Asteron/Classical Nyelaf]] #wl("/dict/ila", sn[], "cln") #low[ila] #wl("/dict/pilyteny", sn[], "cln") #low[pily(teny)]
=== Pronunciation <mos-1-pro>
#mos-pro[eʎapeẅ]
=== Noun <mos-1-noun>
%mos/noun
#mos-cit("") (plural #wl("/dict/ilapiltee", sn[], "mos") #low[ilapiltee])
1. Word
#mos-n("", pl: "")

13
src/dict/ilapiltee.typ Normal file
View File

@ -0,0 +1,13 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "ilapiltee")
%dict
= Mosici <mos>
%mos
=== Pronunciation <mos-1-p>
#mos-pro[eʎapeẅdi]
=== Moun <mos-1-noun>
%mos/noun
#mos-cit("")
1. plural form of #wl("/dict/ilapil", mos-cit(""), "mos"))

18
src/dict/ipianlei.typ Normal file
View File

@ -0,0 +1,18 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "ipianlei")
%dict
= Mosici <mos>
%word %mos
From the [[/worlds/Asteron/Classical Nyelaf]] phrase #sn[]#wl("/dict/i", sn[], "cln") #low[i] #wl("/dict/piany", sn[], "cln") #low[piany] #wl("/dict/lei", sn[], "cln") #low[lei] #sn[] (and afterwards, two)
=== Pronunciation <mos-1-pro>
#mos-pro[epjãʎi]
=== Noun <mos-1-noun>
%mos/noun
#mos-cit("") (plural #wl("/dict/ipianalei", mos-cit(""), "mos"))
1. Sequence, ordering
#mos-n("", pl: "")

18
src/dict/lei.typ Normal file
View File

@ -0,0 +1,18 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "lei")
%dict
%word
= Mosici <mos>
%mos
From [[/worlds/Asteron/Classical Nyelaf]] #wl("/dict/lei", sn[], "cln") #low[lei]
=== Pronunciation
#mos-pro[ʎi]
=== Numeral <mos-1-numeral>
%mos/numeral
#mos-cit("")
1. two
= Classical Nyelaf <cln>
%cln
#mos-cit("") [ɫe.i]

15
src/dict/mósnier.typ Normal file
View File

@ -0,0 +1,15 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "mósnier")
%dict %word
= Mosici <mos>
%mos
From [[/worlds/Asteron/Classical Nyelaf]] #wl("/dict/mōssy", sn[], "cln") #low[mōssy] + #wl("/dict/niehy", sn[], "cln") #low[niehy]
=== Pronunciation <mos-1-p>
#mos-pro[musɲiɐ̯]
=== Noun <mos-1-noun>
#mos-cit("")
1. Convention, custom
2. Rule (of a game)
#mos-n("")

9
src/dict/mōssy.typ Normal file
View File

@ -0,0 +1,9 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "mōssy")
%dict
%word
= Classical Nyelaf <cln>
%cln
#sn[] #low[mōssy] [moːsːə]

9
src/dict/niehy.typ Normal file
View File

@ -0,0 +1,9 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "niehy")
%dict
%word
= Classical Nyelaf <cln>
%cln
#sn[] #low[niehy] [ni.exə]

15
src/dict/o.typ Normal file
View File

@ -0,0 +1,15 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "o")
%dict %word
= Mosici <mos>
%mos
From onomatopeic origin
=== Pronunciation <mos-1-p>
#mos-pro[o]
=== Particle <mos-1-particle>
#mos-cit("")
1. #reg[After nouns] Vocative marker
2. #reg[After verbs] Imperative marker

8
src/dict/ohaioa.typ Normal file
View File

@ -0,0 +1,8 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "ohaioa")
%word %dict
= Classical Nyelaf <cln>
%cln
#sn[] #low[ohaioa] [oxajo.a]

9
src/dict/oheaiā.typ Normal file
View File

@ -0,0 +1,9 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "oheaiā")
%word %dict
= Classical Neyelaf
%cln
#sn[] #low[oheaiā] [oxe.a.i.aː]
1. #reg[Out of Universe] #link("https://www.laghariportals.com/78h")[Oeaiā]

9
src/dict/oiaō.typ Normal file
View File

@ -0,0 +1,9 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "oiaō")
%word %dict
= Classical Nyelaf <cln>
%cln
#sn[] #low[oiaō] [o.i.a.oː]

15
src/dict/óasonela.typ Normal file
View File

@ -0,0 +1,15 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "óasonela")
%word %dict
= Mosici <mos>
%mos
From [[/worlds/Asteron/Classical Nyelaf]] #wl("/dict/ōas", sn[], "cln") #low[ōas] + #wl("/dict/sonela", sn[], "cln") #low[sonela]
=== Pronunciation <mos-1-p>
#mos-pro[wasõnɛʟa]
=== Verb <mos-1-verb>
%mos/verb
#mos-cit("")
1. To discover
#mos-v("")

9
src/dict/īly.typ Normal file
View File

@ -0,0 +1,9 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "īly")
%dict
%word
= Classical Nyelaf <cln>
%cln
#sn[] #low[īly] [iːɫə]

9
src/dict/īny.typ Normal file
View File

@ -0,0 +1,9 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "īny")
%dict
%word
= Classical Nyelaf <cln>
%cln
#sn[] #low[īny] [iː]

8
src/dict/ōas.typ Normal file
View File

@ -0,0 +1,8 @@
#import "/templates/base.typ": *
#import "/templates/utils/dict.typ": *
#import "/templates/utils/lang-mos.typ": *
#show: conf.with(page-title: "ōas")
%word %dict
= Classical Nyelaf <cln>
%cln
#sn[] #low[ōas] [oːas]

7
src/index.typ Normal file
View File

@ -0,0 +1,7 @@
#import "../templates/base.typ": *
#show: conf.with(page-title: sitename, title-override: "Index")
= Welcome <welcome>
foo bar baz
== H2
=== H3

View File

@ -0,0 +1,4 @@
#import "/templates/base.typ": *
#show: conf.with(page-title: "Classical Nyelaf")
#tag("lang") #tag("cln")
#set heading(numbering: "1.")

View File

@ -0,0 +1,121 @@
#import "/templates/base.typ": *
#import "/templates/utils/gloss.typ": example, gloss
#import "/templates/utils/lang-mos.typ": *
#let high = html.span.with(class: "high")
#show: conf.with(page-title: "Mosici")
%lang %mos
#set heading(numbering: "1.")
#let gloss-opts = (
txt-style: sn,
translation-style: html.span.with(class: "low"),
)
#let g = gloss.with(..gloss-opts)
#let ex = example.with(..gloss-opts)
= Sound ⁊ Letters <sec-sound-letters>
== Phonolgy <sec-phonology>
Mosici has the following phonemes
#table(
columns: 5,
[], [*Labial*], [*Coronal*], [*Palatal*], [*Dorsal*],
[*Nasal*], [m], [n], [], [],
[*Stop*], [p], [t], [], [k],
[*Fricative*], [f v], [s z], [ɕ ʑ], [ʀ],
[*Approximants*], [w], [], [j], [ʟ],
)
#table(
columns: 3,
[], [*Front*], [*Back*],
[*Close*], [i y], [u],
[*Close-Mid*], [e ø], [o],
[*Open-Mid*], [ɛ], [ɔ],
[*Open*], table.cell(colspan: 2)[a],
)
All vowels can also all be long,
There is also the following allophony rules:
- The dorsal approximant is realised as a [] off-glide in coda positions.
- The dorsal fricative is realised as a [ɐ̯] off-glide in coda positions.
- The dorsal fricative is realised as a true fricative [ʁ] in consonant clusters.
- /n/ nasalises a preceding vowel.
- /n/ itself is not pronounced in coda positions.#footnote[still applies nasalisation] <fn-nasal-even-coda>
- Nasalised close vowels are realised as mid-centralised: ĩː ỹː ũ ũː/ [ɪ̃ ɪ̃ː ʏ̃ ʏ̃ː ʊ̃ ʊ̃ː]
- The dorsal plosive approximant are realised as palatal before /i y e j/ #footnote[or their or their long and/or
nasalised variants] <fn-dorsal-assimilation>,
- The dorsal plosive approximant are realised as uvular before ther /u o w/@fn-dorsal-assimilation
- The dorsal plosive approximant are realised as palatal after /e i j/@fn-dorsal-assimilation or in the coda of a
syllable with /e i/@fn-dorsal-assimilation as the nucleus.
- The dorsal plosive approximant are realised as velar otherwise
- Plosives are realised as voiced next to other phonemically voiced consonants.
- Plosives are realised as non-sibilant fricatives of the same place of articulation word finally.
== Coalsecence <sec-coalescence>
Mosici doesn't allow consecutive vowels inside of words. To resolve would-be hiatuses, a coalescence process is used.
This process is historic for all native words, but it still current to resolve diphthongs in loan words and is necessary
to understand to read the written language, as the spelling was fixed before that sound change occurred.
The process goes thusly (before applying the allophony):
1. Group <enumitem-coalesce-start> all consecutive vowels by pairs, starting at near the start of the word
2. Combine all pairs of vowels according to the table below (the first vowel indexes the row, and the second vowel
indexes the column)
3. If any vowel is long, the resulting vowel is long;
4. Repeat from #context link(query(<enumitem-coalesce-start>).first().location())[step 1] until all hiatus has been
resolved.
#table(
columns: 10,
[ ], [*a*], [*ɛ*], [*ɔ*], [*e*], [*ø*], [*o*], [*i*], [*y*], [*u*],
[*a*], [ɔ], [a], [ɔ], [ɛ], [ɛ], [ɔ], [e], [ø], [o],
[*ɛ*], [ɛ], [i], [ø], [i], [e], [ø], [i], [ø], [ø],
[*ɔ*], [ɔ], [ø], [ɔ], [ø], [ø], [o], [ø], [ø], [o],
[*e*], [ɛ], [i], [ø], [i], [e], [ø], [i], [ø], [ø],
[*ø*], [ø], [e], [ø], [e], [y], [ø], [y], [y], [y],
[*o*], [ɔ], [ø], [o], [ø], [ø], [u], [ø], [ø], [u],
[*i*], [ja], [], [], [je], [], [jo], [i], [jy], [ju],
[*y*], [ø], [ø], [ø], [ø], [y], [ø], [i], [i], [y],
[*u*], [wa], [], [], [we], [], [wo], [wi], [y], [u],
)
== The Nahan Script <sec-nahan-script>
Mosici is written in the [[/worlds/Asteron/Nahan Script]] (also named the Polia(h)r alphabet), which is am alphabet
which in Mosici is considered to have the following letters, digraphs and diacriticd letters. The sole diacritic is
called the #sn[] 〈sitrapaóha〉.
#table(
columns: 5,
[Letter], [Transliteration], [Value (IPA)], [Name], [Name (IPA)],
sn[], [p], [/p/], sn[], [[pe]],
sn[], [o], [/o/], sn[], [[us]],
sn[], [l], [/ʟ/], sn[], [[ʟɔ̃]],
sn[], [i], [/e/], sn[], [[iɐ̯nɛ]],
sn[], [a], [/a/], sn[], [[ɔ̃ɸ]],
sn[], [h], [/∅/#footnote[Lengthens a preceeding vowel] <fn-script-h>], sn[], [[apfɛ]],
sn[],
[r],
[/ʀ/],
sn[ #footnote[Literally "sounded 〈base letter〉"] <fn-script-sounded>],
[[fasteɕɛx apfɛ]],
sn[], [c], [/k/], sn[], [[kaẅ]],
sn[], [n], [/n/], sn[], [[nɔẅ]],
sn[], [e], [/e/], sn[], [[istaẅ]],
sn[], [s], [/s/], sn[], [[ɕpaẅ]],
sn[], [z], [/z/], sn[  @fn-script-sounded], [[fasteɕɛx ɕpaẅ]],
sn[], [f], [/f/], sn[], [[fasoː]],
sn[], [v], [/v/], sn[  @fn-script-sounded], [[fasteɕex fasoː]],
sn[], [m], [/m/], sn[], [[miʎɔ]],
sn[], [t], [/t/], sn[], [[tɛɟjo]],
)
= Morphology <morphology>
#ex(
caption: [foo],
txt: [ #high[ ] ],
translit: ([il], high[vionreapt], high[anap], [cirtan]),
phono: ([\[eẅ], high[vjõʀɛpθ], high[ãnaɸ], [ceɐ̯dã\]]),
morphemes: (sc[1s.act], high[eat#sc[.gno.pcp.pat]], high(sc[loctmp.gno]), [write] + sc[.gno.2s]),
translation: [#high[Whenever] I #high[eat], you write],
lbl: "example"
)

66
templates/base.typ Normal file
View File

@ -0,0 +1,66 @@
#let tag = tagname => [ #metadata(tagname) <tag> ]
#let wl(path, txt, frag) = {
let fragtext = if frag == none {""} else {"#" + frag}
let texttext = if txt == none {
path.split("/").at(-1)
} else {txt}
link(path + ".html" + fragtext, texttext)
}
#let conf(
page-title: "",
title-override: none,
subtitle: none,
doc,
) = {
let sitename = [Annwan's Wiki]
// matches [[path|text!fragments]] with opt texts and fragment
let link-re = regex(
"\\[\\[([^\\]\\|!]+)(?:\\|([^\\]\\|!]+))?(?:!([^\\]\\|!]+))?\\]\\]"
)
show figure.where(kind: "gloss"): set figure(supplement: [Example])
show figure.where(kind: "gloss"): set figure.caption(position: top)
show figure: it => {
html.details({
html.summary[*#it.caption.supplement #it.caption.counter.display(it.numbering)*: #it.caption.body]
it.body
})
}
show regex("%[a-z0-9/]+"): it => tag(it.text.slice(1))
show link-re: it => wl(..it.text.match(link-re).captures)
set table(stroke: none)
html.head({
html.link(rel: "stylesheet", href: "/assets/style/common.css")
html.meta(charset: "utf-8")
html.meta(name: "viewport", content: "width=device-width, initial-scale=1")
html.meta(name: "search-title", content: if title-override != none {title-override} else {page-title}, id: "search-title")
context html.meta(content: { let t = query(<tag>).map(it => it.value).join(" "); if type(t) != str {""} else {t}}, name: "search-tags", id: "search-tags")
if title-override != none {
html.title(sitename + " " + title-override)
} else {
html.title(sitename + " " + page-title)
}
html.script(src:"/assets/scripts/fuse.min.js")
html.script(src: "/assets/scripts/search.js")
})
html.header({
html.h1(html.a(href: "/", sitename))
html.nav(html.input(id: "searchbox", type: "text", placeholder: "Search..."))
})
html.div(id: "results")[]
html.div(id: "main-body", {
html.main({
html.h1(page-title)
html.hr()
doc
})
html.aside(outline())
})
}
#let sitename = [Annwan's Wiki]
#let s(script, body) = {
html.span(class: "scr-"+script, body)
}
#let sc = smallcaps

6
templates/utils/dict.typ Normal file
View File

@ -0,0 +1,6 @@
#let reg = (it) => [(#html.span(style: "font-style: italic", it))]
#let poet = reg[poetic]
#let arch = reg[archaic]
#let coll = reg[colloquial]
#let slang = reg[slang]
#let low = html.span.with(class: "low")

39
templates/utils/gloss.typ Normal file
View File

@ -0,0 +1,39 @@
#let gloss(
txt: none,
translit: none,
phono: none,
morphemes: none,
translation: none,
txt-style: it => it,
translit-style: it => it,
phono-style: it => it,
morphemes-style: it => it,
translation-style: it => it,
) = {
assert(type(morphemes) == array)
assert(translation == none or type(translation) == content)
assert(txt == none or type(txt) == content or (type(txt) == array and txt.len() == morphemes.len()))
assert(translit == none or (type(translit) == array and translit.len() == morphemes.len()))
assert(translit == none or (type(phono) == array and phono.len() == morphemes.len()))
html.table(class: "gloss",
{
if type(txt) == content {
html.tr(html.td(colspan: morphemes.len(), txt-style(txt)))
} else if type(txt) == array {
html.tr(txt.map(txt-style).map(html.td).join())
}
if translit != none {
html.tr(translit.map(translit-style).map(html.td).join())
}
if phono != none {
html.tr(phono.map(phono-style).map(html.td).join())
}
html.tr(morphemes.map(morphemes-style).map(html.td).join())
if translation != none { html.tr(html.td(colspan: morphemes.len(),translation-style(translation))) }
}
)
}
#let example(..g, lbl: none, caption: none) = [
#figure(kind: "gloss", caption: caption, gloss(..g)) #if lbl != none {label(lbl)}
]

View File

@ -0,0 +1,129 @@
#import "/templates/base.typ"
#let mos-sec = [
= Mosici <mos>
#base.tag("word") #base.tag("mos")
]
#let sn = base.s.with("nahan")
#let mos-pro(ipa) = [
- #base.wl("/worlds/Asteron/Mosici", [Standard], none) [#ipa]
]
#let mos-translit(s) = {
s .replace("", "a")
.replace("", "á")
.replace("", "c")
.replace("", "e")
.replace("", "é")
.replace("", "f")
.replace("", "h")
.replace("", "i")
.replace("", "í")
.replace("", "l")
.replace("", "m")
.replace("", "n")
.replace("", "o")
.replace("", "ó")
.replace("", "p")
.replace("", "r")
.replace("", "s")
.replace("", "t")
.replace("", "u")
.replace("", "v")
.replace("", "z")
.replace("", ",")
.replace("", "·")
.replace("", "")
}
#let mos-cit(t) = [#sn(t) #html.span(class: "low", mos-translit(t))]
#let mos-nstem(w) = {
if w.ends-with("") {(w.clusters().slice(0, -2).join(), "")}
else if w.ends-with("") {(w.clusters().slice(0, -2).join(), "")}
else if w.ends-with("") {(w.clusters().slice(0, -2).join(), "")}
else if w.ends-with("") {(w.clusters().slice(0, -2).join(), "")}
else if w.ends-with("") {(w.clusters().slice(0, -1).join(), "")}
else if w.ends-with("") {(w.clusters().slice(0, -1).join(), "")}
else {(w, "")}
}
#let mos-vstem(w) = w.clusters().slice(0, -1).join()
#let mos-pluralise(w) = {
// find index of last vowel
let revw = w.rev()
let pos = revw.position(regex("[]"))
let v = revw.at(pos)
if v == "" {v = ""}
if v == "" {v = ""}
if v == "" {v = ""}
if v == "" {v = ""}
revw = revw.slice(0, pos) + v + revw.slice(pos)
revw.rev()
}
#let mos-n(sg, pl: none) = {
let pr = if pl == false {""} else if pl != none {pl} else {mos-pluralise(sg)}
let (ps, pv) = mos-nstem(pr)
let (ss, sv) = mos-nstem(sg)
let c(it) = [#base.s("nahan", it) \ #html.span(class: "low", mos-translit(it))]
html.details({
html.summary[ *Declension for* _#mos-cit(sg)_ #if pl != none and pl != false [*Irr. pl. stem* _#mos-cit(pl)_] else if pl == false [*(Uncountable)*]]
table(columns: if pl != false {3} else {2},
..if pl != false { ([],
base.sc[*sg*], base.sc[*pl*],)} else {()},
base.sc[*age*], c(sg), ..if pl != false {(c(pr),)} else {()},
base.sc[*pat*], c(ss + ""), ..if pl != false {(c(ps + ""),)} else {()},
base.sc[*gen*], c(ss + ""), ..if pl != false {(c(ps + ""),)} else {()},
base.sc[*dat*], c(ss + sv + ""), ..if pl != false {(c(ps + pv + ""),)} else {()},
base.sc[*abl*], c(ss + ""), ..if pl != false {(c(ps + ""),)} else {()},
)
})
}
#let mos-v(w) = {
let s = mos-vstem(w)
let c(it) = [#base.s("nahan", it) \ #html.span(class: "low", mos-translit(it))]
html.details({
html.summary[*Conjugation for* _#mos-cit(w)_]
table(columns: 5,
[], base.sc[*prs*], base.sc[*pst*], base.sc[*fut*], base.sc[*gno*],
base.sc[*1s*], c(s+""), c(s+""), c(s+""), c(s+""),
base.sc[*2s*], c(s+""), c(s+""), c(s+""), c(s+""),
base.sc[*3sa*], c(s+""), c(s+""), c(s+""), c(s+""),
base.sc[*3si*], c(s+""), c(s+""), c(s+""), c(s+""),
base.sc[*1pi*], c(s+""), c(s+""), c(s+""), c(s+""),
base.sc[*1pe*], c(s+""), c(s+""), c(s+""), c(s+""),
base.sc[*2p*], c(s+""), c(s+""), c(s+""), c(s+""),
base.sc[*3pa*], c(s+""), c(s+""), c(s+""), c(s+""),
base.sc[*3pi*], c(s+""), c(s+""), c(s+""), c(s+""),
base.sc[*inf*], c(s+""), c(s+""), c(s+""), c(s+""),
base.sc[*pcp.sg*], c(s+""), c(s+""), c(s+""), c(s+""),
base.sc[*pcp.pl*], c(s+""), c(s+""), c(s+""), c(s+"")
)
})
}
#let mos-pron(this) = {
let c(k, h: false) = if h and k != this [
#base.wl("dict/"+mos-translit(k), base.s("nahan", k), "mos") \ #html.span(class: "low", mos-translit(k))
] else [
#base.s("nahan", k) \ #html.span(class: "low", mos-translit(k))
]
html.details({
html.summary[Mosici Pronouns]
table(columns: 6,
[], base.sc[*agt*], base.sc[*pat*], base.sc[*gen*], base.sc[*dat*], base.sc[*abl*],
base.sc[*1s*], c(h: true, ""), c(""), c(""), c(""), c(""),
base.sc[*1p*], c( ""), c(""), c(""), c(""), c(""),
base.sc[*2s*], c(h: true, ""), c(""), c(""), c(""), c(""),
base.sc[*2p*], c( ""), c(""), c(""), c(""), c(""),
base.sc[*3sa*], c(h: true, ""), c(""), c(""), c(""), c(""),
base.sc[*3pa*], c( ""), c(""), c(""), c(""), c(""),
base.sc[*3si*], c(h: true, ""), c(""), c(""), c(""), c(""),
base.sc[*3pi*], c( ""), c(""), c(""), c(""), c(""),
base.sc[*dem.sg*], c(h: true, ""), c(""), c(""), c(""), c(""),
base.sc[*dem.pl*], c( ""), c(""), c(""), c(""), c(""),
base.sc[*q*], c(h: true, ""), c(""), c(""), c(""), c(""),
)
})
}

186
templates/utils/notes.typ Normal file
View File

@ -0,0 +1,186 @@
/*
Keep track of a running note counter, and associated notes.
*/
#let note_state_prefix = "notes-"
#let note_default_group = "default"
#let note_default_display_fn(note) = {
h(0pt, weak: true)
super([[#note.index]])
}
#let add_note(
// The location of the note. This is used to derive
// what the note counter should be for this note.
loc,
// The note itself.
text,
// The offset which will be added to the 0-based counter index
// when the index stored in the state.
offset: 1,
// the display function that creates the returned content from put.
// Put can't return a pure index number because the counter
// and state updates need to output content.
display: note_default_display_fn,
// The state group to track notes in.
// A group acts independent (both counter and set of notes)
// from other groups.
group: note_default_group
) = {
let s = state(note_state_prefix + group, ())
let c = counter(note_state_prefix + group)
// find any existing note that hasn't been printed yet,
// containing the exact same text:
let existing = s.at(loc).filter((n) => n.text == text)
// If we found an existing note use that,
// otherwise the note is the current location's counter + offset
// and the given text (the counter is 0-based, we want 1-based indices)
let note = if existing.len() > 0 {
existing.first()
} else {
(text: text, index: c.at(loc).first() + offset, page: loc.page())
}
// If we didn't find an existing index, increment the counter
// and add the note to the "notes" state.
if existing.len() == 0 {
c.step()
s.update(notes => notes + (note,))
}
// Output the note marker
display(note)
}
// get notes at specific location
#let get_notes(loc, group: note_default_group) = {
state(note_state_prefix + group, ()).at(loc)
}
// Reset the note group to empty.
// Note: The counter does not reset by default.
#let reset_notes(group: note_default_group, reset_counter: false) = {
if reset_counter {
counter(note_state_prefix + group).update(0)
}
state(note_state_prefix + group, ()).update(())
}
//
// Helpers for nicer in-document ergonomics
//
#let render_notes(fn, group: note_default_group, reset: true, reset_counter: false) = {
locate(loc => fn(get_notes(loc, group: group)))
if reset {
reset_notes(group: group, reset_counter: reset_counter)
}
}
// Create a new note at the current location
#let note(note, ..args) = {
locate((loc) => add_note(loc, note, ..args))
}
// The quick-start option that outputs something useful by default.
// This is a sane-defaults call to `render_notes`.
#let notes(
size: 8pt,
font: "Roboto",
line: line(length: 100%, stroke: 1pt + gray),
padding: (top: 3mm),
alignment: bottom,
numberings: "1",
group: note_default_group,
reset: true,
reset_counter: false
) = {
let render(notes) = {
if notes.len() > 0 {
set align(alignment)
block(breakable: false, pad(..padding, {
if line != none { line }
set text(size: size, font: font)
for note in notes {
[/ #text(font: "Roboto Mono")[[#numbering(numberings, note.index)]]: #note.text]
}
}))
}
}
render_notes(group: group, reset: reset, reset_counter: reset_counter, render)
}
//
// Examples
//
#set page(height: 5cm, width: 15cm)
= Example
- Having a flexible note-keeping system is important #note[Citation needed]
- It's pretty easy to implement with Typst #note[Fact]
- Everyone really likes the name "Typst" #note[Citation needed]
// Print notes since last print:
#notes()
#pagebreak()
These notes won't be printed on this page, so they accumulate onto next page.
- Hello World #note[Your first program]
- Foo Bar #note[Does not serve beverages]
#pagebreak()
- Orange #note[A Color]
- Blue #note[A Color]
// Notice that the "Citation needed" gets a new index
// because we've re-used it since we printed the initial "Citation needed"
- All colors are great #note[Citation needed]
#notes()
#pagebreak()
#set page(
height: 8cm,
footer: notes(padding: (bottom: 5mm)),
margin: (rest: 5mm, bottom: 3cm)
)
= Footnotes
It is of course also possible to place the notes _in_ the page footer.
This is the way to implement footnotes.
- Black#note[Debateably a color]
- White#note[Debateably a color]
#pagebreak()
- Orange#note[A Color]
- Blue#note[A Color]
- Purple#note[Also a color]
#pagebreak()
= Note groups
This page still has footnotes (using the default note group)
but we can also name a new group for custom notes.
#let mynote = note.with(group: "custom")
#let mynotes = notes.with(
group: "custom",
font: "Comic Neue",
size: 12pt,
numberings: "a.",
line: none,
alignment: right + top
)
- This is in it's own group#mynote[Custom]
- Regular footnote here#note[Regular footnote]
- Same custom note#mynote[Custom]
#mynotes()