summaryrefslogtreecommitdiff
path: root/docs/typ/style.typ
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-30 22:33:15 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:17 -0300
commit989dcf395be7280240fc501ba1f07f75bacf91a3 (patch)
treed0d5c9901621b13f3bb4520140835ee0dec30ac3 /docs/typ/style.typ
parent71c715e10fe85d71b615c8f9a5a2b0c4c95b1a3f (diff)
downloadpardes-989dcf395be7280240fc501ba1f07f75bacf91a3.tar.gz
pardes-989dcf395be7280240fc501ba1f07f75bacf91a3.zip
The cheatsheet draws mouse buttons as a mouse, keys as chips, and pairs as tables
#btn and #chord draw a mouse (left button, wheel, right button) with the pressed part filled; the wheel is a narrow slot on a paper halo, hollow or filled, so it never reads as a button. A chord is the held button, then for each click the held one and that one down, with arrows between; #btn(.., shift: true) adds a ⇧. HTML gets a span with an aria-label. A key is one soft pill with no border: a combination (Ctrl-w) reads Ctrl + w and a sequence (g g, SPC f c) g › g, separators muted inside it; #keys("h", "j", ...) sets alternatives as separate pills. The drift test reads every key a #keys call names. #pairs sets key | meaning content as a two-column table on alternating tints; split: 2 sets the leader map as two such tables side by side. The mouse chords get their own table: cut, paste, copy (B1-B2 then B1-B3, one B1 hold, as mouse.zig says), 2-1 with an argument, 2-3 cancelling. The A4 page draws its own title and drops the content's level-1 heading. docs/typ/README is the function contract for content files. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'docs/typ/style.typ')
-rw-r--r--docs/typ/style.typ91
1 files changed, 77 insertions, 14 deletions
diff --git a/docs/typ/style.typ b/docs/typ/style.typ
index 7cb05e23..64d96064 100644
--- a/docs/typ/style.typ
+++ b/docs/typ/style.typ
@@ -18,6 +18,7 @@
str: rgb("#34743d"),
num: rgb("#9a5810"),
rule: rgb("#95baa2"),
+ mouse: rgb("#8a3a00"),
)
#let mono = "DejaVu Sans Mono"
@@ -36,26 +37,72 @@
#let span(class, body) = html.elem("span", attrs: (class: class), body)
#let m(s, fill: palette.ink) = text(font: mono, size: 0.92em, fill: fill, s)
-/// A key or a sequence of keys, one cap per space-separated chord.
+/// A key: one press (`x`, `Ctrl-w`, `Shift-Esc`), or a sequence pressed one
+/// after another, written space-separated (`g g`, `SPC f c`). Either is ONE
+/// pill: a combination's parts joined by a muted +, a sequence's steps by a
+/// muted › (`Ctrl-w h` reads Ctrl + w › h).
#let key(k) = context if html-out() {
- k.split(" ").map(t => html.elem("kbd", t)).join(" ")
+ html.elem("kbd", k.split(" ").map(t => html.elem("kbd", t)).join(" "))
} else {
- k.split(" ").map(t => box(
- fill: white, stroke: 0.4pt + palette.rule, radius: 1.5pt,
- inset: (x: 1.6pt, y: 0pt), outset: (y: 1.4pt), m(t),
- )).join(h(1pt))
-}
-
-/// A mouse button.
-#let btn(b) = context if html-out() { span("btn", b) } else {
+ let muted(c) = text(fill: palette.grip.transparentize(25%), size: 0.85em, c)
+ let press(t) = (if t.len() > 1 and t.contains("-") { t.split("-") } else { (t,) }).join(muted[+])
box(
- fill: palette.col-grip, radius: 2pt, inset: (x: 1.6pt, y: 0pt), outset: (y: 1.4pt),
- text(font: mono, size: 0.85em, weight: "bold", fill: white, b),
+ fill: palette.grip.transparentize(84%), radius: 2pt,
+ inset: (x: 1.4pt, y: 0pt), outset: (y: 1.5pt),
+ text(font: mono, size: 0.92em, fill: palette.ink,
+ k.split(" ").map(press).join(muted[#h(1pt)›#h(1pt)])),
)
}
-/// A chord: the first button held, the others clicked.
-#let chord(..bs) = bs.pos().map(btn).join(text(fill: palette.col-grip)[--])
+/// Alternatives: separate keys listed together, each its own command.
+#let keys(..ks) = context ks.pos().map(key).join(if html-out() [ ] else { h(0.25em) })
+
+#let button-names = ("B1": "left button", "B2": "wheel", "B3": "right button")
+
+/// A mouse, about cap height: left button, wheel, right button. The parts
+/// in `pressed` ("B1", "B2", "B3") are filled.
+#let mouse(pressed) = {
+ let (w, h, top) = (0.84em, 1.2em, 0.56em)
+ let ink = palette.mouse
+ let s = 0.7pt + ink
+ let on(b) = if b in pressed { ink } else { none }
+ box(width: w, height: h, baseline: 0.24em, {
+ place(rect(width: w / 2, height: top, radius: (top-left: w / 2), fill: on("B1"), stroke: s))
+ place(dx: w / 2, rect(width: w / 2, height: top, radius: (top-right: w / 2), fill: on("B3"), stroke: s))
+ place(dy: top, rect(width: w, height: h - top, radius: (bottom: w / 2), stroke: s))
+ // the wheel: a narrow tall slot over the buttons' seam, on a paper
+ // halo so a filled wheel stands apart from the button outlines
+ let (ww, wh, halo) = (0.26em, 0.44em, 0.07em)
+ let (wx, wy) = ((w - ww) / 2, 0.06em)
+ place(dx: wx - halo, dy: wy - halo / 2, rect(
+ width: ww + 2 * halo, height: wh + halo, radius: ww, fill: palette.paper))
+ place(dx: wx, dy: wy, rect(
+ width: ww, height: wh, radius: ww / 2, stroke: 0.5pt + ink,
+ fill: if "B2" in pressed { ink } else { palette.paper },
+ ))
+ })
+}
+
+/// A mouse button; `shift: true` for the button with Shift held.
+#let btn(b, shift: false) = context if html-out() {
+ let label = (if shift { "shift " } else { "" }) + button-names.at(b)
+ html.elem("span", attrs: (class: "btn", aria-label: label, title: label), (if shift { "⇧" } else { "" }) + b)
+} else {
+ if shift { text(size: 0.8em, fill: palette.col-grip)[⇧] }
+ mouse((b,))
+}
+
+/// A chord: the first button held, each next one clicked while it is.
+/// Drawn as the held button, then for each click the held one and that one
+/// down, with arrows between.
+#let chord(..bs) = context if html-out() {
+ let label = bs.pos().map(b => button-names.at(b)).join(" then ")
+ html.elem("span", attrs: (class: "chord", aria-label: label, title: label), bs.pos().join("-"))
+} else {
+ let (held, ..clicks) = bs.pos()
+ let arrow = text(size: 0.75em, fill: palette.col-grip)[#h(0.5pt)›#h(0.5pt)]
+ ((mouse((held,)),) + clicks.map(c => mouse((held, c)))).join(arrow)
+}
/// A tag word or builtin, as it sits in a tag.
#let word(w) = context if html-out() { span("word", raw(w)) } else {
@@ -99,3 +146,19 @@
text(fill: palette.num)[→#m(to, fill: palette.num)]
}
}
+
+/// Pairs: a thing and what it means, as a two-column table, key column
+/// first, rows on alternating tints. `split: 2` sets the rows as that many
+/// tables side by side (on paper; HTML gets one table).
+#let pairs(split: 1, ..cells) = {
+ let rows = cells.pos().chunks(2)
+ let one(rows) = table(
+ columns: (auto, 1fr), stroke: none, inset: (x: 2pt, y: 1.6pt),
+ fill: (_, y) => if calc.even(y) { palette.tag-bg.transparentize(35%) },
+ ..rows.flatten(),
+ )
+ context if html-out() or split == 1 { one(rows) } else {
+ let n = calc.ceil(rows.len() / split)
+ grid(columns: (1fr,) * split, column-gutter: 2pt, ..rows.chunks(n).map(one))
+ }
+}