oficina / slides Public

Clone
git clone https://amadan.net/oficina/slides

Plain git — no account needed to clone.

Download

Download this file

1package layout
2
3// sizes.go is internal/slides/static/slides.css evaluated at 1920 by
4// 1080. Every number here is the stylesheet's own declaration with the
5// unit worked out, written as the multiplication rather than as the
6// answer so the two can be read side by side.
7//
8// ── What a cqw is, and why there are two of them ──────────────────────
9//
10// A container query length is one percent of the query container's
11// CONTENT box, not of its border box. The section is the container and
12// it carries `padding: 6.25%` — 120px each side at 1920 — so on a
13// slide with padding one cqw is 16.8px, and on one without it
14// (`image-full` and every canvas slide both set `padding: 0`) it is
15// 19.2. That is a 12.5% difference in every type size on six of the
16// seven templates, which is why it is spelled out twice here instead
17// of being assumed once.
18//
19// Checked against Chromium rather than reasoned about: a `title`
20// slide's h1 computes to 110.88px (6.6 × 16.8) and a canvas slide's to
21// 126.72 (6.6 × 19.2).
22//
23// ── The gap between regions ───────────────────────────────────────────
24//
25// `gap: var(--slides-gap)` used to be written on the section, which is
26// the query container, and an element is never its own container: the
27// browser resolved it against whatever was outside the slide, so the
28// space between a heading and a body was 49.92px on a 1920 screen and
29// 20.27px in a 780px window. Slice 3 moved the template grid onto a
30// `[slides-frame]` inside the section (render.SlideWith writes it), so
31// the declaration is a descendant's like every other one and the gap
32// is 2.6 padded cqw wherever the slide is drawn. sectionGap below is
33// that one number, and it is now the same length as scale.gap() on a
34// padded template — spelled separately because they are two different
35// declarations in the stylesheet and one of them could move.
36
37// The frame. 16:9, and the only aspect this build has (§9).
38const (
39 FrameW = 1920.0
40 FrameH = 1080.0
41
42 // pad is `--slides-pad: 6.25%`. A percentage padding resolves
43 // against the containing block's INLINE size on all four sides, so
44 // the top and bottom of a slide are 120 as well, not 67.5.
45 pad = 0.0625 * FrameW
46
47 // cqwPadded is one cqw inside a section with padding, cqwFull one
48 // inside a section without it.
49 cqwPadded = (FrameW - 2*pad) / 100
50 cqwFull = FrameW / 100
51
52 // sectionGap is `[slides-frame] { gap }` — see the header.
53 // sectionColGap is two-column's
54 // `column-gap: calc(var(--slides-gap) * 1.6)`, on the same
55 // element and so resolved the same way.
56 //
57 // Padded, because every template that has more than one region
58 // keeps the section's padding: image-full is the one that does
59 // not, and its frame sets `gap: 0`.
60 sectionGap = 2.6 * cqwPadded
61 sectionColGap = sectionGap * 1.6
62)
63
64// scale is the type and spacing scale at one cqw. Everything a
65// DESCENDANT of the section is sized in goes through one of these; the
66// section's own two declarations are the constants above.
67type scale struct{ cqw float64 }
68
69var (
70 // padded is the scale on the five templates that keep the
71 // section's padding, and full the one on `image-full` and on every
72 // canvas slide.
73 padded = scale{cqwPadded}
74 full = scale{cqwFull}
75)
76
77// scaleFor is the scale a slide is drawn at: which of the two above
78// depends on whether the section has padding.
79func scaleFor(layout, template string) scale {
80 if layout == "canvas" || template == "image-full" {
81 return full
82 }
83 return padded
84}
85
86// The type scale, from `[slides-slide]`'s custom properties.
87func (s scale) t1() float64 { return 6.6 * s.cqw } // --slides-t-1
88func (s scale) t2() float64 { return 5.0 * s.cqw } // --slides-t-2
89func (s scale) t3() float64 { return 4.0 * s.cqw } // --slides-t-3
90func (s scale) bodyL() float64 { return 3.4 * s.cqw } // --slides-body-l
91func (s scale) bodyM() float64 { return 2.8 * s.cqw } // --slides-body-m
92func (s scale) bodyS() float64 { return 2.2 * s.cqw } // --slides-body-s
93func (s scale) code() float64 { return 2.3 * s.cqw } // --slides-code
94
95// gap is `--slides-gap` as a DESCENDANT reads it: the space between
96// two blocks in a region, between two columns of a columns block, and
97// the padding of image-full's heading scrim.
98func (s scale) gap() float64 { return 2.6 * s.cqw }
99
100// rule is `--slides-rule`: a divider's thickness and the section
101// template's accent bar.
102func (s scale) rule() float64 { return 0.5 * s.cqw }
103
104// bodySize maps a size step to this scale's body sizes.
105func (s scale) bodySize(step string) float64 {
106 switch step {
107 case "s":
108 return s.bodyS()
109 case "l":
110 return s.bodyL()
111 }
112 return s.bodyM()
113}
114
115// Line heights, as the stylesheet sets them: 1.3 on the section and
116// inherited by everything, 1.1 on a heading, 1.45 in a code block.
117//
118// These are ratios of the font size, which is what CSS `line-height: N`
119// means, and they are the reason this package does not use the faces'
120// own default leading (fonts.Metrics returns it and this ignores it):
121// the browser is following the stylesheet, so agreeing with the browser
122// means following the stylesheet too.
123const (
124 leadBody = 1.3
125 leadHeading = 1.1
126 leadCode = 1.45
127)
128
129// trackHeading is `letter-spacing`, in ems, and a heading is the only
130// place the stylesheet sets it. Small, and not negligible: over a
131// thirty-character title it is nearly a word's width.
132const trackHeading = -0.01
133
134// Gaps inside a block, all of them relative to the block's own font
135// size because that is how the stylesheet writes them.
136const (
137 paraGapEm = 0.6 // `[slides-block] p + p { margin-block-start: 0.6em }`
138 listGapEm = 0.4 // `[data-block="list"] { gap: 0.4em }`
139 quoteGap = 0.6 // `[data-block="quote"] { gap: 0.6em }`
140 citeEm = 0.62 // `figcaption { font-size: 0.62em }`
141 inlineEm = 0.88 // `:not(pre) > code { font-size: 0.88em }`
142)
143
144// listIndentEm is `padding-inline-start` per indent step (§2.6: a
145// nested list is a second list block with a bigger indent, never a
146// nested <ul>). Four entries, because the stylesheet has four rules.
147var listIndentEm = [4]float64{1.4, 3.0, 4.6, 6.2}
148
149// Code block geometry: `padding: 1em; border-radius: 0.6em`.
150const (
151 codePadEm = 1.0
152 codeRadiusEm = 0.6
153)
154
155// Table geometry: `padding: 0.45em 0.7em` on every cell and a 1px rule
156// under every row.
157const (
158 cellPadYEm = 0.45
159 cellPadXEm = 0.7
160 cellRule = 1.0
161)
162
163// shapeMinBlockCqw is `[data-block="shape"] { min-block-size: 8cqw }`,
164// which is the floor a shape shrinks to and no further.
165const shapeMinBlockCqw = 8.0
166
167// The mixes the stylesheet makes with color-mix(), as fractions of the
168// foreground mixed into the background.
169const (
170 mixCodePanel = 0.08 // a code block's panel
171 mixTableRule = 0.22 // a table's row rule
172 mixDivider = 0.30 // a divider
173 mixHighlight = 0.26 // a <mark>, mixed from the ACCENT not the fg
174
175 // imageFallback is the ratio an image with no registered size is
176 // drawn at — the frame's own, which is the least surprising guess.
177 imageFallback = 9.0 / 16.0
178)
179