collabmd 0.1.47 → 0.1.48
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 +9 -6
- package/dist/client/assets/JetBrainsMono-Regular-BQaDgvhP.woff2 +0 -0
- package/dist/client/assets/babel-CY5KOv-I.js +16 -0
- package/dist/client/assets/comment-ui-shared-DuoyznXW.js +7 -0
- package/dist/client/assets/dist-ChRoo3IB.js +9 -0
- package/dist/client/assets/document-formatter-Dxl_a8XO.js +2 -0
- package/dist/client/assets/{drawio-editor-BjrxTe3l.js → drawio-editor-BVaNNtYp.js} +2 -2
- package/dist/client/assets/{drawioEditor-DUVZjSSr.js → drawioEditor-BkIBlXx0.js} +2 -2
- package/dist/client/assets/editor-session-DMyVdHLj.js +54 -0
- package/dist/client/assets/embedded-editor-base-B3l6Xy65.css +1 -0
- package/dist/client/assets/estree-CuT_pB8K.js +44 -0
- package/dist/client/assets/{excalidraw-editor-BlcN6umJ.css → excalidraw-editor-BbSbI80a.css} +1 -1
- package/dist/client/assets/excalidraw-editor-BjYaNEMY.js +9 -0
- package/dist/client/assets/{excalidrawEditor-B0jOK3lv.js → excalidrawEditor-ChqF_d82.js} +2 -2
- package/dist/client/assets/export-page-Dyu0XCbu.js +57 -0
- package/dist/client/assets/exportDocument-CJBx4Xjx.css +1 -0
- package/dist/client/assets/{exportDocument-Dg9MjkIk.js → exportDocument-Dgvfa2Sd.js} +2 -2
- package/dist/client/assets/{file-icon-svg-CQAjlWjK.js → file-icon-svg-Y_kpF957.js} +1 -1
- package/dist/client/assets/file-kind-BwMIcZbi.js +1 -0
- package/dist/client/assets/file-search-DDLyyLDU.js +1 -0
- package/dist/client/assets/html-Cdnr2qzU.js +25 -0
- package/dist/client/assets/index-CSNIMyOP.css +1 -0
- package/dist/client/assets/index-DG3N2Ps-.js +2 -0
- package/dist/client/assets/main-D0wCxpVn.js +903 -0
- package/dist/client/assets/markdown-CByV-4CU.js +70 -0
- package/dist/client/assets/mermaid.core-BJRLUQZE.js +11 -0
- package/dist/client/assets/{preview-render-compiler-BApvlLLo.js → preview-render-compiler-CrJIooVD.js} +2 -2
- package/dist/client/assets/preview-render-compiler-O0JxBVNF.js +1 -0
- package/dist/client/assets/{preview-render-profile-CE-5rVTC.js → preview-render-profile-B4RWYWHt.js} +1 -1
- package/dist/client/assets/{preview-render-worker-BmN79bVc.js → preview-render-worker-_QTxqKvP.js} +22 -22
- package/dist/client/assets/quick-switcher-controller-CaEjEtq_.js +1 -0
- package/dist/client/assets/standalone-6z5x8CWe.js +29 -0
- package/dist/client/assets/{vault-api-client-_LpV1aIn.js → vault-api-client-BkwdFjx0.js} +2 -2
- package/dist/client/assets/{es-CAsWR6hG.js → vault-utils-DvoSftJT.js} +1 -1
- package/dist/client/assets/yaml-9ltHPDNO.js +154 -0
- package/dist/client/drawio-editor.html +1 -1
- package/dist/client/excalidraw-editor.html +1 -1
- package/dist/client/export-document.html +2 -2
- package/dist/client/index.html +41 -19
- package/package.json +4 -1
- package/src/client/app/index.html +39 -17
- package/src/client/application/app-shell/export-feature.js +17 -1
- package/src/client/application/app-shell/git-feature.js +28 -9
- package/src/client/application/app-shell/ui-feature-identity.js +13 -0
- package/src/client/application/app-shell/ui-feature-shell.js +164 -9
- package/src/client/application/app-shell-elements.js +4 -0
- package/src/client/application/workspace-coordinator.js +21 -4
- package/src/client/application/workspace-preview-controller.js +120 -2
- package/src/client/application/workspace-route-controller.js +4 -1
- package/src/client/assets/vendor/jetbrains-mono/JetBrainsMono-Regular.woff2 +0 -0
- package/src/client/assets/vendor/jetbrains-mono/OFL.txt +93 -0
- package/src/client/bootstrap/collabmd-app-shell.js +21 -5
- package/src/client/domain/document-formatter.js +193 -0
- package/src/client/domain/file-search.js +73 -0
- package/src/client/domain/git-labels.js +5 -0
- package/src/client/domain/vault-paths.js +6 -4
- package/src/client/domain/wiki-link-completions.js +20 -20
- package/src/client/drawio-editor.js +8 -3
- package/src/client/excalidraw-editor.js +152 -6
- package/src/client/export/export-host.js +56 -35
- package/src/client/export/export-page.js +14 -4
- package/src/client/export/export-pipeline.js +266 -25
- package/src/client/infrastructure/editor-session.js +4 -0
- package/src/client/infrastructure/editor-view-adapter.js +60 -14
- package/src/client/presentation/bases-preview-controller.js +35 -11
- package/src/client/presentation/file-action-controller.js +15 -2
- package/src/client/presentation/file-explorer-controller.js +3 -0
- package/src/client/presentation/file-explorer-view.js +2 -1
- package/src/client/presentation/file-history-view-controller.js +6 -1
- package/src/client/presentation/file-tree-state.js +1 -11
- package/src/client/presentation/git-diff-view-controller.js +36 -11
- package/src/client/presentation/git-panel-controller.js +10 -6
- package/src/client/presentation/quick-switcher-controller.js +54 -154
- package/src/client/styles/components/scrollbars.css +10 -0
- package/src/client/styles/export-document.css +44 -29
- package/src/client/styles/features/collaboration-presence.css +13 -1
- package/src/client/styles/features/preview-markdown.css +54 -0
- package/src/client/styles/foundation/tokens.css +8 -0
- package/src/client/styles/layout/shell.css +76 -24
- package/src/client/styles/layout/view-modes.css +2 -0
- package/src/client/styles/overrides/codemirror.css +31 -19
- package/src/client/styles/surfaces/excalidraw-editor.css +42 -0
- package/src/domain/file-kind.js +12 -1
- package/src/server/domain/ripgrep-search-service.js +110 -37
- package/src/server/infrastructure/persistence/path-utils.js +10 -4
- package/src/server/infrastructure/persistence/vault-file-store.js +2 -0
- package/dist/client/assets/comment-ui-shared-DWkk9Vh3.js +0 -7
- package/dist/client/assets/editor-session-DfZuRgB_.js +0 -54
- package/dist/client/assets/embedded-editor-base-DvMynhKu.css +0 -1
- package/dist/client/assets/excalidraw-editor-D7pnUCLH.js +0 -9
- package/dist/client/assets/export-page-Bs3xE1fg.js +0 -57
- package/dist/client/assets/exportDocument-PnYU3v1s.css +0 -1
- package/dist/client/assets/file-kind-BbqgGzpc.js +0 -1
- package/dist/client/assets/index-BIpgxyGZ.css +0 -1
- package/dist/client/assets/index-Z5sI0Bj-.js +0 -2
- package/dist/client/assets/main-Dwnj9Gaq.js +0 -903
- package/dist/client/assets/mermaid.core-CLZBlpIW.js +0 -11
- package/dist/client/assets/preview-render-compiler-BQ_3h9vD.js +0 -1
- package/dist/client/assets/quick-switcher-controller-ButWPmCI.js +0 -12
- package/dist/client/assets/vault-utils-wdQ0RNR9.js +0 -1
|
@@ -469,6 +469,32 @@ function buildExcalidrawProps({ initialData, renderTopRightUI, viewModeEnabled }
|
|
|
469
469
|
}
|
|
470
470
|
|
|
471
471
|
const diagramCommentsContext = React.createContext(null);
|
|
472
|
+
const presentationContext = React.createContext(null);
|
|
473
|
+
|
|
474
|
+
function PresentationToolbar() {
|
|
475
|
+
const context = React.useContext(presentationContext);
|
|
476
|
+
if (!context) {
|
|
477
|
+
return null;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
const label = context.active ? 'Exit presentation' : 'Start presentation';
|
|
481
|
+
const icon = context.active ? '×' : '▶';
|
|
482
|
+
let title = context.active ? 'Exit presentation' : 'Present frames';
|
|
483
|
+
if (context.frameCount === 0) {
|
|
484
|
+
title = 'Add a frame to create slides';
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return React.createElement('button', {
|
|
488
|
+
'aria-label': label,
|
|
489
|
+
'aria-pressed': context.active,
|
|
490
|
+
className: `diagram-comment-button excalidraw-presentation-toggle sidebar-trigger${context.active ? ' is-active' : ''}`,
|
|
491
|
+
'data-testid': 'excalidraw-presentation-toggle',
|
|
492
|
+
disabled: context.frameCount === 0,
|
|
493
|
+
onClick: context.toggle,
|
|
494
|
+
title,
|
|
495
|
+
type: 'button',
|
|
496
|
+
}, React.createElement('span', { 'aria-hidden': 'true' }, icon));
|
|
497
|
+
}
|
|
472
498
|
|
|
473
499
|
function DiagramCommentsToolbar() {
|
|
474
500
|
const context = React.useContext(diagramCommentsContext);
|
|
@@ -518,7 +544,12 @@ function DiagramCommentsToolbar() {
|
|
|
518
544
|
|
|
519
545
|
const DiagramCommentsExcalidraw = React.memo(function DiagramCommentsExcalidraw({ initialData = null, renderKey = 0, viewModeEnabled }) {
|
|
520
546
|
const renderTopRightUI = React.useCallback(
|
|
521
|
-
() => React.createElement(
|
|
547
|
+
() => React.createElement('div', {
|
|
548
|
+
className: 'excalidraw-editor-toolbar',
|
|
549
|
+
}, [
|
|
550
|
+
React.createElement(PresentationToolbar, { key: 'presentation' }),
|
|
551
|
+
React.createElement(DiagramCommentsToolbar, { key: 'comments' }),
|
|
552
|
+
]),
|
|
522
553
|
[],
|
|
523
554
|
);
|
|
524
555
|
|
|
@@ -566,7 +597,13 @@ function DiagramCommentsEditor({ apiId = '', canWrite = false, focusRequest = nu
|
|
|
566
597
|
const [drawerOpen, setDrawerOpen] = React.useState(false);
|
|
567
598
|
const [draft, setDraft] = React.useState('');
|
|
568
599
|
const [replyDraft, setReplyDraft] = React.useState('');
|
|
600
|
+
const [presentationFrameId, setPresentationFrameId] = React.useState(null);
|
|
569
601
|
const [, setViewportRevision] = React.useState(0);
|
|
602
|
+
const presentationFrames = (
|
|
603
|
+
getMountedExcalidrawAPI()?.getSceneElementsIncludingDeleted?.() || []
|
|
604
|
+
).filter((element) => element?.type === 'frame' && !element.isDeleted);
|
|
605
|
+
const presentationIndex = presentationFrames.findIndex((frame) => frame.id === presentationFrameId);
|
|
606
|
+
const presentationMode = presentationFrameId !== null;
|
|
570
607
|
|
|
571
608
|
React.useEffect(() => {
|
|
572
609
|
const api = getMountedExcalidrawAPI();
|
|
@@ -588,6 +625,76 @@ function DiagramCommentsEditor({ apiId = '', canWrite = false, focusRequest = nu
|
|
|
588
625
|
|
|
589
626
|
useCloseDiagramCommentsOnCanvas(drawerOpen, setDrawerOpen);
|
|
590
627
|
|
|
628
|
+
const goToPresentationFrame = React.useCallback((index) => {
|
|
629
|
+
const targetIndex = Math.min(Math.max(index, 0), presentationFrames.length - 1);
|
|
630
|
+
const frame = presentationFrames[targetIndex];
|
|
631
|
+
const api = getMountedExcalidrawAPI();
|
|
632
|
+
if (!api || !frame) {
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
setPresentationFrameId(frame.id);
|
|
637
|
+
api.setViewport({
|
|
638
|
+
animation: true,
|
|
639
|
+
fit: 'contain',
|
|
640
|
+
offsets: { ui: true },
|
|
641
|
+
target: frame,
|
|
642
|
+
});
|
|
643
|
+
}, [presentationFrames]);
|
|
644
|
+
|
|
645
|
+
const togglePresentation = React.useCallback(() => {
|
|
646
|
+
if (presentationMode) {
|
|
647
|
+
setPresentationFrameId(null);
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
setDrawerOpen(false);
|
|
652
|
+
setComposerOpen(false);
|
|
653
|
+
setActiveThreadId(null);
|
|
654
|
+
goToPresentationFrame(0);
|
|
655
|
+
}, [goToPresentationFrame, presentationMode]);
|
|
656
|
+
|
|
657
|
+
React.useEffect(() => {
|
|
658
|
+
if (!presentationFrameId || presentationIndex >= 0) {
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
if (presentationFrames.length > 0) {
|
|
663
|
+
goToPresentationFrame(0);
|
|
664
|
+
} else {
|
|
665
|
+
setPresentationFrameId(null);
|
|
666
|
+
}
|
|
667
|
+
}, [goToPresentationFrame, presentationFrameId, presentationFrames.length, presentationIndex]);
|
|
668
|
+
|
|
669
|
+
React.useEffect(() => {
|
|
670
|
+
if (!presentationMode) {
|
|
671
|
+
return undefined;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
const handlePresentationKeyDown = (event) => {
|
|
675
|
+
if (event.defaultPrevented || event.metaKey || event.ctrlKey || event.altKey) {
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
if (event.key === 'Escape') {
|
|
680
|
+
event.preventDefault();
|
|
681
|
+
event.stopPropagation();
|
|
682
|
+
setPresentationFrameId(null);
|
|
683
|
+
} else if (event.key === 'ArrowRight') {
|
|
684
|
+
event.preventDefault();
|
|
685
|
+
event.stopPropagation();
|
|
686
|
+
goToPresentationFrame(presentationIndex + 1);
|
|
687
|
+
} else if (event.key === 'ArrowLeft') {
|
|
688
|
+
event.preventDefault();
|
|
689
|
+
event.stopPropagation();
|
|
690
|
+
goToPresentationFrame(presentationIndex - 1);
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
|
|
694
|
+
document.addEventListener('keydown', handlePresentationKeyDown, true);
|
|
695
|
+
return () => document.removeEventListener('keydown', handlePresentationKeyDown, true);
|
|
696
|
+
}, [goToPresentationFrame, presentationIndex, presentationMode]);
|
|
697
|
+
|
|
591
698
|
React.useEffect(() => {
|
|
592
699
|
if (activeThreadId && !threads.some((thread) => thread.id === activeThreadId)) {
|
|
593
700
|
setActiveThreadId(null);
|
|
@@ -833,7 +940,8 @@ function DiagramCommentsEditor({ apiId = '', canWrite = false, focusRequest = nu
|
|
|
833
940
|
]);
|
|
834
941
|
};
|
|
835
942
|
|
|
836
|
-
const
|
|
943
|
+
const commentsVisible = visible && !presentationMode;
|
|
944
|
+
const renderCommentsOverlay = commentsVisible && room
|
|
837
945
|
? React.createElement('div', {
|
|
838
946
|
'aria-label': 'Diagram comments overlay',
|
|
839
947
|
className: 'diagram-comments-overlay',
|
|
@@ -865,7 +973,44 @@ function DiagramCommentsEditor({ apiId = '', canWrite = false, focusRequest = nu
|
|
|
865
973
|
])
|
|
866
974
|
: null;
|
|
867
975
|
|
|
868
|
-
|
|
976
|
+
const renderPresentationNavigation = presentationMode
|
|
977
|
+
? React.createElement('div', {
|
|
978
|
+
'aria-label': 'Presentation navigation',
|
|
979
|
+
className: 'excalidraw-presentation-navigation',
|
|
980
|
+
key: 'presentation-navigation',
|
|
981
|
+
role: 'toolbar',
|
|
982
|
+
}, [
|
|
983
|
+
React.createElement('button', {
|
|
984
|
+
'aria-label': 'Previous slide',
|
|
985
|
+
className: 'diagram-comment-button',
|
|
986
|
+
disabled: presentationIndex <= 0,
|
|
987
|
+
key: 'previous',
|
|
988
|
+
onClick: () => goToPresentationFrame(presentationIndex - 1),
|
|
989
|
+
type: 'button',
|
|
990
|
+
}, '←'),
|
|
991
|
+
React.createElement('span', {
|
|
992
|
+
'aria-live': 'polite',
|
|
993
|
+
className: 'excalidraw-presentation-status',
|
|
994
|
+
key: 'status',
|
|
995
|
+
}, `${presentationFrames[presentationIndex]?.name || `Slide ${presentationIndex + 1}`} · ${presentationIndex + 1} / ${presentationFrames.length}`),
|
|
996
|
+
React.createElement('button', {
|
|
997
|
+
'aria-label': 'Next slide',
|
|
998
|
+
className: 'diagram-comment-button',
|
|
999
|
+
disabled: presentationIndex >= presentationFrames.length - 1,
|
|
1000
|
+
key: 'next',
|
|
1001
|
+
onClick: () => goToPresentationFrame(presentationIndex + 1),
|
|
1002
|
+
type: 'button',
|
|
1003
|
+
}, '→'),
|
|
1004
|
+
])
|
|
1005
|
+
: null;
|
|
1006
|
+
|
|
1007
|
+
return React.createElement(presentationContext.Provider, {
|
|
1008
|
+
value: {
|
|
1009
|
+
active: presentationMode,
|
|
1010
|
+
frameCount: presentationFrames.length,
|
|
1011
|
+
toggle: togglePresentation,
|
|
1012
|
+
},
|
|
1013
|
+
}, React.createElement(diagramCommentsContext.Provider, {
|
|
869
1014
|
value: {
|
|
870
1015
|
canWrite,
|
|
871
1016
|
drawerOpen,
|
|
@@ -874,17 +1019,18 @@ function DiagramCommentsEditor({ apiId = '', canWrite = false, focusRequest = nu
|
|
|
874
1019
|
selectedElement,
|
|
875
1020
|
threads,
|
|
876
1021
|
toggleDrawer: () => setDrawerOpen((open) => !open),
|
|
877
|
-
visible,
|
|
1022
|
+
visible: commentsVisible,
|
|
878
1023
|
},
|
|
879
1024
|
}, [
|
|
880
1025
|
React.createElement(DiagramCommentsExcalidraw, {
|
|
881
1026
|
initialData,
|
|
882
1027
|
key: 'excalidraw',
|
|
883
1028
|
renderKey: editorRenderKey,
|
|
884
|
-
viewModeEnabled: getDocumentViewState().viewModeEnabled,
|
|
1029
|
+
viewModeEnabled: presentationMode || getDocumentViewState().viewModeEnabled,
|
|
885
1030
|
}),
|
|
886
1031
|
renderCommentsOverlay,
|
|
887
|
-
|
|
1032
|
+
renderPresentationNavigation,
|
|
1033
|
+
]));
|
|
888
1034
|
}
|
|
889
1035
|
|
|
890
1036
|
function renderExcalidrawApp({ initialData } = {}) {
|
|
@@ -3,7 +3,7 @@ import { resolveAppUrl } from '../infrastructure/runtime-config.js';
|
|
|
3
3
|
const EXPORT_PAGE_SOURCE = 'collabmd-export-page';
|
|
4
4
|
const EXPORT_HOST_SOURCE = 'collabmd-export-host';
|
|
5
5
|
const EXPORT_JOB_CLOSE_POLL_MS = 500;
|
|
6
|
-
const EXPORT_JOB_TIMEOUT_MS =
|
|
6
|
+
const EXPORT_JOB_TIMEOUT_MS = 300_000;
|
|
7
7
|
const pendingJobs = new Map();
|
|
8
8
|
let exportBridgeErrorHandler = null;
|
|
9
9
|
|
|
@@ -15,31 +15,29 @@ function normalizeFormat(format) {
|
|
|
15
15
|
return ['html', 'pdf'].includes(format) ? format : 'docx';
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
function buildExportUrl({ filePath, format, jobId }) {
|
|
19
|
-
const url = new URL(resolveAppUrl('/export-document.html'), window.location.origin);
|
|
20
|
-
url.searchParams.set('action', normalizeFormat(format));
|
|
21
|
-
url.searchParams.set('job', jobId);
|
|
22
|
-
if (filePath) {
|
|
23
|
-
url.searchParams.set('file', filePath);
|
|
24
|
-
}
|
|
25
|
-
return url.toString();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
18
|
function createBootstrapPayload({
|
|
19
|
+
currentFilePath = '',
|
|
20
|
+
currentMarkdownText = '',
|
|
21
|
+
directoryPath = '',
|
|
29
22
|
fileList = [],
|
|
30
23
|
filePath,
|
|
31
24
|
format,
|
|
32
25
|
jobId,
|
|
33
26
|
markdownText = '',
|
|
27
|
+
theme = 'light',
|
|
34
28
|
title = '',
|
|
35
29
|
}) {
|
|
36
30
|
return {
|
|
37
31
|
action: normalizeFormat(format),
|
|
32
|
+
currentFilePath: String(currentFilePath ?? ''),
|
|
33
|
+
currentMarkdownText: String(currentMarkdownText ?? ''),
|
|
34
|
+
directoryPath: String(directoryPath ?? ''),
|
|
38
35
|
fileList: Array.isArray(fileList) ? fileList.slice() : [],
|
|
39
36
|
filePath: String(filePath ?? ''),
|
|
40
37
|
jobId,
|
|
41
38
|
markdownText: String(markdownText ?? ''),
|
|
42
39
|
source: EXPORT_HOST_SOURCE,
|
|
40
|
+
theme: theme === 'dark' ? 'dark' : 'light',
|
|
43
41
|
title: String(title ?? ''),
|
|
44
42
|
type: 'bootstrap',
|
|
45
43
|
};
|
|
@@ -136,26 +134,9 @@ export function initializeExportBridge({
|
|
|
136
134
|
window.__collabmdExportBridgeInitialized = true;
|
|
137
135
|
}
|
|
138
136
|
|
|
139
|
-
|
|
140
|
-
fileList = [],
|
|
141
|
-
filePath,
|
|
142
|
-
format,
|
|
143
|
-
markdownText = '',
|
|
144
|
-
title = '',
|
|
145
|
-
} = {}) {
|
|
146
|
-
const normalizedFilePath = String(filePath ?? '').trim();
|
|
147
|
-
if (!normalizedFilePath) {
|
|
148
|
-
throw new Error('No markdown note is open');
|
|
149
|
-
}
|
|
150
|
-
|
|
137
|
+
async function startExport(payload) {
|
|
151
138
|
const jobId = createJobId();
|
|
152
|
-
const
|
|
153
|
-
filePath: normalizedFilePath,
|
|
154
|
-
format,
|
|
155
|
-
jobId,
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
const exportWindow = window.open(url, '_blank');
|
|
139
|
+
const exportWindow = globalThis.open('', jobId);
|
|
159
140
|
if (!exportWindow) {
|
|
160
141
|
throw new Error('Export popup was blocked');
|
|
161
142
|
}
|
|
@@ -172,12 +153,9 @@ export async function exportDocument({
|
|
|
172
153
|
});
|
|
173
154
|
}, EXPORT_JOB_CLOSE_POLL_MS),
|
|
174
155
|
payload: createBootstrapPayload({
|
|
175
|
-
|
|
176
|
-
filePath: normalizedFilePath,
|
|
177
|
-
format,
|
|
156
|
+
...payload,
|
|
178
157
|
jobId,
|
|
179
|
-
|
|
180
|
-
title,
|
|
158
|
+
theme: document.documentElement.dataset.theme,
|
|
181
159
|
}),
|
|
182
160
|
timeoutId: window.setTimeout(() => {
|
|
183
161
|
finishPendingJob(jobId, {
|
|
@@ -188,6 +166,49 @@ export async function exportDocument({
|
|
|
188
166
|
window: exportWindow,
|
|
189
167
|
});
|
|
190
168
|
|
|
169
|
+
exportWindow.location.replace(resolveAppUrl('/export-document.html'));
|
|
191
170
|
exportWindow.focus?.();
|
|
192
171
|
return jobId;
|
|
193
172
|
}
|
|
173
|
+
|
|
174
|
+
export async function exportDirectory({
|
|
175
|
+
currentFilePath = '',
|
|
176
|
+
currentMarkdownText = '',
|
|
177
|
+
directoryPath,
|
|
178
|
+
fileList = [],
|
|
179
|
+
format,
|
|
180
|
+
} = {}) {
|
|
181
|
+
const normalizedDirectoryPath = String(directoryPath ?? '').replace(/\\/gu, '/').replace(/^\/+|\/+$/gu, '').trim();
|
|
182
|
+
if (!normalizedDirectoryPath) {
|
|
183
|
+
throw new Error('No folder was selected');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return startExport({
|
|
187
|
+
currentFilePath,
|
|
188
|
+
currentMarkdownText,
|
|
189
|
+
directoryPath: normalizedDirectoryPath,
|
|
190
|
+
fileList,
|
|
191
|
+
format,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export async function exportDocument({
|
|
196
|
+
fileList = [],
|
|
197
|
+
filePath,
|
|
198
|
+
format,
|
|
199
|
+
markdownText = '',
|
|
200
|
+
title = '',
|
|
201
|
+
} = {}) {
|
|
202
|
+
const normalizedFilePath = String(filePath ?? '').trim();
|
|
203
|
+
if (!normalizedFilePath) {
|
|
204
|
+
throw new Error('No markdown note is open');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return startExport({
|
|
208
|
+
fileList,
|
|
209
|
+
filePath: normalizedFilePath,
|
|
210
|
+
format,
|
|
211
|
+
markdownText,
|
|
212
|
+
title,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
postExportPageMessage,
|
|
3
|
+
prepareDirectoryExportSnapshot,
|
|
3
4
|
prepareExportSnapshot,
|
|
4
5
|
runExportAdapter,
|
|
5
6
|
waitForBootstrapPayload,
|
|
@@ -7,6 +8,10 @@ import {
|
|
|
7
8
|
} from './export-pipeline.js';
|
|
8
9
|
import { groupHeadingWithFollowingBlock } from './export-print-layout.js';
|
|
9
10
|
|
|
11
|
+
function getExportJobId() {
|
|
12
|
+
return new URLSearchParams(window.location.search).get('job') || window.name || '';
|
|
13
|
+
}
|
|
14
|
+
|
|
10
15
|
function setStatus(message) {
|
|
11
16
|
const status = document.getElementById('exportStatus');
|
|
12
17
|
if (status) {
|
|
@@ -38,7 +43,8 @@ function renderSnapshot(snapshot) {
|
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
document.title = `${snapshot.title} — Export`;
|
|
41
|
-
|
|
46
|
+
const parsed = new DOMParser().parseFromString(`<body>${snapshot.html}</body>`, 'text/html');
|
|
47
|
+
mount.replaceChildren(...parsed.body.childNodes);
|
|
42
48
|
groupHeadingWithFollowingBlock(mount);
|
|
43
49
|
renderWarnings(snapshot);
|
|
44
50
|
return mount;
|
|
@@ -48,7 +54,11 @@ async function bootstrap() {
|
|
|
48
54
|
try {
|
|
49
55
|
setStatus('Loading export content…');
|
|
50
56
|
const payload = await waitForBootstrapPayload();
|
|
51
|
-
|
|
57
|
+
document.documentElement.dataset.theme = payload.theme;
|
|
58
|
+
document.body.dataset.theme = payload.theme;
|
|
59
|
+
const snapshot = payload.directoryPath
|
|
60
|
+
? await prepareDirectoryExportSnapshot(payload)
|
|
61
|
+
: await prepareExportSnapshot(payload);
|
|
52
62
|
const mount = renderSnapshot(snapshot);
|
|
53
63
|
snapshot.html = await waitForRenderedExportContent(mount);
|
|
54
64
|
setStatus(payload.action === 'pdf'
|
|
@@ -58,12 +68,12 @@ async function bootstrap() {
|
|
|
58
68
|
setStatus(payload.action === 'pdf'
|
|
59
69
|
? 'Print dialog opened.'
|
|
60
70
|
: `${payload.action.toUpperCase()} download started.`);
|
|
61
|
-
postExportPageMessage('complete', { jobId:
|
|
71
|
+
postExportPageMessage('complete', { jobId: getExportJobId() });
|
|
62
72
|
} catch (error) {
|
|
63
73
|
const message = error instanceof Error ? error.message : 'Export failed';
|
|
64
74
|
setStatus(message);
|
|
65
75
|
postExportPageMessage('error', {
|
|
66
|
-
jobId:
|
|
76
|
+
jobId: getExportJobId(),
|
|
67
77
|
message,
|
|
68
78
|
});
|
|
69
79
|
}
|