@airmark/quiver 0.26.0 → 0.28.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 +79 -31
- package/package.json +7 -5
- package/quills/af4141/0.1.0/Quill.yaml +21 -11
- package/quills/af4141/0.1.0/packages/typst-af4141/lib.typ +17 -3
- package/quills/af4141/0.1.0/plate.typ +12 -5
- package/quills/daf1206/0.1.0/Quill.yaml +3 -1
- package/quills/daf4392/0.1.0/Quill.yaml +12 -9
- package/quills/daf4392/0.1.0/packages/daf4392page2_pkg/fonts/GNU General Public License.txt +340 -0
- package/quills/daf4392/0.1.0/packages/daf4392page2_pkg/fonts/NimbusRomNo9L-Med.otf +0 -0
- package/quills/daf4392/0.1.0/packages/daf4392page2_pkg/fonts/NimbusRomNo9L-MedIta.otf +0 -0
- package/quills/daf4392/0.1.0/packages/daf4392page2_pkg/fonts/NimbusRomNo9L-Reg.otf +0 -0
- package/quills/daf4392/0.1.0/packages/daf4392page2_pkg/fonts/NimbusRomNo9L-RegIta.otf +0 -0
- package/quills/daf4392/0.1.0/packages/daf4392page2_pkg/lib.typ +21 -4
- package/quills/daf4392/0.1.0/plate.typ +1 -1
- package/quills/usaf_memo/0.2.0/Quill.yaml +47 -42
- package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/fonts/Cinzel/Cinzel[wght].ttf +0 -0
- package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/src/indorsement.typ +57 -24
- package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/src/utils.typ +33 -4
- package/quills/usaf_memo/0.2.0/plate.typ +19 -14
- package/quills/af4141/0.1.0/assets/Figtree-Bold.ttf +0 -0
- package/quills/af4141/0.1.0/assets/Figtree-Italic.ttf +0 -0
- package/quills/af4141/0.1.0/assets/Figtree-Regular.ttf +0 -0
- package/quills/af4141/0.1.0/design/TASK.md +0 -20
- package/quills/af4141/0.1.0/design/af4141.pdf +0 -0
- package/quills/daf1206/0.1.0/DAFForm_1206_prepared.pdf +0 -0
- package/quills/daf4392/0.1.0/assets/arimo-v35-latin-700.ttf +0 -0
- package/quills/daf4392/0.1.0/assets/arimo-v35-latin-700italic.ttf +0 -0
- package/quills/daf4392/0.1.0/assets/arimo-v35-latin-italic.ttf +0 -0
- package/quills/daf4392/0.1.0/assets/arimo-v35-latin-regular.ttf +0 -0
- package/quills/usaf_memo/0.2.0/.quillignore +0 -31
- package/quills/usaf_memo/0.2.0/assets/Freedom250_USAF.png +0 -0
- package/quills/usaf_memo/0.2.0/assets/Freedom250_USSF.png +0 -0
- package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/fonts/Cinzel/Cinzel-Regular.ttf +0 -0
- /package/quills/af4141/0.1.0/{assets → packages/typst-af4141/fonts}/GNU General Public License.txt +0 -0
- /package/quills/af4141/0.1.0/{assets → packages/typst-af4141/fonts}/NimbusRomNo9L-Med.otf +0 -0
- /package/quills/af4141/0.1.0/{assets → packages/typst-af4141/fonts}/NimbusRomNo9L-MedIta.otf +0 -0
- /package/quills/af4141/0.1.0/{assets → packages/typst-af4141/fonts}/NimbusRomNo9L-Reg.otf +0 -0
- /package/quills/af4141/0.1.0/{assets → packages/typst-af4141/fonts}/NimbusRomNo9L-RegIta.otf +0 -0
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @airmark/quiver
|
|
2
2
|
|
|
3
|
-
A [Quillmark](https://github.com/nibsbin/quillmark)
|
|
4
|
-
and DAF official-document
|
|
3
|
+
A [Quillmark](https://github.com/nibsbin/quillmark) source quiver of Air Force
|
|
4
|
+
and DAF official-document quills, sourced from
|
|
5
5
|
[tonguetoquill-collection](https://github.com/nibsbin/tonguetoquill-collection)
|
|
6
6
|
and aligned to the current Quillmark spec.
|
|
7
7
|
|
|
@@ -20,28 +20,31 @@ and aligned to the current Quillmark spec.
|
|
|
20
20
|
npm install @airmark/quiver @quillmark/quiver @quillmark/wasm
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
This package ships only the
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
over HTTP.
|
|
23
|
+
This package ships only the source-quiver assets (`Quiver.yaml` + `quills/`) and
|
|
24
|
+
exposes no JavaScript API. Loading is `@quillmark/quiver`'s, rendering is
|
|
25
|
+
`@quillmark/wasm`'s.
|
|
27
26
|
|
|
28
27
|
## Usage
|
|
29
28
|
|
|
30
|
-
### Load from the
|
|
29
|
+
### Load from the installed directory (Node)
|
|
31
30
|
|
|
32
|
-
Resolve
|
|
33
|
-
|
|
31
|
+
Resolve this package's `Quiver.yaml` from your own module — your dependencies are
|
|
32
|
+
reachable from you, not from the loader's install location — and hand its
|
|
33
|
+
directory to `fromDir`:
|
|
34
34
|
|
|
35
35
|
```ts
|
|
36
|
-
import {
|
|
37
|
-
import
|
|
38
|
-
import {
|
|
39
|
-
import {
|
|
36
|
+
import { createRequire } from 'node:module';
|
|
37
|
+
import { dirname } from 'node:path';
|
|
38
|
+
import { Engine, init } from '@quillmark/wasm';
|
|
39
|
+
import { fromDir } from '@quillmark/quiver/node';
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
const
|
|
41
|
+
// `init` is the only door to `Document`: there is no static export to reach early.
|
|
42
|
+
const { Document } = await init();
|
|
43
|
+
|
|
44
|
+
const root = dirname(createRequire(import.meta.url).resolve('@airmark/quiver/Quiver.yaml'));
|
|
45
|
+
const quiver = await fromDir(root);
|
|
46
|
+
const engine = new Engine();
|
|
43
47
|
|
|
44
|
-
const engine = new Quillmark();
|
|
45
48
|
const doc = Document.fromMarkdown(`~~~
|
|
46
49
|
$quill: usaf_memo@0.2
|
|
47
50
|
$kind: main
|
|
@@ -53,19 +56,31 @@ signature_block: ["FIRST M. LAST, Rank, USAF", "Duty Title"]
|
|
|
53
56
|
|
|
54
57
|
Body of the memo.`);
|
|
55
58
|
|
|
56
|
-
const quill = await quiver.getQuill(doc.quillRef
|
|
57
|
-
const { artifacts } =
|
|
59
|
+
const quill = await quiver.getQuill(doc.quillRef);
|
|
60
|
+
const { artifacts } = await engine.render(quill, doc, { format: 'pdf' });
|
|
58
61
|
```
|
|
59
62
|
|
|
60
|
-
|
|
63
|
+
A quill from `getQuill` is borrowed: every caller asking for that ref gets the
|
|
64
|
+
same instance, so it is not yours to `free()`.
|
|
65
|
+
|
|
66
|
+
### Load over HTTP (browser)
|
|
67
|
+
|
|
68
|
+
A browser cannot read the source layout, so pack it at deploy time and serve the
|
|
69
|
+
output as static files:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import { build } from '@quillmark/quiver/node'; // build step
|
|
73
|
+
await build(root, './public/quivers/airmark');
|
|
74
|
+
```
|
|
61
75
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
76
|
+
```ts
|
|
77
|
+
import { Quiver } from '@quillmark/quiver'; // browser runtime
|
|
78
|
+
const quiver = await Quiver.fromBuiltUrl('/quivers/airmark/');
|
|
79
|
+
```
|
|
65
80
|
|
|
66
81
|
## Layout
|
|
67
82
|
|
|
68
|
-
This package is a [
|
|
83
|
+
This package is a [source quiver](https://www.npmjs.com/package/@quillmark/quiver)
|
|
69
84
|
conforming to the canonical layout:
|
|
70
85
|
|
|
71
86
|
```
|
|
@@ -79,20 +94,53 @@ quills/
|
|
|
79
94
|
packages/
|
|
80
95
|
```
|
|
81
96
|
|
|
82
|
-
##
|
|
97
|
+
## Working on a quill
|
|
83
98
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
`
|
|
99
|
+
Two verbs, and they answer different questions.
|
|
100
|
+
|
|
101
|
+
Both verbs are [`quillkit`](https://www.npmjs.com/package/quillkit)'s, the quill
|
|
102
|
+
author's toolchain. It resolves `@quillmark/quiver` and `@quillmark/wasm` out of
|
|
103
|
+
this collection's own `node_modules`, so the versions pinned here are the format
|
|
104
|
+
the quiver is packed in and the wasm the gate renders through.
|
|
105
|
+
|
|
106
|
+
**Does it work?** `quillkit test` loads the collection with `fromDir`, compiles
|
|
107
|
+
every quill, and renders each one's example document — the blueprint seeded from
|
|
108
|
+
the `example:` values in `Quill.yaml`. It is the gate CI runs, so a validation
|
|
109
|
+
failure surfaces here rather than on a consumer's build:
|
|
89
110
|
|
|
90
111
|
```bash
|
|
91
112
|
npm install
|
|
92
113
|
npm test
|
|
93
114
|
```
|
|
94
115
|
|
|
116
|
+
The gate renders nothing the schema did not write, so the coverage is the
|
|
117
|
+
`example:` block: a field with no example is a field no render exercises.
|
|
118
|
+
|
|
119
|
+
**What is it like to use?** `npm run dev` is `quillkit studio`: it packs this
|
|
120
|
+
quiver, serves the studio client over it, and repacks on every save — pick a
|
|
121
|
+
quill, edit the seeded document, watch it paint, read the diagnostics. The
|
|
122
|
+
client is quillkit's own, so there is nothing to install for it and nothing to
|
|
123
|
+
keep in step.
|
|
124
|
+
|
|
125
|
+
Reload to pick up a repack. Editing a quill into an invalid state is not a
|
|
126
|
+
failure of the loop: it packs, and the client says what is wrong with that quill
|
|
127
|
+
and where, while the others stay usable.
|
|
128
|
+
|
|
129
|
+
The two verbs answer to different authorities. `quillkit test` renders through
|
|
130
|
+
the wasm pinned here and is what CI blocks on; the client renders through the
|
|
131
|
+
wasm it was built against, and nothing at runtime reconciles the two. The gate
|
|
132
|
+
is authoritative, studio is advisory.
|
|
133
|
+
|
|
134
|
+
`npm run site` writes the arrangement a deploy serves into `site/` — the client
|
|
135
|
+
at the root, a built quiver at `quiver/` beneath it — without serving it. CI
|
|
136
|
+
uploads that on every run, so a pull request — a fork's included — is reviewed
|
|
137
|
+
by downloading the artifact and serving the directory.
|
|
138
|
+
|
|
139
|
+
`main` is deployed to GitHub Pages by `.github/workflows/studio.yml`, which runs
|
|
140
|
+
that same command and keeps the deploy here: nothing outside this repository
|
|
141
|
+
holds `pages: write`.
|
|
142
|
+
|
|
95
143
|
## License
|
|
96
144
|
|
|
97
|
-
Apache-2.0. Individual
|
|
98
|
-
`packages/` directory inside each
|
|
145
|
+
Apache-2.0. Individual quills carry their own licensing terms; see the
|
|
146
|
+
`packages/` directory inside each quill for upstream font and template licenses.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@airmark/quiver",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"description": "Airmark Quiver — Air Force and DAF document Quills for Quillmark.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -16,12 +16,14 @@
|
|
|
16
16
|
"node": ">=24"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@quillmark/quiver": "0.
|
|
20
|
-
"@quillmark/wasm": "^0.
|
|
19
|
+
"@quillmark/quiver": "0.21.0",
|
|
20
|
+
"@quillmark/wasm": "^0.103.0",
|
|
21
|
+
"quillkit": "0.2.0"
|
|
21
22
|
},
|
|
22
23
|
"scripts": {
|
|
23
|
-
"test": "
|
|
24
|
-
"
|
|
24
|
+
"test": "quillkit test",
|
|
25
|
+
"site": "quillkit site --out site",
|
|
26
|
+
"dev": "quillkit studio"
|
|
25
27
|
},
|
|
26
28
|
"keywords": [
|
|
27
29
|
"quillmark",
|
|
@@ -2,9 +2,11 @@ quill:
|
|
|
2
2
|
name: af4141
|
|
3
3
|
version: 0.1.0
|
|
4
4
|
backend: typst
|
|
5
|
-
plate_file: plate.typ
|
|
6
5
|
description: "AF Form 4141 — Individual's Record of Duties and Experience, Ground Environment Personnel"
|
|
7
6
|
|
|
7
|
+
typst:
|
|
8
|
+
plate_file: plate.typ
|
|
9
|
+
|
|
8
10
|
main:
|
|
9
11
|
body:
|
|
10
12
|
enabled: false
|
|
@@ -36,58 +38,66 @@ card_kinds:
|
|
|
36
38
|
description: Each card represents one row in the Record of Experience table. Rows fill page 1 (up to 16 rows) then page 2 (up to 21 rows), for a maximum of 37 rows.
|
|
37
39
|
ui:
|
|
38
40
|
title: Record of Experience
|
|
41
|
+
groups: [record]
|
|
39
42
|
body:
|
|
40
43
|
enabled: false
|
|
41
44
|
fields:
|
|
42
45
|
date:
|
|
43
|
-
type:
|
|
46
|
+
type: date
|
|
44
47
|
default: ""
|
|
48
|
+
example: "2026-03-14"
|
|
45
49
|
ui:
|
|
46
|
-
group:
|
|
50
|
+
group: record
|
|
47
51
|
description: Date of the action (column A).
|
|
48
52
|
|
|
49
53
|
action:
|
|
50
54
|
type: string
|
|
51
55
|
default: ""
|
|
56
|
+
example: Upgraded to 5-level; assumed ADO duties
|
|
52
57
|
ui:
|
|
53
|
-
group:
|
|
58
|
+
group: record
|
|
54
59
|
description: One type of action per line (column B).
|
|
55
60
|
|
|
56
61
|
written_grade:
|
|
57
62
|
type: string
|
|
58
63
|
default: ""
|
|
64
|
+
example: "3"
|
|
59
65
|
ui:
|
|
60
|
-
group:
|
|
66
|
+
group: record
|
|
61
67
|
compact: true
|
|
62
68
|
description: Written grade, if applicable (column C).
|
|
63
69
|
|
|
64
70
|
written_grade_date:
|
|
65
|
-
type:
|
|
71
|
+
type: date
|
|
66
72
|
default: ""
|
|
73
|
+
example: "2026-02-28"
|
|
67
74
|
ui:
|
|
68
|
-
group:
|
|
75
|
+
group: record
|
|
69
76
|
compact: true
|
|
70
77
|
description: Date of written grade (column D). Omit or leave blank when there is no written grade.
|
|
71
78
|
|
|
72
79
|
positional_grade:
|
|
73
80
|
type: string
|
|
74
81
|
default: ""
|
|
82
|
+
example: "2"
|
|
75
83
|
ui:
|
|
76
|
-
group:
|
|
84
|
+
group: record
|
|
77
85
|
compact: true
|
|
78
86
|
description: Positional grade, if applicable (column E).
|
|
79
87
|
|
|
80
88
|
positional_grade_date:
|
|
81
|
-
type:
|
|
89
|
+
type: date
|
|
82
90
|
default: ""
|
|
91
|
+
example: "2026-03-14"
|
|
83
92
|
ui:
|
|
84
|
-
group:
|
|
93
|
+
group: record
|
|
85
94
|
compact: true
|
|
86
95
|
description: Date of positional grade (column F). Omit or leave blank when there is no positional grade.
|
|
87
96
|
|
|
88
97
|
auth_or_remarks:
|
|
89
98
|
type: string
|
|
90
99
|
default: ""
|
|
100
|
+
example: "J.A.D."
|
|
91
101
|
ui:
|
|
92
|
-
group:
|
|
102
|
+
group: record
|
|
93
103
|
description: Authentication or remarks entry (column G).
|
|
@@ -11,7 +11,15 @@
|
|
|
11
11
|
/// True for short/narrow fields with brief content (grades, ranks, dates).
|
|
12
12
|
#let should-shrink-to-fit(display, width, height) = {
|
|
13
13
|
let aspect = width / height
|
|
14
|
-
|
|
14
|
+
// A date field's content is a single `text` element, and the string inside it
|
|
15
|
+
// is what decides the shrink, as a plain value's own does. Any other content
|
|
16
|
+
// (a styled label, a sequence) has no such string and counts as long, so only
|
|
17
|
+
// the dimension conditions apply.
|
|
18
|
+
let char-count = if type(display) == str {
|
|
19
|
+
display.len()
|
|
20
|
+
} else {
|
|
21
|
+
display.at("text", default: "0" * 99).len()
|
|
22
|
+
}
|
|
15
23
|
char-count <= 10 or height < 20pt or aspect > 4.0
|
|
16
24
|
}
|
|
17
25
|
|
|
@@ -81,8 +89,14 @@
|
|
|
81
89
|
/// - field (dictionary): raw field entry from the schema
|
|
82
90
|
#let render-field(field-type, value, width, height, field) = {
|
|
83
91
|
if field-type == "text" {
|
|
84
|
-
if value != none
|
|
85
|
-
|
|
92
|
+
if value != none {
|
|
93
|
+
// A date field arrives as content carrying its click-to-edit region, so it
|
|
94
|
+
// is placed as it stands; a plain string is placed only when non-empty.
|
|
95
|
+
if type(value) == content {
|
|
96
|
+
render-text-field(value, width, height, 1.5pt, 1pt)
|
|
97
|
+
} else if str(value) != "" {
|
|
98
|
+
render-text-field(str(value), width, height, 1.5pt, 1pt)
|
|
99
|
+
}
|
|
86
100
|
}
|
|
87
101
|
} else if field-type == "checkbox" {
|
|
88
102
|
if value == true {
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
#import "@local/quillmark-helper:0.1.0": data
|
|
2
2
|
#import "@local/typst-af4141:0.1.0": form
|
|
3
3
|
|
|
4
|
-
#set text(font:
|
|
4
|
+
#set text(font: "NimbusRomNo9L")
|
|
5
5
|
|
|
6
|
-
// `type: date`
|
|
7
|
-
//
|
|
6
|
+
// A `type: date` field lowers to a click-to-edit value object
|
|
7
|
+
// `(value: datetime, display: closure)`; `display` is a stored closure on a dict
|
|
8
|
+
// rather than a method, so it is called through parentheses, and the content it
|
|
9
|
+
// returns carries the region that makes the glyphs clickable. A native datetime
|
|
10
|
+
// is still accepted. Missing / blank dates arrive as `none`; empty strings may
|
|
11
|
+
// also appear from input.
|
|
8
12
|
#let form-cell(v) = {
|
|
13
|
+
let pattern = "[month padding:none]/[day padding:none]/[year]"
|
|
9
14
|
if v == none { "" }
|
|
10
15
|
else if type(v) == str and v == "" { "" }
|
|
11
|
-
else if type(v) ==
|
|
12
|
-
v.display(
|
|
16
|
+
else if type(v) == dictionary {
|
|
17
|
+
(v.display)(pattern)
|
|
18
|
+
} else if type(v) == datetime {
|
|
19
|
+
v.display(pattern)
|
|
13
20
|
} else {
|
|
14
21
|
str(v)
|
|
15
22
|
}
|
|
@@ -2,9 +2,11 @@ quill:
|
|
|
2
2
|
name: daf4392
|
|
3
3
|
version: 0.1.0
|
|
4
4
|
backend: typst
|
|
5
|
-
plate_file: plate.typ
|
|
6
5
|
description: "DAF Form 4392 - Pre-Departure Safety Briefing (Page 2)"
|
|
7
6
|
|
|
7
|
+
typst:
|
|
8
|
+
plate_file: plate.typ
|
|
9
|
+
|
|
8
10
|
main:
|
|
9
11
|
body:
|
|
10
12
|
enabled: false
|
|
@@ -16,7 +18,7 @@ main:
|
|
|
16
18
|
description: "Matches the check box."
|
|
17
19
|
|
|
18
20
|
departure_date:
|
|
19
|
-
type:
|
|
21
|
+
type: date
|
|
20
22
|
default: ""
|
|
21
23
|
example: "2026-06-01"
|
|
22
24
|
ui:
|
|
@@ -59,7 +61,7 @@ main:
|
|
|
59
61
|
description: "Unit / Organization."
|
|
60
62
|
|
|
61
63
|
briefed_date:
|
|
62
|
-
type:
|
|
64
|
+
type: date
|
|
63
65
|
default: ""
|
|
64
66
|
example: "2026-05-22"
|
|
65
67
|
ui:
|
|
@@ -96,41 +98,42 @@ card_kinds:
|
|
|
96
98
|
description: "Each card represents one row in the travel itinerary table. Up to 10 rows are supported."
|
|
97
99
|
ui:
|
|
98
100
|
title: Proposed Travel Itinerary
|
|
101
|
+
groups: [itinerary_entry]
|
|
99
102
|
body:
|
|
100
103
|
enabled: false
|
|
101
104
|
fields:
|
|
102
105
|
date:
|
|
103
|
-
type:
|
|
106
|
+
type: date
|
|
104
107
|
default: ""
|
|
105
108
|
ui:
|
|
106
|
-
group:
|
|
109
|
+
group: itinerary_entry
|
|
107
110
|
compact: true
|
|
108
111
|
description: "Date for the itinerary row."
|
|
109
112
|
departure_point:
|
|
110
113
|
type: string
|
|
111
114
|
default: ""
|
|
112
115
|
ui:
|
|
113
|
-
group:
|
|
116
|
+
group: itinerary_entry
|
|
114
117
|
compact: true
|
|
115
118
|
description: "Point of departure."
|
|
116
119
|
arrival_point:
|
|
117
120
|
type: string
|
|
118
121
|
default: ""
|
|
119
122
|
ui:
|
|
120
|
-
group:
|
|
123
|
+
group: itinerary_entry
|
|
121
124
|
compact: true
|
|
122
125
|
description: "Point of arrival."
|
|
123
126
|
rest_length:
|
|
124
127
|
type: string
|
|
125
128
|
default: ""
|
|
126
129
|
ui:
|
|
127
|
-
group:
|
|
130
|
+
group: itinerary_entry
|
|
128
131
|
compact: true
|
|
129
132
|
description: "Duration of stay at arrival point"
|
|
130
133
|
mileage:
|
|
131
134
|
type: string
|
|
132
135
|
default: ""
|
|
133
136
|
ui:
|
|
134
|
-
group:
|
|
137
|
+
group: itinerary_entry
|
|
135
138
|
compact: true
|
|
136
139
|
description: "Approximate mileage for this leg (leave blank if not applicable, e.g., flights)."
|