gutterpress 0.11.10 → 0.11.11-alpha.2
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 +3 -3
- package/dist/api/index.js +2 -2
- package/dist/{build-83dnh2qe.js → build-pjd42x09.js} +4 -4
- package/dist/checks/asset/extensions.d.ts +2 -2
- package/dist/checks/policy.d.ts +5 -7
- package/dist/checks/register-builtins.d.ts +6 -6
- package/dist/checks/registry.d.ts +1 -1
- package/dist/{cli-79tsqp3p.js → cli-1kdtzgxm.js} +1 -1
- package/dist/{cli-mv1mhpkk.js → cli-d2he8zph.js} +6 -6
- package/dist/{cli-b36za51e.js → cli-ny50k8md.js} +3 -3
- package/dist/{cli-30j93gzt.js → cli-tjhn2mdn.js} +3 -3
- package/dist/cli.js +12 -12
- package/dist/{doctor-sy4gc8r9.js → doctor-qkh9byxa.js} +2 -2
- package/dist/engine/shared/cdp.d.ts +5 -9
- package/dist/engine/shared/pdf-inspect.d.ts +0 -4
- package/dist/{engine-mwshptgf.js → engine-132czsq9.js} +1 -1
- package/dist/{engine-3gwctsty.js → engine-bgd4aa99.js} +2 -2
- package/dist/{ext-a7ffvyc0.js → ext-271xnh70.js} +4 -4
- package/dist/{index-dzp0hc2c.js → index-b6p1fh61.js} +1 -1
- package/dist/{index-r4wvy5v3.js → index-mw8b25yx.js} +3 -3
- package/dist/{index-0cvkvpkg.js → index-ssjh6tnd.js} +7 -7
- package/dist/index.js +3 -3
- package/dist/lib/asset-inline.d.ts +1 -2
- package/dist/lib/build-error.d.ts +4 -6
- package/dist/lib/build-fingerprint.d.ts +3 -4
- package/dist/lib/build-preflight.d.ts +4 -6
- package/dist/lib/build-runner.d.ts +24 -35
- package/dist/lib/build-staging.d.ts +3 -5
- package/dist/lib/cli-args.d.ts +1 -1
- package/dist/lib/desktop.d.ts +2 -8
- package/dist/lib/engine.d.ts +2 -2
- package/dist/lib/exec.d.ts +3 -6
- package/dist/lib/fetch-timeout.d.ts +3 -4
- package/dist/lib/ghostscript.d.ts +1 -1
- package/dist/lib/host-policy.d.ts +6 -8
- package/dist/lib/image-inspect.d.ts +2 -2
- package/dist/lib/install-hints.d.ts +2 -3
- package/dist/lib/manifest-config.d.ts +2 -3
- package/dist/lib/manifest-doc.d.ts +2 -3
- package/dist/lib/manifest.d.ts +4 -7
- package/dist/lib/markdown/assemble.d.ts +7 -13
- package/dist/lib/markdown/gutterpress-css.d.ts +6 -9
- package/dist/lib/markdown/images.d.ts +0 -7
- package/dist/lib/markdown/index.d.ts +7 -11
- package/dist/lib/markdown/markers.d.ts +3 -4
- package/dist/lib/markdown/plugins.d.ts +9 -12
- package/dist/lib/markdown/renderer.d.ts +10 -14
- package/dist/lib/missing-asset-placeholder.d.ts +2 -5
- package/dist/lib/output-paths.d.ts +4 -5
- package/dist/lib/pdf-inspect.d.ts +5 -5
- package/dist/lib/pdf-parse.d.ts +6 -7
- package/dist/lib/presets.d.ts +2 -3
- package/dist/lib/project-source.d.ts +3 -4
- package/dist/lib/publish/command-runner.d.ts +1 -1
- package/dist/lib/publish/connect-google.d.ts +2 -2
- package/dist/lib/publish/types.d.ts +3 -3
- package/dist/lib/remote-auth/clone.d.ts +2 -2
- package/dist/lib/remote-auth/converge-merge.d.ts +1 -1
- package/dist/lib/remote-auth/diagnose.d.ts +3 -3
- package/dist/lib/remote-auth/generic-auth.d.ts +1 -1
- package/dist/lib/remote-auth/git-http.d.ts +5 -5
- package/dist/lib/remote-auth/github-auth.d.ts +3 -3
- package/dist/lib/remote-auth/github-repos.d.ts +4 -4
- package/dist/lib/remote-auth/sync-types.d.ts +1 -1
- package/dist/lib/remote-auth/sync.d.ts +1 -1
- package/dist/lib/remote-auth/test-access.d.ts +1 -1
- package/dist/lib/remote-auth/token-store.d.ts +1 -1
- package/dist/lib/remote-auth/transport.d.ts +3 -3
- package/dist/lib/render-parity-raster.d.ts +28 -0
- package/dist/lib/render-parity.d.ts +4 -1
- package/dist/lib/source-provider.d.ts +4 -5
- package/dist/lib/static-serve.d.ts +8 -13
- package/dist/lib/style-resolver.d.ts +1 -1
- package/dist/lib/targets.d.ts +1 -5
- package/dist/lib/tool-probe.d.ts +2 -3
- package/dist/lib/validation-exec.d.ts +3 -4
- package/dist/{new-994trd8k.js → new-7w4ezfpy.js} +4 -4
- package/dist/platform.d.ts +8 -41
- package/dist/{preflight-2rtrakyf.js → preflight-f3h6arjp.js} +4 -4
- package/dist/preview/file-watcher.d.ts +3 -5
- package/dist/preview/lifecycle.d.ts +9 -17
- package/dist/{preview-bridge-b4jbtb79.js → preview-bridge-8jhd1wpb.js} +1 -1
- package/dist/{preview-interface-9rwz21yw.js → preview-interface-twd6nsf5.js} +74 -13
- package/dist/{preview-shell-tqndvhbx.js → preview-shell-y8yrm3f0.js} +8 -19
- package/dist/{preview-n9s46142.js → preview-y39jrpbs.js} +4 -4
- package/dist/{publish-wte9548r.js → publish-tvj3xh8m.js} +4 -4
- package/dist/render.d.ts +5 -5
- package/dist/render.js +2 -2
- package/dist/schema/manifest.types.d.ts +2 -2
- package/dist/utils/logger.d.ts +1 -2
- package/dist/{validate-jfsh3m1c.js → validate-9enr4ecc.js} +4 -4
- package/package.json +3 -3
|
@@ -7,16 +7,16 @@ import {
|
|
|
7
7
|
TARGET_IDS,
|
|
8
8
|
scaffoldExtension,
|
|
9
9
|
scaffoldProject
|
|
10
|
-
} from "./cli-
|
|
10
|
+
} from "./cli-d2he8zph.js";
|
|
11
11
|
import {
|
|
12
12
|
resolveGhostscript
|
|
13
|
-
} from "./cli-
|
|
13
|
+
} from "./cli-1kdtzgxm.js";
|
|
14
14
|
import {
|
|
15
15
|
UsageError,
|
|
16
16
|
rejectExtraPositionals,
|
|
17
17
|
rejectUnknownFlags
|
|
18
|
-
} from "./cli-
|
|
19
|
-
import"./cli-
|
|
18
|
+
} from "./cli-ny50k8md.js";
|
|
19
|
+
import"./cli-tjhn2mdn.js";
|
|
20
20
|
import {
|
|
21
21
|
EXIT_CODES
|
|
22
22
|
} from "./cli-46ycxe6r.js";
|
package/dist/platform.d.ts
CHANGED
|
@@ -2,22 +2,19 @@
|
|
|
2
2
|
* Platform abstraction contract (GitHub #41).
|
|
3
3
|
*
|
|
4
4
|
* The desktop talks to its host through ONE seam so that the app code never
|
|
5
|
-
* branches on
|
|
6
|
-
*
|
|
7
|
-
* backed by the File System Access API drops in behind the same interface and
|
|
8
|
-
* the app code does not change.
|
|
5
|
+
* branches on the host directly. The only host is Electron (IPC + native
|
|
6
|
+
* dialogs).
|
|
9
7
|
*
|
|
10
8
|
* This module is **types only** — it is imported by the browser SPA via
|
|
11
9
|
* `import type`, so it must never pull in a Node runtime dependency.
|
|
12
10
|
*
|
|
13
11
|
* Canonical home: `gutterpress`. The desktop re-exports these types
|
|
14
|
-
* from `src/lib/platform/` and implements them in `electron-adapter.ts
|
|
15
|
-
*
|
|
12
|
+
* from `src/lib/platform/` and implements them in `electron-adapter.ts`.
|
|
13
|
+
* Keep the implementation in lockstep with this contract.
|
|
16
14
|
*/
|
|
17
15
|
/**
|
|
18
|
-
* The narrow set of
|
|
19
|
-
*
|
|
20
|
-
* IO, filesystem watching, and OS-keychain-backed secrets.
|
|
16
|
+
* The narrow set of host file primitives: raw file IO and filesystem
|
|
17
|
+
* watching.
|
|
21
18
|
*
|
|
22
19
|
* Host RPC services that are *also* host-divergent (preview/build/doctor/prefs/
|
|
23
20
|
* updater) are modelled separately as {@link HostServices} so this primitive
|
|
@@ -45,56 +42,26 @@ export interface FileWriteResult {
|
|
|
45
42
|
mtimeMs: number;
|
|
46
43
|
}
|
|
47
44
|
export interface PlatformAdapter {
|
|
48
|
-
/** Which host backs this adapter. Lets the rare unavoidable branch be explicit. */
|
|
49
|
-
readonly platform: "electron" | "web";
|
|
50
|
-
/**
|
|
51
|
-
* Prompt the user to choose a project folder.
|
|
52
|
-
* @returns the absolute path, or `null` if the user cancelled.
|
|
53
|
-
* Electron: native directory dialog. Web: File System Access API.
|
|
54
|
-
*/
|
|
55
|
-
openFolder(): Promise<string | null>;
|
|
56
45
|
/**
|
|
57
46
|
* Read a UTF-8 text file by absolute path.
|
|
58
|
-
* Editor seam for #38/#39 — no current consumer in 0.4.0.
|
|
59
47
|
*/
|
|
60
48
|
readFile(path: string): Promise<string>;
|
|
61
49
|
/**
|
|
62
50
|
* Write a UTF-8 text file by absolute path, creating/overwriting it.
|
|
63
51
|
* Resolves with the post-write {@link FileWriteResult} (`{ mtimeMs }`) so the
|
|
64
|
-
* editor (#44) can record the on-disk baseline mtime
|
|
65
|
-
* value are unaffected (additive widening — was `Promise<void>`).
|
|
52
|
+
* editor (#44) can record the on-disk baseline mtime.
|
|
66
53
|
*/
|
|
67
54
|
writeFile(path: string, content: string): Promise<FileWriteResult>;
|
|
68
|
-
/**
|
|
69
|
-
* List the immediate entries of a directory (single level, no recursion).
|
|
70
|
-
* @returns each entry's `name`, absolute `path`, and whether it `isDir`.
|
|
71
|
-
* Editor seam for #38 (file-tree sidebar). Electron: `node:fs/promises`
|
|
72
|
-
* `readdir`. Web: File System Access API (0.6.0).
|
|
73
|
-
*/
|
|
74
|
-
listDir(path: string): Promise<Array<{
|
|
75
|
-
name: string;
|
|
76
|
-
path: string;
|
|
77
|
-
isDir: boolean;
|
|
78
|
-
}>>;
|
|
79
55
|
/**
|
|
80
56
|
* Stat a file by absolute path (GitHub #44). Used by the editor to confirm a
|
|
81
57
|
* `watchFolder` event reflects a real on-disk change (mtime moved) versus the
|
|
82
58
|
* self-echo of our own `writeFile`. Resolves with `exists: false` rather than
|
|
83
|
-
* rejecting when the path is absent.
|
|
59
|
+
* rejecting when the path is absent.
|
|
84
60
|
*/
|
|
85
61
|
statFile(path: string): Promise<FileStat>;
|
|
86
62
|
/**
|
|
87
63
|
* Watch a folder for changes, invoking `cb` on each change.
|
|
88
64
|
* @returns an unsubscribe function.
|
|
89
|
-
* Web has no general recursive-watch primitive — `WebAdapter` throws here
|
|
90
|
-
* until 0.6.0. Electron wiring lands with the in-app editor (#38).
|
|
91
65
|
*/
|
|
92
66
|
watchFolder(path: string, cb: () => void): () => void;
|
|
93
|
-
/**
|
|
94
|
-
* Read a secret by key (e.g. a GitHub token). Lands with #12.
|
|
95
|
-
* Electron: OS keychain via `safeStorage`. Web: encrypted localStorage.
|
|
96
|
-
*/
|
|
97
|
-
getSecret(key: string): Promise<string | null>;
|
|
98
|
-
/** Store a secret by key. Lands with #12. */
|
|
99
|
-
setSecret(key: string, value: string): Promise<void>;
|
|
100
67
|
}
|
|
@@ -2,16 +2,16 @@ import {
|
|
|
2
2
|
executeValidation,
|
|
3
3
|
publishTargetFor,
|
|
4
4
|
reportMissingTools
|
|
5
|
-
} from "./cli-
|
|
5
|
+
} from "./cli-d2he8zph.js";
|
|
6
6
|
import {
|
|
7
7
|
log
|
|
8
|
-
} from "./cli-
|
|
8
|
+
} from "./cli-1kdtzgxm.js";
|
|
9
9
|
import {
|
|
10
10
|
UsageError,
|
|
11
11
|
rejectExtraPositionals,
|
|
12
12
|
rejectUnknownFlags
|
|
13
|
-
} from "./cli-
|
|
14
|
-
import"./cli-
|
|
13
|
+
} from "./cli-ny50k8md.js";
|
|
14
|
+
import"./cli-tjhn2mdn.js";
|
|
15
15
|
import {
|
|
16
16
|
EXIT_CODES
|
|
17
17
|
} from "./cli-46ycxe6r.js";
|
|
@@ -125,11 +125,9 @@ export declare function externalWatchTargets(projectDir: string, config: {
|
|
|
125
125
|
* Create and configure a file watcher for the project's input directory plus
|
|
126
126
|
* the book's declared external dependencies (see {@link externalWatchTargets}).
|
|
127
127
|
*
|
|
128
|
-
* Nothing is mirrored anywhere: the
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
* The project is served straight from disk and stylesheets are inlined at
|
|
132
|
-
* render time, so an external dependency needs watching, not staging.
|
|
128
|
+
* Nothing is mirrored anywhere: the project is served straight from disk and
|
|
129
|
+
* stylesheets are inlined at render time, so an external dependency needs
|
|
130
|
+
* watching, not staging.
|
|
133
131
|
*/
|
|
134
132
|
export declare function createFileWatcher(state: ServerState): FSWatcher;
|
|
135
133
|
/**
|
|
@@ -9,9 +9,8 @@ import type { ServerState } from './server-context';
|
|
|
9
9
|
/**
|
|
10
10
|
* Initialize the preview's temp directory.
|
|
11
11
|
*
|
|
12
|
-
* SERVE-IN-PLACE
|
|
13
|
-
*
|
|
14
|
-
* mirror of the project. It holds ONLY files gutterpress itself generates — right
|
|
12
|
+
* SERVE-IN-PLACE: the temp dir is not a mirror of the project. It holds ONLY
|
|
13
|
+
* files gutterpress itself generates — right
|
|
15
14
|
* now that's `book.html` (written later by {@link generateAndWriteHtml}) and
|
|
16
15
|
* the PID marker file below. Every other path the served HTML asks for
|
|
17
16
|
* (images, anything else under the project) is read straight from the
|
|
@@ -23,12 +22,8 @@ import type { ServerState } from './server-context';
|
|
|
23
22
|
* so there is no separate copy step that can drift from what a build actually
|
|
24
23
|
* ships (the "works in preview, broken in the PDF" bug class). It also means
|
|
25
24
|
* a project's `.env`, `.git`, or any other dotfile is never duplicated into a
|
|
26
|
-
* world-readable temp dir
|
|
27
|
-
*
|
|
28
|
-
* the project's real dotfiles now that the project is served directly.
|
|
29
|
-
*
|
|
30
|
-
* No longer takes `inputPath`/`config` — both were needed only for the copy
|
|
31
|
-
* steps removed above, and there is nothing left to configure here.
|
|
25
|
+
* world-readable temp dir — see http-server.ts's dotfile guard, which is what
|
|
26
|
+
* stands between a request and the project's real dotfiles.
|
|
32
27
|
*/
|
|
33
28
|
export declare function initializePreviewDirectories(): Promise<string>;
|
|
34
29
|
/**
|
|
@@ -46,14 +41,11 @@ export declare function initializeConfiguration(inputPath: string): Promise<Reso
|
|
|
46
41
|
/**
|
|
47
42
|
* Restart the preview server with a new input directory.
|
|
48
43
|
*
|
|
49
|
-
* SERVE-IN-PLACE makes this trivially correct
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* shared-nothing, generated-files-only) temp dir the way the previous
|
|
55
|
-
* `copyDirectory(newInputPath, state.tempDir)` could leave a stale mix of two
|
|
56
|
-
* projects' content if it partially failed.
|
|
44
|
+
* SERVE-IN-PLACE makes this trivially correct: the HTTP server
|
|
45
|
+
* (http-server.ts) reads `state.currentInputPath` fresh on every request
|
|
46
|
+
* instead of serving a mirror, so repointing that one field IS the switch —
|
|
47
|
+
* there is no per-project copy to redo, and no old project's files left
|
|
48
|
+
* behind in the generated-files-only temp dir.
|
|
57
49
|
*/
|
|
58
50
|
export declare function restartPreview(newInputPath: string, state: ServerState): Promise<void>;
|
|
59
51
|
/**
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
window.addEventListener('renderingComplete', function (e) {
|
|
68
68
|
post({ type: 'gutterpress:event', name: 'renderingComplete', detail: e.detail });
|
|
69
69
|
});
|
|
70
|
-
//
|
|
70
|
+
// source-position sync + click-to-source.
|
|
71
71
|
window.addEventListener('sourceLineChanged', function (e) {
|
|
72
72
|
post({ type: 'gutterpress:event', name: 'sourceLineChanged', detail: e.detail });
|
|
73
73
|
});
|
|
@@ -82,16 +82,18 @@
|
|
|
82
82
|
return (bestArea > 0 ? best : nearest) + 1;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
function scrollToCurrentPage() {
|
|
85
|
+
function scrollToCurrentPage(smooth) {
|
|
86
86
|
if (pages.length === 0) return;
|
|
87
87
|
var page = clampPage(currentPage);
|
|
88
88
|
currentPage = page;
|
|
89
|
-
|
|
89
|
+
// A smooth scroll is still moving when the plain 300ms guard expires, and
|
|
90
|
+
// detectVisiblePage would then report the page it is passing through.
|
|
91
|
+
ignoreScrollUntil = Date.now() + (smooth ? 700 : 300);
|
|
90
92
|
// Native's rows can be wider than the viewport (a long chapter scrolls
|
|
91
93
|
// horizontally within its own row) — align the target sheet's left edge
|
|
92
94
|
// to the viewport's left edge (matching detectVisiblePage's `refX`).
|
|
93
95
|
pages[page - 1].scrollIntoView({
|
|
94
|
-
behavior: 'instant',
|
|
96
|
+
behavior: smooth ? 'smooth' : 'instant',
|
|
95
97
|
block: 'start',
|
|
96
98
|
inline: 'start'
|
|
97
99
|
});
|
|
@@ -102,7 +104,7 @@
|
|
|
102
104
|
return (mode || currentViewMode) === 'single' ? 1 : 2;
|
|
103
105
|
}
|
|
104
106
|
|
|
105
|
-
// ── Source-mapping helpers
|
|
107
|
+
// ── Source-mapping helpers ──────────────────────────────────────
|
|
106
108
|
// Every block element carries data-source-line (markdown-it-source-map). These
|
|
107
109
|
// map rendered DOM <-> markdown source line and rendered DOM <-> page. The
|
|
108
110
|
// native fragmenter MOVES elements into strips, it does not clone them, so
|
|
@@ -360,7 +362,7 @@
|
|
|
360
362
|
// plate UNDER the page's own text (gutterpress-css.ts's depth ladder) —
|
|
361
363
|
// hit-tests beneath the covering paragraph boxes and the annotated
|
|
362
364
|
// `.page`/`.section` containers too, so document.elementFromPoint() can
|
|
363
|
-
// NEVER return it
|
|
365
|
+
// NEVER return it: a right-click would resolve the covering element
|
|
364
366
|
// instead, leaving the image's context menu unreachable at EVERY point.
|
|
365
367
|
// Probe the full hit stack for the first (= top-most in paint order, so
|
|
366
368
|
// the upper of two overlapping plates wins) image layered at negative z.
|
|
@@ -632,13 +634,11 @@
|
|
|
632
634
|
// swapped for that block's markdown source under
|
|
633
635
|
// `contenteditable="plaintext-only"`, so the caret sits in the real page, in
|
|
634
636
|
// the book's own typography, and Chromium's fragmenter re-flows the pages
|
|
635
|
-
// around it as the author types.
|
|
636
|
-
// positioned in host-SPA coordinates; `getRectsFor()`/`setEditMask()` existed
|
|
637
|
-
// ONLY to serve that panel and went with it (protocol v8).
|
|
637
|
+
// around it as the author types.
|
|
638
638
|
//
|
|
639
639
|
// Three properties of the native viewer are what make this work, each
|
|
640
|
-
//
|
|
641
|
-
//
|
|
640
|
+
// verified rather than assumed (plan §2) — none of them can be assumed of
|
|
641
|
+
// a paginator that pre-cuts the DOM:
|
|
642
642
|
// 1. A block spanning a page break is ONE element with several client
|
|
643
643
|
// rects, so it takes ONE contenteditable and the caret crosses the
|
|
644
644
|
// break natively (ArrowDown walks into the next page).
|
|
@@ -1064,7 +1064,7 @@
|
|
|
1064
1064
|
return api.notifyPageChange();
|
|
1065
1065
|
},
|
|
1066
1066
|
|
|
1067
|
-
// ──
|
|
1067
|
+
// ── Generic primitives ─────────────────────────────────────────
|
|
1068
1068
|
// Bumped whenever a command/event is added so a hot-updated SPA can
|
|
1069
1069
|
// feature-detect against an older bundled lib.
|
|
1070
1070
|
// v6 (WORK PACKAGE B item 2): getRectsFor()/setEditMask() dropped the
|
|
@@ -1360,7 +1360,7 @@
|
|
|
1360
1360
|
|
|
1361
1361
|
// Click-to-source: emit elementActivated when the user clicks a source-mapped
|
|
1362
1362
|
// block. Never preventDefault (links/selection keep working); the host decides
|
|
1363
|
-
// whether to act.
|
|
1363
|
+
// whether to act.
|
|
1364
1364
|
if (typeof document.addEventListener === 'function') {
|
|
1365
1365
|
document.addEventListener('click', function (e) {
|
|
1366
1366
|
var el = e.target && e.target.closest ? e.target.closest('[data-source-line]') : null;
|
|
@@ -1472,7 +1472,7 @@
|
|
|
1472
1472
|
currentPage = page;
|
|
1473
1473
|
if (!silent) api.notifyPageChange();
|
|
1474
1474
|
}
|
|
1475
|
-
// Emit finer-grained source position for editor sync
|
|
1475
|
+
// Emit finer-grained source position for editor sync.
|
|
1476
1476
|
var pos = visibleSourcePosition();
|
|
1477
1477
|
var sl = pos ? pos.line : null;
|
|
1478
1478
|
var chapter = pos ? chapterOf(pos.el) : null;
|
|
@@ -1505,6 +1505,67 @@
|
|
|
1505
1505
|
});
|
|
1506
1506
|
window.addEventListener('resize', scheduleViewportChanged);
|
|
1507
1507
|
|
|
1508
|
+
// Wheel / trackpad page flip (#301). Viewer tooling, not pagination: it
|
|
1509
|
+
// only chooses which already-laid-out page to show. It lives here, in the
|
|
1510
|
+
// book document, because wheel events over a cross-origin iframe never
|
|
1511
|
+
// reach the host page.
|
|
1512
|
+
//
|
|
1513
|
+
// One flick turns one step — the same 1 page (single view) or 2 pages
|
|
1514
|
+
// (spread) the arrow keys move. A gesture is every wheel event until the
|
|
1515
|
+
// wheel has been quiet for WHEEL_GESTURE_IDLE_MS, so a fast mouse spin or a
|
|
1516
|
+
// trackpad's inertia tail turns exactly one step.
|
|
1517
|
+
//
|
|
1518
|
+
// A page taller than the viewport (fit-width on a short window, high zoom)
|
|
1519
|
+
// is READ first: while there is more of it in the wheel's direction, the
|
|
1520
|
+
// wheel scrolls normally, and only a gesture that starts at its edge turns
|
|
1521
|
+
// the page. The choice is made once per gesture, so the momentum of reading
|
|
1522
|
+
// down to a page's end never turns the page by itself. Pinch / Ctrl+wheel
|
|
1523
|
+
// (zoom), sideways swipes and in-place editing are left alone.
|
|
1524
|
+
var WHEEL_FLIP_PX = 50;
|
|
1525
|
+
var WHEEL_GESTURE_IDLE_MS = 220;
|
|
1526
|
+
var wheelGesture = null; // null | 'scroll' | 'flip'
|
|
1527
|
+
var wheelAccum = 0;
|
|
1528
|
+
var wheelTurned = false;
|
|
1529
|
+
var wheelIdleTimer = null;
|
|
1530
|
+
function wheelDeltaPx(e) {
|
|
1531
|
+
if (e.deltaMode === 1) return e.deltaY * 16; // lines
|
|
1532
|
+
if (e.deltaMode === 2) return e.deltaY * window.innerHeight; // pages
|
|
1533
|
+
return e.deltaY;
|
|
1534
|
+
}
|
|
1535
|
+
// More of the current page lies beyond the viewport edge in direction `dir`.
|
|
1536
|
+
function pageContinuesPastViewport(dir) {
|
|
1537
|
+
if (pages.length === 0) refreshPages();
|
|
1538
|
+
var sheet = pages[clampPage(currentPage) - 1];
|
|
1539
|
+
if (!sheet) return false;
|
|
1540
|
+
var r = sheet.getBoundingClientRect();
|
|
1541
|
+
return dir > 0 ? r.bottom > window.innerHeight + 1 : r.top < -1;
|
|
1542
|
+
}
|
|
1543
|
+
window.addEventListener('wheel', function (e) {
|
|
1544
|
+
if (e.ctrlKey || edit || e.deltaY === 0 || Math.abs(e.deltaX) > Math.abs(e.deltaY)) return;
|
|
1545
|
+
if (wheelIdleTimer) clearTimeout(wheelIdleTimer);
|
|
1546
|
+
wheelIdleTimer = setTimeout(function () {
|
|
1547
|
+
wheelIdleTimer = null;
|
|
1548
|
+
wheelGesture = null;
|
|
1549
|
+
wheelAccum = 0;
|
|
1550
|
+
wheelTurned = false;
|
|
1551
|
+
}, WHEEL_GESTURE_IDLE_MS);
|
|
1552
|
+
if (wheelGesture === null) {
|
|
1553
|
+
wheelGesture = pageContinuesPastViewport(e.deltaY > 0 ? 1 : -1) ? 'scroll' : 'flip';
|
|
1554
|
+
}
|
|
1555
|
+
if (wheelGesture === 'scroll') return;
|
|
1556
|
+
e.preventDefault();
|
|
1557
|
+
if (wheelTurned) return;
|
|
1558
|
+
wheelAccum += wheelDeltaPx(e);
|
|
1559
|
+
if (Math.abs(wheelAccum) < WHEEL_FLIP_PX) return;
|
|
1560
|
+
wheelTurned = true;
|
|
1561
|
+
refreshPages();
|
|
1562
|
+
var target = clampPage(currentPage + (wheelAccum > 0 ? 1 : -1) * pageStep());
|
|
1563
|
+
if (target === currentPage) return;
|
|
1564
|
+
currentPage = target;
|
|
1565
|
+
scrollToCurrentPage(true);
|
|
1566
|
+
api.notifyPageChange();
|
|
1567
|
+
}, { passive: false });
|
|
1568
|
+
|
|
1508
1569
|
// Reset to page 1, scroll to top, and announce completion once the native
|
|
1509
1570
|
// viewer's pagination finishes.
|
|
1510
1571
|
function onRenderingComplete() {
|
|
@@ -288,27 +288,16 @@
|
|
|
288
288
|
armPendingSwap();
|
|
289
289
|
}
|
|
290
290
|
|
|
291
|
-
//
|
|
292
|
-
//
|
|
293
|
-
//
|
|
294
|
-
//
|
|
295
|
-
// visible, 5 samples, 34pp field guide) the plain full reload (`swap`,
|
|
296
|
-
// below) is 509ms avg vs the incremental splice's 998ms avg. The server
|
|
297
|
-
// now sends ONE update kind, `full-reload`, and every one goes straight to
|
|
298
|
-
// `swap()`; the `/__chapter` route and `content-update` message that fed
|
|
299
|
-
// the splice were deleted with it.
|
|
291
|
+
// The server sends ONE update kind, `full-reload`, and every one goes
|
|
292
|
+
// straight to `swap()` (below). An incremental chapter splice was measured
|
|
293
|
+
// SLOWER, not unsound: end-to-end (file write -> change visible, 5 samples,
|
|
294
|
+
// 34pp field guide) the full reload is 509ms avg vs the splice's 998ms avg.
|
|
300
295
|
//
|
|
301
|
-
//
|
|
302
|
-
//
|
|
303
|
-
//
|
|
304
|
-
// introduces. That is false against the current `fragment.ts`, whose
|
|
305
|
-
// `relayout()` unwraps the strips and re-runs `buildStrips()` from
|
|
306
|
-
// scratch before re-measuring, precisely so a mutation that adds or
|
|
307
|
-
// removes a page-context run is seen. Do not cite the old objection as a
|
|
308
|
-
// reason a DOM mutation cannot be re-paginated — it can, and the inline
|
|
296
|
+
// A DOM mutation CAN be re-paginated: `refresh()` -> `relayout()` unwraps
|
|
297
|
+
// the strips and re-runs `buildStrips()` from scratch before re-measuring,
|
|
298
|
+
// so a mutation that adds or removes a page-context run is seen. The inline
|
|
309
299
|
// editing work depends on it (docs/inline-editing-plan.md, ADR 0009
|
|
310
|
-
// decision 4
|
|
311
|
-
// own for the full-document reload path.
|
|
300
|
+
// decision 4).
|
|
312
301
|
|
|
313
302
|
function markActiveReady() {
|
|
314
303
|
onReady(active, function () {
|
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
runBuild,
|
|
7
7
|
splitOutPath,
|
|
8
8
|
startPreviewServer
|
|
9
|
-
} from "./cli-
|
|
9
|
+
} from "./cli-d2he8zph.js";
|
|
10
10
|
import {
|
|
11
11
|
log
|
|
12
|
-
} from "./cli-
|
|
12
|
+
} from "./cli-1kdtzgxm.js";
|
|
13
13
|
import {
|
|
14
14
|
UsageError,
|
|
15
15
|
parseFormat,
|
|
@@ -17,8 +17,8 @@ import {
|
|
|
17
17
|
rejectExtraPositionals,
|
|
18
18
|
rejectUnknownFlags,
|
|
19
19
|
resolvePort
|
|
20
|
-
} from "./cli-
|
|
21
|
-
import"./cli-
|
|
20
|
+
} from "./cli-ny50k8md.js";
|
|
21
|
+
import"./cli-tjhn2mdn.js";
|
|
22
22
|
import {
|
|
23
23
|
BuildError
|
|
24
24
|
} from "./cli-46ycxe6r.js";
|
|
@@ -11,17 +11,17 @@ import {
|
|
|
11
11
|
publishProviderFor,
|
|
12
12
|
resolvePublishFormat,
|
|
13
13
|
runPublish
|
|
14
|
-
} from "./cli-
|
|
14
|
+
} from "./cli-d2he8zph.js";
|
|
15
15
|
import {
|
|
16
16
|
FileTokenStore,
|
|
17
17
|
log
|
|
18
|
-
} from "./cli-
|
|
18
|
+
} from "./cli-1kdtzgxm.js";
|
|
19
19
|
import {
|
|
20
20
|
UsageError,
|
|
21
21
|
rejectExtraPositionals,
|
|
22
22
|
rejectUnknownFlags
|
|
23
|
-
} from "./cli-
|
|
24
|
-
import"./cli-
|
|
23
|
+
} from "./cli-ny50k8md.js";
|
|
24
|
+
import"./cli-tjhn2mdn.js";
|
|
25
25
|
import {
|
|
26
26
|
EXIT_CODES
|
|
27
27
|
} from "./cli-46ycxe6r.js";
|
package/dist/render.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* gutterpress/render — the PURE, node-free render core.
|
|
3
3
|
*
|
|
4
|
-
* §1/§8
|
|
4
|
+
* §1/§8: this entry deliberately exposes ONLY the browser-safe
|
|
5
5
|
* markdown→HTML→book.html pieces. It transitively imports markdown-it + its
|
|
6
6
|
* plugins, Gutterpress's inlined marker parser (`markers.js`), and pure helpers
|
|
7
|
-
* — and NOTHING from `node:*`/`fs`/`path`/`url`.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* — and NOTHING from `node:*`/`fs`/`path`/`url`. It has no browser consumer
|
|
8
|
+
* today; it is kept node-free (scripts/check-render-pure.mjs) because any
|
|
9
|
+
* future browser build of the app needs to render a book client-side, and that
|
|
10
|
+
* discipline is far harder to restore than to keep.
|
|
11
11
|
*
|
|
12
12
|
* The CLI build path keeps using `renderChapters` / `renderChaptersToFile` from
|
|
13
13
|
* `./lib/markdown/index.ts` (the node wrapper around this same core).
|
package/dist/render.js
CHANGED
|
@@ -894,8 +894,8 @@ var GUTTERPRESS_CSS = `
|
|
|
894
894
|
|
|
895
895
|
/* the per-shape decisions the paragraph above deliberately leaves to the
|
|
896
896
|
author, named instead of left as raw CSS every book was reinventing
|
|
897
|
-
(
|
|
898
|
-
|
|
897
|
+
(CLAUDE.md §0: "behavior broadly useful to non-technical authors belongs
|
|
898
|
+
in core").
|
|
899
899
|
Permanent vocabulary, standard properties verbatim — same rationale as
|
|
900
900
|
the column/grid runs above. One name each, no aliases:
|
|
901
901
|
.gp-columns-all column-span: all a heading or block that
|
|
@@ -206,11 +206,11 @@ export interface ResolvedExtensionConfig {
|
|
|
206
206
|
}
|
|
207
207
|
/**
|
|
208
208
|
* Fully-resolved config. Every field is a concrete default with one
|
|
209
|
-
* deliberate exception: `styles
|
|
209
|
+
* deliberate exception: `styles`. There is no preset
|
|
210
210
|
* default for it — `undefined` means "the manifest didn't set one", and
|
|
211
211
|
* `resolveActiveStyles` (style-resolver.ts) is the single source of truth for
|
|
212
212
|
* what that resolves to (styles/book.css, else the first discovered `.css`,
|
|
213
|
-
* else `[]`). Baking a preset default in here
|
|
213
|
+
* else `[]`). Baking a preset default in here would defeat that fallback chain.
|
|
214
214
|
*/
|
|
215
215
|
export interface ResolvedConfig {
|
|
216
216
|
title: string;
|
package/dist/utils/logger.d.ts
CHANGED
|
@@ -10,8 +10,7 @@
|
|
|
10
10
|
* - The `log` facade object (`log.info`/`log.warn`/`log.error`/`log.success`)
|
|
11
11
|
* — clean, prefix-styled command output used by the CLI commands and
|
|
12
12
|
* re-exported from `index.ts` for the desktop. Always emitted (it carries
|
|
13
|
-
* user-facing command results, not diagnostic chatter)
|
|
14
|
-
* historical `lib/logger` behavior verbatim.
|
|
13
|
+
* user-facing command results, not diagnostic chatter).
|
|
15
14
|
*/
|
|
16
15
|
export type LogLevel = 'DEBUG' | 'INFO' | 'WARN' | 'ERROR';
|
|
17
16
|
/**
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
executeAndReport
|
|
3
|
-
} from "./cli-
|
|
3
|
+
} from "./cli-d2he8zph.js";
|
|
4
4
|
import {
|
|
5
5
|
log
|
|
6
|
-
} from "./cli-
|
|
6
|
+
} from "./cli-1kdtzgxm.js";
|
|
7
7
|
import {
|
|
8
8
|
UsageError,
|
|
9
9
|
rejectExtraPositionals,
|
|
10
10
|
rejectUnknownFlags
|
|
11
|
-
} from "./cli-
|
|
12
|
-
import"./cli-
|
|
11
|
+
} from "./cli-ny50k8md.js";
|
|
12
|
+
import"./cli-tjhn2mdn.js";
|
|
13
13
|
import {
|
|
14
14
|
EXIT_CODES
|
|
15
15
|
} from "./cli-46ycxe6r.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gutterpress",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.11-alpha.2",
|
|
4
4
|
"description": "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
|
|
5
5
|
"author": "itlackey",
|
|
6
6
|
"license": "MPL-2.0",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"glob": "^13.0.0",
|
|
68
68
|
"htmlhint": "^1.9.2",
|
|
69
69
|
"isomorphic-git": "^1.38.4",
|
|
70
|
-
"markdown-it": "^14.
|
|
70
|
+
"markdown-it": "^14.3.2",
|
|
71
71
|
"markdown-it-abbr": "^2.0.0",
|
|
72
72
|
"markdown-it-attrs": "^4.3.0",
|
|
73
73
|
"markdown-it-deflist": "^3.0.1",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"postcss": "^8.5.18",
|
|
82
82
|
"resolve.exports": "2.0.3",
|
|
83
83
|
"semver": "7.8.0",
|
|
84
|
-
"tar": "7.5.
|
|
84
|
+
"tar": "7.5.22",
|
|
85
85
|
"unpdf": "^1.6.2",
|
|
86
86
|
"ws": "^8.21.0",
|
|
87
87
|
"yaml": "^2.8.2"
|