@open-press/cli 1.0.0 → 1.1.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 +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,77 +0,0 @@
|
|
|
1
|
-
import { type ComponentPropsWithoutRef } from "react";
|
|
2
|
-
import { cn } from "../core/cn";
|
|
3
|
-
|
|
4
|
-
type PanelProps = ComponentPropsWithoutRef<"section">;
|
|
5
|
-
type PanelHeaderProps = ComponentPropsWithoutRef<"header">;
|
|
6
|
-
type PanelDivProps = ComponentPropsWithoutRef<"div">;
|
|
7
|
-
type PanelTextProps = ComponentPropsWithoutRef<"p">;
|
|
8
|
-
type PanelTitleProps = ComponentPropsWithoutRef<"h2">;
|
|
9
|
-
type PanelSectionTitleProps = ComponentPropsWithoutRef<"h3">;
|
|
10
|
-
type PanelButtonProps = ComponentPropsWithoutRef<"button">;
|
|
11
|
-
|
|
12
|
-
function PanelRoot({ className, ...props }: PanelProps) {
|
|
13
|
-
return <section {...props} className={cn("openpress-panel", className)} />;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function PanelHeader({ className, ...props }: PanelHeaderProps) {
|
|
17
|
-
return <header {...props} className={cn("openpress-panel-header", className)} />;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function PanelKicker({ className, ...props }: ComponentPropsWithoutRef<"span">) {
|
|
21
|
-
return <span {...props} className={cn("openpress-panel-kicker", className)} />;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function PanelTitle({ className, ...props }: PanelTitleProps) {
|
|
25
|
-
return <h2 {...props} className={cn("openpress-panel-title", className)} />;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function PanelDescription({ className, ...props }: PanelTextProps) {
|
|
29
|
-
return <p {...props} className={cn("openpress-panel-description", className)} />;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function PanelActions({ className, ...props }: PanelDivProps) {
|
|
33
|
-
return <div {...props} className={cn("openpress-panel-actions", className)} />;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function PanelActionButton({ className, ...props }: PanelButtonProps) {
|
|
37
|
-
return <button {...props} className={cn("openpress-panel-action-button", className)} />;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function PanelBody({ className, ...props }: PanelDivProps) {
|
|
41
|
-
return <div {...props} className={cn("openpress-panel-body", className)} />;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function PanelSection({ className, ...props }: PanelProps) {
|
|
45
|
-
return <section {...props} className={cn("openpress-panel-section", className)} />;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function PanelSectionTitle({ className, ...props }: PanelSectionTitleProps) {
|
|
49
|
-
return <h3 {...props} className={cn("openpress-panel-section-title", className)} />;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function PanelSectionDescription({ className, ...props }: PanelTextProps) {
|
|
53
|
-
return <p {...props} className={cn("openpress-panel-section-description", className)} />;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function PanelEmpty({ className, ...props }: PanelDivProps) {
|
|
57
|
-
return <div {...props} className={cn("openpress-panel-empty", className)} />;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function PanelError({ className, role = "alert", ...props }: PanelTextProps) {
|
|
61
|
-
return <p {...props} role={role} className={cn("openpress-panel-error", className)} />;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export const Panel = Object.assign(PanelRoot, {
|
|
65
|
-
Header: PanelHeader,
|
|
66
|
-
Kicker: PanelKicker,
|
|
67
|
-
Title: PanelTitle,
|
|
68
|
-
Description: PanelDescription,
|
|
69
|
-
Actions: PanelActions,
|
|
70
|
-
ActionButton: PanelActionButton,
|
|
71
|
-
Body: PanelBody,
|
|
72
|
-
Section: PanelSection,
|
|
73
|
-
SectionTitle: PanelSectionTitle,
|
|
74
|
-
SectionDescription: PanelSectionDescription,
|
|
75
|
-
Empty: PanelEmpty,
|
|
76
|
-
Error: PanelError,
|
|
77
|
-
});
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
type BrowserFrameCallback = (timestamp: number) => void;
|
|
2
|
-
|
|
3
|
-
export function scheduleBrowserFrame(callback: BrowserFrameCallback) {
|
|
4
|
-
if (canUseAnimationFrame()) {
|
|
5
|
-
const frame = window.requestAnimationFrame(callback);
|
|
6
|
-
return () => window.cancelAnimationFrame(frame);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const timer = window.setTimeout(() => callback(now()), 0);
|
|
10
|
-
return () => window.clearTimeout(timer);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function waitForBrowserFrame() {
|
|
14
|
-
return new Promise<void>((resolve) => {
|
|
15
|
-
scheduleBrowserFrame(() => resolve());
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function canUseAnimationFrame() {
|
|
20
|
-
return (
|
|
21
|
-
typeof window !== "undefined" &&
|
|
22
|
-
typeof window.requestAnimationFrame === "function" &&
|
|
23
|
-
typeof document !== "undefined" &&
|
|
24
|
-
document.visibilityState !== "hidden"
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function now() {
|
|
29
|
-
return typeof performance !== "undefined" && typeof performance.now === "function"
|
|
30
|
-
? performance.now()
|
|
31
|
-
: Date.now();
|
|
32
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export function isLocalWorkspaceHost(hostname: string) {
|
|
2
|
-
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1";
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export function isWorkspaceModeLocation(location: Pick<Location, "hostname" | "search">) {
|
|
6
|
-
return isLocalWorkspaceHost(location.hostname) && new URLSearchParams(location.search).has("dev");
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function isPrintModeLocation(location: Pick<Location, "search">) {
|
|
10
|
-
return new URLSearchParams(location.search).has("print");
|
|
11
|
-
}
|
|
@@ -1,506 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
useMemo,
|
|
3
|
-
useRef,
|
|
4
|
-
useState,
|
|
5
|
-
type CSSProperties,
|
|
6
|
-
} from "react";
|
|
7
|
-
import { ExternalLink, Home, MousePointer2, Ruler } from "lucide-react";
|
|
8
|
-
import {
|
|
9
|
-
getProjectIdentity,
|
|
10
|
-
resolveAnchorPageIndex,
|
|
11
|
-
type DeploymentInfo,
|
|
12
|
-
type HtmlPageBlock,
|
|
13
|
-
type ReaderDocument,
|
|
14
|
-
} from "../document-model";
|
|
15
|
-
import { InlineInspectorLayer, useInspector, useInspectorComments } from "./inspector";
|
|
16
|
-
import { ProjectEntryPanel } from "./project";
|
|
17
|
-
import {
|
|
18
|
-
Bookmarks,
|
|
19
|
-
CurrentPagePanel,
|
|
20
|
-
PageThumbnails,
|
|
21
|
-
PUBLIC_DRAWER_BREAKPOINT,
|
|
22
|
-
PublicPage,
|
|
23
|
-
useReaderRuntime,
|
|
24
|
-
usePageViewportScale,
|
|
25
|
-
useViewMode,
|
|
26
|
-
type PageLayoutMode,
|
|
27
|
-
} from "../reader";
|
|
28
|
-
import {
|
|
29
|
-
ReaderStage,
|
|
30
|
-
InlineSourceEditorLayer,
|
|
31
|
-
useDocumentWorkbenchModel,
|
|
32
|
-
useInlineDocumentEditor,
|
|
33
|
-
type InlineDocumentEditStatus,
|
|
34
|
-
type InlineDocumentSourceTarget,
|
|
35
|
-
} from "./document";
|
|
36
|
-
import {
|
|
37
|
-
DeploymentControl,
|
|
38
|
-
ExportImageControl,
|
|
39
|
-
PageZoomControl,
|
|
40
|
-
SearchControl,
|
|
41
|
-
useDeploymentWorkbench,
|
|
42
|
-
} from "./actions";
|
|
43
|
-
import { PendingCommentsPanel, WorkbenchControlPanel, type WorkbenchPanel } from "./panels";
|
|
44
|
-
import { WorkbenchShell } from "./shell";
|
|
45
|
-
import {
|
|
46
|
-
formatPageGeometrySpec,
|
|
47
|
-
formatInspectorSelection,
|
|
48
|
-
} from "./workbenchFormatters";
|
|
49
|
-
|
|
50
|
-
export function HtmlWorkbench({
|
|
51
|
-
document,
|
|
52
|
-
pages,
|
|
53
|
-
style,
|
|
54
|
-
devMode,
|
|
55
|
-
deploymentInfo,
|
|
56
|
-
onDocumentRefresh,
|
|
57
|
-
onBackToWorkspace,
|
|
58
|
-
extraControlPanels,
|
|
59
|
-
}: {
|
|
60
|
-
document: ReaderDocument;
|
|
61
|
-
pages: Array<HtmlPageBlock>;
|
|
62
|
-
style: CSSProperties;
|
|
63
|
-
devMode: boolean;
|
|
64
|
-
deploymentInfo: DeploymentInfo;
|
|
65
|
-
onDocumentRefresh?: () => void | Promise<void>;
|
|
66
|
-
onBackToWorkspace?: () => void;
|
|
67
|
-
// Append extra panels into the right-side control panel. Built-in panels
|
|
68
|
-
// (pending comments + project entry) render first; extra panels render
|
|
69
|
-
// after them in the supplied order.
|
|
70
|
-
extraControlPanels?: WorkbenchPanel[];
|
|
71
|
-
}) {
|
|
72
|
-
const sourceContainerRef = useRef<HTMLDivElement | null>(null);
|
|
73
|
-
const displayPages = pages;
|
|
74
|
-
const { viewMode } = useViewMode();
|
|
75
|
-
const {
|
|
76
|
-
mediaAssets,
|
|
77
|
-
anchorPageMap,
|
|
78
|
-
projectComponentUsages,
|
|
79
|
-
bookmarks,
|
|
80
|
-
sourceBlockMap,
|
|
81
|
-
sourceBlocksByPath,
|
|
82
|
-
projectMentionItems,
|
|
83
|
-
} = useDocumentWorkbenchModel(document, displayPages);
|
|
84
|
-
const inspector = useInspector(document, { enabled: devMode });
|
|
85
|
-
const reader = useReaderRuntime({
|
|
86
|
-
pageCount: Math.max(displayPages.length, 1),
|
|
87
|
-
leftPanelBreakpoint: PUBLIC_DRAWER_BREAKPOINT,
|
|
88
|
-
rightPanelBreakpoint: PUBLIC_DRAWER_BREAKPOINT,
|
|
89
|
-
});
|
|
90
|
-
const [pageLayoutMode, setPageLayoutMode] = useState<PageLayoutMode>("single");
|
|
91
|
-
const pageViewport = usePageViewportScale({
|
|
92
|
-
stageRef: reader.stageRef,
|
|
93
|
-
pageContainerRef: sourceContainerRef,
|
|
94
|
-
pageCount: displayPages.length,
|
|
95
|
-
layoutMode: pageLayoutMode,
|
|
96
|
-
});
|
|
97
|
-
const deployment = useDeploymentWorkbench({ deploymentInfo });
|
|
98
|
-
const [inlineEditStatus, setInlineEditStatus] = useState<InlineDocumentEditStatus>({ state: "idle" });
|
|
99
|
-
const [sourceEditorTarget, setSourceEditorTarget] = useState<InlineDocumentSourceTarget | null>(null);
|
|
100
|
-
|
|
101
|
-
const projectIdentity = getProjectIdentity(document.meta);
|
|
102
|
-
const pageGeometry = formatPageGeometrySpec(document.theme);
|
|
103
|
-
const inspectorSelectionLabel = formatInspectorSelection(
|
|
104
|
-
inspector.selectedBlock,
|
|
105
|
-
inspector.selectedObjectEntity,
|
|
106
|
-
);
|
|
107
|
-
const inspectorToolbarExpanded = inspector.inspectorMode;
|
|
108
|
-
const editStatusMessage = formatInlineEditStatus(inlineEditStatus);
|
|
109
|
-
|
|
110
|
-
// Inline source editing and inspector commenting are mutually exclusive
|
|
111
|
-
// interaction modes on the same blocks. While inspector mode is on, the
|
|
112
|
-
// user is selecting blocks to comment on — keeping contenteditable + the
|
|
113
|
-
// text cursor active would (a) show the I-beam instead of the inspector
|
|
114
|
-
// crosshair, (b) allow accidental text selection that paints the whole
|
|
115
|
-
// page (notably covers) with the browser ::selection color.
|
|
116
|
-
const inlineEditEnabled = devMode && !inspector.inspectorMode;
|
|
117
|
-
useInlineDocumentEditor({
|
|
118
|
-
enabled: inlineEditEnabled,
|
|
119
|
-
sourceContainerRef,
|
|
120
|
-
sourceBlockMap,
|
|
121
|
-
onStatusChange: setInlineEditStatus,
|
|
122
|
-
onOpenSourceBlock: setSourceEditorTarget,
|
|
123
|
-
onDocumentEdited: onDocumentRefresh,
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
const selectWorkspacePage = (pageIndex: number, options?: { behavior?: ScrollBehavior }) => {
|
|
127
|
-
reader.setPage(pageIndex, options);
|
|
128
|
-
if (
|
|
129
|
-
typeof window !== "undefined"
|
|
130
|
-
&& window.innerWidth < PUBLIC_DRAWER_BREAKPOINT
|
|
131
|
-
&& reader.rightPanelOpen
|
|
132
|
-
) {
|
|
133
|
-
reader.toggleRightPanel();
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
const selectWorkspaceAnchor = (anchorId: string, pageIndex?: number) => {
|
|
138
|
-
const targetPageIndex = resolveAnchorPageIndex(anchorPageMap, displayPages.length, anchorId, pageIndex);
|
|
139
|
-
if (targetPageIndex === null) return false;
|
|
140
|
-
selectWorkspacePage(targetPageIndex, { behavior: "smooth" });
|
|
141
|
-
return true;
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
const comments = useInspectorComments({
|
|
145
|
-
devMode,
|
|
146
|
-
inspector,
|
|
147
|
-
sourceBlockMap,
|
|
148
|
-
sourceBlocksByPath,
|
|
149
|
-
sourceContainerRef,
|
|
150
|
-
onSelectWorkspacePage: selectWorkspacePage,
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
// Stabilize the controller objects so memoized InlineInspectorLayer can skip
|
|
154
|
-
// re-rendering when nothing observable changed.
|
|
155
|
-
const inspectorLayerComments = useMemo(() => ({
|
|
156
|
-
saved: comments.inlineSavedComments,
|
|
157
|
-
active: comments.activeInlineSavedComment ?? null,
|
|
158
|
-
status: comments.inspectorCommentStatus,
|
|
159
|
-
statusMessage: comments.inspectorCommentStatusMessage,
|
|
160
|
-
totalCount: comments.pendingComments.length,
|
|
161
|
-
onOpenSaved: comments.handleOpenInlineSavedComment,
|
|
162
|
-
onRemoveSaved: comments.handleRemoveInlineSavedComment,
|
|
163
|
-
}), [
|
|
164
|
-
comments.activeInlineSavedComment,
|
|
165
|
-
comments.handleOpenInlineSavedComment,
|
|
166
|
-
comments.handleRemoveInlineSavedComment,
|
|
167
|
-
comments.inlineSavedComments,
|
|
168
|
-
comments.inspectorCommentStatus,
|
|
169
|
-
comments.inspectorCommentStatusMessage,
|
|
170
|
-
comments.pendingComments.length,
|
|
171
|
-
]);
|
|
172
|
-
const inspectorLayerComposer = useMemo(() => ({
|
|
173
|
-
text: comments.inspectorCommentText,
|
|
174
|
-
submitDisabled: comments.inspectorCommentDisabled,
|
|
175
|
-
mentionItems: projectMentionItems,
|
|
176
|
-
onTextChange: comments.setInspectorCommentText,
|
|
177
|
-
onSubmit: comments.handleSubmitInspectorComment,
|
|
178
|
-
}), [
|
|
179
|
-
comments.handleSubmitInspectorComment,
|
|
180
|
-
comments.inspectorCommentDisabled,
|
|
181
|
-
comments.inspectorCommentText,
|
|
182
|
-
comments.setInspectorCommentText,
|
|
183
|
-
projectMentionItems,
|
|
184
|
-
]);
|
|
185
|
-
|
|
186
|
-
const currentSourcePath = displayPages[reader.currentPageIndex]?.source;
|
|
187
|
-
// Stabilize the panel registry across keystrokes in the inspector
|
|
188
|
-
// composer. Without `useMemo` the registry array (and the JSX closures
|
|
189
|
-
// inside) would be recreated on every Workbench render, so typing a
|
|
190
|
-
// single character would force WorkbenchControlPanel + every panel to
|
|
191
|
-
// diff fresh React elements.
|
|
192
|
-
const builtInControlPanels = useMemo<WorkbenchPanel[]>(() => [
|
|
193
|
-
{
|
|
194
|
-
id: "pending-comments",
|
|
195
|
-
render: () => (
|
|
196
|
-
<PendingCommentsPanel
|
|
197
|
-
comments={comments.pendingComments}
|
|
198
|
-
status={comments.commentsStatus}
|
|
199
|
-
error={comments.commentsError}
|
|
200
|
-
onClear={comments.clearPendingComment}
|
|
201
|
-
onSelect={comments.handleSelectPendingComment}
|
|
202
|
-
/>
|
|
203
|
-
),
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
id: "project-entry",
|
|
207
|
-
render: () => (
|
|
208
|
-
<ProjectEntryPanel
|
|
209
|
-
mediaAssets={mediaAssets}
|
|
210
|
-
componentUsages={projectComponentUsages}
|
|
211
|
-
mentionItems={projectMentionItems}
|
|
212
|
-
currentSource={currentSourcePath}
|
|
213
|
-
onCommentSubmitted={comments.refreshPendingComments}
|
|
214
|
-
/>
|
|
215
|
-
),
|
|
216
|
-
},
|
|
217
|
-
], [
|
|
218
|
-
comments.clearPendingComment,
|
|
219
|
-
comments.commentsError,
|
|
220
|
-
comments.commentsStatus,
|
|
221
|
-
comments.handleSelectPendingComment,
|
|
222
|
-
comments.pendingComments,
|
|
223
|
-
comments.refreshPendingComments,
|
|
224
|
-
currentSourcePath,
|
|
225
|
-
mediaAssets,
|
|
226
|
-
projectComponentUsages,
|
|
227
|
-
projectMentionItems,
|
|
228
|
-
]);
|
|
229
|
-
const controlPanels = useMemo(
|
|
230
|
-
() => (extraControlPanels ? [...builtInControlPanels, ...extraControlPanels] : builtInControlPanels),
|
|
231
|
-
[builtInControlPanels, extraControlPanels],
|
|
232
|
-
);
|
|
233
|
-
|
|
234
|
-
// Memoize so composer keystrokes (which only flip `comments.inspectorCommentText`)
|
|
235
|
-
// don't rebuild the toolbar JSX. The toolbar depends on deploy/page/zoom
|
|
236
|
-
// state and inspector mode, but never on the composer draft text.
|
|
237
|
-
const toolbarActions = useMemo(() => (
|
|
238
|
-
<>
|
|
239
|
-
{onBackToWorkspace ? (
|
|
240
|
-
<div className="openpress-workbench-toolbar__group" aria-label="工作台導覽">
|
|
241
|
-
<button
|
|
242
|
-
type="button"
|
|
243
|
-
className="openpress-workbench-toolbar-action openpress-workbench-toolbar-action--back"
|
|
244
|
-
data-openpress-back-to-workspace
|
|
245
|
-
onClick={onBackToWorkspace}
|
|
246
|
-
title="回到工作台"
|
|
247
|
-
aria-label="回到工作台"
|
|
248
|
-
>
|
|
249
|
-
<Home aria-hidden="true" />
|
|
250
|
-
<span className="openpress-workbench-toolbar-action__label">工作台</span>
|
|
251
|
-
</button>
|
|
252
|
-
</div>
|
|
253
|
-
) : null}
|
|
254
|
-
<div className="openpress-workbench-toolbar__group" aria-label="輸出">
|
|
255
|
-
<button
|
|
256
|
-
type="button"
|
|
257
|
-
className="openpress-workbench-toolbar-action"
|
|
258
|
-
data-openpress-public-export
|
|
259
|
-
data-openpress-toolbar-expanded={deployment.pdfToolbarExpanded ? "true" : "false"}
|
|
260
|
-
data-openpress-toolbar-active={deployment.pdfToolbarExpanded ? "true" : "false"}
|
|
261
|
-
disabled={deployment.pdfButtonDisabled}
|
|
262
|
-
onClick={deployment.handleOpenWorkbenchPdf}
|
|
263
|
-
title={deployment.pdfButtonText}
|
|
264
|
-
aria-label={deployment.pdfButtonText}
|
|
265
|
-
>
|
|
266
|
-
<ExternalLink aria-hidden="true" />
|
|
267
|
-
<span className="openpress-workbench-toolbar-action__label">{deployment.pdfButtonText}</span>
|
|
268
|
-
{deployment.pdfStatusMessage ? (
|
|
269
|
-
<span
|
|
270
|
-
className="openpress-dev-pdf-status"
|
|
271
|
-
data-openpress-pdf-status={deployment.pdfActionStatus}
|
|
272
|
-
role="status"
|
|
273
|
-
aria-live="polite"
|
|
274
|
-
>
|
|
275
|
-
<span className="openpress-dev-pdf-status__spinner" aria-hidden="true" />
|
|
276
|
-
<span>{deployment.pdfStatusMessage}</span>
|
|
277
|
-
</span>
|
|
278
|
-
) : null}
|
|
279
|
-
</button>
|
|
280
|
-
<ExportImageControl
|
|
281
|
-
currentPageIndex={reader.currentPageIndex}
|
|
282
|
-
currentPageLabel={reader.currentPageLabel}
|
|
283
|
-
pressTitle={projectIdentity.name}
|
|
284
|
-
/>
|
|
285
|
-
</div>
|
|
286
|
-
<div className="openpress-workbench-toolbar__group openpress-workbench-toolbar__group--page" aria-label="頁面規格">
|
|
287
|
-
<button
|
|
288
|
-
type="button"
|
|
289
|
-
className="openpress-workbench-page-geometry"
|
|
290
|
-
data-openpress-page-geometry
|
|
291
|
-
title={pageGeometry.title}
|
|
292
|
-
aria-label={`頁面規格 ${pageGeometry.title}`}
|
|
293
|
-
>
|
|
294
|
-
<Ruler aria-hidden="true" />
|
|
295
|
-
<span className="openpress-workbench-page-geometry__label">{pageGeometry.label}</span>
|
|
296
|
-
<span className="openpress-workbench-page-geometry__dimensions">{pageGeometry.dimensions}</span>
|
|
297
|
-
</button>
|
|
298
|
-
<PageZoomControl
|
|
299
|
-
scaleMode={pageViewport.scaleMode}
|
|
300
|
-
scaleLabel={pageViewport.scaleLabel}
|
|
301
|
-
pageLayoutMode={pageLayoutMode}
|
|
302
|
-
onScaleModeChange={pageViewport.setScaleMode}
|
|
303
|
-
onPageLayoutModeChange={setPageLayoutMode}
|
|
304
|
-
/>
|
|
305
|
-
</div>
|
|
306
|
-
<div className="openpress-workbench-toolbar__group openpress-workbench-toolbar__group--right" aria-label="工作台狀態與發布">
|
|
307
|
-
{devMode ? (
|
|
308
|
-
<SearchControl
|
|
309
|
-
sourceBlocksByPath={sourceBlocksByPath}
|
|
310
|
-
onSelectPage={selectWorkspacePage}
|
|
311
|
-
/>
|
|
312
|
-
) : null}
|
|
313
|
-
{devMode && editStatusMessage ? (
|
|
314
|
-
<span
|
|
315
|
-
className="openpress-dev-edit-status openpress-dev-edit-status--toolbar"
|
|
316
|
-
data-openpress-edit-status={inlineEditStatus.state}
|
|
317
|
-
role="status"
|
|
318
|
-
aria-live="polite"
|
|
319
|
-
>
|
|
320
|
-
{inlineEditStatus.state === "saving" ? <span className="openpress-dev-edit-status__spinner" aria-hidden="true" /> : null}
|
|
321
|
-
<span>{editStatusMessage}</span>
|
|
322
|
-
</span>
|
|
323
|
-
) : null}
|
|
324
|
-
{devMode ? (
|
|
325
|
-
<button
|
|
326
|
-
type="button"
|
|
327
|
-
className="openpress-workbench-toolbar-action"
|
|
328
|
-
data-openpress-inspector-toggle
|
|
329
|
-
data-openpress-inspector-active={inspector.inspectorMode ? "true" : "false"}
|
|
330
|
-
data-openpress-toolbar-expanded={inspectorToolbarExpanded ? "true" : "false"}
|
|
331
|
-
data-openpress-toolbar-active={inspectorToolbarExpanded ? "true" : "false"}
|
|
332
|
-
onClick={() => inspector.setInspectorMode(!inspector.inspectorMode)}
|
|
333
|
-
aria-pressed={inspector.inspectorMode}
|
|
334
|
-
title={inspector.inspectorMode ? "關閉註解" : "開啟註解"}
|
|
335
|
-
aria-label={inspector.inspectorMode ? "關閉註解" : "開啟註解"}
|
|
336
|
-
>
|
|
337
|
-
<MousePointer2 aria-hidden="true" />
|
|
338
|
-
<span className="openpress-workbench-toolbar-action__label">{inspector.inspectorMode ? "註解中" : "註解"}</span>
|
|
339
|
-
<span className="openpress-dev-inspector-status">{inspectorSelectionLabel}</span>
|
|
340
|
-
</button>
|
|
341
|
-
) : null}
|
|
342
|
-
{devMode && inspector.inspectorMode ? (
|
|
343
|
-
<span
|
|
344
|
-
className="openpress-dev-inspector-status"
|
|
345
|
-
role="status"
|
|
346
|
-
aria-live="polite"
|
|
347
|
-
data-openpress-inspector-comment-status={comments.inspectorCommentStatus}
|
|
348
|
-
>
|
|
349
|
-
{comments.inspectorCommentStatusMessage}
|
|
350
|
-
</span>
|
|
351
|
-
) : null}
|
|
352
|
-
{deployment.localDeployEnabled ? (
|
|
353
|
-
<DeploymentControl
|
|
354
|
-
info={deployment.currentDeploymentInfo}
|
|
355
|
-
status={deployment.status}
|
|
356
|
-
onDeploy={deployment.handleDeploy}
|
|
357
|
-
/>
|
|
358
|
-
) : null}
|
|
359
|
-
</div>
|
|
360
|
-
</>
|
|
361
|
-
), [
|
|
362
|
-
comments.inspectorCommentStatus,
|
|
363
|
-
comments.inspectorCommentStatusMessage,
|
|
364
|
-
deployment.currentDeploymentInfo,
|
|
365
|
-
deployment.handleDeploy,
|
|
366
|
-
deployment.handleOpenWorkbenchPdf,
|
|
367
|
-
deployment.localDeployEnabled,
|
|
368
|
-
deployment.pdfActionStatus,
|
|
369
|
-
deployment.pdfButtonDisabled,
|
|
370
|
-
deployment.pdfButtonText,
|
|
371
|
-
deployment.pdfStatusMessage,
|
|
372
|
-
deployment.pdfToolbarExpanded,
|
|
373
|
-
deployment.status,
|
|
374
|
-
devMode,
|
|
375
|
-
editStatusMessage,
|
|
376
|
-
inlineEditStatus.state,
|
|
377
|
-
inspector.inspectorMode,
|
|
378
|
-
inspector.setInspectorMode,
|
|
379
|
-
inspectorSelectionLabel,
|
|
380
|
-
inspectorToolbarExpanded,
|
|
381
|
-
pageGeometry.dimensions,
|
|
382
|
-
pageGeometry.label,
|
|
383
|
-
pageGeometry.title,
|
|
384
|
-
pageLayoutMode,
|
|
385
|
-
pageViewport.scaleLabel,
|
|
386
|
-
pageViewport.scaleMode,
|
|
387
|
-
pageViewport.setScaleMode,
|
|
388
|
-
selectWorkspacePage,
|
|
389
|
-
sourceBlocksByPath,
|
|
390
|
-
onBackToWorkspace,
|
|
391
|
-
reader.currentPageIndex,
|
|
392
|
-
reader.currentPageLabel,
|
|
393
|
-
projectIdentity.name,
|
|
394
|
-
]);
|
|
395
|
-
|
|
396
|
-
return (
|
|
397
|
-
<WorkbenchShell
|
|
398
|
-
style={style}
|
|
399
|
-
devMode={devMode}
|
|
400
|
-
viewMode={viewMode}
|
|
401
|
-
inspectorMode={inspector.inspectorMode}
|
|
402
|
-
editMode={inlineEditEnabled}
|
|
403
|
-
leftPanelOpen={reader.leftPanelOpen}
|
|
404
|
-
rightPanelOpen={reader.rightPanelOpen}
|
|
405
|
-
onToggleLeftPanel={reader.toggleLeftPanel}
|
|
406
|
-
onToggleRightPanel={reader.toggleRightPanel}
|
|
407
|
-
>
|
|
408
|
-
<WorkbenchShell.Toolbar>
|
|
409
|
-
{toolbarActions}
|
|
410
|
-
</WorkbenchShell.Toolbar>
|
|
411
|
-
|
|
412
|
-
<WorkbenchShell.LeftPanel>
|
|
413
|
-
<section className="openpress-public-identity" aria-label="文件資訊">
|
|
414
|
-
<strong>
|
|
415
|
-
<span className="openpress-public-title-main">{projectIdentity.name}</span>
|
|
416
|
-
{projectIdentity.subtitle ? <span className="openpress-public-title-sub">{projectIdentity.subtitle}</span> : null}
|
|
417
|
-
</strong>
|
|
418
|
-
{projectIdentity.label ? <span>{projectIdentity.label}</span> : null}
|
|
419
|
-
</section>
|
|
420
|
-
|
|
421
|
-
{bookmarks.length > 0 ? (
|
|
422
|
-
<section
|
|
423
|
-
id="openpress-bookmarks"
|
|
424
|
-
className="openpress-panel-section openpress-panel-section--bookmarks"
|
|
425
|
-
aria-label="章節書籤"
|
|
426
|
-
>
|
|
427
|
-
<nav className="reader-bookmarks" aria-label="章節導覽" data-openpress-react-bookmarks="true">
|
|
428
|
-
<div className="reader-bookmarks-rail" aria-hidden="true" />
|
|
429
|
-
<Bookmarks
|
|
430
|
-
items={bookmarks}
|
|
431
|
-
currentPageIndex={reader.currentPageIndex}
|
|
432
|
-
onSelectPage={selectWorkspacePage}
|
|
433
|
-
/>
|
|
434
|
-
</nav>
|
|
435
|
-
</section>
|
|
436
|
-
) : (
|
|
437
|
-
<section
|
|
438
|
-
id="openpress-thumbnails"
|
|
439
|
-
className="openpress-panel-section openpress-panel-section--thumbnails"
|
|
440
|
-
aria-label="頁面縮圖"
|
|
441
|
-
>
|
|
442
|
-
<PageThumbnails
|
|
443
|
-
pages={displayPages}
|
|
444
|
-
currentPageIndex={reader.currentPageIndex}
|
|
445
|
-
onSelectPage={selectWorkspacePage}
|
|
446
|
-
theme={document.theme}
|
|
447
|
-
/>
|
|
448
|
-
</section>
|
|
449
|
-
)}
|
|
450
|
-
<CurrentPagePanel
|
|
451
|
-
currentPageLabel={reader.currentPageLabel}
|
|
452
|
-
totalPageLabel={reader.totalPageLabel}
|
|
453
|
-
progressPercent={reader.progressPercent}
|
|
454
|
-
title={displayPages[reader.currentPageIndex]?.title || document.meta.title}
|
|
455
|
-
pageLabelPrefix="頁"
|
|
456
|
-
showHeading={false}
|
|
457
|
-
showTitle={false}
|
|
458
|
-
/>
|
|
459
|
-
</WorkbenchShell.LeftPanel>
|
|
460
|
-
|
|
461
|
-
<WorkbenchShell.RightPanel>
|
|
462
|
-
<WorkbenchControlPanel panels={controlPanels} />
|
|
463
|
-
</WorkbenchShell.RightPanel>
|
|
464
|
-
|
|
465
|
-
<WorkbenchShell.MainContent>
|
|
466
|
-
<ReaderStage ref={reader.stageRef}>
|
|
467
|
-
<PublicPage
|
|
468
|
-
pages={displayPages}
|
|
469
|
-
currentPageIndex={reader.currentPageIndex}
|
|
470
|
-
devMode={devMode}
|
|
471
|
-
sourceContainerRef={sourceContainerRef}
|
|
472
|
-
registerPage={reader.registerPage}
|
|
473
|
-
exposeSourceData={devMode}
|
|
474
|
-
inspector={inspector}
|
|
475
|
-
onInternalAnchorNavigate={selectWorkspaceAnchor}
|
|
476
|
-
pageLayoutMode={pageLayoutMode}
|
|
477
|
-
/>
|
|
478
|
-
{devMode ? (
|
|
479
|
-
<InlineInspectorLayer
|
|
480
|
-
sourceContainerRef={sourceContainerRef}
|
|
481
|
-
inspector={inspector}
|
|
482
|
-
comments={inspectorLayerComments}
|
|
483
|
-
composer={inspectorLayerComposer}
|
|
484
|
-
geometryVersion={`${pageViewport.scaleMode}:${pageViewport.scale}:${pageLayoutMode}`}
|
|
485
|
-
/>
|
|
486
|
-
) : null}
|
|
487
|
-
{devMode ? (
|
|
488
|
-
<InlineSourceEditorLayer
|
|
489
|
-
target={sourceEditorTarget}
|
|
490
|
-
onClose={() => setSourceEditorTarget(null)}
|
|
491
|
-
onStatusChange={setInlineEditStatus}
|
|
492
|
-
geometryVersion={`${pageViewport.scaleMode}:${pageViewport.scale}:${pageLayoutMode}`}
|
|
493
|
-
/>
|
|
494
|
-
) : null}
|
|
495
|
-
</ReaderStage>
|
|
496
|
-
</WorkbenchShell.MainContent>
|
|
497
|
-
</WorkbenchShell>
|
|
498
|
-
);
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
function formatInlineEditStatus(status: InlineDocumentEditStatus) {
|
|
502
|
-
if (status.state === "saving") return "儲存中";
|
|
503
|
-
if (status.state === "saved") return "已儲存";
|
|
504
|
-
if (status.state === "failed") return "儲存失敗";
|
|
505
|
-
return "";
|
|
506
|
-
}
|