@airmark/quiver 0.35.7 → 0.36.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.
@@ -9,171 +9,156 @@ typst:
9
9
 
10
10
  main:
11
11
  description: "Write the letter as plain paragraphs; they aren't numbered. Use a block quote for lines that should stay as written, like an address. You can close with your phone number and email."
12
- ui:
13
- groups: [addressing, letterhead, classification, additional]
14
- fields:
15
- letter_from:
16
- type: array
17
- items:
18
- type: plaintext
19
- inline: true
20
- ui:
21
- group: addressing
22
- compact: true
23
- description: "Your rank and full name, then your duty title and mailing address, one per line. Don't put a comma between city and state."
24
-
25
- letter_for:
26
- type: array
27
- items:
28
- type: plaintext
29
- inline: true
30
- ui:
31
- group: addressing
32
- compact: true
33
- description: "The recipient's rank and full name, then their duty title and mailing address, one per line. Don't put a comma between city and state."
34
-
35
- salutation:
36
- type: plaintext
37
- inline: true
38
- ui:
39
- group: addressing
40
- compact: true
41
- description: "The greeting, for example 'Dear Major Smith', with no punctuation after the name."
42
-
43
- date:
44
- type: date
45
- default: ""
46
- ui:
47
- group: addressing
48
- compact: true
49
- description: "The date you sign. Leave blank to add a fillable date field to the PDF instead."
50
-
51
- complimentary_close:
52
- type: plaintext
53
- inline: true
54
- default: Sincerely
55
- ui:
56
- group: addressing
57
- compact: true
58
- description: "The closing above your signature. 'Sincerely' suits most letters."
59
-
60
- signature_block:
61
- type: array
62
- items:
63
- type: plaintext
64
- inline: true
65
- ui:
66
- group: addressing
67
- compact: true
68
- description: "Your name in uppercase, grade, and service, for example 'FIRST M. LAST, Col, USAF'. A personal letter leaves out the duty title."
69
-
70
- letterhead_title:
71
- type: array
72
- items:
73
- type: plaintext
74
- inline: true
75
- default:
76
- - DEPARTMENT OF THE AIR FORCE
77
- ui:
78
- group: letterhead
79
- description: "The letterhead, in uppercase. Keep the first line unless you work for a joint command or a DoW agency, and add your unit's full name on the lines below it."
80
-
81
- letterhead_seal:
82
- type: enum
83
- values:
84
- - dow
85
- - dod
86
- default: dow
87
- ui:
88
- group: letterhead
89
- compact: true
90
- description: "The seal at the top left of the letterhead: Department of War or Department of Defense."
91
-
92
- letterhead_seal_subtitle:
93
- type: plaintext
94
- inline: true
95
- default: ""
96
- ui:
97
- group: letterhead
98
- compact: true
99
- description: "An optional line in bold capitals under the seal."
100
-
101
- tag_line:
102
- type: richtext
103
- inline: true
104
- default: ""
105
- ui:
106
- group: letterhead
107
- compact: true
108
- description: "Your unit's motto, centered at the bottom of every page."
12
+ sections:
13
+ addressing:
14
+ fields:
15
+ letter_from:
16
+ type: array
17
+ items:
18
+ type: plaintext
19
+ inline: true
20
+ ui:
21
+ compact: true
22
+ description: "Your rank and full name, then your duty title and mailing address, one per line. Don't put a comma between city and state."
109
23
 
110
- classification:
111
- type: enum
112
- values:
113
- - UNCLASSIFIED
114
- - CUI
115
- - CONFIDENTIAL
116
- - SECRET
117
- - TOP SECRET
118
- default: ""
119
- ui:
120
- group: classification
121
- compact: true
122
- description: "The classification banner at the top and bottom of every page. Leave blank for an unclassified document."
123
- variants:
124
- CUI:
125
- controlled_by:
24
+ letter_for:
25
+ type: array
26
+ items:
126
27
  type: plaintext
127
28
  inline: true
