pi-studio 0.9.37 → 0.9.38
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 +5 -0
- package/index.ts +4 -4
- package/package.json +1 -1
- package/shared/studio-mermaid.js +39 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,11 @@ All notable changes to `pi-studio` are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.9.38] — 2026-08-01
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- Preserved corrected Mermaid node colours during Chromium PDF printing and gave external icon-node labels a theme-aware backdrop, preventing washed-out labels beside custom icon fills.
|
|
11
|
+
|
|
7
12
|
## [0.9.37] — 2026-08-01
|
|
8
13
|
|
|
9
14
|
### Added
|
package/index.ts
CHANGED
|
@@ -5843,14 +5843,14 @@ async function renderStudioMermaidDiagramForPdf(source: string, workDir: string,
|
|
|
5843
5843
|
const mermaidTheme = getStudioMermaidPdfTheme();
|
|
5844
5844
|
const inputPath = join(workDir, `mermaid-diagram-${blockNumber}.mmd`);
|
|
5845
5845
|
const outputPath = join(workDir, `mermaid-diagram-${blockNumber}.pdf`);
|
|
5846
|
-
const
|
|
5846
|
+
const contrastCssPath = join(workDir, `mermaid-diagram-${blockNumber}.css`);
|
|
5847
5847
|
|
|
5848
5848
|
const preparedSource = ensureStudioMermaidSourceContrast(source);
|
|
5849
|
-
const
|
|
5849
|
+
const contrastCss = buildStudioMermaidPdfIconContrastCss(preparedSource, { theme: mermaidTheme });
|
|
5850
5850
|
await writeFile(inputPath, preparedSource, "utf-8");
|
|
5851
|
-
if (
|
|
5851
|
+
if (contrastCss) await writeFile(contrastCssPath, contrastCss, "utf-8");
|
|
5852
5852
|
const args = ["-i", inputPath, "-o", outputPath, "-t", mermaidTheme, "-f"];
|
|
5853
|
-
if (
|
|
5853
|
+
if (contrastCss) args.push("-C", contrastCssPath);
|
|
5854
5854
|
args.push(...buildStudioMermaidCliIconArgs(preparedSource));
|
|
5855
5855
|
const result = await runStudioSubprocess(mermaidCommand, args, {
|
|
5856
5856
|
timeoutMs: STUDIO_MERMAID_TIMEOUT_MS,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-studio",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.38",
|
|
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",
|
package/shared/studio-mermaid.js
CHANGED
|
@@ -232,12 +232,44 @@ function buildStudioMermaidIconPaintRule(selector, color) {
|
|
|
232
232
|
].join("\n");
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
-
|
|
235
|
+
function buildStudioMermaidPdfPrintColorRule() {
|
|
236
|
+
return [
|
|
237
|
+
".node, .node *, .icon-shape, .icon-shape * {",
|
|
238
|
+
" -webkit-print-color-adjust: exact !important;",
|
|
239
|
+
" print-color-adjust: exact !important;",
|
|
240
|
+
"}",
|
|
241
|
+
].join("\n");
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function buildStudioMermaidPdfIconLabelRule(selectors, theme) {
|
|
245
|
+
if (selectors.length === 0) return "";
|
|
246
|
+
const darkTheme = String(theme || "default").toLowerCase() === "dark";
|
|
247
|
+
const background = darkTheme ? "#1f2937" : "#ffffff";
|
|
248
|
+
const foreground = darkTheme ? "#ffffff" : "#000000";
|
|
249
|
+
const backgroundSelectors = selectors.map((selector) => `${selector} .labelBkg`).join(",\n");
|
|
250
|
+
const textSelectors = selectors.flatMap((selector) => [
|
|
251
|
+
`${selector} .nodeLabel`,
|
|
252
|
+
`${selector} .nodeLabel *`,
|
|
253
|
+
]).join(",\n");
|
|
254
|
+
return [
|
|
255
|
+
`${backgroundSelectors} { background-color: ${background} !important; }`,
|
|
256
|
+
`${textSelectors} {`,
|
|
257
|
+
` color: ${foreground} !important;`,
|
|
258
|
+
` fill: ${foreground} !important;`,
|
|
259
|
+
` -webkit-text-fill-color: ${foreground} !important;`,
|
|
260
|
+
" opacity: 1 !important;",
|
|
261
|
+
"}",
|
|
262
|
+
].join("\n");
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export function buildStudioMermaidPdfIconContrastCss(source, options = {}) {
|
|
236
266
|
const preparedSource = ensureStudioMermaidSourceContrast(source);
|
|
237
267
|
const { iconNodeIds, classNamesByNode } = collectStudioMermaidIconStyleTargets(preparedSource);
|
|
238
|
-
|
|
268
|
+
const printColorRule = buildStudioMermaidPdfPrintColorRule();
|
|
269
|
+
if (iconNodeIds.size === 0) return printColorRule;
|
|
239
270
|
const classStyles = collectStudioMermaidStylesByTarget(preparedSource, "classDef");
|
|
240
271
|
const directStyles = collectStudioMermaidStylesByTarget(preparedSource, "style");
|
|
272
|
+
const iconSelectors = Array.from(iconNodeIds, (iconNodeId) => `.icon-shape[id*="flowchart-${iconNodeId}-"]`);
|
|
241
273
|
const rulesBySelector = new Map();
|
|
242
274
|
|
|
243
275
|
for (const iconNodeId of iconNodeIds) {
|
|
@@ -250,5 +282,9 @@ export function buildStudioMermaidPdfIconContrastCss(source) {
|
|
|
250
282
|
if (paint) rulesBySelector.set(`.icon-shape[id*="flowchart-${iconNodeId}-"]`, paint);
|
|
251
283
|
}
|
|
252
284
|
|
|
253
|
-
return
|
|
285
|
+
return [
|
|
286
|
+
printColorRule,
|
|
287
|
+
buildStudioMermaidPdfIconLabelRule(iconSelectors, options.theme),
|
|
288
|
+
...Array.from(rulesBySelector, ([selector, color]) => buildStudioMermaidIconPaintRule(selector, color)),
|
|
289
|
+
].filter(Boolean).join("\n");
|
|
254
290
|
}
|