@open-press/core 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.
Files changed (144) hide show
  1. package/README.md +6 -3
  2. package/engine/cli.mjs +8 -8
  3. package/engine/commands/_shared.mjs +37 -15
  4. package/engine/commands/dev.mjs +2 -2
  5. package/engine/commands/image.mjs +29 -0
  6. package/engine/commands/skills-sync.mjs +71 -0
  7. package/engine/commands/typecheck.mjs +63 -1
  8. package/engine/commands/upgrade.mjs +3 -3
  9. package/engine/document-export.mjs +1 -1
  10. package/engine/output/chrome-pdf.mjs +110 -3
  11. package/engine/output/static-server.mjs +87 -9
  12. package/engine/react/comment-endpoint.mjs +13 -39
  13. package/engine/react/comment-marker.mjs +43 -19
  14. package/engine/react/document-entry.mjs +46 -28
  15. package/engine/react/document-export.mjs +328 -164
  16. package/engine/react/http-json.mjs +24 -0
  17. package/engine/react/mdx-compile.mjs +126 -3
  18. package/engine/react/measurement-css.mjs +114 -1
  19. package/engine/react/object-entities.mjs +204 -0
  20. package/engine/react/pagination/allocator.mjs +48 -3
  21. package/engine/react/pagination.mjs +1 -1
  22. package/engine/react/pipeline/allocate.mjs +41 -72
  23. package/engine/react/pipeline/frame-measurement.mjs +6 -0
  24. package/engine/react/press-tree-inspection.mjs +172 -0
  25. package/engine/react/project-asset-endpoint.mjs +6 -24
  26. package/engine/react/source-edit-endpoint.d.mts +10 -0
  27. package/engine/react/source-edit-endpoint.mjs +75 -0
  28. package/engine/react/sources/mdx-resolver.mjs +13 -15
  29. package/engine/react/style-discovery.mjs +23 -8
  30. package/engine/runtime/config.d.mts +8 -0
  31. package/engine/runtime/config.mjs +57 -60
  32. package/engine/runtime/file-utils.mjs +9 -1
  33. package/engine/runtime/file-walk.mjs +22 -0
  34. package/engine/runtime/inspection.mjs +1 -20
  35. package/engine/runtime/page-geometry.mjs +131 -0
  36. package/engine/runtime/path-utils.mjs +20 -0
  37. package/engine/runtime/source-text-tools.d.mts +102 -0
  38. package/engine/runtime/source-text-tools.mjs +551 -16
  39. package/engine/runtime/source-workspace.mjs +16 -34
  40. package/engine/runtime/validation.mjs +19 -10
  41. package/package.json +3 -5
  42. package/src/openpress/app/OpenPressApp.tsx +296 -0
  43. package/src/openpress/{renderer.tsx → app/OpenPressRuntime.tsx} +20 -9
  44. package/src/openpress/app/WorkspaceGalleryPage.tsx +219 -0
  45. package/src/openpress/app/index.ts +2 -0
  46. package/src/openpress/core/Frame.tsx +26 -15
  47. package/src/openpress/core/FrameContext.tsx +10 -3
  48. package/src/openpress/core/MdxArea.tsx +11 -12
  49. package/src/openpress/core/Press.tsx +25 -4
  50. package/src/openpress/core/Workspace.tsx +36 -0
  51. package/src/openpress/core/cn.ts +4 -0
  52. package/src/openpress/core/index.tsx +11 -3
  53. package/src/openpress/core/primitives.tsx +74 -6
  54. package/src/openpress/core/types.ts +94 -41
  55. package/src/openpress/core/useSource.ts +1 -1
  56. package/src/openpress/{anchorMap.ts → document-model/anchorMapModel.ts} +1 -1
  57. package/src/openpress/{indexes.ts → document-model/documentIndexes.ts} +1 -1
  58. package/src/openpress/{types.ts → document-model/documentTypes.ts} +51 -0
  59. package/src/openpress/document-model/index.ts +7 -0
  60. package/src/openpress/document-model/objectEntityModel.ts +55 -0
  61. package/src/openpress/{projectIdentity.ts → document-model/projectIdentityModel.ts} +1 -1
  62. package/src/openpress/{reactDocumentMetadata.ts → document-model/reactDocumentMetadataModel.ts} +1 -1
  63. package/src/openpress/document-model/workspaceManifestModel.ts +57 -0
  64. package/src/openpress/manuscript/index.tsx +49 -7
  65. package/src/openpress/mdx/index.ts +15 -7
  66. package/src/openpress/reader/PageThumbnailsPanel.tsx +168 -0
  67. package/src/openpress/{publicPage.tsx → reader/PublicReaderPage.tsx} +31 -51
  68. package/src/openpress/{workbenchPanels.tsx → reader/ReaderNavigationPanel.tsx} +6 -5
  69. package/src/openpress/reader/index.ts +11 -0
  70. package/src/openpress/reader/pageViewportScaleModel.ts +73 -0
  71. package/src/openpress/reader/readerTypes.ts +4 -0
  72. package/src/openpress/reader/usePageViewportScale.ts +119 -0
  73. package/src/openpress/reader/usePanelState.ts +56 -0
  74. package/src/openpress/reader/useReaderHashSync.ts +61 -0
  75. package/src/openpress/reader/useReaderKeyboardNav.ts +48 -0
  76. package/src/openpress/reader/useReaderRuntime.ts +146 -0
  77. package/src/openpress/reader/useReaderScrollAnchor.ts +64 -0
  78. package/src/openpress/shared/Panel.tsx +77 -0
  79. package/src/openpress/shared/index.ts +4 -0
  80. package/src/openpress/shared/numberUtils.ts +3 -0
  81. package/src/openpress/{runtimeMode.ts → shared/runtimeMode.ts} +0 -11
  82. package/src/openpress/workbench/Workbench.tsx +506 -0
  83. package/src/openpress/workbench/actions/DeploymentControl.tsx +157 -0
  84. package/src/openpress/workbench/actions/ExportImageControl.tsx +96 -0
  85. package/src/openpress/workbench/actions/PageZoomControl.tsx +182 -0
  86. package/src/openpress/workbench/actions/SearchControl.tsx +345 -0
  87. package/src/openpress/workbench/actions/deploymentStatusModel.ts +112 -0
  88. package/src/openpress/workbench/actions/index.ts +6 -0
  89. package/src/openpress/workbench/actions/useDeploymentWorkbench.ts +136 -0
  90. package/src/openpress/workbench/dialog/WorkbenchDialog.tsx +72 -0
  91. package/src/openpress/workbench/dialog/index.ts +1 -0
  92. package/src/openpress/workbench/document/components/DocumentPanel.tsx +127 -0
  93. package/src/openpress/workbench/document/components/InlineSourceEditorLayer.tsx +207 -0
  94. package/src/openpress/workbench/document/components/ReaderStage.tsx +9 -0
  95. package/src/openpress/workbench/document/hooks/useDocumentWorkbenchModel.ts +34 -0
  96. package/src/openpress/workbench/document/hooks/useInlineDocumentEditor.ts +525 -0
  97. package/src/openpress/workbench/document/index.ts +10 -0
  98. package/src/openpress/workbench/index.ts +2 -0
  99. package/src/openpress/workbench/inspector/InlineInspectorLayer.tsx +459 -0
  100. package/src/openpress/workbench/inspector/index.ts +5 -0
  101. package/src/openpress/workbench/inspector/inlineCommentModel.ts +125 -0
  102. package/src/openpress/workbench/inspector/inspectorGeometryModel.ts +160 -0
  103. package/src/openpress/workbench/inspector/inspectorModel.ts +408 -0
  104. package/src/openpress/workbench/inspector/useInspectorComments.ts +254 -0
  105. package/src/openpress/workbench/mentions/MentionSuggestionList.tsx +41 -0
  106. package/src/openpress/workbench/mentions/index.ts +2 -0
  107. package/src/openpress/{composerMentions.ts → workbench/mentions/useComposerMentions.ts} +1 -4
  108. package/src/openpress/workbench/panels/Panel.tsx +1 -0
  109. package/src/openpress/workbench/panels/PendingCommentsPanel.tsx +80 -0
  110. package/src/openpress/workbench/panels/WorkbenchControlPanel.tsx +29 -0
  111. package/src/openpress/workbench/panels/index.ts +3 -0
  112. package/src/openpress/workbench/project/ProjectEntryPanel.tsx +525 -0
  113. package/src/openpress/workbench/project/ProjectPreviewDialog.tsx +35 -0
  114. package/src/openpress/workbench/project/index.ts +2 -0
  115. package/src/openpress/workbench/project/projectPreviewTypes.ts +11 -0
  116. package/src/openpress/workbench/shell/WorkbenchShell.tsx +167 -0
  117. package/src/openpress/workbench/shell/index.ts +1 -0
  118. package/src/openpress/workbench/workbenchFormatters.ts +120 -0
  119. package/src/openpress/workbench/workbenchTypes.ts +35 -0
  120. package/src/styles/openpress/print-route.css +0 -2
  121. package/src/styles/openpress/{project-workspace.css → project-preview-panel.css} +13 -407
  122. package/src/styles/openpress/public-viewer.css +25 -320
  123. package/src/styles/openpress/reader-runtime.css +252 -55
  124. package/src/styles/openpress/responsive.css +145 -270
  125. package/src/styles/openpress/workbench-panels.css +327 -178
  126. package/src/styles/openpress/workbench.css +986 -451
  127. package/src/styles/openpress/workspace-gallery.css +300 -0
  128. package/src/styles/openpress.css +2 -1
  129. package/tsconfig.json +1 -1
  130. package/vite.config.ts +50 -0
  131. package/engine/commands/init.mjs +0 -24
  132. package/engine/init.mjs +0 -90
  133. package/src/openpress/App.tsx +0 -127
  134. package/src/openpress/inspector.ts +0 -282
  135. package/src/openpress/projectWorkspace.tsx +0 -919
  136. package/src/openpress/readerRuntime.ts +0 -230
  137. package/src/openpress/workbench.tsx +0 -1265
  138. package/src/openpress/workbenchTypes.ts +0 -4
  139. /package/src/openpress/{readerPageRegistry.ts → reader/readerPageRegistry.ts} +0 -0
  140. /package/src/openpress/{pageRoute.ts → reader/readerPageRoute.ts} +0 -0
  141. /package/src/openpress/{readerScroll.ts → reader/readerScroll.ts} +0 -0
  142. /package/src/openpress/{readerState.ts → reader/readerStateModel.ts} +0 -0
  143. /package/src/openpress/{frameScheduler.ts → shared/frameScheduler.ts} +0 -0
  144. /package/src/openpress/{projectSources.ts → workbench/project/projectSourceModel.ts} +0 -0
