@dimm-city/print-md 0.1.12 → 0.2.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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Command-line interface for print-md — markdown to print-ready PDF.
4
4
 
5
- The CLI is for power users who want to script builds, run in CI, batch-process projects, or work outside the desktop app. If you just want to write a book and export a PDF, use the [desktop app](../../README.md#get-the-desktop-app) instead.
5
+ The CLI is for power users who want to script builds, run in CI, batch-process projects, or work outside the desktop app. If you just want to write a book and export a PDF, use the [desktop app](https://github.com/dimm-city/print-md#get-the-desktop-app) instead.
6
6
 
7
7
  ## Install
8
8
 
@@ -26,34 +26,9 @@ Move the binary somewhere on your `PATH`, mark it executable (`chmod +x`), and y
26
26
  npm install -g @dimm-city/print-md
27
27
  ```
28
28
 
29
- This installs the CLI for `node`-based projects. Same surface area as the binary.
30
-
31
- ### With Docker (full PDF/X pipeline pre-installed)
32
-
33
- No need to install Chromium, Ghostscript, or qpdf — the image bundles
34
- everything the `lint → build → validate` pipeline needs, including the PDF/X
35
- (CMYK) pre-print path. (All other validation runs in-process; Poppler and
36
- ImageMagick are no longer used.) Mount your project at `/work`:
37
-
38
- ```sh
39
- docker run --rm -u "$(id -u):$(id -g)" -v "$PWD:/work" \
40
- ghcr.io/dimm-city/print-md build my-book --out dist/my-book.pdf --format pdfx
41
- ```
42
-
43
- See [docs/docker.md](../../docs/docker.md) for the full guide.
44
-
45
- ### From source (development only)
46
-
47
- ```sh
48
- git clone https://github.com/dimm-city/print-md.git
49
- cd print-md
50
- bun install
51
- bun packages/cli/src/cli.ts --help
52
- ```
53
-
54
29
  ## System requirements
55
30
 
56
- The CLI needs a Chromium-based browser for PDF generation, and a few external tools for PDF post-processing and validation depending on which features you use. See [User Guide: Chapter 8 — System Setup](../../examples/print-md-user-guide/08-system-setup.md) for the full per-feature requirements matrix.
31
+ The CLI needs a Chromium-based browser for PDF generation, and a few external tools for PDF post-processing and validation depending on which features you use. See [User Guide: Chapter 8 — System Setup](https://github.com/dimm-city/print-md/blob/main/examples/print-md-user-guide/08-system-setup.md) for the full per-feature requirements matrix.
57
32
 
58
33
  The short version: you almost certainly want **Ghostscript** installed for PDF output, and **Chrome** / **Chromium** / **Edge** for the actual render.
59
34
 
@@ -91,11 +66,11 @@ my-book/
91
66
  └─ images/ ← images referenced from markdown or CSS
92
67
  ```
93
68
 
94
- See [User Guide: Chapter 1 — Getting Started](../../examples/print-md-user-guide/01-getting-started.md) for a full first-project walkthrough and [examples/](../../examples/) for working starters.
69
+ See [User Guide: Chapter 1 — Getting Started](https://github.com/dimm-city/print-md/blob/main/examples/print-md-user-guide/01-getting-started.md) for a full first-project walkthrough and [examples/](https://github.com/dimm-city/print-md/tree/main/examples) for working starters.
95
70
 
96
71
  ## Manifest
97
72
 
98
- `manifest.yaml` is where you control everything that isn't authored in markdown — book title, the page-size preset, custom styles, plugin loading, validation rules, PDF/X configuration. The schema lives in [`docs/schema-autocomplete.md`](../../docs/schema-autocomplete.md) for YAML autocomplete in editors.
73
+ `manifest.yaml` is where you control everything that isn't authored in markdown — book title, the page-size preset, custom styles, plugin loading, validation rules, PDF/X configuration. The schema lives in [`docs/schema-autocomplete.md`](https://github.com/dimm-city/print-md/blob/main/docs/schema-autocomplete.md) for YAML autocomplete in editors.
99
74
 
100
75
  Minimal example:
101
76
 
@@ -116,7 +91,7 @@ source:
116
91
  - chapter-02.md
117
92
  ```
118
93
 
119
- The full configuration cascade is `CLI flags > manifest.yaml > preset defaults`. See [docs/user-guide.md](../../docs/user-guide.md#configuration) for the comprehensive reference.
94
+ The full configuration cascade is `CLI flags > manifest.yaml > preset defaults`. See the [configuration reference](https://github.com/dimm-city/print-md/blob/main/docs/user-guide.md#configuration) for details.
120
95
 
121
96
  ## Commands
122
97
 
@@ -165,7 +140,7 @@ Common print-unsafe patterns the plugin flags: remote `url(...)` references in C
165
140
 
166
141
  ### `print-md validate`
167
142
 
168
- Run the validation pipeline (pre-build source checks and/or post-build PDF checks). Tools that aren't installed are skipped with a warning — they don't fail the run. See [User Guide: Chapter 7 — Validation](../../examples/print-md-user-guide/07-validation.md) for the full check list and [User Guide: Chapter 8 — System Setup](../../examples/print-md-user-guide/08-system-setup.md) for which external tools each check needs.
143
+ Run the validation pipeline (pre-build source checks and/or post-build PDF checks). Tools that aren't installed are skipped with a warning — they don't fail the run. See [User Guide: Chapter 7 — Validation](https://github.com/dimm-city/print-md/blob/main/examples/print-md-user-guide/07-validation.md) for the full check list and [User Guide: Chapter 8 — System Setup](https://github.com/dimm-city/print-md/blob/main/examples/print-md-user-guide/08-system-setup.md) for which external tools each check needs.
169
144
 
170
145
  ```sh
171
146
  print-md validate [input-dir] [options]
@@ -196,7 +171,7 @@ plugins:
196
171
  priority: 10
197
172
  ```
198
173
 
199
- See [User Guide: Chapter 6 — Plugins](../../examples/print-md-user-guide/06-plugins.md) for authoring custom plugins.
174
+ See [User Guide: Chapter 6 — Plugins](https://github.com/dimm-city/print-md/blob/main/examples/print-md-user-guide/06-plugins.md) for authoring custom plugins.
200
175
 
201
176
  ## CI / scripting
202
177
 
@@ -212,35 +187,22 @@ The standalone binary is the easiest way — drop it in a GitHub Actions step an
212
187
  ./print-md build ./my-book --out dist/my-book.pdf
213
188
  ```
214
189
 
215
- The binary is self-contained except for the system tools described in [User Guide: Chapter 8 — System Setup](../../examples/print-md-user-guide/08-system-setup.md). On a runner with Chrome and Ghostscript present, you don't need a separate Node or Bun install.
190
+ The binary is self-contained except for the system tools described in [User Guide: Chapter 8 — System Setup](https://github.com/dimm-city/print-md/blob/main/examples/print-md-user-guide/08-system-setup.md). On a runner with Chrome and Ghostscript present, you don't need a separate Node or Bun install.
216
191
 
217
192
  ## Troubleshooting
218
193
 
219
- - **`spawn gs ENOENT`** — Ghostscript not installed. Plain `--format pdf` keeps working (only loses the `/Creator` metadata stamp). PDF/X builds genuinely need it. See [User Guide: Chapter 8 — System Setup](../../examples/print-md-user-guide/08-system-setup.md).
194
+ - **`spawn gs ENOENT`** — Ghostscript not installed. Plain `--format pdf` keeps working (only loses the `/Creator` metadata stamp). PDF/X builds genuinely need it. See [User Guide: Chapter 8 — System Setup](https://github.com/dimm-city/print-md/blob/main/examples/print-md-user-guide/08-system-setup.md).
220
195
  - **`No Chrome or Chromium binary found`** — install Chrome/Chromium/Edge, or set `CHROMIUM_PATH=/path/to/chrome` in your environment.
221
196
  - **`Tool "X" not found — skipping`** during validate — that's the graceful path; the check requires `X` and isn't available. Install the tool or accept the skip.
222
197
  - **All validate checks skipped on Windows** — was a bug pre-0.1.7 (used `which`, which isn't on stock Windows); fixed to use `where.exe`.
223
198
 
224
- ## Development
225
-
226
- This package is part of the [print-md monorepo](../../README.md). The CLI itself is a thin shell over [`@dimm-city/print-md-lib`](../lib/) — almost all logic lives there.
227
-
228
- ```sh
229
- # From repo root
230
- bun install
231
-
232
- # Run CLI from source
233
- bun packages/cli/src/cli.ts build ./examples/dc-design-guide
234
-
235
- # Build the standalone binary for the current platform
236
- bun --cwd packages/cli scripts/compile.ts bun-linux-x64 ./dist/print-md-cli-linux-x64
237
-
238
- # Build the npm tarball
239
- bun --cwd packages/cli scripts/build-npm.ts
240
- ```
199
+ ## Links
241
200
 
242
- See [`CONTRIBUTING.md`](../../CONTRIBUTING.md) for the contributor workflow and [`docs/ARCHITECTURE.md`](../../docs/ARCHITECTURE.md) for the architectural rules of this package (no bundlers at runtime, lazy-loaded heavy deps, etc).
201
+ - [GitHub repository](https://github.com/dimm-city/print-md)
202
+ - [Report an issue](https://github.com/dimm-city/print-md/issues)
203
+ - [Full user guide](https://github.com/dimm-city/print-md/tree/main/examples/print-md-user-guide)
204
+ - [Desktop app](https://github.com/dimm-city/print-md/releases/latest)
243
205
 
244
206
  ## License
245
207
 
246
- [MPL-2.0](../../LICENSE)
208
+ [MPL-2.0](https://github.com/dimm-city/print-md/blob/main/LICENSE)
package/dist/cli.js CHANGED
@@ -22640,7 +22640,7 @@ var package_default;
22640
22640
  var init_package = __esm(() => {
22641
22641
  package_default = {
22642
22642
  name: "@dimm-city/print-md-lib",
22643
- version: "0.1.12",
22643
+ version: "0.2.0",
22644
22644
  private: true,
22645
22645
  type: "module",
22646
22646
  main: "dist/index.js",
@@ -22883,7 +22883,7 @@ var manifest_schema_default = "./manifest.schema-16z94mx1.json";
22883
22883
  var init_manifest_schema = () => {};
22884
22884
 
22885
22885
  // ../lib/src/assets/preview/scripts/pagedjs-interface.js
22886
- var pagedjs_interface_default = "./pagedjs-interface-vzkzgeb9.js";
22886
+ var pagedjs_interface_default = "./pagedjs-interface-9w9r490k.js";
22887
22887
  var init_pagedjs_interface = () => {};
22888
22888
 
22889
22889
  // ../lib/src/assets/preview/scripts/pagedjs-bridge.js
@@ -0,0 +1,175 @@
1
+ // Interface adapter: exposes window.previewAPI for the parent toolbar.
2
+ // Paged.js paginates into .pagedjs_page elements. We use PagedConfig.after
3
+ // to know when rendering is done.
4
+
5
+ (function () {
6
+ 'use strict';
7
+
8
+ var pages = [];
9
+ var currentPage = 1;
10
+ var debugMode = false;
11
+ var currentViewMode = 'two-column';
12
+ var ignoreScrollUntil = 0;
13
+
14
+ function refreshPages() {
15
+ pages = Array.from(document.querySelectorAll('.pagedjs_page'));
16
+ return pages;
17
+ }
18
+
19
+ function clampPage(n) {
20
+ if (pages.length === 0) return 1;
21
+ var page = Number(n);
22
+ if (!Number.isFinite(page)) page = 1;
23
+ return Math.max(1, Math.min(Math.round(page), pages.length));
24
+ }
25
+
26
+ function detectVisiblePage() {
27
+ if (pages.length === 0) return 1;
28
+ var scrollTop = window.scrollY || document.documentElement.scrollTop;
29
+ var threshold = scrollTop + window.innerHeight / 3;
30
+ var page = 1;
31
+ var pageTop = pages[0].offsetTop;
32
+ for (var i = pages.length - 1; i >= 0; i--) {
33
+ if (pages[i].offsetTop <= threshold) {
34
+ pageTop = pages[i].offsetTop;
35
+ break;
36
+ }
37
+ }
38
+ for (var j = 0; j < pages.length; j++) {
39
+ if (Math.abs(pages[j].offsetTop - pageTop) < 2) {
40
+ page = j + 1;
41
+ break;
42
+ }
43
+ }
44
+ return page;
45
+ }
46
+
47
+ function scrollToCurrentPage() {
48
+ if (pages.length === 0) return;
49
+ var page = clampPage(currentPage);
50
+ currentPage = page;
51
+ ignoreScrollUntil = Date.now() + 300;
52
+ pages[page - 1].scrollIntoView({ behavior: 'instant', block: 'start', inline: 'nearest' });
53
+ }
54
+
55
+ function pageStep(mode) {
56
+ return (mode || currentViewMode) === 'single' ? 1 : 2;
57
+ }
58
+
59
+ var api = {
60
+ getTotalPages: function () { refreshPages(); return pages.length; },
61
+ getCurrentPage: function () { return currentPage; },
62
+ goToPage: function (n) {
63
+ refreshPages();
64
+ currentPage = clampPage(n);
65
+ scrollToCurrentPage();
66
+ return api.notifyPageChange();
67
+ },
68
+ getPageDimensions: function () {
69
+ refreshPages();
70
+ var page = pages[0] || null;
71
+ var pagesEl = document.querySelector('.pagedjs_pages');
72
+ if (!page) return null;
73
+ return {
74
+ width: currentViewMode === 'single' ? page.offsetWidth : (pagesEl ? pagesEl.scrollWidth : page.offsetWidth),
75
+ height: page.offsetHeight
76
+ };
77
+ },
78
+ firstPage: function () { return api.goToPage(1); },
79
+ prevPage: function (mode) { return api.goToPage(currentPage - pageStep(mode)); },
80
+ nextPage: function (mode) { return api.goToPage(currentPage + pageStep(mode)); },
81
+ lastPage: function () { refreshPages(); return api.goToPage(pages.length); },
82
+ setViewMode: function (mode) {
83
+ refreshPages();
84
+ currentViewMode = mode || 'two-column';
85
+ document.body.classList.remove('view-single', 'view-spread', 'view-two-column');
86
+ if (mode) document.body.classList.add('view-' + mode);
87
+ scrollToCurrentPage();
88
+ return api.notifyPageChange();
89
+ },
90
+ setZoom: function (z) {
91
+ document.documentElement.style.setProperty('--pmd-zoom', z);
92
+ },
93
+ toggleDebugMode: function () {
94
+ debugMode = !debugMode;
95
+ document.body.classList.toggle('debug', debugMode);
96
+ return debugMode;
97
+ },
98
+ notifyPageChange: function () {
99
+ var detail = { currentPage: api.getCurrentPage(), totalPages: pages.length };
100
+ window.dispatchEvent(new CustomEvent('pageChanged', { detail: detail }));
101
+ return detail;
102
+ },
103
+ notifyRenderingComplete: function () {
104
+ window.dispatchEvent(new CustomEvent('renderingComplete', {
105
+ detail: { totalPages: pages.length }
106
+ }));
107
+ }
108
+ };
109
+
110
+ window.previewAPI = api;
111
+
112
+ var observedPageCount = 0;
113
+ var pageObserverQueued = false;
114
+ function publishObservedPageCount() {
115
+ pageObserverQueued = false;
116
+ if (window.__PAGED_RENDERED__ === true) return;
117
+ var count = refreshPages().length;
118
+ if (count > observedPageCount) {
119
+ observedPageCount = count;
120
+ window.dispatchEvent(new CustomEvent('pageChanged', {
121
+ detail: { currentPage: count, totalPages: count }
122
+ }));
123
+ }
124
+ }
125
+ var pageObserver = new MutationObserver(function () {
126
+ if (window.__PAGED_RENDERED__ === true) return;
127
+ if (pageObserverQueued) return;
128
+ pageObserverQueued = true;
129
+ window.requestAnimationFrame(publishObservedPageCount);
130
+ });
131
+
132
+ function startPageObserver() {
133
+ var target = document.body || document.documentElement;
134
+ if (!target) return false;
135
+ pageObserver.observe(target, { childList: true, subtree: true });
136
+ return true;
137
+ }
138
+
139
+ if (!startPageObserver()) {
140
+ document.addEventListener('DOMContentLoaded', function onReady() {
141
+ document.removeEventListener('DOMContentLoaded', onReady);
142
+ startPageObserver();
143
+ });
144
+ }
145
+
146
+ // Scroll tracking
147
+ var scrollTimer = null;
148
+ window.addEventListener('scroll', function () {
149
+ if (pages.length === 0) refreshPages();
150
+ if (pages.length === 0) return;
151
+ if (scrollTimer) clearTimeout(scrollTimer);
152
+ scrollTimer = setTimeout(function () {
153
+ if (Date.now() < ignoreScrollUntil) return;
154
+ var page = detectVisiblePage();
155
+ if (page !== currentPage) {
156
+ currentPage = page;
157
+ api.notifyPageChange();
158
+ }
159
+ }, 150);
160
+ });
161
+
162
+ // Paged.js calls this when rendering is complete
163
+ window.PagedConfig = window.PagedConfig || {};
164
+ window.PagedConfig.after = function (flow) {
165
+ refreshPages();
166
+ observedPageCount = pages.length;
167
+ pageObserver.disconnect();
168
+ currentPage = 1;
169
+ ignoreScrollUntil = Date.now() + 300;
170
+ window.scrollTo(0, 0);
171
+ console.log('Paged.js rendered ' + pages.length + ' pages');
172
+ api.notifyRenderingComplete();
173
+ setTimeout(api.notifyPageChange, 0);
174
+ };
175
+ })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dimm-city/print-md",
3
- "version": "0.1.12",
3
+ "version": "0.2.0",
4
4
  "description": "Markdown-to-PDF converter for professional print layout using Paged.js and Ghostscript.",
5
5
  "author": "itlackey",
6
6
  "license": "MPL-2.0",
@@ -1,94 +0,0 @@
1
- // Interface adapter: exposes window.previewAPI for the parent toolbar.
2
- // Paged.js paginates into .pagedjs_page elements. We use PagedConfig.after
3
- // to know when rendering is done.
4
-
5
- (function () {
6
- 'use strict';
7
-
8
- var pages = [];
9
- var currentIndex = 0;
10
- var debugMode = false;
11
-
12
- function refreshPages() {
13
- pages = Array.from(document.querySelectorAll('.pagedjs_page'));
14
- return pages;
15
- }
16
-
17
- function detectCurrentPage() {
18
- if (pages.length === 0) return 0;
19
- var scrollTop = window.scrollY || document.documentElement.scrollTop;
20
- var threshold = scrollTop + window.innerHeight / 3;
21
- for (var i = pages.length - 1; i >= 0; i--) {
22
- if (pages[i].offsetTop <= threshold) return i;
23
- }
24
- return 0;
25
- }
26
-
27
- var api = {
28
- getTotalPages: function () { refreshPages(); return pages.length; },
29
- getCurrentPage: function () { return currentIndex + 1; },
30
- goToPage: function (n) {
31
- refreshPages();
32
- currentIndex = Math.max(0, Math.min(n - 1, pages.length - 1));
33
- // Use 'instant' so the scroll completes synchronously before notifyPageChange
34
- // fires. 'smooth' interacts with the scroll-listener debounce timer and causes
35
- // the parent Svelte toolbar to receive a stale page number on fast navigation.
36
- pages[currentIndex].scrollIntoView({ behavior: 'instant', block: 'start' });
37
- api.notifyPageChange();
38
- },
39
- getPageDimensions: function () {
40
- var page = document.querySelector('.pagedjs_page');
41
- return page ? { width: page.offsetWidth, height: page.offsetHeight } : null;
42
- },
43
- firstPage: function () { api.goToPage(1); },
44
- prevPage: function () { api.goToPage(currentIndex); },
45
- nextPage: function () { api.goToPage(currentIndex + 2); },
46
- lastPage: function () { api.goToPage(pages.length); },
47
- setViewMode: function (mode) {
48
- document.body.classList.remove('view-single', 'view-spread', 'view-two-column');
49
- if (mode) document.body.classList.add('view-' + mode);
50
- },
51
- setZoom: function (z) {
52
- document.documentElement.style.setProperty('--pmd-zoom', z);
53
- },
54
- toggleDebugMode: function () {
55
- debugMode = !debugMode;
56
- document.body.classList.toggle('debug', debugMode);
57
- return debugMode;
58
- },
59
- notifyPageChange: function () {
60
- window.dispatchEvent(new CustomEvent('pageChanged', {
61
- detail: { currentPage: api.getCurrentPage(), totalPages: pages.length }
62
- }));
63
- },
64
- notifyRenderingComplete: function () {
65
- window.dispatchEvent(new CustomEvent('renderingComplete', {
66
- detail: { totalPages: pages.length }
67
- }));
68
- }
69
- };
70
-
71
- window.previewAPI = api;
72
-
73
- // Scroll tracking
74
- var scrollTimer = null;
75
- window.addEventListener('scroll', function () {
76
- if (pages.length === 0) return;
77
- if (scrollTimer) clearTimeout(scrollTimer);
78
- scrollTimer = setTimeout(function () {
79
- var idx = detectCurrentPage();
80
- if (idx !== currentIndex) {
81
- currentIndex = idx;
82
- api.notifyPageChange();
83
- }
84
- }, 150);
85
- });
86
-
87
- // Paged.js calls this when rendering is complete
88
- window.PagedConfig = window.PagedConfig || {};
89
- window.PagedConfig.after = function (flow) {
90
- refreshPages();
91
- console.log('Paged.js rendered ' + pages.length + ' pages');
92
- api.notifyRenderingComplete();
93
- };
94
- })();