@airmark/quiver 0.1.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.
Files changed (77) hide show
  1. package/Quiver.yaml +2 -0
  2. package/README.md +92 -0
  3. package/index.d.ts +16 -0
  4. package/index.js +28 -0
  5. package/package.json +44 -0
  6. package/quills/af4141/0.1.0/Quill.yaml +95 -0
  7. package/quills/af4141/0.1.0/assets/Figtree-Bold.ttf +0 -0
  8. package/quills/af4141/0.1.0/assets/Figtree-Italic.ttf +0 -0
  9. package/quills/af4141/0.1.0/assets/Figtree-Regular.ttf +0 -0
  10. package/quills/af4141/0.1.0/assets/GNU General Public License.txt +340 -0
  11. package/quills/af4141/0.1.0/assets/NimbusRomNo9L-Med.otf +0 -0
  12. package/quills/af4141/0.1.0/assets/NimbusRomNo9L-MedIta.otf +0 -0
  13. package/quills/af4141/0.1.0/assets/NimbusRomNo9L-Reg.otf +0 -0
  14. package/quills/af4141/0.1.0/assets/NimbusRomNo9L-RegIta.otf +0 -0
  15. package/quills/af4141/0.1.0/design/TASK.md +20 -0
  16. package/quills/af4141/0.1.0/design/af4141.pdf +0 -0
  17. package/quills/af4141/0.1.0/example.md +86 -0
  18. package/quills/af4141/0.1.0/packages/typst-af4141/FIELDS.json +3170 -0
  19. package/quills/af4141/0.1.0/packages/typst-af4141/form.typ +538 -0
  20. package/quills/af4141/0.1.0/packages/typst-af4141/lib.typ +270 -0
  21. package/quills/af4141/0.1.0/packages/typst-af4141/page1.png +0 -0
  22. package/quills/af4141/0.1.0/packages/typst-af4141/page2.png +0 -0
  23. package/quills/af4141/0.1.0/packages/typst-af4141/typst.toml +7 -0
  24. package/quills/af4141/0.1.0/plate.typ +67 -0
  25. package/quills/daf1206/0.1.0/DAFForm_1206_prepared.pdf +0 -0
  26. package/quills/daf1206/0.1.0/Quill.yaml +55 -0
  27. package/quills/daf1206/0.1.0/assets/arimo-v35-latin-700.ttf +0 -0
  28. package/quills/daf1206/0.1.0/assets/arimo-v35-latin-700italic.ttf +0 -0
  29. package/quills/daf1206/0.1.0/assets/arimo-v35-latin-italic.ttf +0 -0
  30. package/quills/daf1206/0.1.0/assets/arimo-v35-latin-regular.ttf +0 -0
  31. package/quills/daf1206/0.1.0/example.md +23 -0
  32. package/quills/daf1206/0.1.0/packages/typst-daf1206/FIELDS.json +158 -0
  33. package/quills/daf1206/0.1.0/packages/typst-daf1206/form.typ +36 -0
  34. package/quills/daf1206/0.1.0/packages/typst-daf1206/lib.typ +297 -0
  35. package/quills/daf1206/0.1.0/packages/typst-daf1206/page1.svg +826 -0
  36. package/quills/daf1206/0.1.0/packages/typst-daf1206/page2.svg +497 -0
  37. package/quills/daf1206/0.1.0/packages/typst-daf1206/typst.toml +7 -0
  38. package/quills/daf1206/0.1.0/plate.typ +47 -0
  39. package/quills/daf4392/0.1.0/Quill.yaml +139 -0
  40. package/quills/daf4392/0.1.0/assets/arimo-v35-latin-700.ttf +0 -0
  41. package/quills/daf4392/0.1.0/assets/arimo-v35-latin-700italic.ttf +0 -0
  42. package/quills/daf4392/0.1.0/assets/arimo-v35-latin-italic.ttf +0 -0
  43. package/quills/daf4392/0.1.0/assets/arimo-v35-latin-regular.ttf +0 -0
  44. package/quills/daf4392/0.1.0/assets/page1.png +0 -0
  45. package/quills/daf4392/0.1.0/example.md +34 -0
  46. package/quills/daf4392/0.1.0/packages/daf4392page2_pkg/FIELDS.json +9 -0
  47. package/quills/daf4392/0.1.0/packages/daf4392page2_pkg/form.typ +14 -0
  48. package/quills/daf4392/0.1.0/packages/daf4392page2_pkg/lib.typ +227 -0
  49. package/quills/daf4392/0.1.0/packages/daf4392page2_pkg/typst.toml +7 -0
  50. package/quills/daf4392/0.1.0/plate.typ +86 -0
  51. package/quills/usaf_memo/0.2.0/.quillignore +31 -0
  52. package/quills/usaf_memo/0.2.0/Quill.yaml +255 -0
  53. package/quills/usaf_memo/0.2.0/assets/dod_seal.png +0 -0
  54. package/quills/usaf_memo/0.2.0/assets/dow_seal.png +0 -0
  55. package/quills/usaf_memo/0.2.0/example.md +56 -0
  56. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/.gitignore +7 -0
  57. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/LICENSE +21 -0
  58. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/fonts/Cinzel/Cinzel-Regular.ttf +0 -0
  59. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/fonts/Cinzel/LICENSE +93 -0
  60. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/fonts/CopperplateCC/CopperplateCC-Heavy.otf +0 -0
  61. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/fonts/CopperplateCC/LICENSE.md +79 -0
  62. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/fonts/NimbusRomanNo9L/GNU General Public License.txt +340 -0
  63. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/fonts/NimbusRomanNo9L/NimbusRomNo9L-Med.otf +0 -0
  64. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/fonts/NimbusRomanNo9L/NimbusRomNo9L-MedIta.otf +0 -0
  65. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/fonts/NimbusRomanNo9L/NimbusRomNo9L-Reg.otf +0 -0
  66. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/fonts/NimbusRomanNo9L/NimbusRomNo9L-RegIta.otf +0 -0
  67. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/src/backmatter.typ +28 -0
  68. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/src/body.typ +344 -0
  69. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/src/config.typ +73 -0
  70. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/src/frontmatter.typ +137 -0
  71. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/src/indorsement.typ +111 -0
  72. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/src/lib.typ +57 -0
  73. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/src/mainmatter.typ +32 -0
  74. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/src/primitives.typ +321 -0
  75. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/src/utils.typ +356 -0
  76. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/typst.toml +27 -0
  77. package/quills/usaf_memo/0.2.0/plate.typ +85 -0