128
- description: "The office that designated this information as CUI, for example 'SAF/AA'."
129
- poc:
29
+ ui:
30
+ compact: true
31
+ description: "The recipient's rank and full name, then their duty title and mailing address, one per line. Don't put a comma between city and state."
32
+
33
+ salutation:
34
+ type: plaintext
35
+ inline: true
36
+ ui:
37
+ compact: true
38
+ description: "The greeting, for example 'Dear Major Smith', with no punctuation after the name."
39
+
40
+ date:
41
+ type: date
42
+ default: ""
43
+ ui:
44
+ compact: true
45
+ description: "The date you sign. Leave blank to add a fillable date field to the PDF instead."
46
+
47
+ complimentary_close:
48
+ type: plaintext
49
+ inline: true
50
+ default: Sincerely
51
+ ui:
52
+ compact: true
53
+ description: "The closing above your signature. 'Sincerely' suits most letters."
54
+
55
+ signature_block:
56
+ type: array
57
+ items:
130
58
  type: plaintext
131
59
  inline: true
132
- description: "Who to contact with questions about this CUI, with phone and email, for example 'Capt J. Smith, DSN 555-1234, john.smith@us.af.mil'."
133
- category:
60
+ ui:
61
+ compact: true
62
+ description: "Your name in uppercase, grade, and service, for example 'FIRST M. LAST, Col, USAF'. A personal letter leaves out the duty title."
63
+ letterhead:
64
+ fields:
65
+ letterhead_title:
66
+ type: array
67
+ items:
134
68
  type: plaintext
135
69
  inline: true
136
- default: ""
137
- description: "The category from the DoD CUI Registry, for example 'CTI' or 'PRVCY'."
138
- limited_dissemination:
70
+ default:
71
+ - DEPARTMENT OF THE AIR FORCE
72
+ description: "The letterhead, in uppercase. Keep the first line unless you work for a joint command or a DoW agency, and add your unit's full name on the lines below it."
73
+
74
+ letterhead_seal:
75
+ type: enum
76
+ values:
77
+ - dow
78
+ - dod
79
+ default: dow
80
+ ui:
81
+ compact: true
82
+ description: "The seal at the top left of the letterhead: Department of War or Department of Defense."
83
+
84
+ letterhead_seal_subtitle:
85
+ type: plaintext
86
+ inline: true
87
+ default: ""
88
+ ui:
89
+ compact: true
90
+ description: "An optional line in bold capitals under the seal."
91
+
92
+ tag_line:
93
+ type: richtext
94
+ inline: true
95
+ default: ""
96
+ ui:
97
+ compact: true
98
+ description: "Your unit's motto, centered at the bottom of every page."
99
+ classification:
100
+ fields:
101
+ classification:
102
+ type: enum
103
+ values:
104
+ - UNCLASSIFIED
105
+ - CUI
106
+ - CONFIDENTIAL
107
+ - SECRET
108
+ - TOP SECRET
109
+ default: ""
110
+ ui:
111
+ compact: true
112
+ description: "The classification banner at the top and bottom of every page. Leave blank for an unclassified document."
113
+ variants:
114
+ CUI:
115
+ controlled_by:
116
+ type: plaintext
117
+ inline: true
118
+ description: "The office that designated this information as CUI, for example 'SAF/AA'."
119
+ poc:
120
+ type: plaintext
121
+ inline: true
122
+ description: "Who to contact with questions about this CUI, with phone and email, for example 'Capt J. Smith, DSN 555-1234, john.smith@us.af.mil'."
123
+ category:
124
+ type: plaintext
125
+ inline: true
126
+ default: ""
127
+ description: "The category from the DoD CUI Registry, for example 'CTI' or 'PRVCY'."
128
+ limited_dissemination:
129
+ type: plaintext
130
+ inline: true
131
+ default: ""
132
+ description: "A dissemination control for the CUI block, for example 'FEDONLY' or 'NOFORN'. To add one to the banner, use Dissemination."
133
+
134
+ dissemination:
135
+ type: plaintext
136
+ inline: true
137
+ default: ""
138
+ ui:
139
+ compact: true
140
+ description: "A control added to the end of the banner. For example, 'NF' prints as CUI//NF."
141
+ additional:
142
+ fields:
143
+ cc:
144
+ type: array
145
+ items:
139
146
  type: plaintext
