pi-studio 0.1.8 → 0.2.0
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 +19 -0
- package/README.md +5 -1
- package/index.ts +547 -67
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `pi-studio` are documented here.
|
|
4
4
|
|
|
5
|
+
## [0.2.0] — 2026-03-02
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- Luminance-based canvas color derivation from theme surface colors — proper bg/panel/panel2 tiers instead of flat mid-tone mapping.
|
|
9
|
+
- Dedicated `--editor-bg` CSS variable — editor text box pushed toward white (light) for a crisp paper feel.
|
|
10
|
+
- `Cmd/Ctrl+Enter` keyboard shortcut to trigger "Run editor text" when editor pane is active.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Renamed "Highlight markdown: On/Off" → "Syntax highlight: On/Off".
|
|
14
|
+
- Renamed "Editor: Markdown" / "Response: Markdown" → "Editor: Raw" / "Response: Raw" (future-proofing for non-markdown formats).
|
|
15
|
+
- Active pane indicator simplified to subtle border color change (removed thick top accent bar).
|
|
16
|
+
- Panel shadows, button hierarchy (filled accent for primary actions), heading scale, blockquote/table styling improvements.
|
|
17
|
+
|
|
5
18
|
## [Unreleased]
|
|
6
19
|
|
|
7
20
|
### Added
|
|
@@ -25,6 +38,7 @@ All notable changes to `pi-studio` are documented here.
|
|
|
25
38
|
- Response-side markdown highlighting toggle (`Highlight markdown: Off|On`) in `Response: Markdown` view, with local preference persistence.
|
|
26
39
|
- Markdown highlighter now applies lightweight fenced-code token colors for common languages (`js/ts`, `python`, `bash/sh`, `json`).
|
|
27
40
|
- Obsidian wiki-image syntax normalization (`![[path]]`, `![[path|alt]]`) before pandoc preview rendering.
|
|
41
|
+
- Client-side Mermaid rendering for fenced `mermaid` code blocks in both Preview panes.
|
|
28
42
|
|
|
29
43
|
### Changed
|
|
30
44
|
- Removed Annotate/Critique tabs and related mode state.
|
|
@@ -38,6 +52,10 @@ All notable changes to `pi-studio` are documented here.
|
|
|
38
52
|
- Studio still live-updates latest response when assistant output arrives outside studio requests (e.g., manual send from pi editor).
|
|
39
53
|
- Preview pane typography/style now follows the higher-fidelity `/preview-browser` rendering style more closely.
|
|
40
54
|
- Preview mode now uses pandoc code highlighting output for syntax-colored code blocks.
|
|
55
|
+
- Preview markdown styling now maps markdown (`md*`) and syntax (`syntax*`) theme tokens for closer parity with terminal rendering.
|
|
56
|
+
- Theme surface mapping now uses theme-export backgrounds when available (`pageBg`, `cardBg`, `infoBg`) for clearer depth across `bg/panel/panel2`.
|
|
57
|
+
- Mermaid preview now uses palette-driven Mermaid defaults (base theme + theme variables) for better visual fit with active pi themes.
|
|
58
|
+
- Studio chrome was refined for a cleaner visual hierarchy (subtle panel shadows, primary action emphasis, lighter active-pane accent bar, softer heading scale, table striping, and tinted blockquotes).
|
|
41
59
|
- Hardened Studio preview HTTP handling and added client-side preview-request timeout to avoid stuck "Rendering preview…" states.
|
|
42
60
|
|
|
43
61
|
### Fixed
|
|
@@ -47,6 +65,7 @@ All notable changes to `pi-studio` are documented here.
|
|
|
47
65
|
- `respondText` now includes `X-Content-Type-Options: nosniff` for consistency with JSON responses.
|
|
48
66
|
- If `dompurify` is unavailable, preview now falls back to escaped plain markdown instead of injecting unsanitized HTML.
|
|
49
67
|
- Preview sanitization now preserves MathML profile and strips MathML annotation tags to avoid duplicate raw TeX text beside rendered equations.
|
|
68
|
+
- Preview now shows an inline warning when Mermaid is unavailable or diagram rendering fails, instead of failing silently.
|
|
50
69
|
|
|
51
70
|
### Changed
|
|
52
71
|
- Added npm metadata fields (`repository`, `homepage`, `bugs`) so npm package page links to GitHub.
|
package/README.md
CHANGED
|
@@ -33,8 +33,9 @@ Status: experimental alpha.
|
|
|
33
33
|
- critique: **Load critique (notes)** / **Load critique (full)**
|
|
34
34
|
- File actions: **Save As…**, **Save file**, **Load file in editor**
|
|
35
35
|
- View toggles: `Editor: Markdown|Preview`, `Response: Markdown|Preview`
|
|
36
|
+
- Preview mode supports MathML equations and Mermaid fenced diagrams
|
|
36
37
|
- Optional markdown highlighting toggles for editor and response markdown views (including fenced-code token colors for common languages)
|
|
37
|
-
- Theme-aware browser UI based on current pi theme
|
|
38
|
+
- Theme-aware browser UI based on current pi theme, with refined surface depth and lighter visual chrome
|
|
38
39
|
|
|
39
40
|
## Commands
|
|
40
41
|
|
|
@@ -75,6 +76,9 @@ pi -e https://github.com/omaclaren/pi-studio
|
|
|
75
76
|
- Pi Studio is currently optimized for markdown workflows (model responses, plans, and notes), including fenced code blocks. Pure code files are supported, but highlighting is tuned for markdown and fenced blocks rather than full-file language mode.
|
|
76
77
|
- Studio URLs include a token query parameter; avoid sharing full Studio URLs.
|
|
77
78
|
- Preview panes render markdown via `pandoc` (`gfm+tex_math_dollars` → HTML5 + MathML), including pandoc code syntax highlighting, sanitized in-browser with `dompurify`.
|
|
79
|
+
- Preview markdown/code colors are mapped from active theme markdown (`md*`) and syntax (`syntax*`) tokens for closer terminal-vs-browser parity.
|
|
80
|
+
- Mermaid fenced `mermaid` code blocks are rendered client-side in preview mode (Mermaid v11 loaded from jsDelivr), with palette-driven defaults for better theme fit.
|
|
81
|
+
- If Mermaid cannot load or a diagram fails to render, preview shows an inline warning and keeps source text visible.
|
|
78
82
|
- Preview rendering normalizes Obsidian wiki-image syntax (`![[path]]`, `![[path|alt]]`) into standard markdown images.
|
|
79
83
|
- Install pandoc for full preview rendering (`brew install pandoc` on macOS).
|
|
80
84
|
- If `pandoc` is unavailable, preview falls back to plain markdown text with an inline warning.
|
package/index.ts
CHANGED
|
@@ -112,6 +112,7 @@ interface StudioPalette {
|
|
|
112
112
|
panel: string;
|
|
113
113
|
panel2: string;
|
|
114
114
|
border: string;
|
|
115
|
+
borderMuted: string;
|
|
115
116
|
text: string;
|
|
116
117
|
muted: string;
|
|
117
118
|
accent: string;
|
|
@@ -124,6 +125,25 @@ interface StudioPalette {
|
|
|
124
125
|
accentSoftStrong: string;
|
|
125
126
|
okBorder: string;
|
|
126
127
|
warnBorder: string;
|
|
128
|
+
mdHeading: string;
|
|
129
|
+
mdLink: string;
|
|
130
|
+
mdLinkUrl: string;
|
|
131
|
+
mdCode: string;
|
|
132
|
+
mdCodeBlock: string;
|
|
133
|
+
mdCodeBlockBorder: string;
|
|
134
|
+
mdQuote: string;
|
|
135
|
+
mdQuoteBorder: string;
|
|
136
|
+
mdHr: string;
|
|
137
|
+
mdListBullet: string;
|
|
138
|
+
syntaxComment: string;
|
|
139
|
+
syntaxKeyword: string;
|
|
140
|
+
syntaxFunction: string;
|
|
141
|
+
syntaxVariable: string;
|
|
142
|
+
syntaxString: string;
|
|
143
|
+
syntaxNumber: string;
|
|
144
|
+
syntaxType: string;
|
|
145
|
+
syntaxOperator: string;
|
|
146
|
+
syntaxPunctuation: string;
|
|
127
147
|
}
|
|
128
148
|
|
|
129
149
|
interface StudioThemeStyle {
|
|
@@ -136,6 +156,7 @@ const DARK_STUDIO_PALETTE: StudioPalette = {
|
|
|
136
156
|
panel: "#171b24",
|
|
137
157
|
panel2: "#11161f",
|
|
138
158
|
border: "#2d3748",
|
|
159
|
+
borderMuted: "#242b38",
|
|
139
160
|
text: "#e6edf3",
|
|
140
161
|
muted: "#9aa5b1",
|
|
141
162
|
accent: "#5ea1ff",
|
|
@@ -148,6 +169,25 @@ const DARK_STUDIO_PALETTE: StudioPalette = {
|
|
|
148
169
|
accentSoftStrong: "rgba(94, 161, 255, 0.40)",
|
|
149
170
|
okBorder: "rgba(115, 209, 61, 0.70)",
|
|
150
171
|
warnBorder: "rgba(249, 199, 79, 0.70)",
|
|
172
|
+
mdHeading: "#f0c674",
|
|
173
|
+
mdLink: "#81a2be",
|
|
174
|
+
mdLinkUrl: "#666666",
|
|
175
|
+
mdCode: "#8abeb7",
|
|
176
|
+
mdCodeBlock: "#b5bd68",
|
|
177
|
+
mdCodeBlockBorder: "#808080",
|
|
178
|
+
mdQuote: "#808080",
|
|
179
|
+
mdQuoteBorder: "#808080",
|
|
180
|
+
mdHr: "#808080",
|
|
181
|
+
mdListBullet: "#8abeb7",
|
|
182
|
+
syntaxComment: "#6A9955",
|
|
183
|
+
syntaxKeyword: "#569CD6",
|
|
184
|
+
syntaxFunction: "#DCDCAA",
|
|
185
|
+
syntaxVariable: "#9CDCFE",
|
|
186
|
+
syntaxString: "#CE9178",
|
|
187
|
+
syntaxNumber: "#B5CEA8",
|
|
188
|
+
syntaxType: "#4EC9B0",
|
|
189
|
+
syntaxOperator: "#D4D4D4",
|
|
190
|
+
syntaxPunctuation: "#D4D4D4",
|
|
151
191
|
};
|
|
152
192
|
|
|
153
193
|
const LIGHT_STUDIO_PALETTE: StudioPalette = {
|
|
@@ -155,6 +195,7 @@ const LIGHT_STUDIO_PALETTE: StudioPalette = {
|
|
|
155
195
|
panel: "#ffffff",
|
|
156
196
|
panel2: "#f8fafc",
|
|
157
197
|
border: "#d0d7de",
|
|
198
|
+
borderMuted: "#e0e6ee",
|
|
158
199
|
text: "#1f2328",
|
|
159
200
|
muted: "#57606a",
|
|
160
201
|
accent: "#0969da",
|
|
@@ -167,6 +208,25 @@ const LIGHT_STUDIO_PALETTE: StudioPalette = {
|
|
|
167
208
|
accentSoftStrong: "rgba(9, 105, 218, 0.35)",
|
|
168
209
|
okBorder: "rgba(26, 127, 55, 0.55)",
|
|
169
210
|
warnBorder: "rgba(154, 103, 0, 0.55)",
|
|
211
|
+
mdHeading: "#9a7326",
|
|
212
|
+
mdLink: "#547da7",
|
|
213
|
+
mdLinkUrl: "#767676",
|
|
214
|
+
mdCode: "#5a8080",
|
|
215
|
+
mdCodeBlock: "#588458",
|
|
216
|
+
mdCodeBlockBorder: "#6c6c6c",
|
|
217
|
+
mdQuote: "#6c6c6c",
|
|
218
|
+
mdQuoteBorder: "#6c6c6c",
|
|
219
|
+
mdHr: "#6c6c6c",
|
|
220
|
+
mdListBullet: "#588458",
|
|
221
|
+
syntaxComment: "#008000",
|
|
222
|
+
syntaxKeyword: "#0000FF",
|
|
223
|
+
syntaxFunction: "#795E26",
|
|
224
|
+
syntaxVariable: "#001080",
|
|
225
|
+
syntaxString: "#A31515",
|
|
226
|
+
syntaxNumber: "#098658",
|
|
227
|
+
syntaxType: "#267F99",
|
|
228
|
+
syntaxOperator: "#000000",
|
|
229
|
+
syntaxPunctuation: "#000000",
|
|
170
230
|
};
|
|
171
231
|
|
|
172
232
|
function getStudioThemeMode(theme?: Theme): StudioThemeMode {
|
|
@@ -278,6 +338,127 @@ function withAlpha(color: string, alpha: number, fallback: string): string {
|
|
|
278
338
|
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${clamped.toFixed(2)})`;
|
|
279
339
|
}
|
|
280
340
|
|
|
341
|
+
function adjustBrightness(color: string, factor: number): string {
|
|
342
|
+
const rgb = hexToRgb(color);
|
|
343
|
+
if (!rgb) return color;
|
|
344
|
+
return rgbToHex(
|
|
345
|
+
Math.round(rgb.r * factor),
|
|
346
|
+
Math.round(rgb.g * factor),
|
|
347
|
+
Math.round(rgb.b * factor),
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function relativeLuminance(color: string): number {
|
|
352
|
+
const rgb = hexToRgb(color);
|
|
353
|
+
if (!rgb) return 0;
|
|
354
|
+
return (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) / 255;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function blendColors(a: string, b: string, t: number): string {
|
|
358
|
+
const rgbA = hexToRgb(a);
|
|
359
|
+
const rgbB = hexToRgb(b);
|
|
360
|
+
if (!rgbA || !rgbB) return a;
|
|
361
|
+
return rgbToHex(
|
|
362
|
+
Math.round(rgbA.r + (rgbB.r - rgbA.r) * t),
|
|
363
|
+
Math.round(rgbA.g + (rgbB.g - rgbA.g) * t),
|
|
364
|
+
Math.round(rgbA.b + (rgbB.b - rgbA.b) * t),
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function deriveCanvasColors(
|
|
369
|
+
baseColor: string,
|
|
370
|
+
mode: StudioThemeMode,
|
|
371
|
+
): { pageBg: string; cardBg: string; panel2: string } {
|
|
372
|
+
if (mode === "dark") {
|
|
373
|
+
const pageBg = adjustBrightness(baseColor, 0.50);
|
|
374
|
+
const cardBg = adjustBrightness(baseColor, 0.60);
|
|
375
|
+
return {
|
|
376
|
+
pageBg,
|
|
377
|
+
cardBg,
|
|
378
|
+
panel2: adjustBrightness(baseColor, 0.72),
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
const lum = relativeLuminance(baseColor);
|
|
382
|
+
const lighten = (c: string, amount: number): string => {
|
|
383
|
+
const rgb = hexToRgb(c);
|
|
384
|
+
if (!rgb) return c;
|
|
385
|
+
return rgbToHex(
|
|
386
|
+
Math.round(rgb.r + (255 - rgb.r) * amount),
|
|
387
|
+
Math.round(rgb.g + (255 - rgb.g) * amount),
|
|
388
|
+
Math.round(rgb.b + (255 - rgb.b) * amount),
|
|
389
|
+
);
|
|
390
|
+
};
|
|
391
|
+
if (lum > 0.92) {
|
|
392
|
+
return { pageBg: baseColor, cardBg: "#ffffff", panel2: lighten(baseColor, 0.3) };
|
|
393
|
+
}
|
|
394
|
+
return {
|
|
395
|
+
pageBg: lighten(baseColor, 0.6),
|
|
396
|
+
cardBg: lighten(baseColor, 0.93),
|
|
397
|
+
panel2: lighten(baseColor, 0.45),
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
interface ThemeExportPalette {
|
|
402
|
+
pageBg?: string;
|
|
403
|
+
cardBg?: string;
|
|
404
|
+
infoBg?: string;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const themeExportPaletteCache = new Map<string, ThemeExportPalette | null>();
|
|
408
|
+
|
|
409
|
+
function resolveThemeExportValue(
|
|
410
|
+
value: string | number | undefined,
|
|
411
|
+
vars: Record<string, string | number>,
|
|
412
|
+
seen: Set<string> = new Set(),
|
|
413
|
+
): string | undefined {
|
|
414
|
+
if (value == null) return undefined;
|
|
415
|
+
if (typeof value === "number") return xterm256ToHex(value);
|
|
416
|
+
|
|
417
|
+
const token = value.trim();
|
|
418
|
+
if (!token) return undefined;
|
|
419
|
+
if (token.startsWith("#")) return token;
|
|
420
|
+
|
|
421
|
+
const varKey = token.startsWith("$") ? token.slice(1) : token;
|
|
422
|
+
if (!varKey || seen.has(varKey)) return token;
|
|
423
|
+
|
|
424
|
+
const referenced = vars[varKey];
|
|
425
|
+
if (referenced == null) return token;
|
|
426
|
+
|
|
427
|
+
seen.add(varKey);
|
|
428
|
+
return resolveThemeExportValue(referenced, vars, seen) ?? token;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function readThemeExportPalette(theme?: Theme): ThemeExportPalette | undefined {
|
|
432
|
+
const sourcePath = theme?.sourcePath?.trim();
|
|
433
|
+
if (!sourcePath) return undefined;
|
|
434
|
+
|
|
435
|
+
if (themeExportPaletteCache.has(sourcePath)) {
|
|
436
|
+
const cached = themeExportPaletteCache.get(sourcePath);
|
|
437
|
+
return cached ?? undefined;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
try {
|
|
441
|
+
const raw = readFileSync(sourcePath, "utf-8");
|
|
442
|
+
const parsed = JSON.parse(raw) as {
|
|
443
|
+
export?: { pageBg?: string | number; cardBg?: string | number; infoBg?: string | number };
|
|
444
|
+
vars?: Record<string, string | number>;
|
|
445
|
+
};
|
|
446
|
+
const vars = parsed.vars ?? {};
|
|
447
|
+
const exportSection = parsed.export ?? {};
|
|
448
|
+
const resolved: ThemeExportPalette = {
|
|
449
|
+
pageBg: resolveThemeExportValue(exportSection.pageBg, vars),
|
|
450
|
+
cardBg: resolveThemeExportValue(exportSection.cardBg, vars),
|
|
451
|
+
infoBg: resolveThemeExportValue(exportSection.infoBg, vars),
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
themeExportPaletteCache.set(sourcePath, resolved);
|
|
455
|
+
return resolved;
|
|
456
|
+
} catch {
|
|
457
|
+
themeExportPaletteCache.set(sourcePath, null);
|
|
458
|
+
return undefined;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
281
462
|
function getStudioThemeStyle(theme?: Theme): StudioThemeStyle {
|
|
282
463
|
const mode = getStudioThemeMode(theme);
|
|
283
464
|
const fallback = mode === "light" ? LIGHT_STUDIO_PALETTE : DARK_STUDIO_PALETTE;
|
|
@@ -296,12 +477,30 @@ function getStudioThemeStyle(theme?: Theme): StudioThemeStyle {
|
|
|
296
477
|
const warn = safeThemeColor(() => theme.getFgAnsi("warning")) ?? fallback.warn;
|
|
297
478
|
const error = safeThemeColor(() => theme.getFgAnsi("error")) ?? fallback.error;
|
|
298
479
|
const ok = safeThemeColor(() => theme.getFgAnsi("success")) ?? fallback.ok;
|
|
480
|
+
const exported = readThemeExportPalette(theme);
|
|
481
|
+
|
|
482
|
+
const surfaceBase =
|
|
483
|
+
safeThemeColor(() => theme.getBgAnsi("userMessageBg"))
|
|
484
|
+
?? safeThemeColor(() => theme.getBgAnsi("customMessageBg"));
|
|
485
|
+
const derived = surfaceBase ? deriveCanvasColors(surfaceBase, mode) : undefined;
|
|
299
486
|
|
|
300
487
|
const palette: StudioPalette = {
|
|
301
|
-
bg:
|
|
302
|
-
|
|
303
|
-
|
|
488
|
+
bg:
|
|
489
|
+
exported?.pageBg
|
|
490
|
+
?? derived?.pageBg
|
|
491
|
+
?? fallback.bg,
|
|
492
|
+
panel:
|
|
493
|
+
exported?.cardBg
|
|
494
|
+
?? derived?.cardBg
|
|
495
|
+
?? safeThemeColor(() => theme.getBgAnsi("toolPendingBg"))
|
|
496
|
+
?? fallback.panel,
|
|
497
|
+
panel2:
|
|
498
|
+
derived?.panel2
|
|
499
|
+
?? safeThemeColor(() => theme.getBgAnsi("selectedBg"))
|
|
500
|
+
?? exported?.infoBg
|
|
501
|
+
?? fallback.panel2,
|
|
304
502
|
border: safeThemeColor(() => theme.getFgAnsi("border")) ?? fallback.border,
|
|
503
|
+
borderMuted: safeThemeColor(() => theme.getFgAnsi("borderMuted")) ?? fallback.borderMuted,
|
|
305
504
|
text: safeThemeColor(() => theme.getFgAnsi("text")) ?? fallback.text,
|
|
306
505
|
muted: safeThemeColor(() => theme.getFgAnsi("muted")) ?? fallback.muted,
|
|
307
506
|
accent,
|
|
@@ -314,6 +513,25 @@ function getStudioThemeStyle(theme?: Theme): StudioThemeStyle {
|
|
|
314
513
|
accentSoftStrong: withAlpha(accent, mode === "light" ? 0.35 : 0.40, fallback.accentSoftStrong),
|
|
315
514
|
okBorder: withAlpha(ok, mode === "light" ? 0.55 : 0.70, fallback.okBorder),
|
|
316
515
|
warnBorder: withAlpha(warn, mode === "light" ? 0.55 : 0.70, fallback.warnBorder),
|
|
516
|
+
mdHeading: safeThemeColor(() => theme.getFgAnsi("mdHeading")) ?? fallback.mdHeading,
|
|
517
|
+
mdLink: safeThemeColor(() => theme.getFgAnsi("mdLink")) ?? fallback.mdLink,
|
|
518
|
+
mdLinkUrl: safeThemeColor(() => theme.getFgAnsi("mdLinkUrl")) ?? fallback.mdLinkUrl,
|
|
519
|
+
mdCode: safeThemeColor(() => theme.getFgAnsi("mdCode")) ?? fallback.mdCode,
|
|
520
|
+
mdCodeBlock: safeThemeColor(() => theme.getFgAnsi("mdCodeBlock")) ?? fallback.mdCodeBlock,
|
|
521
|
+
mdCodeBlockBorder: safeThemeColor(() => theme.getFgAnsi("mdCodeBlockBorder")) ?? fallback.mdCodeBlockBorder,
|
|
522
|
+
mdQuote: safeThemeColor(() => theme.getFgAnsi("mdQuote")) ?? fallback.mdQuote,
|
|
523
|
+
mdQuoteBorder: safeThemeColor(() => theme.getFgAnsi("mdQuoteBorder")) ?? fallback.mdQuoteBorder,
|
|
524
|
+
mdHr: safeThemeColor(() => theme.getFgAnsi("mdHr")) ?? fallback.mdHr,
|
|
525
|
+
mdListBullet: safeThemeColor(() => theme.getFgAnsi("mdListBullet")) ?? fallback.mdListBullet,
|
|
526
|
+
syntaxComment: safeThemeColor(() => theme.getFgAnsi("syntaxComment")) ?? fallback.syntaxComment,
|
|
527
|
+
syntaxKeyword: safeThemeColor(() => theme.getFgAnsi("syntaxKeyword")) ?? fallback.syntaxKeyword,
|
|
528
|
+
syntaxFunction: safeThemeColor(() => theme.getFgAnsi("syntaxFunction")) ?? fallback.syntaxFunction,
|
|
529
|
+
syntaxVariable: safeThemeColor(() => theme.getFgAnsi("syntaxVariable")) ?? fallback.syntaxVariable,
|
|
530
|
+
syntaxString: safeThemeColor(() => theme.getFgAnsi("syntaxString")) ?? fallback.syntaxString,
|
|
531
|
+
syntaxNumber: safeThemeColor(() => theme.getFgAnsi("syntaxNumber")) ?? fallback.syntaxNumber,
|
|
532
|
+
syntaxType: safeThemeColor(() => theme.getFgAnsi("syntaxType")) ?? fallback.syntaxType,
|
|
533
|
+
syntaxOperator: safeThemeColor(() => theme.getFgAnsi("syntaxOperator")) ?? fallback.syntaxOperator,
|
|
534
|
+
syntaxPunctuation: safeThemeColor(() => theme.getFgAnsi("syntaxPunctuation")) ?? fallback.syntaxPunctuation,
|
|
317
535
|
};
|
|
318
536
|
|
|
319
537
|
return { mode, palette };
|
|
@@ -912,6 +1130,51 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
912
1130
|
const initialLabel = escapeHtmlForInline(initialDocument?.label ?? "blank");
|
|
913
1131
|
const initialPath = escapeHtmlForInline(initialDocument?.path ?? "");
|
|
914
1132
|
const style = getStudioThemeStyle(theme);
|
|
1133
|
+
const mermaidConfig = {
|
|
1134
|
+
startOnLoad: false,
|
|
1135
|
+
theme: "base",
|
|
1136
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace",
|
|
1137
|
+
flowchart: {
|
|
1138
|
+
curve: "basis",
|
|
1139
|
+
},
|
|
1140
|
+
themeVariables: {
|
|
1141
|
+
background: style.palette.bg,
|
|
1142
|
+
primaryColor: style.palette.panel2,
|
|
1143
|
+
primaryTextColor: style.palette.text,
|
|
1144
|
+
primaryBorderColor: style.palette.mdCodeBlockBorder,
|
|
1145
|
+
secondaryColor: style.palette.panel,
|
|
1146
|
+
secondaryTextColor: style.palette.text,
|
|
1147
|
+
secondaryBorderColor: style.palette.mdCodeBlockBorder,
|
|
1148
|
+
tertiaryColor: style.palette.panel,
|
|
1149
|
+
tertiaryTextColor: style.palette.text,
|
|
1150
|
+
tertiaryBorderColor: style.palette.mdCodeBlockBorder,
|
|
1151
|
+
lineColor: style.palette.mdQuote,
|
|
1152
|
+
textColor: style.palette.text,
|
|
1153
|
+
edgeLabelBackground: style.palette.panel2,
|
|
1154
|
+
nodeBorder: style.palette.mdCodeBlockBorder,
|
|
1155
|
+
clusterBkg: style.palette.panel,
|
|
1156
|
+
clusterBorder: style.palette.mdCodeBlockBorder,
|
|
1157
|
+
titleColor: style.palette.mdHeading,
|
|
1158
|
+
},
|
|
1159
|
+
};
|
|
1160
|
+
const panelShadow =
|
|
1161
|
+
style.mode === "light"
|
|
1162
|
+
? "0 1px 2px rgba(15, 23, 42, 0.03), 0 4px 14px rgba(15, 23, 42, 0.04)"
|
|
1163
|
+
: "0 1px 2px rgba(0, 0, 0, 0.36), 0 6px 18px rgba(0, 0, 0, 0.22)";
|
|
1164
|
+
const accentContrast = style.mode === "light" ? "#ffffff" : "#0e1616";
|
|
1165
|
+
const blockquoteBg = withAlpha(
|
|
1166
|
+
style.palette.mdQuoteBorder,
|
|
1167
|
+
style.mode === "light" ? 0.10 : 0.16,
|
|
1168
|
+
style.mode === "light" ? "rgba(15, 23, 42, 0.04)" : "rgba(255, 255, 255, 0.05)",
|
|
1169
|
+
);
|
|
1170
|
+
const tableAltBg = withAlpha(
|
|
1171
|
+
style.palette.mdCodeBlockBorder,
|
|
1172
|
+
style.mode === "light" ? 0.10 : 0.14,
|
|
1173
|
+
style.mode === "light" ? "rgba(15, 23, 42, 0.03)" : "rgba(255, 255, 255, 0.04)",
|
|
1174
|
+
);
|
|
1175
|
+
const editorBg = style.mode === "light"
|
|
1176
|
+
? blendColors(style.palette.panel, "#ffffff", 0.5)
|
|
1177
|
+
: style.palette.panel;
|
|
915
1178
|
|
|
916
1179
|
return `<!doctype html>
|
|
917
1180
|
<html>
|
|
@@ -926,6 +1189,7 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
926
1189
|
--panel: ${style.palette.panel};
|
|
927
1190
|
--panel-2: ${style.palette.panel2};
|
|
928
1191
|
--border: ${style.palette.border};
|
|
1192
|
+
--border-muted: ${style.palette.borderMuted};
|
|
929
1193
|
--text: ${style.palette.text};
|
|
930
1194
|
--muted: ${style.palette.muted};
|
|
931
1195
|
--accent: ${style.palette.accent};
|
|
@@ -938,6 +1202,30 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
938
1202
|
--accent-soft-strong: ${style.palette.accentSoftStrong};
|
|
939
1203
|
--ok-border: ${style.palette.okBorder};
|
|
940
1204
|
--warn-border: ${style.palette.warnBorder};
|
|
1205
|
+
--md-heading: ${style.palette.mdHeading};
|
|
1206
|
+
--md-link: ${style.palette.mdLink};
|
|
1207
|
+
--md-link-url: ${style.palette.mdLinkUrl};
|
|
1208
|
+
--md-code: ${style.palette.mdCode};
|
|
1209
|
+
--md-codeblock: ${style.palette.mdCodeBlock};
|
|
1210
|
+
--md-codeblock-border: ${style.palette.mdCodeBlockBorder};
|
|
1211
|
+
--md-quote: ${style.palette.mdQuote};
|
|
1212
|
+
--md-quote-border: ${style.palette.mdQuoteBorder};
|
|
1213
|
+
--md-hr: ${style.palette.mdHr};
|
|
1214
|
+
--md-list-bullet: ${style.palette.mdListBullet};
|
|
1215
|
+
--syntax-comment: ${style.palette.syntaxComment};
|
|
1216
|
+
--syntax-keyword: ${style.palette.syntaxKeyword};
|
|
1217
|
+
--syntax-function: ${style.palette.syntaxFunction};
|
|
1218
|
+
--syntax-variable: ${style.palette.syntaxVariable};
|
|
1219
|
+
--syntax-string: ${style.palette.syntaxString};
|
|
1220
|
+
--syntax-number: ${style.palette.syntaxNumber};
|
|
1221
|
+
--syntax-type: ${style.palette.syntaxType};
|
|
1222
|
+
--syntax-operator: ${style.palette.syntaxOperator};
|
|
1223
|
+
--syntax-punctuation: ${style.palette.syntaxPunctuation};
|
|
1224
|
+
--panel-shadow: ${panelShadow};
|
|
1225
|
+
--accent-contrast: ${accentContrast};
|
|
1226
|
+
--blockquote-bg: ${blockquoteBg};
|
|
1227
|
+
--table-alt-bg: ${tableAltBg};
|
|
1228
|
+
--editor-bg: ${editorBg};
|
|
941
1229
|
}
|
|
942
1230
|
|
|
943
1231
|
* { box-sizing: border-box; }
|
|
@@ -956,7 +1244,7 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
956
1244
|
}
|
|
957
1245
|
|
|
958
1246
|
header {
|
|
959
|
-
border-bottom: 1px solid var(--border);
|
|
1247
|
+
border-bottom: 1px solid var(--border-muted);
|
|
960
1248
|
padding: 12px 16px;
|
|
961
1249
|
background: var(--panel);
|
|
962
1250
|
display: flex;
|
|
@@ -997,23 +1285,50 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
997
1285
|
}
|
|
998
1286
|
|
|
999
1287
|
button, select, .file-label {
|
|
1000
|
-
border: 1px solid var(--border);
|
|
1001
|
-
background: var(--panel
|
|
1288
|
+
border: 1px solid var(--border-muted);
|
|
1289
|
+
background: var(--panel);
|
|
1002
1290
|
color: var(--text);
|
|
1003
1291
|
border-radius: 8px;
|
|
1004
1292
|
padding: 8px 10px;
|
|
1005
1293
|
font-size: 13px;
|
|
1294
|
+
transition: background-color 120ms ease, border-color 120ms ease;
|
|
1006
1295
|
}
|
|
1007
1296
|
|
|
1008
1297
|
button {
|
|
1009
1298
|
cursor: pointer;
|
|
1010
1299
|
}
|
|
1011
1300
|
|
|
1301
|
+
button:not(:disabled):hover,
|
|
1302
|
+
select:hover,
|
|
1303
|
+
.file-label:hover {
|
|
1304
|
+
background: var(--panel-2);
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
button:focus-visible,
|
|
1308
|
+
select:focus-visible,
|
|
1309
|
+
.file-label:focus-within {
|
|
1310
|
+
outline: 2px solid var(--accent-soft-strong);
|
|
1311
|
+
outline-offset: 1px;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1012
1314
|
button:disabled {
|
|
1013
1315
|
opacity: 0.6;
|
|
1014
1316
|
cursor: not-allowed;
|
|
1015
1317
|
}
|
|
1016
1318
|
|
|
1319
|
+
#sendRunBtn,
|
|
1320
|
+
#loadResponseBtn:not(:disabled):not([hidden]) {
|
|
1321
|
+
background: var(--accent);
|
|
1322
|
+
border-color: var(--accent);
|
|
1323
|
+
color: var(--accent-contrast);
|
|
1324
|
+
font-weight: 600;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
#sendRunBtn:not(:disabled):hover,
|
|
1328
|
+
#loadResponseBtn:not(:disabled):not([hidden]):hover {
|
|
1329
|
+
filter: brightness(0.95);
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1017
1332
|
.file-label {
|
|
1018
1333
|
cursor: pointer;
|
|
1019
1334
|
display: inline-flex;
|
|
@@ -1035,18 +1350,18 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1035
1350
|
}
|
|
1036
1351
|
|
|
1037
1352
|
section {
|
|
1038
|
-
border: 1px solid var(--border);
|
|
1353
|
+
border: 1px solid var(--border-muted);
|
|
1039
1354
|
border-radius: 10px;
|
|
1040
1355
|
background: var(--panel);
|
|
1041
1356
|
min-height: 0;
|
|
1042
1357
|
display: flex;
|
|
1043
1358
|
flex-direction: column;
|
|
1044
1359
|
overflow: hidden;
|
|
1360
|
+
box-shadow: var(--panel-shadow);
|
|
1045
1361
|
}
|
|
1046
1362
|
|
|
1047
1363
|
section.pane-active {
|
|
1048
|
-
border-color: var(--
|
|
1049
|
-
box-shadow: inset 0 0 0 1px var(--accent-soft);
|
|
1364
|
+
border-color: var(--border);
|
|
1050
1365
|
}
|
|
1051
1366
|
|
|
1052
1367
|
body.pane-focus-left main,
|
|
@@ -1061,28 +1376,28 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1061
1376
|
|
|
1062
1377
|
body.pane-focus-left #leftPane,
|
|
1063
1378
|
body.pane-focus-right #rightPane {
|
|
1064
|
-
border-color: var(--
|
|
1065
|
-
box-shadow: inset 0 0 0 1px var(--accent-soft-strong);
|
|
1379
|
+
border-color: var(--border);
|
|
1066
1380
|
}
|
|
1067
1381
|
|
|
1068
1382
|
.section-header {
|
|
1069
1383
|
padding: 10px 12px;
|
|
1070
|
-
border-bottom: 1px solid var(--border);
|
|
1384
|
+
border-bottom: 1px solid var(--border-muted);
|
|
1385
|
+
background: var(--panel-2);
|
|
1071
1386
|
font-weight: 600;
|
|
1072
1387
|
font-size: 14px;
|
|
1073
1388
|
}
|
|
1074
1389
|
|
|
1075
1390
|
.reference-meta {
|
|
1076
1391
|
padding: 8px 10px;
|
|
1077
|
-
border-bottom: 1px solid var(--border);
|
|
1078
|
-
background: var(--panel);
|
|
1392
|
+
border-bottom: 1px solid var(--border-muted);
|
|
1393
|
+
background: var(--panel-2);
|
|
1079
1394
|
}
|
|
1080
1395
|
|
|
1081
1396
|
textarea {
|
|
1082
1397
|
width: 100%;
|
|
1083
|
-
border: 1px solid var(--border);
|
|
1398
|
+
border: 1px solid var(--border-muted);
|
|
1084
1399
|
border-radius: 8px;
|
|
1085
|
-
background: var(--panel
|
|
1400
|
+
background: var(--panel);
|
|
1086
1401
|
color: var(--text);
|
|
1087
1402
|
padding: 10px;
|
|
1088
1403
|
font-size: 13px;
|
|
@@ -1093,7 +1408,7 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1093
1408
|
|
|
1094
1409
|
.source-wrap {
|
|
1095
1410
|
padding: 10px;
|
|
1096
|
-
border-bottom: 1px solid var(--border);
|
|
1411
|
+
border-bottom: 1px solid var(--border-muted);
|
|
1097
1412
|
display: flex;
|
|
1098
1413
|
flex-direction: column;
|
|
1099
1414
|
gap: 8px;
|
|
@@ -1117,8 +1432,8 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1117
1432
|
}
|
|
1118
1433
|
|
|
1119
1434
|
.source-badge {
|
|
1120
|
-
border: 1px solid var(--border);
|
|
1121
|
-
background: var(--panel
|
|
1435
|
+
border: 1px solid var(--border-muted);
|
|
1436
|
+
background: var(--panel);
|
|
1122
1437
|
border-radius: 999px;
|
|
1123
1438
|
padding: 4px 10px;
|
|
1124
1439
|
font-size: 12px;
|
|
@@ -1155,9 +1470,9 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1155
1470
|
flex: 1 1 auto;
|
|
1156
1471
|
min-height: 0;
|
|
1157
1472
|
max-height: none;
|
|
1158
|
-
border: 1px solid var(--border);
|
|
1473
|
+
border: 1px solid var(--border-muted);
|
|
1159
1474
|
border-radius: 8px;
|
|
1160
|
-
background: var(--
|
|
1475
|
+
background: var(--editor-bg);
|
|
1161
1476
|
overflow: hidden;
|
|
1162
1477
|
}
|
|
1163
1478
|
|
|
@@ -1189,6 +1504,7 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1189
1504
|
border-radius: 0;
|
|
1190
1505
|
background: transparent;
|
|
1191
1506
|
resize: none;
|
|
1507
|
+
outline: none;
|
|
1192
1508
|
}
|
|
1193
1509
|
|
|
1194
1510
|
#sourceText.highlight-active {
|
|
@@ -1205,7 +1521,7 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1205
1521
|
}
|
|
1206
1522
|
|
|
1207
1523
|
.hl-heading {
|
|
1208
|
-
color: var(--
|
|
1524
|
+
color: var(--md-heading);
|
|
1209
1525
|
font-weight: 700;
|
|
1210
1526
|
}
|
|
1211
1527
|
|
|
@@ -1214,58 +1530,58 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1214
1530
|
}
|
|
1215
1531
|
|
|
1216
1532
|
.hl-code {
|
|
1217
|
-
color: var(--
|
|
1533
|
+
color: var(--md-code);
|
|
1218
1534
|
}
|
|
1219
1535
|
|
|
1220
1536
|
.hl-code-kw {
|
|
1221
|
-
color: var(--
|
|
1537
|
+
color: var(--syntax-keyword);
|
|
1222
1538
|
font-weight: 600;
|
|
1223
1539
|
}
|
|
1224
1540
|
|
|
1225
1541
|
.hl-code-str {
|
|
1226
|
-
color: var(--
|
|
1542
|
+
color: var(--syntax-string);
|
|
1227
1543
|
}
|
|
1228
1544
|
|
|
1229
1545
|
.hl-code-num {
|
|
1230
|
-
color: var(--
|
|
1546
|
+
color: var(--syntax-number);
|
|
1231
1547
|
}
|
|
1232
1548
|
|
|
1233
1549
|
.hl-code-com {
|
|
1234
|
-
color: var(--
|
|
1550
|
+
color: var(--syntax-comment);
|
|
1235
1551
|
font-style: italic;
|
|
1236
1552
|
}
|
|
1237
1553
|
|
|
1238
1554
|
.hl-code-var,
|
|
1239
1555
|
.hl-code-key {
|
|
1240
|
-
color: var(--
|
|
1556
|
+
color: var(--syntax-variable);
|
|
1241
1557
|
}
|
|
1242
1558
|
|
|
1243
1559
|
.hl-list {
|
|
1244
|
-
color: var(--
|
|
1560
|
+
color: var(--md-list-bullet);
|
|
1245
1561
|
font-weight: 600;
|
|
1246
1562
|
}
|
|
1247
1563
|
|
|
1248
1564
|
.hl-quote {
|
|
1249
|
-
color: var(--
|
|
1565
|
+
color: var(--md-quote);
|
|
1250
1566
|
font-style: italic;
|
|
1251
1567
|
}
|
|
1252
1568
|
|
|
1253
1569
|
.hl-link {
|
|
1254
|
-
color: var(--
|
|
1570
|
+
color: var(--md-link);
|
|
1255
1571
|
text-decoration: underline;
|
|
1256
1572
|
}
|
|
1257
1573
|
|
|
1258
1574
|
.hl-url {
|
|
1259
|
-
color: var(--
|
|
1575
|
+
color: var(--md-link-url);
|
|
1260
1576
|
}
|
|
1261
1577
|
|
|
1262
1578
|
#sourcePreview {
|
|
1263
1579
|
flex: 1 1 auto;
|
|
1264
1580
|
min-height: 0;
|
|
1265
1581
|
max-height: none;
|
|
1266
|
-
border: 1px solid var(--border);
|
|
1582
|
+
border: 1px solid var(--border-muted);
|
|
1267
1583
|
border-radius: 8px;
|
|
1268
|
-
background: var(--panel
|
|
1584
|
+
background: var(--panel);
|
|
1269
1585
|
}
|
|
1270
1586
|
|
|
1271
1587
|
.panel-scroll {
|
|
@@ -1291,18 +1607,20 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1291
1607
|
margin-top: 1.2em;
|
|
1292
1608
|
margin-bottom: 0.5em;
|
|
1293
1609
|
line-height: 1.25;
|
|
1610
|
+
letter-spacing: -0.01em;
|
|
1611
|
+
color: var(--md-heading);
|
|
1294
1612
|
}
|
|
1295
1613
|
|
|
1296
1614
|
.rendered-markdown h1 {
|
|
1297
|
-
font-size:
|
|
1298
|
-
border-bottom:
|
|
1299
|
-
padding-bottom: 0
|
|
1615
|
+
font-size: 1.6em;
|
|
1616
|
+
border-bottom: 0;
|
|
1617
|
+
padding-bottom: 0;
|
|
1300
1618
|
}
|
|
1301
1619
|
|
|
1302
1620
|
.rendered-markdown h2 {
|
|
1303
|
-
font-size: 1.
|
|
1304
|
-
border-bottom:
|
|
1305
|
-
padding-bottom: 0
|
|
1621
|
+
font-size: 1.25em;
|
|
1622
|
+
border-bottom: 0;
|
|
1623
|
+
padding-bottom: 0;
|
|
1306
1624
|
}
|
|
1307
1625
|
|
|
1308
1626
|
.rendered-markdown p,
|
|
@@ -1314,8 +1632,12 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1314
1632
|
margin-bottom: 1em;
|
|
1315
1633
|
}
|
|
1316
1634
|
|
|
1635
|
+
.rendered-markdown li::marker {
|
|
1636
|
+
color: var(--md-list-bullet);
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1317
1639
|
.rendered-markdown a {
|
|
1318
|
-
color: var(--
|
|
1640
|
+
color: var(--md-link);
|
|
1319
1641
|
text-decoration: none;
|
|
1320
1642
|
}
|
|
1321
1643
|
|
|
@@ -1323,16 +1645,23 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1323
1645
|
text-decoration: underline;
|
|
1324
1646
|
}
|
|
1325
1647
|
|
|
1648
|
+
.rendered-markdown a.uri,
|
|
1649
|
+
.rendered-markdown .uri {
|
|
1650
|
+
color: var(--md-link-url);
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1326
1653
|
.rendered-markdown blockquote {
|
|
1327
1654
|
margin-left: 0;
|
|
1328
|
-
padding: 0 1em;
|
|
1329
|
-
border-left: 0.25em solid var(--border);
|
|
1330
|
-
|
|
1655
|
+
padding: 0.2em 1em;
|
|
1656
|
+
border-left: 0.25em solid var(--md-quote-border);
|
|
1657
|
+
border-radius: 0 8px 8px 0;
|
|
1658
|
+
background: var(--blockquote-bg);
|
|
1659
|
+
color: var(--md-quote);
|
|
1331
1660
|
}
|
|
1332
1661
|
|
|
1333
1662
|
.rendered-markdown pre {
|
|
1334
|
-
background: var(--panel);
|
|
1335
|
-
border: 1px solid var(--border);
|
|
1663
|
+
background: var(--panel-2);
|
|
1664
|
+
border: 1px solid var(--md-codeblock-border);
|
|
1336
1665
|
border-radius: 8px;
|
|
1337
1666
|
padding: 12px 14px;
|
|
1338
1667
|
overflow: auto;
|
|
@@ -1343,49 +1672,67 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1343
1672
|
.rendered-markdown code {
|
|
1344
1673
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
1345
1674
|
font-size: 0.9em;
|
|
1675
|
+
color: var(--md-code);
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
.rendered-markdown pre code {
|
|
1679
|
+
color: var(--md-codeblock);
|
|
1346
1680
|
}
|
|
1347
1681
|
|
|
1348
1682
|
.rendered-markdown :not(pre) > code {
|
|
1349
|
-
background: rgba(127, 127, 127, 0.
|
|
1350
|
-
border: 1px solid var(--border);
|
|
1683
|
+
background: rgba(127, 127, 127, 0.13);
|
|
1684
|
+
border: 1px solid var(--md-codeblock-border);
|
|
1351
1685
|
border-radius: 6px;
|
|
1352
1686
|
padding: 0.12em 0.35em;
|
|
1353
1687
|
}
|
|
1354
1688
|
|
|
1355
1689
|
.rendered-markdown code span.kw,
|
|
1356
1690
|
.rendered-markdown code span.cf,
|
|
1357
|
-
.rendered-markdown code span.im
|
|
1691
|
+
.rendered-markdown code span.im {
|
|
1692
|
+
color: var(--syntax-keyword);
|
|
1693
|
+
font-weight: 600;
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1358
1696
|
.rendered-markdown code span.dt {
|
|
1359
|
-
color: var(--
|
|
1697
|
+
color: var(--syntax-type);
|
|
1360
1698
|
font-weight: 600;
|
|
1361
1699
|
}
|
|
1362
1700
|
|
|
1363
1701
|
.rendered-markdown code span.fu,
|
|
1364
|
-
.rendered-markdown code span.bu
|
|
1702
|
+
.rendered-markdown code span.bu {
|
|
1703
|
+
color: var(--syntax-function);
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1365
1706
|
.rendered-markdown code span.va,
|
|
1366
1707
|
.rendered-markdown code span.ot {
|
|
1367
|
-
color: var(--
|
|
1708
|
+
color: var(--syntax-variable);
|
|
1368
1709
|
}
|
|
1369
1710
|
|
|
1370
1711
|
.rendered-markdown code span.st,
|
|
1371
1712
|
.rendered-markdown code span.ss,
|
|
1372
|
-
.rendered-markdown code span.sc
|
|
1373
|
-
|
|
1713
|
+
.rendered-markdown code span.sc,
|
|
1714
|
+
.rendered-markdown code span.ch {
|
|
1715
|
+
color: var(--syntax-string);
|
|
1374
1716
|
}
|
|
1375
1717
|
|
|
1376
1718
|
.rendered-markdown code span.dv,
|
|
1377
1719
|
.rendered-markdown code span.bn,
|
|
1378
1720
|
.rendered-markdown code span.fl {
|
|
1379
|
-
color: var(--
|
|
1721
|
+
color: var(--syntax-number);
|
|
1380
1722
|
}
|
|
1381
1723
|
|
|
1382
1724
|
.rendered-markdown code span.co {
|
|
1383
|
-
color: var(--
|
|
1725
|
+
color: var(--syntax-comment);
|
|
1384
1726
|
font-style: italic;
|
|
1385
1727
|
}
|
|
1386
1728
|
|
|
1387
1729
|
.rendered-markdown code span.op {
|
|
1388
|
-
color: var(--
|
|
1730
|
+
color: var(--syntax-operator);
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
.rendered-markdown code span.pp,
|
|
1734
|
+
.rendered-markdown code span.pu {
|
|
1735
|
+
color: var(--syntax-punctuation);
|
|
1389
1736
|
}
|
|
1390
1737
|
|
|
1391
1738
|
.rendered-markdown code span.er,
|
|
@@ -1403,13 +1750,21 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1403
1750
|
|
|
1404
1751
|
.rendered-markdown th,
|
|
1405
1752
|
.rendered-markdown td {
|
|
1406
|
-
border: 1px solid var(--border);
|
|
1753
|
+
border: 1px solid var(--border-muted);
|
|
1407
1754
|
padding: 6px 12px;
|
|
1408
1755
|
}
|
|
1409
1756
|
|
|
1757
|
+
.rendered-markdown thead th {
|
|
1758
|
+
background: var(--panel-2);
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
.rendered-markdown tbody tr:nth-child(even) {
|
|
1762
|
+
background: var(--table-alt-bg);
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1410
1765
|
.rendered-markdown hr {
|
|
1411
1766
|
border: 0;
|
|
1412
|
-
border-top: 1px solid var(--
|
|
1767
|
+
border-top: 1px solid var(--md-hr);
|
|
1413
1768
|
margin: 1.25em 0;
|
|
1414
1769
|
}
|
|
1415
1770
|
|
|
@@ -1424,6 +1779,17 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1424
1779
|
overflow-y: hidden;
|
|
1425
1780
|
}
|
|
1426
1781
|
|
|
1782
|
+
.rendered-markdown .mermaid-container {
|
|
1783
|
+
text-align: center;
|
|
1784
|
+
margin: 1em 0;
|
|
1785
|
+
overflow-x: auto;
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
.rendered-markdown .mermaid-container svg {
|
|
1789
|
+
max-width: 100%;
|
|
1790
|
+
height: auto;
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1427
1793
|
.plain-markdown {
|
|
1428
1794
|
margin: 0;
|
|
1429
1795
|
white-space: pre-wrap;
|
|
@@ -1453,6 +1819,13 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1453
1819
|
font-size: 12px;
|
|
1454
1820
|
}
|
|
1455
1821
|
|
|
1822
|
+
.preview-warning {
|
|
1823
|
+
color: var(--warn);
|
|
1824
|
+
margin-top: 0.75em;
|
|
1825
|
+
font-size: 12px;
|
|
1826
|
+
font-style: italic;
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1456
1829
|
.marker {
|
|
1457
1830
|
display: inline-block;
|
|
1458
1831
|
padding: 0 4px;
|
|
@@ -1478,7 +1851,7 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1478
1851
|
}
|
|
1479
1852
|
|
|
1480
1853
|
.response-wrap {
|
|
1481
|
-
border-top: 1px solid var(--border);
|
|
1854
|
+
border-top: 1px solid var(--border-muted);
|
|
1482
1855
|
padding: 10px;
|
|
1483
1856
|
display: flex;
|
|
1484
1857
|
flex-direction: column;
|
|
@@ -1494,7 +1867,7 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1494
1867
|
}
|
|
1495
1868
|
|
|
1496
1869
|
footer {
|
|
1497
|
-
border-top: 1px solid var(--border);
|
|
1870
|
+
border-top: 1px solid var(--border-muted);
|
|
1498
1871
|
padding: 8px 12px;
|
|
1499
1872
|
color: var(--muted);
|
|
1500
1873
|
font-size: 12px;
|
|
@@ -1535,11 +1908,11 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1535
1908
|
<h1><span class="app-logo" aria-hidden="true">π</span> Pi Studio <span class="app-subtitle">Feedback Workspace</span></h1>
|
|
1536
1909
|
<div class="controls">
|
|
1537
1910
|
<select id="editorViewSelect" aria-label="Editor view mode">
|
|
1538
|
-
<option value="markdown" selected>Editor:
|
|
1911
|
+
<option value="markdown" selected>Editor: Raw</option>
|
|
1539
1912
|
<option value="preview">Editor: Preview</option>
|
|
1540
1913
|
</select>
|
|
1541
1914
|
<select id="rightViewSelect" aria-label="Response view mode">
|
|
1542
|
-
<option value="markdown">Response:
|
|
1915
|
+
<option value="markdown">Response: Raw</option>
|
|
1543
1916
|
<option value="preview" selected>Response: Preview</option>
|
|
1544
1917
|
</select>
|
|
1545
1918
|
<button id="saveAsBtn" type="button" title="Save editor text to a new file path.">Save As…</button>
|
|
@@ -1569,8 +1942,8 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1569
1942
|
<button id="sendEditorBtn" type="button">Send to pi editor</button>
|
|
1570
1943
|
<button id="copyDraftBtn" type="button">Copy editor text</button>
|
|
1571
1944
|
<select id="highlightSelect" aria-label="Editor syntax highlighting">
|
|
1572
|
-
<option value="off">
|
|
1573
|
-
<option value="on" selected>
|
|
1945
|
+
<option value="off">Syntax highlight: Off</option>
|
|
1946
|
+
<option value="on" selected>Syntax highlight: On</option>
|
|
1574
1947
|
</select>
|
|
1575
1948
|
</div>
|
|
1576
1949
|
</div>
|
|
@@ -1595,8 +1968,8 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1595
1968
|
<option value="off">Auto-update response: Off</option>
|
|
1596
1969
|
</select>
|
|
1597
1970
|
<select id="responseHighlightSelect" aria-label="Response markdown highlighting">
|
|
1598
|
-
<option value="off">
|
|
1599
|
-
<option value="on" selected>
|
|
1971
|
+
<option value="off">Syntax highlight: Off</option>
|
|
1972
|
+
<option value="on" selected>Syntax highlight: On</option>
|
|
1600
1973
|
</select>
|
|
1601
1974
|
<button id="pullLatestBtn" type="button" title="Fetch the latest assistant response when auto-update is off.">Get latest response</button>
|
|
1602
1975
|
<button id="loadResponseBtn" type="button">Load response into editor</button>
|
|
@@ -1710,6 +2083,12 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1710
2083
|
let editorHighlightEnabled = false;
|
|
1711
2084
|
let responseHighlightEnabled = false;
|
|
1712
2085
|
let editorHighlightRenderRaf = null;
|
|
2086
|
+
const MERMAID_CDN_URL = "https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs";
|
|
2087
|
+
const MERMAID_CONFIG = ${JSON.stringify(mermaidConfig)};
|
|
2088
|
+
const MERMAID_UNAVAILABLE_MESSAGE = "Mermaid renderer unavailable. Showing mermaid blocks as code.";
|
|
2089
|
+
const MERMAID_RENDER_FAIL_MESSAGE = "Mermaid render failed. Showing diagram source text.";
|
|
2090
|
+
let mermaidModulePromise = null;
|
|
2091
|
+
let mermaidInitialized = false;
|
|
1713
2092
|
|
|
1714
2093
|
function getIdleStatus() {
|
|
1715
2094
|
return "Ready. Edit text, then run or critique (insert annotation header if needed).";
|
|
@@ -1813,6 +2192,19 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1813
2192
|
event.preventDefault();
|
|
1814
2193
|
}
|
|
1815
2194
|
}
|
|
2195
|
+
|
|
2196
|
+
if (
|
|
2197
|
+
key === "Enter"
|
|
2198
|
+
&& (event.metaKey || event.ctrlKey)
|
|
2199
|
+
&& !event.altKey
|
|
2200
|
+
&& !event.shiftKey
|
|
2201
|
+
&& activePane === "left"
|
|
2202
|
+
&& sendRunBtn
|
|
2203
|
+
&& !sendRunBtn.disabled
|
|
2204
|
+
) {
|
|
2205
|
+
event.preventDefault();
|
|
2206
|
+
sendRunBtn.click();
|
|
2207
|
+
}
|
|
1816
2208
|
}
|
|
1817
2209
|
|
|
1818
2210
|
function formatReferenceTime(timestamp) {
|
|
@@ -1906,6 +2298,93 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1906
2298
|
return buildPreviewErrorHtml("Preview sanitizer unavailable. Showing plain markdown.", markdown);
|
|
1907
2299
|
}
|
|
1908
2300
|
|
|
2301
|
+
function appendMermaidNotice(targetEl, message) {
|
|
2302
|
+
if (!targetEl || typeof targetEl.querySelector !== "function" || typeof targetEl.appendChild !== "function") {
|
|
2303
|
+
return;
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2306
|
+
if (targetEl.querySelector(".preview-mermaid-warning")) {
|
|
2307
|
+
return;
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
const warningEl = document.createElement("div");
|
|
2311
|
+
warningEl.className = "preview-warning preview-mermaid-warning";
|
|
2312
|
+
warningEl.textContent = String(message || MERMAID_RENDER_FAIL_MESSAGE);
|
|
2313
|
+
targetEl.appendChild(warningEl);
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
async function getMermaidApi() {
|
|
2317
|
+
if (mermaidModulePromise) {
|
|
2318
|
+
return mermaidModulePromise;
|
|
2319
|
+
}
|
|
2320
|
+
|
|
2321
|
+
mermaidModulePromise = import(MERMAID_CDN_URL)
|
|
2322
|
+
.then((module) => {
|
|
2323
|
+
const mermaidApi = module && module.default ? module.default : null;
|
|
2324
|
+
if (!mermaidApi) {
|
|
2325
|
+
throw new Error("Mermaid module did not expose a default export.");
|
|
2326
|
+
}
|
|
2327
|
+
|
|
2328
|
+
if (!mermaidInitialized) {
|
|
2329
|
+
mermaidApi.initialize(MERMAID_CONFIG);
|
|
2330
|
+
mermaidInitialized = true;
|
|
2331
|
+
}
|
|
2332
|
+
|
|
2333
|
+
return mermaidApi;
|
|
2334
|
+
})
|
|
2335
|
+
.catch((error) => {
|
|
2336
|
+
mermaidModulePromise = null;
|
|
2337
|
+
throw error;
|
|
2338
|
+
});
|
|
2339
|
+
|
|
2340
|
+
return mermaidModulePromise;
|
|
2341
|
+
}
|
|
2342
|
+
|
|
2343
|
+
async function renderMermaidInElement(targetEl) {
|
|
2344
|
+
if (!targetEl || typeof targetEl.querySelectorAll !== "function") return;
|
|
2345
|
+
|
|
2346
|
+
const mermaidBlocks = targetEl.querySelectorAll("pre.mermaid");
|
|
2347
|
+
if (!mermaidBlocks || mermaidBlocks.length === 0) return;
|
|
2348
|
+
|
|
2349
|
+
let mermaidApi;
|
|
2350
|
+
try {
|
|
2351
|
+
mermaidApi = await getMermaidApi();
|
|
2352
|
+
} catch (error) {
|
|
2353
|
+
console.error("Mermaid module load failed:", error);
|
|
2354
|
+
appendMermaidNotice(targetEl, MERMAID_UNAVAILABLE_MESSAGE);
|
|
2355
|
+
return;
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2358
|
+
mermaidBlocks.forEach((preEl) => {
|
|
2359
|
+
const codeEl = preEl.querySelector("code");
|
|
2360
|
+
const source = codeEl ? codeEl.textContent : preEl.textContent;
|
|
2361
|
+
|
|
2362
|
+
const wrapper = document.createElement("div");
|
|
2363
|
+
wrapper.className = "mermaid-container";
|
|
2364
|
+
|
|
2365
|
+
const diagramEl = document.createElement("div");
|
|
2366
|
+
diagramEl.className = "mermaid";
|
|
2367
|
+
diagramEl.textContent = source || "";
|
|
2368
|
+
|
|
2369
|
+
wrapper.appendChild(diagramEl);
|
|
2370
|
+
preEl.replaceWith(wrapper);
|
|
2371
|
+
});
|
|
2372
|
+
|
|
2373
|
+
const diagramNodes = Array.from(targetEl.querySelectorAll(".mermaid"));
|
|
2374
|
+
if (diagramNodes.length === 0) return;
|
|
2375
|
+
|
|
2376
|
+
try {
|
|
2377
|
+
await mermaidApi.run({ nodes: diagramNodes });
|
|
2378
|
+
} catch (error) {
|
|
2379
|
+
try {
|
|
2380
|
+
await mermaidApi.run();
|
|
2381
|
+
} catch (fallbackError) {
|
|
2382
|
+
console.error("Mermaid render failed:", fallbackError || error);
|
|
2383
|
+
appendMermaidNotice(targetEl, MERMAID_RENDER_FAIL_MESSAGE);
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
|
|
1909
2388
|
async function renderMarkdownWithPandoc(markdown) {
|
|
1910
2389
|
const token = getToken();
|
|
1911
2390
|
if (!token) {
|
|
@@ -1976,6 +2455,7 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1976
2455
|
}
|
|
1977
2456
|
|
|
1978
2457
|
targetEl.innerHTML = sanitizeRenderedHtml(renderedHtml, markdown);
|
|
2458
|
+
await renderMermaidInElement(targetEl);
|
|
1979
2459
|
} catch (error) {
|
|
1980
2460
|
if (pane === "source") {
|
|
1981
2461
|
if (nonce !== sourcePreviewRenderNonce || editorView !== "preview") return;
|