@@ -0,0 +1,270 @@
1
+ // Formalizer Engine – rendering engine
2
+ // Renders pixel-perfect PDF form replicas from a PyMuPDF-extracted schema.
3
+
4
+ /// Global configuration for text rendering.
5
+ /// Adjust these to change the overall form text appearance.
6
+ #let FORM_MAX_TEXT_SIZE = 14pt
7
+ #let FORM_MIN_TEXT_SIZE = 6pt
8
+ #let FORM_MIN_CHARS_PER_LINE = 7
9
+
10
+ /// Should this field shrink text to a single line rather than word-wrap?
11
+ /// True for short/narrow fields with brief content (grades, ranks, dates).
12
+ #let should-shrink-to-fit(display, width, height) = {
13
+ let aspect = width / height
14
+ let char-count = display.len()
15
+ char-count <= 10 or height < 20pt or aspect > 4.0
16
+ }
17
+
18
+ /// Render a text-like field with shrink-to-fit and word-wrap fallback.
19
+ #let render-text-field(display, width, height, x-inset, y-inset) = {
20
+ set par(leading: 0.25em)
21
+ context {
22
+ let avail-w = width - 2 * x-inset
23
+ let avail-h = height - 2 * y-inset
24
+ let shrink = should-shrink-to-fit(display, width, height)
25
+
26
+ let final-size = FORM_MIN_TEXT_SIZE
27
+ let current = FORM_MAX_TEXT_SIZE
28
+ let step = 0.5pt
29
+
30
+ while current >= FORM_MIN_TEXT_SIZE {
31
+ let m = if shrink {
32
+ // Measure as a single line (no width constraint → no wrapping)
33
+ measure(text(size: current, display))
34
+ } else {
35
+ // Measure with wrapping within the available width
36
+ measure(block(width: avail-w, text(size: current, display)))
37
+ }
38
+ let char-m = measure(text(size: current, "0" * FORM_MIN_CHARS_PER_LINE))
39
+
40
+ if m.width <= avail-w and m.height <= avail-h and char-m.width <= avail-w {
41
+ final-size = current
42
+ break
43
+ }
44
+ current = current - step
45
+ }
46
+
47
+ // Fallback: if shrink-to-fit hit min size and still overflows,
48
+ // re-try with word-wrap enabled as a last resort.
49
+ if shrink and current < FORM_MIN_TEXT_SIZE {
50
+ current = FORM_MAX_TEXT_SIZE
51
+ while current >= FORM_MIN_TEXT_SIZE {
52
+ let m = measure(block(width: avail-w, text(size: current, display)))
53
+ let char-m = measure(text(size: current, "0" * FORM_MIN_CHARS_PER_LINE))
54
+ if m.height <= avail-h and char-m.width <= avail-w {
55
+ final-size = current
56
+ break
57
+ }
58
+ current = current - step
59
+ }
60
+ }
61
+
62
+ // Default to vertically centered. Only top-align for tall "text areas".
63
+ let vert-align = if height >= 40pt { top } else { horizon }
64
+
65
+ box(
66
+ width: width,
67
+ height: height,
68
+ clip: true,
69
+ inset: (x: x-inset, y: y-inset),
70
+ align(left + vert-align, text(size: final-size, display)),
71
+ )
72
+ }
73
+ }
74
+
75
+ /// Render a single field's content overlay.
76
+ ///
77
+ /// - field-type (str): normalised lowercase type
78
+ /// - value: user-supplied value for this field (or none)
79
+ /// - width (length): field width
80
+ /// - height (length): field height
81
+ /// - field (dictionary): raw field entry from the schema
82
+ #let render-field(field-type, value, width, height, field) = {
83
+ if field-type == "text" {
84
+ if value != none and str(value) != "" {
85
+ render-text-field(str(value), width, height, 1.5pt, 1pt)
86
+ }
87
+ } else if field-type == "checkbox" {
88
+ if value == true {
89
+ box(
90
+ width: width,
91
+ height: height,
92
+ align(center + horizon, text(size: height * 0.8, "✓")),
93
+ )
94
+ }
95
+ } else if field-type == "radio" {
96
+ // value is true when this specific button is the selected one
97
+ // (resolved at group level before calling this helper)
98
+ if value == true {
99
+ let dot-r = calc.min(width, height) * 0.3
100
+ box(
101
+ width: width,
102
+ height: height,
103
+ align(center + horizon, circle(radius: dot-r, fill: black)),
104
+ )
105
+ }
106
+ } else if field-type == "combobox" or field-type == "listbox" {
107
+ let display = if value != none { str(value) } else { "" }
108
+ // Resolve export value → display label when options are present
109
+ if field.at("options", default: none) != none and value != none {
110
+ for opt in field.options {
111
+ if str(opt.at(0)) == str(value) {
112
+ display = str(opt.at(1))
113
+ }
114
+ }
115
+ }
116
+ if display != "" {
117
+ render-text-field(display, width, height, 2pt, 1pt)
118
+ }
119
+ }
120
+ }
121
+
122
+ /// Determine whether a single radio button should appear selected.
123
+ ///
124
+ /// Strategy:
125
+ /// 1. If the field carries an `export_value` key, match against it.
126
+ /// 2. Otherwise fall back to matching the 0-based index within the group
127
+ /// (stringified) against the supplied value.
128
+ #let radio-button-selected(field, group-value, index-in-group) = {
129
+ if group-value == none { return false }
130
+ let ev = field.at("export_value", default: none)
131
+ if ev != none {
132
+ return str(ev) == str(group-value)
133
+ }
134
+ // Fallback: match against the stringified index
135
+ str(index-in-group) == str(group-value)
136
+ }
137
+
138
+ /// Draw a debug overlay rectangle with a label for a field.
139
+ ///
140
+ /// - field-type (str): normalised lowercase type
141
+ /// - name (str): field name
142
+ /// - width (length): field width
143
+ /// - height (length): field height
144
+ #let debug-overlay(field-type, name, width, height) = {
145
+ let color = if field-type == "text" {
146
+ rgb(0, 0, 255, 40%)
147
+ } else if field-type == "checkbox" {
148
+ rgb(0, 128, 0, 40%)
149
+ } else if field-type == "radio" {
150
+ rgb(255, 165, 0, 40%)
151
+ } else if field-type == "combobox" {
152
+ rgb(128, 0, 128, 40%)
153
+ } else if field-type == "listbox" {
154
+ rgb(0, 128, 128, 40%)
155
+ } else {
156
+ rgb(128, 128, 128, 40%)
157
+ }
158
+
159
+ let stroke-color = if field-type == "text" {
160
+ rgb(0, 0, 255)
161
+ } else if field-type == "checkbox" {
162
+ rgb(0, 128, 0)
163
+ } else if field-type == "radio" {
164
+ rgb(255, 165, 0)
165
+ } else if field-type == "combobox" {
166
+ rgb(128, 0, 128)
167
+ } else if field-type == "listbox" {
168
+ rgb(0, 128, 128)
169
+ } else {
170
+ rgb(128, 128, 128)
171
+ }
172
+
173
+ // Insert zero-width spaces after _ and - so the label can wrap
174
+ let breakable-name = name.replace("_", "_\u{200B}").replace("-", "-\u{200B}")
175
+ let label = breakable-name + " [" + field-type + "]"
176
+
177
+ box(width: width, height: height, {
178
+ // Semi-transparent colored background
179
+ rect(width: 100%, height: 100%, fill: color, stroke: 0.5pt + stroke-color)
180
+ // Label in top-left — uses block so text wraps within field width
181
+ place(
182
+ top + left,
183
+ dx: 1pt,
184
+ dy: 1pt,
185
+ block(
186
+ width: calc.max(width - 2pt, 10pt),
187
+ fill: white,
188
+ inset: (x: 2pt, y: 1pt),
189
+ radius: 2pt,
190
+ stroke: 0.3pt + stroke-color,
191
+ breakable: false,
192
+ text(size: 5pt, fill: stroke-color, weight: "bold", label),
193
+ ),
194
+ )
195
+ })
196
+ }
197
+
198
+ /// Main entry point.
199
+ ///
200
+ /// - schema (dictionary): result of `json("FIELDS.json")`
201
+ /// - backgrounds (array): list of image paths / bytes, one per page
202
+ /// - values (dictionary): field name → value; omit to render blank
203
+ /// - debug (bool): when true, draw colored overlays on each field
204
+ #let render-form(schema: none, backgrounds: (), values: (:), debug: false) = {
205
+ assert(schema != none, message: "render-form: `schema` is required")
206
+ assert(backgrounds.len() > 0, message: "render-form: `backgrounds` is required")
207
+ let pages = schema.pages
208
+ let fields = schema.fields
209
+
210
+ // Track how many radio buttons we have seen per group so far
211
+ let radio-counters = (:)
212
+
213
+ for (i, page-info) in pages.enumerate() {
214
+ let page-num = i + 1
215
+ let page-fields = fields.filter(f => f.page == page-num)
216
+
217
+ let bg = backgrounds.at(i)
218
+ let pw = page-info.width * 1pt
219
+ let ph = page-info.height * 1pt
220
+
221
+ page(
222
+ width: pw,
223
+ height: ph,
224
+ margin: 0pt,
225
+ )[
226
+ // Background image (the original PDF page rasterised as PNG)
227
+ #place(top + left, image(bg, width: pw, height: ph, fit: "stretch"))
228
+
229
+ // Field overlays
230
+ #for field in page-fields.filter(f => ("text", "checkbox", "radio", "combobox", "listbox").contains(lower(
231
+ f.type,
232
+ ))) {
233
+ let x = field.bbox.at(0) * 1pt
234
+ let y = field.bbox.at(1) * 1pt
235
+ let w = (field.bbox.at(2) - field.bbox.at(0)) * 1pt
236
+ let h = (field.bbox.at(3) - field.bbox.at(1)) * 1pt
237
+
238
+ let field-type = lower(field.type)
239
+ let val = values.at(field.name, default: none)
240
+
241
+ // --- Radio: resolve group-level value to per-button boolean ---
242
+ if field-type == "radio" {
243
+ let group-name = field.name
244
+ let idx = radio-counters.at(group-name, default: 0)
245
+ radio-counters.insert(group-name, idx + 1)
246
+ val = radio-button-selected(field, val, idx)
247
+ }
248
+
249
+ place(
250
+ top + left,
251
+ dx: x,
252
+ dy: y,
253
+ render-field(field-type, val, w, h, field),
254
+ )
255
+
256
+ if debug {
257
+ place(
258
+ top + left,
259
+ dx: x,
260
+ dy: y,
261
+ debug-overlay(field-type, field.name, w, h),
262
+ )
263
+ }
264
+
265
+ // Zero-width fence to break PDF viewer text-selection grouping
266
+ place(top + left, dx: x, dy: y, text(size: 0.001pt, "\u{FEFF}"))
267
+ }
268
+ ]
269
+ }
270
+ }
@@ -0,0 +1,7 @@
1
+ [package]
2
+ name = "typst-af4141"
3
+ version = "0.1.0"
4
+ entrypoint = "form.typ"
5
+ authors = ["formalizer"]
6
+ license = "Apache-2.0"
7
+ description = "Fillable form package generated by formalizer"
@@ -0,0 +1,67 @@
1
+ #import "@local/quillmark-helper:0.1.0": data
2
+ #import "@local/typst-af4141:0.1.0": form
3
+
4
+ #set text(font: ("NimbusRomNo9L", "Times New Roman", "serif"))
5
+
6
+ // `type: date` fields arrive as Typst `datetime`; PDF overlay expects strings.
7
+ // Missing / blank dates: helper uses `none`; empty strings may also appear from input.
8
+ #let form-cell(v) = {
9
+ if v == none { "" }
10
+ else if type(v) == str and v == "" { "" }
11
+ else if type(v) == datetime {
12
+ v.display("[month padding:none]/[day padding:none]/[year]")
13
+ } else {
14
+ str(v)
15
+ }
16
+ }
17
+
18
+ // Column order within each 7-field row group
19
+ #let col-keys = (
20
+ "date",
21
+ "action",
22
+ "written_grade",
23
+ "written_grade_date",
24
+ "positional_grade",
25
+ "positional_grade_date",
26
+ "auth_or_remarks",
27
+ )
28
+
29
+ // Build the values dictionary for the form
30
+ #let vals = (:)
31
+
32
+ // --- Admin fields (page 1 header) ---
33
+ #if "name" in data { vals.insert("commonforms_text_p1_1", data.name) }
34
+ #if "unit" in data { vals.insert("commonforms_text_p1_2", data.unit) }
35
+ #if "grade" in data { vals.insert("commonforms_text_p1_3", data.grade) }
36
+ #if "commanders_auth" in data { vals.insert("commonforms_text_p1_116", data.commanders_auth) }
37
+
38
+ // --- Experience table rows from cards ---
39
+ // The form supports 16 rows on page 1 and 21 rows on page 2 (37 total).
40
+ // Overflow rows are silently ignored.
41
+ #let max-rows = 37
42
+ #{
43
+ let row = 0
44
+ for card in data.CARDS {
45
+ if card.CARD == "experience" {
46
+ if row < max-rows {
47
+ for (col, key) in col-keys.enumerate() {
48
+ let value = form-cell(card.at(key, default: none))
49
+ if value != "" {
50
+ let field-name = if row < 16 {
51
+ // Page 1: fields start at index 4, stride 7
52
+ "commonforms_text_p1_" + str(4 + row * 7 + col)
53
+ } else {
54
+ // Page 2: fields start at index 1, stride 7
55
+ "commonforms_text_p2_" + str(1 + (row - 16) * 7 + col)
56
+ }
57
+ vals.insert(field-name, value)
58
+ }
59
+ }
60
+ }
61
+ row = row + 1
62
+ }
63
+ }
64
+ }
65
+
66
+ // Render the form with assembled values
67
+ #form(..vals)
@@ -0,0 +1,55 @@
1
+ quill:
2
+ name: daf1206
3
+ version: 0.1.0
4
+ backend: typst
5
+ plate_file: plate.typ
6
+ example_file: example.md
7
+ description: "DAF Form 1206 — Nomination for Award"
8
+
9
+ main:
10
+ ui:
11
+ hide_body: false
12
+ fields:
13
+ award:
14
+ title: Award Program
15
+ type: string
16
+ category_if_applicable:
17
+ title: Award Category
18
+ type: string
19
+ ui:
20
+ compact: true
21
+ award_period:
22
+ title: Award Period
23
+ type: string
24
+ ui:
25
+ compact: true
26
+ rankname_of_nominee:
27
+ title: Nominee Rank & Name
28
+ type: string
29
+ ui:
30
+ compact: true
31
+ majcom_fldcom_foa_or_dru:
32
+ title: Command (MAJCOM/FLDCOM/FOA/DRU)
33
+ type: string
34
+ ui:
35
+ compact: true
36
+ dafsc_duty_title:
37
+ title: DAFSC & Duty Title
38
+ type: string
39
+ nominees_telephone_dsn_commercial:
40
+ title: Nominee Phone
41
+ type: string
42
+ unit_office_symbol_street_address_base_state_zip:
43
+ title: Unit Mailing Address
44
+ type: string
45
+ unit_commander_rank_name_and_telephone:
46
+ title: Unit Commander
47
+ type: string
48
+
49
+ cards:
50
+ accomplishments_continued:
51
+ title: Specific Accomplishments (Continued — Page 2)
52
+ description: Optional. Add this card only when page 2 overflow is required. Use the card body for continued bullets. Rank/name on page 2 matches the main nominee line automatically.
53
+ ui:
54
+ hide_body: false
55
+ fields: {}
@@ -0,0 +1,23 @@
1
+ ---
2
+ QUILL: daf1206@0.1.0
3
+ award: "CY2018 Stripes for Exceptional Performers II Board"
4
+ category_if_applicable: "Senior Master Sgt"
5
+ award_period: "N/A"
6
+ rankname_of_nominee: "Smith, John Q., SMSgt"
7
+ majcom_fldcom_foa_or_dru: "MAJCOM of Assignment"
8
+ dafsc_duty_title: "3F071/NCOIC, 123rd Force Support Squadron"
9
+ nominees_telephone_dsn_commercial: "DSN XXXX-XXXX, Comm (XXX) XXX-XXXX"
10
+ unit_office_symbol_street_address_base_state_zip: "123 FSS/FMSPD, Someplace AFB, CO XXXXX"
11
+ unit_commander_rank_name_and_telephone: "Lt Col Jane C. Doe, DSN XXX-XXXXXXX, Comm (XXX) XXX-XXXX"
12
+ ---
13
+
14
+ Use this main body for page 1 accomplishments.
15
+ - Keep bullet format.
16
+ - Replace all placeholder values.
17
+
18
+ ---
19
+ CARD: accomplishments_continued
20
+ ---
21
+
22
+ Use this card body only if page 2 overflow is needed.
23
+ - Add continuation bullets here.
@@ -0,0 +1,158 @@
1
+ {
2
+ "pages": [
3
+ {
4
+ "width": 612.0,
5
+ "height": 792.0
6
+ },
7
+ {
8
+ "width": 612.0,
9
+ "height": 792.0
10
+ }
11
+ ],
12
+ "fields": [
13
+ {
14
+ "name": "AWARD",
15
+ "type": "text",
16
+ "bbox": [
17
+ 21.479999542236328,
18
+ 30.5999755859375,
19
+ 307.55999755859375,
20
+ 46.79998779296875
21
+ ],
22
+ "page": 1,
23
+ "options": null
24
+ },
25
+ {
26
+ "name": "CATEGORY If Applicable",
27
+ "type": "text",
28
+ "bbox": [
29
+ 309.1199951171875,
30
+ 30.719970703125,
31
+ 423.3599853515625,
32
+ 46.79998779296875
33
+ ],
34
+ "page": 1,
35
+ "options": null
36
+ },
37
+ {
38
+ "name": "AWARD PERIOD",
39
+ "type": "text",
40
+ "bbox": [
41
+ 424.9200134277344,
42
+ 31.20001220703125,
43
+ 593.4000244140625,
44
+ 46.79998779296875
45
+ ],
46
+ "page": 1,
47
+ "options": null
48
+ },
49
+ {
50
+ "name": "RANKNAME OF NOMINEE First Middle Initial Last",
51
+ "type": "text",
52
+ "bbox": [
53
+ 21.360000610351562,
54
+ 54.0,
55
+ 348.8399963378906,
56
+ 68.52001953125
57
+ ],
58
+ "page": 1,
59
+ "options": null
60
+ },
61
+ {
62
+ "name": "MAJCOM FLDCOM FOA OR DRU",
63
+ "type": "text",
64
+ "bbox": [
65
+ 350.1600036621094,
66
+ 54.0,
67
+ 593.52001953125,
68
+ 68.52001953125
69
+ ],
70
+ "page": 1,
71
+ "options": null
72
+ },
73
+ {
74
+ "name": "DAFSCDUTY TITLE",
75
+ "type": "text",
76
+ "bbox": [
77
+ 21.479999542236328,
78
+ 76.91998291015625,
79
+ 286.9200134277344,
80
+ 93.96002197265625
81
+ ],
82
+ "page": 1,
83
+ "options": null
84
+ },
85
+ {
86
+ "name": "NOMINEES TELEPHONE DSN Commercial",
87
+ "type": "text",
88
+ "bbox": [
89
+ 288.4800109863281,
90
+ 76.91998291015625,
91
+ 593.4000244140625,
92
+ 93.96002197265625
93
+ ],
94
+ "page": 1,
95
+ "options": null
96
+ },
97
+ {
98
+ "name": "UNITOFFICE SYMBOLSTREET ADDRESSBASESTATEZIP CODE",
99
+ "type": "text",
100
+ "bbox": [
101
+ 21.360000610351562,
102
+ 101.280029296875,
103
+ 593.52001953125,
104
+ 115.79998779296875
105
+ ],
106
+ "page": 1,
107
+ "options": null
108
+ },
109
+ {
110
+ "name": "RANKNAME OF UNIT COMMANDER First Middle Initial LastCOMMANDERS TELEPHONE DSN Commercial",
111
+ "type": "text",
112
+ "bbox": [
113
+ 21.479999542236328,
114
+ 123.3599853515625,
115
+ 593.4000244140625,
116
+ 139.20001220703125
117
+ ],
118
+ "page": 1,
119
+ "options": null
120
+ },
121
+ {
122
+ "name": "SPECIFIC ACCOMPLISHMENTS Use Performance Statements IAW DAFMAN 362806",
123
+ "type": "text",
124
+ "bbox": [
125
+ 22.079999923706055,
126
+ 147.1199951171875,
127
+ 592.7999877929688,
128
+ 767.4000244140625
129
+ ],
130
+ "page": 1,
131
+ "options": null
132
+ },
133
+ {
134
+ "name": "RANKNAME OF NOMINEE First Middle Initial Last_2",
135
+ "type": "text",
136
+ "bbox": [
137
+ 21.479999542236328,
138
+ 36.84002685546875,
139
+ 593.4000244140625,
140
+ 54.84002685546875
141
+ ],
142
+ "page": 2,
143
+ "options": null
144
+ },
145
+ {
146
+ "name": "SPECIFIC ACCOMPLISHMENTS Use Performance Statements IAW DAFMAN 362806 Continued",
147
+ "type": "text",
148
+ "bbox": [
149
+ 22.079999923706055,
150
+ 62.8800048828125,
151
+ 592.7999877929688,
152
+ 769.2000122070312
153
+ ],
154
+ "page": 2,
155
+ "options": null
156
+ }
157
+ ]
158
+ }
@@ -0,0 +1,36 @@
1
+ // form.typ (generated — do not edit)
2
+ #import "lib.typ": render-form
3
+
4
+ #let form(
5
+ debug: false,
6
+ AWARD: "", // text
7
+ CATEGORY_If_Applicable: "", // text
8
+ AWARD_PERIOD: "", // text
9
+ RANKNAME_OF_NOMINEE_First_Middle_Initial_Last: "", // text
10
+ MAJCOM_FLDCOM_FOA_OR_DRU: "", // text
11
+ DAFSCDUTY_TITLE: "", // text
12
+ NOMINEES_TELEPHONE__DSN__Commercial: "", // text
13
+ UNITOFFICE_SYMBOLSTREET_ADDRESSBASESTATEZIP_CODE: "", // text
14
+ RANKNAME_OF_UNIT_COMMANDER_First_Middle_Initial_LastCOMMANDERS_TELEPHONE_DSN__Commercial: "", // text
15
+ SPECIFIC_ACCOMPLISHMENTS_Use_Performance_Statements_IAW_DAFMAN_362806: "", // text
16
+ RANKNAME_OF_NOMINEE_First_Middle_Initial_Last_2: "", // text
17
+ SPECIFIC_ACCOMPLISHMENTS_Use_Performance_Statements_IAW_DAFMAN_362806_Continued: "", // text
18
+ ) = render-form(
19
+ schema: json("FIELDS.json"),
20
+ backgrounds: ("page1.svg", "page2.svg",),
21
+ values: (
22
+ "AWARD": AWARD,
23
+ "CATEGORY If Applicable": CATEGORY_If_Applicable,
24
+ "AWARD PERIOD": AWARD_PERIOD,
25
+ "RANKNAME OF NOMINEE First Middle Initial Last": RANKNAME_OF_NOMINEE_First_Middle_Initial_Last,
26
+ "MAJCOM FLDCOM FOA OR DRU": MAJCOM_FLDCOM_FOA_OR_DRU,
27
+ "DAFSCDUTY TITLE": DAFSCDUTY_TITLE,
28
+ "NOMINEES TELEPHONE DSN Commercial": NOMINEES_TELEPHONE__DSN__Commercial,
29
+ "UNITOFFICE SYMBOLSTREET ADDRESSBASESTATEZIP CODE": UNITOFFICE_SYMBOLSTREET_ADDRESSBASESTATEZIP_CODE,
30
+ "RANKNAME OF UNIT COMMANDER First Middle Initial LastCOMMANDERS TELEPHONE DSN Commercial": RANKNAME_OF_UNIT_COMMANDER_First_Middle_Initial_LastCOMMANDERS_TELEPHONE_DSN__Commercial,
31
+ "SPECIFIC ACCOMPLISHMENTS Use Performance Statements IAW DAFMAN 362806": SPECIFIC_ACCOMPLISHMENTS_Use_Performance_Statements_IAW_DAFMAN_362806,
32
+ "RANKNAME OF NOMINEE First Middle Initial Last_2": RANKNAME_OF_NOMINEE_First_Middle_Initial_Last_2,
33
+ "SPECIFIC ACCOMPLISHMENTS Use Performance Statements IAW DAFMAN 362806 Continued": SPECIFIC_ACCOMPLISHMENTS_Use_Performance_Statements_IAW_DAFMAN_362806_Continued,
34
+ ),
35
+ debug: debug,
36
+ )