Skip to content

Commit 55be347

Browse files
authored
pc-letter:0.2.0 (#2730)
1 parent a382e4a commit 55be347

20 files changed

+1714
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Copyright 2025 Florian Breit
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4+
5+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6+
7+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# `pc-letter`: A simple letter template for personal correspondence.
2+
3+
The `pc-letter` template allows you to effortlessly write letters for personal correspondence in Typst that will have a classic feel about them yet largely follow contemporary format guidance (e.g. compatible with DIN 5008's recommendations for personal correspondence).
4+
5+
## Features
6+
7+
- **Localisation options**: Comes with built-in localisation options for various languages and regions which trigger auto-adjustment of many layout option.
8+
- **Adjustable style**: `pc-letter` provides numerous options to tweak fonts, font-sizes, colours etc. to your liking.
9+
- **Optional fields when you need them**: The template provides optional fields for a reference number, listing enclosed documents, and carbon copy recipients.
10+
- **Context aware page numbering**: No need to manually configure, `pc-letter` will add page numbering for you if your content flows over a single page.
11+
- **Print vs digital variants**: Easily switch between variants tweaked for printing or sending out digital-only correspondence.
12+
13+
<a href="./thumbnail.png"><img src="./thumbnail.png" width="250px" alt="Example of a letter written with pc-letter."></a>
14+
15+
## Usage
16+
17+
To use the `pc-letter` template, just import it, initialise it, and add your content. Here's a minimal working example:
18+
19+
```typst
20+
#import "@preview/pc-letter:0.2.0"
21+
22+
#let letter = pc-letter.init(
23+
author: (
24+
name: "Jane Smith",
25+
address: ("Tiny House", "12 Eagle Lane", "New Quay SA45 4FH"),
26+
phone: "015 4523 4567",
27+
28+
)
29+
)
30+
31+
#show: letter.letter-style
32+
33+
#(letter.address-field)[
34+
Mr Reed A. Lott\
35+
Sunnyhill Cottage\
36+
St Davids\
37+
Haverfordwest SA62 9QB
38+
]
39+
40+
Dear Reed,
41+
42+
I have recently come across a nice letter template for _Typst_ called `pc-letter`. Since I know that you have a penchant for physical letters, I thought I would use that as an excuse to send a few words your way.
43+
44+
#(letter.valediction)[So long,]
45+
```
46+
47+
For more examples, see the Repo's [`examples/`](./examples/) folder
48+
49+
## Arguments
50+
51+
The `pc-letter.init()` function takes the following arguments:
52+
53+
- `author` (required): A dictionary with the fields `name` (str), `address` (array[str] of address components), `phone` (str, with spaces to group digits), and `email` (str).
54+
- `title` (optional): A string that will be used as a document title (in the document metadata only, it will not appear anywhere on the letter), or `none`. Default: `none`.
55+
- `date` (optional): A `datetime` object with the date of the letter. Defaults to the current date if not provided or set to `auto`.
56+
- `place-name` (optional): A place name, usually the town or city where the letter was written.
57+
- `style` (optional): A dictionary with various style options you can modify. The dictionary may have the following fields:
58+
- `locale.lang`: The two-letter language code of the language the letter is (mainly) written in. Default: `"en"`.
59+
- `locale.region`: The two-letter region code of the letter's locale. Default: `"GB"`.
60+
- `medium`: One of the two options `"print"` or `"digital"`. If `"print"` is selected, the page will be optimised for printing out, while the `"digital"` option makes some adjustments to make the letter appear more pleasant if it is only to be distributed digitally (e.g. via email), such as making the page background fill a slightly warm off-white.
61+
- `text.font`: The typeface that should be used for the letter. The template has mainly been designed to work well with serif fonts and expects the chosen font to support font features such as true smallcaps. By default, `pc-letter` will use the first available of the fonts *Minion Pro*, *Gentium*, *Libertinus Serif*, *Vollkorn* and as a last resort *Times New Roman*.
62+
- `text.size.normal`: The font-size to be used for normal text. Default: 11pt.
63+
- `text.size.small`: The font-size to be used for areas where it should be
64+
just slightly smaller than normal-size. Default: 10pt.
65+
- `text.size.tiny`: The smallest font-size used by the template. Default: 8pt.
66+
- `text.fill.headline`: The colour to be used for the author's name on the letterhead. Default #800022, a deep burgundy.
67+
- `text.fill.faded`: The colour to be used for text (and some lines) that should appear slightly less prominent compared to adjacent text. Default: 80% gray.
68+
- `alignment.address-field`: Whether to align the address field `left` or `right`. Default: `auto`.
69+
- `alignment.date-field`: How to align the date field. Horizontally `left`, `center` or `right`, and vertically `top`, `bottom` or `horizon` (`horizon` aligns it just above the first falzmarke). Default: `auto`.
70+
- `alignment.headings`: Whether to align headings (first and second level) flush `left` or `center`-ed. Default: `auto`.
71+
- `alignment.reference-field`: How to align the reference field. Horizontally `left` or `right`, and vertically `top`, `bottom` or `horizon` (`horizon` aligns it just above the first falzmarke). Default: `auto`.
72+
- `alignment.valediction`: Whether the valediction at the end of the letter should appear flush `left`, or indented to the `right` half of the page. Default: `auto`.
73+
- `page.fill`: A background fill colour for the page(s). If set to `auto` the value will be determined based on the value for `medium`: blank for print, #faf9f0 (a light, warm off-white) for digital. Default: `auto`.
74+
- `date.format`: A Typst date format string (e.g. `"[year]-[month pad:zero]-[day pad:zero]"`) or `auto`, in which case the template tries to pick something appropriate based on the `locale` setting. Default: `auto`.
75+
- `components.place-name.display`: Whether to display the place name next to the date (`true` or `false`). Note that even if this is set to `true`, a place name is only shown on the letter if it is specified as an argument to `pc-letter.init()`. Default: `auto`.
76+
- `components.place-name.pattern`: A pattern to format the place name, where `"[place-name]"` will be replaced with the place name. Default: `"[place-name],"`.
77+
- `components.return-address-field.display`: Whether to display the return address field immediately on top of the recipient's address or not (`true` or `false`). Default: `auto`.
78+
79+
## Localisations
80+
81+
Different languages and regions have different expectations for the layout of correspondence and use different labels for various fields (such as carbon-copy, attachments, reference, etc.).
82+
83+
`pc-letter` tries to be both versatile and helpful by auto-adjusting its default layout options and translating default labels depending on the specified locale (see the `style.locale.lang` and `style.locale.region` options above).
84+
85+
So for example, if you set `style.locale` to `(lang: "de", region: "AT")`, the recipient's address will be set on the left, dates in January will show "Jänner" for the month's name, headings will be left-aligned, and cc recipients preceded by "In Kopie:". Conversely, if you set it to `(lang: "fr", region: "FR")`, the recipient's address will be set to the right and without return address information, the date will be in French (e.g. "A Paris, le 2 juin 2025"), and attachments will be preceded by "pj:" (pièces jointes).
86+
87+
Currently supported localisations:
88+
- `cy`: Welsh
89+
- `de`: German
90+
- `de-AT`: German (Austria)
91+
- `en`: English
92+
- `en-GB`: English (UK) **[default]**
93+
- `es`: Spanish
94+
- `es-ES`: Spanish (Spain)
95+
- `fr`: French
96+
97+
For examples showing various localised versions, see the Repo's [`examples/`](./examples/) folder.
98+
99+
Contributions of further localisations &mdash; as well as corrections to any already included &mdash; are very welcome!
100+
101+
Please note that `pc-letter` currently only supports A4 paper, so is currently of limited use for those who use the US letter/ANSI A paper size. While I have no specific plans to do this yet, I might well implement this in the future, particularly if there is a use case.
102+
103+
## Fields and functions
104+
105+
As shown in the example above, `pc-letter.init()` returns a dictionary of functions that can be used to add various fields to your letter and help with formatting your text.
106+
107+
*Important:* To call any of these functions, you have to enclose them in parentheses. So it should be `#(letter.spaced-smallcaps)[My Text]`✔️ rather than `#letter.spaced-smallcaps[My Text]`💣, the latter of which will produce an error. This is currently a limitation of Typst's module-model and might change in future.
108+
109+
Here's a list of the available fields and functions, assuming you have used `#let letter = pc-letter.init()` to collect them in the variable `letter`:
110+
111+
- `letter.spaced-smallcaps(content)`: Selects the font's true smallcaps option and spaces the letters slightly apart for a more prominent effect.
112+
- `letter.thin-space()`: A weak thin-space, narrower than a normal inter-word space, such as it is used to separate blocks of numbers in phone numbers.
113+
- `letter.en-space()`: A space of length 0.5em, slightly wider than a regular inter-word space. Used where a little extra space adds more visual clarity.
114+
- `letter.phone-number(number)`: Wraps the phone number as a clickable telephone-link (`tel:XXXXXXXXXXX`) and adjusts the inter-word spacing such that if regular spaces are used to group digits they look a little neater.
115+
- `letter.email-address(email)`: Wraps the email address as a clickable email-link (`mailto:[email protected]`).
116+
- `letter.web-address(dest, include-schema: true)`: Wraps a URL as a clickable link. If the optional `include-schema` argument is set to `false`, the link text will hide the initial schema element (e.g. `"https://"`).
117+
- `letter.falzmarken()`: Can be optionally used at the start of the document to add folding marks to the left margin of the first page (two marks where you can fold the A4 paper to fit it into a DL, C5 or C6 envelope, which may be windowed). A third mark is added at the centre of the page, which can be used to centre-fold it but is principally meant to align a hole punch such that it is centred vertically.
118+
- `letter.address-field(recipient-address, return-address-field: auto)`: Used to set the recipient's address on the first page. The recipient's address should normally be no more than 6 lines (though it won't be clipped if it is longer) and you should include manual line-breaks. The optional `return-address-field` argument can be used to overwrite the content that appears in tiny text above the recipients address, normally used to provide a return address in case the letter cannot be delivered.
119+
- `letter.reference-field(reference, supplement: "Ref:")`: Can be used to optionally add a reference at the same height as the date. This can be useful when replying to correspondence from e.g. a business or the government, where the other party has given you a reference number to quote on future correspondence. The `supplement` argument can be used to optionally replace the standard text "Ref:" with something of your choice.
120+
- `letter.letter-style`: Encapsulates the main layout of the letter template. Should be used with a show rule (e.g. `#show: letter.letter-style` -- note the absence of the parentheses!) to activate the template after initialising it.
121+
- `letter.valediction(valediction, signature: none, name: auto)`: Adds a properly formatted valediction (a closing formula) at the end of the letter. The `valediction` parameter includes the acutal valediction (e.g. `(letter.valediction)[Yours faithfully,]` or `(letter.valediction)[Yours sincerely,]`) though you may of course also chose something a little more old-fashioned like `(letter.valediction)[I remain, Sir, your humble and obedient servant,]`. By default this is followed by a 3em space (a space in which you can add your signature) and then the author's name. You can use the `signature` parameter to insert some content, e.g. text or an image in place of the 3em space, and you can use the `name` parameter to use a name other than what has been set as the author's name here - or indeed to omit it altogether by setting it to `none`.
122+
- `letter.cc-field(..recipients)`: Add any number of names of additional recipients whom you have sent a (carbon)-copy of the letter. If these are fewer than 3, they will be set on a single line. 3 or more will be automatically set as a list.
123+
- `letter.enclosed-field(..enclosures)`: Add any number of strings refering to enclosed (attached) documents. If this is a single item it will be set without a bullet, if there are more than one they will be set as a bullet list.
124+
125+
## License
126+
127+
The `pc-letter` package is free and open-source, licensed under the MIT License. See the file [`LICENSE`](./LICENSE) for mor information.
128+
129+
## Change log
130+
131+
### v0.2.0
132+
133+
#### Added
134+
135+
- Author's details (`author` argument of `pc-letter.init`) now also accepts a `web` argument where an author can include their homepage address.
136+
137+
#### Changed
138+
139+
- The default `medium` (`style` argument of `pc-letter.init`) is now `"print"` (previously `"digital"`), because a letter set for printing will work digitally without problems, but one set for digital-only use (with background fill and such) may well produce problems when printing.
140+
- Author's address (`author.address` argument of `pc-letter.init`) is now optional.
141+
- Author's contact details (phone, email, web) (`author.phone`, `author.email`, `author.web` arguments of `pc-letter.init`) are now all optional and break across two lines iff more than two of them are specified.
142+
- Headings (used for subject lines and as section separators) now get 1.25em spacing above and below (previously 1em), making them subtly more prominent as separators in the text body.
143+
- Internal calculations for spacing of different fields is now relative to page dimensions and margins, which will help with implementing different paper sizes (e.g. `us-letter`) in future versions of `pc-letter`.
144+
- The package now has full [`tidy`](https://typst.app/universe/package/tidy/) 0.4.0-compatible doc comments. While `tinymist` still only parses the pre-0.4.0 style comments, it is expected that this will also enhance hinting for users once `tinymist` implements the up-to-date doc comment style. The dictionary-passing method of initialisation may still pose a problem for this, but the change should generally aid in future-proofing the package.
145+
146+
#### Fixed
147+
148+
- Missing translation of pagination for non-Austrian German fixed.
28.9 KB
Binary file not shown.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#import "@preview/pc-letter:0.2.0"
2+
3+
#let letter = pc-letter.init(
4+
author: (
5+
name: "Thomas Mathias",
6+
address: ("7B Cae Melyn", "Aberystwyth SY23 2HA"),
7+
phone: "01970 612 125",
8+
9+
),
10+
date: datetime(day: 29, month: 10, year: 2013),
11+
style: (
12+
locale: (lang: "cy"),
13+
medium: "digital",
14+
),
15+
)
16+
17+
#show: letter.letter-style
18+
19+
#(letter.falzmarken)()
20+
21+
#(letter.address-field)[
22+
CS Brian Prosser\
23+
Gorsaf Heddlu Aberystwyth\
24+
Heddlu Dyfed-Powys\
25+
Boulevard Sanit Brieuc\
26+
Aberystwyth SY23 1PH
27+
]
28+
29+
#(letter.reference-field)[DPP/2013/10/HR-621]
30+
31+
Annwyl Syr,
32+
33+
= Trosglwyddiad i'ch uned yn Aberystwyth
34+
35+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam in sapien sed orci sodales mollis eget vel elit. Sed ultricies risus in neque eleifend, malesuada lacinia ipsum iaculis. Pellentesque enim purus, sagittis congue dolor ut, ullamcorper rutrum quam. Praesent suscipit orci at mauris finibus malesuada.
36+
37+
Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin gravida pharetra lacus, non laoreet nunc ornare eu.
38+
39+
In sit amet mi eleifend, viverra tortor ut, ultricies nunc. Etiam mollis neque ac erat placerat, id pharetra nisi tempus. Etiam nisi ipsum, bibendum in nisi eu, euismod finibus libero.
40+
41+
== Eisampl o is-bennawd
42+
43+
Ut metus turpis, varius sed risus ut, tempus mattis odio. Ut a sodales mauris. Vivamus tincidunt purus ex, pellentesque dignissim neque dignissim sed.
44+
45+
Aliquam sem nibh, eleifend facilisis nunc at, elementum eleifend lacus. Vivamus nec justo est. Nam tincidunt felis eget posuere auctor. Vivamus erat purus, elementum eget lobortis eget, rutrum eu felis. Aliquam ex nulla, auctor fermentum enim sed, cursus hendrerit mauris.
46+
47+
#(letter.valediction)(
48+
signature: text(size: 1.5em, font: ("Lucida Handwriting", "Syne Tactile"), "T. Mathias"),
49+
name: "Tom Mathias"
50+
)[Yr eiddoch yn gywir,]
51+
52+
#(letter.cc-field)("DI Mared Rhys", "DS Siân Owens", "DC Lloyd Elis")
53+
54+
#(letter.enclosed-field)("Cynllun ail-strwythuro'r uned")
30.6 KB
Binary file not shown.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#import "@preview/pc-letter:0.2.0"
2+
3+
#let letter = pc-letter.init(
4+
author: (
5+
name: "Georg Wilsberg",
6+
address: ("Frauenstraße 49/50", "48143 Münster"),
7+
phone: "0251/385 317",
8+
9+
),
10+
date: datetime(day: 8, month: 2, year: 2020),
11+
place-name: "Münster",
12+
style: (
13+
locale: (lang: "de", region: "DE"),
14+
medium: "digital",
15+
alignment: (valediction: right),
16+
),
17+
)
18+
19+
#show: letter.letter-style
20+
21+
#(letter.falzmarken)()
22+
23+
#(letter.address-field)[
24+
Frau Tessa Tilker\
25+
Livesey, Trelawney & Gunn LLP\
26+
Birkenenallee 13\
27+
48143 Münster
28+
]
29+
30+
#(letter.reference-field)[LTG/2020/02/ofo]
31+
32+
= Betreff: Beratende Tätigkeit im Fall Folkerts
33+
34+
Sehr geehrte Frau Tilker,
35+
36+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam in sapien sed orci sodales mollis eget vel elit. Sed ultricies risus in neque eleifend, malesuada lacinia ipsum iaculis. Pellentesque enim purus, sagittis congue dolor ut, ullamcorper rutrum quam. Praesent suscipit orci at mauris finibus malesuada.
37+
38+
Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Proin gravida pharetra lacus, non laoreet nunc ornare eu.
39+
40+
In sit amet mi eleifend, viverra tortor ut, ultricies nunc. Etiam mollis neque ac erat placerat, id pharetra nisi tempus. Etiam nisi ipsum, bibendum in nisi eu, euismod finibus libero.
41+
42+
== Überschrift einer Untersektion:
43+
44+
Ut metus turpis, varius sed risus ut, tempus mattis odio. Ut a sodales mauris. Vivamus tincidunt purus ex, pellentesque dignissim neque dignissim sed.
45+
46+
Aliquam sem nibh, eleifend facilisis nunc at, elementum eleifend lacus. Vivamus nec justo est. Nam tincidunt felis eget posuere auctor. Vivamus erat purus, elementum eget lobortis eget, rutrum eu felis. Aliquam ex nulla, auctor fermentum enim sed, cursus hendrerit mauris.
47+
48+
#(letter.valediction)(
49+
signature: text(size: 1.5em, font: ("Lucida Handwriting", "Syne Tactile"), "Wilsberg")
50+
)[Mit freundlichen Grüßen,]
51+
52+
#(letter.cc-field)("Alex Holtkamp, Ekki Talkötter")
53+
54+
#(letter.enclosed-field)("Ursprüngl. Testament", "Angefochtenes Folgetestament", "Gutachten Steinthal")
28.5 KB
Binary file not shown.

0 commit comments

Comments
 (0)