@open-press/cli 0.7.1 → 1.0.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 +29 -13
- package/dist/cli.js +44 -195
- package/package.json +4 -5
- package/template/core/AGENTS.md +18 -14
- package/template/core/CHANGELOG.md +57 -9
- package/template/core/README.md +6 -3
- package/template/core/engine/cli.mjs +8 -8
- package/template/core/engine/commands/_shared.mjs +37 -15
- package/template/core/engine/commands/dev.mjs +2 -2
- package/template/core/engine/commands/image.mjs +29 -0
- package/template/core/engine/commands/skills-sync.mjs +71 -0
- package/template/core/engine/commands/typecheck.mjs +63 -1
- package/template/core/engine/commands/upgrade.mjs +3 -3
- package/template/core/engine/document-export.mjs +1 -1
- package/template/core/engine/output/chrome-pdf.mjs +110 -3
- package/template/core/engine/output/static-server.mjs +87 -9
- package/template/core/engine/react/comment-endpoint.mjs +13 -39
- package/template/core/engine/react/comment-marker.mjs +43 -19
- package/template/core/engine/react/document-entry.mjs +46 -28
- package/template/core/engine/react/document-export.mjs +328 -164
- package/template/core/engine/react/http-json.mjs +24 -0
- package/template/core/engine/react/mdx-compile.mjs +126 -3
- package/template/core/engine/react/measurement-css.mjs +114 -1
- package/template/core/engine/react/object-entities.mjs +204 -0
- package/template/core/engine/react/pagination/allocator.mjs +48 -3
- package/template/core/engine/react/pagination.mjs +1 -1
- package/template/core/engine/react/pipeline/allocate.mjs +41 -72
- package/template/core/engine/react/pipeline/frame-measurement.mjs +6 -0
- package/template/core/engine/react/press-tree-inspection.mjs +172 -0
- package/template/core/engine/react/project-asset-endpoint.mjs +6 -24
- package/template/core/engine/react/source-edit-endpoint.d.mts +10 -0
- package/template/core/engine/react/source-edit-endpoint.mjs +75 -0
- package/template/core/engine/react/sources/mdx-resolver.mjs +13 -15
- package/template/core/engine/react/style-discovery.mjs +23 -8
- package/template/core/engine/runtime/config.d.mts +8 -0
- package/template/core/engine/runtime/config.mjs +57 -60
- package/template/core/engine/runtime/file-utils.mjs +9 -1
- package/template/core/engine/runtime/file-walk.mjs +22 -0
- package/template/core/engine/runtime/inspection.mjs +1 -20
- package/template/core/engine/runtime/page-geometry.mjs +131 -0
- package/template/core/engine/runtime/path-utils.mjs +20 -0
- package/template/core/engine/runtime/source-text-tools.d.mts +102 -0
- package/template/core/engine/runtime/source-text-tools.mjs +551 -16
- package/template/core/engine/runtime/source-workspace.mjs +16 -34
- package/template/core/engine/runtime/validation.mjs +19 -10
- package/template/core/openpress.config.mjs +3 -7
- package/template/core/package.json +3 -5
- package/template/core/src/main.tsx +2 -2
- package/template/core/src/openpress/app/OpenPressApp.tsx +296 -0
- package/template/core/src/openpress/{renderer.tsx → app/OpenPressRuntime.tsx} +20 -9
- package/template/core/src/openpress/app/WorkspaceGalleryPage.tsx +219 -0
- package/template/core/src/openpress/app/index.ts +2 -0
- package/template/core/src/openpress/core/Frame.tsx +26 -15
- package/template/core/src/openpress/core/FrameContext.tsx +10 -3
- package/template/core/src/openpress/core/MdxArea.tsx +11 -12
- package/template/core/src/openpress/core/Press.tsx +25 -4
- package/template/core/src/openpress/core/Workspace.tsx +36 -0
- package/template/core/src/openpress/core/cn.ts +4 -0
- package/template/core/src/openpress/core/index.tsx +11 -3
- package/template/core/src/openpress/core/primitives.tsx +74 -6
- package/template/core/src/openpress/core/types.ts +94 -41
- package/template/core/src/openpress/core/useSource.ts +1 -1
- package/template/core/src/openpress/{anchorMap.ts → document-model/anchorMapModel.ts} +1 -1
- package/template/core/src/openpress/{indexes.ts → document-model/documentIndexes.ts} +1 -1
- package/template/core/src/openpress/{types.ts → document-model/documentTypes.ts} +51 -0
- package/template/core/src/openpress/document-model/index.ts +7 -0
- package/template/core/src/openpress/document-model/objectEntityModel.ts +55 -0
- package/template/core/src/openpress/{projectIdentity.ts → document-model/projectIdentityModel.ts} +1 -1
- package/template/core/src/openpress/{reactDocumentMetadata.ts → document-model/reactDocumentMetadataModel.ts} +1 -1
- package/template/core/src/openpress/document-model/workspaceManifestModel.ts +57 -0
- package/template/core/src/openpress/manuscript/index.tsx +49 -7
- package/template/core/src/openpress/mdx/index.ts +15 -7
- package/template/core/src/openpress/reader/PageThumbnailsPanel.tsx +168 -0
- package/template/core/src/openpress/{publicPage.tsx → reader/PublicReaderPage.tsx} +31 -51
- package/template/core/src/openpress/{workbenchPanels.tsx → reader/ReaderNavigationPanel.tsx} +6 -5
- package/template/core/src/openpress/reader/index.ts +11 -0
- package/template/core/src/openpress/reader/pageViewportScaleModel.ts +73 -0
- package/template/core/src/openpress/reader/readerTypes.ts +4 -0
- package/template/core/src/openpress/reader/usePageViewportScale.ts +119 -0
- package/template/core/src/openpress/reader/usePanelState.ts +56 -0
- package/template/core/src/openpress/reader/useReaderHashSync.ts +61 -0
- package/template/core/src/openpress/reader/useReaderKeyboardNav.ts +48 -0
- package/template/core/src/openpress/reader/useReaderRuntime.ts +146 -0
- package/template/core/src/openpress/reader/useReaderScrollAnchor.ts +64 -0
- package/template/core/src/openpress/shared/Panel.tsx +77 -0
- package/template/core/src/openpress/shared/index.ts +4 -0
- package/template/core/src/openpress/shared/numberUtils.ts +3 -0
- package/template/core/src/openpress/{runtimeMode.ts → shared/runtimeMode.ts} +0 -11
- package/template/core/src/openpress/workbench/Workbench.tsx +506 -0
- package/template/core/src/openpress/workbench/actions/DeploymentControl.tsx +157 -0
- package/template/core/src/openpress/workbench/actions/ExportImageControl.tsx +96 -0
- package/template/core/src/openpress/workbench/actions/PageZoomControl.tsx +182 -0
- package/template/core/src/openpress/workbench/actions/SearchControl.tsx +345 -0
- package/template/core/src/openpress/workbench/actions/deploymentStatusModel.ts +112 -0
- package/template/core/src/openpress/workbench/actions/index.ts +6 -0
- package/template/core/src/openpress/workbench/actions/useDeploymentWorkbench.ts +136 -0
- package/template/core/src/openpress/workbench/dialog/WorkbenchDialog.tsx +72 -0
- package/template/core/src/openpress/workbench/dialog/index.ts +1 -0
- package/template/core/src/openpress/workbench/document/components/DocumentPanel.tsx +127 -0
- package/template/core/src/openpress/workbench/document/components/InlineSourceEditorLayer.tsx +207 -0
- package/template/core/src/openpress/workbench/document/components/ReaderStage.tsx +9 -0
- package/template/core/src/openpress/workbench/document/hooks/useDocumentWorkbenchModel.ts +34 -0
- package/template/core/src/openpress/workbench/document/hooks/useInlineDocumentEditor.ts +525 -0
- package/template/core/src/openpress/workbench/document/index.ts +10 -0
- package/template/core/src/openpress/workbench/index.ts +2 -0
- package/template/core/src/openpress/workbench/inspector/InlineInspectorLayer.tsx +459 -0
- package/template/core/src/openpress/workbench/inspector/index.ts +5 -0
- package/template/core/src/openpress/workbench/inspector/inlineCommentModel.ts +125 -0
- package/template/core/src/openpress/workbench/inspector/inspectorGeometryModel.ts +160 -0
- package/template/core/src/openpress/workbench/inspector/inspectorModel.ts +408 -0
- package/template/core/src/openpress/workbench/inspector/useInspectorComments.ts +254 -0
- package/template/core/src/openpress/workbench/mentions/MentionSuggestionList.tsx +41 -0
- package/template/core/src/openpress/workbench/mentions/index.ts +2 -0
- package/template/core/src/openpress/{composerMentions.ts → workbench/mentions/useComposerMentions.ts} +1 -4
- package/template/core/src/openpress/workbench/panels/Panel.tsx +1 -0
- package/template/core/src/openpress/workbench/panels/PendingCommentsPanel.tsx +80 -0
- package/template/core/src/openpress/workbench/panels/WorkbenchControlPanel.tsx +29 -0
- package/template/core/src/openpress/workbench/panels/index.ts +3 -0
- package/template/core/src/openpress/workbench/project/ProjectEntryPanel.tsx +525 -0
- package/template/core/src/openpress/workbench/project/ProjectPreviewDialog.tsx +35 -0
- package/template/core/src/openpress/workbench/project/index.ts +2 -0
- package/template/core/src/openpress/workbench/project/projectPreviewTypes.ts +11 -0
- package/template/core/src/openpress/workbench/shell/WorkbenchShell.tsx +167 -0
- package/template/core/src/openpress/workbench/shell/index.ts +1 -0
- package/template/core/src/openpress/workbench/workbenchFormatters.ts +120 -0
- package/template/core/src/openpress/workbench/workbenchTypes.ts +35 -0
- package/template/core/src/styles/openpress/print-route.css +0 -2
- package/template/core/src/styles/openpress/{project-workspace.css → project-preview-panel.css} +13 -407
- package/template/core/src/styles/openpress/public-viewer.css +25 -320
- package/template/core/src/styles/openpress/reader-runtime.css +252 -55
- package/template/core/src/styles/openpress/responsive.css +145 -270
- package/template/core/src/styles/openpress/workbench-panels.css +327 -178
- package/template/core/src/styles/openpress/workbench.css +986 -451
- package/template/core/src/styles/openpress/workspace-gallery.css +300 -0
- package/template/core/src/styles/openpress.css +2 -1
- package/template/core/tsconfig.json +1 -1
- package/template/core/vite.config.ts +50 -0
- package/template/core/engine/commands/init.mjs +0 -24
- package/template/core/engine/init.mjs +0 -90
- package/template/core/src/openpress/App.tsx +0 -127
- package/template/core/src/openpress/inspector.ts +0 -282
- package/template/core/src/openpress/projectWorkspace.tsx +0 -919
- package/template/core/src/openpress/readerRuntime.ts +0 -230
- package/template/core/src/openpress/workbench.tsx +0 -1265
- package/template/core/src/openpress/workbenchTypes.ts +0 -4
- package/template/packs/academic-paper/document/chapters/01-introduction/content/01-introduction.mdx +0 -35
- package/template/packs/academic-paper/document/chapters/02-methods/content/01-methods.mdx +0 -50
- package/template/packs/academic-paper/document/chapters/03-results-and-discussion/content/01-results.mdx +0 -47
- package/template/packs/academic-paper/document/chapters/04-acknowledgment/content/01-acknowledgment.mdx +0 -26
- package/template/packs/academic-paper/document/chapters/05-references/content/01-references.mdx +0 -32
- package/template/packs/academic-paper/document/components/ChapterOpenerVisual/index.tsx +0 -76
- package/template/packs/academic-paper/document/components/Page.tsx +0 -60
- package/template/packs/academic-paper/document/components/TokenSwatchGrid/index.tsx +0 -46
- package/template/packs/academic-paper/document/components/TokenSwatchGrid/style.css +0 -63
- package/template/packs/academic-paper/document/components/TypeSpecimen/index.tsx +0 -38
- package/template/packs/academic-paper/document/components/TypeSpecimen/style.css +0 -111
- package/template/packs/academic-paper/document/design.md +0 -279
- package/template/packs/academic-paper/document/index.tsx +0 -123
- package/template/packs/academic-paper/document/media/README.md +0 -13
- package/template/packs/academic-paper/document/media/figure-placeholder.svg +0 -9
- package/template/packs/academic-paper/document/openpress.config.mjs +0 -26
- package/template/packs/academic-paper/document/theme/README.md +0 -11
- package/template/packs/academic-paper/document/theme/base/page-contract.css +0 -522
- package/template/packs/academic-paper/document/theme/base/print.css +0 -93
- package/template/packs/academic-paper/document/theme/base/typography.css +0 -333
- package/template/packs/academic-paper/document/theme/fonts.css +0 -3
- package/template/packs/academic-paper/document/theme/page-surfaces/back-cover.css +0 -43
- package/template/packs/academic-paper/document/theme/page-surfaces/chapter-opener.css +0 -205
- package/template/packs/academic-paper/document/theme/page-surfaces/cover.css +0 -294
- package/template/packs/academic-paper/document/theme/page-surfaces/toc.css +0 -149
- package/template/packs/academic-paper/document/theme/patterns/_chart-frame.css +0 -49
- package/template/packs/academic-paper/document/theme/patterns/figure-grid.css +0 -68
- package/template/packs/academic-paper/document/theme/patterns/table-utilities.css +0 -66
- package/template/packs/academic-paper/document/theme/shell/reader-controls.css +0 -761
- package/template/packs/academic-paper/document/theme/tokens.css +0 -80
- package/template/packs/academic-paper/openpress.config.mjs +0 -5
- package/template/packs/claude-document/document/chapters/01-document-shape/content/01-document-shape.mdx +0 -51
- package/template/packs/claude-document/document/chapters/02-review-loop/content/01-review-loop.mdx +0 -31
- package/template/packs/claude-document/document/components/ChapterOpenerVisual.tsx +0 -96
- package/template/packs/claude-document/document/components/Page.tsx +0 -37
- package/template/packs/claude-document/document/design.md +0 -142
- package/template/packs/claude-document/document/index.tsx +0 -94
- package/template/packs/claude-document/document/media/README.md +0 -13
- package/template/packs/claude-document/document/openpress.config.mjs +0 -26
- package/template/packs/claude-document/document/theme/README.md +0 -15
- package/template/packs/claude-document/document/theme/base/page-contract.css +0 -525
- package/template/packs/claude-document/document/theme/base/print.css +0 -93
- package/template/packs/claude-document/document/theme/base/typography.css +0 -612
- package/template/packs/claude-document/document/theme/fonts.css +0 -4
- package/template/packs/claude-document/document/theme/page-surfaces/back-cover.css +0 -72
- package/template/packs/claude-document/document/theme/page-surfaces/chapter-opener.css +0 -236
- package/template/packs/claude-document/document/theme/page-surfaces/cover.css +0 -309
- package/template/packs/claude-document/document/theme/page-surfaces/toc.css +0 -225
- package/template/packs/claude-document/document/theme/patterns/_chart-frame.css +0 -53
- package/template/packs/claude-document/document/theme/patterns/figure-grid.css +0 -68
- package/template/packs/claude-document/document/theme/patterns/table-utilities.css +0 -66
- package/template/packs/claude-document/document/theme/shell/reader-controls.css +0 -789
- package/template/packs/claude-document/document/theme/tokens.css +0 -89
- package/template/packs/claude-document/openpress.config.mjs +0 -5
- package/template/packs/editorial-monograph/document/chapters/01-product-and-use-cases/content/01-product-and-use-cases.mdx +0 -31
- package/template/packs/editorial-monograph/document/chapters/02-workflow/content/01-workflow.mdx +0 -89
- package/template/packs/editorial-monograph/document/chapters/03-agent-skills-contributors/content/01-agent-skills-contributors.mdx +0 -51
- package/template/packs/editorial-monograph/document/chapters/04-validation-deploy/content/01-validation-deploy.mdx +0 -39
- package/template/packs/editorial-monograph/document/components/ChapterOpenerVisual/index.tsx +0 -76
- package/template/packs/editorial-monograph/document/components/Page.tsx +0 -37
- package/template/packs/editorial-monograph/document/components/TokenSwatchGrid/index.tsx +0 -46
- package/template/packs/editorial-monograph/document/components/TokenSwatchGrid/style.css +0 -63
- package/template/packs/editorial-monograph/document/components/TypeSpecimen/index.tsx +0 -38
- package/template/packs/editorial-monograph/document/components/TypeSpecimen/style.css +0 -111
- package/template/packs/editorial-monograph/document/design.md +0 -279
- package/template/packs/editorial-monograph/document/index.tsx +0 -97
- package/template/packs/editorial-monograph/document/media/README.md +0 -13
- package/template/packs/editorial-monograph/document/openpress.config.mjs +0 -26
- package/template/packs/editorial-monograph/document/theme/README.md +0 -11
- package/template/packs/editorial-monograph/document/theme/base/page-contract.css +0 -505
- package/template/packs/editorial-monograph/document/theme/base/print.css +0 -93
- package/template/packs/editorial-monograph/document/theme/base/typography.css +0 -336
- package/template/packs/editorial-monograph/document/theme/fonts.css +0 -3
- package/template/packs/editorial-monograph/document/theme/page-surfaces/back-cover.css +0 -43
- package/template/packs/editorial-monograph/document/theme/page-surfaces/chapter-opener.css +0 -205
- package/template/packs/editorial-monograph/document/theme/page-surfaces/cover.css +0 -147
- package/template/packs/editorial-monograph/document/theme/page-surfaces/toc.css +0 -149
- package/template/packs/editorial-monograph/document/theme/patterns/_chart-frame.css +0 -49
- package/template/packs/editorial-monograph/document/theme/patterns/figure-grid.css +0 -68
- package/template/packs/editorial-monograph/document/theme/patterns/table-utilities.css +0 -66
- package/template/packs/editorial-monograph/document/theme/shell/reader-controls.css +0 -761
- package/template/packs/editorial-monograph/document/theme/tokens.css +0 -80
- package/template/packs/editorial-monograph/openpress.config.mjs +0 -5
- /package/template/core/src/openpress/{readerPageRegistry.ts → reader/readerPageRegistry.ts} +0 -0
- /package/template/core/src/openpress/{pageRoute.ts → reader/readerPageRoute.ts} +0 -0
- /package/template/core/src/openpress/{readerScroll.ts → reader/readerScroll.ts} +0 -0
- /package/template/core/src/openpress/{readerState.ts → reader/readerStateModel.ts} +0 -0
- /package/template/core/src/openpress/{frameScheduler.ts → shared/frameScheduler.ts} +0 -0
- /package/template/core/src/openpress/{projectSources.ts → workbench/project/projectSourceModel.ts} +0 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/* Workspace gallery — the reader's landing page for multi-Press
|
|
2
|
+
workspaces. Shows a card per <Press> child; clicking enters that
|
|
3
|
+
document's reader. Single-Press workspaces skip the gallery and
|
|
4
|
+
load the document directly, so this CSS is dormant until users
|
|
5
|
+
add a second <Press> to their <Workspace>.
|
|
6
|
+
|
|
7
|
+
Layout intent: Figma-style file grid — uniform card width, fixed
|
|
8
|
+
thumbnail aspect ratio (4:3), filename + meta below. Each card
|
|
9
|
+
loads its first page asynchronously and renders it scaled-down
|
|
10
|
+
inside the thumbnail slot. */
|
|
11
|
+
|
|
12
|
+
.openpress-workspace-gallery {
|
|
13
|
+
--workspace-bg: #10110f;
|
|
14
|
+
--workspace-bg-soft: #171813;
|
|
15
|
+
--workspace-ink: #f4f1e8;
|
|
16
|
+
--workspace-muted: rgba(244, 241, 232, 0.52);
|
|
17
|
+
--workspace-line: rgba(244, 241, 232, 0.12);
|
|
18
|
+
--workspace-card: #f7f5ee;
|
|
19
|
+
--workspace-card-ink: #141411;
|
|
20
|
+
--workspace-card-muted: #65635d;
|
|
21
|
+
--workspace-card-line: rgba(20, 20, 17, 0.1);
|
|
22
|
+
--workspace-card-stage: #e8e5dc;
|
|
23
|
+
display: grid;
|
|
24
|
+
gap: 2rem;
|
|
25
|
+
min-height: 100vh;
|
|
26
|
+
max-width: none;
|
|
27
|
+
margin: 0;
|
|
28
|
+
padding: 3.6rem clamp(2rem, 4vw, 4.5rem) 6rem;
|
|
29
|
+
font-family: var(--openpress-font-body, system-ui, sans-serif);
|
|
30
|
+
color: var(--workspace-ink);
|
|
31
|
+
background:
|
|
32
|
+
linear-gradient(180deg, var(--workspace-bg-soft), var(--workspace-bg) 42rem),
|
|
33
|
+
var(--workspace-bg);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.openpress-workspace-gallery__header {
|
|
37
|
+
display: grid;
|
|
38
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
39
|
+
align-items: end;
|
|
40
|
+
justify-content: space-between;
|
|
41
|
+
gap: 2.5rem;
|
|
42
|
+
padding: 0 0 1.45rem;
|
|
43
|
+
border-bottom: 1px solid var(--workspace-line);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.openpress-workspace-gallery__headline {
|
|
47
|
+
display: grid;
|
|
48
|
+
gap: 0.75rem;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.openpress-workspace-gallery__eyebrow {
|
|
52
|
+
margin: 0;
|
|
53
|
+
color: var(--workspace-muted);
|
|
54
|
+
font-family: var(--openpress-font-mono, ui-monospace, monospace);
|
|
55
|
+
font-size: 0.68rem;
|
|
56
|
+
font-weight: 600;
|
|
57
|
+
letter-spacing: 0.16em;
|
|
58
|
+
text-transform: uppercase;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.openpress-workspace-gallery__header h1 {
|
|
62
|
+
margin: 0;
|
|
63
|
+
font-family: var(--openpress-font-display, var(--openpress-font-body, system-ui));
|
|
64
|
+
font-size: clamp(2.6rem, 5.4vw, 5.2rem);
|
|
65
|
+
font-weight: 720;
|
|
66
|
+
line-height: 0.94;
|
|
67
|
+
letter-spacing: -0.035em;
|
|
68
|
+
color: var(--workspace-ink);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.openpress-workspace-gallery__count {
|
|
72
|
+
margin: 0;
|
|
73
|
+
display: grid;
|
|
74
|
+
justify-items: end;
|
|
75
|
+
gap: 0.25rem;
|
|
76
|
+
min-width: 4.5rem;
|
|
77
|
+
color: var(--workspace-ink);
|
|
78
|
+
font-family: var(--openpress-font-mono, ui-monospace, monospace);
|
|
79
|
+
line-height: 1;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.openpress-workspace-gallery__count span {
|
|
83
|
+
color: var(--workspace-ink);
|
|
84
|
+
font-size: 2rem;
|
|
85
|
+
font-weight: 500;
|
|
86
|
+
letter-spacing: -0.04em;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.openpress-workspace-gallery__count small {
|
|
90
|
+
color: var(--workspace-muted);
|
|
91
|
+
font-size: 0.62rem;
|
|
92
|
+
font-weight: 600;
|
|
93
|
+
letter-spacing: 0.14em;
|
|
94
|
+
text-transform: uppercase;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.openpress-workspace-gallery__grid {
|
|
98
|
+
list-style: none;
|
|
99
|
+
margin: 0;
|
|
100
|
+
padding: 0;
|
|
101
|
+
display: grid;
|
|
102
|
+
align-items: start;
|
|
103
|
+
/* Uniform card size — Figma-style. Outer thumb is fixed 4:3, the
|
|
104
|
+
inner page letterboxes to its own geometry. */
|
|
105
|
+
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
|
|
106
|
+
gap: 1.5rem;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.openpress-workspace-gallery__item {
|
|
110
|
+
display: flex;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.openpress-workspace-gallery__card {
|
|
114
|
+
appearance: none;
|
|
115
|
+
display: grid;
|
|
116
|
+
grid-template-rows: auto minmax(6.75rem, auto);
|
|
117
|
+
align-self: start;
|
|
118
|
+
width: 100%;
|
|
119
|
+
padding: 0;
|
|
120
|
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
121
|
+
border-radius: 8px;
|
|
122
|
+
background: var(--workspace-card);
|
|
123
|
+
color: var(--workspace-card-ink);
|
|
124
|
+
text-align: left;
|
|
125
|
+
cursor: pointer;
|
|
126
|
+
overflow: hidden;
|
|
127
|
+
transition:
|
|
128
|
+
transform 160ms ease,
|
|
129
|
+
box-shadow 160ms ease,
|
|
130
|
+
border-color 160ms ease;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.openpress-workspace-gallery__card:hover,
|
|
134
|
+
.openpress-workspace-gallery__card:focus-visible {
|
|
135
|
+
border-color: rgba(255, 255, 255, 0.28);
|
|
136
|
+
transform: translateY(-2px);
|
|
137
|
+
box-shadow: 0 18px 44px rgba(0, 0, 0, 0.34);
|
|
138
|
+
outline: none;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.openpress-workspace-gallery__thumb {
|
|
142
|
+
position: relative;
|
|
143
|
+
display: block;
|
|
144
|
+
width: 100%;
|
|
145
|
+
/* Uniform 4:3 outer slot across every card. The page itself
|
|
146
|
+
letterboxes inside via centered scale, so each Press shows at its
|
|
147
|
+
own true aspect against the gradient background. */
|
|
148
|
+
aspect-ratio: 4 / 3;
|
|
149
|
+
background:
|
|
150
|
+
linear-gradient(
|
|
151
|
+
135deg,
|
|
152
|
+
color-mix(in srgb, var(--workspace-card-ink) 5%, var(--workspace-card-stage)),
|
|
153
|
+
var(--workspace-card-stage)
|
|
154
|
+
);
|
|
155
|
+
border-bottom: 1px solid var(--workspace-card-line);
|
|
156
|
+
overflow: hidden;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.openpress-workspace-gallery__thumb::before {
|
|
160
|
+
content: "";
|
|
161
|
+
position: absolute;
|
|
162
|
+
inset: 0;
|
|
163
|
+
pointer-events: none;
|
|
164
|
+
background-image:
|
|
165
|
+
linear-gradient(rgba(20, 20, 17, 0.05) 1px, transparent 1px),
|
|
166
|
+
linear-gradient(90deg, rgba(20, 20, 17, 0.05) 1px, transparent 1px);
|
|
167
|
+
background-size: 24px 24px;
|
|
168
|
+
opacity: 0.5;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.openpress-workspace-gallery__thumb-stage {
|
|
172
|
+
position: absolute;
|
|
173
|
+
inset: clamp(0.85rem, 6%, 1.45rem);
|
|
174
|
+
display: grid;
|
|
175
|
+
place-items: center;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.openpress-workspace-gallery__thumb-frame {
|
|
179
|
+
position: relative;
|
|
180
|
+
box-shadow:
|
|
181
|
+
0 18px 36px rgba(20, 20, 17, 0.18),
|
|
182
|
+
0 0 0 1px rgba(20, 20, 17, 0.08);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.openpress-workspace-gallery__thumb-stage .openpress-public-page {
|
|
186
|
+
display: block;
|
|
187
|
+
pointer-events: none;
|
|
188
|
+
user-select: none;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.openpress-workspace-gallery__thumb-placeholder {
|
|
192
|
+
position: absolute;
|
|
193
|
+
inset: clamp(0.85rem, 6%, 1.45rem);
|
|
194
|
+
display: grid;
|
|
195
|
+
place-items: center;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.openpress-workspace-gallery__thumb-skel {
|
|
199
|
+
display: block;
|
|
200
|
+
width: 70%;
|
|
201
|
+
height: 70%;
|
|
202
|
+
background:
|
|
203
|
+
repeating-linear-gradient(
|
|
204
|
+
135deg,
|
|
205
|
+
rgba(20, 20, 17, 0.04) 0 6px,
|
|
206
|
+
transparent 6px 14px
|
|
207
|
+
),
|
|
208
|
+
#fff;
|
|
209
|
+
border: 1px solid var(--workspace-card-line);
|
|
210
|
+
border-radius: 3px;
|
|
211
|
+
box-shadow: 0 14px 28px rgba(20, 20, 17, 0.14);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.openpress-workspace-gallery__thumb-placeholder[data-state="loading"] .openpress-workspace-gallery__thumb-skel {
|
|
215
|
+
animation: openpress-gallery-skel-pulse 1.4s ease-in-out infinite;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
@keyframes openpress-gallery-skel-pulse {
|
|
219
|
+
0%, 100% { opacity: 1; }
|
|
220
|
+
50% { opacity: 0.55; }
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.openpress-workspace-gallery__body {
|
|
224
|
+
display: grid;
|
|
225
|
+
align-content: space-between;
|
|
226
|
+
gap: 1.2rem;
|
|
227
|
+
min-height: 6.75rem;
|
|
228
|
+
padding: 1.1rem 1.22rem 1.15rem;
|
|
229
|
+
background: var(--workspace-card);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.openpress-workspace-gallery__title {
|
|
233
|
+
display: block;
|
|
234
|
+
color: var(--workspace-card-ink);
|
|
235
|
+
font-size: 1rem;
|
|
236
|
+
font-weight: 700;
|
|
237
|
+
line-height: 1.2;
|
|
238
|
+
white-space: nowrap;
|
|
239
|
+
overflow: hidden;
|
|
240
|
+
text-overflow: ellipsis;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.openpress-workspace-gallery__meta {
|
|
244
|
+
display: flex;
|
|
245
|
+
align-items: center;
|
|
246
|
+
justify-content: space-between;
|
|
247
|
+
gap: 0.7rem;
|
|
248
|
+
flex-wrap: wrap;
|
|
249
|
+
color: var(--workspace-card-muted);
|
|
250
|
+
font-family: var(--openpress-font-mono, ui-monospace, monospace);
|
|
251
|
+
font-size: 0.66rem;
|
|
252
|
+
letter-spacing: 0.03em;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.openpress-workspace-gallery__slug {
|
|
256
|
+
max-width: 13rem;
|
|
257
|
+
color: color-mix(in srgb, var(--workspace-card-ink) 72%, transparent);
|
|
258
|
+
font-weight: 500;
|
|
259
|
+
overflow: hidden;
|
|
260
|
+
text-overflow: ellipsis;
|
|
261
|
+
text-transform: uppercase;
|
|
262
|
+
white-space: nowrap;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.openpress-workspace-gallery__dot {
|
|
266
|
+
color: color-mix(in srgb, var(--workspace-card-muted) 55%, transparent);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.openpress-workspace-gallery__pages,
|
|
270
|
+
.openpress-workspace-gallery__geom {
|
|
271
|
+
color: var(--workspace-card-muted);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.openpress-workspace-gallery__geom {
|
|
275
|
+
display: inline-flex;
|
|
276
|
+
align-items: center;
|
|
277
|
+
min-height: 1.35rem;
|
|
278
|
+
padding: 0 0.48rem;
|
|
279
|
+
border: 1px solid var(--workspace-card-line);
|
|
280
|
+
border-radius: 4px;
|
|
281
|
+
background: rgba(255, 255, 255, 0.36);
|
|
282
|
+
color: color-mix(in srgb, var(--workspace-card-ink) 76%, transparent);
|
|
283
|
+
font-size: 0.62rem;
|
|
284
|
+
white-space: nowrap;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
@media (max-width: 720px) {
|
|
288
|
+
.openpress-workspace-gallery {
|
|
289
|
+
padding: 2.25rem 1rem 4rem;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.openpress-workspace-gallery__header {
|
|
293
|
+
display: grid;
|
|
294
|
+
align-items: start;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.openpress-workspace-gallery__grid {
|
|
298
|
+
grid-template-columns: 1fr;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
@import url("/openpress/components.css");
|
|
5
5
|
|
|
6
6
|
@import "./openpress/app-shell.css";
|
|
7
|
+
@import "./openpress/workspace-gallery.css";
|
|
7
8
|
@import "./openpress/workbench.css";
|
|
8
9
|
@import "./openpress/workbench-panels.css";
|
|
9
|
-
@import "./openpress/project-
|
|
10
|
+
@import "./openpress/project-preview-panel.css";
|
|
10
11
|
@import "./openpress/media-workspace.css";
|
|
11
12
|
@import "./openpress/reader-runtime.css";
|
|
12
13
|
@import "./openpress/public-viewer.css";
|
|
@@ -6,8 +6,10 @@ import type { IncomingMessage, ServerResponse } from "node:http";
|
|
|
6
6
|
import { defineConfig } from "vite";
|
|
7
7
|
import react from "@vitejs/plugin-react";
|
|
8
8
|
import { loadConfig, publicPdfHref } from "./engine/runtime/config.mjs";
|
|
9
|
+
import { searchSourceText } from "./engine/runtime/source-text-tools.mjs";
|
|
9
10
|
import { handleCommentRequest } from "./engine/react/comment-endpoint.mjs";
|
|
10
11
|
import { handleProjectAssetRequest } from "./engine/react/project-asset-endpoint.mjs";
|
|
12
|
+
import { handleSourceEditRequest } from "./engine/react/source-edit-endpoint.mjs";
|
|
11
13
|
|
|
12
14
|
const frameworkRoot = fileURLToPath(new URL("./", import.meta.url));
|
|
13
15
|
const workspaceRoot = process.env.OPENPRESS_WORKSPACE_ROOT
|
|
@@ -53,6 +55,7 @@ const workspaceDefines = {
|
|
|
53
55
|
|
|
54
56
|
export default defineConfig({
|
|
55
57
|
base: "./",
|
|
58
|
+
cacheDir: path.join(workspaceRoot, ".openpress", "vite-client"),
|
|
56
59
|
plugins: [openpressLocalDeployPlugin(), react()],
|
|
57
60
|
define: workspaceDefines,
|
|
58
61
|
resolve: {
|
|
@@ -68,6 +71,17 @@ export default defineConfig({
|
|
|
68
71
|
...workspaceAliases,
|
|
69
72
|
},
|
|
70
73
|
},
|
|
74
|
+
optimizeDeps: {
|
|
75
|
+
include: [
|
|
76
|
+
"@mdx-js/react",
|
|
77
|
+
"lucide-react",
|
|
78
|
+
"react",
|
|
79
|
+
"react-dom",
|
|
80
|
+
"react-dom/client",
|
|
81
|
+
"react/jsx-dev-runtime",
|
|
82
|
+
"react/jsx-runtime",
|
|
83
|
+
],
|
|
84
|
+
},
|
|
71
85
|
build: {
|
|
72
86
|
outDir: outputDir,
|
|
73
87
|
emptyOutDir: true,
|
|
@@ -108,6 +122,12 @@ function openpressLocalDeployPlugin() {
|
|
|
108
122
|
server.middlewares.use("/__openpress/status", (req, res) => {
|
|
109
123
|
void handleLocalStatusRequest(req, res);
|
|
110
124
|
});
|
|
125
|
+
server.middlewares.use("/__openpress/search", (req, res) => {
|
|
126
|
+
void handleLocalSearchRequest(req, res);
|
|
127
|
+
});
|
|
128
|
+
server.middlewares.use("/__openpress/source-edit", (req, res) => {
|
|
129
|
+
void handleSourceEditRequest(req, res, { root: workspaceRoot });
|
|
130
|
+
});
|
|
111
131
|
server.middlewares.use("/__openpress/deploy", (req, res) => {
|
|
112
132
|
void handleLocalDeployRequest(req, res);
|
|
113
133
|
});
|
|
@@ -267,6 +287,32 @@ async function handleLocalStatusRequest(req: IncomingMessage, res: ServerRespons
|
|
|
267
287
|
});
|
|
268
288
|
}
|
|
269
289
|
|
|
290
|
+
async function handleLocalSearchRequest(req: IncomingMessage, res: ServerResponse) {
|
|
291
|
+
if (req.method !== "GET") {
|
|
292
|
+
writeJson(res, 405, { ok: false, message: "Search endpoint requires GET." });
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const requestUrl = new URL(req.url ?? "/", "http://localhost");
|
|
297
|
+
const query = (requestUrl.searchParams.get("q") ?? "").trim();
|
|
298
|
+
if (!query) {
|
|
299
|
+
writeJson(res, 400, { ok: false, message: "Search query is required." });
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
try {
|
|
304
|
+
const report = await searchSourceText({
|
|
305
|
+
config: openpressConfig,
|
|
306
|
+
query,
|
|
307
|
+
scope: searchScopeFrom(requestUrl.searchParams),
|
|
308
|
+
caseSensitive: requestUrl.searchParams.get("caseSensitive") === "true",
|
|
309
|
+
});
|
|
310
|
+
writeJson(res, 200, { ok: true, ...report });
|
|
311
|
+
} catch (error) {
|
|
312
|
+
writeJson(res, 500, { ok: false, message: error instanceof Error ? error.message : String(error) });
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
270
316
|
async function handleLocalDeployRequest(req: IncomingMessage, res: ServerResponse) {
|
|
271
317
|
if (req.method !== "POST") {
|
|
272
318
|
writeJson(res, 405, { ok: false, message: "Deploy endpoint requires POST." });
|
|
@@ -368,6 +414,10 @@ function localDeploySetupMessage() {
|
|
|
368
414
|
return `Deployment adapter \`${openpressConfig.deploy.adapter}\` is not configured.`;
|
|
369
415
|
}
|
|
370
416
|
|
|
417
|
+
function searchScopeFrom(searchParams: URLSearchParams) {
|
|
418
|
+
return searchParams.get("scope") === "all" ? "all" : "content";
|
|
419
|
+
}
|
|
420
|
+
|
|
371
421
|
async function fileExists(filePath: string) {
|
|
372
422
|
try {
|
|
373
423
|
await fs.access(filePath);
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { initWorkspace, listStylePackSkills } from "../init.mjs";
|
|
2
|
-
import { formatDisplayPath, parseInitOptions } from "./_shared.mjs";
|
|
3
|
-
|
|
4
|
-
export const needsWorkspace = false;
|
|
5
|
-
|
|
6
|
-
export async function run({ argv }) {
|
|
7
|
-
const options = parseInitOptions(argv);
|
|
8
|
-
if (!options.target) {
|
|
9
|
-
console.error("openpress init: target path is required");
|
|
10
|
-
console.error("Usage: openpress init <target> [--skill <name>] [--force]");
|
|
11
|
-
const available = await listStylePackSkills();
|
|
12
|
-
if (available.length) console.error(`Style packs available: ${available.join(", ")}`);
|
|
13
|
-
return 1;
|
|
14
|
-
}
|
|
15
|
-
const result = await initWorkspace(options);
|
|
16
|
-
const displayPath = formatDisplayPath(result.targetPath);
|
|
17
|
-
console.log(`OpenPress init: created ${displayPath} from style pack "${result.skill}".`);
|
|
18
|
-
console.log("Next steps:");
|
|
19
|
-
console.log(` cd ${displayPath}`);
|
|
20
|
-
console.log(" # 填入 openpress.config.mjs 的 title / subtitle / organization");
|
|
21
|
-
console.log(" # 改 document/index.tsx 與 document/chapters/**/*.mdx 為實際內容");
|
|
22
|
-
console.log(" node engine/cli.mjs validate");
|
|
23
|
-
return 0;
|
|
24
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
|
-
|
|
5
|
-
const SELF_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
-
const ENGINE_ROOT = path.resolve(SELF_DIR, "..");
|
|
7
|
-
const SKILLS_DIR = path.join(ENGINE_ROOT, "skills");
|
|
8
|
-
|
|
9
|
-
const DEFAULT_SKILL = "editorial-monograph";
|
|
10
|
-
|
|
11
|
-
export async function initWorkspace({ target, skill = DEFAULT_SKILL, force = false }) {
|
|
12
|
-
if (!target) throw new Error("openpress init: target path is required");
|
|
13
|
-
const targetPath = path.resolve(target);
|
|
14
|
-
|
|
15
|
-
const starterPath = path.join(SKILLS_DIR, skill, "starter");
|
|
16
|
-
try {
|
|
17
|
-
const stat = await fs.stat(starterPath);
|
|
18
|
-
if (!stat.isDirectory()) {
|
|
19
|
-
throw new Error(`openpress init: skill "${skill}" has no starter/ directory at ${starterPath}`);
|
|
20
|
-
}
|
|
21
|
-
} catch (error) {
|
|
22
|
-
if (error?.code === "ENOENT") {
|
|
23
|
-
const available = await listStylePackSkills();
|
|
24
|
-
throw new Error(
|
|
25
|
-
`openpress init: skill "${skill}" not found or has no starter. ` +
|
|
26
|
-
`Available style packs: ${available.join(", ") || "(none)"}`,
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
throw error;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (!force) {
|
|
33
|
-
try {
|
|
34
|
-
const stat = await fs.stat(targetPath);
|
|
35
|
-
if (stat.isDirectory()) {
|
|
36
|
-
const entries = await fs.readdir(targetPath);
|
|
37
|
-
if (entries.length > 0) {
|
|
38
|
-
throw new Error(`openpress init: target ${targetPath} exists and is not empty. Pass --force to overwrite.`);
|
|
39
|
-
}
|
|
40
|
-
} else {
|
|
41
|
-
throw new Error(`openpress init: target ${targetPath} exists and is not a directory.`);
|
|
42
|
-
}
|
|
43
|
-
} catch (error) {
|
|
44
|
-
if (error?.code !== "ENOENT") throw error;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
await fs.mkdir(targetPath, { recursive: true });
|
|
49
|
-
await copyDirectory(starterPath, targetPath);
|
|
50
|
-
|
|
51
|
-
return { targetPath, skill };
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export async function listStylePackSkills() {
|
|
55
|
-
try {
|
|
56
|
-
const entries = await fs.readdir(SKILLS_DIR, { withFileTypes: true });
|
|
57
|
-
const names = [];
|
|
58
|
-
for (const entry of entries) {
|
|
59
|
-
if (!entry.isDirectory()) continue;
|
|
60
|
-
const starter = path.join(SKILLS_DIR, entry.name, "starter");
|
|
61
|
-
try {
|
|
62
|
-
const stat = await fs.stat(starter);
|
|
63
|
-
if (stat.isDirectory()) names.push(entry.name);
|
|
64
|
-
} catch {
|
|
65
|
-
// skill without starter/ is not a style pack — skip
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return names.sort();
|
|
69
|
-
} catch (error) {
|
|
70
|
-
if (error?.code === "ENOENT") return [];
|
|
71
|
-
throw error;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async function copyDirectory(source, destination) {
|
|
76
|
-
await fs.mkdir(destination, { recursive: true });
|
|
77
|
-
for (const entry of await fs.readdir(source, { withFileTypes: true })) {
|
|
78
|
-
if (entry.name === ".DS_Store") continue;
|
|
79
|
-
const sourcePath = path.join(source, entry.name);
|
|
80
|
-
const destPath = path.join(destination, entry.name);
|
|
81
|
-
if (entry.isDirectory()) {
|
|
82
|
-
await copyDirectory(sourcePath, destPath);
|
|
83
|
-
} else if (entry.isFile()) {
|
|
84
|
-
await fs.copyFile(sourcePath, destPath);
|
|
85
|
-
} else if (entry.isSymbolicLink()) {
|
|
86
|
-
const link = await fs.readlink(sourcePath);
|
|
87
|
-
await fs.symlink(link, destPath);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from "react";
|
|
2
|
-
import { Renderer } from "./renderer";
|
|
3
|
-
import { isLocalWorkspaceHost } from "./runtimeMode";
|
|
4
|
-
import type { DeploymentInfo, ReaderDocument } from "./types";
|
|
5
|
-
|
|
6
|
-
type LoadState =
|
|
7
|
-
| { status: "loading" }
|
|
8
|
-
| {
|
|
9
|
-
status: "ready";
|
|
10
|
-
document: ReaderDocument;
|
|
11
|
-
deploymentInfo: DeploymentInfo;
|
|
12
|
-
}
|
|
13
|
-
| { status: "error"; message: string };
|
|
14
|
-
|
|
15
|
-
interface DeployConfig {
|
|
16
|
-
pdf?: string;
|
|
17
|
-
deployed_at?: string;
|
|
18
|
-
public_url?: string;
|
|
19
|
-
dirty?: boolean;
|
|
20
|
-
deploy_configured?: boolean;
|
|
21
|
-
deploy_adapter?: string;
|
|
22
|
-
deploy_source?: string;
|
|
23
|
-
deploy_project_name?: string | null;
|
|
24
|
-
deploy_setup_message?: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const offlineDeploymentInfo: DeploymentInfo = { online: false };
|
|
28
|
-
|
|
29
|
-
function LoadingScreen() {
|
|
30
|
-
return (
|
|
31
|
-
<div className="openpress-loading-screen" aria-label="載入中" role="status">
|
|
32
|
-
<div className="openpress-loading-screen__inner">
|
|
33
|
-
<div className="openpress-loading-dots" aria-hidden="true">
|
|
34
|
-
<span /><span /><span />
|
|
35
|
-
</div>
|
|
36
|
-
<span className="openpress-loading-screen__label">載入文件</span>
|
|
37
|
-
</div>
|
|
38
|
-
</div>
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function App() {
|
|
43
|
-
const [state, setState] = useState<LoadState>({ status: "loading" });
|
|
44
|
-
|
|
45
|
-
useEffect(() => {
|
|
46
|
-
let cancelled = false;
|
|
47
|
-
|
|
48
|
-
async function loadDocument() {
|
|
49
|
-
try {
|
|
50
|
-
const [response, deploymentInfo] = await Promise.all([
|
|
51
|
-
fetch("/openpress/document.json", { cache: "no-store" }),
|
|
52
|
-
loadDeploymentInfo(),
|
|
53
|
-
]);
|
|
54
|
-
if (!response.ok) {
|
|
55
|
-
throw new Error(`Unable to load /openpress/document.json (${response.status})`);
|
|
56
|
-
}
|
|
57
|
-
const document = (await response.json()) as ReaderDocument;
|
|
58
|
-
if (!cancelled) {
|
|
59
|
-
setState({ status: "ready", document, deploymentInfo });
|
|
60
|
-
}
|
|
61
|
-
} catch (error) {
|
|
62
|
-
if (!cancelled) {
|
|
63
|
-
setState({
|
|
64
|
-
status: "error",
|
|
65
|
-
message: error instanceof Error ? error.message : "Unable to load OpenPress document.",
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
void loadDocument();
|
|
72
|
-
return () => {
|
|
73
|
-
cancelled = true;
|
|
74
|
-
};
|
|
75
|
-
}, []);
|
|
76
|
-
|
|
77
|
-
if (state.status === "loading") return <LoadingScreen />;
|
|
78
|
-
|
|
79
|
-
if (state.status === "error") {
|
|
80
|
-
return <div className="openpress-load-state openpress-load-state--error">{state.message}</div>;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return (
|
|
84
|
-
<Renderer
|
|
85
|
-
document={state.document}
|
|
86
|
-
deploymentInfo={state.deploymentInfo}
|
|
87
|
-
/>
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
async function loadDeploymentInfo(): Promise<DeploymentInfo> {
|
|
92
|
-
if (typeof window !== "undefined" && isLocalWorkspaceHost(window.location.hostname)) {
|
|
93
|
-
const localInfo = await loadDeploymentInfoFrom("/__openpress/status");
|
|
94
|
-
if (localInfo) return localInfo;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return (await loadDeploymentInfoFrom("/openpress/deploy.json")) ?? offlineDeploymentInfo;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
async function loadDeploymentInfoFrom(path: string): Promise<DeploymentInfo | null> {
|
|
101
|
-
try {
|
|
102
|
-
const response = await fetch(path, { cache: "no-store" });
|
|
103
|
-
if (!response.ok) {
|
|
104
|
-
return null;
|
|
105
|
-
}
|
|
106
|
-
const config = (await response.json()) as DeployConfig;
|
|
107
|
-
return deploymentConfigToInfo(config);
|
|
108
|
-
} catch {
|
|
109
|
-
return null;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function deploymentConfigToInfo(config: DeployConfig): DeploymentInfo {
|
|
114
|
-
const configured = config.deploy_configured !== false;
|
|
115
|
-
return {
|
|
116
|
-
online: configured && Boolean(config.deployed_at || config.public_url),
|
|
117
|
-
deployedAt: config.deployed_at,
|
|
118
|
-
pdf: typeof config.pdf === "string" ? config.pdf : undefined,
|
|
119
|
-
publicUrl: typeof config.public_url === "string" ? config.public_url : undefined,
|
|
120
|
-
dirty: config.dirty === true,
|
|
121
|
-
configured,
|
|
122
|
-
adapter: typeof config.deploy_adapter === "string" ? config.deploy_adapter : undefined,
|
|
123
|
-
source: typeof config.deploy_source === "string" ? config.deploy_source : undefined,
|
|
124
|
-
projectName: typeof config.deploy_project_name === "string" ? config.deploy_project_name : undefined,
|
|
125
|
-
setupMessage: typeof config.deploy_setup_message === "string" ? config.deploy_setup_message : undefined,
|
|
126
|
-
};
|
|
127
|
-
}
|