@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,7 @@
1
+ [package]
2
+ name = "typst-daf1206"
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,47 @@
1
+ #import "@local/quillmark-helper:0.1.0": data
2
+ #import "@local/typst-daf1206:0.1.0": form
3
+
4
+ #set text(font: "Arimo")
5
+
6
+ // Map snake_case Quill `data` keys to generated `form.typ` parameter names.
7
+ #let vals = (:)
8
+
9
+ #if "award" in data { vals.insert("AWARD", data.award) }
10
+ #if "category_if_applicable" in data { vals.insert("CATEGORY_If_Applicable", data.category_if_applicable) }
11
+ #if "award_period" in data { vals.insert("AWARD_PERIOD", data.award_period) }
12
+ #if "rankname_of_nominee" in data {
13
+ vals.insert("RANKNAME_OF_NOMINEE_First_Middle_Initial_Last", data.rankname_of_nominee)
14
+ vals.insert("RANKNAME_OF_NOMINEE_First_Middle_Initial_Last_2", data.rankname_of_nominee)
15
+ }
16
+ #if "majcom_fldcom_foa_or_dru" in data { vals.insert("MAJCOM_FLDCOM_FOA_OR_DRU", data.majcom_fldcom_foa_or_dru) }
17
+ #if "dafsc_duty_title" in data { vals.insert("DAFSCDUTY_TITLE", data.dafsc_duty_title) }
18
+ #if "nominees_telephone_dsn_commercial" in data {
19
+ vals.insert("NOMINEES_TELEPHONE__DSN__Commercial", data.nominees_telephone_dsn_commercial)
20
+ }
21
+ #if "unit_office_symbol_street_address_base_state_zip" in data {
22
+ vals.insert(
23
+ "UNITOFFICE_SYMBOLSTREET_ADDRESSBASESTATEZIP_CODE",
24
+ data.unit_office_symbol_street_address_base_state_zip,
25
+ )
26
+ }
27
+ #if "unit_commander_rank_name_and_telephone" in data {
28
+ vals.insert(
29
+ "RANKNAME_OF_UNIT_COMMANDER_First_Middle_Initial_LastCOMMANDERS_TELEPHONE_DSN__Commercial",
30
+ data.unit_commander_rank_name_and_telephone,
31
+ )
32
+ }
33
+ #if "BODY" in data {
34
+ vals.insert(
35
+ "SPECIFIC_ACCOMPLISHMENTS_Use_Performance_Statements_IAW_DAFMAN_362806",
36
+ data.BODY,
37
+ )
38
+ }
39
+
40
+ #let continued-key = "SPECIFIC_ACCOMPLISHMENTS_Use_Performance_Statements_IAW_DAFMAN_362806_Continued"
41
+ #for card in data.CARDS {
42
+ if card.CARD == "accomplishments_continued" and continued-key not in vals and "BODY" in card {
43
+ vals.insert(continued-key, card.BODY)
44
+ }
45
+ }
46
+
47
+ #form(..vals)
@@ -0,0 +1,139 @@
1
+ quill:
2
+ name: daf4392
3
+ version: 0.1.0
4
+ backend: typst
5
+ plate_file: plate.typ
6
+ example_file: example.md
7
+ description: "DAF Form 4392 - Pre-Departure Safety Briefing (Page 2)"
8
+
9
+ main:
10
+ ui:
11
+ hide_body: true
12
+ fields:
13
+ transportation_mode:
14
+ title: Mode of Transportation
15
+ type: string
16
+ enum: [pmv, airplane, bus, train, motorcycle, other]
17
+ required: true
18
+ description: "Matches the check box."
19
+
20
+
21
+ departure_date:
22
+ title: Departure Date
23
+ type: date
24
+ required: true
25
+ ui:
26
+ compact: true
27
+ description: "Date of initial departure."
28
+
29
+ final_destination:
30
+ title: Final Destination
31
+ type: string
32
+ required: true
33
+ ui:
34
+ compact: true
35
+ description: "Final travel destination."
36
+
37
+ dept_flight_num:
38
+ title: Departure Flight Number
39
+ type: string
40
+ ui:
41
+ compact: true
42
+ description: "Departure flight number. (tenative or confirmed)"
43
+
44
+ arrival_flight_num:
45
+ title: Arrival Flight Number
46
+ type: string
47
+ ui:
48
+ compact: true
49
+ description: "Arrival flight number. (tenative or confirmed)"
50
+
51
+ notes:
52
+ title: Notes
53
+ type: string
54
+ description: "Additional notes or remarks for the travel."
55
+
56
+ organization:
57
+ title: Organization
58
+ type: string
59
+ required: true
60
+ ui:
61
+ compact: true
62
+ description: "Unit / Organization."
63
+
64
+ briefed_date:
65
+ title: Date Briefed
66
+ type: date
67
+ required: true
68
+ ui:
69
+ compact: true
70
+ description: "Put in today's date."
71
+
72
+ briefee_name:
73
+ title: Individual Receiving Brief (Name)
74
+ type: string
75
+ required: true
76
+ ui:
77
+ compact: true
78
+ description: "Put in your Name (Last, First)."
79
+
80
+ briefee_grade:
81
+ title: Individual Receiving Brief (Grade)
82
+ type: string
83
+ ui:
84
+ compact: true
85
+ description: "Put in your Grade."
86
+
87
+ emergency_contact_name:
88
+ title: Emergency Contact Name
89
+ type: string
90
+ description: "Put in your Emergency Contact Name."
91
+
92
+ emergency_contact_phone:
93
+ title: Emergency Contact Phone
94
+ type: string
95
+ description: "Put in your Emergency Contact's Phone Number."
96
+
97
+ cards:
98
+ itinerary:
99
+ title: Proposed Travel Itinerary
100
+ description: "Each card represents one row in the travel itinerary table. Up to 10 rows are supported."
101
+ ui:
102
+ hide_body: true
103
+ default_title: Leg
104
+ fields:
105
+ date:
106
+ title: Date
107
+ type: date
108
+ ui:
109
+ group: Itinerary Entry
110
+ compact: true
111
+ description: "Date for the itinerary row."
112
+ departure_point:
113
+ title: Departure Point
114
+ type: string
115
+ ui:
116
+ group: Itinerary Entry
117
+ compact: true
118
+ description: "Point of departure."
119
+ arrival_point:
120
+ title: Arrival Point
121
+ type: string
122
+ ui:
123
+ group: Itinerary Entry
124
+ compact: true
125
+ description: "Point of arrival."
126
+ rest_length:
127
+ title: Length of Rest Period
128
+ type: string
129
+ ui:
130
+ group: Itinerary Entry
131
+ compact: true
132
+ description: "Duration of stay at arrival point"
133
+ mileage:
134
+ title: Approximate Mileage
135
+ type: string
136
+ ui:
137
+ group: Itinerary Entry
138
+ compact: true
139
+ description: "Approximate mileage for this leg (leave blank if not applicable, e.g., flights)."
@@ -0,0 +1,34 @@
1
+ ---
2
+ QUILL: daf4392
3
+
4
+ transportation_mode: "other"
5
+ departure_date: 2026-03-26
6
+ final_destination: "123 Sesame St, Fake City, MS"
7
+ notes: "Visiting Donald Duck over 3 day weekend."
8
+ organization: "333 TRS"
9
+ briefed_date: 2026-03-25
10
+ briefee_name: "Doe, Jane"
11
+ briefee_grade: "O-1"
12
+ briefer_name: ""
13
+ briefer_grade: ""
14
+ emergency_contact_name: "John Doe"
15
+ emergency_contact_phone: "999-999-9999"
16
+ ---
17
+
18
+ ---
19
+ CARD: itinerary
20
+ date: 2026-03-26
21
+ departure_point: "Biloxi, MS"
22
+ arrival_point: "Fake City, MS"
23
+ rest_length: "2 days"
24
+ mileage: "250"
25
+ ---
26
+
27
+ ---
28
+ CARD: itinerary
29
+ date: 2026-03-29
30
+ departure_point: "Fake City, MS"
31
+ arrival_point: "Biloxi, MS"
32
+ rest_length: "0"
33
+ mileage: "0"
34
+ ---
@@ -0,0 +1,9 @@
1
+ {
2
+ "pages": [
3
+ {
4
+ "width": 612.0,
5
+ "height": 792.0
6
+ }
7
+ ],
8
+ "fields": []
9
+ }
@@ -0,0 +1,14 @@
1
+ // form.typ (generated � do not edit)
2
+ #import "lib.typ": render-form
3
+
4
+ #let form(
5
+ debug: false,
6
+
7
+ ) = render-form(
8
+ schema: json("FIELDS.json"),
9
+ backgrounds: ("page1.png",),
10
+ values: (
11
+ ,
12
+ ),
13
+ debug: debug,
14
+ )
@@ -0,0 +1,227 @@
1
+ // Formalizer Engine – rendering engine
2
+ // Renders pixel-perfect PDF form replicas from a PyMuPDF-extracted schema.
3
+
4
+ /// Render a single field's content overlay.
5
+ ///
6
+ /// - field-type (str): normalised lowercase type
7
+ /// - value: user-supplied value for this field (or none)
8
+ /// - width (length): field width
9
+ /// - height (length): field height
10
+ /// - field (dictionary): raw field entry from the schema
11
+ #let render-field(field-type, value, width, height, field) = {
12
+ if field-type == "text" {
13
+ if value != none and str(value) != "" {
14
+ context {
15
+ let default-size = height * 0.6
16
+ let min-size = 6pt
17
+ let x-inset = 1.5pt
18
+ let m = measure(text(size: default-size, str(value)))
19
+ let scale = calc.min(1.0, (width - 2 * x-inset) / m.width)
20
+ let final-size = calc.max(min-size, default-size * scale)
21
+ box(
22
+ width: width,
23
+ height: height,
24
+ clip: true,
25
+ inset: (x: x-inset),
26
+ align(left + horizon, text(size: final-size, str(value))),
27
+ )
28
+ }
29
+ }
30
+ } else if field-type == "checkbox" {
31
+ if value == true {
32
+ box(
33
+ width: width,
34
+ height: height,
35
+ align(center + horizon, text(size: height * 0.8, "✓")),
36
+ )
37
+ }
38
+ } else if field-type == "radio" {
39
+ // value is true when this specific button is the selected one
40
+ // (resolved at group level before calling this helper)
41
+ if value == true {
42
+ let dot-r = calc.min(width, height) * 0.3
43
+ box(
44
+ width: width,
45
+ height: height,
46
+ align(center + horizon, circle(radius: dot-r, fill: black)),
47
+ )
48
+ }
49
+ } else if field-type == "combobox" or field-type == "listbox" {
50
+ let display = if value != none { str(value) } else { "" }
51
+ // Resolve export value → display label when options are present
52
+ if field.at("options", default: none) != none and value != none {
53
+ for opt in field.options {
54
+ if str(opt.at(0)) == str(value) {
55
+ display = str(opt.at(1))
56
+ }
57
+ }
58
+ }
59
+ if display != "" {
60
+ context {
61
+ let default-size = height * 0.6
62
+ let min-size = 6pt
63
+ let x-inset = 2pt
64
+ let m = measure(text(size: default-size, display))
65
+ let scale = calc.min(1.0, (width - 2 * x-inset) / m.width)
66
+ let final-size = calc.max(min-size, default-size * scale)
67
+ box(
68
+ width: width,
69
+ height: height,
70
+ clip: true,
71
+ inset: (x: x-inset),
72
+ align(left + horizon, text(size: final-size, display)),
73
+ )
74
+ }
75
+ }
76
+ }
77
+ }
78
+
79
+ /// Determine whether a single radio button should appear selected.
80
+ ///
81
+ /// Strategy:
82
+ /// 1. If the field carries an `export_value` key, match against it.
83
+ /// 2. Otherwise fall back to matching the 0-based index within the group
84
+ /// (stringified) against the supplied value.
85
+ #let radio-button-selected(field, group-value, index-in-group) = {
86
+ if group-value == none { return false }
87
+ let ev = field.at("export_value", default: none)
88
+ if ev != none {
89
+ return str(ev) == str(group-value)
90
+ }
91
+ // Fallback: match against the stringified index
92
+ str(index-in-group) == str(group-value)
93
+ }
94
+
95
+ /// Draw a debug overlay rectangle with a label for a field.
96
+ ///
97
+ /// - field-type (str): normalised lowercase type
98
+ /// - name (str): field name
99
+ /// - width (length): field width
100
+ /// - height (length): field height
101
+ #let debug-overlay(field-type, name, width, height) = {
102
+ let color = if field-type == "text" {
103
+ rgb(0, 0, 255, 40%)
104
+ } else if field-type == "checkbox" {
105
+ rgb(0, 128, 0, 40%)
106
+ } else if field-type == "radio" {
107
+ rgb(255, 165, 0, 40%)
108
+ } else if field-type == "combobox" {
109
+ rgb(128, 0, 128, 40%)
110
+ } else if field-type == "listbox" {
111
+ rgb(0, 128, 128, 40%)
112
+ } else {
113
+ rgb(128, 128, 128, 40%)
114
+ }
115
+
116
+ let stroke-color = if field-type == "text" {
117
+ rgb(0, 0, 255)
118
+ } else if field-type == "checkbox" {
119
+ rgb(0, 128, 0)
120
+ } else if field-type == "radio" {
121
+ rgb(255, 165, 0)
122
+ } else if field-type == "combobox" {
123
+ rgb(128, 0, 128)
124
+ } else if field-type == "listbox" {
125
+ rgb(0, 128, 128)
126
+ } else {
127
+ rgb(128, 128, 128)
128
+ }
129
+
130
+ // Insert zero-width spaces after _ and - so the label can wrap
131
+ let breakable-name = name.replace("_", "_\u{200B}").replace("-", "-\u{200B}")
132
+ let label = breakable-name + " [" + field-type + "]"
133
+
134
+ box(width: width, height: height, {
135
+ // Semi-transparent colored background
136
+ rect(width: 100%, height: 100%, fill: color, stroke: 0.5pt + stroke-color)
137
+ // Label in top-left — uses block so text wraps within field width
138
+ place(
139
+ top + left,
140
+ dx: 1pt,
141
+ dy: 1pt,
142
+ block(
143
+ width: calc.max(width - 2pt, 10pt),
144
+ fill: white,
145
+ inset: (x: 2pt, y: 1pt),
146
+ radius: 2pt,
147
+ stroke: 0.3pt + stroke-color,
148
+ breakable: false,
149
+ text(size: 5pt, fill: stroke-color, weight: "bold", label),
150
+ ),
151
+ )
152
+ })
153
+ }
154
+
155
+ /// Main entry point.
156
+ ///
157
+ /// - schema (dictionary): result of `json("FIELDS.json")`
158
+ /// - backgrounds (array): list of image paths / bytes, one per page
159
+ /// - values (dictionary): field name → value; omit to render blank
160
+ /// - debug (bool): when true, draw colored overlays on each field
161
+ #let render-form(schema: none, backgrounds: (), values: (:), debug: false) = {
162
+ assert(schema != none, message: "render-form: `schema` is required")
163
+ assert(backgrounds.len() > 0, message: "render-form: `backgrounds` is required")
164
+ let pages = schema.pages
165
+ let fields = schema.fields
166
+
167
+ // Track how many radio buttons we have seen per group so far
168
+ let radio-counters = (:)
169
+
170
+ for (i, page-info) in pages.enumerate() {
171
+ let page-num = i + 1
172
+ let page-fields = fields.filter(f => f.page == page-num)
173
+
174
+ let bg = backgrounds.at(i)
175
+ let pw = page-info.width * 1pt
176
+ let ph = page-info.height * 1pt
177
+
178
+ page(
179
+ width: pw,
180
+ height: ph,
181
+ margin: 0pt,
182
+ )[
183
+ // Background image (the original PDF page rasterised as PNG)
184
+ #place(top + left, image(bg, width: pw, height: ph, fit: "stretch"))
185
+
186
+ // Field overlays
187
+ #for field in page-fields.filter(f => ("text", "checkbox", "radio", "combobox", "listbox").contains(lower(
188
+ f.type,
189
+ ))) {
190
+ let x = field.bbox.at(0) * 1pt
191
+ let y = field.bbox.at(1) * 1pt
192
+ let w = (field.bbox.at(2) - field.bbox.at(0)) * 1pt
193
+ let h = (field.bbox.at(3) - field.bbox.at(1)) * 1pt
194
+
195
+ let field-type = lower(field.type)
196
+ let val = values.at(field.name, default: none)
197
+
198
+ // --- Radio: resolve group-level value to per-button boolean ---
199
+ if field-type == "radio" {
200
+ let group-name = field.name
201
+ let idx = radio-counters.at(group-name, default: 0)
202
+ radio-counters.insert(group-name, idx + 1)
203
+ val = radio-button-selected(field, val, idx)
204
+ }
205
+
206
+ place(
207
+ top + left,
208
+ dx: x,
209
+ dy: y,
210
+ render-field(field-type, val, w, h, field),
211
+ )
212
+
213
+ if debug {
214
+ place(
215
+ top + left,
216
+ dx: x,
217
+ dy: y,
218
+ debug-overlay(field-type, field.name, w, h),
219
+ )
220
+ }
221
+
222
+ // Zero-width fence to break PDF viewer text-selection grouping
223
+ place(top + left, dx: x, dy: y, text(size: 0.001pt, "\u{FEFF}"))
224
+ }
225
+ ]
226
+ }
227
+ }
@@ -0,0 +1,7 @@
1
+ [package]
2
+ name = "daf4392page2-pkg"
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,86 @@
1
+ #import "@local/quillmark-helper:0.1.0": data
2
+
3
+ // `type: date` fields arrive as Typst `datetime`; overlay text must be plain strings.
4
+ #let show-date(v) = {
5
+ if v == none { "" }
6
+ else if type(v) == datetime { v.display("[month padding:none]/[day padding:none]/[year]") }
7
+ else { str(v) }
8
+ }
9
+
10
+ #set page(width: 8.5in, height: 11in, margin: 0in)
11
+ #set text(font: "Arimo", size: 10pt)
12
+
13
+ // Background
14
+ #place(image("assets/page1.png", width: 100%, height: 100%))
15
+
16
+ #let tf(dx, dy, content) = place(dx: dx, dy: dy, content)
17
+ #let check(dx, dy, is_checked) = if is_checked { place(dx: dx, dy: dy, text(weight: "bold", size: 12pt)[✓]) }
18
+
19
+ // Mode of Transportation
20
+ #let mode = data.at("transportation_mode", default: "")
21
+ #check(40pt, 67pt, mode == "pmv")
22
+ #check(173pt, 67pt, mode == "airplane")
23
+ #check(243pt, 67pt, mode == "bus")
24
+ #check(286pt, 67pt, mode == "train")
25
+ #check(336pt, 67pt, mode == "motorcycle")
26
+ #check(411pt, 67pt, mode == "other")
27
+
28
+ // Fields
29
+ #tf(40pt, 100pt)[#show-date(data.at("departure_date", default: none))]
30
+ #tf(123pt, 100pt)[#data.at("final_destination", default: "")]
31
+
32
+ // Itinerary Rows (via CARDS)
33
+ #{
34
+ let row = 0
35
+ let dy-start = 160pt
36
+ let dy-step = 40pt
37
+ if "CARDS" in data {
38
+ for card in data.CARDS {
39
+ if card.CARD == "itinerary" and row < 10 {
40
+ let dy = dy-start + (row * dy-step)
41
+ tf(80pt, dy)[#show-date(card.at("date", default: none))]
42
+ tf(135pt, dy)[#card.at("departure_point", default: "")]
43
+ tf(295pt, dy)[#card.at("arrival_point", default: "")]
44
+ tf(450pt, dy)[#card.at("rest_length", default: "")]
45
+ tf(515pt, dy)[#card.at("mileage", default: "")]
46
+ row = row + 1
47
+ }
48
+ }
49
+ }
50
+ }
51
+
52
+ // Flight Info
53
+ #{
54
+ let d-flight = str(data.at("dept_flight_num", default: ""))
55
+ if d-flight != "" { tf(350pt, 545pt)[#text(weight: "bold")[Dept Flight:] #d-flight] }
56
+
57
+ let a-flight = str(data.at("arrival_flight_num", default: ""))
58
+ if a-flight != "" { tf(450pt, 545pt)[#text(weight: "bold")[Arr Flight:] #a-flight] }
59
+ }
60
+
61
+ // Notes
62
+ #tf(40pt, 565pt)[#block(width: 530pt)[#data.at("notes", default: "")]]
63
+
64
+ // Acknowledgements
65
+ #tf(40pt, 620pt)[#data.at("organization", default: "")]
66
+ #tf(500pt, 620pt)[#show-date(data.at("briefed_date", default: none))]
67
+
68
+ #tf(40pt, 650pt)[#data.at("briefee_name", default: "")]
69
+ #tf(270pt, 650pt)[#data.at("briefee_grade", default: "")]
70
+
71
+ #tf(40pt, 680pt)[#data.at("briefer_name", default: "")]
72
+ #tf(270pt, 680pt)[#data.at("briefer_grade", default: "")]
73
+
74
+ // Emergency Contact
75
+ #{
76
+ let emergency_name = str(data.at("emergency_contact_name", default: ""))
77
+ let emergency_phone = str(data.at("emergency_contact_phone", default: ""))
78
+ let emergency_contact = if emergency_name != "" and emergency_phone != "" {
79
+ emergency_name + ": " + emergency_phone
80
+ } else if emergency_name != "" {
81
+ emergency_name
82
+ } else {
83
+ emergency_phone
84
+ }
85
+ tf(40pt, 700pt)[#text(size: 10pt, weight: "bold")[EMERGENCY CONTACT:] #text(size: 10pt)[#emergency_contact]]
86
+ }
@@ -0,0 +1,31 @@
1
+ # Example .quillignore for usaf_memo template
2
+ # This demonstrates the .quillignore functionality
3
+
4
+ # Ignore temporary and backup files
5
+ *.tmp
6
+ *.bak
7
+ *~
8
+ *.swp
9
+
10
+ # Ignore build artifacts
11
+ target/
12
+ dist/
13
+ build/
14
+
15
+ # Ignore OS-specific files
16
+ .DS_Store
17
+ Thumbs.db
18
+ desktop.ini
19
+
20
+ # Ignore version control
21
+ .git/
22
+ .svn/
23
+
24
+ # Ignore editor files
25
+ .vscode/
26
+ .idea/
27
+ *.sublime-*
28
+
29
+ # Ignore log files
30
+ *.log
31
+ logs/