140
147
  inline: true
141
- default: ""
142
- description: "A dissemination control for the CUI block, for example 'FEDONLY' or 'NOFORN'. To add one to the banner, use Dissemination."
148
+ default: []
149
+ description: Offices or people receiving a courtesy copy, one per line.
143
150
 
144
- dissemination:
145
- type: plaintext
146
- inline: true
147
- default: ""
148
- ui:
149
- group: classification
150
- compact: true
151
- description: "A control added to the end of the banner. For example, 'NF' prints as CUI//NF."
152
-
153
- cc:
154
- type: array
155
- items:
156
- type: plaintext
157
- inline: true
158
- default: []
159
- ui:
160
- group: additional
161
- description: Offices or people receiving a courtesy copy, one per line.
162
-
163
- attachments:
164
- type: array
165
- items:
166
- type: richtext
167
- inline: true
168
- default: []
169
- ui:
170
- group: additional
171
- description: "Attachments in the order the letter mentions them. Describe each briefly and include its date. Don't write 'as stated'."
172
-
173
- font_size:
174
- type: number
175
- default: 12
176
- ui:
177
- group: additional
178
- compact: true
179
- description: "Body text size in points. The standard is 12."
151
+ attachments:
152
+ type: array
153
+ items:
154
+ type: richtext
155
+ inline: true
156
+ default: []
157
+ description: "Attachments in the order the letter mentions them. Describe each briefly and include its date. Don't write 'as stated'."
158
+
159
+ font_size:
160
+ type: number
161
+ default: 12
162
+ ui:
163
+ compact: true
164
+ description: "Body text size in points. The standard is 12."
@@ -1,6 +1,4 @@
1
- #import "@local/quillmark-helper:0.1.0": (
2
- data, display, form-field, signature-field,
3
- )
1
+ #import "@local/quillmark-helper:0.2.0" as qm
4
2
  #import "@local/tonguetoquill-usaf-letter:0.1.0": (
5
3
  backmatter, date-pattern, frontmatter, mainmatter,
6
4
  )
@@ -10,10 +8,10 @@
10
8
  // the title alone — the package skips a falsey caption. An empty array renders
11
9
  // no letterhead text at all, silently: the block is `place`d, so an empty title
12
10
  // leaves no glyphs and takes no space from the flow, and the seal stands alone.
13
- #let letterhead_lines = data.letterhead_title
11
+ #let letterhead_lines = qm.data.letterhead_title
14
12
 
15
13
  // Body text size, in points. Also the height of a blank date's fill-in widget.
16
- #let body_font_size = data.font_size * 1pt
14
+ #let body_font_size = qm.data.font_size * 1pt
17
15
 
18
16
  // A blank date's fill-in slot: an empty AcroForm text box the signer types the
19
17
  // date into, set in the body face and flush right, as the printed date would
@@ -27,7 +25,7 @@
27
25
  #let date_slot(name, field) = context box(
28
26
  width: date_slot_width,
29
27
  height: measure[0].height,