@@ -0,0 +1,167 @@
1
+ import { createContext, useContext, type CSSProperties, type ReactNode } from "react";
2
+ import { PanelLeftClose, PanelLeftOpen, PanelRightClose, PanelRightOpen, X } from "lucide-react";
3
+
4
+ type WorkbenchShellContextValue = {
5
+ leftPanelOpen: boolean;
6
+ rightPanelOpen: boolean;
7
+ onToggleLeftPanel: () => void;
8
+ onToggleRightPanel: () => void;
9
+ };
10
+
11
+ const WorkbenchShellContext = createContext<WorkbenchShellContextValue | null>(null);
12
+
13
+ function useWorkbenchShell() {
14
+ const value = useContext(WorkbenchShellContext);
15
+ if (!value) throw new Error("WorkbenchShell compound components must be rendered inside <WorkbenchShell>.");
16
+ return value;
17
+ }
18
+
19
+ function WorkbenchShellRoot({
20
+ style,
21
+ devMode,
22
+ viewMode,
23
+ inspectorMode,
24
+ editMode = false,
25
+ leftPanelOpen,
26
+ rightPanelOpen,
27
+ onToggleLeftPanel,
28
+ onToggleRightPanel,
29
+ children,
30
+ }: {
31
+ style: CSSProperties;
32
+ devMode: boolean;
33
+ viewMode: string;
34
+ inspectorMode: boolean;
35
+ editMode?: boolean;
36
+ leftPanelOpen: boolean;
37
+ rightPanelOpen: boolean;
38
+ onToggleLeftPanel: () => void;
39
+ onToggleRightPanel: () => void;
40
+ children: ReactNode;
41
+ }) {
42
+ const scrimOpen = leftPanelOpen || rightPanelOpen;
43
+ const handleScrimClick = rightPanelOpen ? onToggleRightPanel : onToggleLeftPanel;
44
+ const shellClassName = [
45
+ "reader-app openpress-reader-app openpress-public-viewer openpress-dev-public-viewer openpress-workbench-shell is-ready",
46
+ leftPanelOpen ? "" : "is-closed-left",
47
+ rightPanelOpen ? "" : "is-closed-right",
48
+ ].filter(Boolean).join(" ");
49
+
50
+ return (
51
+ <WorkbenchShellContext.Provider value={{ leftPanelOpen, rightPanelOpen, onToggleLeftPanel, onToggleRightPanel }}>
52
+ <main className="openpress-workbench" style={style} data-dev-mode={devMode ? "true" : "false"}>
53
+ <div
54
+ className={shellClassName}
55
+ data-openpress-react-runtime="true"
56
+ data-openpress-view-mode={viewMode}
57
+ data-openpress-inspector-mode={inspectorMode ? "on" : "off"}
58
+ data-openpress-edit-mode={editMode ? "on" : "off"}
59
+ data-openpress-workbench-shell
60
+ data-testid="workbench-shell"
61
+ >
62
+ {scrimOpen ? (
63
+ <div className="openpress-public-scrim" aria-hidden="true" onClick={handleScrimClick} />
64
+ ) : null}
65
+ {children}
66
+ </div>
67
+ </main>
68
+ </WorkbenchShellContext.Provider>
69
+ );
70
+ }
71
+
72
+ export function WorkbenchToolbar({ children }: { children: ReactNode }) {
73
+ const {
74
+ leftPanelOpen,
75
+ rightPanelOpen,
76
+ onToggleLeftPanel,
77
+ onToggleRightPanel,
78
+ } = useWorkbenchShell();
79
+ const LeftIcon = leftPanelOpen ? PanelLeftClose : PanelLeftOpen;
80
+ const RightIcon = rightPanelOpen ? PanelRightClose : PanelRightOpen;
81
+ const leftLabel = leftPanelOpen ? "收合左側面板" : "展開左側面板";
82
+ const rightLabel = rightPanelOpen ? "收合右側面板" : "展開右側面板";
83
+
84
+ return (
85
+ <header
86
+ className="openpress-workbench-toolbar"
87
+ role="toolbar"
88
+ aria-label="工作台操作"
89
+ data-openpress-workbench-toolbar
90
+ >
91
+ <button
92
+ type="button"
93
+ className="openpress-workbench-toolbar-panel-toggle"
94
+ data-openpress-toggle-left-panel
95
+ data-openpress-panel-open={leftPanelOpen ? "true" : "false"}
96
+ aria-label={leftLabel}
97
+ title={leftLabel}
98
+ onClick={onToggleLeftPanel}
99
+ >
100
+ <LeftIcon aria-hidden="true" />
101
+ </button>
102
+ <div className="openpress-workbench-toolbar__content">
103
+ {children}
104
+ </div>
105
+ <button
106
+ type="button"
107
+ className="openpress-workbench-toolbar-panel-toggle"
108
+ data-openpress-toggle-right-panel
109
+ data-openpress-panel-open={rightPanelOpen ? "true" : "false"}
110
+ aria-label={rightLabel}
111
+ title={rightLabel}
112
+ onClick={onToggleRightPanel}
113
+ >
114
+ <RightIcon aria-hidden="true" />
115
+ </button>
116
+ </header>
117
+ );
118
+ }
119
+
120
+ function WorkbenchLeftPanel({ children }: { children: ReactNode }) {
121
+ return (
122
+ <aside
123
+ className="reader-side-nav openpress-workspace-panel openpress-workbench-left-panel openpress-public-navigation"
124
+ aria-label="文件導覽"
125
+ data-openpress-left-panel
126
+ >
127
+ {children}
128
+ </aside>
129
+ );
130
+ }
131
+
132
+ function WorkbenchRightPanel({ children }: { children: ReactNode }) {
133
+ const { onToggleRightPanel } = useWorkbenchShell();
134
+
135
+ return (
136
+ <aside
137
+ className="openpress-workspace-panel openpress-workbench-right-panel openpress-dev-public-navigation"
138
+ aria-label="控制面板"
139
+ data-openpress-right-panel
140
+ >
141
+ <button type="button" className="openpress-public-drawer-close" aria-label="關閉右側面板" onClick={onToggleRightPanel}>
142
+ <X size={16} aria-hidden="true" />
143
+ </button>
144
+ {children}
145
+ </aside>
146
+ );
147
+ }
148
+
149
+ function WorkbenchMainContent({ children }: { children: ReactNode }) {
150
+ return (
151
+ <section
152
+ className="openpress-workbench__stage openpress-workbench-main openpress-public-viewer__stage openpress-dev-main-content"
153
+ aria-label="主要內容"
154
+ data-openpress-main-content
155
+ >
156
+ {children}
157
+ </section>
158
+ );
159
+ }
160
+
161
+ export const WorkbenchShell = Object.assign(WorkbenchShellRoot, {
162
+ Toolbar: WorkbenchToolbar,
163
+ LeftPanel: WorkbenchLeftPanel,
164
+ RightPanel: WorkbenchRightPanel,
165
+ ControlPanel: WorkbenchRightPanel,
166
+ MainContent: WorkbenchMainContent,
167
+ });
@@ -0,0 +1 @@
1
+ export * from "./WorkbenchShell";
@@ -0,0 +1,120 @@
1
+ import type { InspectorPlacement } from "./inspector";
2
+ import type { ObjectEntity, SourceBlock, Theme } from "../document-model";
3
+ import type { PendingCommentsStatus, InspectorCommentStatus } from "./workbenchTypes";
4
+
5
+ export type PageGeometrySpec = {
6
+ label: string;
7
+ dimensions: string;
8
+ title: string;
9
+ };
10
+
11
+ const DEFAULT_PAGE_GEOMETRY = {
12
+ pageWidth: "210mm",
13
+ pageHeight: "297mm",
14
+ };
15
+
16
+ export function formatInspectorSelection(block: SourceBlock | null, entity?: ObjectEntity | null) {
17
+ if (entity) return entity.label;
18
+ if (!block) return "未選取";
19
+ const line = block.source?.line;
20
+ return line ? `${block.path}:${line}` : block.path;
21
+ }
22
+
23
+ export function formatInspectorCommentStatus(status: InspectorCommentStatus, error: string) {
24
+ if (status === "submitting") return "寫入中";
25
+ if (status === "saved") return "已寫入 source";
26
+ if (status === "failed") return error || "寫入失敗";
27
+ return "";
28
+ }
29
+
30
+ export function formatCommentsCount(count: number, status: PendingCommentsStatus) {
31
+ if (status === "loading") return "正在讀取";
32
+ if (status === "clearing") return "正在清除";
33
+ return `${count} 則待處理`;
34
+ }
35
+
36
+ export function formatPageGeometrySpec(theme?: Pick<Theme, "pageLabel" | "pageWidth" | "pageHeight">): PageGeometrySpec {
37
+ const width = parseCssLength(theme?.pageWidth ?? DEFAULT_PAGE_GEOMETRY.pageWidth);
38
+ const height = parseCssLength(theme?.pageHeight ?? DEFAULT_PAGE_GEOMETRY.pageHeight);
39
+ const dimensions = formatLengthPair(width, height);
40
+ const label = theme?.pageLabel?.trim() || pageGeometryLabel(width, height);
41
+
42
+ return {
43
+ label,
44
+ dimensions,
45
+ title: `${label} · ${dimensions}`,
46
+ };
47
+ }
48
+
49
+ export function parseCommentHint(hint?: string) {
50
+ if (!hint?.startsWith("openpress-react-inspector")) return null;
51
+ const intent = hint.match(/\bintent=(add|edit|delete)\b/)?.[1];
52
+ const placement = hint.match(/\bplacement=(block|before)\b/)?.[1] as InspectorPlacement | undefined;
53
+ const targetObjectId = decodeHintValue(hint.match(/\btarget=([^\s]+)/)?.[1]);
54
+ const intentLabel = intent === "add" ? "Add" : intent === "delete" ? "Remove" : "Edit";
55
+ const placementLabel = placement === "before" ? "插入於區塊前" : "針對目前區塊";
56
+ return { intent: intent ?? "edit", intentLabel, placement: placement ?? "block", placementLabel, targetObjectId };
57
+ }
58
+
59
+ export function formatCommentTimestamp(value: string) {
60
+ const date = new Date(value);
61
+ if (Number.isNaN(date.getTime())) return value;
62
+ return new Intl.DateTimeFormat("zh-TW", {
63
+ month: "2-digit",
64
+ day: "2-digit",
65
+ hour: "2-digit",
66
+ minute: "2-digit",
67
+ hour12: false,
68
+ }).format(date);
69
+ }
70
+
71
+ function pageGeometryLabel(width: CssLength, height: CssLength) {
72
+ if (matchesPageSize(width, height, "210", "297", "mm")) return "A4 Page";
73
+ if (matchesPageSize(width, height, "176", "250", "mm")) return "B5 Page";
74
+ if (matchesPageSize(width, height, "215.9", "279.4", "mm")) return "Letter Page";
75
+ if (isSixteenByNine(width, height)) return "16:9 Page";
76
+ return "Custom Page";
77
+ }
78
+
79
+ type CssLength = {
80
+ raw: string;
81
+ value: string | null;
82
+ unit: string | null;
83
+ };
84
+
85
+ function parseCssLength(value: string): CssLength {
86
+ const raw = value.trim();
87
+ const match = raw.match(/^(-?\d+(?:\.\d+)?)([a-z%]+)$/i);
88
+ if (!match) return { raw, value: null, unit: null };
89
+ return { raw, value: trimTrailingZeroes(match[1]), unit: match[2] };
90
+ }
91
+
92
+ function formatLengthPair(width: CssLength, height: CssLength) {
93
+ if (width.value && height.value && width.unit && width.unit === height.unit) {
94
+ return `${width.value} × ${height.value} ${width.unit}`;
95
+ }
96
+ return `${width.raw} × ${height.raw}`;
97
+ }
98
+
99
+ function matchesPageSize(width: CssLength, height: CssLength, targetWidth: string, targetHeight: string, unit: string) {
100
+ return width.value === targetWidth && height.value === targetHeight && width.unit === unit && height.unit === unit;
101
+ }
102
+
103
+ function isSixteenByNine(width: CssLength, height: CssLength) {
104
+ if (!width.value || !height.value || !width.unit || width.unit !== height.unit) return false;
105
+ const ratio = Number(width.value) / Number(height.value);
106
+ return ratio > 1 && Math.abs(ratio - (16 / 9)) < 0.02;
107
+ }
108
+
109
+ function decodeHintValue(value?: string) {
110
+ if (!value) return undefined;
111
+ try {
112
+ return decodeURIComponent(value);
113
+ } catch {
114
+ return value;
115
+ }
116
+ }
117
+
118
+ function trimTrailingZeroes(value: string) {
119
+ return value.replace(/\.0+$/, "").replace(/(\.\d*?)0+$/, "$1");
120
+ }
@@ -0,0 +1,35 @@
1
+ import type { InspectorPlacement, ObjectSelection } from "./inspector/inspectorModel";
2
+
3
+ export type DeployStatus = "idle" | "deploying" | "deployed" | "unavailable" | "failed" | "setup";
4
+ export type PdfActionStatus = "idle" | "generating" | "opening" | "failed";
5
+ export type InspectorCommentStatus = "idle" | "submitting" | "saved" | "failed";
6
+ export type PendingCommentsStatus = "idle" | "loading" | "ready" | "failed" | "clearing";
7
+
8
+ export interface InlineSavedComment {
9
+ id: string;
10
+ objectId?: string;
11
+ blockId?: string;
12
+ placement: InspectorPlacement;
13
+ note: string;
14
+ path?: string;
15
+ line?: number;
16
+ timestamp?: string;
17
+ markerLabel?: string;
18
+ }
19
+
20
+ export interface InlineSavedCommentMarkerEntry {
21
+ target: ObjectSelection;
22
+ comments: InlineSavedComment[];
23
+ }
24
+
25
+ export interface InspectorLayerRect {
26
+ top: number;
27
+ left: number;
28
+ width: number;
29
+ height: number;
30
+ }
31
+
32
+ export interface InspectorInsertTargetView {
33
+ blockId: string;
34
+ rect: InspectorLayerRect;
35
+ }
@@ -46,8 +46,6 @@
46
46
 
47
47
  .reader-navbar,
48
48
  .reader-side-nav,
49
- .reader-thumb-strip,
50
- .openpress-workspace-navbar,
51
49
  .openpress-workspace-panel,
52
50
  .openpress-public-identity,
53
51
  .openpress-html-page__toolbar {