h17-sspdf 0.1.7 → 0.1.8
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/DOCUMENTATION.md +232 -1
- package/README.md +65 -7
- package/cli.js +52 -1
- package/core/pdf-core.js +12 -2
- package/core/render-document.js +25 -6
- package/package.json +1 -1
package/DOCUMENTATION.md
CHANGED
|
@@ -169,7 +169,9 @@ Used by `divider` operations. Does not use font properties.
|
|
|
169
169
|
|
|
170
170
|
#### Bullet marker label properties
|
|
171
171
|
|
|
172
|
-
The marker label controls the bullet character's appearance.
|
|
172
|
+
The marker label controls the bullet character's appearance. A marker can be either a text character or a vector shape.
|
|
173
|
+
|
|
174
|
+
**Text marker** (default):
|
|
173
175
|
|
|
174
176
|
| Property | Type | Description |
|
|
175
177
|
|---|---|---|
|
|
@@ -180,6 +182,17 @@ The marker label controls the bullet character's appearance.
|
|
|
180
182
|
| `lineHeight` | number | Marker line height multiplier |
|
|
181
183
|
| `marker` | string | The marker character (e.g., `"-"`) |
|
|
182
184
|
|
|
185
|
+
**Shape marker** (vector, no text encoding needed):
|
|
186
|
+
|
|
187
|
+
| Property | Type | Description |
|
|
188
|
+
|---|---|---|
|
|
189
|
+
| `shape` | string | Shape name from the built-in shape library (see Vector Shapes below) |
|
|
190
|
+
| `shapeColor` | [R,G,B] | Shape fill/stroke color (falls back to `color` if omitted) |
|
|
191
|
+
| `shapeSize` | number | Scale factor (default: 1) |
|
|
192
|
+
| `textIndentMm` | number | Gap between shape and bullet text in mm (default: 1.5, added to shape width) |
|
|
193
|
+
|
|
194
|
+
When `shape` is set, the core renders a vector shape instead of a text character. The text indent is calculated as `shapeWidth + textIndentMm`. No `fontFamily`, `fontSize`, or `marker` needed.
|
|
195
|
+
|
|
183
196
|
#### Table label properties
|
|
184
197
|
|
|
185
198
|
Used by `table` operations. The `label` controls data cell styling, `headerLabel` controls header cell styling.
|
|
@@ -1087,6 +1100,224 @@ module.exports = {
|
|
|
1087
1100
|
- Each face needs its own file - there's no automatic bold/italic synthesis
|
|
1088
1101
|
- If you reference a font style that wasn't registered, jsPDF will throw
|
|
1089
1102
|
|
|
1103
|
+
### Font style limitations
|
|
1104
|
+
|
|
1105
|
+
The built-in fonts ship with `Regular` and `Bold` faces only. There are no italic or bolditalic TTF files included. If you set `fontStyle: "italic"` with a built-in font, you will get:
|
|
1106
|
+
|
|
1107
|
+
```
|
|
1108
|
+
Unable to look up font label for font 'Inter', 'italic'
|
|
1109
|
+
```
|
|
1110
|
+
|
|
1111
|
+
To use italic text, you need a font that includes an italic TTF file, registered as a separate face in `customFonts`.
|
|
1112
|
+
|
|
1113
|
+
---
|
|
1114
|
+
|
|
1115
|
+
## Built-in fonts
|
|
1116
|
+
|
|
1117
|
+
The package ships with 20 pre-embedded Google Fonts as base64-encoded TTF files. No need to convert fonts yourself.
|
|
1118
|
+
|
|
1119
|
+
**Sans-serif:** Inter, Roboto, Open Sans, Montserrat, Lato, Raleway, Nunito, Work Sans, IBM Plex Sans, PT Sans, Oswald
|
|
1120
|
+
|
|
1121
|
+
**Serif:** Merriweather, Lora, Playfair Display, Crimson Text, Libre Baskerville, Source Serif 4
|
|
1122
|
+
|
|
1123
|
+
**Monospace:** Fira Code, JetBrains Mono, Source Code Pro
|
|
1124
|
+
|
|
1125
|
+
### Usage
|
|
1126
|
+
|
|
1127
|
+
```js
|
|
1128
|
+
const INTER = require("h17-sspdf/fonts/inter.js");
|
|
1129
|
+
|
|
1130
|
+
module.exports = {
|
|
1131
|
+
name: "My Theme",
|
|
1132
|
+
|
|
1133
|
+
customFonts: [
|
|
1134
|
+
{
|
|
1135
|
+
family: "Inter",
|
|
1136
|
+
faces: [
|
|
1137
|
+
{ style: "normal", fileName: "Inter-Regular.ttf", data: INTER.Regular },
|
|
1138
|
+
{ style: "bold", fileName: "Inter-Bold.ttf", data: INTER.Bold },
|
|
1139
|
+
],
|
|
1140
|
+
},
|
|
1141
|
+
],
|
|
1142
|
+
|
|
1143
|
+
// now use fontFamily: "Inter" in any label
|
|
1144
|
+
labels: {
|
|
1145
|
+
"doc.body": {
|
|
1146
|
+
fontFamily: "Inter",
|
|
1147
|
+
fontStyle: "normal",
|
|
1148
|
+
fontSize: 10,
|
|
1149
|
+
color: [40, 40, 40],
|
|
1150
|
+
lineHeight: 1.4,
|
|
1151
|
+
},
|
|
1152
|
+
},
|
|
1153
|
+
};
|
|
1154
|
+
```
|
|
1155
|
+
|
|
1156
|
+
The exported properties are `Regular` and `Bold` (capitalized). Every built-in font file exports these two keys.
|
|
1157
|
+
|
|
1158
|
+
### Available font files
|
|
1159
|
+
|
|
1160
|
+
| Font | Require path |
|
|
1161
|
+
|---|---|
|
|
1162
|
+
| Inter | `h17-sspdf/fonts/inter.js` |
|
|
1163
|
+
| Roboto | `h17-sspdf/fonts/roboto.js` |
|
|
1164
|
+
| Open Sans | `h17-sspdf/fonts/open-sans.js` |
|
|
1165
|
+
| Montserrat | `h17-sspdf/fonts/montserrat.js` |
|
|
1166
|
+
| Lato | `h17-sspdf/fonts/lato.js` |
|
|
1167
|
+
| Raleway | `h17-sspdf/fonts/raleway.js` |
|
|
1168
|
+
| Nunito | `h17-sspdf/fonts/nunito.js` |
|
|
1169
|
+
| Work Sans | `h17-sspdf/fonts/work-sans.js` |
|
|
1170
|
+
| IBM Plex Sans | `h17-sspdf/fonts/ibm-plex-sans.js` |
|
|
1171
|
+
| PT Sans | `h17-sspdf/fonts/pt-sans.js` |
|
|
1172
|
+
| Oswald | `h17-sspdf/fonts/oswald.js` |
|
|
1173
|
+
| Merriweather | `h17-sspdf/fonts/merriweather.js` |
|
|
1174
|
+
| Lora | `h17-sspdf/fonts/lora.js` |
|
|
1175
|
+
| Playfair Display | `h17-sspdf/fonts/playfair-display.js` |
|
|
1176
|
+
| Crimson Text | `h17-sspdf/fonts/crimson-text.js` |
|
|
1177
|
+
| Libre Baskerville | `h17-sspdf/fonts/libre-baskerville.js` |
|
|
1178
|
+
| Source Serif 4 | `h17-sspdf/fonts/source-serif-4.js` |
|
|
1179
|
+
| Fira Code | `h17-sspdf/fonts/fira-code.js` |
|
|
1180
|
+
| JetBrains Mono | `h17-sspdf/fonts/jetbrains-mono.js` |
|
|
1181
|
+
| Source Code Pro | `h17-sspdf/fonts/source-code-pro.js` |
|
|
1182
|
+
|
|
1183
|
+
You can also list available fonts from the CLI:
|
|
1184
|
+
|
|
1185
|
+
```bash
|
|
1186
|
+
npx h17-sspdf --fonts
|
|
1187
|
+
```
|
|
1188
|
+
|
|
1189
|
+
---
|
|
1190
|
+
|
|
1191
|
+
## Vector shapes
|
|
1192
|
+
|
|
1193
|
+
The engine includes 20 vector shapes rendered directly via jsPDF drawing primitives. These bypass text encoding entirely, so they work regardless of font or character support.
|
|
1194
|
+
|
|
1195
|
+
### Available shapes
|
|
1196
|
+
|
|
1197
|
+
**Bullets:** `arrow`, `circle`, `square`, `diamond`, `triangle`, `dash`, `chevron`
|
|
1198
|
+
|
|
1199
|
+
**Decorators:** `doubleColon`, `commentSlash`, `hashComment`, `bracketChevron`, `treeBranch`, `terminalPrompt`
|
|
1200
|
+
|
|
1201
|
+
**Symbols:** `checkmark`, `cross`, `star`, `plus`, `minus`, `warning`, `infoCircle`
|
|
1202
|
+
|
|
1203
|
+
### Using shapes as bullet markers
|
|
1204
|
+
|
|
1205
|
+
Shapes work through the existing `bullet` operation. The theme label decides whether the marker is text or a vector shape. The source JSON does not change.
|
|
1206
|
+
|
|
1207
|
+
**Theme:**
|
|
1208
|
+
|
|
1209
|
+
```js
|
|
1210
|
+
labels: {
|
|
1211
|
+
"doc.marker.arrow": {
|
|
1212
|
+
shape: "arrow",
|
|
1213
|
+
shapeColor: [0, 128, 255],
|
|
1214
|
+
shapeSize: 0.8,
|
|
1215
|
+
textIndentMm: 2,
|
|
1216
|
+
},
|
|
1217
|
+
"doc.body": {
|
|
1218
|
+
fontFamily: "helvetica",
|
|
1219
|
+
fontStyle: "normal",
|
|
1220
|
+
fontSize: 10,
|
|
1221
|
+
color: [40, 40, 40],
|
|
1222
|
+
lineHeight: 1.4,
|
|
1223
|
+
},
|
|
1224
|
+
}
|
|
1225
|
+
```
|
|
1226
|
+
|
|
1227
|
+
**Source:**
|
|
1228
|
+
|
|
1229
|
+
```json
|
|
1230
|
+
{
|
|
1231
|
+
"type": "bullet",
|
|
1232
|
+
"label": "doc.body",
|
|
1233
|
+
"markerLabel": "doc.marker.arrow",
|
|
1234
|
+
"bullets": ["First point", "Second point"]
|
|
1235
|
+
}
|
|
1236
|
+
```
|
|
1237
|
+
|
|
1238
|
+
The core calculates the text indent from the shape's known width (defined in `core/shapes.js`) plus the label's `textIndentMm`. All positioning is exact, derived from the shape width constants.
|
|
1239
|
+
|
|
1240
|
+
### Programmatic usage
|
|
1241
|
+
|
|
1242
|
+
For custom plugins or advanced rendering, shapes can be called directly:
|
|
1243
|
+
|
|
1244
|
+
```js
|
|
1245
|
+
const { renderShape, getShapeWidth } = require("h17-sspdf/core/shapes");
|
|
1246
|
+
|
|
1247
|
+
// Draw a shape at position (x, y) aligned to text baseline
|
|
1248
|
+
renderShape("arrow", doc, x, baseline, [0, 128, 255], 0.8, fontSize);
|
|
1249
|
+
|
|
1250
|
+
// Get the shape's width in mm for spacing calculations
|
|
1251
|
+
const widthMm = getShapeWidth("arrow", 0.8);
|
|
1252
|
+
```
|
|
1253
|
+
|
|
1254
|
+
Parameters: `renderShape(name, doc, x, y, color, size, fontSizePt)`
|
|
1255
|
+
|
|
1256
|
+
The shape centers vertically at half the font height above the baseline, so it aligns with adjacent text.
|
|
1257
|
+
|
|
1258
|
+
---
|
|
1259
|
+
|
|
1260
|
+
## Colors
|
|
1261
|
+
|
|
1262
|
+
All colors in the engine are RGB arrays with values 0-255:
|
|
1263
|
+
|
|
1264
|
+
```js
|
|
1265
|
+
color: [255, 0, 128], // pink
|
|
1266
|
+
backgroundColor: [18, 18, 26], // dark background
|
|
1267
|
+
borderColor: [200, 200, 200], // light gray border
|
|
1268
|
+
```
|
|
1269
|
+
|
|
1270
|
+
Common values:
|
|
1271
|
+
- White: `[255, 255, 255]`
|
|
1272
|
+
- Black: `[0, 0, 0]`
|
|
1273
|
+
- Gray: `[128, 128, 128]`
|
|
1274
|
+
|
|
1275
|
+
This applies to all color properties: `color`, `backgroundColor`, `borderColor`, `altRowColor`, `shapeColor`, and all per-edge border color overrides.
|
|
1276
|
+
|
|
1277
|
+
---
|
|
1278
|
+
|
|
1279
|
+
## Operation quick reference
|
|
1280
|
+
|
|
1281
|
+
| Type | Required fields | Optional fields |
|
|
1282
|
+
|---|---|---|
|
|
1283
|
+
| `text` | `label`, `text` | `align`, `keepWithNext`, `wrap`, `advance` |
|
|
1284
|
+
| `row` | `leftLabel`, `rightLabel`, `leftText`, `rightText` | `xLeftMm`, `xRightMm` |
|
|
1285
|
+
| `bullet` | `label`, `text`/`items`/`bullets` | `markerLabel`, `marker`, `textIndentMm` |
|
|
1286
|
+
| `divider` | `label` | `x1Mm`, `x2Mm` |
|
|
1287
|
+
| `table` | `label`, `columns`, `rows` | `headerLabel`, `xMm`, `maxWidthMm`, border/padding overrides |
|
|
1288
|
+
| `spacer` | `mm` or `px` or `label` | - |
|
|
1289
|
+
| `block` | `children`/`content`/`items` | `label`, `keepTogether`, `spaceAfterMm`/`Px`/`Label` |
|
|
1290
|
+
| `section` | `content` | `label`, `keepTogether` |
|
|
1291
|
+
| `quote` | `label`, `text` | `attribution`, `attributionLabel` |
|
|
1292
|
+
| `hiddenText` | `label`, `text` | - |
|
|
1293
|
+
|
|
1294
|
+
Every operation also accepts `xMm` and `maxWidthMm` to override the theme margins for that operation only.
|
|
1295
|
+
|
|
1296
|
+
---
|
|
1297
|
+
|
|
1298
|
+
## Table labels pattern
|
|
1299
|
+
|
|
1300
|
+
For tables, define two labels: one for data cells, one for headers. The shared constants file `examples/themes/table.js` provides base styles you can spread and override:
|
|
1301
|
+
|
|
1302
|
+
```js
|
|
1303
|
+
const table = require("h17-sspdf/examples/themes/table");
|
|
1304
|
+
|
|
1305
|
+
labels: {
|
|
1306
|
+
"report.table.cell": {
|
|
1307
|
+
...table.cell,
|
|
1308
|
+
color: [51, 65, 85],
|
|
1309
|
+
altRowColor: [248, 249, 252],
|
|
1310
|
+
},
|
|
1311
|
+
"report.table.header": {
|
|
1312
|
+
...table.header,
|
|
1313
|
+
backgroundColor: [55, 65, 81],
|
|
1314
|
+
color: [255, 255, 255],
|
|
1315
|
+
},
|
|
1316
|
+
}
|
|
1317
|
+
```
|
|
1318
|
+
|
|
1319
|
+
The spread gives you sensible defaults for `cellPaddingMm`, `borderColor`, border widths, `altRowColor`, and font settings. Override the properties you want to customize.
|
|
1320
|
+
|
|
1090
1321
|
---
|
|
1091
1322
|
|
|
1092
1323
|
## Common patterns
|
package/README.md
CHANGED
|
@@ -320,23 +320,69 @@ Any operation accepts `xMm` and `maxWidthMm` to override the theme margins for t
|
|
|
320
320
|
|
|
321
321
|
---
|
|
322
322
|
|
|
323
|
+
## Built-in fonts
|
|
324
|
+
|
|
325
|
+
20 Google Fonts ship with the package as base64 TTF. Each exports `{ Regular, Bold }`.
|
|
326
|
+
|
|
327
|
+
**Sans-serif:** Inter, Roboto, Open Sans, Montserrat, Lato, Raleway, Nunito, Work Sans, IBM Plex Sans, PT Sans, Oswald
|
|
328
|
+
|
|
329
|
+
**Serif:** Merriweather, Lora, Playfair Display, Crimson Text, Libre Baskerville, Source Serif 4
|
|
330
|
+
|
|
331
|
+
**Monospace:** Fira Code, JetBrains Mono, Source Code Pro
|
|
332
|
+
|
|
333
|
+
```js
|
|
334
|
+
const INTER = require('h17-sspdf/fonts/inter.js');
|
|
335
|
+
|
|
336
|
+
customFonts: [{
|
|
337
|
+
family: 'Inter',
|
|
338
|
+
faces: [
|
|
339
|
+
{ style: 'normal', fileName: 'Inter-Regular.ttf', data: INTER.Regular },
|
|
340
|
+
{ style: 'bold', fileName: 'Inter-Bold.ttf', data: INTER.Bold },
|
|
341
|
+
],
|
|
342
|
+
}],
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
List all fonts: `npx h17-sspdf --fonts`
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## Vector shapes
|
|
350
|
+
|
|
351
|
+
20 built-in vector shapes rendered via jsPDF drawing primitives. No text encoding, no font dependencies.
|
|
352
|
+
|
|
353
|
+
Use as bullet markers by setting `shape` on a marker label:
|
|
354
|
+
|
|
355
|
+
```js
|
|
356
|
+
// Theme
|
|
357
|
+
'bullet.arrow': { shape: 'arrow', shapeColor: [0, 128, 255], shapeSize: 0.8 }
|
|
358
|
+
|
|
359
|
+
// Source JSON (same bullet operation as always)
|
|
360
|
+
{ "type": "bullet", "label": "doc.body", "markerLabel": "bullet.arrow", "bullets": ["Point one"] }
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Available: `arrow`, `circle`, `square`, `diamond`, `triangle`, `dash`, `chevron`, `doubleColon`, `commentSlash`, `hashComment`, `bracketChevron`, `treeBranch`, `terminalPrompt`, `checkmark`, `cross`, `star`, `plus`, `minus`, `warning`, `infoCircle`
|
|
364
|
+
|
|
365
|
+
List all shapes: `npx h17-sspdf --shapes`
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
323
369
|
## Custom fonts
|
|
324
370
|
|
|
325
|
-
Embed TTF as base64 and register in the theme:
|
|
371
|
+
Embed your own TTF as base64 and register in the theme:
|
|
326
372
|
|
|
327
373
|
```js
|
|
328
374
|
customFonts: [
|
|
329
375
|
{
|
|
330
|
-
family: '
|
|
376
|
+
family: 'MyFont',
|
|
331
377
|
faces: [
|
|
332
|
-
{ style: 'normal', fileName: '
|
|
333
|
-
{ style: 'bold', fileName: '
|
|
378
|
+
{ style: 'normal', fileName: 'MyFont-Regular.ttf', data: '<base64>' },
|
|
379
|
+
{ style: 'bold', fileName: 'MyFont-Bold.ttf', data: '<base64>' },
|
|
334
380
|
],
|
|
335
381
|
},
|
|
336
382
|
],
|
|
337
383
|
```
|
|
338
384
|
|
|
339
|
-
Then use `fontFamily: '
|
|
385
|
+
Then use `fontFamily: 'MyFont'` in any label.
|
|
340
386
|
|
|
341
387
|
---
|
|
342
388
|
|
|
@@ -394,14 +440,26 @@ registerPlugin('chart', plugins.chart);
|
|
|
394
440
|
## CLI
|
|
395
441
|
|
|
396
442
|
```bash
|
|
397
|
-
npx sspdf -s source.json -t theme.js -o output.pdf
|
|
443
|
+
npx h17-sspdf -s source.json -t theme.js -o output.pdf
|
|
398
444
|
```
|
|
399
445
|
|
|
400
446
|
| Flag | Short | Description |
|
|
401
447
|
|------|-------|-------------|
|
|
402
448
|
| `--source` | `-s` | Path to source JSON (or pipe via stdin) |
|
|
403
|
-
| `--theme` | `-t` | Path to theme `.js` file |
|
|
449
|
+
| `--theme` | `-t` | Path to theme `.js` file or built-in name |
|
|
404
450
|
| `--output` | `-o` | Output PDF path |
|
|
451
|
+
| `--fonts` | | List built-in fonts |
|
|
452
|
+
| `--shapes` | | List built-in vector shapes |
|
|
453
|
+
| `--help` | `-h` | Show help |
|
|
454
|
+
|
|
455
|
+
---
|
|
456
|
+
|
|
457
|
+
## AI skills
|
|
458
|
+
|
|
459
|
+
Claude Code skills for generating PDFs and themes are available in the `skills/` directory of the [GitHub repository](https://github.com/hugopalma17/sspdf):
|
|
460
|
+
|
|
461
|
+
- `skills/sspdf/` - Generate PDF documents from a task description
|
|
462
|
+
- `skills/sspdf-theme-generator/` - Generate theme files from brand specs
|
|
405
463
|
|
|
406
464
|
---
|
|
407
465
|
|
package/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ const { renderDocument, registerPlugin, plugins } = require("./index");
|
|
|
7
7
|
const EXAMPLES_THEMES_DIR = path.join(__dirname, "examples", "themes");
|
|
8
8
|
|
|
9
9
|
function parseArgs(argv) {
|
|
10
|
-
const out = { source: null, theme: null, output: null, help: false };
|
|
10
|
+
const out = { source: null, theme: null, output: null, help: false, fonts: false, shapes: false };
|
|
11
11
|
|
|
12
12
|
for (let i = 0; i < argv.length; i++) {
|
|
13
13
|
const arg = argv[i];
|
|
@@ -19,6 +19,10 @@ function parseArgs(argv) {
|
|
|
19
19
|
out.output = argv[++i];
|
|
20
20
|
} else if (arg === "--help" || arg === "-h") {
|
|
21
21
|
out.help = true;
|
|
22
|
+
} else if (arg === "--fonts") {
|
|
23
|
+
out.fonts = true;
|
|
24
|
+
} else if (arg === "--shapes") {
|
|
25
|
+
out.shapes = true;
|
|
22
26
|
} else {
|
|
23
27
|
throw new Error(`Unknown argument: ${arg}`);
|
|
24
28
|
}
|
|
@@ -81,6 +85,43 @@ function readSource(sourcePath) {
|
|
|
81
85
|
return JSON.parse(raw);
|
|
82
86
|
}
|
|
83
87
|
|
|
88
|
+
function listBuiltInFonts() {
|
|
89
|
+
const fontsDir = path.join(__dirname, "fonts");
|
|
90
|
+
try {
|
|
91
|
+
return fs.readdirSync(fontsDir)
|
|
92
|
+
.filter((f) => f.endsWith(".js"))
|
|
93
|
+
.map((f) => f.replace(".js", ""))
|
|
94
|
+
.sort();
|
|
95
|
+
} catch (e) {
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function printFonts() {
|
|
101
|
+
const fonts = listBuiltInFonts();
|
|
102
|
+
if (fonts.length === 0) {
|
|
103
|
+
console.log("No built-in fonts found.");
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
console.log(`Built-in fonts (${fonts.length}):\n`);
|
|
107
|
+
for (const font of fonts) {
|
|
108
|
+
console.log(` ${font.padEnd(22)} require("h17-sspdf/fonts/${font}.js")`);
|
|
109
|
+
}
|
|
110
|
+
console.log(`\nEach font exports { Regular, Bold } as base64 strings.`);
|
|
111
|
+
console.log(`See DOCUMENTATION.md "Built-in fonts" for usage.`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function printShapes() {
|
|
115
|
+
const { shapeWidths } = require("./core/shapes");
|
|
116
|
+
const names = Object.keys(shapeWidths);
|
|
117
|
+
console.log(`Built-in shapes (${names.length}):\n`);
|
|
118
|
+
console.log(" Bullets: arrow, circle, square, diamond, triangle, dash, chevron");
|
|
119
|
+
console.log(" Decorators: doubleColon, commentSlash, hashComment, bracketChevron, treeBranch, terminalPrompt");
|
|
120
|
+
console.log(" Symbols: checkmark, cross, star, plus, minus, warning, infoCircle");
|
|
121
|
+
console.log(`\nUse as marker labels: { shape: "arrow", shapeColor: [0,0,0], shapeSize: 1 }`);
|
|
122
|
+
console.log(`See DOCUMENTATION.md "Vector shapes" for usage.`);
|
|
123
|
+
}
|
|
124
|
+
|
|
84
125
|
function printHelp() {
|
|
85
126
|
const themes = listBuiltInThemes();
|
|
86
127
|
console.log(`
|
|
@@ -95,6 +136,8 @@ Options:
|
|
|
95
136
|
-t, --theme <name|path> Built-in theme name or path to a .js theme file
|
|
96
137
|
-o, --output <path> Output PDF path (default: output/cli-output.pdf)
|
|
97
138
|
-h, --help Show this help
|
|
139
|
+
--fonts List built-in fonts
|
|
140
|
+
--shapes List built-in vector shapes
|
|
98
141
|
|
|
99
142
|
Built-in themes: ${themes.join(", ")}
|
|
100
143
|
|
|
@@ -129,6 +172,14 @@ async function main() {
|
|
|
129
172
|
printHelp();
|
|
130
173
|
return;
|
|
131
174
|
}
|
|
175
|
+
if (args.fonts) {
|
|
176
|
+
printFonts();
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (args.shapes) {
|
|
180
|
+
printShapes();
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
132
183
|
|
|
133
184
|
const source = readSource(args.source);
|
|
134
185
|
const theme = resolveTheme(args.theme);
|
package/core/pdf-core.js
CHANGED
|
@@ -493,8 +493,18 @@ class PDFCore {
|
|
|
493
493
|
);
|
|
494
494
|
const baseline = y + baselineOffsetMm;
|
|
495
495
|
|
|
496
|
-
|
|
497
|
-
|
|
496
|
+
if (markerStyle.shape) {
|
|
497
|
+
// Vector shape marker: renders via core/shapes.js, no text encoding needed
|
|
498
|
+
const { renderShape, getShapeWidth } = require("./shapes");
|
|
499
|
+
const shapeColor = markerStyle.shapeColor || markerStyle.color || [0, 0, 0];
|
|
500
|
+
const shapeSize = markerStyle.shapeSize || 1;
|
|
501
|
+
renderShape(markerStyle.shape, this.doc, x, baseline, shapeColor, shapeSize, textFontSize);
|
|
502
|
+
this.applyDefaultRenderState();
|
|
503
|
+
} else {
|
|
504
|
+
// Text-based marker (existing behavior)
|
|
505
|
+
this.applyTextStyle(markerStyle);
|
|
506
|
+
this.doc.text(String(marker), x, baseline);
|
|
507
|
+
}
|
|
498
508
|
|
|
499
509
|
this.applyTextStyle(textStyle);
|
|
500
510
|
this.doc.setLineHeightFactor(Number(textStyle.lineHeight));
|
package/core/render-document.js
CHANGED
|
@@ -603,9 +603,18 @@ function executeOperation(ctx) {
|
|
|
603
603
|
const defaultX = bounds.left;
|
|
604
604
|
const x = operation.xMm !== undefined ? operation.xMm : defaultX;
|
|
605
605
|
validatePointInsideBounds("xMm", x, bounds, index, templateBypassMargins);
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
606
|
+
let textIndentMm;
|
|
607
|
+
if (operation.textIndentMm !== undefined) {
|
|
608
|
+
textIndentMm = operation.textIndentMm;
|
|
609
|
+
} else if (markerStyle && markerStyle.shape) {
|
|
610
|
+
const { getShapeWidth } = require("./shapes");
|
|
611
|
+
const shapeW = getShapeWidth(markerStyle.shape, markerStyle.shapeSize || 1);
|
|
612
|
+
textIndentMm = shapeW + (markerStyle.textIndentMm !== undefined ? markerStyle.textIndentMm : 1.5);
|
|
613
|
+
} else if (markerStyle && markerStyle.textIndentMm !== undefined) {
|
|
614
|
+
textIndentMm = markerStyle.textIndentMm;
|
|
615
|
+
} else {
|
|
616
|
+
textIndentMm = (theme.layout && Number(theme.layout.bulletIndentMm)) || 4;
|
|
617
|
+
}
|
|
609
618
|
const rightBoundary = bounds.right;
|
|
610
619
|
const maxWidth = operation.maxWidthMm !== undefined
|
|
611
620
|
? operation.maxWidthMm
|
|
@@ -833,10 +842,20 @@ function estimateOperationHeight(ctx) {
|
|
|
833
842
|
|
|
834
843
|
if (operation.type === "bullet") {
|
|
835
844
|
const style = resolveLabelStyle(theme, operation.label, operation, index);
|
|
845
|
+
const markerEstStyle = resolveLabelStyle(theme, operation.markerLabel || "bullet.marker", operation, index, "markerLabel", true);
|
|
836
846
|
const x = operation.xMm !== undefined ? operation.xMm : core.marginLeftMm;
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
847
|
+
let textIndentMm;
|
|
848
|
+
if (operation.textIndentMm !== undefined) {
|
|
849
|
+
textIndentMm = operation.textIndentMm;
|
|
850
|
+
} else if (markerEstStyle && markerEstStyle.shape) {
|
|
851
|
+
const { getShapeWidth } = require("./shapes");
|
|
852
|
+
const shapeW = getShapeWidth(markerEstStyle.shape, markerEstStyle.shapeSize || 1);
|
|
853
|
+
textIndentMm = shapeW + (markerEstStyle.textIndentMm !== undefined ? markerEstStyle.textIndentMm : 1.5);
|
|
854
|
+
} else if (markerEstStyle && markerEstStyle.textIndentMm !== undefined) {
|
|
855
|
+
textIndentMm = markerEstStyle.textIndentMm;
|
|
856
|
+
} else {
|
|
857
|
+
textIndentMm = (theme.layout && Number(theme.layout.bulletIndentMm)) || 4;
|
|
858
|
+
}
|
|
840
859
|
const maxWidth = operation.maxWidthMm !== undefined
|
|
841
860
|
? operation.maxWidthMm
|
|
842
861
|
: core.pageWidth - core.marginRightMm - (x + textIndentMm);
|