@youtyan/code-viewer 0.1.36 → 0.1.37

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 (2) hide show
  1. package/package.json +1 -1
  2. package/web/app.js +64 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@youtyan/code-viewer",
3
- "version": "0.1.36",
3
+ "version": "0.1.37",
4
4
  "description": "Local browser-based code and git diff viewer",
5
5
  "type": "module",
6
6
  "bin": {
package/web/app.js CHANGED
@@ -532,16 +532,16 @@
532
532
  };
533
533
  deps.jump(item.entryId).then(proceed, proceed);
534
534
  }
535
- function play() {
535
+ function play(fromIndex) {
536
536
  if (status === "playing")
537
537
  return;
538
538
  if (status === "paused") {
539
- startEntry(index);
539
+ startEntry(fromIndex ?? index);
540
540
  return;
541
541
  }
542
542
  if (deps.items().length === 0)
543
543
  return;
544
- startEntry(0);
544
+ startEntry(fromIndex ?? 0);
545
545
  }
546
546
  function pause() {
547
547
  if (status !== "playing")
@@ -574,6 +574,11 @@
574
574
  deps.jump(item.entryId).catch(() => {});
575
575
  }
576
576
  }
577
+ function jumpTo(at) {
578
+ if (status === "idle")
579
+ return;
580
+ moveTo(at);
581
+ }
577
582
  function next() {
578
583
  if (status === "idle")
579
584
  return;
@@ -603,7 +608,17 @@
603
608
  rate = value;
604
609
  restartCurrentIfPlaying();
605
610
  }
606
- return { play, pause, stop, next, prev, setMuted, setRate, getState };
611
+ return {
612
+ play,
613
+ pause,
614
+ stop,
615
+ next,
616
+ prev,
617
+ jumpTo,
618
+ setMuted,
619
+ setRate,
620
+ getState
621
+ };
607
622
  }
608
623
 
609
624
  // web-src/core/annotation-speech.ts
@@ -616,6 +631,7 @@
616
631
  text = text.replace(/\[([^\]]*)\]\([^)]*\)/g, "$1");
617
632
  text = text.replace(/`([^`]*)`/g, "$1");
618
633
  text = text.replace(/https?:\/\/\S+/g, "URL");
634
+ text = text.replace(/<([^<>]*)>/g, " $1 ");
619
635
  text = text.replace(/^[ \t]*(?:#{1,6}|>|[-*+]|\d+\.)[ \t]+/gm, "");
620
636
  text = text.replace(/(\*\*|__|\*|_)/g, "");
621
637
  return text.replace(/\s+/g, " ").trim();
@@ -689,9 +705,17 @@
689
705
  prevBtn.disabled = state.status === "idle";
690
706
  nextBtn.disabled = state.status === "idle";
691
707
  }
708
+ let selfJumping = false;
692
709
  const core = createAnnotationPlayerCore({
693
710
  items,
694
- jump: (entryId) => deps.openAnnotationEntry(entryId),
711
+ jump: async (entryId) => {
712
+ selfJumping = true;
713
+ try {
714
+ await deps.openAnnotationEntry(entryId);
715
+ } finally {
716
+ selfJumping = false;
717
+ }
718
+ },
695
719
  speak,
696
720
  schedule: (ms, cb) => {
697
721
  const id = window.setTimeout(cb, ms);
@@ -713,13 +737,23 @@
713
737
  rateSel.disabled = true;
714
738
  core.setMuted(true);
715
739
  }
740
+ function entryIndexOf(entryId) {
741
+ if (!entryId)
742
+ return -1;
743
+ return deps.getActiveSessionEntries().findIndex((entry) => entry.id === entryId);
744
+ }
716
745
  toggleBtn.addEventListener("click", () => {
717
746
  const state = core.getState();
718
747
  if (state.status === "playing") {
719
748
  core.pause();
720
749
  } else {
721
750
  deps.setAnnotationPanelOpen(true);
722
- core.play();
751
+ if (state.status === "idle") {
752
+ const activeIndex = entryIndexOf(deps.getActiveAnnotationId());
753
+ core.play(activeIndex >= 0 ? activeIndex : 0);
754
+ } else {
755
+ core.play();
756
+ }
723
757
  }
724
758
  });
725
759
  prevBtn.addEventListener("click", () => core.prev());
@@ -743,6 +777,15 @@
743
777
  core.stop();
744
778
  syncVisibility();
745
779
  });
780
+ deps.onAnnotationOpened((entryId) => {
781
+ if (selfJumping)
782
+ return;
783
+ if (core.getState().status === "idle")
784
+ return;
785
+ const index = entryIndexOf(entryId);
786
+ if (index >= 0)
787
+ core.jumpTo(index);
788
+ });
746
789
  syncVisibility();
747
790
  render(core.getState());
748
791
  return { stop: () => core.stop(), syncVisibility };
@@ -6970,6 +7013,11 @@ ${frontmatter.yaml}
6970
7013
  for (const cb of annotationsChangedCallbacks)
6971
7014
  cb();
6972
7015
  }
7016
+ const annotationOpenedCallbacks = [];
7017
+ function notifyAnnotationOpened(entryId) {
7018
+ for (const cb of annotationOpenedCallbacks)
7019
+ cb(entryId);
7020
+ }
6973
7021
  let mdHighlighter = null;
6974
7022
  let mdHighlighterRequested = false;
6975
7023
  function ensureMarkdownHighlighter() {
@@ -7475,6 +7523,7 @@ ${frontmatter.yaml}
7475
7523
  activeSessionId = session.id;
7476
7524
  if (sessionChanged)
7477
7525
  notifyAnnotationsChanged();
7526
+ notifyAnnotationOpened(entry.id);
7478
7527
  showAnnotationDetail(session, entry, index);
7479
7528
  const from = entry.range.from || "HEAD";
7480
7529
  const to = entry.range.to || "worktree";
@@ -7595,6 +7644,12 @@ ${frontmatter.yaml}
7595
7644
  },
7596
7645
  onAnnotationsChanged(cb) {
7597
7646
  annotationsChangedCallbacks.push(cb);
7647
+ },
7648
+ onAnnotationOpened(cb) {
7649
+ annotationOpenedCallbacks.push(cb);
7650
+ },
7651
+ getActiveAnnotationId() {
7652
+ return activeAnnotationId;
7598
7653
  }
7599
7654
  };
7600
7655
  }
@@ -15874,7 +15929,9 @@ ${frontmatter.yaml}
15874
15929
  getActiveSessionEntries: () => ANNOTATIONS_UI?.getActiveSessionEntries() ?? [],
15875
15930
  openAnnotationEntry: (id) => ANNOTATIONS_UI ? ANNOTATIONS_UI.openAnnotationEntry(id) : Promise.resolve(),
15876
15931
  setAnnotationPanelOpen: (open) => ANNOTATIONS_UI?.setAnnotationPanelOpen(open),
15877
- onAnnotationsChanged: (cb) => ANNOTATIONS_UI?.onAnnotationsChanged(cb)
15932
+ onAnnotationsChanged: (cb) => ANNOTATIONS_UI?.onAnnotationsChanged(cb),
15933
+ onAnnotationOpened: (cb) => ANNOTATIONS_UI?.onAnnotationOpened(cb),
15934
+ getActiveAnnotationId: () => ANNOTATIONS_UI ? ANNOTATIONS_UI.getActiveAnnotationId() : null
15878
15935
  });
15879
15936
  let sseTimer = null;
15880
15937
  function scheduleSseLoad() {