@open-press/cli 1.0.0 → 1.1.1
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 +11 -12
- package/dist/cli.js +298 -79
- package/package.json +9 -7
- package/template/core/AGENTS.md +0 -130
- package/template/core/CHANGELOG.md +0 -218
- package/template/core/README.md +0 -43
- package/template/core/engine/cli.mjs +0 -96
- package/template/core/engine/commands/_shared.mjs +0 -199
- package/template/core/engine/commands/deploy.mjs +0 -31
- package/template/core/engine/commands/dev.mjs +0 -49
- package/template/core/engine/commands/doctor.mjs +0 -229
- package/template/core/engine/commands/export.mjs +0 -8
- package/template/core/engine/commands/image.mjs +0 -29
- package/template/core/engine/commands/inspect.mjs +0 -35
- package/template/core/engine/commands/pdf.mjs +0 -26
- package/template/core/engine/commands/preview.mjs +0 -26
- package/template/core/engine/commands/render.mjs +0 -17
- package/template/core/engine/commands/replace.mjs +0 -41
- package/template/core/engine/commands/search.mjs +0 -33
- package/template/core/engine/commands/skills-sync.mjs +0 -71
- package/template/core/engine/commands/typecheck.mjs +0 -67
- package/template/core/engine/commands/upgrade.mjs +0 -159
- package/template/core/engine/commands/validate.mjs +0 -17
- package/template/core/engine/document-export.mjs +0 -15
- package/template/core/engine/output/chrome-pdf.d.mts +0 -34
- package/template/core/engine/output/chrome-pdf.mjs +0 -450
- package/template/core/engine/output/deploy-sync.mjs +0 -15
- package/template/core/engine/output/fonts.mjs +0 -62
- package/template/core/engine/output/katex-assets.mjs +0 -45
- package/template/core/engine/output/page-block.mjs +0 -30
- package/template/core/engine/output/pdf-media.mjs +0 -45
- package/template/core/engine/output/public-assets.mjs +0 -19
- package/template/core/engine/output/static-server.mjs +0 -571
- package/template/core/engine/react/caption-numbering.mjs +0 -73
- package/template/core/engine/react/comment-endpoint.d.mts +0 -11
- package/template/core/engine/react/comment-endpoint.mjs +0 -102
- package/template/core/engine/react/comment-marker.mjs +0 -374
- package/template/core/engine/react/document-entry.mjs +0 -331
- package/template/core/engine/react/document-export.mjs +0 -512
- package/template/core/engine/react/http-json.mjs +0 -24
- package/template/core/engine/react/mdx-compile.mjs +0 -629
- package/template/core/engine/react/measurement-css.mjs +0 -157
- package/template/core/engine/react/object-entities.mjs +0 -204
- package/template/core/engine/react/pagination/allocator.mjs +0 -167
- package/template/core/engine/react/pagination/regions.mjs +0 -81
- package/template/core/engine/react/pagination-constants.mjs +0 -3
- package/template/core/engine/react/pagination.mjs +0 -9
- package/template/core/engine/react/pipeline/allocate.mjs +0 -217
- package/template/core/engine/react/pipeline/final-render.mjs +0 -94
- package/template/core/engine/react/pipeline/frame-measurement.mjs +0 -306
- package/template/core/engine/react/pipeline/press-tree.mjs +0 -135
- package/template/core/engine/react/press-tree-inspection.mjs +0 -172
- package/template/core/engine/react/project-asset-endpoint.d.mts +0 -10
- package/template/core/engine/react/project-asset-endpoint.mjs +0 -361
- package/template/core/engine/react/section-css.mjs +0 -56
- package/template/core/engine/react/source-edit-endpoint.d.mts +0 -10
- package/template/core/engine/react/source-edit-endpoint.mjs +0 -75
- package/template/core/engine/react/sources/heading-numbering.mjs +0 -132
- package/template/core/engine/react/sources/mdx-resolver.mjs +0 -439
- package/template/core/engine/react/style-discovery.mjs +0 -160
- package/template/core/engine/runtime/config.d.mts +0 -48
- package/template/core/engine/runtime/config.mjs +0 -172
- package/template/core/engine/runtime/file-utils.mjs +0 -114
- package/template/core/engine/runtime/file-walk.mjs +0 -22
- package/template/core/engine/runtime/inspection.mjs +0 -328
- package/template/core/engine/runtime/issue-report.mjs +0 -44
- package/template/core/engine/runtime/page-geometry.mjs +0 -131
- package/template/core/engine/runtime/path-utils.mjs +0 -20
- package/template/core/engine/runtime/source-text-tools.d.mts +0 -102
- package/template/core/engine/runtime/source-text-tools.mjs +0 -832
- package/template/core/engine/runtime/source-workspace.mjs +0 -168
- package/template/core/engine/runtime/validation.mjs +0 -183
- package/template/core/index.html +0 -13
- package/template/core/openpress.config.mjs +0 -8
- package/template/core/package.json +0 -89
- package/template/core/src/main.tsx +0 -16
- package/template/core/src/openpress/app/OpenPressApp.tsx +0 -296
- package/template/core/src/openpress/app/OpenPressRuntime.tsx +0 -102
- package/template/core/src/openpress/app/WorkspaceGalleryPage.tsx +0 -219
- package/template/core/src/openpress/app/index.ts +0 -2
- package/template/core/src/openpress/core/Frame.tsx +0 -91
- package/template/core/src/openpress/core/FrameContext.tsx +0 -26
- package/template/core/src/openpress/core/MdxArea.tsx +0 -34
- package/template/core/src/openpress/core/Press.tsx +0 -55
- package/template/core/src/openpress/core/Workspace.tsx +0 -36
- package/template/core/src/openpress/core/cn.ts +0 -4
- package/template/core/src/openpress/core/index.tsx +0 -47
- package/template/core/src/openpress/core/primitives.tsx +0 -91
- package/template/core/src/openpress/core/types.ts +0 -236
- package/template/core/src/openpress/core/useSource.ts +0 -28
- package/template/core/src/openpress/document-model/anchorMapModel.ts +0 -27
- package/template/core/src/openpress/document-model/documentIndexes.ts +0 -329
- package/template/core/src/openpress/document-model/documentTypes.ts +0 -147
- package/template/core/src/openpress/document-model/index.ts +0 -7
- package/template/core/src/openpress/document-model/objectEntityModel.ts +0 -55
- package/template/core/src/openpress/document-model/projectIdentityModel.ts +0 -15
- package/template/core/src/openpress/document-model/reactDocumentMetadataModel.ts +0 -27
- package/template/core/src/openpress/document-model/workspaceManifestModel.ts +0 -57
- package/template/core/src/openpress/manuscript/index.tsx +0 -238
- package/template/core/src/openpress/mdx/index.ts +0 -96
- package/template/core/src/openpress/numbering/index.ts +0 -294
- package/template/core/src/openpress/reader/PageThumbnailsPanel.tsx +0 -168
- package/template/core/src/openpress/reader/PublicReaderPage.tsx +0 -267
- package/template/core/src/openpress/reader/ReaderNavigationPanel.tsx +0 -123
- package/template/core/src/openpress/reader/index.ts +0 -11
- package/template/core/src/openpress/reader/pageViewportScaleModel.ts +0 -73
- package/template/core/src/openpress/reader/readerPageRegistry.ts +0 -41
- package/template/core/src/openpress/reader/readerPageRoute.ts +0 -21
- package/template/core/src/openpress/reader/readerScroll.ts +0 -92
- package/template/core/src/openpress/reader/readerStateModel.ts +0 -15
- package/template/core/src/openpress/reader/readerTypes.ts +0 -4
- package/template/core/src/openpress/reader/usePageViewportScale.ts +0 -119
- package/template/core/src/openpress/reader/usePanelState.ts +0 -56
- package/template/core/src/openpress/reader/useReaderHashSync.ts +0 -61
- package/template/core/src/openpress/reader/useReaderKeyboardNav.ts +0 -48
- package/template/core/src/openpress/reader/useReaderRuntime.ts +0 -146
- package/template/core/src/openpress/reader/useReaderScrollAnchor.ts +0 -64
- package/template/core/src/openpress/shared/Panel.tsx +0 -77
- package/template/core/src/openpress/shared/frameScheduler.ts +0 -32
- package/template/core/src/openpress/shared/index.ts +0 -4
- package/template/core/src/openpress/shared/numberUtils.ts +0 -3
- package/template/core/src/openpress/shared/runtimeMode.ts +0 -11
- package/template/core/src/openpress/workbench/Workbench.tsx +0 -506
- package/template/core/src/openpress/workbench/actions/DeploymentControl.tsx +0 -157
- package/template/core/src/openpress/workbench/actions/ExportImageControl.tsx +0 -96
- package/template/core/src/openpress/workbench/actions/PageZoomControl.tsx +0 -182
- package/template/core/src/openpress/workbench/actions/SearchControl.tsx +0 -345
- package/template/core/src/openpress/workbench/actions/deploymentStatusModel.ts +0 -112
- package/template/core/src/openpress/workbench/actions/index.ts +0 -6
- package/template/core/src/openpress/workbench/actions/useDeploymentWorkbench.ts +0 -136
- package/template/core/src/openpress/workbench/dialog/WorkbenchDialog.tsx +0 -72
- package/template/core/src/openpress/workbench/dialog/index.ts +0 -1
- package/template/core/src/openpress/workbench/document/components/DocumentPanel.tsx +0 -127
- package/template/core/src/openpress/workbench/document/components/InlineSourceEditorLayer.tsx +0 -207
- package/template/core/src/openpress/workbench/document/components/ReaderStage.tsx +0 -9
- package/template/core/src/openpress/workbench/document/hooks/useDocumentWorkbenchModel.ts +0 -34
- package/template/core/src/openpress/workbench/document/hooks/useInlineDocumentEditor.ts +0 -525
- package/template/core/src/openpress/workbench/document/index.ts +0 -10
- package/template/core/src/openpress/workbench/index.ts +0 -2
- package/template/core/src/openpress/workbench/inspector/InlineInspectorLayer.tsx +0 -459
- package/template/core/src/openpress/workbench/inspector/index.ts +0 -5
- package/template/core/src/openpress/workbench/inspector/inlineCommentModel.ts +0 -125
- package/template/core/src/openpress/workbench/inspector/inspectorGeometryModel.ts +0 -160
- package/template/core/src/openpress/workbench/inspector/inspectorModel.ts +0 -408
- package/template/core/src/openpress/workbench/inspector/useInspectorComments.ts +0 -254
- package/template/core/src/openpress/workbench/mentions/MentionSuggestionList.tsx +0 -41
- package/template/core/src/openpress/workbench/mentions/index.ts +0 -2
- package/template/core/src/openpress/workbench/mentions/useComposerMentions.ts +0 -185
- package/template/core/src/openpress/workbench/panels/Panel.tsx +0 -1
- package/template/core/src/openpress/workbench/panels/PendingCommentsPanel.tsx +0 -80
- package/template/core/src/openpress/workbench/panels/WorkbenchControlPanel.tsx +0 -29
- package/template/core/src/openpress/workbench/panels/index.ts +0 -3
- package/template/core/src/openpress/workbench/project/ProjectEntryPanel.tsx +0 -525
- package/template/core/src/openpress/workbench/project/ProjectPreviewDialog.tsx +0 -35
- package/template/core/src/openpress/workbench/project/index.ts +0 -2
- package/template/core/src/openpress/workbench/project/projectPreviewTypes.ts +0 -11
- package/template/core/src/openpress/workbench/project/projectSourceModel.ts +0 -24
- package/template/core/src/openpress/workbench/shell/WorkbenchShell.tsx +0 -167
- package/template/core/src/openpress/workbench/shell/index.ts +0 -1
- package/template/core/src/openpress/workbench/workbenchFormatters.ts +0 -120
- package/template/core/src/openpress/workbench/workbenchTypes.ts +0 -35
- package/template/core/src/styles/openpress/app-shell.css +0 -251
- package/template/core/src/styles/openpress/media-workspace.css +0 -230
- package/template/core/src/styles/openpress/print-route.css +0 -184
- package/template/core/src/styles/openpress/project-preview-panel.css +0 -924
- package/template/core/src/styles/openpress/public-viewer.css +0 -688
- package/template/core/src/styles/openpress/reader-runtime.css +0 -989
- package/template/core/src/styles/openpress/responsive.css +0 -245
- package/template/core/src/styles/openpress/workbench-panels.css +0 -707
- package/template/core/src/styles/openpress/workbench.css +0 -1255
- package/template/core/src/styles/openpress/workspace-gallery.css +0 -300
- package/template/core/src/styles/openpress.css +0 -15
- package/template/core/src/vite-env.d.ts +0 -9
- package/template/core/tsconfig.json +0 -40
- package/template/core/vite.config.ts +0 -584
|
@@ -1,329 +0,0 @@
|
|
|
1
|
-
import type { BlockSource } from "./documentTypes";
|
|
2
|
-
|
|
3
|
-
export type MediaAssetKind = "image" | "svg";
|
|
4
|
-
|
|
5
|
-
export interface IndexedHtmlPage {
|
|
6
|
-
id: string;
|
|
7
|
-
html: string;
|
|
8
|
-
title: string;
|
|
9
|
-
pageNumber: number;
|
|
10
|
-
anchors?: string[];
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface MediaAssetItem {
|
|
14
|
-
id: string;
|
|
15
|
-
kind: MediaAssetKind;
|
|
16
|
-
fileName: string;
|
|
17
|
-
src: string;
|
|
18
|
-
pageIndex: number;
|
|
19
|
-
sourceTitle: string;
|
|
20
|
-
usageCount: number;
|
|
21
|
-
references: Array<{
|
|
22
|
-
pageIndex: number;
|
|
23
|
-
sourceTitle: string;
|
|
24
|
-
}>;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface ContentSourceItem {
|
|
28
|
-
id: string;
|
|
29
|
-
file: string;
|
|
30
|
-
path: string;
|
|
31
|
-
kind?: string;
|
|
32
|
-
chapter?: number;
|
|
33
|
-
slug?: string;
|
|
34
|
-
title: string;
|
|
35
|
-
pageIndexes: number[];
|
|
36
|
-
sectionCount: number;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface BookmarkItem {
|
|
40
|
-
id: string;
|
|
41
|
-
title: string;
|
|
42
|
-
label?: string;
|
|
43
|
-
pageIndex: number;
|
|
44
|
-
endPageIndex: number;
|
|
45
|
-
subs: BookmarkSubItem[];
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export interface BookmarkSubItem {
|
|
49
|
-
id: string;
|
|
50
|
-
title: string;
|
|
51
|
-
label?: string;
|
|
52
|
-
pageIndex: number;
|
|
53
|
-
endPageIndex: number;
|
|
54
|
-
subs: BookmarkTopicItem[];
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface BookmarkTopicItem {
|
|
58
|
-
id: string;
|
|
59
|
-
title: string;
|
|
60
|
-
label?: string;
|
|
61
|
-
pageIndex: number;
|
|
62
|
-
endPageIndex: number;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function collectBookmarkIndex(pages: IndexedHtmlPage[]): BookmarkItem[] {
|
|
66
|
-
const totalPages = pages.length;
|
|
67
|
-
const chapters: BookmarkItem[] = [];
|
|
68
|
-
let currentChapter: BookmarkItem | undefined;
|
|
69
|
-
let currentSub: BookmarkSubItem | undefined;
|
|
70
|
-
let pendingChapterOpener: { pageIndex: number } | undefined;
|
|
71
|
-
let tocAdded = false;
|
|
72
|
-
|
|
73
|
-
pages.forEach((page) => {
|
|
74
|
-
const html = parseHtmlPage(page.html);
|
|
75
|
-
if (!html) return;
|
|
76
|
-
const readerPage = html.querySelector<HTMLElement>(".reader-page");
|
|
77
|
-
if (!readerPage) return;
|
|
78
|
-
const pageIndex = page.pageNumber - 1;
|
|
79
|
-
|
|
80
|
-
if (pageKindOf(readerPage) === "toc") {
|
|
81
|
-
if (!tocAdded && readerPage.dataset.tocContinuation !== "true") {
|
|
82
|
-
tocAdded = true;
|
|
83
|
-
chapters.push({
|
|
84
|
-
id: `toc-bookmark-${page.pageNumber}`,
|
|
85
|
-
title: readerPage.dataset.pageTitle || readerPage.querySelector<HTMLElement>(".toc-heading, h2")?.textContent?.trim() || "目錄",
|
|
86
|
-
label: "00",
|
|
87
|
-
pageIndex,
|
|
88
|
-
endPageIndex: totalPages - 1,
|
|
89
|
-
subs: [],
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (pageKindOf(readerPage) === "chapter-opener") {
|
|
96
|
-
pendingChapterOpener = { pageIndex };
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (!isContentPage(readerPage)) return;
|
|
101
|
-
|
|
102
|
-
let pageStartedChapter = false;
|
|
103
|
-
html.querySelectorAll("h2, h3, h4").forEach((heading, headingIndex) => {
|
|
104
|
-
const id = bookmarkItemId(page, heading, headingIndex);
|
|
105
|
-
if (heading.tagName === "H2") {
|
|
106
|
-
const opener = pendingChapterOpener;
|
|
107
|
-
pendingChapterOpener = undefined;
|
|
108
|
-
pageStartedChapter = true;
|
|
109
|
-
currentChapter = {
|
|
110
|
-
id,
|
|
111
|
-
title: normalizeChapterTitle(heading.textContent ?? ""),
|
|
112
|
-
label: heading instanceof HTMLElement ? heading.dataset.chapter : undefined,
|
|
113
|
-
pageIndex: opener?.pageIndex ?? pageIndex,
|
|
114
|
-
endPageIndex: totalPages - 1,
|
|
115
|
-
subs: [],
|
|
116
|
-
};
|
|
117
|
-
chapters.push(currentChapter);
|
|
118
|
-
currentSub = undefined;
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (heading.tagName === "H3" && currentChapter) {
|
|
123
|
-
currentSub = {
|
|
124
|
-
id,
|
|
125
|
-
title: normalizeSectionTitle(heading.textContent ?? ""),
|
|
126
|
-
label: heading instanceof HTMLElement ? heading.dataset.section : undefined,
|
|
127
|
-
pageIndex,
|
|
128
|
-
endPageIndex: totalPages - 1,
|
|
129
|
-
subs: [],
|
|
130
|
-
};
|
|
131
|
-
currentChapter.subs.push(currentSub);
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (heading.tagName === "H4" && currentSub) {
|
|
136
|
-
currentSub.subs.push({
|
|
137
|
-
id,
|
|
138
|
-
title: normalizeTopicTitle(heading.textContent ?? ""),
|
|
139
|
-
label: heading instanceof HTMLElement ? heading.dataset.topic : undefined,
|
|
140
|
-
pageIndex,
|
|
141
|
-
endPageIndex: totalPages - 1,
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
if (!pageStartedChapter) pendingChapterOpener = undefined;
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
// Back-fill endPageIndex: each item ends where the next sibling starts (exclusive)
|
|
149
|
-
for (let i = 0; i < chapters.length; i++) {
|
|
150
|
-
const nextChapterStart = chapters[i + 1]?.pageIndex ?? totalPages;
|
|
151
|
-
chapters[i].endPageIndex = nextChapterStart - 1;
|
|
152
|
-
|
|
153
|
-
const subs = chapters[i].subs;
|
|
154
|
-
for (let j = 0; j < subs.length; j++) {
|
|
155
|
-
const nextSubStart = subs[j + 1]?.pageIndex ?? nextChapterStart;
|
|
156
|
-
subs[j].endPageIndex = Math.max(subs[j].pageIndex, nextSubStart - 1);
|
|
157
|
-
|
|
158
|
-
const topics = subs[j].subs;
|
|
159
|
-
for (let k = 0; k < topics.length; k++) {
|
|
160
|
-
const nextTopicStart = topics[k + 1]?.pageIndex ?? nextSubStart;
|
|
161
|
-
topics[k].endPageIndex = Math.max(topics[k].pageIndex, nextTopicStart - 1);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return chapters;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function pageKindOf(page: HTMLElement) {
|
|
170
|
-
return page.dataset.pageKind || "";
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function isContentPage(page: HTMLElement) {
|
|
174
|
-
return pageKindOf(page) === "content";
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function bookmarkItemId(page: IndexedHtmlPage, heading: Element, headingIndex: number) {
|
|
178
|
-
const anchor = heading.id || page.anchors?.[0] || page.id;
|
|
179
|
-
return `${anchor}-bookmark-${page.pageNumber}-${headingIndex + 1}`;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
export function collectContentSourceIndex(
|
|
183
|
-
pages: Array<IndexedHtmlPage & { source?: BlockSource }>,
|
|
184
|
-
): ContentSourceItem[] {
|
|
185
|
-
const items = new Map<string, ContentSourceItem>();
|
|
186
|
-
|
|
187
|
-
pages.forEach((page) => {
|
|
188
|
-
const source = page.source;
|
|
189
|
-
if (!source?.path) return;
|
|
190
|
-
const existing = items.get(source.path);
|
|
191
|
-
if (existing) {
|
|
192
|
-
existing.pageIndexes.push(page.pageNumber - 1);
|
|
193
|
-
existing.sectionCount += 1;
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
items.set(source.path, {
|
|
198
|
-
id: `content-${items.size + 1}`,
|
|
199
|
-
file: source.file,
|
|
200
|
-
path: source.path,
|
|
201
|
-
kind: source.kind,
|
|
202
|
-
chapter: source.chapter,
|
|
203
|
-
slug: source.slug,
|
|
204
|
-
title: page.title,
|
|
205
|
-
pageIndexes: [page.pageNumber - 1],
|
|
206
|
-
sectionCount: 1,
|
|
207
|
-
});
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
return Array.from(items.values()).sort((a, b) => a.path.localeCompare(b.path, "zh-Hant"));
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
export function collectMediaAssetIndex(pages: IndexedHtmlPage[]): MediaAssetItem[] {
|
|
214
|
-
const assets = createMediaInventory();
|
|
215
|
-
const imagePattern = /<(img|image)\b([^>]*)>/gi;
|
|
216
|
-
|
|
217
|
-
pages.forEach((page) => {
|
|
218
|
-
let match: RegExpExecArray | null;
|
|
219
|
-
imagePattern.lastIndex = 0;
|
|
220
|
-
while ((match = imagePattern.exec(page.html)) !== null) {
|
|
221
|
-
const src = normalizeMediaAssetSrc(readHtmlAttribute(match[2], "src") ?? readHtmlAttribute(match[2], "href"));
|
|
222
|
-
if (!src) continue;
|
|
223
|
-
const existing = assets.get(src);
|
|
224
|
-
if (existing) {
|
|
225
|
-
existing.usageCount += 1;
|
|
226
|
-
existing.pageIndex = existing.usageCount === 1 ? page.pageNumber - 1 : existing.pageIndex;
|
|
227
|
-
existing.sourceTitle = existing.usageCount === 1 ? page.title : existing.sourceTitle;
|
|
228
|
-
existing.references.push({
|
|
229
|
-
pageIndex: page.pageNumber - 1,
|
|
230
|
-
sourceTitle: page.title,
|
|
231
|
-
});
|
|
232
|
-
continue;
|
|
233
|
-
}
|
|
234
|
-
const fileName = safeDecodeURIComponent(src.split("/").pop() ?? src);
|
|
235
|
-
assets.set(src, {
|
|
236
|
-
id: `asset-${assets.size + 1}`,
|
|
237
|
-
kind: fileName.toLowerCase().endsWith(".svg") ? "svg" : "image",
|
|
238
|
-
fileName,
|
|
239
|
-
src,
|
|
240
|
-
pageIndex: page.pageNumber - 1,
|
|
241
|
-
sourceTitle: page.title,
|
|
242
|
-
usageCount: 1,
|
|
243
|
-
references: [{
|
|
244
|
-
pageIndex: page.pageNumber - 1,
|
|
245
|
-
sourceTitle: page.title,
|
|
246
|
-
}],
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
return Array.from(assets.values()).sort((a, b) => a.fileName.localeCompare(b.fileName, "zh-Hant"));
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
const workspaceMediaFiles = import.meta.glob<string>("@workspace/media/*", {
|
|
255
|
-
eager: true,
|
|
256
|
-
query: "?url",
|
|
257
|
-
import: "default",
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
function createMediaInventory() {
|
|
261
|
-
const assets = new Map<string, MediaAssetItem>();
|
|
262
|
-
|
|
263
|
-
Object.keys(workspaceMediaFiles).forEach((path) => {
|
|
264
|
-
const fileName = safeDecodeURIComponent(path.split("/").pop() ?? path);
|
|
265
|
-
if (!isMediaFileName(fileName)) return;
|
|
266
|
-
const src = `/openpress/media/${fileName}`;
|
|
267
|
-
assets.set(src, {
|
|
268
|
-
id: `asset-${assets.size + 1}`,
|
|
269
|
-
kind: fileName.toLowerCase().endsWith(".svg") ? "svg" : "image",
|
|
270
|
-
fileName,
|
|
271
|
-
src,
|
|
272
|
-
pageIndex: -1,
|
|
273
|
-
sourceTitle: "未引用",
|
|
274
|
-
usageCount: 0,
|
|
275
|
-
references: [],
|
|
276
|
-
});
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
return assets;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function isMediaFileName(fileName: string) {
|
|
283
|
-
return /\.(png|jpe?g|gif|svg|webp)$/i.test(fileName);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
function parseHtmlPage(html: string) {
|
|
287
|
-
if (typeof DOMParser === "undefined") return undefined;
|
|
288
|
-
return new DOMParser().parseFromString(html, "text/html");
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
function normalizeChapterTitle(value: string) {
|
|
292
|
-
return value
|
|
293
|
-
.trim()
|
|
294
|
-
.replace(/^[一二三四五六七八九十]+、\s*/, "");
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
function normalizeSectionTitle(value: string) {
|
|
298
|
-
return value
|
|
299
|
-
.trim()
|
|
300
|
-
.replace(/^[((][一二三四五六七八九十]+[))]、?\s*/, "")
|
|
301
|
-
.replace(/^\d+\.\d+\s+/, "");
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
function normalizeTopicTitle(value: string) {
|
|
305
|
-
return value
|
|
306
|
-
.trim()
|
|
307
|
-
.replace(/^\d+\.\d+\.\d+\s+/, "");
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
function readHtmlAttribute(attributes: string, name: string) {
|
|
311
|
-
const pattern = new RegExp(`\\b${name}=["']([^"']+)["']`, "i");
|
|
312
|
-
return attributes.match(pattern)?.[1];
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
function normalizeMediaAssetSrc(value?: string) {
|
|
316
|
-
if (!value) return undefined;
|
|
317
|
-
if (value.startsWith("/openpress/media/")) return value;
|
|
318
|
-
if (value.startsWith("media/")) return `/openpress/${value}`;
|
|
319
|
-
if (value.startsWith("./media/")) return `/openpress/${value.slice(2)}`;
|
|
320
|
-
return undefined;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
function safeDecodeURIComponent(value: string) {
|
|
324
|
-
try {
|
|
325
|
-
return decodeURIComponent(value);
|
|
326
|
-
} catch {
|
|
327
|
-
return value;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
export interface DeploymentInfo {
|
|
2
|
-
online: boolean;
|
|
3
|
-
deployedAt?: string;
|
|
4
|
-
pdf?: string;
|
|
5
|
-
publicUrl?: string;
|
|
6
|
-
dirty?: boolean;
|
|
7
|
-
configured?: boolean;
|
|
8
|
-
adapter?: string;
|
|
9
|
-
source?: string;
|
|
10
|
-
projectName?: string;
|
|
11
|
-
setupMessage?: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface ReaderDocument {
|
|
15
|
-
meta: DocumentMeta;
|
|
16
|
-
source?: DocumentSource;
|
|
17
|
-
theme?: Theme;
|
|
18
|
-
blocks: HtmlPageBlock[];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface DocumentSource {
|
|
22
|
-
type: string;
|
|
23
|
-
contentDir?: string;
|
|
24
|
-
editable?: boolean;
|
|
25
|
-
editMode?: string;
|
|
26
|
-
styles?: DocumentStyle[];
|
|
27
|
-
blockMap?: Record<string, SourceBlock>;
|
|
28
|
-
objectEntities?: Record<string, ObjectEntity>;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface DocumentStyle {
|
|
32
|
-
kind: string;
|
|
33
|
-
href?: string;
|
|
34
|
-
path?: string;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface SourceLocation {
|
|
38
|
-
line: number;
|
|
39
|
-
column: number;
|
|
40
|
-
endLine?: number;
|
|
41
|
-
endColumn?: number;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface SourceBlock {
|
|
45
|
-
id: string;
|
|
46
|
-
kind?: string;
|
|
47
|
-
name?: string;
|
|
48
|
-
chapterSlug?: string;
|
|
49
|
-
path: string;
|
|
50
|
-
pageIndex?: number;
|
|
51
|
-
pageNumber?: number;
|
|
52
|
-
source?: SourceLocation;
|
|
53
|
-
frameKey?: string;
|
|
54
|
-
chainId?: string;
|
|
55
|
-
sectionSlug?: string;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export interface DocumentMeta {
|
|
59
|
-
title: string;
|
|
60
|
-
subtitle?: string;
|
|
61
|
-
organization?: string;
|
|
62
|
-
version?: string;
|
|
63
|
-
footer?: string;
|
|
64
|
-
workspaceLabel?: string;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export interface Theme {
|
|
68
|
-
pagePreset?: string;
|
|
69
|
-
pageLabel?: string;
|
|
70
|
-
pageWidth?: string;
|
|
71
|
-
pageHeight?: string;
|
|
72
|
-
pageAspectRatio?: string;
|
|
73
|
-
pageHeightRatio?: string;
|
|
74
|
-
pagePadding?: string;
|
|
75
|
-
fontFamily?: string;
|
|
76
|
-
accentColor?: string;
|
|
77
|
-
textColor?: string;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export interface BlockSource {
|
|
81
|
-
file: string;
|
|
82
|
-
path: string;
|
|
83
|
-
kind?: string;
|
|
84
|
-
chapter?: number;
|
|
85
|
-
slug?: string;
|
|
86
|
-
sectionIndex?: number;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// The engine currently emits one block kind only: a fully-rendered HTML page.
|
|
90
|
-
// All historical structured-block variants (cover / section / paragraph /
|
|
91
|
-
// list / figure / table / callout) were aspirational and never instantiated;
|
|
92
|
-
// they were removed along with the unused client-side block model. If the
|
|
93
|
-
// engine ever emits structured blocks again, reintroduce a discriminated
|
|
94
|
-
// union here.
|
|
95
|
-
export interface HtmlPageBlock {
|
|
96
|
-
id: string;
|
|
97
|
-
kind: "htmlPage";
|
|
98
|
-
title: string;
|
|
99
|
-
pageNumber: number;
|
|
100
|
-
html: string;
|
|
101
|
-
anchors?: string[];
|
|
102
|
-
className?: string;
|
|
103
|
-
source?: BlockSource;
|
|
104
|
-
frameKey?: string;
|
|
105
|
-
role?: string | null;
|
|
106
|
-
chrome?: boolean;
|
|
107
|
-
blockIds?: string[];
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export type ObjectEntityKind =
|
|
111
|
-
| "page"
|
|
112
|
-
| "frame"
|
|
113
|
-
| "mdx-area"
|
|
114
|
-
| "mdx-block"
|
|
115
|
-
| "text"
|
|
116
|
-
| "component"
|
|
117
|
-
| "media";
|
|
118
|
-
|
|
119
|
-
export interface EditableSourceRef {
|
|
120
|
-
path: string;
|
|
121
|
-
file?: string;
|
|
122
|
-
kind?: string;
|
|
123
|
-
objectId?: string;
|
|
124
|
-
scope?: string;
|
|
125
|
-
component?: string;
|
|
126
|
-
source?: SourceLocation;
|
|
127
|
-
line?: number;
|
|
128
|
-
column?: number;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
export interface ObjectEntityRef {
|
|
132
|
-
id: string;
|
|
133
|
-
kind: ObjectEntityKind;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export interface ObjectEntity {
|
|
137
|
-
id: string;
|
|
138
|
-
kind: ObjectEntityKind;
|
|
139
|
-
label: string;
|
|
140
|
-
parentId?: string;
|
|
141
|
-
pageId?: string;
|
|
142
|
-
blockId?: string;
|
|
143
|
-
frameKey?: string;
|
|
144
|
-
chainId?: string;
|
|
145
|
-
source?: EditableSourceRef;
|
|
146
|
-
metadata?: Record<string, string | number | boolean | null>;
|
|
147
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export * from "./anchorMapModel";
|
|
2
|
-
export * from "./documentIndexes";
|
|
3
|
-
export * from "./documentTypes";
|
|
4
|
-
export * from "./objectEntityModel";
|
|
5
|
-
export * from "./projectIdentityModel";
|
|
6
|
-
export * from "./reactDocumentMetadataModel";
|
|
7
|
-
export * from "./workspaceManifestModel";
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import type { ObjectEntity, ObjectEntityKind, ReaderDocument, SourceBlock } from "./documentTypes";
|
|
2
|
-
|
|
3
|
-
export function createObjectEntityId(kind: ObjectEntityKind, ...parts: Array<string | number>) {
|
|
4
|
-
return [kind, ...parts.map((part) => encodeURIComponent(String(part)))].join(":");
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function createScopedObjectEntityId(kind: ObjectEntityKind, parentId: string | undefined, objectId: string) {
|
|
8
|
-
return parentId ? createObjectEntityId(kind, parentId, objectId) : createObjectEntityId(kind, objectId);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function createBlockObjectEntityId(blockId: string) {
|
|
12
|
-
return createObjectEntityId("mdx-block", blockId);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function createFrameObjectEntityId(frameKey: string) {
|
|
16
|
-
return createObjectEntityId("frame", frameKey);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function createPageObjectEntityId(frameKey: string) {
|
|
20
|
-
return createObjectEntityId("page", frameKey);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function createMdxAreaObjectEntityId(frameKey: string, chainId: string, indexInFrame: number) {
|
|
24
|
-
return createObjectEntityId("mdx-area", frameKey, chainId, indexInFrame);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function getObjectEntityMap(document: Pick<ReaderDocument, "source"> | null | undefined): Record<string, ObjectEntity> {
|
|
28
|
-
return document?.source?.objectEntities ?? {};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function getObjectEntity(document: Pick<ReaderDocument, "source"> | null | undefined, objectId: string): ObjectEntity | null {
|
|
32
|
-
return getObjectEntityMap(document)[objectId] ?? null;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function sourceBlockToObjectEntity(block: SourceBlock): ObjectEntity {
|
|
36
|
-
return {
|
|
37
|
-
id: createBlockObjectEntityId(block.id),
|
|
38
|
-
kind: "mdx-block",
|
|
39
|
-
label: block.name ? `${block.name} ${block.id}` : block.id,
|
|
40
|
-
blockId: block.id,
|
|
41
|
-
frameKey: block.frameKey,
|
|
42
|
-
chainId: block.chainId,
|
|
43
|
-
pageId: block.frameKey ? createPageObjectEntityId(block.frameKey) : undefined,
|
|
44
|
-
source: {
|
|
45
|
-
path: block.path,
|
|
46
|
-
source: block.source,
|
|
47
|
-
line: block.source?.line,
|
|
48
|
-
column: block.source?.column,
|
|
49
|
-
},
|
|
50
|
-
metadata: {
|
|
51
|
-
blockKind: block.kind ?? null,
|
|
52
|
-
sectionSlug: block.sectionSlug ?? block.chapterSlug ?? null,
|
|
53
|
-
},
|
|
54
|
-
};
|
|
55
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { DocumentMeta } from "./documentTypes";
|
|
2
|
-
|
|
3
|
-
export interface ProjectIdentity {
|
|
4
|
-
name: string;
|
|
5
|
-
subtitle: string;
|
|
6
|
-
label: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function getProjectIdentity(meta: DocumentMeta): ProjectIdentity {
|
|
10
|
-
return {
|
|
11
|
-
name: meta.organization ?? "",
|
|
12
|
-
subtitle: meta.subtitle ?? "",
|
|
13
|
-
label: meta.workspaceLabel ?? "",
|
|
14
|
-
};
|
|
15
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ReaderDocument,
|
|
3
|
-
SourceBlock,
|
|
4
|
-
} from "./documentTypes";
|
|
5
|
-
|
|
6
|
-
export const PRESS_TREE_MDX_SOURCE_TYPE = "openpress-press-tree-mdx";
|
|
7
|
-
|
|
8
|
-
export function isReactMdxDocument(document: Pick<ReaderDocument, "source"> | null | undefined) {
|
|
9
|
-
return document?.source?.type === PRESS_TREE_MDX_SOURCE_TYPE;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function getSourceBlockMap(
|
|
13
|
-
document: Pick<ReaderDocument, "source"> | null | undefined,
|
|
14
|
-
): Record<string, SourceBlock> {
|
|
15
|
-
if (!isReactMdxDocument(document)) return {};
|
|
16
|
-
const blockMap = document?.source?.blockMap;
|
|
17
|
-
if (!blockMap || typeof blockMap !== "object") return {};
|
|
18
|
-
return blockMap;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function getSourceBlock(
|
|
22
|
-
document: Pick<ReaderDocument, "source"> | null | undefined,
|
|
23
|
-
blockId: string | null | undefined,
|
|
24
|
-
): SourceBlock | null {
|
|
25
|
-
if (!blockId) return null;
|
|
26
|
-
return getSourceBlockMap(document)[blockId] ?? null;
|
|
27
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
// Shape of /openpress/workspace.json — the reader fetches this on
|
|
2
|
-
// boot to decide between gallery routing (multi-Press) and direct
|
|
3
|
-
// load (single Press). One entry per <Press> child of <Workspace>.
|
|
4
|
-
//
|
|
5
|
-
// Single-Press workspaces emit one entry with slug = "" and the
|
|
6
|
-
// legacy /openpress/document.json path. Multi-Press emits one entry
|
|
7
|
-
// per slug; each `documentUrl` resolves to /openpress/<slug>/document.json.
|
|
8
|
-
|
|
9
|
-
export interface WorkspaceManifest {
|
|
10
|
-
version: 1;
|
|
11
|
-
// <Workspace name="..."> prop. Null when the user did not set one.
|
|
12
|
-
// Surfaced as the gallery header in the reader.
|
|
13
|
-
name: string | null;
|
|
14
|
-
presses: WorkspaceManifestPress[];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface WorkspaceManifestPress {
|
|
18
|
-
// Slug for this Press. Empty string for single-Press workspaces
|
|
19
|
-
// (legacy root); slug-shaped string for multi-Press.
|
|
20
|
-
slug: string;
|
|
21
|
-
// <Press title="..."> prop. Required in v1.0 contract.
|
|
22
|
-
title: string;
|
|
23
|
-
// Page geometry summary. Same shape as the reader's
|
|
24
|
-
// ReaderDocument.theme — readers can show a thumb in the gallery
|
|
25
|
-
// without loading the full document.json.
|
|
26
|
-
page: {
|
|
27
|
-
pagePreset?: string;
|
|
28
|
-
pageLabel?: string;
|
|
29
|
-
pageWidth?: string;
|
|
30
|
-
pageHeight?: string;
|
|
31
|
-
pageAspectRatio?: string;
|
|
32
|
-
pageHeightRatio?: string;
|
|
33
|
-
} | null;
|
|
34
|
-
// Number of pages produced for this Press.
|
|
35
|
-
pageCount: number;
|
|
36
|
-
// Absolute path the reader fetches for this Press's full document.json.
|
|
37
|
-
documentUrl: string;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// True when the reader should render the gallery first instead of
|
|
41
|
-
// going straight into a single Press's document.
|
|
42
|
-
export function manifestHasMultiplePresses(manifest: WorkspaceManifest): boolean {
|
|
43
|
-
return manifest.presses.length > 1;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Find a Press entry by slug. Returns null when the slug is unknown.
|
|
47
|
-
export function findManifestPress(
|
|
48
|
-
manifest: WorkspaceManifest,
|
|
49
|
-
slug: string,
|
|
50
|
-
): WorkspaceManifestPress | null {
|
|
51
|
-
const normalized = slug.replace(/^\/+|\/+$/g, "");
|
|
52
|
-
for (const press of manifest.presses) {
|
|
53
|
-
const normalizedSlug = press.slug.replace(/^\/+|\/+$/g, "");
|
|
54
|
-
if (normalizedSlug === normalized) return press;
|
|
55
|
-
}
|
|
56
|
-
return null;
|
|
57
|
-
}
|