@airmark/quiver 0.33.0 → 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -12
- package/package.json +7 -7
- package/quills/af4141/0.1.0/Quill.yaml +3 -12
- package/quills/af4141/0.1.0/example.md +53 -0
- package/quills/afmc_moa/0.0.1/Quill.yaml +29 -45
- package/quills/afmc_moa/0.0.1/example.md +114 -0
- package/quills/afmc_moa/0.0.1/packages/typst-afmc-moa/src/config.typ +1 -1
- package/quills/classic_resume/{0.0.1 → 0.1.0}/Quill.yaml +88 -168
- package/quills/classic_resume/0.1.0/example.md +111 -0
- package/quills/classic_resume/{0.0.1 → 0.1.0}/packages/ttq-classic-resume/src/components.typ +77 -35
- package/quills/classic_resume/{0.0.1 → 0.1.0}/packages/ttq-classic-resume/src/config.typ +23 -14
- package/quills/classic_resume/{0.0.1 → 0.1.0}/packages/ttq-classic-resume/src/layout.typ +37 -7
- package/quills/classic_resume/{0.0.1 → 0.1.0}/packages/ttq-classic-resume/src/lib.typ +1 -0
- package/quills/classic_resume/0.1.0/packages/ttq-classic-resume/src/util.typ +50 -0
- package/quills/classic_resume/{0.0.1 → 0.1.0}/packages/ttq-classic-resume/typst.toml +0 -5
- package/quills/classic_resume/{0.0.1 → 0.1.0}/plate.typ +63 -56
- package/quills/cyber_career_plan/0.1.0/Quill.yaml +328 -0
- package/quills/cyber_career_plan/0.1.0/example.md +55 -0
- package/quills/cyber_career_plan/0.1.0/plate.typ +681 -0
- package/quills/daf1206/0.1.0/Quill.yaml +14 -16
- package/quills/daf1206/0.1.0/example.md +55 -0
- package/quills/daf4392/0.1.0/Quill.yaml +1 -6
- package/quills/daf4392/0.1.0/example.md +51 -0
- package/quills/usaf_letter/0.1.0/Quill.yaml +7 -42
- package/quills/usaf_letter/0.1.0/example.md +35 -0
- package/quills/{usaf_memo/0.3.0/packages/tonguetoquill-usaf-memo/fonts/Cinzel/LICENSE → usaf_letter/0.1.0/packages/tonguetoquill-usaf-letter/fonts/SpectralSC/OFL.txt} +2 -2
- package/quills/usaf_letter/0.1.0/packages/tonguetoquill-usaf-letter/fonts/SpectralSC/SpectralSC-Italic.ttf +0 -0
- package/quills/usaf_letter/0.1.0/packages/tonguetoquill-usaf-letter/fonts/SpectralSC/SpectralSC-Regular.ttf +0 -0
- package/quills/usaf_letter/0.1.0/packages/tonguetoquill-usaf-letter/src/frontmatter.typ +1 -1
- package/quills/usaf_letter/0.1.0/plate.typ +1 -4
- package/quills/usaf_memo/0.2.0/Quill.yaml +7 -40
- package/quills/usaf_memo/0.2.0/example.md +45 -0
- package/quills/usaf_memo/0.3.0/Quill.yaml +13 -50
- package/quills/usaf_memo/0.3.0/example.md +48 -0
- package/quills/{usaf_letter/0.1.0/packages/tonguetoquill-usaf-letter/fonts/Cinzel/LICENSE → usaf_memo/0.3.0/packages/tonguetoquill-usaf-memo/fonts/SpectralSC/OFL.txt} +2 -2
- package/quills/usaf_memo/0.3.0/packages/tonguetoquill-usaf-memo/fonts/SpectralSC/SpectralSC-Italic.ttf +0 -0
- package/quills/usaf_memo/0.3.0/packages/tonguetoquill-usaf-memo/fonts/SpectralSC/SpectralSC-Regular.ttf +0 -0
- package/quills/usaf_memo/0.3.0/packages/tonguetoquill-usaf-memo/src/frontmatter.typ +1 -1
- package/quills/usaf_memo/0.3.0/plate.typ +1 -4
- package/templates/deros_extension.md +40 -0
- package/templates/templates.json +7 -0
- package/quills/classic_resume/0.0.1/packages/ttq-classic-resume/src/util.typ +0 -32
- package/quills/cyber_ribbon_chart/0.0.1/Quill.yaml +0 -320
- package/quills/cyber_ribbon_chart/0.0.1/plate.typ +0 -428
- package/quills/usaf_letter/0.1.0/packages/tonguetoquill-usaf-letter/fonts/Cinzel/Cinzel-Regular.ttf +0 -0
- package/quills/usaf_letter/0.1.0/packages/tonguetoquill-usaf-letter/fonts/CopperplateCC/CopperplateCC-Heavy.otf +0 -0
- package/quills/usaf_memo/0.3.0/packages/tonguetoquill-usaf-memo/fonts/Cinzel/Cinzel-Regular.ttf +0 -0
- package/quills/usaf_memo/0.3.0/packages/tonguetoquill-usaf-memo/fonts/CopperplateCC/CopperplateCC-Heavy.otf +0 -0
- /package/quills/classic_resume/{0.0.1 → 0.1.0}/packages/ttq-classic-resume/LICENSE +0 -0
- /package/quills/classic_resume/{0.0.1 → 0.1.0}/packages/ttq-classic-resume/fonts/EBGaramond/EBGaramond-Bold.ttf +0 -0
- /package/quills/classic_resume/{0.0.1 → 0.1.0}/packages/ttq-classic-resume/fonts/EBGaramond/EBGaramond-BoldItalic.ttf +0 -0
- /package/quills/classic_resume/{0.0.1 → 0.1.0}/packages/ttq-classic-resume/fonts/EBGaramond/EBGaramond-Italic.ttf +0 -0
- /package/quills/classic_resume/{0.0.1 → 0.1.0}/packages/ttq-classic-resume/fonts/EBGaramond/EBGaramond-Regular.ttf +0 -0
- /package/quills/classic_resume/{0.0.1 → 0.1.0}/packages/ttq-classic-resume/fonts/EBGaramond/OFL.txt +0 -0
|
@@ -1,428 +0,0 @@
|
|
|
1
|
-
#import "@local/quillmark-helper:0.1.0": data
|
|
2
|
-
|
|
3
|
-
#let ink = luma(12%)
|
|
4
|
-
#let mute = luma(45%)
|
|
5
|
-
#let faint = luma(62%)
|
|
6
|
-
|
|
7
|
-
#set page(width: 11in, height: 8.5in, margin: 0.45in)
|
|
8
|
-
#set text(font: "Figtree", size: 8pt, fill: ink)
|
|
9
|
-
|
|
10
|
-
#set document(
|
|
11
|
-
title: "Ribbon Chart — " + data.name,
|
|
12
|
-
author: data.name,
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
// A `plaintext` field lowers to content padded with a space on each side, which
|
|
16
|
-
// would print inside a bold run and defeat an emptiness test.
|
|
17
|
-
#let trim(v) = {
|
|
18
|
-
if type(v) != content { return v }
|
|
19
|
-
let kids = v.at("children", default: none)
|
|
20
|
-
if kids == none { return v }
|
|
21
|
-
let pad(c) = c == [ ] or c.func() == parbreak
|
|
22
|
-
while kids.len() > 0 and pad(kids.first()) { kids = kids.slice(1) }
|
|
23
|
-
while kids.len() > 0 and pad(kids.last()) { kids = kids.slice(0, -1) }
|
|
24
|
-
kids.sum(default: [])
|
|
25
|
-
}
|
|
26
|
-
#let blank(v) = { let t = trim(v); t == [] or t == "" }
|
|
27
|
-
|
|
28
|
-
// The bundled fallback face carries no geometric glyphs — no ✓, ■, □, ●, ▸ — so
|
|
29
|
-
// a mark is drawn rather than set. Held against open is a value contrast, which
|
|
30
|
-
// is what survives the photocopier these are read from.
|
|
31
|
-
#let held-mark = box(baseline: 0.5pt, rect(width: 4.6pt, height: 4.6pt, fill: ink, stroke: 0.5pt + ink))
|
|
32
|
-
#let open-mark = box(baseline: 0.5pt, rect(width: 4.6pt, height: 4.6pt, fill: none, stroke: 0.5pt + faint))
|
|
33
|
-
|
|
34
|
-
#let section-rule(title) = block(spacing: 0pt, below: 5pt)[
|
|
35
|
-
#text(size: 6.6pt, weight: 700, tracking: 0.7pt)[#upper(title)]
|
|
36
|
-
#v(2pt)
|
|
37
|
-
#line(length: 100%, stroke: 0.6pt + ink)
|
|
38
|
-
]
|
|
39
|
-
|
|
40
|
-
#let fact(label, value) = block(spacing: 0pt)[
|
|
41
|
-
#text(size: 5.8pt, weight: 600, tracking: 0.4pt, fill: mute)[#upper(label)]
|
|
42
|
-
#v(1.5pt)
|
|
43
|
-
#text(size: 8.5pt, weight: 500)[#if value == none { text(fill: faint)[—] } else { value }]
|
|
44
|
-
]
|
|
45
|
-
|
|
46
|
-
#let show-date(d) = if d == none { none } else { d.display("[day padding:none] [month repr:short] [year]") }
|
|
47
|
-
|
|
48
|
-
// ─── the ladder ──────────────────────────────────────────────────────────────
|
|
49
|
-
// Every 17X board and school gate, as an offset from the year group, counted
|
|
50
|
-
// from the adjusted year group where one is set because that is the year a
|
|
51
|
-
// board counts from. The tier is how heavily it prints: a board is a date you
|
|
52
|
-
// are ranked against, a look is one of a numbered series, a course is neither.
|
|
53
|
-
#let ladder = (
|
|
54
|
-
(3, "Cyber 200", "course"),
|
|
55
|
-
(4, "SOS window", "course"),
|
|
56
|
-
(8, "Maj board", "board"),
|
|
57
|
-
(8, "IDE 1st look", "look"),
|
|
58
|
-
(9, "Cyber 300", "course"),
|
|
59
|
-
(9, "IDE 2nd look", "look"),
|
|
60
|
-
(10, "IDE 3rd look", "look"),
|
|
61
|
-
(11, "IDE final look", "look"),
|
|
62
|
-
(12, "Lt Col board", "board"),
|
|
63
|
-
(14, "SDE 1st look", "look"),
|
|
64
|
-
(15, "SDE 2nd look", "look"),
|
|
65
|
-
(16, "SDE 3rd look", "look"),
|
|
66
|
-
(17, "SDE final look", "look"),
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
// ─── inputs ──────────────────────────────────────────────────────────────────
|
|
70
|
-
#let comm-yg = data.commissioning_yg
|
|
71
|
-
#let adj-yg = data.adjusted_yg
|
|
72
|
-
#let board-yg = if adj-yg != 0 { adj-yg } else { comm-yg }
|
|
73
|
-
#let start-year = data.timeline_start_year
|
|
74
|
-
#let years = calc.max(1, data.timeline_years)
|
|
75
|
-
#let cols = years * 2
|
|
76
|
-
#let narrow = years > 12
|
|
77
|
-
#let band-height = 0.52in
|
|
78
|
-
#let chip-size = if narrow { 5.6pt } else { 6.2pt }
|
|
79
|
-
#let chip-inset = if narrow { 2pt } else { 3.5pt }
|
|
80
|
-
|
|
81
|
-
// Three weights of gate, by what each one is: a board ranks you against a year
|
|
82
|
-
// group on a date, a look is one of a numbered series, a course is a seat.
|
|
83
|
-
#let chip(label, tier) = {
|
|
84
|
-
if tier == "board" {
|
|
85
|
-
box(fill: ink, inset: (x: chip-inset, y: 2pt))[#text(size: chip-size, weight: 700, fill: white)[#label]]
|
|
86
|
-
} else if tier == "look" {
|
|
87
|
-
box(fill: none, stroke: 0.5pt + ink, inset: (x: chip-inset, y: 2pt))[#text(size: chip-size, weight: 600)[#label]]
|
|
88
|
-
} else {
|
|
89
|
-
box(inset: (x: 0.5pt, y: 2pt))[#text(size: chip-size, fill: mute)[#label]]
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// One tint per vector, darkest first, so the shade says which row this is.
|
|
94
|
-
// Adjacent tours part by a gap and an edge instead, and at the third rank the
|
|
95
|
-
// edge is doing all the work — which is what a photocopy leaves anyway.
|
|
96
|
-
#let rank-tints = (luma(86%), luma(92%), luma(96%))
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
// ─── vectors ─────────────────────────────────────────────────────────────────
|
|
100
|
-
#let vectors = data.vectors.enumerate().map(((i, v)) => (
|
|
101
|
-
label: if blank(v.label) { [Vector #(i + 1)] } else { trim(v.label) },
|
|
102
|
-
focus: trim(v.focus),
|
|
103
|
-
tours: v.tours.map(t => (
|
|
104
|
-
title: trim(t.title),
|
|
105
|
-
duration: float(t.duration),
|
|
106
|
-
vml: t.vml,
|
|
107
|
-
school: t.school,
|
|
108
|
-
)),
|
|
109
|
-
))
|
|
110
|
-
|
|
111
|
-
// A half-year column is H1 (Jan–Jun, even) or H2 (Jul–Dec, odd), and a VML
|
|
112
|
-
// cycle picks the phase a tour may start on. Where that means waiting, the wait
|
|
113
|
-
// is added to the tour before it rather than left as a hole: you hold a job
|
|
114
|
-
// until you move, and an empty half-year on a career chart reads as
|
|
115
|
-
// unemployment. Only the first tour can be preceded by nothing, and its indent
|
|
116
|
-
// is the half-year before a summer move.
|
|
117
|
-
//
|
|
118
|
-
// Nothing is dropped. A tour the window cuts keeps a torn edge and says which
|
|
119
|
-
// year it runs past; one starting beyond the window is counted on its row.
|
|
120
|
-
#let place(tours) = {
|
|
121
|
-
let cursor = 0
|
|
122
|
-
let out = ()
|
|
123
|
-
for t in tours {
|
|
124
|
-
let phase = if t.vml == "Winter" { 0 } else { 1 }
|
|
125
|
-
let start = cursor
|
|
126
|
-
if calc.rem(start, 2) != phase { start += 1 }
|
|
127
|
-
if start > cursor and out.len() > 0 {
|
|
128
|
-
let prev = out.last()
|
|
129
|
-
prev.span += start - cursor
|
|
130
|
-
prev.held = true
|
|
131
|
-
out.at(out.len() - 1) = prev
|
|
132
|
-
}
|
|
133
|
-
out.push((
|
|
134
|
-
tour: t,
|
|
135
|
-
start: start,
|
|
136
|
-
span: calc.max(1, int(calc.round(t.duration * 2))),
|
|
137
|
-
held: false,
|
|
138
|
-
))
|
|
139
|
-
cursor = out.last().start + out.last().span
|
|
140
|
-
}
|
|
141
|
-
out.map(p => if p.start >= cols { (..p, beyond: true) } else {
|
|
142
|
-
(..p, beyond: false, drawn: calc.min(p.span, cols - p.start), clipped: p.start + p.span > cols)
|
|
143
|
-
})
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// The band is ruled to an even height, so a narrow block cannot grow to fit its
|
|
147
|
-
// title: the title sets to the block instead. That is the ceiling `title`
|
|
148
|
-
// warns about in Quill.yaml — about twenty characters per year of length.
|
|
149
|
-
#let title-size(span) = if span <= 1 { 6.4pt } else if span == 2 { 7.2pt } else { 8pt }
|
|
150
|
-
|
|
151
|
-
// Half-columns back to years, so a stretched block prints the length it draws
|
|
152
|
-
// rather than the length it was given.
|
|
153
|
-
#let span-label(span) = {
|
|
154
|
-
let years = span / 2
|
|
155
|
-
if calc.rem(span, 2) == 0 { [#int(years) yr] } else { [#years yr] }
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// ═══ IDENTITY ════════════════════════════════════════════════════════════════
|
|
159
|
-
#grid(
|
|
160
|
-
columns: (2.7in, 1fr),
|
|
161
|
-
column-gutter: 18pt,
|
|
162
|
-
align: bottom,
|
|
163
|
-
[
|
|
164
|
-
#text(size: 17pt, weight: 800, tracking: -0.25pt)[#data.name]
|
|
165
|
-
#if not blank(data.duty_title) [
|
|
166
|
-
#v(2pt)
|
|
167
|
-
#text(size: 8pt, weight: 500, fill: mute)[#data.duty_title]
|
|
168
|
-
]
|
|
169
|
-
],
|
|
170
|
-
grid(
|
|
171
|
-
columns: (1fr,) * 5,
|
|
172
|
-
column-gutter: 12pt,
|
|
173
|
-
align: top,
|
|
174
|
-
fact("Commissioning YG", [#comm-yg]),
|
|
175
|
-
fact("Adjusted YG", if adj-yg != 0 { [#adj-yg] } else { none }),
|
|
176
|
-
fact("Date of rank", show-date(data.date_of_rank)),
|
|
177
|
-
fact("Arrived station", show-date(data.date_arrived_station)),
|
|
178
|
-
fact("Advanced degree", if blank(data.advanced_degree) { none } else { data.advanced_degree }),
|
|
179
|
-
),
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
#v(6pt)
|
|
183
|
-
#line(length: 100%, stroke: 1.3pt + ink)
|
|
184
|
-
#v(9pt)
|
|
185
|
-
|
|
186
|
-
// ═══ TIMELINE ════════════════════════════════════════════════════════════════
|
|
187
|
-
#let in-window(cy) = cy >= start-year and cy < start-year + years
|
|
188
|
-
#let ahead = ladder.filter(m => board-yg + m.at(0) >= start-year + years)
|
|
189
|
-
|
|
190
|
-
#block(spacing: 0pt)[
|
|
191
|
-
#grid(columns: (1fr, auto), align: (left + bottom, right + bottom),
|
|
192
|
-
text(size: 6.6pt, weight: 700, tracking: 0.7pt)[#upper("Assignment vectors & development timeline")],
|
|
193
|
-
text(size: 6.2pt, fill: mute)[
|
|
194
|
-
CY #start-year–#(start-year + years - 1) · counted from YG #board-yg
|
|
195
|
-
#if ahead.len() > 0 [ · #ahead.len() later milestone#if ahead.len() > 1 [s] beyond #(start-year + years - 1)]
|
|
196
|
-
],
|
|
197
|
-
)
|
|
198
|
-
#v(2pt)
|
|
199
|
-
#line(length: 100%, stroke: 0.6pt + ink)
|
|
200
|
-
]
|
|
201
|
-
#v(5pt)
|
|
202
|
-
|
|
203
|
-
#let rows = ()
|
|
204
|
-
|
|
205
|
-
// year header
|
|
206
|
-
#rows.push(table.cell(stroke: none)[])
|
|
207
|
-
#for i in range(years) {
|
|
208
|
-
rows.push(table.cell(colspan: 2, stroke: (bottom: 0.7pt + ink), inset: (bottom: 2.5pt))[
|
|
209
|
-
#text(size: 8pt, weight: 700)[#(start-year + i)]
|
|
210
|
-
#linebreak()
|
|
211
|
-
#text(size: 5.8pt, fill: mute)[YG+#(start-year + i - board-yg)]
|
|
212
|
-
])
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// milestone row
|
|
216
|
-
#rows.push(table.cell(align: left + horizon, stroke: none)[
|
|
217
|
-
#text(size: 6.4pt, weight: 600, fill: mute)[Eligibility]
|
|
218
|
-
])
|
|
219
|
-
#for i in range(years) {
|
|
220
|
-
let cy = start-year + i
|
|
221
|
-
let hits = ladder.filter(m => board-yg + m.at(0) == cy)
|
|
222
|
-
rows.push(table.cell(colspan: 2, stroke: none, inset: (x: 1.5pt, y: 3pt))[
|
|
223
|
-
#for m in hits [
|
|
224
|
-
#block(spacing: 2pt, breakable: false)[#chip(m.at(1), m.at(2))]
|
|
225
|
-
]
|
|
226
|
-
])
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// one row per vector
|
|
230
|
-
#for (rank, v) in vectors.enumerate() {
|
|
231
|
-
let placed = place(v.tours)
|
|
232
|
-
let beyond = placed.filter(p => p.beyond)
|
|
233
|
-
let top-rule = (top: 0.4pt + luma(80%))
|
|
234
|
-
let tint = rank-tints.at(calc.min(rank, rank-tints.len() - 1))
|
|
235
|
-
|
|
236
|
-
rows.push(table.cell(align: left + horizon, stroke: top-rule, inset: (right: 5pt, y: 3pt))[
|
|
237
|
-
#text(size: 8.5pt, weight: 700)[#v.label]
|
|
238
|
-
#if not blank(v.focus) or beyond.len() > 0 [
|
|
239
|
-
#linebreak()
|
|
240
|
-
#text(size: 6pt, fill: mute)[
|
|
241
|
-
#if not blank(v.focus) [#v.focus]
|
|
242
|
-
#if beyond.len() > 0 [
|
|
243
|
-
#if not blank(v.focus) [ · ]
|
|
244
|
-
+#beyond.len() past #(start-year + years - 1)
|
|
245
|
-
]
|
|
246
|
-
]
|
|
247
|
-
]
|
|
248
|
-
])
|
|
249
|
-
|
|
250
|
-
let at = 0
|
|
251
|
-
let idx = 0
|
|
252
|
-
for p in placed.filter(p => not p.beyond) {
|
|
253
|
-
if p.start > at {
|
|
254
|
-
rows.push(table.cell(colspan: p.start - at, stroke: top-rule)[])
|
|
255
|
-
at = p.start
|
|
256
|
-
}
|
|
257
|
-
rows.push(table.cell(
|
|
258
|
-
colspan: p.drawn,
|
|
259
|
-
stroke: top-rule,
|
|
260
|
-
inset: (x: 1pt, y: 2pt),
|
|
261
|
-
align: left + horizon,
|
|
262
|
-
)[
|
|
263
|
-
// The block is drawn inside its cell rather than as the cell's fill, so
|
|
264
|
-
// adjacent tours are parted by a gap and an edge instead of by a second
|
|
265
|
-
// shade — which is what lets the shade say which vector this is.
|
|
266
|
-
#box(
|
|
267
|
-
width: 100%,
|
|
268
|
-
height: 100%,
|
|
269
|
-
fill: if p.tour.school { none } else { tint },
|
|
270
|
-
stroke: if p.tour.school { (paint: mute, thickness: 0.5pt, dash: (2pt, 1.5pt)) } else { 0.5pt + luma(55%) },
|
|
271
|
-
inset: (x: 3pt, y: 2pt),
|
|
272
|
-
baseline: 0pt,
|
|
273
|
-
)[
|
|
274
|
-
#set align(left + horizon)
|
|
275
|
-
#text(size: title-size(p.drawn), weight: 600, style: if p.tour.school { "italic" } else { "normal" })[
|
|
276
|
-
#p.tour.title
|
|
277
|
-
]
|
|
278
|
-
#linebreak()
|
|
279
|
-
#text(size: 5.8pt, fill: mute)[
|
|
280
|
-
#span-label(p.span)#if p.held [ #sym.dagger] · #p.tour.vml#if p.clipped [ · runs past #(start-year + years - 1)]
|
|
281
|
-
]
|
|
282
|
-
]
|
|
283
|
-
])
|
|
284
|
-
at = p.start + p.drawn
|
|
285
|
-
idx += 1
|
|
286
|
-
}
|
|
287
|
-
if at < cols { rows.push(table.cell(colspan: cols - at, stroke: top-rule)[]) }
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
#table(
|
|
291
|
-
columns: (1.2in,) + (1fr,) * cols,
|
|
292
|
-
rows: (auto, auto) + (band-height,) * vectors.len(),
|
|
293
|
-
stroke: none,
|
|
294
|
-
inset: 2pt,
|
|
295
|
-
..rows,
|
|
296
|
-
)
|
|
297
|
-
|
|
298
|
-
// The legend names the marks this chart actually carries and no others.
|
|
299
|
-
#let drawn-tours = vectors.map(v => place(v.tours).filter(p => not p.beyond)).flatten()
|
|
300
|
-
#let shown-tiers = ladder.filter(m => in-window(board-yg + m.at(0))).map(m => m.at(2)).dedup()
|
|
301
|
-
#let legend = ()
|
|
302
|
-
#if "board" in shown-tiers { legend.push([#chip("board", "board") ranked against your year group]) }
|
|
303
|
-
#if "look" in shown-tiers { legend.push([#chip("look", "look") one of a numbered series]) }
|
|
304
|
-
#if drawn-tours.any(p => not p.tour.school) {
|
|
305
|
-
legend.push([#box(width: 14pt, height: 6pt, fill: rank-tints.at(0), stroke: 0.5pt + luma(55%)) assignment])
|
|
306
|
-
}
|
|
307
|
-
#if drawn-tours.any(p => p.tour.school) {
|
|
308
|
-
legend.push([#box(width: 14pt, height: 6pt, stroke: (paint: mute, thickness: 0.5pt, dash: (2pt, 1.5pt))) school])
|
|
309
|
-
}
|
|
310
|
-
#if drawn-tours.any(p => p.held) { legend.push([#sym.dagger held to the next cycle]) }
|
|
311
|
-
|
|
312
|
-
#if legend.len() > 0 {
|
|
313
|
-
v(3pt)
|
|
314
|
-
text(size: 5.8pt, fill: mute, legend.join(h(6pt)))
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
#v(9pt)
|
|
318
|
-
|
|
319
|
-
// ═══ RECORD ══════════════════════════════════════════════════════════════════
|
|
320
|
-
// Every member arrives, held or not, in the order Quill.yaml declares it; an
|
|
321
|
-
// unheld member's detail arrives blank whatever the document retains.
|
|
322
|
-
#let quals = data.qualifications
|
|
323
|
-
#let vocabulary = (
|
|
324
|
-
("Leadership & Command", quals.command),
|
|
325
|
-
("Operations", quals.operations),
|
|
326
|
-
("Staff & Functional", quals.staff),
|
|
327
|
-
("Education & PME", quals.education),
|
|
328
|
-
)
|
|
329
|
-
|
|
330
|
-
#let remarks = (
|
|
331
|
-
("Awards", data.awards),
|
|
332
|
-
("Certifications", data.certifications),
|
|
333
|
-
("Deployments", data.deployments),
|
|
334
|
-
).filter(r => r.at(1).len() > 0)
|
|
335
|
-
|
|
336
|
-
// The stratifications sit beside the vocabulary; with none, there is no narrow
|
|
337
|
-
// empty column beside it, there is no column.
|
|
338
|
-
#let strats-column = [
|
|
339
|
-
#section-rule("Recent stratifications")
|
|
340
|
-
#for s in data.stratifications {
|
|
341
|
-
block(spacing: 7pt)[
|
|
342
|
-
#grid(columns: (0.44in, 1fr), column-gutter: 7pt, align: (right + top, left + top),
|
|
343
|
-
text(size: 8.5pt, weight: 700)[#s.year],
|
|
344
|
-
[
|
|
345
|
-
#if not blank(s.rater_strat) [#text(size: 8pt)[#s.rater_strat]]
|
|
346
|
-
#if not blank(s.rater_strat) and not blank(s.hlr_strat) [#linebreak()]
|
|
347
|
-
#if not blank(s.hlr_strat) [#text(size: 7.4pt, fill: mute)[#s.hlr_strat]]
|
|
348
|
-
],
|
|
349
|
-
)
|
|
350
|
-
]
|
|
351
|
-
}
|
|
352
|
-
]
|
|
353
|
-
|
|
354
|
-
#let vocabulary-column = [
|
|
355
|
-
#section-rule("Qualifications & experience")
|
|
356
|
-
#grid(
|
|
357
|
-
columns: (1fr,) * vocabulary.len(),
|
|
358
|
-
column-gutter: 14pt,
|
|
359
|
-
..vocabulary.map(group => {
|
|
360
|
-
let (heading, members) = group
|
|
361
|
-
[
|
|
362
|
-
#text(size: 6.2pt, weight: 700, tracking: 0.4pt, fill: mute)[#upper(heading)]
|
|
363
|
-
#v(3pt)
|
|
364
|
-
#set par(leading: 0.42em)
|
|
365
|
-
#for (_, m) in members {
|
|
366
|
-
block(spacing: 0pt, inset: (y: 1.1pt))[
|
|
367
|
-
#grid(columns: (7.6pt, 1fr), align: (left + top, left + top))[
|
|
368
|
-
#if m.held { held-mark } else { open-mark }
|
|
369
|
-
][
|
|
370
|
-
#text(
|
|
371
|
-
size: 7.2pt,
|
|
372
|
-
weight: if m.held { 600 } else { 400 },
|
|
373
|
-
fill: if m.held { ink } else { luma(50%) },
|
|
374
|
-
)[#m.title]
|
|
375
|
-
#if not blank(m.detail) [
|
|
376
|
-
#linebreak()
|
|
377
|
-
#text(size: 6.4pt, style: "italic", fill: mute)[#trim(m.detail)]
|
|
378
|
-
]
|
|
379
|
-
]
|
|
380
|
-
]
|
|
381
|
-
}
|
|
382
|
-
]
|
|
383
|
-
}),
|
|
384
|
-
)
|
|
385
|
-
]
|
|
386
|
-
|
|
387
|
-
#if data.stratifications.len() > 0 {
|
|
388
|
-
grid(columns: (2.45in, 1fr), column-gutter: 24pt, strats-column, vocabulary-column)
|
|
389
|
-
} else {
|
|
390
|
-
vocabulary-column
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
// Three lists side by side across the full width. Stacked in a narrow column
|
|
394
|
-
// they cost three times the height and read as one long list.
|
|
395
|
-
#if remarks.len() > 0 [
|
|
396
|
-
#v(8pt)
|
|
397
|
-
#section-rule("Awards · certifications · deployments")
|
|
398
|
-
#grid(
|
|
399
|
-
columns: (1fr,) * 3,
|
|
400
|
-
column-gutter: 24pt,
|
|
401
|
-
..remarks.map(((label, lines)) => [
|
|
402
|
-
#text(size: 5.8pt, weight: 600, tracking: 0.4pt, fill: mute)[#upper(label)]
|
|
403
|
-
#v(2pt)
|
|
404
|
-
#for l in lines [#block(spacing: 2.5pt)[#text(size: 7.6pt)[#l]]]
|
|
405
|
-
]),
|
|
406
|
-
)
|
|
407
|
-
]
|
|
408
|
-
|
|
409
|
-
// ═══ NOTES ═══════════════════════════════════════════════════════════════════
|
|
410
|
-
// The one thing the page does that the browser tool it came from could not: a
|
|
411
|
-
// rater writes on it during the discussion, and the sheet becomes the record of
|
|
412
|
-
// the conversation. So the lines print whether or not anything was typed above
|
|
413
|
-
// them.
|
|
414
|
-
#v(9pt)
|
|
415
|
-
#section-rule("Development notes")
|
|
416
|
-
#let typed = data.at("$body", default: "")
|
|
417
|
-
#if type(typed) != str [
|
|
418
|
-
#block(spacing: 6pt)[#text(size: 7.6pt)[#typed]]
|
|
419
|
-
]
|
|
420
|
-
#for _ in range(2) {
|
|
421
|
-
v(11pt)
|
|
422
|
-
line(length: 100%, stroke: 0.4pt + luma(80%))
|
|
423
|
-
}
|
|
424
|
-
#v(8pt)
|
|
425
|
-
#text(size: 6.2pt, fill: mute)[
|
|
426
|
-
Discussed with #box(width: 1.7in, stroke: (bottom: 0.4pt + luma(60%)))[]
|
|
427
|
-
#h(10pt) on #box(width: 1in, stroke: (bottom: 0.4pt + luma(60%)))[]
|
|
428
|
-
]
|
package/quills/usaf_letter/0.1.0/packages/tonguetoquill-usaf-letter/fonts/Cinzel/Cinzel-Regular.ttf
DELETED
|
Binary file
|
|
Binary file
|
package/quills/usaf_memo/0.3.0/packages/tonguetoquill-usaf-memo/fonts/Cinzel/Cinzel-Regular.ttf
DELETED
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/quills/classic_resume/{0.0.1 → 0.1.0}/packages/ttq-classic-resume/fonts/EBGaramond/OFL.txt
RENAMED
|
File without changes
|