pi-studio 0.5.50 → 0.5.51
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/CHANGELOG.md +13 -0
- package/README.md +1 -1
- package/client/studio-client.js +207 -91
- package/client/studio.css +26 -20
- package/index.ts +4 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ All notable changes to `pi-studio` are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.5.51] — 2026-04-09
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- Raw-editor selection actions now also include a transient **Jump** control beside **Comment** when the right pane is showing **Editor (Preview)**, so editor selections can reveal the corresponding preview location without creating a local comment first.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Selection-time **Comment** / **Jump** affordances are now more consistent across raw editor and preview: preview-side actions use a fixed top-right action area while remaining transient and selection-only.
|
|
14
|
+
- Standalone selection **Jump** actions now use the same preview highlight/reveal treatment as comment-card jumps, making it easier to stay oriented after jumping in either direction.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- Preview-side selection actions are once again hidden unless an appropriate preview text selection is active.
|
|
18
|
+
- Code/text/diff preview selection mapping now preserves literal underscores in identifiers such as `add_subplot`, avoiding comment/jump failures caused by markdown-style underscore stripping.
|
|
19
|
+
|
|
7
20
|
## [0.5.50] — 2026-04-09
|
|
8
21
|
|
|
9
22
|
### Added
|
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ Extension for [pi](https://pi.dev) that opens a local two-pane browser workspace
|
|
|
18
18
|
- Supports one canonical full Studio view per Pi session, plus additional editor-only companion views when you just want extra editing/preview surfaces
|
|
19
19
|
- Runs editor text directly, or asks for structured critique (auto/writing/code focus)
|
|
20
20
|
- Includes a local persistent scratchpad for quick notes you want to keep out of the main editor until you're ready to copy or insert them
|
|
21
|
-
- Includes local comments anchored to selections/lines, shown in a docked **Comments** rail, with **Comment** actions from raw-editor selections plus editor-preview selections for Markdown, LaTeX, and code/text/diff previews, alongside
|
|
21
|
+
- Includes local comments anchored to selections/lines, shown in a docked **Comments** rail, with transient **Comment** / **Jump** actions from raw-editor selections plus editor-preview selections for Markdown, LaTeX, and code/text/diff previews, alongside optional inline `[an: ...]` toggles when you want comments reflected in the document text
|
|
22
22
|
- Browses response history (`Prev/Next/Last`) and loads either:
|
|
23
23
|
- response text
|
|
24
24
|
- critique notes/full critique
|
package/client/studio-client.js
CHANGED
|
@@ -53,7 +53,9 @@
|
|
|
53
53
|
const lineNumberGutterContentEl = document.getElementById("lineNumberGutterContent");
|
|
54
54
|
const lineNumberMeasureEl = document.getElementById("lineNumberMeasure");
|
|
55
55
|
const sourcePreviewEl = document.getElementById("sourcePreview");
|
|
56
|
+
const editorSelectionActionsEl = document.getElementById("editorSelectionActions");
|
|
56
57
|
const editorSelectionCommentBtn = document.getElementById("editorSelectionCommentBtn");
|
|
58
|
+
const editorSelectionJumpBtn = document.getElementById("editorSelectionJumpBtn");
|
|
57
59
|
const leftPaneEl = document.getElementById("leftPane");
|
|
58
60
|
const rightPaneEl = document.getElementById("rightPane");
|
|
59
61
|
const sourceBadgeEl = document.getElementById("sourceBadge");
|
|
@@ -3859,11 +3861,6 @@
|
|
|
3859
3861
|
+ " data-review-note-line-end='" + String(lineNumber) + "'"
|
|
3860
3862
|
+ " data-preview-comment-kind='" + escapeHtml(kind) + "'"
|
|
3861
3863
|
+ ">"
|
|
3862
|
-
+ "<div class='preview-comment-controls'>"
|
|
3863
|
-
+ "<button type='button' class='preview-comment-summary' hidden></button>"
|
|
3864
|
-
+ "<button type='button' class='preview-comment-add' data-preview-comment-action='comment'>Comment</button>"
|
|
3865
|
-
+ "<button type='button' class='preview-comment-jump' data-preview-comment-action='jump'>Jump</button>"
|
|
3866
|
-
+ "</div>"
|
|
3867
3864
|
+ "<div class='preview-comment-block-content preview-code-line-content'>" + lineHtml + "</div>"
|
|
3868
3865
|
+ "</div>",
|
|
3869
3866
|
);
|
|
@@ -3879,6 +3876,7 @@
|
|
|
3879
3876
|
clearPreviewJumpHighlight(targetEl);
|
|
3880
3877
|
finishPreviewRender(targetEl);
|
|
3881
3878
|
targetEl.innerHTML = buildCodePreviewHtmlWithCommentBlocks(text, editorLanguage || "");
|
|
3879
|
+
ensurePreviewSelectionActions(targetEl);
|
|
3882
3880
|
updatePreviewCommentBlocksForElement(targetEl);
|
|
3883
3881
|
if (pane === "response") {
|
|
3884
3882
|
applyPendingResponseScrollReset();
|
|
@@ -5575,8 +5573,23 @@
|
|
|
5575
5573
|
return bestIndex;
|
|
5576
5574
|
}
|
|
5577
5575
|
|
|
5576
|
+
function buildLiteralPreviewDisplayMap(text, rawOffsets) {
|
|
5577
|
+
const source = String(text || "");
|
|
5578
|
+
const rawMap = Array.isArray(rawOffsets) ? rawOffsets : [];
|
|
5579
|
+
const charStarts = [];
|
|
5580
|
+
const charEnds = [];
|
|
5581
|
+
for (let i = 0; i < source.length; i += 1) {
|
|
5582
|
+
charStarts.push(rawMap[i]);
|
|
5583
|
+
charEnds.push(rawMap[i] + 1);
|
|
5584
|
+
}
|
|
5585
|
+
return buildNormalizedPreviewDisplayMap(source, charStarts, charEnds);
|
|
5586
|
+
}
|
|
5587
|
+
|
|
5578
5588
|
function buildPreviewSelectionDisplayMap(blockText, kind) {
|
|
5579
5589
|
const body = buildPreviewSelectionSourceBody(blockText, kind);
|
|
5590
|
+
if (kind === "code-line" || kind === "diff-line" || kind === "text-line") {
|
|
5591
|
+
return buildLiteralPreviewDisplayMap(body.text, body.rawOffsets);
|
|
5592
|
+
}
|
|
5580
5593
|
const inlineMap = buildPreviewInlineDisplayMap(body.text, body.rawOffsets);
|
|
5581
5594
|
return buildNormalizedPreviewDisplayMap(inlineMap.text, inlineMap.charStarts, inlineMap.charEnds);
|
|
5582
5595
|
}
|
|
@@ -5593,6 +5606,7 @@
|
|
|
5593
5606
|
function getPreviewCommentSelectionKey(selection) {
|
|
5594
5607
|
if (!selection) return "";
|
|
5595
5608
|
return [
|
|
5609
|
+
String(selection.paneId || ""),
|
|
5596
5610
|
String(selection.blockKey || ""),
|
|
5597
5611
|
String(selection.selectionStart || 0),
|
|
5598
5612
|
String(selection.selectionEnd || 0),
|
|
@@ -5620,6 +5634,96 @@
|
|
|
5620
5634
|
: null;
|
|
5621
5635
|
}
|
|
5622
5636
|
|
|
5637
|
+
function getPreviewSelectionPaneIdForNode(node) {
|
|
5638
|
+
if (!node) return "";
|
|
5639
|
+
const element = node instanceof Element ? node : node.parentElement;
|
|
5640
|
+
const paneEl = element && typeof element.closest === "function"
|
|
5641
|
+
? element.closest("#sourcePreview, #critiqueView")
|
|
5642
|
+
: null;
|
|
5643
|
+
return paneEl && paneEl.id ? String(paneEl.id) : "";
|
|
5644
|
+
}
|
|
5645
|
+
|
|
5646
|
+
function getPreviewSelectionPaneElement(paneId) {
|
|
5647
|
+
if (paneId === "sourcePreview") return sourcePreviewEl;
|
|
5648
|
+
if (paneId === "critiqueView") return critiqueViewEl;
|
|
5649
|
+
return null;
|
|
5650
|
+
}
|
|
5651
|
+
|
|
5652
|
+
function getActivePreviewSelectionForPane(paneId) {
|
|
5653
|
+
if (!paneId) return null;
|
|
5654
|
+
return activePreviewCommentSelection && activePreviewCommentSelection.paneId === paneId
|
|
5655
|
+
? activePreviewCommentSelection
|
|
5656
|
+
: null;
|
|
5657
|
+
}
|
|
5658
|
+
|
|
5659
|
+
function ensurePreviewSelectionActions(targetEl) {
|
|
5660
|
+
if (!targetEl || typeof document.createElement !== "function") return null;
|
|
5661
|
+
const paneId = targetEl.id ? String(targetEl.id) : "";
|
|
5662
|
+
if (!paneId) return null;
|
|
5663
|
+
const existing = Array.from(targetEl.children || []).find((child) => child.classList && child.classList.contains("preview-selection-actions"));
|
|
5664
|
+
if (existing) {
|
|
5665
|
+
existing.dataset.previewPane = paneId;
|
|
5666
|
+
return existing;
|
|
5667
|
+
}
|
|
5668
|
+
|
|
5669
|
+
const actionsEl = document.createElement("div");
|
|
5670
|
+
actionsEl.className = "preview-selection-actions";
|
|
5671
|
+
actionsEl.dataset.previewPane = paneId;
|
|
5672
|
+
actionsEl.hidden = true;
|
|
5673
|
+
|
|
5674
|
+
const commentBtn = document.createElement("button");
|
|
5675
|
+
commentBtn.type = "button";
|
|
5676
|
+
commentBtn.className = "preview-comment-add";
|
|
5677
|
+
commentBtn.dataset.previewCommentAction = "comment";
|
|
5678
|
+
commentBtn.textContent = "Comment";
|
|
5679
|
+
commentBtn.hidden = true;
|
|
5680
|
+
actionsEl.appendChild(commentBtn);
|
|
5681
|
+
|
|
5682
|
+
const jumpBtn = document.createElement("button");
|
|
5683
|
+
jumpBtn.type = "button";
|
|
5684
|
+
jumpBtn.className = "preview-comment-jump";
|
|
5685
|
+
jumpBtn.dataset.previewCommentAction = "jump";
|
|
5686
|
+
jumpBtn.textContent = "Jump";
|
|
5687
|
+
jumpBtn.hidden = true;
|
|
5688
|
+
actionsEl.appendChild(jumpBtn);
|
|
5689
|
+
|
|
5690
|
+
targetEl.insertBefore(actionsEl, targetEl.firstChild || null);
|
|
5691
|
+
return actionsEl;
|
|
5692
|
+
}
|
|
5693
|
+
|
|
5694
|
+
function updatePreviewSelectionActions(targetEl) {
|
|
5695
|
+
if (!targetEl) return;
|
|
5696
|
+
const actionsEl = ensurePreviewSelectionActions(targetEl);
|
|
5697
|
+
if (!actionsEl) return;
|
|
5698
|
+
const paneId = targetEl.id ? String(targetEl.id) : "";
|
|
5699
|
+
const selection = getActivePreviewSelectionForPane(paneId);
|
|
5700
|
+
const commentBtn = actionsEl.querySelector(".preview-comment-add");
|
|
5701
|
+
const jumpBtn = actionsEl.querySelector(".preview-comment-jump");
|
|
5702
|
+
if (!selection) {
|
|
5703
|
+
actionsEl.hidden = true;
|
|
5704
|
+
if (commentBtn) commentBtn.hidden = true;
|
|
5705
|
+
if (jumpBtn) jumpBtn.hidden = true;
|
|
5706
|
+
return;
|
|
5707
|
+
}
|
|
5708
|
+
const lineLabel = summarizeReviewNoteAnchor(selection).toLowerCase();
|
|
5709
|
+
const blockKindLabel = getPreviewCommentBlockKindLabel(selection.previewCommentKind || "paragraph");
|
|
5710
|
+
actionsEl.hidden = false;
|
|
5711
|
+
if (commentBtn) {
|
|
5712
|
+
commentBtn.hidden = false;
|
|
5713
|
+
commentBtn.dataset.previewCommentMode = "selection";
|
|
5714
|
+
commentBtn.dataset.previewPane = paneId;
|
|
5715
|
+
commentBtn.title = "Add a local comment from the current preview selection on this " + blockKindLabel + " (" + lineLabel + ").";
|
|
5716
|
+
commentBtn.setAttribute("aria-label", commentBtn.title || "Comment");
|
|
5717
|
+
}
|
|
5718
|
+
if (jumpBtn) {
|
|
5719
|
+
jumpBtn.hidden = false;
|
|
5720
|
+
jumpBtn.dataset.previewCommentMode = "selection";
|
|
5721
|
+
jumpBtn.dataset.previewPane = paneId;
|
|
5722
|
+
jumpBtn.title = "Jump to the current preview selection on this " + blockKindLabel + " in the raw editor (" + lineLabel + ").";
|
|
5723
|
+
jumpBtn.setAttribute("aria-label", jumpBtn.title || "Jump");
|
|
5724
|
+
}
|
|
5725
|
+
}
|
|
5726
|
+
|
|
5623
5727
|
function unwrapPreviewJumpHighlightElement(element) {
|
|
5624
5728
|
if (!element || !element.parentNode) return;
|
|
5625
5729
|
const parent = element.parentNode;
|
|
@@ -6449,52 +6553,26 @@
|
|
|
6449
6553
|
|
|
6450
6554
|
function updatePreviewCommentBlockState(blockEl, sourceText, displayNotes) {
|
|
6451
6555
|
if (!blockEl || !blockEl.dataset) return;
|
|
6452
|
-
const lineStart = Math.max(1, Number(blockEl.dataset.reviewNoteLineStart) || 1);
|
|
6453
|
-
const lineEnd = Math.max(lineStart, Number(blockEl.dataset.reviewNoteLineEnd) || lineStart);
|
|
6454
|
-
const summaryBtn = blockEl.querySelector(".preview-comment-summary");
|
|
6455
|
-
const addBtn = blockEl.querySelector(".preview-comment-add");
|
|
6456
|
-
const jumpBtn = blockEl.querySelector(".preview-comment-jump");
|
|
6457
|
-
const lineLabel = summarizeReviewNoteAnchor({ lineStart: lineStart, lineEnd: lineEnd }).toLowerCase();
|
|
6458
|
-
const blockKindLabel = getPreviewCommentBlockKindLabel(blockEl.dataset.previewCommentKind || "paragraph");
|
|
6459
6556
|
const blockKey = getPreviewCommentBlockKey(blockEl);
|
|
6460
|
-
const
|
|
6557
|
+
const paneId = getPreviewSelectionPaneIdForNode(blockEl);
|
|
6558
|
+
const hasSelection = Boolean(
|
|
6559
|
+
activePreviewCommentSelection
|
|
6560
|
+
&& activePreviewCommentSelection.paneId === paneId
|
|
6561
|
+
&& activePreviewCommentSelection.blockKey === blockKey
|
|
6562
|
+
);
|
|
6461
6563
|
|
|
6462
6564
|
blockEl.classList.remove("has-comments");
|
|
6463
6565
|
blockEl.classList.toggle("has-selection", hasSelection);
|
|
6464
|
-
|
|
6465
|
-
if (summaryBtn) {
|
|
6466
|
-
summaryBtn.hidden = true;
|
|
6467
|
-
summaryBtn.textContent = "";
|
|
6468
|
-
summaryBtn.dataset.reviewNoteId = "";
|
|
6469
|
-
}
|
|
6470
|
-
|
|
6471
|
-
if (addBtn) {
|
|
6472
|
-
addBtn.hidden = !hasSelection;
|
|
6473
|
-
addBtn.textContent = "Comment";
|
|
6474
|
-
addBtn.dataset.previewCommentMode = hasSelection ? "selection" : "";
|
|
6475
|
-
addBtn.title = hasSelection
|
|
6476
|
-
? ("Add a local comment from the current preview selection on this " + blockKindLabel + " (" + lineLabel + ").")
|
|
6477
|
-
: "";
|
|
6478
|
-
addBtn.setAttribute("aria-label", addBtn.title || "Comment");
|
|
6479
|
-
}
|
|
6480
|
-
|
|
6481
|
-
if (jumpBtn) {
|
|
6482
|
-
jumpBtn.hidden = !hasSelection;
|
|
6483
|
-
jumpBtn.textContent = "Jump";
|
|
6484
|
-
jumpBtn.dataset.previewCommentMode = hasSelection ? "selection" : "";
|
|
6485
|
-
jumpBtn.title = hasSelection
|
|
6486
|
-
? ("Jump to the current preview selection on this " + blockKindLabel + " in the raw editor (" + lineLabel + ").")
|
|
6487
|
-
: "";
|
|
6488
|
-
jumpBtn.setAttribute("aria-label", jumpBtn.title || "Jump");
|
|
6489
|
-
}
|
|
6490
6566
|
}
|
|
6491
6567
|
|
|
6492
6568
|
function updatePreviewCommentBlocksForElement(targetEl) {
|
|
6493
6569
|
if (!targetEl || typeof targetEl.querySelectorAll !== "function") return;
|
|
6570
|
+
ensurePreviewSelectionActions(targetEl);
|
|
6494
6571
|
const sourceText = String(sourceTextEl && sourceTextEl.value ? sourceTextEl.value : "");
|
|
6495
6572
|
Array.from(targetEl.querySelectorAll(".preview-comment-block")).forEach((blockEl) => {
|
|
6496
6573
|
updatePreviewCommentBlockState(blockEl, sourceText);
|
|
6497
6574
|
});
|
|
6575
|
+
updatePreviewSelectionActions(targetEl);
|
|
6498
6576
|
}
|
|
6499
6577
|
|
|
6500
6578
|
function decorateRenderedEditorPreviewComments(targetEl, sourceText) {
|
|
@@ -6522,43 +6600,20 @@
|
|
|
6522
6600
|
wrapper.dataset.reviewNoteLineEnd = String(sourceBlock.lineEnd);
|
|
6523
6601
|
wrapper.dataset.previewCommentKind = sourceBlock.kind;
|
|
6524
6602
|
|
|
6525
|
-
const controls = document.createElement("div");
|
|
6526
|
-
controls.className = "preview-comment-controls";
|
|
6527
|
-
|
|
6528
|
-
const summaryBtn = document.createElement("button");
|
|
6529
|
-
summaryBtn.type = "button";
|
|
6530
|
-
summaryBtn.className = "preview-comment-summary";
|
|
6531
|
-
summaryBtn.hidden = true;
|
|
6532
|
-
controls.appendChild(summaryBtn);
|
|
6533
|
-
|
|
6534
|
-
const addBtn = document.createElement("button");
|
|
6535
|
-
addBtn.type = "button";
|
|
6536
|
-
addBtn.className = "preview-comment-add";
|
|
6537
|
-
addBtn.dataset.previewCommentAction = "comment";
|
|
6538
|
-
addBtn.textContent = "Comment";
|
|
6539
|
-
controls.appendChild(addBtn);
|
|
6540
|
-
|
|
6541
|
-
const jumpBtn = document.createElement("button");
|
|
6542
|
-
jumpBtn.type = "button";
|
|
6543
|
-
jumpBtn.className = "preview-comment-jump";
|
|
6544
|
-
jumpBtn.dataset.previewCommentAction = "jump";
|
|
6545
|
-
jumpBtn.textContent = "Jump";
|
|
6546
|
-
controls.appendChild(jumpBtn);
|
|
6547
|
-
|
|
6548
6603
|
originalElement.replaceWith(wrapper);
|
|
6549
|
-
wrapper.appendChild(controls);
|
|
6550
6604
|
originalElement.classList.add("preview-comment-block-content");
|
|
6551
6605
|
wrapper.appendChild(originalElement);
|
|
6552
6606
|
}
|
|
6553
6607
|
|
|
6608
|
+
ensurePreviewSelectionActions(targetEl);
|
|
6554
6609
|
updatePreviewCommentBlocksForElement(targetEl);
|
|
6555
6610
|
}
|
|
6556
6611
|
|
|
6557
6612
|
function refreshRenderedEditorPreviewComments() {
|
|
6558
|
-
if (sourcePreviewEl
|
|
6613
|
+
if (sourcePreviewEl) {
|
|
6559
6614
|
updatePreviewCommentBlocksForElement(sourcePreviewEl);
|
|
6560
6615
|
}
|
|
6561
|
-
if (critiqueViewEl
|
|
6616
|
+
if (critiqueViewEl) {
|
|
6562
6617
|
updatePreviewCommentBlocksForElement(critiqueViewEl);
|
|
6563
6618
|
}
|
|
6564
6619
|
}
|
|
@@ -6792,10 +6847,11 @@
|
|
|
6792
6847
|
}
|
|
6793
6848
|
|
|
6794
6849
|
function revealReviewNoteInPreview(note) {
|
|
6795
|
-
if (!supportsPreviewCommentsForCurrentEditor()) return;
|
|
6850
|
+
if (!supportsPreviewCommentsForCurrentEditor()) return false;
|
|
6796
6851
|
if (rightView === "editor-preview" && critiqueViewEl && critiqueViewEl.isConnected) {
|
|
6797
|
-
revealReviewNoteInPreviewElement(critiqueViewEl, note);
|
|
6852
|
+
return revealReviewNoteInPreviewElement(critiqueViewEl, note);
|
|
6798
6853
|
}
|
|
6854
|
+
return false;
|
|
6799
6855
|
}
|
|
6800
6856
|
|
|
6801
6857
|
function updateActivePreviewCommentSelectionFromDom() {
|
|
@@ -6827,7 +6883,9 @@
|
|
|
6827
6883
|
|
|
6828
6884
|
setActivePreviewCommentSelection({
|
|
6829
6885
|
...anchor,
|
|
6886
|
+
paneId: getPreviewSelectionPaneIdForNode(startBlock),
|
|
6830
6887
|
blockKey: getPreviewCommentBlockKey(startBlock),
|
|
6888
|
+
previewCommentKind: String(startBlock.dataset && startBlock.dataset.previewCommentKind || "paragraph"),
|
|
6831
6889
|
});
|
|
6832
6890
|
}
|
|
6833
6891
|
|
|
@@ -6922,11 +6980,27 @@
|
|
|
6922
6980
|
&& typeof sourceTextEl.selectionEnd === "number"
|
|
6923
6981
|
&& sourceTextEl.selectionEnd > sourceTextEl.selectionStart
|
|
6924
6982
|
);
|
|
6983
|
+
const canJumpToPreview = Boolean(
|
|
6984
|
+
hasSelection
|
|
6985
|
+
&& rightView === "editor-preview"
|
|
6986
|
+
&& critiqueViewEl
|
|
6987
|
+
&& supportsPreviewCommentsForCurrentEditor()
|
|
6988
|
+
);
|
|
6925
6989
|
editorSelectionCommentBtn.hidden = !hasSelection;
|
|
6990
|
+
if (editorSelectionJumpBtn) {
|
|
6991
|
+
editorSelectionJumpBtn.hidden = !canJumpToPreview;
|
|
6992
|
+
}
|
|
6993
|
+
if (editorSelectionActionsEl) {
|
|
6994
|
+
editorSelectionActionsEl.hidden = !hasSelection;
|
|
6995
|
+
}
|
|
6926
6996
|
if (hasSelection) {
|
|
6927
6997
|
editorSelectionCommentBtn.title = "Create a new local comment from the current editor selection.";
|
|
6928
6998
|
editorSelectionCommentBtn.setAttribute("aria-label", editorSelectionCommentBtn.title);
|
|
6929
6999
|
}
|
|
7000
|
+
if (editorSelectionJumpBtn && canJumpToPreview) {
|
|
7001
|
+
editorSelectionJumpBtn.title = "Jump to the current editor selection in the preview.";
|
|
7002
|
+
editorSelectionJumpBtn.setAttribute("aria-label", editorSelectionJumpBtn.title);
|
|
7003
|
+
}
|
|
6930
7004
|
}
|
|
6931
7005
|
|
|
6932
7006
|
function clearSuppressedEditorSelectionComment() {
|
|
@@ -7143,17 +7217,12 @@
|
|
|
7143
7217
|
});
|
|
7144
7218
|
}
|
|
7145
7219
|
|
|
7146
|
-
function
|
|
7147
|
-
|
|
7148
|
-
const blockKey = getPreviewCommentBlockKey(blockEl);
|
|
7149
|
-
return activePreviewCommentSelection && activePreviewCommentSelection.blockKey === blockKey
|
|
7150
|
-
? activePreviewCommentSelection
|
|
7151
|
-
: null;
|
|
7220
|
+
function getActivePreviewSelectionAnchorForPane(paneId) {
|
|
7221
|
+
return getActivePreviewSelectionForPane(paneId);
|
|
7152
7222
|
}
|
|
7153
7223
|
|
|
7154
|
-
function addReviewNoteFromPreviewSelection(
|
|
7155
|
-
|
|
7156
|
-
const anchor = getActivePreviewSelectionAnchorForBlock(blockEl);
|
|
7224
|
+
function addReviewNoteFromPreviewSelection(paneId) {
|
|
7225
|
+
const anchor = getActivePreviewSelectionAnchorForPane(paneId);
|
|
7157
7226
|
if (!anchor) {
|
|
7158
7227
|
setStatus("Select some preview text within a single block first.", "warning");
|
|
7159
7228
|
return null;
|
|
@@ -7189,6 +7258,12 @@
|
|
|
7189
7258
|
if (editorSelectionCommentBtn) {
|
|
7190
7259
|
editorSelectionCommentBtn.hidden = true;
|
|
7191
7260
|
}
|
|
7261
|
+
if (editorSelectionJumpBtn) {
|
|
7262
|
+
editorSelectionJumpBtn.hidden = true;
|
|
7263
|
+
}
|
|
7264
|
+
if (editorSelectionActionsEl) {
|
|
7265
|
+
editorSelectionActionsEl.hidden = true;
|
|
7266
|
+
}
|
|
7192
7267
|
const shouldOpenReviewNotes = !isReviewNotesOpen();
|
|
7193
7268
|
pendingReviewNoteFocusId = note.id;
|
|
7194
7269
|
setReviewNotes(reviewNotes.concat([note]));
|
|
@@ -7218,6 +7293,30 @@
|
|
|
7218
7293
|
});
|
|
7219
7294
|
}
|
|
7220
7295
|
|
|
7296
|
+
function jumpToEditorSelectionInPreview() {
|
|
7297
|
+
if (editorView !== "markdown") {
|
|
7298
|
+
setStatus("Switch to Editor (Raw) before jumping from an editor selection.", "warning");
|
|
7299
|
+
return false;
|
|
7300
|
+
}
|
|
7301
|
+
if (rightView !== "editor-preview" || !critiqueViewEl || !supportsPreviewCommentsForCurrentEditor()) {
|
|
7302
|
+
setStatus("Open Editor (Preview) on the right to jump the current editor selection there.", "warning");
|
|
7303
|
+
return false;
|
|
7304
|
+
}
|
|
7305
|
+
const anchor = getEditorAnchorForReviewNote();
|
|
7306
|
+
const jumped = revealReviewNoteInPreview(anchor);
|
|
7307
|
+
if (!jumped) {
|
|
7308
|
+
setStatus("Could not find the current editor selection in the preview.", "warning");
|
|
7309
|
+
return false;
|
|
7310
|
+
}
|
|
7311
|
+
const current = String(sourceTextEl.value || "");
|
|
7312
|
+
const range = resolveReviewNoteRange(anchor, current);
|
|
7313
|
+
if (range) {
|
|
7314
|
+
scrollEditorRangeIntoView(range);
|
|
7315
|
+
}
|
|
7316
|
+
setStatus("Jumped to the current editor selection in the preview.", "success");
|
|
7317
|
+
return true;
|
|
7318
|
+
}
|
|
7319
|
+
|
|
7221
7320
|
function addReviewNoteFromEditorLine() {
|
|
7222
7321
|
if (editorView !== "markdown") {
|
|
7223
7322
|
setStatus("Switch to Editor (Raw) before adding a line comment.", "warning");
|
|
@@ -7260,23 +7359,32 @@
|
|
|
7260
7359
|
return true;
|
|
7261
7360
|
}
|
|
7262
7361
|
|
|
7263
|
-
function jumpToPreviewSelection(
|
|
7264
|
-
|
|
7265
|
-
const anchor = getActivePreviewSelectionAnchorForBlock(blockEl);
|
|
7362
|
+
function jumpToPreviewSelection(paneId) {
|
|
7363
|
+
const anchor = getActivePreviewSelectionAnchorForPane(paneId);
|
|
7266
7364
|
if (!anchor) {
|
|
7267
7365
|
setStatus("Select some preview text within a single block first.", "warning");
|
|
7268
7366
|
return false;
|
|
7269
7367
|
}
|
|
7270
|
-
const
|
|
7368
|
+
const previewNote = normalizeReviewNote(anchor);
|
|
7369
|
+
const jumped = jumpToReviewAnchor(previewNote, {
|
|
7271
7370
|
statusMessage: "Jumped to preview selection in the raw editor.",
|
|
7371
|
+
afterJump: () => {
|
|
7372
|
+
const paneEl = getPreviewSelectionPaneElement(paneId);
|
|
7373
|
+
if (paneEl && previewNote) {
|
|
7374
|
+
revealReviewNoteInPreviewElement(paneEl, previewNote);
|
|
7375
|
+
}
|
|
7376
|
+
const schedule = typeof window.requestAnimationFrame === "function"
|
|
7377
|
+
? window.requestAnimationFrame.bind(window)
|
|
7378
|
+
: (cb) => window.setTimeout(cb, 16);
|
|
7379
|
+
schedule(() => {
|
|
7380
|
+
const selection = typeof window.getSelection === "function" ? window.getSelection() : null;
|
|
7381
|
+
if (selection && typeof selection.removeAllRanges === "function") {
|
|
7382
|
+
selection.removeAllRanges();
|
|
7383
|
+
}
|
|
7384
|
+
clearPreviewCommentSelection();
|
|
7385
|
+
});
|
|
7386
|
+
},
|
|
7272
7387
|
});
|
|
7273
|
-
if (jumped) {
|
|
7274
|
-
const selection = typeof window.getSelection === "function" ? window.getSelection() : null;
|
|
7275
|
-
if (selection && typeof selection.removeAllRanges === "function") {
|
|
7276
|
-
selection.removeAllRanges();
|
|
7277
|
-
}
|
|
7278
|
-
clearPreviewCommentSelection();
|
|
7279
|
-
}
|
|
7280
7388
|
return jumped;
|
|
7281
7389
|
}
|
|
7282
7390
|
|
|
@@ -9203,6 +9311,15 @@
|
|
|
9203
9311
|
});
|
|
9204
9312
|
}
|
|
9205
9313
|
|
|
9314
|
+
if (editorSelectionJumpBtn) {
|
|
9315
|
+
editorSelectionJumpBtn.addEventListener("mousedown", (event) => {
|
|
9316
|
+
event.preventDefault();
|
|
9317
|
+
});
|
|
9318
|
+
editorSelectionJumpBtn.addEventListener("click", () => {
|
|
9319
|
+
jumpToEditorSelectionInPreview();
|
|
9320
|
+
});
|
|
9321
|
+
}
|
|
9322
|
+
|
|
9206
9323
|
if (reviewNotesInlineAllBtn) {
|
|
9207
9324
|
reviewNotesInlineAllBtn.addEventListener("click", () => {
|
|
9208
9325
|
toggleAllReviewNotesInlineAnnotations();
|
|
@@ -9231,18 +9348,17 @@
|
|
|
9231
9348
|
const target = event.target;
|
|
9232
9349
|
const actionBtn = target instanceof Element ? target.closest(".preview-comment-add, .preview-comment-jump, .preview-comment-summary") : null;
|
|
9233
9350
|
if (!actionBtn) return;
|
|
9234
|
-
const blockEl = actionBtn.closest(".preview-comment-block");
|
|
9235
|
-
if (!blockEl) return;
|
|
9236
9351
|
event.preventDefault();
|
|
9237
9352
|
event.stopPropagation();
|
|
9238
9353
|
const mode = String(actionBtn.dataset && actionBtn.dataset.previewCommentMode ? actionBtn.dataset.previewCommentMode : "");
|
|
9239
9354
|
if (!mode || !mode.startsWith("selection")) return;
|
|
9355
|
+
const paneId = String(actionBtn.dataset && actionBtn.dataset.previewPane ? actionBtn.dataset.previewPane : "");
|
|
9240
9356
|
const action = String(actionBtn.dataset && actionBtn.dataset.previewCommentAction ? actionBtn.dataset.previewCommentAction : "comment");
|
|
9241
9357
|
if (action === "jump") {
|
|
9242
|
-
jumpToPreviewSelection(
|
|
9358
|
+
jumpToPreviewSelection(paneId);
|
|
9243
9359
|
return;
|
|
9244
9360
|
}
|
|
9245
|
-
addReviewNoteFromPreviewSelection(
|
|
9361
|
+
addReviewNoteFromPreviewSelection(paneId);
|
|
9246
9362
|
}
|
|
9247
9363
|
|
|
9248
9364
|
if (leftPaneEl) {
|
package/client/studio.css
CHANGED
|
@@ -661,11 +661,17 @@
|
|
|
661
661
|
-webkit-text-fill-color: transparent;
|
|
662
662
|
}
|
|
663
663
|
|
|
664
|
-
.editor-selection-
|
|
664
|
+
.editor-selection-actions {
|
|
665
665
|
position: absolute;
|
|
666
666
|
top: 12px;
|
|
667
667
|
right: 12px;
|
|
668
668
|
z-index: 4;
|
|
669
|
+
display: inline-flex;
|
|
670
|
+
align-items: center;
|
|
671
|
+
gap: 8px;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
.editor-selection-action-btn {
|
|
669
675
|
min-height: 24px;
|
|
670
676
|
border-radius: 999px;
|
|
671
677
|
padding: 0 10px;
|
|
@@ -677,13 +683,22 @@
|
|
|
677
683
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
|
|
678
684
|
}
|
|
679
685
|
|
|
680
|
-
.editor-selection-
|
|
681
|
-
.editor-selection-
|
|
686
|
+
.editor-selection-action-btn:hover,
|
|
687
|
+
.editor-selection-action-btn:focus-visible {
|
|
682
688
|
background: var(--accent-soft-strong);
|
|
683
689
|
color: var(--accent);
|
|
684
690
|
border-color: var(--accent);
|
|
685
691
|
}
|
|
686
692
|
|
|
693
|
+
.editor-selection-actions[hidden],
|
|
694
|
+
.editor-selection-action-btn[hidden],
|
|
695
|
+
.preview-selection-actions[hidden],
|
|
696
|
+
.preview-comment-add[hidden],
|
|
697
|
+
.preview-comment-jump[hidden],
|
|
698
|
+
.preview-comment-summary[hidden] {
|
|
699
|
+
display: none !important;
|
|
700
|
+
}
|
|
701
|
+
|
|
687
702
|
.hl-heading {
|
|
688
703
|
color: var(--md-heading);
|
|
689
704
|
font-weight: 700;
|
|
@@ -916,15 +931,16 @@
|
|
|
916
931
|
overflow-wrap: inherit;
|
|
917
932
|
}
|
|
918
933
|
|
|
919
|
-
.preview-
|
|
920
|
-
position:
|
|
921
|
-
top:
|
|
922
|
-
right: 0;
|
|
934
|
+
.preview-selection-actions {
|
|
935
|
+
position: sticky;
|
|
936
|
+
top: 12px;
|
|
923
937
|
z-index: 6;
|
|
924
|
-
|
|
925
|
-
|
|
938
|
+
height: 0;
|
|
939
|
+
display: flex;
|
|
940
|
+
justify-content: flex-end;
|
|
941
|
+
align-items: flex-start;
|
|
926
942
|
gap: 8px;
|
|
927
|
-
|
|
943
|
+
pointer-events: none;
|
|
928
944
|
}
|
|
929
945
|
|
|
930
946
|
.preview-comment-summary {
|
|
@@ -941,21 +957,11 @@
|
|
|
941
957
|
padding: 0 10px;
|
|
942
958
|
font-size: 12px;
|
|
943
959
|
line-height: 1;
|
|
944
|
-
opacity: 0;
|
|
945
|
-
pointer-events: none;
|
|
946
|
-
transform: translateY(-2px);
|
|
947
|
-
transition: opacity 120ms ease, transform 120ms ease, color 120ms ease, border-color 120ms ease, background-color 120ms ease;
|
|
948
960
|
background: var(--accent-soft);
|
|
949
961
|
border-color: var(--accent);
|
|
950
962
|
color: var(--accent);
|
|
951
963
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
.preview-comment-block.has-selection .preview-comment-add,
|
|
955
|
-
.preview-comment-block.has-selection .preview-comment-jump {
|
|
956
|
-
opacity: 1;
|
|
957
964
|
pointer-events: auto;
|
|
958
|
-
transform: translateY(0);
|
|
959
965
|
}
|
|
960
966
|
|
|
961
967
|
.preview-comment-add:hover,
|
package/index.ts
CHANGED
|
@@ -6095,7 +6095,10 @@ ${cssVarsBlock}
|
|
|
6095
6095
|
<div id="lineNumberMeasure" class="editor-line-number-measure" aria-hidden="true"></div>
|
|
6096
6096
|
<pre id="sourceHighlight" class="editor-highlight" aria-hidden="true"></pre>
|
|
6097
6097
|
<textarea id="sourceText" placeholder="Paste or edit text here.">${initialText}</textarea>
|
|
6098
|
-
<
|
|
6098
|
+
<div id="editorSelectionActions" class="editor-selection-actions" hidden>
|
|
6099
|
+
<button id="editorSelectionCommentBtn" type="button" class="editor-selection-action-btn" hidden title="Create a new local comment from the current editor selection.">Comment</button>
|
|
6100
|
+
<button id="editorSelectionJumpBtn" type="button" class="editor-selection-action-btn" hidden title="Jump to the current editor selection in the preview.">Jump</button>
|
|
6101
|
+
</div>
|
|
6099
6102
|
</div>
|
|
6100
6103
|
<div id="sourcePreview" class="panel-scroll rendered-markdown" hidden><pre class="plain-markdown"></pre></div>
|
|
6101
6104
|
</div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-studio",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.51",
|
|
4
4
|
"description": "Two-pane browser workspace for pi with prompt/response editing, annotations, critiques, prompt/response history, and live Markdown/LaTeX/code preview",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|