pi-studio 0.9.51 → 0.9.52
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 +15 -0
- package/README.md +4 -2
- package/ROADMAP.md +74 -0
- package/client/studio-client.js +256 -18
- package/client/studio.css +56 -6
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,21 @@ All notable changes to `pi-studio` are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.9.52] — 2026-08-28
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- Add a visible **Enlarge** control for embedded PDF cards, plus **Copy path** alongside PDF actions that operate on the computer running Pi.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Offer true browser fullscreen only when the current browser exposes the Fullscreen API, while retaining Studio's in-page image, PDF, and HTML focus viewers everywhere.
|
|
14
|
+
- Keep ordinary images and rendered PDF figures unobscured by using their hover zoom cursor and whole-media click target instead of overlay buttons.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- Restore a clear, explicitly sized H1–H6 hierarchy in rendered Markdown without allowing application-header styles to override document headings.
|
|
18
|
+
- Apply click-to-focus image behavior consistently to Side-question and Quiz Markdown as well as the main Editor, Response, and Working surfaces.
|
|
19
|
+
- Keep image, rendered-PDF, and PDF-card actions interactive after the response pane resets its scroll position by adding clone-safe delegated handling; preserve rendered PDF canvas pixels across the reset so inline and enlarged figures do not become blank; show contextual success/failure feedback for host PDF actions.
|
|
20
|
+
- Hide side-thread-only Markdown save, copy, and editor actions from ordinary Response, Editor Preview, and REPL export menus, with a runtime guard against stale menu activation.
|
|
21
|
+
|
|
7
22
|
## [0.9.51] — 2026-08-26
|
|
8
23
|
|
|
9
24
|
### Added
|
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Extension for [pi](https://pi.dev) that opens a local two-pane browser workspace for working with prompts, responses, live working details, Markdown and LaTeX documents, interactive HTML previews, code files, REPL sessions, and other common text-based files side by side. Annotate responses and files, add local comments, write, edit, run prompts, send code to a REPL, browse prompt and response history, request critiques, and use live preview for code, Markdown, LaTeX, and interactive HTML.
|
|
4
4
|
|
|
5
|
+
See [`ROADMAP.md`](./ROADMAP.md) for the current release plan.
|
|
6
|
+
|
|
5
7
|
## Quick demo
|
|
6
8
|
|
|
7
9
|
[Watch the 2-minute demo (MP4, 2x speed, no audio)](https://github.com/omaclaren/pi-studio/releases/latest/download/pi-studio-demo-2min.mp4)
|
|
@@ -52,10 +54,10 @@ _The video shows an earlier version of the Studio interface. The basic workflow
|
|
|
52
54
|
- shows/hides annotation markers in preview
|
|
53
55
|
- strips markers before send (optional)
|
|
54
56
|
- saves `.annotated.md`
|
|
55
|
-
- Renders Markdown/LaTeX/code previews (math + Mermaid) plus lightweight CSV/TSV table previews, theme-synced with pi, with copy buttons for code blocks and blockquotes; Mermaid previews include Lucide/Logos icon nodes and accessible label contrast over custom fills
|
|
57
|
+
- Renders Markdown/LaTeX/code previews (math + Mermaid) plus lightweight CSV/TSV table previews, theme-synced with pi, with an explicit H1–H6 hierarchy, zoomable images across Studio-owned Markdown surfaces, and copy buttons for code blocks and blockquotes; Mermaid previews include Lucide/Logos icon nodes and accessible label contrast over custom fills
|
|
56
58
|
- Adds a contextual **Editor (Quarto Preview)** right-pane view for file-backed `.qmd`, `.md`, and `.markdown` documents. Studio checks Quarto and the document/project configuration before showing an explicit start action, launches a single loopback `quarto preview` process with `--no-execute`, embeds Quarto's authoritative saved-file output without restyling it, and provides open-in-browser, restart, stop, logs, and unsaved-editor warnings. If Quarto is missing, the view remains available with an actionable dependency message.
|
|
57
59
|
- Renders straight, unfenced interactive HTML in preview via a sandboxed browser iframe with zoom controls, while fenced `html` blocks remain source code
|
|
58
|
-
- Embeds local PDFs in Studio Markdown previews via explicit `studio-pdf` fenced blocks and opens existing PDFs directly with `/studio <path.pdf>`, with
|
|
60
|
+
- Embeds local PDFs in Studio Markdown previews via explicit `studio-pdf` fenced blocks and opens existing PDFs directly with `/studio <path.pdf>`, with visible enlarge, browser-tab, system-viewer, show-in-folder, copy-path, manual refresh, and opt-in stable-file auto-refresh actions; true browser fullscreen is offered only when the browser supports it
|
|
59
61
|
- Ships optional `pi-studio-dark` and `pi-studio-light` themes tuned for Studio's browser workspace
|
|
60
62
|
- Exports right-pane preview as PDF (pandoc + LaTeX) or standalone HTML into the source file directory, Studio working directory, or Pi session directory; PDF export can open in a Studio preview tab or the default PDF viewer, and HTML export can open in the default browser or in a new Studio editor tab for inspection/commenting, while preserving authored HTML previews as HTML and rendering CSV/TSV editor previews as tables
|
|
61
63
|
- Exports local files headlessly via `/studio-pdf <path>` to `<name>.studio.pdf` or `/studio-html <path>` to `<name>.studio.html`; without a path, those commands export the last model response to a timestamped file. Agent tools `studio_export_pdf` and `studio_export_html` expose the same export pipeline for remote/Telegram-style sessions.
|
package/ROADMAP.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Pi Studio roadmap
|
|
2
|
+
|
|
3
|
+
This is the current planning source of truth for Studio work. `NEXT-STAGE.md` is historical; `TODO.md` tracks smaller backlog items that are not yet assigned to a release.
|
|
4
|
+
|
|
5
|
+
## Release approach
|
|
6
|
+
|
|
7
|
+
Studio development follows two tracks:
|
|
8
|
+
|
|
9
|
+
- **Stable `0.9.x` releases** contain one coherent family of fixes or incremental features and keep `main` releasable.
|
|
10
|
+
- **`0.10.0`** is reserved for the buffer-first document architecture. Risky prereleases should use the npm `next` tag before replacing `latest`.
|
|
11
|
+
|
|
12
|
+
Changes should be based on capabilities rather than browser, terminal host, or user-agent detection. Muxy, ordinary Chromium browsers, embedded WebKit views, and SSH/headless use are validation environments, not separate product variants.
|
|
13
|
+
|
|
14
|
+
Each release should finish with:
|
|
15
|
+
|
|
16
|
+
1. focused regression tests plus the full test suite;
|
|
17
|
+
2. TypeScript and JavaScript syntax checks;
|
|
18
|
+
3. production dependency audit;
|
|
19
|
+
4. exact package-content and byte-level artifact audit;
|
|
20
|
+
5. a fresh npm installation and naturally rendered Studio smoke test.
|
|
21
|
+
|
|
22
|
+
Publishing, pushing, and tagging remain explicit release actions rather than automatic consequences of merging work.
|
|
23
|
+
|
|
24
|
+
## 0.9.52 — Rendering and media consistency
|
|
25
|
+
|
|
26
|
+
A focused portability and affordance pass:
|
|
27
|
+
|
|
28
|
+
- scope application-header typography so it cannot override rendered Markdown;
|
|
29
|
+
- define an explicit, visibly ordered H1–H6 scale;
|
|
30
|
+
- apply image focus consistently across Studio-owned same-document Markdown surfaces;
|
|
31
|
+
- give embedded PDF cards and rendered PDF figures an obvious enlarge action;
|
|
32
|
+
- expose true browser fullscreen only when the Fullscreen API is available, while retaining Studio's in-page focus viewer everywhere;
|
|
33
|
+
- make local PDF actions clearly refer to the computer running Pi and provide **Copy path** alongside system-viewer and file-manager actions.
|
|
34
|
+
|
|
35
|
+
This release must not add Muxy-specific branches or attempt to instrument opaque Quarto/authored-HTML iframe contents.
|
|
36
|
+
|
|
37
|
+
## 0.9.53 — Resource locations
|
|
38
|
+
|
|
39
|
+
Replace the single-root assumption with explicit resource grants:
|
|
40
|
+
|
|
41
|
+
- grant the current document directory automatically;
|
|
42
|
+
- allow an exact file or additional folder to be granted explicitly;
|
|
43
|
+
- keep grants session-scoped by default;
|
|
44
|
+
- store canonical server-side paths and retain traversal and symlink-escape checks;
|
|
45
|
+
- use the same grants for Markdown resources, local links, PDFs, Files view, and Side questions;
|
|
46
|
+
- explain that paths, Finder/file-manager actions, and system viewers belong to the computer running Pi;
|
|
47
|
+
- offer **Allow this file**, **Allow this folder for this Studio session**, and **Cancel** when an explicit local link crosses the current boundary.
|
|
48
|
+
|
|
49
|
+
The resource-location registry should be workspace-level rather than tied to the current editor document so it remains compatible with multiple buffers. Remembering grants per project can follow after the session-only model is proven.
|
|
50
|
+
|
|
51
|
+
## 0.10.0 — Buffer-first editing
|
|
52
|
+
|
|
53
|
+
The first architectural `0.10` release should add:
|
|
54
|
+
|
|
55
|
+
- a `StudioBufferStore` with stable document identity;
|
|
56
|
+
- recovery schema v2 with migration from the single-document schema;
|
|
57
|
+
- buffer-specific text/baseline, dirty state, cursor, selection, scroll, preview context, annotations, and resource directory;
|
|
58
|
+
- tabs at ordinary widths and a compact searchable buffer picker at narrow widths;
|
|
59
|
+
- MRU cycling, next/previous, close, and reopen commands;
|
|
60
|
+
- originating buffer ID and revision targeting for asynchronous Pi work.
|
|
61
|
+
|
|
62
|
+
PDFs remain preview documents, and conversation history remains session-global. Split panes, arbitrary layouts, project trees, and simultaneous per-buffer Pi conversations are outside the initial `0.10.0` scope.
|
|
63
|
+
|
|
64
|
+
## Validation matrix
|
|
65
|
+
|
|
66
|
+
Cross-environment checks should cover, where relevant:
|
|
67
|
+
|
|
68
|
+
- full and editor-only Studio;
|
|
69
|
+
- file-backed and detached documents;
|
|
70
|
+
- ordinary Chromium and embedded WebKit browser surfaces;
|
|
71
|
+
- local, SSH, and `--no-browser` Pi sessions;
|
|
72
|
+
- paths with spaces, Unicode, traversal attempts, and symlinks;
|
|
73
|
+
- supported and unavailable browser APIs;
|
|
74
|
+
- browser reconstruction, refresh recovery, and clean shutdown.
|
package/client/studio-client.js
CHANGED
|
@@ -296,6 +296,7 @@
|
|
|
296
296
|
let studioPdfFocusOpenLinkEl = null;
|
|
297
297
|
let studioPdfFocusSystemViewerBtn = null;
|
|
298
298
|
let studioPdfFocusRevealBtn = null;
|
|
299
|
+
let studioPdfFocusCopyPathBtn = null;
|
|
299
300
|
let studioPdfFocusAutoRefreshBtn = null;
|
|
300
301
|
let studioPdfFocusFullscreenBtn = null;
|
|
301
302
|
let studioPdfFocusCloseBtn = null;
|
|
@@ -305,6 +306,7 @@
|
|
|
305
306
|
let studioPdfFocusSourceCard = null;
|
|
306
307
|
let studioPdfFocusStandaloneAutoRefreshState = null;
|
|
307
308
|
const studioPdfCardAutoRefreshStates = new WeakMap();
|
|
309
|
+
const studioPdfActionFeedbackStates = new WeakMap();
|
|
308
310
|
const STUDIO_PDF_AUTO_REFRESH_INTERVAL_MS = 1_000;
|
|
309
311
|
const STUDIO_PDF_AUTO_REFRESH_STABLE_OBSERVATIONS = 2;
|
|
310
312
|
let studioHtmlFocusOverlayEl = null;
|
|
@@ -6715,10 +6717,22 @@
|
|
|
6715
6717
|
button.setAttribute("aria-pressed", focused ? "true" : "false");
|
|
6716
6718
|
}
|
|
6717
6719
|
|
|
6720
|
+
function isStudioFullscreenAvailable(element) {
|
|
6721
|
+
return Boolean(
|
|
6722
|
+
element
|
|
6723
|
+
&& typeof element.requestFullscreen === "function"
|
|
6724
|
+
&& typeof document.exitFullscreen === "function"
|
|
6725
|
+
);
|
|
6726
|
+
}
|
|
6727
|
+
|
|
6718
6728
|
function syncStudioHtmlFocusFullscreenButton() {
|
|
6719
6729
|
const button = studioHtmlFocusFullscreenBtn;
|
|
6720
6730
|
if (!button) return;
|
|
6721
6731
|
const shell = studioHtmlFocusShellEl;
|
|
6732
|
+
const available = isStudioFullscreenAvailable(shell);
|
|
6733
|
+
button.hidden = !available;
|
|
6734
|
+
button.setAttribute("aria-hidden", available ? "false" : "true");
|
|
6735
|
+
if (!available) return;
|
|
6722
6736
|
const isFullscreen = Boolean(shell && document.fullscreenElement && document.fullscreenElement === shell);
|
|
6723
6737
|
button.replaceChildren(makeStudioUiRefreshIcon(isFullscreen ? "fullscreen-exit" : "fullscreen"));
|
|
6724
6738
|
const label = isFullscreen ? "Exit fullscreen" : "Fullscreen";
|
|
@@ -7191,9 +7205,9 @@
|
|
|
7191
7205
|
systemViewerBtn.type = "button";
|
|
7192
7206
|
systemViewerBtn.className = "studio-pdf-focus-btn studio-pdf-focus-system-viewer";
|
|
7193
7207
|
systemViewerBtn.textContent = "System viewer";
|
|
7194
|
-
systemViewerBtn.title = "Open the local PDF in the
|
|
7208
|
+
systemViewerBtn.title = "Open the local PDF in the default viewer on the computer running Pi.";
|
|
7195
7209
|
systemViewerBtn.addEventListener("click", () => {
|
|
7196
|
-
void runStudioPdfLocalAction("system-viewer", studioPdfFocusResourceQuery);
|
|
7210
|
+
void runStudioPdfLocalAction("system-viewer", studioPdfFocusResourceQuery, systemViewerBtn);
|
|
7197
7211
|
});
|
|
7198
7212
|
actions.appendChild(systemViewerBtn);
|
|
7199
7213
|
|
|
@@ -7201,12 +7215,22 @@
|
|
|
7201
7215
|
revealBtn.type = "button";
|
|
7202
7216
|
revealBtn.className = "studio-pdf-focus-btn studio-pdf-focus-reveal";
|
|
7203
7217
|
revealBtn.textContent = "Show in folder";
|
|
7204
|
-
revealBtn.title = "Reveal the local PDF in
|
|
7218
|
+
revealBtn.title = "Reveal the local PDF in the file manager on the computer running Pi.";
|
|
7205
7219
|
revealBtn.addEventListener("click", () => {
|
|
7206
|
-
void runStudioPdfLocalAction("reveal", studioPdfFocusResourceQuery);
|
|
7220
|
+
void runStudioPdfLocalAction("reveal", studioPdfFocusResourceQuery, revealBtn);
|
|
7207
7221
|
});
|
|
7208
7222
|
actions.appendChild(revealBtn);
|
|
7209
7223
|
|
|
7224
|
+
const copyPathBtn = document.createElement("button");
|
|
7225
|
+
copyPathBtn.type = "button";
|
|
7226
|
+
copyPathBtn.className = "studio-pdf-focus-btn studio-pdf-focus-copy-path";
|
|
7227
|
+
copyPathBtn.textContent = "Copy path";
|
|
7228
|
+
copyPathBtn.title = "Copy the PDF path on the computer running Pi.";
|
|
7229
|
+
copyPathBtn.addEventListener("click", () => {
|
|
7230
|
+
void copyStudioPdfResourcePath(studioPdfFocusResourceQuery, copyPathBtn);
|
|
7231
|
+
});
|
|
7232
|
+
actions.appendChild(copyPathBtn);
|
|
7233
|
+
|
|
7210
7234
|
const refreshBtn = document.createElement("button");
|
|
7211
7235
|
refreshBtn.type = "button";
|
|
7212
7236
|
refreshBtn.className = "studio-pdf-focus-btn studio-pdf-focus-refresh";
|
|
@@ -7282,6 +7306,7 @@
|
|
|
7282
7306
|
studioPdfFocusOpenLinkEl = openLink;
|
|
7283
7307
|
studioPdfFocusSystemViewerBtn = systemViewerBtn;
|
|
7284
7308
|
studioPdfFocusRevealBtn = revealBtn;
|
|
7309
|
+
studioPdfFocusCopyPathBtn = copyPathBtn;
|
|
7285
7310
|
studioPdfFocusAutoRefreshBtn = autoRefreshBtn;
|
|
7286
7311
|
studioPdfFocusFullscreenBtn = fullscreenBtn;
|
|
7287
7312
|
studioPdfFocusCloseBtn = closeBtn;
|
|
@@ -7576,9 +7601,33 @@
|
|
|
7576
7601
|
return setStudioPdfAutoRefreshEnabled(state, !state.enabled);
|
|
7577
7602
|
}
|
|
7578
7603
|
|
|
7579
|
-
|
|
7604
|
+
function flashStudioPdfActionFeedback(buttonEl, label, level) {
|
|
7605
|
+
if (!(buttonEl instanceof HTMLButtonElement)) return;
|
|
7606
|
+
const existing = studioPdfActionFeedbackStates.get(buttonEl) || null;
|
|
7607
|
+
if (existing && existing.timer) window.clearTimeout(existing.timer);
|
|
7608
|
+
const state = {
|
|
7609
|
+
baselineText: existing ? existing.baselineText : buttonEl.textContent,
|
|
7610
|
+
baselineAriaLabel: existing ? existing.baselineAriaLabel : buttonEl.getAttribute("aria-label"),
|
|
7611
|
+
timer: null,
|
|
7612
|
+
};
|
|
7613
|
+
studioPdfActionFeedbackStates.set(buttonEl, state);
|
|
7614
|
+
buttonEl.textContent = String(label || "Done");
|
|
7615
|
+
buttonEl.dataset.studioActionFeedback = level === "warning" ? "warning" : "success";
|
|
7616
|
+
buttonEl.setAttribute("aria-label", String(label || "Done"));
|
|
7617
|
+
state.timer = window.setTimeout(() => {
|
|
7618
|
+
if (studioPdfActionFeedbackStates.get(buttonEl) !== state) return;
|
|
7619
|
+
buttonEl.textContent = state.baselineText;
|
|
7620
|
+
if (state.baselineAriaLabel === null) buttonEl.removeAttribute("aria-label");
|
|
7621
|
+
else buttonEl.setAttribute("aria-label", state.baselineAriaLabel);
|
|
7622
|
+
delete buttonEl.dataset.studioActionFeedback;
|
|
7623
|
+
studioPdfActionFeedbackStates.delete(buttonEl);
|
|
7624
|
+
}, 2_200);
|
|
7625
|
+
}
|
|
7626
|
+
|
|
7627
|
+
async function runStudioPdfLocalAction(action, resourceQuery, actionButton) {
|
|
7580
7628
|
const query = normalizeStudioPdfResourceQuery(resourceQuery);
|
|
7581
7629
|
if (!query) {
|
|
7630
|
+
flashStudioPdfActionFeedback(actionButton, "Unavailable", "warning");
|
|
7582
7631
|
setStatus("Could not resolve this PDF's local path.", "warning");
|
|
7583
7632
|
return false;
|
|
7584
7633
|
}
|
|
@@ -7589,11 +7638,13 @@
|
|
|
7589
7638
|
method: "POST",
|
|
7590
7639
|
body: JSON.stringify(query),
|
|
7591
7640
|
});
|
|
7641
|
+
flashStudioPdfActionFeedback(actionButton, openInSystemViewer ? "Opened ✓" : "Shown ✓", "success");
|
|
7592
7642
|
setStatus(payload && payload.message
|
|
7593
7643
|
? payload.message
|
|
7594
7644
|
: (openInSystemViewer ? "Opened PDF in the system viewer." : "Revealed PDF in the file manager."), "success");
|
|
7595
7645
|
return true;
|
|
7596
7646
|
} catch (error) {
|
|
7647
|
+
flashStudioPdfActionFeedback(actionButton, "Failed", "warning");
|
|
7597
7648
|
setStatus((error && error.message)
|
|
7598
7649
|
? error.message
|
|
7599
7650
|
: (openInSystemViewer ? "Could not open PDF in the system viewer." : "Could not reveal PDF in the file manager."), "warning");
|
|
@@ -7605,6 +7656,31 @@
|
|
|
7605
7656
|
const available = Boolean(normalizeStudioPdfResourceQuery(studioPdfFocusResourceQuery));
|
|
7606
7657
|
if (studioPdfFocusSystemViewerBtn) studioPdfFocusSystemViewerBtn.disabled = !available;
|
|
7607
7658
|
if (studioPdfFocusRevealBtn) studioPdfFocusRevealBtn.disabled = !available;
|
|
7659
|
+
if (studioPdfFocusCopyPathBtn) studioPdfFocusCopyPathBtn.disabled = !available;
|
|
7660
|
+
}
|
|
7661
|
+
|
|
7662
|
+
async function copyStudioPdfResourcePath(resourceQuery, actionButton) {
|
|
7663
|
+
const query = normalizeStudioPdfResourceQuery(resourceQuery);
|
|
7664
|
+
if (!query) {
|
|
7665
|
+
flashStudioPdfActionFeedback(actionButton, "Unavailable", "warning");
|
|
7666
|
+
setStatus("Could not resolve this PDF's local path.", "warning");
|
|
7667
|
+
return false;
|
|
7668
|
+
}
|
|
7669
|
+
try {
|
|
7670
|
+
const payload = await fetchStudioJson("/local-preview-link", {
|
|
7671
|
+
query: { ...query, action: "resolve" },
|
|
7672
|
+
});
|
|
7673
|
+
const path = payload && typeof payload.path === "string" ? payload.path : "";
|
|
7674
|
+
if (!path) throw new Error("Studio did not return a PDF path.");
|
|
7675
|
+
if (!(await writeTextToClipboard(path))) throw new Error("Clipboard write failed.");
|
|
7676
|
+
flashStudioPdfActionFeedback(actionButton, "Copied ✓", "success");
|
|
7677
|
+
setStatus("Copied PDF path from the computer running Pi.", "success");
|
|
7678
|
+
return true;
|
|
7679
|
+
} catch (error) {
|
|
7680
|
+
flashStudioPdfActionFeedback(actionButton, "Failed", "warning");
|
|
7681
|
+
setStatus((error && error.message) ? error.message : "Could not copy this PDF's local path.", "warning");
|
|
7682
|
+
return false;
|
|
7683
|
+
}
|
|
7608
7684
|
}
|
|
7609
7685
|
|
|
7610
7686
|
function buildRefreshedStudioPdfViewerUrl(value) {
|
|
@@ -7731,6 +7807,10 @@
|
|
|
7731
7807
|
|
|
7732
7808
|
function syncStudioPdfFocusFullscreenButton() {
|
|
7733
7809
|
if (!studioPdfFocusFullscreenBtn) return;
|
|
7810
|
+
const available = isStudioFullscreenAvailable(studioPdfFocusDialogEl);
|
|
7811
|
+
studioPdfFocusFullscreenBtn.hidden = !available;
|
|
7812
|
+
studioPdfFocusFullscreenBtn.setAttribute("aria-hidden", available ? "false" : "true");
|
|
7813
|
+
if (!available) return;
|
|
7734
7814
|
const isFullscreen = Boolean(document.fullscreenElement && studioPdfFocusDialogEl && document.fullscreenElement === studioPdfFocusDialogEl);
|
|
7735
7815
|
studioPdfFocusFullscreenBtn.replaceChildren(makeStudioUiRefreshIcon(isFullscreen ? "fullscreen-exit" : "fullscreen"));
|
|
7736
7816
|
const label = isFullscreen ? "Exit fullscreen" : "Fullscreen";
|
|
@@ -7789,6 +7869,16 @@
|
|
|
7789
7869
|
studioPdfFocusFrameEl.title = String(title || "PDF focus viewer").trim() || "PDF focus viewer";
|
|
7790
7870
|
}
|
|
7791
7871
|
|
|
7872
|
+
function getStudioPdfCardResourceQuery(card) {
|
|
7873
|
+
return card && card.dataset
|
|
7874
|
+
? normalizeStudioPdfResourceQuery({
|
|
7875
|
+
path: card.dataset.studioPdfPath || "",
|
|
7876
|
+
sourcePath: card.dataset.studioPdfSourcePath || "",
|
|
7877
|
+
resourceDir: card.dataset.studioPdfResourceDir || "",
|
|
7878
|
+
})
|
|
7879
|
+
: null;
|
|
7880
|
+
}
|
|
7881
|
+
|
|
7792
7882
|
function openStudioPdfFocusFromButton(buttonEl) {
|
|
7793
7883
|
if (!buttonEl) return false;
|
|
7794
7884
|
const card = buttonEl.closest && buttonEl.closest(".studio-pdf-card");
|
|
@@ -7798,13 +7888,7 @@
|
|
|
7798
7888
|
|| String(card && card.dataset ? (card.dataset.studioPdfTitle || "") : "").trim()
|
|
7799
7889
|
|| "PDF preview";
|
|
7800
7890
|
const sourceFrame = card && typeof card.querySelector === "function" ? card.querySelector("iframe.studio-pdf-frame") : null;
|
|
7801
|
-
const resourceQuery = card
|
|
7802
|
-
? normalizeStudioPdfResourceQuery({
|
|
7803
|
-
path: card.dataset.studioPdfPath || "",
|
|
7804
|
-
sourcePath: card.dataset.studioPdfSourcePath || "",
|
|
7805
|
-
resourceDir: card.dataset.studioPdfResourceDir || "",
|
|
7806
|
-
})
|
|
7807
|
-
: null;
|
|
7891
|
+
const resourceQuery = getStudioPdfCardResourceQuery(card);
|
|
7808
7892
|
if (!viewerUrl) return false;
|
|
7809
7893
|
openStudioPdfFocusViewer(viewerUrl, title, sourceFrame, resourceQuery, card);
|
|
7810
7894
|
return true;
|
|
@@ -7824,6 +7908,73 @@
|
|
|
7824
7908
|
}
|
|
7825
7909
|
}
|
|
7826
7910
|
|
|
7911
|
+
function consumeStudioPreviewMediaEvent(event) {
|
|
7912
|
+
event.preventDefault();
|
|
7913
|
+
event.stopPropagation();
|
|
7914
|
+
if (typeof event.stopImmediatePropagation === "function") event.stopImmediatePropagation();
|
|
7915
|
+
}
|
|
7916
|
+
|
|
7917
|
+
function handleStudioPreviewMediaKeydown(event) {
|
|
7918
|
+
if (!event || (event.key !== "Enter" && event.key !== " ")) return;
|
|
7919
|
+
const target = event.target;
|
|
7920
|
+
const imageEl = target instanceof Element ? target.closest("img.studio-image-focus-target") : null;
|
|
7921
|
+
if (!imageEl) return;
|
|
7922
|
+
consumeStudioPreviewMediaEvent(event);
|
|
7923
|
+
if (!openPreviewImageElementInFocus(imageEl)) setStatus("Could not open image focus view.", "warning");
|
|
7924
|
+
}
|
|
7925
|
+
|
|
7926
|
+
function handleStudioPreviewMediaActivation(event) {
|
|
7927
|
+
const target = event && event.target;
|
|
7928
|
+
if (!(target instanceof Element)) return;
|
|
7929
|
+
|
|
7930
|
+
const imageEl = target.closest("img.studio-image-focus-target");
|
|
7931
|
+
if (imageEl) {
|
|
7932
|
+
consumeStudioPreviewMediaEvent(event);
|
|
7933
|
+
if (!openPreviewImageElementInFocus(imageEl)) setStatus("Could not open image focus view.", "warning");
|
|
7934
|
+
return;
|
|
7935
|
+
}
|
|
7936
|
+
|
|
7937
|
+
const pdfFigureEl = target.closest(".studio-pdf-preview-focus-target");
|
|
7938
|
+
if (pdfFigureEl && !target.closest("button, a")) {
|
|
7939
|
+
consumeStudioPreviewMediaEvent(event);
|
|
7940
|
+
if (!openPreviewPdfFigureInFocus(pdfFigureEl)) setStatus("Could not enlarge this PDF figure preview.", "warning");
|
|
7941
|
+
return;
|
|
7942
|
+
}
|
|
7943
|
+
|
|
7944
|
+
const actionBtn = target.closest(
|
|
7945
|
+
".studio-pdf-card-system-viewer, .studio-pdf-card-reveal, .studio-pdf-card-copy-path, .studio-pdf-card-refresh, .studio-pdf-card-auto-refresh"
|
|
7946
|
+
);
|
|
7947
|
+
if (!actionBtn) return;
|
|
7948
|
+
const card = actionBtn.closest(".studio-pdf-card");
|
|
7949
|
+
if (!card) return;
|
|
7950
|
+
consumeStudioPreviewMediaEvent(event);
|
|
7951
|
+
const resourceQuery = getStudioPdfCardResourceQuery(card);
|
|
7952
|
+
if (actionBtn.classList.contains("studio-pdf-card-system-viewer")) {
|
|
7953
|
+
void runStudioPdfLocalAction("system-viewer", resourceQuery, actionBtn);
|
|
7954
|
+
return;
|
|
7955
|
+
}
|
|
7956
|
+
if (actionBtn.classList.contains("studio-pdf-card-reveal")) {
|
|
7957
|
+
void runStudioPdfLocalAction("reveal", resourceQuery, actionBtn);
|
|
7958
|
+
return;
|
|
7959
|
+
}
|
|
7960
|
+
if (actionBtn.classList.contains("studio-pdf-card-copy-path")) {
|
|
7961
|
+
void copyStudioPdfResourcePath(resourceQuery, actionBtn);
|
|
7962
|
+
return;
|
|
7963
|
+
}
|
|
7964
|
+
if (actionBtn.classList.contains("studio-pdf-card-refresh")) {
|
|
7965
|
+
const refreshed = refreshStudioPdfCard(card);
|
|
7966
|
+
flashStudioPdfActionFeedback(actionBtn, refreshed ? "Refreshed ✓" : "Failed", refreshed ? "success" : "warning");
|
|
7967
|
+
if (!refreshed) setStatus("Could not refresh this PDF preview.", "warning");
|
|
7968
|
+
return;
|
|
7969
|
+
}
|
|
7970
|
+
const state = ensureStudioPdfCardAutoRefreshState(card, resourceQuery);
|
|
7971
|
+
if (!state) {
|
|
7972
|
+
setStatus("Could not resolve this PDF for auto-refresh.", "warning");
|
|
7973
|
+
return;
|
|
7974
|
+
}
|
|
7975
|
+
setStudioPdfCardAutoRefresh(card, !state.enabled);
|
|
7976
|
+
}
|
|
7977
|
+
|
|
7827
7978
|
function isStudioImageFocusOpen() {
|
|
7828
7979
|
return Boolean(studioImageFocusOverlayEl && studioImageFocusOverlayEl.hidden === false);
|
|
7829
7980
|
}
|
|
@@ -7976,6 +8127,10 @@
|
|
|
7976
8127
|
|
|
7977
8128
|
function syncStudioImageFocusFullscreenButton() {
|
|
7978
8129
|
if (!studioImageFocusFullscreenBtn) return;
|
|
8130
|
+
const available = isStudioFullscreenAvailable(studioImageFocusDialogEl);
|
|
8131
|
+
studioImageFocusFullscreenBtn.hidden = !available;
|
|
8132
|
+
studioImageFocusFullscreenBtn.setAttribute("aria-hidden", available ? "false" : "true");
|
|
8133
|
+
if (!available) return;
|
|
7979
8134
|
const isFullscreen = Boolean(document.fullscreenElement && studioImageFocusDialogEl && document.fullscreenElement === studioImageFocusDialogEl);
|
|
7980
8135
|
studioImageFocusFullscreenBtn.replaceChildren(makeStudioUiRefreshIcon(isFullscreen ? "fullscreen-exit" : "fullscreen"));
|
|
7981
8136
|
const label = isFullscreen ? "Exit fullscreen" : "Fullscreen";
|
|
@@ -8212,6 +8367,39 @@
|
|
|
8212
8367
|
});
|
|
8213
8368
|
}
|
|
8214
8369
|
|
|
8370
|
+
function openPreviewPdfFigureInFocus(previewEl) {
|
|
8371
|
+
const canvas = previewEl && typeof previewEl.querySelector === "function"
|
|
8372
|
+
? previewEl.querySelector("canvas")
|
|
8373
|
+
: null;
|
|
8374
|
+
if (!(canvas instanceof HTMLCanvasElement)) return false;
|
|
8375
|
+
try {
|
|
8376
|
+
const dataUrl = canvas.toDataURL("image/png");
|
|
8377
|
+
const title = String(previewEl.getAttribute("title") || "PDF figure preview").trim() || "PDF figure preview";
|
|
8378
|
+
return openStudioImageFocusViewer(dataUrl, title);
|
|
8379
|
+
} catch {
|
|
8380
|
+
return false;
|
|
8381
|
+
}
|
|
8382
|
+
}
|
|
8383
|
+
|
|
8384
|
+
function decoratePreviewPdfFigures(targetEl) {
|
|
8385
|
+
if (!targetEl || typeof targetEl.querySelectorAll !== "function") return;
|
|
8386
|
+
const previews = Array.from(targetEl.querySelectorAll(".studio-pdf-preview"));
|
|
8387
|
+
previews.forEach((previewEl) => {
|
|
8388
|
+
if (!(previewEl instanceof HTMLElement)) return;
|
|
8389
|
+
if (previewEl.dataset && previewEl.dataset.studioPdfFigureFocusDecorated === "1") return;
|
|
8390
|
+
if (!previewEl.querySelector("canvas")) return;
|
|
8391
|
+
previewEl.classList.add("studio-pdf-preview-focus-target");
|
|
8392
|
+
previewEl.title = "PDF figure preview (page 1). Click to enlarge.";
|
|
8393
|
+
if (previewEl.dataset) previewEl.dataset.studioPdfFigureFocusDecorated = "1";
|
|
8394
|
+
|
|
8395
|
+
previewEl.addEventListener("click", (event) => {
|
|
8396
|
+
if (event.target instanceof Element && event.target.closest("button, a")) return;
|
|
8397
|
+
event.preventDefault();
|
|
8398
|
+
if (!openPreviewPdfFigureInFocus(previewEl)) setStatus("Could not enlarge this PDF figure preview.", "warning");
|
|
8399
|
+
});
|
|
8400
|
+
});
|
|
8401
|
+
}
|
|
8402
|
+
|
|
8215
8403
|
function createStudioPdfCard(block, useEditorResourceContext) {
|
|
8216
8404
|
const options = block && block.options ? block.options : {};
|
|
8217
8405
|
const path = String(options.path || "").trim();
|
|
@@ -8244,12 +8432,13 @@
|
|
|
8244
8432
|
focusBtn.type = "button";
|
|
8245
8433
|
focusBtn.className = "studio-pdf-card-action studio-pdf-card-focus";
|
|
8246
8434
|
focusBtn.title = "Open this PDF in a larger Studio overlay.";
|
|
8247
|
-
focusBtn.setAttribute("aria-label", "
|
|
8435
|
+
focusBtn.setAttribute("aria-label", "Enlarge PDF");
|
|
8248
8436
|
if (focusBtn.dataset) {
|
|
8249
8437
|
focusBtn.dataset.studioPdfViewerUrl = viewerUrl;
|
|
8250
8438
|
focusBtn.dataset.studioPdfTitle = title;
|
|
8251
8439
|
}
|
|
8252
8440
|
focusBtn.appendChild(makeStudioUiRefreshIcon("focus"));
|
|
8441
|
+
focusBtn.appendChild(document.createTextNode("Enlarge"));
|
|
8253
8442
|
focusBtn.addEventListener("click", handleStudioPdfFocusButtonClick);
|
|
8254
8443
|
titleGroup.appendChild(focusBtn);
|
|
8255
8444
|
}
|
|
@@ -8276,11 +8465,11 @@
|
|
|
8276
8465
|
systemViewerBtn.type = "button";
|
|
8277
8466
|
systemViewerBtn.className = "studio-pdf-card-action studio-pdf-card-system-viewer";
|
|
8278
8467
|
systemViewerBtn.textContent = "System viewer";
|
|
8279
|
-
systemViewerBtn.title = "Open the local PDF in the
|
|
8468
|
+
systemViewerBtn.title = "Open the local PDF in the default viewer on the computer running Pi.";
|
|
8280
8469
|
systemViewerBtn.addEventListener("click", (event) => {
|
|
8281
8470
|
event.preventDefault();
|
|
8282
8471
|
event.stopPropagation();
|
|
8283
|
-
void runStudioPdfLocalAction("system-viewer", resourceQuery);
|
|
8472
|
+
void runStudioPdfLocalAction("system-viewer", resourceQuery, systemViewerBtn);
|
|
8284
8473
|
});
|
|
8285
8474
|
actions.appendChild(systemViewerBtn);
|
|
8286
8475
|
|
|
@@ -8288,14 +8477,26 @@
|
|
|
8288
8477
|
revealBtn.type = "button";
|
|
8289
8478
|
revealBtn.className = "studio-pdf-card-action studio-pdf-card-reveal";
|
|
8290
8479
|
revealBtn.textContent = "Show in folder";
|
|
8291
|
-
revealBtn.title = "Reveal the local PDF in
|
|
8480
|
+
revealBtn.title = "Reveal the local PDF in the file manager on the computer running Pi.";
|
|
8292
8481
|
revealBtn.addEventListener("click", (event) => {
|
|
8293
8482
|
event.preventDefault();
|
|
8294
8483
|
event.stopPropagation();
|
|
8295
|
-
void runStudioPdfLocalAction("reveal", resourceQuery);
|
|
8484
|
+
void runStudioPdfLocalAction("reveal", resourceQuery, revealBtn);
|
|
8296
8485
|
});
|
|
8297
8486
|
actions.appendChild(revealBtn);
|
|
8298
8487
|
|
|
8488
|
+
const copyPathBtn = document.createElement("button");
|
|
8489
|
+
copyPathBtn.type = "button";
|
|
8490
|
+
copyPathBtn.className = "studio-pdf-card-action studio-pdf-card-copy-path";
|
|
8491
|
+
copyPathBtn.textContent = "Copy path";
|
|
8492
|
+
copyPathBtn.title = "Copy the PDF path on the computer running Pi.";
|
|
8493
|
+
copyPathBtn.addEventListener("click", (event) => {
|
|
8494
|
+
event.preventDefault();
|
|
8495
|
+
event.stopPropagation();
|
|
8496
|
+
void copyStudioPdfResourcePath(resourceQuery, copyPathBtn);
|
|
8497
|
+
});
|
|
8498
|
+
actions.appendChild(copyPathBtn);
|
|
8499
|
+
|
|
8299
8500
|
const refreshBtn = document.createElement("button");
|
|
8300
8501
|
refreshBtn.type = "button";
|
|
8301
8502
|
refreshBtn.className = "studio-pdf-card-action studio-pdf-card-refresh";
|
|
@@ -9238,6 +9439,32 @@
|
|
|
9238
9439
|
});
|
|
9239
9440
|
}
|
|
9240
9441
|
|
|
9442
|
+
function copyResponsePaneCanvasState(sourceEl, replacementEl) {
|
|
9443
|
+
if (!sourceEl || !replacementEl || typeof sourceEl.querySelectorAll !== "function" || typeof replacementEl.querySelectorAll !== "function") {
|
|
9444
|
+
return false;
|
|
9445
|
+
}
|
|
9446
|
+
const sourceCanvases = Array.from(sourceEl.querySelectorAll("canvas"));
|
|
9447
|
+
const replacementCanvases = Array.from(replacementEl.querySelectorAll("canvas"));
|
|
9448
|
+
if (sourceCanvases.length !== replacementCanvases.length) return false;
|
|
9449
|
+
|
|
9450
|
+
for (let index = 0; index < sourceCanvases.length; index += 1) {
|
|
9451
|
+
const sourceCanvas = sourceCanvases[index];
|
|
9452
|
+
const replacementCanvas = replacementCanvases[index];
|
|
9453
|
+
if (!(sourceCanvas instanceof HTMLCanvasElement) || !(replacementCanvas instanceof HTMLCanvasElement)) return false;
|
|
9454
|
+
if (sourceCanvas.width < 1 || sourceCanvas.height < 1) continue;
|
|
9455
|
+
try {
|
|
9456
|
+
replacementCanvas.width = sourceCanvas.width;
|
|
9457
|
+
replacementCanvas.height = sourceCanvas.height;
|
|
9458
|
+
const context = replacementCanvas.getContext("2d");
|
|
9459
|
+
if (!context) return false;
|
|
9460
|
+
context.drawImage(sourceCanvas, 0, 0);
|
|
9461
|
+
} catch {
|
|
9462
|
+
return false;
|
|
9463
|
+
}
|
|
9464
|
+
}
|
|
9465
|
+
return true;
|
|
9466
|
+
}
|
|
9467
|
+
|
|
9241
9468
|
function replaceResponsePaneWithClone() {
|
|
9242
9469
|
const currentEl = critiqueViewEl;
|
|
9243
9470
|
if (!currentEl || !currentEl.parentNode || typeof currentEl.cloneNode !== "function") {
|
|
@@ -9245,7 +9472,7 @@
|
|
|
9245
9472
|
}
|
|
9246
9473
|
|
|
9247
9474
|
const replacement = currentEl.cloneNode(true);
|
|
9248
|
-
if (!replacement || replacement.nodeType !== 1) {
|
|
9475
|
+
if (!replacement || replacement.nodeType !== 1 || !copyResponsePaneCanvasState(currentEl, replacement)) {
|
|
9249
9476
|
return currentEl;
|
|
9250
9477
|
}
|
|
9251
9478
|
|
|
@@ -10019,6 +10246,10 @@
|
|
|
10019
10246
|
|
|
10020
10247
|
function exportRightPaneFormat(format) {
|
|
10021
10248
|
closeExportPreviewMenu();
|
|
10249
|
+
if (String(format || "").startsWith("side-markdown-") && rightView !== "side-questions") {
|
|
10250
|
+
setStatus("Side-thread Markdown export is available only in Side questions.", "warning");
|
|
10251
|
+
return false;
|
|
10252
|
+
}
|
|
10022
10253
|
if (format === "side-markdown-save") {
|
|
10023
10254
|
return saveSideQuestionTranscriptMarkdown();
|
|
10024
10255
|
}
|
|
@@ -10259,6 +10490,7 @@
|
|
|
10259
10490
|
await renderAnnotationMathInElement(targetEl);
|
|
10260
10491
|
decoratePdfEmbeds(targetEl);
|
|
10261
10492
|
await renderPdfPreviewsInElement(targetEl);
|
|
10493
|
+
decoratePreviewPdfFigures(targetEl);
|
|
10262
10494
|
const annotationMode = (pane === "source" || pane === "response")
|
|
10263
10495
|
? (annotationsEnabled ? "highlight" : "hide")
|
|
10264
10496
|
: "none";
|
|
@@ -12141,6 +12373,7 @@
|
|
|
12141
12373
|
await renderMermaidInElement(target);
|
|
12142
12374
|
await renderMathFallbackInElement(target);
|
|
12143
12375
|
decorateCopyablePreviewBlocks(target);
|
|
12376
|
+
decoratePreviewImages(target);
|
|
12144
12377
|
} catch (error) {
|
|
12145
12378
|
console.error("Side-question markdown preview failed:", error);
|
|
12146
12379
|
target.classList.add("side-question-markdown-failed");
|
|
@@ -15015,9 +15248,11 @@
|
|
|
15015
15248
|
await renderAnnotationMathInElement(target);
|
|
15016
15249
|
decoratePdfEmbeds(target);
|
|
15017
15250
|
await renderPdfPreviewsInElement(target);
|
|
15251
|
+
decoratePreviewPdfFigures(target);
|
|
15018
15252
|
await renderMermaidInElement(target);
|
|
15019
15253
|
await renderMathFallbackInElement(target);
|
|
15020
15254
|
decorateCopyablePreviewBlocks(target);
|
|
15255
|
+
decoratePreviewImages(target);
|
|
15021
15256
|
if (preserveScroll) restoreQuizScrollTopSoon(scrollTop);
|
|
15022
15257
|
} catch (error) {
|
|
15023
15258
|
console.error("Quiz markdown preview render failed:", error);
|
|
@@ -23552,6 +23787,9 @@
|
|
|
23552
23787
|
});
|
|
23553
23788
|
}
|
|
23554
23789
|
|
|
23790
|
+
document.addEventListener("click", handleStudioPreviewMediaActivation, true);
|
|
23791
|
+
document.addEventListener("keydown", handleStudioPreviewMediaKeydown, true);
|
|
23792
|
+
|
|
23555
23793
|
document.addEventListener("click", (event) => {
|
|
23556
23794
|
const target = event.target;
|
|
23557
23795
|
const focusBtn = target instanceof Element ? target.closest(".studio-pdf-card-focus") : null;
|
package/client/studio.css
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
justify-content: space-between;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
h1 {
|
|
32
|
+
body > header h1 {
|
|
33
33
|
margin: 0;
|
|
34
34
|
font-size: 18px;
|
|
35
35
|
font-weight: 600;
|
|
@@ -202,6 +202,10 @@
|
|
|
202
202
|
font-weight: 450;
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
+
.export-preview-menu button[hidden] {
|
|
206
|
+
display: none !important;
|
|
207
|
+
}
|
|
208
|
+
|
|
205
209
|
.export-preview-menu button:not(:disabled):hover,
|
|
206
210
|
.export-preview-menu button:not(:disabled):focus-visible {
|
|
207
211
|
background: var(--panel-2);
|
|
@@ -1182,6 +1186,7 @@
|
|
|
1182
1186
|
.rendered-markdown h4,
|
|
1183
1187
|
.rendered-markdown h5,
|
|
1184
1188
|
.rendered-markdown h6 {
|
|
1189
|
+
display: block;
|
|
1185
1190
|
margin-top: 1.2em;
|
|
1186
1191
|
margin-bottom: 0.5em;
|
|
1187
1192
|
line-height: 1.25;
|
|
@@ -1190,17 +1195,39 @@
|
|
|
1190
1195
|
}
|
|
1191
1196
|
|
|
1192
1197
|
.rendered-markdown h1 {
|
|
1193
|
-
font-size: 1.
|
|
1198
|
+
font-size: 1.7em;
|
|
1199
|
+
font-weight: 720;
|
|
1194
1200
|
border-bottom: 0;
|
|
1195
1201
|
padding-bottom: 0;
|
|
1196
1202
|
}
|
|
1197
1203
|
|
|
1198
1204
|
.rendered-markdown h2 {
|
|
1199
|
-
font-size: 1.
|
|
1205
|
+
font-size: 1.4em;
|
|
1206
|
+
font-weight: 700;
|
|
1200
1207
|
border-bottom: 0;
|
|
1201
1208
|
padding-bottom: 0;
|
|
1202
1209
|
}
|
|
1203
1210
|
|
|
1211
|
+
.rendered-markdown h3 {
|
|
1212
|
+
font-size: 1.2em;
|
|
1213
|
+
font-weight: 680;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
.rendered-markdown h4 {
|
|
1217
|
+
font-size: 1.08em;
|
|
1218
|
+
font-weight: 660;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
.rendered-markdown h5 {
|
|
1222
|
+
font-size: 1em;
|
|
1223
|
+
font-weight: 650;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
.rendered-markdown h6 {
|
|
1227
|
+
font-size: 0.92em;
|
|
1228
|
+
font-weight: 650;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1204
1231
|
.rendered-markdown #title-block-header {
|
|
1205
1232
|
text-align: center;
|
|
1206
1233
|
margin-bottom: 2em;
|
|
@@ -1767,6 +1794,7 @@
|
|
|
1767
1794
|
}
|
|
1768
1795
|
|
|
1769
1796
|
.rendered-markdown .studio-pdf-preview {
|
|
1797
|
+
position: relative;
|
|
1770
1798
|
display: block;
|
|
1771
1799
|
max-width: 100%;
|
|
1772
1800
|
border: 1px solid var(--md-table-border);
|
|
@@ -1776,6 +1804,10 @@
|
|
|
1776
1804
|
line-height: 0;
|
|
1777
1805
|
}
|
|
1778
1806
|
|
|
1807
|
+
.rendered-markdown .studio-pdf-preview-focus-target {
|
|
1808
|
+
cursor: zoom-in;
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1779
1811
|
.rendered-markdown .studio-pdf-preview[data-fig-align="center"] {
|
|
1780
1812
|
margin-left: auto;
|
|
1781
1813
|
margin-right: auto;
|
|
@@ -1881,6 +1913,19 @@
|
|
|
1881
1913
|
border-color: var(--control-border);
|
|
1882
1914
|
}
|
|
1883
1915
|
|
|
1916
|
+
.rendered-markdown button.studio-pdf-card-action[data-studio-action-feedback="success"],
|
|
1917
|
+
.studio-pdf-focus-btn[data-studio-action-feedback="success"] {
|
|
1918
|
+
background: var(--accent-soft);
|
|
1919
|
+
color: var(--accent);
|
|
1920
|
+
border-color: color-mix(in srgb, var(--accent) 45%, var(--control-border));
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
.rendered-markdown button.studio-pdf-card-action[data-studio-action-feedback="warning"],
|
|
1924
|
+
.studio-pdf-focus-btn[data-studio-action-feedback="warning"] {
|
|
1925
|
+
color: var(--warn);
|
|
1926
|
+
border-color: color-mix(in srgb, var(--warn) 45%, var(--control-border));
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1884
1929
|
.rendered-markdown button.studio-pdf-card-auto-refresh[aria-pressed="true"] {
|
|
1885
1930
|
background: transparent;
|
|
1886
1931
|
color: var(--accent);
|
|
@@ -1896,13 +1941,14 @@
|
|
|
1896
1941
|
}
|
|
1897
1942
|
|
|
1898
1943
|
.rendered-markdown button.studio-pdf-card-focus {
|
|
1899
|
-
width:
|
|
1944
|
+
width: auto;
|
|
1900
1945
|
min-width: 29px;
|
|
1901
1946
|
min-height: 29px;
|
|
1902
|
-
padding: 0;
|
|
1947
|
+
padding: 0 8px;
|
|
1903
1948
|
display: inline-flex;
|
|
1904
1949
|
align-items: center;
|
|
1905
1950
|
justify-content: center;
|
|
1951
|
+
gap: 5px;
|
|
1906
1952
|
}
|
|
1907
1953
|
|
|
1908
1954
|
.rendered-markdown button.studio-pdf-card-focus .studio-refresh-icon {
|
|
@@ -2075,6 +2121,10 @@
|
|
|
2075
2121
|
height: 14px;
|
|
2076
2122
|
}
|
|
2077
2123
|
|
|
2124
|
+
.studio-pdf-focus-fullscreen[hidden] {
|
|
2125
|
+
display: none !important;
|
|
2126
|
+
}
|
|
2127
|
+
|
|
2078
2128
|
.studio-pdf-focus-fullscreen,
|
|
2079
2129
|
.studio-pdf-focus-close {
|
|
2080
2130
|
width: 29px;
|
|
@@ -5429,7 +5479,7 @@
|
|
|
5429
5479
|
gap: 9px;
|
|
5430
5480
|
}
|
|
5431
5481
|
|
|
5432
|
-
body.studio-ui-refresh h1 {
|
|
5482
|
+
body.studio-ui-refresh > header h1 {
|
|
5433
5483
|
font-size: 16px;
|
|
5434
5484
|
}
|
|
5435
5485
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-studio",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.52",
|
|
4
4
|
"description": "Two-pane browser workspace for pi with prompt/response editing, annotations, critiques, active quiz, prompt/response history, live previews, and tmux-backed REPL/literate REPL workflows",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"themes",
|
|
25
25
|
"README.md",
|
|
26
26
|
"CHANGELOG.md",
|
|
27
|
+
"ROADMAP.md",
|
|
27
28
|
"WORKFLOW.md",
|
|
28
29
|
"assets/screenshots",
|
|
29
30
|
"assets/demo"
|