diff options
Diffstat (limited to 'docs/typ/style.typ')
| -rw-r--r-- | docs/typ/style.typ | 91 |
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)) + } +} |
