@open-press/cli 0.7.0 → 0.8.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 +6 -1
- package/package.json +1 -1
- package/template/core/AGENTS.md +126 -0
- package/template/core/CHANGELOG.md +65 -0
- package/template/core/engine/commands/dev.mjs +2 -2
- package/template/core/engine/commands/upgrade.mjs +47 -5
- package/template/core/engine/output/chrome-pdf.mjs +18 -3
- package/template/core/engine/output/static-server.mjs +39 -0
- package/template/core/engine/react/comment-endpoint.mjs +13 -39
- package/template/core/engine/react/comment-marker.mjs +30 -6
- package/template/core/engine/react/document-entry.mjs +11 -0
- package/template/core/engine/react/document-export.mjs +45 -5
- package/template/core/engine/react/http-json.mjs +24 -0
- package/template/core/engine/react/mdx-compile.mjs +187 -3
- package/template/core/engine/react/measurement-css.mjs +93 -1
- package/template/core/engine/react/object-entities.mjs +119 -0
- package/template/core/engine/react/pipeline/allocate.mjs +10 -7
- package/template/core/engine/react/pipeline/frame-measurement.mjs +40 -9
- 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 +12 -14
- package/template/core/engine/react/style-discovery.mjs +1 -4
- package/template/core/engine/runtime/file-walk.mjs +22 -0
- package/template/core/engine/runtime/inspection.mjs +1 -20
- 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 +4 -31
- package/template/core/package.json +1 -1
- package/template/core/src/main.tsx +2 -2
- package/template/core/src/openpress/{App.tsx → app/OpenPressApp.tsx} +25 -12
- package/template/core/src/openpress/{renderer.tsx → app/OpenPressRuntime.tsx} +10 -7
- package/template/core/src/openpress/app/index.ts +2 -0
- package/template/core/src/openpress/core/Frame.tsx +9 -11
- package/template/core/src/openpress/core/FrameContext.tsx +8 -3
- package/template/core/src/openpress/core/MdxArea.tsx +11 -12
- package/template/core/src/openpress/core/cn.ts +4 -0
- package/template/core/src/openpress/core/index.tsx +2 -1
- package/template/core/src/openpress/core/primitives.tsx +29 -8
- package/template/core/src/openpress/core/types.ts +8 -0
- 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} +42 -0
- package/template/core/src/openpress/document-model/index.ts +6 -0
- package/template/core/src/openpress/document-model/objectEntityModel.ts +51 -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/manuscript/index.tsx +49 -7
- 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 +10 -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 +407 -0
- package/template/core/src/openpress/workbench/actions/DeploymentControl.tsx +157 -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 +5 -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 +248 -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 +76 -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 +523 -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 +243 -55
- package/template/core/src/styles/openpress/responsive.css +145 -270
- package/template/core/src/styles/openpress/workbench-panels.css +214 -178
- package/template/core/src/styles/openpress/workbench.css +986 -451
- package/template/core/src/styles/openpress.css +1 -1
- package/template/core/vite.config.ts +50 -0
- package/template/packs/academic-paper/document/chapters/01-introduction/content/01-introduction.mdx +26 -12
- package/template/packs/academic-paper/document/chapters/02-methods/content/01-methods.mdx +37 -17
- package/template/packs/academic-paper/document/chapters/03-results-and-discussion/content/01-results.mdx +34 -16
- package/template/packs/academic-paper/document/chapters/04-acknowledgment/content/01-acknowledgment.mdx +22 -8
- package/template/packs/academic-paper/document/chapters/05-references/content/01-references.mdx +20 -15
- package/template/packs/academic-paper/document/components/Page.tsx +26 -3
- package/template/packs/academic-paper/document/index.tsx +51 -59
- package/template/packs/academic-paper/document/media/figure-placeholder.svg +9 -0
- package/template/packs/academic-paper/document/theme/base/page-contract.css +30 -13
- package/template/packs/academic-paper/document/theme/base/typography.css +30 -33
- package/template/packs/academic-paper/document/theme/page-surfaces/cover.css +74 -47
- 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/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
|
@@ -383,12 +383,12 @@ button:focus-visible {
|
|
|
383
383
|
position: relative;
|
|
384
384
|
width: var(--reader-page-width, var(--openpress-page-width));
|
|
385
385
|
height: calc(var(--reader-page-width, var(--openpress-page-width)) * var(--openpress-page-height) / var(--openpress-page-width));
|
|
386
|
-
--page-margin-x: clamp(
|
|
387
|
-
--page-margin-top: clamp(
|
|
388
|
-
--page-margin-bottom: clamp(
|
|
389
|
-
--page-header-height: clamp(
|
|
390
|
-
--page-footer-height: clamp(
|
|
391
|
-
--page-frame-gap: clamp(
|
|
386
|
+
--page-margin-x: clamp(20px, 3.8cqw, 34px);
|
|
387
|
+
--page-margin-top: clamp(18px, 3.5cqw, 30px);
|
|
388
|
+
--page-margin-bottom: clamp(14px, 2.4cqw, 24px);
|
|
389
|
+
--page-header-height: clamp(10px, 1.6cqw, 16px);
|
|
390
|
+
--page-footer-height: clamp(16px, 2.2cqw, 22px);
|
|
391
|
+
--page-frame-gap: clamp(5px, 1.1cqw, 11px);
|
|
392
392
|
overflow: hidden;
|
|
393
393
|
color: var(--openpress-color-ink);
|
|
394
394
|
background: var(--openpress-color-document);
|
|
@@ -429,12 +429,29 @@ button:focus-visible {
|
|
|
429
429
|
|
|
430
430
|
.page-header {
|
|
431
431
|
display: flex;
|
|
432
|
-
align-items:
|
|
432
|
+
align-items: baseline;
|
|
433
|
+
justify-content: space-between;
|
|
434
|
+
gap: var(--openpress-space-3);
|
|
433
435
|
color: var(--openpress-color-muted);
|
|
434
|
-
font-
|
|
435
|
-
|
|
436
|
-
|
|
436
|
+
font-family: var(--openpress-font-body);
|
|
437
|
+
font-size: clamp(8px, 1.2cqw, 9px);
|
|
438
|
+
letter-spacing: normal;
|
|
439
|
+
opacity: 0.82;
|
|
437
440
|
pointer-events: none;
|
|
441
|
+
line-height: 1.2;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
.running-head-left,
|
|
445
|
+
.running-head-right {
|
|
446
|
+
min-width: 0;
|
|
447
|
+
overflow: hidden;
|
|
448
|
+
text-overflow: ellipsis;
|
|
449
|
+
white-space: nowrap;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
.running-head-right {
|
|
453
|
+
max-width: 45%;
|
|
454
|
+
text-align: right;
|
|
438
455
|
}
|
|
439
456
|
|
|
440
457
|
.page-body {
|
|
@@ -448,9 +465,9 @@ button:focus-visible {
|
|
|
448
465
|
justify-content: space-between;
|
|
449
466
|
align-items: baseline;
|
|
450
467
|
gap: 12px;
|
|
451
|
-
font-size: clamp(
|
|
468
|
+
font-size: clamp(8px, 1.2cqw, 9px);
|
|
452
469
|
color: var(--openpress-color-muted);
|
|
453
|
-
letter-spacing:
|
|
470
|
+
letter-spacing: normal;
|
|
454
471
|
opacity: 0.7;
|
|
455
472
|
pointer-events: none;
|
|
456
473
|
}
|
|
@@ -465,7 +482,7 @@ button:focus-visible {
|
|
|
465
482
|
|
|
466
483
|
.page-footer .footer-right {
|
|
467
484
|
font-variant-numeric: tabular-nums;
|
|
468
|
-
letter-spacing: 0.
|
|
485
|
+
letter-spacing: 0.02em;
|
|
469
486
|
flex-shrink: 0;
|
|
470
487
|
}
|
|
471
488
|
|
|
@@ -14,50 +14,45 @@ h3,
|
|
|
14
14
|
h4 {
|
|
15
15
|
break-after: avoid;
|
|
16
16
|
color: var(--openpress-color-ink);
|
|
17
|
-
letter-spacing:
|
|
17
|
+
letter-spacing: normal;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
h2 {
|
|
21
|
-
margin: 0 0 var(--openpress-space-
|
|
21
|
+
margin: 0 0 var(--openpress-space-3);
|
|
22
22
|
padding: 0;
|
|
23
23
|
font-family: var(--openpress-font-serif);
|
|
24
|
-
font-size: clamp(
|
|
24
|
+
font-size: clamp(15px, 2.4cqw, 20px);
|
|
25
25
|
line-height: 1.45;
|
|
26
|
-
font-weight:
|
|
26
|
+
font-weight: 700;
|
|
27
27
|
border: 0;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
h2::before {
|
|
31
|
-
content:
|
|
32
|
-
display: block;
|
|
33
|
-
width: 36px;
|
|
34
|
-
height: 1px;
|
|
35
|
-
background: var(--openpress-color-ink);
|
|
36
|
-
margin-bottom: var(--openpress-space-4);
|
|
31
|
+
content: none;
|
|
37
32
|
}
|
|
38
33
|
|
|
39
|
-
.reader-page--content .page-body
|
|
34
|
+
.reader-page--content .page-body .openpress-mdx-area h2 {
|
|
40
35
|
display: flex;
|
|
41
36
|
align-items: baseline;
|
|
42
37
|
gap: 0.55em;
|
|
43
38
|
margin: 0 0 var(--openpress-space-4);
|
|
44
39
|
}
|
|
45
40
|
|
|
46
|
-
.reader-page--content .page-body
|
|
41
|
+
.reader-page--content .page-body .openpress-mdx-area h2::before {
|
|
47
42
|
content: attr(data-chapter);
|
|
48
43
|
display: inline-block;
|
|
49
44
|
flex-shrink: 0;
|
|
50
45
|
font-family: var(--openpress-font-serif);
|
|
51
|
-
font-size:
|
|
52
|
-
font-weight:
|
|
53
|
-
color: var(--openpress-color-
|
|
46
|
+
font-size: 0.88em;
|
|
47
|
+
font-weight: 700;
|
|
48
|
+
color: var(--openpress-color-ink);
|
|
54
49
|
line-height: 1;
|
|
55
|
-
letter-spacing:
|
|
50
|
+
letter-spacing: normal;
|
|
56
51
|
width: auto;
|
|
57
52
|
min-width: 0;
|
|
58
53
|
height: auto;
|
|
59
54
|
background: transparent;
|
|
60
|
-
padding: 0;
|
|
55
|
+
padding-right: 0.22em;
|
|
61
56
|
margin: 0;
|
|
62
57
|
border: 0;
|
|
63
58
|
}
|
|
@@ -72,26 +67,26 @@ h2::before {
|
|
|
72
67
|
content: attr(data-section);
|
|
73
68
|
flex-shrink: 0;
|
|
74
69
|
font-family: var(--openpress-font-serif);
|
|
75
|
-
font-size: 0.
|
|
76
|
-
font-weight:
|
|
77
|
-
color: var(--openpress-color-
|
|
78
|
-
letter-spacing:
|
|
70
|
+
font-size: 0.98em;
|
|
71
|
+
font-weight: 500;
|
|
72
|
+
color: var(--openpress-color-ink);
|
|
73
|
+
letter-spacing: normal;
|
|
79
74
|
line-height: inherit;
|
|
80
75
|
}
|
|
81
76
|
|
|
82
77
|
h2 + p,
|
|
83
78
|
h2 + h3 {
|
|
84
|
-
margin-top: var(--openpress-space-
|
|
79
|
+
margin-top: var(--openpress-space-2);
|
|
85
80
|
}
|
|
86
81
|
|
|
87
82
|
h3 {
|
|
88
83
|
margin: var(--openpress-space-3) 0 var(--openpress-space-2);
|
|
89
84
|
font-family: var(--openpress-font-serif);
|
|
90
|
-
font-size: clamp(
|
|
91
|
-
line-height: 1.
|
|
92
|
-
font-weight:
|
|
85
|
+
font-size: clamp(12px, 2cqw, 16px);
|
|
86
|
+
line-height: 1.5;
|
|
87
|
+
font-weight: 500;
|
|
93
88
|
color: var(--openpress-color-ink);
|
|
94
|
-
letter-spacing:
|
|
89
|
+
letter-spacing: normal;
|
|
95
90
|
}
|
|
96
91
|
|
|
97
92
|
.reader-page--content .page-body > h3:first-child {
|
|
@@ -100,17 +95,19 @@ h3 {
|
|
|
100
95
|
|
|
101
96
|
h4 {
|
|
102
97
|
margin: var(--openpress-space-3) 0 var(--openpress-space-1);
|
|
103
|
-
font-family: var(--openpress-font-
|
|
104
|
-
font-size: clamp(
|
|
98
|
+
font-family: var(--openpress-font-serif);
|
|
99
|
+
font-size: clamp(10px, 1.75cqw, 14px);
|
|
105
100
|
font-weight: 500;
|
|
106
101
|
color: var(--openpress-color-muted);
|
|
107
|
-
letter-spacing: 0.
|
|
102
|
+
letter-spacing: 0.01em;
|
|
108
103
|
}
|
|
109
104
|
|
|
110
105
|
p {
|
|
111
106
|
margin: 0 0 var(--openpress-space-2);
|
|
112
|
-
font-size: clamp(
|
|
113
|
-
line-height: 1.
|
|
107
|
+
font-size: clamp(10px, 1.8cqw, 11px);
|
|
108
|
+
line-height: 1.65;
|
|
109
|
+
text-align: justify;
|
|
110
|
+
text-justify: inter-word;
|
|
114
111
|
}
|
|
115
112
|
|
|
116
113
|
.reader-page--content p,
|
|
@@ -206,8 +203,8 @@ ol,
|
|
|
206
203
|
ul {
|
|
207
204
|
margin: 0 0 var(--openpress-space-3);
|
|
208
205
|
padding-left: 7mm;
|
|
209
|
-
font-size: clamp(
|
|
210
|
-
line-height: 1.
|
|
206
|
+
font-size: clamp(10px, 1.75cqw, 11px);
|
|
207
|
+
line-height: 1.65;
|
|
211
208
|
}
|
|
212
209
|
|
|
213
210
|
ol {
|
|
@@ -146,99 +146,126 @@
|
|
|
146
146
|
color: var(--openpress-color-ink);
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
/* ─ academic-paper title block
|
|
150
|
-
/* IEEE-style title page: large serif title, optional subtitle, 3-column */
|
|
151
|
-
/* author grid, abstract band, index terms band. Single-column body picks */
|
|
152
|
-
/* up after this surface. Two-column body arrives with the v0.8 paged.js */
|
|
153
|
-
/* migration. */
|
|
149
|
+
/* ─ academic-paper title block for the journal-style template ───────────── */
|
|
154
150
|
|
|
155
151
|
.paper-cover {
|
|
156
152
|
display: flex;
|
|
157
153
|
flex-direction: column;
|
|
158
|
-
gap: clamp(
|
|
159
|
-
padding-block: clamp(
|
|
154
|
+
gap: clamp(11px, 2.2cqw, 20px);
|
|
155
|
+
padding-block: clamp(18px, 2.5cqw, 30px) 0;
|
|
160
156
|
font-family: var(--openpress-font-serif);
|
|
161
157
|
color: var(--openpress-color-ink);
|
|
162
158
|
}
|
|
163
159
|
|
|
160
|
+
.paper-cover-lead,
|
|
161
|
+
.paper-cover-short-title {
|
|
162
|
+
margin: 0;
|
|
163
|
+
text-align: center;
|
|
164
|
+
color: var(--openpress-color-muted);
|
|
165
|
+
font-family: var(--openpress-font-body);
|
|
166
|
+
font-size: clamp(8.5pt, 1.55cqw, 9.5pt);
|
|
167
|
+
letter-spacing: 0.01em;
|
|
168
|
+
line-height: 1.3;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.paper-cover-date {
|
|
172
|
+
margin: 0;
|
|
173
|
+
text-align: center;
|
|
174
|
+
color: var(--openpress-color-muted);
|
|
175
|
+
font-family: var(--openpress-font-body);
|
|
176
|
+
font-size: clamp(7.8pt, 1.3cqw, 8.7pt);
|
|
177
|
+
letter-spacing: 0;
|
|
178
|
+
line-height: 1.25;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.paper-cover-lead {
|
|
182
|
+
margin-top: 2mm;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.paper-cover-short-title {
|
|
186
|
+
margin-bottom: clamp(6px, 1.2cqw, 10px);
|
|
187
|
+
}
|
|
188
|
+
|
|
164
189
|
.paper-title {
|
|
165
190
|
font-family: var(--openpress-font-serif);
|
|
166
|
-
font-size: clamp(
|
|
191
|
+
font-size: clamp(32px, 4.9cqw, 45px);
|
|
167
192
|
line-height: 1.2;
|
|
168
193
|
font-weight: 400;
|
|
169
194
|
text-align: center;
|
|
170
195
|
margin: 0;
|
|
171
|
-
letter-spacing: 0;
|
|
196
|
+
letter-spacing: -0.01em;
|
|
172
197
|
}
|
|
173
198
|
|
|
174
|
-
.paper-
|
|
175
|
-
font-size: clamp(11px, 1.4cqw, 12px);
|
|
176
|
-
font-style: italic;
|
|
199
|
+
.paper-author-contact-note {
|
|
177
200
|
text-align: center;
|
|
201
|
+
margin: 0;
|
|
202
|
+
font-size: clamp(8.5pt, 1.45cqw, 9.5pt);
|
|
178
203
|
color: var(--openpress-color-muted);
|
|
204
|
+
line-height: 1.35;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.paper-author-line {
|
|
179
208
|
margin: 0;
|
|
209
|
+
text-align: center;
|
|
210
|
+
font-size: clamp(11px, 2cqw, 13px);
|
|
211
|
+
line-height: 1.45;
|
|
212
|
+
font-weight: 500;
|
|
180
213
|
}
|
|
181
214
|
|
|
182
|
-
.paper-
|
|
215
|
+
.paper-author-affiliations {
|
|
216
|
+
margin: 0;
|
|
183
217
|
list-style: none;
|
|
184
218
|
padding: 0;
|
|
185
|
-
margin: clamp(8px, 1.6cqw, 16px) 0 0;
|
|
186
|
-
display: grid;
|
|
187
|
-
grid-template-columns: repeat(3, 1fr);
|
|
188
|
-
gap: clamp(10px, 1.4cqw, 16px) clamp(8px, 1.2cqw, 14px);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
.paper-author {
|
|
192
219
|
display: flex;
|
|
193
220
|
flex-direction: column;
|
|
194
|
-
|
|
221
|
+
gap: 1mm;
|
|
195
222
|
text-align: center;
|
|
196
|
-
font-size: clamp(10.5px, 1.3cqw, 11.5px);
|
|
197
|
-
line-height: 1.35;
|
|
198
|
-
gap: 0;
|
|
199
223
|
}
|
|
200
224
|
|
|
201
|
-
.paper-author
|
|
202
|
-
|
|
203
|
-
|
|
225
|
+
.paper-author {
|
|
226
|
+
display: flex;
|
|
227
|
+
flex-direction: column;
|
|
204
228
|
}
|
|
205
229
|
|
|
206
230
|
.paper-author-affiliation {
|
|
207
|
-
font-style: italic;
|
|
208
|
-
margin: 0;
|
|
209
|
-
color: var(--openpress-color-ink);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
.paper-author-location,
|
|
213
|
-
.paper-author-contact {
|
|
214
231
|
margin: 0;
|
|
215
232
|
color: var(--openpress-color-ink);
|
|
233
|
+
font-family: var(--openpress-font-body);
|
|
234
|
+
font-size: clamp(9px, 1.6cqw, 10px);
|
|
235
|
+
line-height: 1.42;
|
|
216
236
|
}
|
|
217
237
|
|
|
218
238
|
.paper-abstract,
|
|
219
|
-
.paper-
|
|
239
|
+
.paper-nontechnical-summary,
|
|
240
|
+
.paper-contributions,
|
|
241
|
+
.paper-abstract > p,
|
|
242
|
+
.paper-nontechnical-summary > p,
|
|
243
|
+
.paper-contributions > p {
|
|
220
244
|
margin-top: clamp(8px, 1.6cqw, 14px);
|
|
221
|
-
font-
|
|
245
|
+
font-family: var(--openpress-font-body);
|
|
246
|
+
font-size: clamp(10px, 1.7cqw, 11px);
|
|
222
247
|
line-height: 1.45;
|
|
248
|
+
text-align: justify;
|
|
249
|
+
text-justify: inter-word;
|
|
223
250
|
}
|
|
224
251
|
|
|
225
|
-
.paper-abstract p,
|
|
226
|
-
.paper-
|
|
252
|
+
.paper-abstract > p,
|
|
253
|
+
.paper-nontechnical-summary > p,
|
|
254
|
+
.paper-contributions > p {
|
|
227
255
|
margin: 0;
|
|
228
|
-
text-indent:
|
|
229
|
-
font-style: italic;
|
|
256
|
+
text-indent: 0.9em;
|
|
230
257
|
}
|
|
231
258
|
|
|
232
259
|
.paper-abstract-label {
|
|
233
|
-
|
|
234
|
-
font-weight:
|
|
260
|
+
display: inline-block;
|
|
261
|
+
font-weight: 500;
|
|
262
|
+
text-transform: none;
|
|
235
263
|
}
|
|
236
264
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
max-width: none;
|
|
265
|
+
.paper-section-label {
|
|
266
|
+
font-family: var(--openpress-font-serif);
|
|
267
|
+
font-size: 0.95em;
|
|
268
|
+
font-weight: 500;
|
|
242
269
|
}
|
|
243
270
|
|
|
244
271
|
/* ─ academic-paper back cover ───────────────────────────────────────────── */
|
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
import { useCallback, useEffect, useMemo, useState, type MouseEvent as ReactMouseEvent } from "react";
|
|
2
|
-
import { getSourceBlockMap } from "./reactDocumentMetadata";
|
|
3
|
-
import type { ReaderDocument, SourceBlock } from "./types";
|
|
4
|
-
|
|
5
|
-
const DEFAULT_INSPECTOR_STORAGE_KEY = "openpress:inspector-mode";
|
|
6
|
-
|
|
7
|
-
export type InspectorIntent = "edit" | "delete" | "add";
|
|
8
|
-
export type InspectorPlacement = "block" | "before";
|
|
9
|
-
|
|
10
|
-
export interface InspectorTarget {
|
|
11
|
-
blockId: string;
|
|
12
|
-
placement: InspectorPlacement;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface InspectorState {
|
|
16
|
-
enabled: boolean;
|
|
17
|
-
inspectorMode: boolean;
|
|
18
|
-
selectedBlockId: string | null;
|
|
19
|
-
selectedBlock: SourceBlock | null;
|
|
20
|
-
selectedTarget: InspectorTarget | null;
|
|
21
|
-
commentIntent: InspectorIntent;
|
|
22
|
-
setInspectorMode: (enabled: boolean) => void;
|
|
23
|
-
toggleInspectorMode: () => void;
|
|
24
|
-
setCommentIntent: (intent: InspectorIntent) => void;
|
|
25
|
-
selectTarget: (target: InspectorTarget | null) => SourceBlock | null;
|
|
26
|
-
inspectTarget: (target: EventTarget | null) => SourceBlock | null;
|
|
27
|
-
handleClick: (event: ReactMouseEvent) => boolean;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface InspectorCommentResult {
|
|
31
|
-
ok: boolean;
|
|
32
|
-
comment?: {
|
|
33
|
-
id?: string;
|
|
34
|
-
timestamp?: string;
|
|
35
|
-
path?: string;
|
|
36
|
-
line?: number;
|
|
37
|
-
note?: string;
|
|
38
|
-
hint?: string;
|
|
39
|
-
};
|
|
40
|
-
message?: string;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface PendingComment {
|
|
44
|
-
id: string;
|
|
45
|
-
timestamp?: string;
|
|
46
|
-
path: string;
|
|
47
|
-
absolutePath?: string;
|
|
48
|
-
line: number;
|
|
49
|
-
marker?: string;
|
|
50
|
-
note: string;
|
|
51
|
-
hint?: string;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export interface CommentListResult {
|
|
55
|
-
ok: boolean;
|
|
56
|
-
comments?: PendingComment[];
|
|
57
|
-
message?: string;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export interface CommentClearResult {
|
|
61
|
-
ok: boolean;
|
|
62
|
-
removedCount: number;
|
|
63
|
-
comments?: PendingComment[];
|
|
64
|
-
message?: string;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export async function submitInspectorComment({
|
|
68
|
-
block,
|
|
69
|
-
note,
|
|
70
|
-
intent,
|
|
71
|
-
placement,
|
|
72
|
-
endpoint = "/__openpress/comment",
|
|
73
|
-
fetchImpl = globalThis.fetch?.bind(globalThis),
|
|
74
|
-
}: {
|
|
75
|
-
block: SourceBlock | null;
|
|
76
|
-
note: string;
|
|
77
|
-
intent?: InspectorIntent;
|
|
78
|
-
placement?: InspectorPlacement;
|
|
79
|
-
endpoint?: string;
|
|
80
|
-
fetchImpl?: typeof fetch;
|
|
81
|
-
}): Promise<InspectorCommentResult> {
|
|
82
|
-
if (!block) throw new Error("OpenPress inspector comment requires a selected block.");
|
|
83
|
-
const normalizedNote = note.trim();
|
|
84
|
-
if (!normalizedNote) throw new Error("OpenPress inspector comment note must not be empty.");
|
|
85
|
-
if (!block.path || !block.source?.line) throw new Error("OpenPress inspector selected block has no editable source location.");
|
|
86
|
-
if (typeof fetchImpl !== "function") throw new Error("OpenPress inspector comment endpoint is unavailable.");
|
|
87
|
-
|
|
88
|
-
const response = await fetchImpl(endpoint, {
|
|
89
|
-
method: "POST",
|
|
90
|
-
headers: { "Content-Type": "application/json" },
|
|
91
|
-
body: JSON.stringify({
|
|
92
|
-
target: {
|
|
93
|
-
blockId: block.id,
|
|
94
|
-
path: block.path,
|
|
95
|
-
source: block.source,
|
|
96
|
-
},
|
|
97
|
-
note: normalizedNote,
|
|
98
|
-
hint: formatInspectorHint({ intent, placement }),
|
|
99
|
-
}),
|
|
100
|
-
});
|
|
101
|
-
const result = await response.json().catch(() => null) as InspectorCommentResult | null;
|
|
102
|
-
if (!response.ok) {
|
|
103
|
-
throw new Error(result?.message ?? `OpenPress inspector comment failed with status ${response.status}`);
|
|
104
|
-
}
|
|
105
|
-
return result ?? { ok: true };
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export async function fetchInspectorComments({
|
|
109
|
-
endpoint = "/__openpress/comment",
|
|
110
|
-
fetchImpl = globalThis.fetch?.bind(globalThis),
|
|
111
|
-
}: {
|
|
112
|
-
endpoint?: string;
|
|
113
|
-
fetchImpl?: typeof fetch;
|
|
114
|
-
} = {}): Promise<PendingComment[]> {
|
|
115
|
-
if (typeof fetchImpl !== "function") throw new Error("OpenPress inspector comment endpoint is unavailable.");
|
|
116
|
-
|
|
117
|
-
const response = await fetchImpl(endpoint, { method: "GET" });
|
|
118
|
-
const result = await response.json().catch(() => null) as CommentListResult | null;
|
|
119
|
-
if (!response.ok) {
|
|
120
|
-
throw new Error(result?.message ?? `OpenPress inspector comment list failed with status ${response.status}`);
|
|
121
|
-
}
|
|
122
|
-
return Array.isArray(result?.comments) ? result.comments : [];
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export async function clearInspectorComment({
|
|
126
|
-
id,
|
|
127
|
-
all = false,
|
|
128
|
-
endpoint = "/__openpress/comment",
|
|
129
|
-
fetchImpl = globalThis.fetch?.bind(globalThis),
|
|
130
|
-
}: {
|
|
131
|
-
id?: string;
|
|
132
|
-
all?: boolean;
|
|
133
|
-
endpoint?: string;
|
|
134
|
-
fetchImpl?: typeof fetch;
|
|
135
|
-
} = {}): Promise<CommentClearResult> {
|
|
136
|
-
if (typeof fetchImpl !== "function") throw new Error("OpenPress inspector comment endpoint is unavailable.");
|
|
137
|
-
if (!all && !id) throw new Error("OpenPress inspector comment clear requires an id or all=true.");
|
|
138
|
-
|
|
139
|
-
const response = await fetchImpl(endpoint, {
|
|
140
|
-
method: "DELETE",
|
|
141
|
-
headers: { "Content-Type": "application/json" },
|
|
142
|
-
body: JSON.stringify(all ? { all: true } : { id }),
|
|
143
|
-
});
|
|
144
|
-
const result = await response.json().catch(() => null) as CommentClearResult | null;
|
|
145
|
-
if (!response.ok) {
|
|
146
|
-
throw new Error(result?.message ?? `OpenPress inspector comment clear failed with status ${response.status}`);
|
|
147
|
-
}
|
|
148
|
-
return result ?? { ok: true, removedCount: 0 };
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export async function updateInspectorComment({
|
|
152
|
-
id,
|
|
153
|
-
note,
|
|
154
|
-
intent,
|
|
155
|
-
placement,
|
|
156
|
-
endpoint = "/__openpress/comment",
|
|
157
|
-
fetchImpl = globalThis.fetch?.bind(globalThis),
|
|
158
|
-
}: {
|
|
159
|
-
id: string;
|
|
160
|
-
note: string;
|
|
161
|
-
intent?: InspectorIntent;
|
|
162
|
-
placement?: InspectorPlacement;
|
|
163
|
-
endpoint?: string;
|
|
164
|
-
fetchImpl?: typeof fetch;
|
|
165
|
-
}): Promise<InspectorCommentResult> {
|
|
166
|
-
const normalizedNote = note.trim();
|
|
167
|
-
if (!id.trim()) throw new Error("OpenPress inspector comment update requires an id.");
|
|
168
|
-
if (!normalizedNote) throw new Error("OpenPress inspector comment note must not be empty.");
|
|
169
|
-
if (typeof fetchImpl !== "function") throw new Error("OpenPress inspector comment endpoint is unavailable.");
|
|
170
|
-
|
|
171
|
-
const response = await fetchImpl(endpoint, {
|
|
172
|
-
method: "PATCH",
|
|
173
|
-
headers: { "Content-Type": "application/json" },
|
|
174
|
-
body: JSON.stringify({
|
|
175
|
-
id,
|
|
176
|
-
note: normalizedNote,
|
|
177
|
-
hint: formatInspectorHint({ intent, placement }),
|
|
178
|
-
}),
|
|
179
|
-
});
|
|
180
|
-
const result = await response.json().catch(() => null) as InspectorCommentResult | null;
|
|
181
|
-
if (!response.ok) {
|
|
182
|
-
throw new Error(result?.message ?? `OpenPress inspector comment update failed with status ${response.status}`);
|
|
183
|
-
}
|
|
184
|
-
return result ?? { ok: true };
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export function useInspector(
|
|
188
|
-
document: ReaderDocument,
|
|
189
|
-
{
|
|
190
|
-
enabled = false,
|
|
191
|
-
storageKey = DEFAULT_INSPECTOR_STORAGE_KEY,
|
|
192
|
-
}: {
|
|
193
|
-
enabled?: boolean;
|
|
194
|
-
storageKey?: string;
|
|
195
|
-
} = {},
|
|
196
|
-
): InspectorState {
|
|
197
|
-
const blockMap = useMemo(() => getSourceBlockMap(document), [document]);
|
|
198
|
-
const [inspectorMode, setInspectorModeState] = useState(() => {
|
|
199
|
-
if (!enabled || typeof window === "undefined") return false;
|
|
200
|
-
return window.localStorage.getItem(storageKey) === "on";
|
|
201
|
-
});
|
|
202
|
-
const [selectedTarget, setSelectedTarget] = useState<InspectorTarget | null>(null);
|
|
203
|
-
const [commentIntent, setCommentIntent] = useState<InspectorIntent>("edit");
|
|
204
|
-
|
|
205
|
-
useEffect(() => {
|
|
206
|
-
if (!enabled && inspectorMode) setInspectorModeState(false);
|
|
207
|
-
}, [enabled, inspectorMode]);
|
|
208
|
-
|
|
209
|
-
const setInspectorMode = useCallback((nextEnabled: boolean) => {
|
|
210
|
-
setInspectorModeState(nextEnabled);
|
|
211
|
-
if (typeof window !== "undefined") {
|
|
212
|
-
window.localStorage.setItem(storageKey, nextEnabled ? "on" : "off");
|
|
213
|
-
}
|
|
214
|
-
if (!nextEnabled) setSelectedTarget(null);
|
|
215
|
-
}, [storageKey]);
|
|
216
|
-
|
|
217
|
-
const selectTarget = useCallback((target: InspectorTarget | null) => {
|
|
218
|
-
setSelectedTarget(target);
|
|
219
|
-
if (!target) return null;
|
|
220
|
-
setCommentIntent(target.placement === "before" ? "add" : "edit");
|
|
221
|
-
const sourceBlock = blockMap[target.blockId] ?? null;
|
|
222
|
-
return sourceBlock;
|
|
223
|
-
}, [blockMap]);
|
|
224
|
-
|
|
225
|
-
const inspectTarget = useCallback((target: EventTarget | null) => {
|
|
226
|
-
const inspectorTarget = findInspectorTarget(target);
|
|
227
|
-
return selectTarget(inspectorTarget);
|
|
228
|
-
}, [selectTarget]);
|
|
229
|
-
|
|
230
|
-
const handleClick = useCallback((event: ReactMouseEvent) => {
|
|
231
|
-
if (!enabled || !inspectorMode) return false;
|
|
232
|
-
const inspectorTarget = findInspectorTarget(event.target);
|
|
233
|
-
if (!inspectorTarget) return false;
|
|
234
|
-
selectTarget(inspectorTarget);
|
|
235
|
-
event.preventDefault();
|
|
236
|
-
event.stopPropagation();
|
|
237
|
-
return true;
|
|
238
|
-
}, [enabled, inspectorMode, selectTarget]);
|
|
239
|
-
|
|
240
|
-
const selectedBlockId = selectedTarget?.blockId ?? null;
|
|
241
|
-
const selectedBlock = selectedBlockId ? (blockMap[selectedBlockId] ?? null) : null;
|
|
242
|
-
|
|
243
|
-
return {
|
|
244
|
-
enabled,
|
|
245
|
-
inspectorMode: enabled && inspectorMode,
|
|
246
|
-
selectedBlockId,
|
|
247
|
-
selectedBlock,
|
|
248
|
-
selectedTarget,
|
|
249
|
-
commentIntent,
|
|
250
|
-
setInspectorMode,
|
|
251
|
-
toggleInspectorMode: () => setInspectorMode(!inspectorMode),
|
|
252
|
-
setCommentIntent,
|
|
253
|
-
selectTarget,
|
|
254
|
-
inspectTarget,
|
|
255
|
-
handleClick,
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
export function findInspectorTarget(target: EventTarget | null): InspectorTarget | null {
|
|
260
|
-
if (typeof Element === "undefined") return null;
|
|
261
|
-
if (!(target instanceof Element)) return null;
|
|
262
|
-
const insertTarget = target.closest<HTMLElement>("[data-openpress-insert-before-block-id]");
|
|
263
|
-
const insertBeforeBlockId = insertTarget?.dataset.openpressInsertBeforeBlockId;
|
|
264
|
-
if (insertBeforeBlockId) return { blockId: insertBeforeBlockId, placement: "before" };
|
|
265
|
-
|
|
266
|
-
const element = target.closest<HTMLElement>("[data-openpress-block-id]");
|
|
267
|
-
const blockId = element?.dataset.openpressBlockId;
|
|
268
|
-
return blockId ? { blockId, placement: "block" } : null;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
export function formatInspectorHint({
|
|
272
|
-
intent,
|
|
273
|
-
placement,
|
|
274
|
-
}: {
|
|
275
|
-
intent?: InspectorIntent;
|
|
276
|
-
placement?: InspectorPlacement;
|
|
277
|
-
} = {}) {
|
|
278
|
-
const parts = ["openpress-react-inspector"];
|
|
279
|
-
if (intent) parts.push(`intent=${intent}`);
|
|
280
|
-
if (placement) parts.push(`placement=${placement}`);
|
|
281
|
-
return parts.join(" ");
|
|
282
|
-
}
|