mdv-live 0.3.6 → 0.3.8
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/bin/mdv.js +1 -1
- package/package.json +1 -1
- package/src/api/pdf.js +1 -1
- package/src/static/app.js +97 -0
- package/src/static/styles.css +83 -0
package/bin/mdv.js
CHANGED
|
@@ -274,7 +274,7 @@ async function convertToPdf(inputPath, outputPath) {
|
|
|
274
274
|
*/
|
|
275
275
|
async function convertMarpToPdf(inputPath, outputPath) {
|
|
276
276
|
try {
|
|
277
|
-
execSync(`npx @marp-team/marp-cli --no-stdin "${inputPath}" --pdf -o "${outputPath}"`, {
|
|
277
|
+
execSync(`npx @marp-team/marp-cli --no-stdin "${inputPath}" --pdf --html --allow-local-files -o "${outputPath}"`, {
|
|
278
278
|
encoding: 'utf-8',
|
|
279
279
|
stdio: 'inherit'
|
|
280
280
|
});
|
package/package.json
CHANGED
package/src/api/pdf.js
CHANGED
|
@@ -49,7 +49,7 @@ export function setupPdfRoutes(app) {
|
|
|
49
49
|
|
|
50
50
|
const outputPath = fullPath.replace(/\.md$/, '.pdf');
|
|
51
51
|
const outputFileName = path.basename(outputPath);
|
|
52
|
-
const command = `"${marpBin}" "${fullPath}" -o "${outputPath}" --allow-local-files --no-stdin`;
|
|
52
|
+
const command = `"${marpBin}" "${fullPath}" -o "${outputPath}" --html --allow-local-files --no-stdin`;
|
|
53
53
|
|
|
54
54
|
try {
|
|
55
55
|
await execAsync(command, { timeout: 60000 });
|
package/src/static/app.js
CHANGED
|
@@ -608,6 +608,16 @@
|
|
|
608
608
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
|
609
609
|
</svg>
|
|
610
610
|
</button>
|
|
611
|
+
<button class="marp-fullscreen-btn" title="Fullscreen (F)">
|
|
612
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
613
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4" />
|
|
614
|
+
</svg>
|
|
615
|
+
</button>
|
|
616
|
+
<button class="marp-close-nav" title="Hide (N to show)">
|
|
617
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
618
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
619
|
+
</svg>
|
|
620
|
+
</button>
|
|
611
621
|
`;
|
|
612
622
|
marpit.appendChild(nav);
|
|
613
623
|
}
|
|
@@ -669,18 +679,104 @@
|
|
|
669
679
|
if (prevBtn) prevBtn.addEventListener('click', prevSlide);
|
|
670
680
|
if (nextBtn) nextBtn.addEventListener('click', nextSlide);
|
|
671
681
|
|
|
682
|
+
// Fullscreen toggle
|
|
683
|
+
const fullscreenBtn = elements.content.querySelector('.marp-fullscreen-btn');
|
|
684
|
+
const expandIcon = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4" /></svg>';
|
|
685
|
+
const shrinkIcon = '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 9V4m0 5H4m5 0L4 4m11 5h5m-5 0V4m0 5l5-5M9 15v5m0-5H4m5 0l-5 5m11-5h5m-5 0v5m0-5l5 5" /></svg>';
|
|
686
|
+
const toggleFullscreen = () => {
|
|
687
|
+
document.body.classList.toggle('marp-fullscreen');
|
|
688
|
+
const isFullscreen = document.body.classList.contains('marp-fullscreen');
|
|
689
|
+
if (fullscreenBtn) {
|
|
690
|
+
fullscreenBtn.innerHTML = isFullscreen ? shrinkIcon : expandIcon;
|
|
691
|
+
fullscreenBtn.title = isFullscreen ? 'Exit Fullscreen (Esc)' : 'Fullscreen (F)';
|
|
692
|
+
}
|
|
693
|
+
// Reset nav position when exiting fullscreen
|
|
694
|
+
const nav = elements.content.querySelector('.marp-nav');
|
|
695
|
+
if (!isFullscreen && nav) {
|
|
696
|
+
nav.style.left = '';
|
|
697
|
+
nav.style.top = '';
|
|
698
|
+
nav.style.right = '';
|
|
699
|
+
nav.style.bottom = '';
|
|
700
|
+
nav.style.transform = '';
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
if (fullscreenBtn) fullscreenBtn.addEventListener('click', toggleFullscreen);
|
|
704
|
+
|
|
705
|
+
// Make nav draggable and closeable
|
|
706
|
+
const nav = elements.content.querySelector('.marp-nav');
|
|
707
|
+
if (nav) {
|
|
708
|
+
let isDragging = false;
|
|
709
|
+
let dragStartX, dragStartY, navStartX, navStartY;
|
|
710
|
+
|
|
711
|
+
nav.addEventListener('mousedown', (e) => {
|
|
712
|
+
// Don't drag when clicking buttons or not in fullscreen
|
|
713
|
+
if (e.target.closest('button')) return;
|
|
714
|
+
if (!document.body.classList.contains('marp-fullscreen')) return;
|
|
715
|
+
isDragging = true;
|
|
716
|
+
nav.classList.add('dragging');
|
|
717
|
+
dragStartX = e.clientX;
|
|
718
|
+
dragStartY = e.clientY;
|
|
719
|
+
const rect = nav.getBoundingClientRect();
|
|
720
|
+
navStartX = rect.left;
|
|
721
|
+
navStartY = rect.top;
|
|
722
|
+
e.preventDefault();
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
document.addEventListener('mousemove', (e) => {
|
|
726
|
+
if (!isDragging) return;
|
|
727
|
+
const dx = e.clientX - dragStartX;
|
|
728
|
+
const dy = e.clientY - dragStartY;
|
|
729
|
+
const newX = Math.max(0, Math.min(window.innerWidth - nav.offsetWidth, navStartX + dx));
|
|
730
|
+
const newY = Math.max(0, Math.min(window.innerHeight - nav.offsetHeight, navStartY + dy));
|
|
731
|
+
nav.style.left = newX + 'px';
|
|
732
|
+
nav.style.top = newY + 'px';
|
|
733
|
+
nav.style.right = 'auto';
|
|
734
|
+
nav.style.bottom = 'auto';
|
|
735
|
+
nav.style.transform = 'none';
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
document.addEventListener('mouseup', () => {
|
|
739
|
+
if (isDragging) {
|
|
740
|
+
isDragging = false;
|
|
741
|
+
nav.classList.remove('dragging');
|
|
742
|
+
}
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
// Close button to hide nav
|
|
746
|
+
const closeBtn = nav.querySelector('.marp-close-nav');
|
|
747
|
+
if (closeBtn) {
|
|
748
|
+
closeBtn.addEventListener('click', () => {
|
|
749
|
+
nav.classList.add('hidden');
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
|
|
672
754
|
// Keyboard navigation
|
|
673
755
|
marpKeyHandler = (e) => {
|
|
674
756
|
// Don't handle if editing or in dialog
|
|
675
757
|
if (state.isEditMode || !elements.dialogOverlay.classList.contains('hidden')) {
|
|
676
758
|
return;
|
|
677
759
|
}
|
|
760
|
+
const nav = elements.content.querySelector('.marp-nav');
|
|
678
761
|
if (e.key === 'ArrowRight' || e.key === ' ') {
|
|
679
762
|
e.preventDefault();
|
|
680
763
|
nextSlide();
|
|
681
764
|
} else if (e.key === 'ArrowLeft') {
|
|
682
765
|
e.preventDefault();
|
|
683
766
|
prevSlide();
|
|
767
|
+
} else if (e.key === 'f' || e.key === 'F') {
|
|
768
|
+
e.preventDefault();
|
|
769
|
+
toggleFullscreen();
|
|
770
|
+
} else if (e.key === 'n' || e.key === 'N') {
|
|
771
|
+
e.preventDefault();
|
|
772
|
+
if (nav) nav.classList.toggle('hidden');
|
|
773
|
+
} else if (e.key === 'Escape') {
|
|
774
|
+
e.preventDefault();
|
|
775
|
+
if (document.body.classList.contains('marp-fullscreen')) {
|
|
776
|
+
toggleFullscreen();
|
|
777
|
+
} else if (nav && nav.classList.contains('hidden')) {
|
|
778
|
+
nav.classList.remove('hidden');
|
|
779
|
+
}
|
|
684
780
|
}
|
|
685
781
|
};
|
|
686
782
|
document.addEventListener('keydown', marpKeyHandler);
|
|
@@ -688,6 +784,7 @@
|
|
|
688
784
|
|
|
689
785
|
cleanupMarp() {
|
|
690
786
|
elements.content.classList.remove('marp-viewer');
|
|
787
|
+
document.body.classList.remove('marp-fullscreen');
|
|
691
788
|
if (marpKeyHandler) {
|
|
692
789
|
document.removeEventListener('keydown', marpKeyHandler);
|
|
693
790
|
marpKeyHandler = null;
|
package/src/static/styles.css
CHANGED
|
@@ -875,6 +875,7 @@ body {
|
|
|
875
875
|
border-radius: 8px;
|
|
876
876
|
border: 1px solid var(--border);
|
|
877
877
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
|
878
|
+
user-select: none;
|
|
878
879
|
}
|
|
879
880
|
|
|
880
881
|
.marp-nav button {
|
|
@@ -911,12 +912,94 @@ body {
|
|
|
911
912
|
text-align: center;
|
|
912
913
|
}
|
|
913
914
|
|
|
915
|
+
body.marp-fullscreen .marp-nav .slide-counter {
|
|
916
|
+
cursor: grab;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
body.marp-fullscreen .marp-nav.dragging {
|
|
920
|
+
cursor: grabbing;
|
|
921
|
+
opacity: 0.9;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
body.marp-fullscreen .marp-nav.dragging .slide-counter {
|
|
925
|
+
cursor: grabbing;
|
|
926
|
+
}
|
|
927
|
+
|
|
914
928
|
.marp-nav .keyboard-hint {
|
|
915
929
|
font-size: 11px;
|
|
916
930
|
color: var(--text-muted);
|
|
917
931
|
margin-left: 8px;
|
|
918
932
|
}
|
|
919
933
|
|
|
934
|
+
/* Fullscreen Mode */
|
|
935
|
+
body.marp-fullscreen {
|
|
936
|
+
overflow: hidden;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
body.marp-fullscreen .sidebar,
|
|
940
|
+
body.marp-fullscreen .resize-handle,
|
|
941
|
+
body.marp-fullscreen .toolbar,
|
|
942
|
+
body.marp-fullscreen .tab-bar {
|
|
943
|
+
display: none !important;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
body.marp-fullscreen .container {
|
|
947
|
+
display: block;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
body.marp-fullscreen .main {
|
|
951
|
+
position: fixed;
|
|
952
|
+
top: 0;
|
|
953
|
+
left: 0;
|
|
954
|
+
right: 0;
|
|
955
|
+
bottom: 0;
|
|
956
|
+
z-index: 9999;
|
|
957
|
+
background: #0f172a;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
body.marp-fullscreen .content {
|
|
961
|
+
height: 100vh;
|
|
962
|
+
padding: 0;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
body.marp-fullscreen .marp-nav {
|
|
966
|
+
bottom: 32px;
|
|
967
|
+
left: 50%;
|
|
968
|
+
right: auto;
|
|
969
|
+
transform: translateX(-50%);
|
|
970
|
+
cursor: grab;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
body.marp-fullscreen .marpit {
|
|
974
|
+
padding: 0;
|
|
975
|
+
height: 100vh;
|
|
976
|
+
display: flex;
|
|
977
|
+
align-items: center;
|
|
978
|
+
justify-content: center;
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
body.marp-fullscreen .marpit > svg[data-marpit-svg] {
|
|
982
|
+
max-height: 95vh;
|
|
983
|
+
max-width: 95vw;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
.marp-fullscreen-btn {
|
|
987
|
+
margin-left: 4px;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
.marp-close-nav {
|
|
991
|
+
margin-left: 4px;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
.marp-close-nav:hover:not(:disabled) {
|
|
995
|
+
background: var(--danger) !important;
|
|
996
|
+
border-color: var(--danger) !important;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
.marp-nav.hidden {
|
|
1000
|
+
display: none !important;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
920
1003
|
/* Print styles for Marp */
|
|
921
1004
|
@media print {
|
|
922
1005
|
.marp-nav { display: none !important; }
|