diff options
| author | hachem <im@hachem.wtf> | 2026-09-18 13:59:45 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2026-09-18 13:59:45 +0200 |
| commit | 2720a126aa5a8412f8d355f8937cf6c37975be78 (patch) | |
| tree | 1070b2bbc875b6bb56ca1c19e652f882dfe10279 | |
| parent | ab2774b23c66521e13541ab3e361bba95c394a8a (diff) | |
feat: add letter template
| -rw-r--r-- | .gitignore | 4 | ||||
| -rw-r--r-- | Makefile | 68 | ||||
| -rw-r--r-- | lib.typ | 3 | ||||
| -rw-r--r-- | samples/letter.typ | 21 | ||||
| -rw-r--r-- | samples/paper.typ | 39 | ||||
| -rw-r--r-- | templates/letter.typ | 90 | ||||
| -rw-r--r-- | templates/paper.typ | 94 | ||||
| -rw-r--r-- | typst.toml | 4 |
8 files changed, 278 insertions, 45 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6f2fc6d --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +mktypst +*.dSYM +.DS_Store +*.pdf @@ -1,20 +1,72 @@ -NAME := mktypst +BIN := mktypst +PKG := hachem VERSION := 0.1.0 +CC := clang +STD := c17 + +DEBUG ?= 1 +SANITIZE ?= 1 + +CFLAGS := -std=$(STD) \ + -Wall \ + -Wextra \ + -Wshadow \ + -Wpedantic \ + -Wconversion \ + -Wstrict-prototypes \ + -Wsign-conversion \ + -Wmissing-prototypes + +ifeq ($(DEBUG),1) +CFLAGS += -g -fno-omit-frame-pointer +else +CFLAGS += -O2 +endif + +ifeq ($(SANITIZE),1) +CFLAGS += -fsanitize=address,undefined +LDFLAGS += -fsanitize=address,undefined +endif + +PREFIX ?= /usr/local +bindir := $(DESTDIR)$(PREFIX)/bin + ifeq ($(shell uname),Darwin) DATADIR := $(HOME)/Library/Application Support else DATADIR := $(if $(XDG_DATA_HOME),$(XDG_DATA_HOME),$(HOME)/.local/share) endif +pkgdir := $(DATADIR)/typst/packages/local/$(PKG)/$(VERSION) + +all: $(BIN) + +$(BIN): mktypst.c + $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) -PKGDIR := $(DATADIR)/typst/packages/local/$(NAME)/$(VERSION) +install: install-bin install-pkg -install: - mkdir -p "$(PKGDIR)" - cp typst.toml lib.typ README.md LICENSE "$(PKGDIR)"/ - cp -r templates "$(PKGDIR)"/ +install-bin: + $(MAKE) DEBUG=0 SANITIZE=0 clean $(BIN) + install -d $(bindir) + install -m 755 $(BIN) $(bindir)/$(BIN) + +install-pkg: + mkdir -p "$(pkgdir)" + cp typst.toml lib.typ README.md LICENSE "$(pkgdir)"/ + cp -r templates "$(pkgdir)"/ uninstall: - rm -rf "$(DATADIR)/typst/packages/local/$(NAME)/$(VERSION)" + rm -f $(bindir)/$(BIN) + rm -rf "$(DATADIR)/typst/packages/local/$(PKG)/$(VERSION)" + +samples: + @for f in samples/*.typ; do \ + printf ' %s\n' "$${f%.typ}.pdf"; \ + typst compile --root . "$$f" "$${f%.typ}.pdf" || exit 1; \ + done + +clean: + rm -rf $(BIN) $(BIN).dSYM samples/*.pdf -.PHONY: install uninstall +.PHONY: all install install-bin install-pkg uninstall samples clean @@ -1 +1,2 @@ -#import "templates/paper.typ": paper +#import "templates/paper.typ": paper, booktabs +#import "templates/letter.typ": letter diff --git a/samples/letter.typ b/samples/letter.typ new file mode 100644 index 0000000..d3ccad9 --- /dev/null +++ b/samples/letter.typ @@ -0,0 +1,21 @@ +#import "../lib.typ": letter + +#show: letter.with( + sender: ( + name: [Hachem H.], + address: [12 rue de la Paix \ 75002 Paris], + ), + recipient: ( + name: [Département de Musicologie], + address: [Université de Paris \ 75005 Paris], + ), + place: "Paris", + date: "18 septembre 2026", + subject: [candidature spontanée], +) + +Je me permets de vous adresser ma candidature pour un poste de recherche au sein +de votre département. #lorem(35) + +Passionné par la théorie spectrale et la composition, je serais honoré de +contribuer à vos travaux. #lorem(25) diff --git a/samples/paper.typ b/samples/paper.typ new file mode 100644 index 0000000..95ad6a5 --- /dev/null +++ b/samples/paper.typ @@ -0,0 +1,39 @@ +#import "../lib.typ": paper, booktabs + +#show: paper.with( + title: "Les Origines de YHWH", + date: "mars 2026", + authors: ( + (name: "Hachem H.", location: [Paris, France]), + ), + abstract: [ + Cet article soutient que l'origine de Yahweh se comprend au mieux à travers + trois cadres : la « convergence des indices », la compétition de niches + fonctionnelles, et la portabilité cultuelle. + ], +) + += Introduction +Yahweh serait apparu comme une divinité du sud, importée dans les hautes terres +israélites où elle a fusionné avec El. #lorem(35) + +Un second paragraphe, avec alinéa, pour montrer le rythme du texte : la +ponctuation haute est correctement espacée ; les guillemets « aussi ». #lorem(25) + +== La convergence des indices +Trois lignes indépendantes convergent vers une même conclusion. + +#figure( + booktabs( + columns: (auto, auto), + align: (center, left), + header: ([Ligne], [Nature de l'indice]), + [1], [voyelle anormale (morphologie)], + [2], [poésie archaïque (littérature)], + [3], [absence à Ougarit (archéologie)], + ), + caption: [Les trois lignes d'évidence.], +) + += Conclusion +Aucune ligne n'est décisive seule ; leur convergence l'est. #lorem(25) diff --git a/templates/letter.typ b/templates/letter.typ new file mode 100644 index 0000000..361f47b --- /dev/null +++ b/templates/letter.typ @@ -0,0 +1,90 @@ +#let sender-block(sender) = if type(sender) == dictionary { + text(weight: "medium", tracking: 0.03em)[#smallcaps(sender.name)] + if sender.at("address", default: none) != none { + v(0.35em) + text(size: 0.85em, fill: luma(30%))[#sender.address] + } +} else { + sender +} + +#let recipient-block(recipient) = if type(recipient) == dictionary { + recipient.name + if recipient.at("address", default: none) != none { + linebreak() + text(size: 0.9em, fill: luma(30%))[#recipient.address] + } +} else { + recipient +} + +#let letter( + sender: none, + recipient: none, + place: none, + date: none, + subject: none, + opening: [Madame, Monsieur,], + closing: [Veuillez agréer, Madame, Monsieur, l'expression de mes salutations distinguées.], + signature: none, + lang: "fr", + region: "FR", + font: "EB Garamond", + size: 11pt, + doc, +) = { + set page(paper: "a4", margin: (x: 26mm, top: 30mm, bottom: 26mm), numbering: none) + set par(justify: true, leading: 0.72em, spacing: 1.3em) + set text(font: font, size: size, lang: lang, region: region, number-type: "old-style") + + let dateline = if place != none and date != none { + [#place, le #date] + } else if date != none { + [le #date] + } else { + place + } + + let sign = if signature != none { + signature + } else if type(sender) == dictionary { + sender.name + } else { + none + } + + grid( + columns: (1fr, 1fr), + align: (left + top, right + top), + sender-block(sender), + { + recipient-block(recipient) + if dateline != none { + if recipient != none { v(1.4em) } + dateline + } + }, + ) + + v(1.9em) + line(length: 100%, stroke: 0.4pt) + v(1.9em) + + if subject != none { + [#text(weight: "bold")[Objet :] #subject] + v(1.4em) + } + + opening + + v(0.6em) + doc + + v(1.6em) + closing + + if sign != none { + v(3.2em) + align(right, smallcaps(sign)) + } +} diff --git a/templates/paper.typ b/templates/paper.typ index c7658ec..caf33b6 100644 --- a/templates/paper.typ +++ b/templates/paper.typ @@ -1,38 +1,59 @@ -#let paper-title(title, date) = [ - #place(top + center, float: true)[ - #block(width: 100%)[ - #align(center)[ - #text(size: 18pt)[#smallcaps[#title]] \ - #v(0em) - #text(size: 12pt)[--- #smallcaps(date) ---] - ] - ] - ] +#let title-block(title, date) = align(center)[ + #text(size: 18pt)[#smallcaps[#title]] \ + #v(0.15em) + #text(size: 12pt)[--- #smallcaps(date) ---] ] -#let author-block(authors) = [ - #align(center)[ - #for author in authors [ - #author.name \ - #text(style: "italic")[#author.location] - ] +#let author-block(authors) = align(center)[ + #for author in authors [ + #author.name \ + #text(style: "italic")[#author.location] ] - #v(1.2em) ] -#let abstract-block(body) = [ - #block(width: 100%)[ - #text(weight: "bold")[Abstract---] - #body - ] - #v(0.8em) +#let abstract-block(prefix, body) = block(width: 100%, inset: (x: 10%))[ + #set par(justify: true, first-line-indent: 0pt) + #text(size: 9pt)[#text(weight: "bold")[#prefix]#body] +] + +#let frontmatter(title, date, authors, abstract, abstract-prefix) = place( + top + center, + scope: "parent", + float: true, +)[ + #title-block(title, date) + #v(0.7em) + #author-block(authors) + #v(0.9em) + #if abstract != none { + abstract-block(abstract-prefix, abstract) + v(0.7em) + } + #line(length: 100%, stroke: 0.4pt) + #v(0.5em) ] +// a booktabs table: a top rule, a rule under the header, a bottom rule, and +// nothing else. header is the row of heading cells; the rest are body cells. +#let booktabs(columns: auto, align: auto, header: (), ..rows) = table( + columns: columns, + align: align, + stroke: none, + inset: (x: 6pt, y: 4pt), + table.hline(stroke: 0.8pt), + table.header(..header.map(cell => strong(cell))), + table.hline(stroke: 0.4pt), + ..rows.pos(), + table.hline(stroke: 0.8pt), +) + #let paper( title: none, date: none, authors: (), abstract: none, + lang: "fr", + region: "FR", font: "EB Garamond", size: 10pt, doc, @@ -46,18 +67,25 @@ numbering: "- 1/1 -", ) - set par(justify: true, leading: 0.55em) - set text(font: font, size: size) + set par( + justify: true, + leading: 0.62em, + spacing: 0.62em, + first-line-indent: (amount: 1.2em, all: false), + linebreaks: "optimized", + ) + set text(font: font, size: size, lang: lang, region: region, number-type: "old-style") set figure(gap: 0.65em) + set table(inset: (x: 6pt, y: 4pt)) show heading.where(level: 1): it => [ - #v(0.8em) - #text(size: 12pt, weight: "medium")[#align(center)[#smallcaps[#it.body]]] - #v(0.35em) + #v(0.9em) + #align(center)[#text(size: 11pt, weight: "medium")[#smallcaps[#it.body]]] + #v(0.4em) ] show heading.where(level: 2): it => [ - #v(0.6em) + #v(0.7em) #align(right)[#text(size: 10pt, style: "italic")[#it.body]] #v(0.25em) ] @@ -69,14 +97,12 @@ ] show figure.where(kind: table): set text(size: 8.5pt) + show figure.caption: set text(size: 8.5pt) show bibliography: set text(size: 8.5pt) - paper-title(title, date) - author-block(authors) + let abstract-prefix = if lang == "fr" { [Résumé --- ] } else { [Abstract---] } - if abstract != none { - abstract-block(abstract) - } + frontmatter(title, date, authors, abstract, abstract-prefix) doc } @@ -1,7 +1,7 @@ [package] -name = "mktypst" +name = "hachem" version = "0.1.0" entrypoint = "lib.typ" -authors = ["hachem <im@hachem.wtf>"] +authors = ["hachem <contact@hachem.cc>"] license = "MIT" description = "a couple of dumb typst templates" |
