mdv-live 0.3.7 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mdv-live",
3
- "version": "0.3.7",
3
+ "version": "0.3.8",
4
4
  "description": "Markdown Viewer - File tree + Live preview + Marp support + Hot reload",
5
5
  "main": "src/server.js",
6
6
  "bin": {
package/src/static/app.js CHANGED
@@ -613,6 +613,11 @@
613
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
614
  </svg>
615
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>
616
621
  `;
617
622
  marpit.appendChild(nav);
618
623
  }
@@ -676,17 +681,83 @@
676
681
 
677
682
  // Fullscreen toggle
678
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>';
679
686
  const toggleFullscreen = () => {
680
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
+ }
681
702
  };
682
703
  if (fullscreenBtn) fullscreenBtn.addEventListener('click', toggleFullscreen);
683
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
+
684
754
  // Keyboard navigation
685
755
  marpKeyHandler = (e) => {
686
756
  // Don't handle if editing or in dialog
687
757
  if (state.isEditMode || !elements.dialogOverlay.classList.contains('hidden')) {
688
758
  return;
689
759
  }
760
+ const nav = elements.content.querySelector('.marp-nav');
690
761
  if (e.key === 'ArrowRight' || e.key === ' ') {
691
762
  e.preventDefault();
692
763
  nextSlide();
@@ -696,9 +767,16 @@
696
767
  } else if (e.key === 'f' || e.key === 'F') {
697
768
  e.preventDefault();
698
769
  toggleFullscreen();
699
- } else if (e.key === 'Escape' && document.body.classList.contains('marp-fullscreen')) {
770
+ } else if (e.key === 'n' || e.key === 'N') {
700
771
  e.preventDefault();
701
- document.body.classList.remove('marp-fullscreen');
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
+ }
702
780
  }
703
781
  };
704
782
  document.addEventListener('keydown', marpKeyHandler);
@@ -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,6 +912,19 @@ 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);
@@ -950,7 +964,10 @@ body.marp-fullscreen .content {
950
964
 
951
965
  body.marp-fullscreen .marp-nav {
952
966
  bottom: 32px;
953
- right: 32px;
967
+ left: 50%;
968
+ right: auto;
969
+ transform: translateX(-50%);
970
+ cursor: grab;
954
971
  }
955
972
 
956
973
  body.marp-fullscreen .marpit {
@@ -970,6 +987,19 @@ body.marp-fullscreen .marpit > svg[data-marpit-svg] {
970
987
  margin-left: 4px;
971
988
  }
972
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
+
973
1003
  /* Print styles for Marp */
974
1004
  @media print {
975
1005
  .marp-nav { display: none !important; }