30
- place(horizon + left, form-field(
28
+ place(horizon + left, qm.form-field(
31
29
  name,
32
30
  type: "text",
33
31
  width: date_slot_width,
@@ -42,10 +40,10 @@
42
40
  #show: frontmatter.with(
43
41
  letterhead-title: letterhead_lines.at(0, default: ""),
44
42
  letterhead-caption: if letterhead_lines.len() > 1 { letterhead_lines.slice(1) } else { () },
45
- letterhead-seal-subtitle: data.letterhead_seal_subtitle,
43
+ letterhead-seal-subtitle: qm.data.letterhead_seal_subtitle,
46
44
  // A letter has no seal-less state, so the blank takes the default, DoW.
47
45
  letterhead-seal: image(
48
- if data.letterhead_seal == "dod" {
46
+ if qm.data.letterhead_seal == "dod" {
49
47
  "assets/dod_seal.png"
50
48
  } else {
51
49
  "assets/dow_seal.png"
@@ -54,7 +52,7 @@
54
52
 
55
53
  // Date. `data.date` is the native `datetime` and would render identically,
56
54
  // but its ink would be born inside the package and carry no schema address.
57
- // `display` places the field's *content* projection instead: the glyphs are
55
+ // `qm.ink` places the field's *content* projection instead: the glyphs are
58
56
  // born in the generated helper, so the letter's date stays click-to-edit
59
57
  // however deep the package formats it.
60
58
  //
@@ -63,33 +61,33 @@
63
61
  // than stamped with the compile date. Passing it as the date also keeps it
64
62
  // from `frontmatter`'s own `datetime.today()` fallback.
65
63
  date: {
66
- let authored = display("date", date-pattern())
64
+ let authored = qm.ink(qm.data, "date", date-pattern())
67
65
  if authored != none { authored } else { date_slot("Date", "date") }
68
66
  },
69
67
 
70
- letter-from: data.letter_from,
71
- letter-for: data.letter_for,
72
- salutation: data.salutation,
68
+ letter-from: qm.data.letter_from,
69
+ letter-for: qm.data.letter_for,
70
+ salutation: qm.data.salutation,
73
71
 
74
- footer-tag-line: data.tag_line,
72
+ footer-tag-line: qm.data.tag_line,
75
73
 
76
74
  // The blank reads as no banner, which is what the package's own
77
75
  // `classification-level: none` default means.
78
- classification-level: data.classification.value,
76
+ classification-level: qm.data.classification.value,
79
77
 
80
- dissemination: data.dissemination,
78
+ dissemination: qm.data.dissemination,
81
79
 
82
80
  // CUI designation indicator block fields (DoDM 5200.48). `classification`
83
81
  // declares a `CUI` variant, so these four exist only where the discriminant
84
82
  // reads CUI, and the branch is what makes reading them total: inside it every
85
83
  // declared field of that world is present, outside it none is. The package's
86
84
  // own `cui_*: none` defaults cover the worlds that omit them.
87
- ..if data.classification.value == "CUI" {
85
+ ..if qm.data.classification.value == "CUI" {
88
86
  (
89
- cui-controlled-by: data.classification.controlled_by,
90
- cui-category: data.classification.category,
91
- cui-limited-dissemination: data.classification.limited_dissemination,
92
- cui-poc: data.classification.poc,
87
+ cui-controlled-by: qm.data.classification.controlled_by,
88
+ cui-category: qm.data.classification.category,
89
+ cui-limited-dissemination: qm.data.classification.limited_dissemination,
90
+ cui-poc: qm.data.classification.poc,
93
91
  )
94
92
  },
95
93
 
@@ -98,24 +96,24 @@
98
96
 
99
97
  // An empty body reaches the plate as `""`, and `mainmatter` would still set a
100
98
  // blank paragraph for it, dropping the close two lines too far.
101
- #if data.at("$body") != "" {
102
- mainmatter[#data.at("$body")]
99
+ #if qm.data.at("$body") != "" {
100
+ mainmatter[#qm.data.at("$body")]
103
101
  }
104
102
 
105
103
  #backmatter(
106
- complimentary-close: data.complimentary_close,
107
- signature-block: data.signature_block,
104
+ complimentary-close: qm.data.complimentary_close,
105
+ signature-block: qm.data.signature_block,
108
106
  // The widget sits at the bottom of AFH 33-337's four blank lines and is
109
107
  // sized to two and a half of them, so the line and a half above it stays
110
108
  // clear of the complimentary close without moving the block off the fifth
111
109
  // line.
112
- signing-field: signature-field(
110
+ signing-field: qm.signature-field(
113
111
  "Signature",
114
112
  field: "signature_block",
115
113
  height: body_font_size * 2.5,
116
114
  ),
117
115
 
118
- ..if data.attachments.len() > 0 { (attachments: data.attachments) },
116
+ ..if qm.data.attachments.len() > 0 { (attachments: qm.data.attachments) },
119
117
 
120
- ..if data.cc.len() > 0 { (cc: data.cc) },
118
+ ..if qm.data.cc.len() > 0 { (cc: qm.data.cc) },
121
119
  )