pi-studio 0.1.9 → 0.2.1
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 +33 -0
- package/README.md +37 -14
- package/assets/screenshots/dark-code-mode.png +0 -0
- package/assets/screenshots/dark-julia-fenced.png +0 -0
- package/assets/screenshots/dark-math.png +0 -0
- package/assets/screenshots/dark-mermaid.png +0 -0
- package/assets/screenshots/dark-workspace.png +0 -0
- package/assets/screenshots/light-code-mode.png +0 -0
- package/assets/screenshots/light-math.png +0 -0
- package/assets/screenshots/light-workspace.png +0 -0
- package/index.ts +642 -76
- package/package.json +1 -1
- package/assets/screenshots/dark-annotation.png +0 -0
- package/assets/screenshots/dark-critique.png +0 -0
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
|
|
|
@@ -1496,7 +1851,7 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1496
1851
|
}
|
|
1497
1852
|
|
|
1498
1853
|
.response-wrap {
|
|
1499
|
-
border-top: 1px solid var(--border);
|
|
1854
|
+
border-top: 1px solid var(--border-muted);
|
|
1500
1855
|
padding: 10px;
|
|
1501
1856
|
display: flex;
|
|
1502
1857
|
flex-direction: column;
|
|
@@ -1512,7 +1867,7 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1512
1867
|
}
|
|
1513
1868
|
|
|
1514
1869
|
footer {
|
|
1515
|
-
border-top: 1px solid var(--border);
|
|
1870
|
+
border-top: 1px solid var(--border-muted);
|
|
1516
1871
|
padding: 8px 12px;
|
|
1517
1872
|
color: var(--muted);
|
|
1518
1873
|
font-size: 12px;
|
|
@@ -1553,16 +1908,16 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1553
1908
|
<h1><span class="app-logo" aria-hidden="true">π</span> Pi Studio <span class="app-subtitle">Feedback Workspace</span></h1>
|
|
1554
1909
|
<div class="controls">
|
|
1555
1910
|
<select id="editorViewSelect" aria-label="Editor view mode">
|
|
1556
|
-
<option value="markdown" selected>Editor:
|
|
1911
|
+
<option value="markdown" selected>Editor: Raw</option>
|
|
1557
1912
|
<option value="preview">Editor: Preview</option>
|
|
1558
1913
|
</select>
|
|
1559
1914
|
<select id="rightViewSelect" aria-label="Response view mode">
|
|
1560
|
-
<option value="markdown">Response:
|
|
1915
|
+
<option value="markdown">Response: Raw</option>
|
|
1561
1916
|
<option value="preview" selected>Response: Preview</option>
|
|
1562
1917
|
</select>
|
|
1563
1918
|
<button id="saveAsBtn" type="button" title="Save editor text to a new file path.">Save As…</button>
|
|
1564
1919
|
<button id="saveOverBtn" type="button" title="Overwrite current file with editor text." disabled>Save file</button>
|
|
1565
|
-
<label class="file-label" title="Load a local file into editor text.">Load file
|
|
1920
|
+
<label class="file-label" title="Load a local file into editor text.">Load file content<input id="fileInput" type="file" accept=".txt,.md,.markdown,.rst,.adoc,.tex,.json,.js,.ts,.py,.java,.c,.cpp,.h,.hpp,.go,.rs,.rb,.swift,.sh,.html,.css,.xml,.yaml,.yml,.toml,.jl,.f90,.f95,.f03,.f,.for,.r,.R,.m,.lua" /></label>
|
|
1566
1921
|
</div>
|
|
1567
1922
|
</header>
|
|
1568
1923
|
|
|
@@ -1587,8 +1942,23 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1587
1942
|
<button id="sendEditorBtn" type="button">Send to pi editor</button>
|
|
1588
1943
|
<button id="copyDraftBtn" type="button">Copy editor text</button>
|
|
1589
1944
|
<select id="highlightSelect" aria-label="Editor syntax highlighting">
|
|
1590
|
-
<option value="off">
|
|
1591
|
-
<option value="on" selected>
|
|
1945
|
+
<option value="off">Syntax highlight: Off</option>
|
|
1946
|
+
<option value="on" selected>Syntax highlight: On</option>
|
|
1947
|
+
</select>
|
|
1948
|
+
<select id="langSelect" aria-label="Highlight language">
|
|
1949
|
+
<option value="markdown" selected>Lang: Markdown</option>
|
|
1950
|
+
<option value="javascript">Lang: JavaScript</option>
|
|
1951
|
+
<option value="typescript">Lang: TypeScript</option>
|
|
1952
|
+
<option value="python">Lang: Python</option>
|
|
1953
|
+
<option value="bash">Lang: Bash</option>
|
|
1954
|
+
<option value="json">Lang: JSON</option>
|
|
1955
|
+
<option value="rust">Lang: Rust</option>
|
|
1956
|
+
<option value="c">Lang: C</option>
|
|
1957
|
+
<option value="cpp">Lang: C++</option>
|
|
1958
|
+
<option value="julia">Lang: Julia</option>
|
|
1959
|
+
<option value="fortran">Lang: Fortran</option>
|
|
1960
|
+
<option value="r">Lang: R</option>
|
|
1961
|
+
<option value="matlab">Lang: MATLAB</option>
|
|
1592
1962
|
</select>
|
|
1593
1963
|
</div>
|
|
1594
1964
|
</div>
|
|
@@ -1613,8 +1983,8 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1613
1983
|
<option value="off">Auto-update response: Off</option>
|
|
1614
1984
|
</select>
|
|
1615
1985
|
<select id="responseHighlightSelect" aria-label="Response markdown highlighting">
|
|
1616
|
-
<option value="off">
|
|
1617
|
-
<option value="on" selected>
|
|
1986
|
+
<option value="off">Syntax highlight: Off</option>
|
|
1987
|
+
<option value="on" selected>Syntax highlight: On</option>
|
|
1618
1988
|
</select>
|
|
1619
1989
|
<button id="pullLatestBtn" type="button" title="Fetch the latest assistant response when auto-update is off.">Get latest response</button>
|
|
1620
1990
|
<button id="loadResponseBtn" type="button">Load response into editor</button>
|
|
@@ -1688,6 +2058,7 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1688
2058
|
const sendRunBtn = document.getElementById("sendRunBtn");
|
|
1689
2059
|
const copyDraftBtn = document.getElementById("copyDraftBtn");
|
|
1690
2060
|
const highlightSelect = document.getElementById("highlightSelect");
|
|
2061
|
+
const langSelect = document.getElementById("langSelect");
|
|
1691
2062
|
|
|
1692
2063
|
const initialSourceState = {
|
|
1693
2064
|
source: (document.body && document.body.dataset && document.body.dataset.initialSource) || "blank",
|
|
@@ -1720,16 +2091,19 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1720
2091
|
let paneFocusTarget = "off";
|
|
1721
2092
|
const EDITOR_HIGHLIGHT_MAX_CHARS = 80_000;
|
|
1722
2093
|
const EDITOR_HIGHLIGHT_STORAGE_KEY = "piStudio.editorHighlightEnabled";
|
|
2094
|
+
const EDITOR_LANGUAGE_STORAGE_KEY = "piStudio.editorLanguage";
|
|
2095
|
+
const SUPPORTED_LANGUAGES = ["markdown", "javascript", "typescript", "python", "bash", "json", "rust", "c", "cpp", "julia", "fortran", "r", "matlab"];
|
|
1723
2096
|
const RESPONSE_HIGHLIGHT_MAX_CHARS = 120_000;
|
|
1724
2097
|
const RESPONSE_HIGHLIGHT_STORAGE_KEY = "piStudio.responseHighlightEnabled";
|
|
1725
2098
|
let sourcePreviewRenderTimer = null;
|
|
1726
2099
|
let sourcePreviewRenderNonce = 0;
|
|
1727
2100
|
let responsePreviewRenderNonce = 0;
|
|
1728
2101
|
let editorHighlightEnabled = false;
|
|
2102
|
+
let editorLanguage = "markdown";
|
|
1729
2103
|
let responseHighlightEnabled = false;
|
|
1730
2104
|
let editorHighlightRenderRaf = null;
|
|
1731
2105
|
const MERMAID_CDN_URL = "https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs";
|
|
1732
|
-
const
|
|
2106
|
+
const MERMAID_CONFIG = ${JSON.stringify(mermaidConfig)};
|
|
1733
2107
|
const MERMAID_UNAVAILABLE_MESSAGE = "Mermaid renderer unavailable. Showing mermaid blocks as code.";
|
|
1734
2108
|
const MERMAID_RENDER_FAIL_MESSAGE = "Mermaid render failed. Showing diagram source text.";
|
|
1735
2109
|
let mermaidModulePromise = null;
|
|
@@ -1837,6 +2211,19 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1837
2211
|
event.preventDefault();
|
|
1838
2212
|
}
|
|
1839
2213
|
}
|
|
2214
|
+
|
|
2215
|
+
if (
|
|
2216
|
+
key === "Enter"
|
|
2217
|
+
&& (event.metaKey || event.ctrlKey)
|
|
2218
|
+
&& !event.altKey
|
|
2219
|
+
&& !event.shiftKey
|
|
2220
|
+
&& activePane === "left"
|
|
2221
|
+
&& sendRunBtn
|
|
2222
|
+
&& !sendRunBtn.disabled
|
|
2223
|
+
) {
|
|
2224
|
+
event.preventDefault();
|
|
2225
|
+
sendRunBtn.click();
|
|
2226
|
+
}
|
|
1840
2227
|
}
|
|
1841
2228
|
|
|
1842
2229
|
function formatReferenceTime(timestamp) {
|
|
@@ -1958,10 +2345,7 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
1958
2345
|
}
|
|
1959
2346
|
|
|
1960
2347
|
if (!mermaidInitialized) {
|
|
1961
|
-
mermaidApi.initialize(
|
|
1962
|
-
startOnLoad: false,
|
|
1963
|
-
theme: MERMAID_THEME,
|
|
1964
|
-
});
|
|
2348
|
+
mermaidApi.initialize(MERMAID_CONFIG);
|
|
1965
2349
|
mermaidInitialized = true;
|
|
1966
2350
|
}
|
|
1967
2351
|
|
|
@@ -2105,10 +2489,14 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
2105
2489
|
|
|
2106
2490
|
function renderSourcePreviewNow() {
|
|
2107
2491
|
if (editorView !== "preview") return;
|
|
2108
|
-
const
|
|
2492
|
+
const text = sourceTextEl.value || "";
|
|
2493
|
+
if (editorLanguage && editorLanguage !== "markdown") {
|
|
2494
|
+
sourcePreviewEl.innerHTML = "<div class='response-markdown-highlight' style='white-space:pre;font-family:var(--font-mono);font-size:13px;line-height:1.5;padding:16px;overflow:auto;'>" + highlightCode(text, editorLanguage) + "</div>";
|
|
2495
|
+
return;
|
|
2496
|
+
}
|
|
2109
2497
|
const nonce = ++sourcePreviewRenderNonce;
|
|
2110
2498
|
sourcePreviewEl.innerHTML = "<div class='preview-loading'>Rendering preview…</div>";
|
|
2111
|
-
void applyRenderedMarkdown(sourcePreviewEl,
|
|
2499
|
+
void applyRenderedMarkdown(sourcePreviewEl, text, "source", nonce);
|
|
2112
2500
|
}
|
|
2113
2501
|
|
|
2114
2502
|
function scheduleSourcePreviewRender(delayMs) {
|
|
@@ -2233,6 +2621,7 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
2233
2621
|
sendRunBtn.disabled = uiBusy;
|
|
2234
2622
|
copyDraftBtn.disabled = uiBusy;
|
|
2235
2623
|
if (highlightSelect) highlightSelect.disabled = uiBusy;
|
|
2624
|
+
if (langSelect) langSelect.disabled = uiBusy;
|
|
2236
2625
|
editorViewSelect.disabled = uiBusy;
|
|
2237
2626
|
rightViewSelect.disabled = uiBusy;
|
|
2238
2627
|
followSelect.disabled = uiBusy;
|
|
@@ -2279,6 +2668,7 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
2279
2668
|
}
|
|
2280
2669
|
|
|
2281
2670
|
updateEditorHighlightState();
|
|
2671
|
+
updateLangSelectVisibility();
|
|
2282
2672
|
}
|
|
2283
2673
|
|
|
2284
2674
|
function setRightView(nextView) {
|
|
@@ -2364,6 +2754,13 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
2364
2754
|
if (first === "py" || first === "python") return "python";
|
|
2365
2755
|
if (first === "sh" || first === "bash" || first === "zsh" || first === "shell") return "bash";
|
|
2366
2756
|
if (first === "json" || first === "jsonc") return "json";
|
|
2757
|
+
if (first === "rust" || first === "rs") return "rust";
|
|
2758
|
+
if (first === "c" || first === "h") return "c";
|
|
2759
|
+
if (first === "cpp" || first === "c++" || first === "cxx" || first === "hpp") return "cpp";
|
|
2760
|
+
if (first === "julia" || first === "jl") return "julia";
|
|
2761
|
+
if (first === "fortran" || first === "f90" || first === "f95" || first === "f03" || first === "f" || first === "for") return "fortran";
|
|
2762
|
+
if (first === "r") return "r";
|
|
2763
|
+
if (first === "matlab" || first === "m") return "matlab";
|
|
2367
2764
|
|
|
2368
2765
|
return "";
|
|
2369
2766
|
}
|
|
@@ -2456,6 +2853,80 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
2456
2853
|
return "<span class='hl-code'>" + highlighted + "</span>";
|
|
2457
2854
|
}
|
|
2458
2855
|
|
|
2856
|
+
if (lang === "rust") {
|
|
2857
|
+
const rustPattern = /(\\/\\/.*$)|("(?:[^"\\\\]|\\\\.)*")|(\\b(?:fn|let|mut|const|struct|enum|impl|trait|pub|mod|use|crate|self|super|match|if|else|for|while|loop|return|break|continue|where|as|in|ref|move|async|await|unsafe|extern|type|static|true|false|Some|None|Ok|Err|Self)\\b)|(\\b\\d[\\d_]*(?:\\.\\d[\\d_]*)?(?:f32|f64|u8|u16|u32|u64|u128|usize|i8|i16|i32|i64|i128|isize)?\\b)/g;
|
|
2858
|
+
const highlighted = highlightCodeTokens(source, rustPattern, (match) => {
|
|
2859
|
+
if (match[1]) return "hl-code-com";
|
|
2860
|
+
if (match[2]) return "hl-code-str";
|
|
2861
|
+
if (match[3]) return "hl-code-kw";
|
|
2862
|
+
if (match[4]) return "hl-code-num";
|
|
2863
|
+
return "hl-code";
|
|
2864
|
+
});
|
|
2865
|
+
return "<span class='hl-code'>" + highlighted + "</span>";
|
|
2866
|
+
}
|
|
2867
|
+
|
|
2868
|
+
if (lang === "c" || lang === "cpp") {
|
|
2869
|
+
const cPattern = /(\\/\\/.*$)|("(?:[^"\\\\]|\\\\.)*"|'(?:[^'\\\\]|\\\\.)')|(#\\s*\\w+)|(\\b(?:if|else|for|while|do|switch|case|break|continue|return|goto|struct|union|enum|typedef|sizeof|void|int|char|short|long|float|double|unsigned|signed|const|static|extern|volatile|register|inline|auto|restrict|true|false|NULL|nullptr|class|public|private|protected|virtual|override|template|typename|namespace|using|new|delete|try|catch|throw|noexcept|constexpr|auto|decltype|static_cast|dynamic_cast|reinterpret_cast|const_cast|std|include|define|ifdef|ifndef|endif|pragma)\\b)|(\\b\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?[fFlLuU]*\\b)/g;
|
|
2870
|
+
const highlighted = highlightCodeTokens(source, cPattern, (match) => {
|
|
2871
|
+
if (match[1]) return "hl-code-com";
|
|
2872
|
+
if (match[2]) return "hl-code-str";
|
|
2873
|
+
if (match[3]) return "hl-code-kw";
|
|
2874
|
+
if (match[4]) return "hl-code-kw";
|
|
2875
|
+
if (match[5]) return "hl-code-num";
|
|
2876
|
+
return "hl-code";
|
|
2877
|
+
});
|
|
2878
|
+
return "<span class='hl-code'>" + highlighted + "</span>";
|
|
2879
|
+
}
|
|
2880
|
+
|
|
2881
|
+
if (lang === "julia") {
|
|
2882
|
+
const jlPattern = /(#.*$)|("(?:[^"\\\\]|\\\\.)*"|'(?:[^'\\\\]|\\\\.)*')|(\\b(?:function|end|if|elseif|else|for|while|begin|let|local|global|const|return|break|continue|do|try|catch|finally|throw|module|import|using|export|struct|mutable|abstract|primitive|where|macro|quote|true|false|nothing|missing|in|isa|typeof)\\b)|(\\b\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?\\b)/g;
|
|
2883
|
+
const highlighted = highlightCodeTokens(source, jlPattern, (match) => {
|
|
2884
|
+
if (match[1]) return "hl-code-com";
|
|
2885
|
+
if (match[2]) return "hl-code-str";
|
|
2886
|
+
if (match[3]) return "hl-code-kw";
|
|
2887
|
+
if (match[4]) return "hl-code-num";
|
|
2888
|
+
return "hl-code";
|
|
2889
|
+
});
|
|
2890
|
+
return "<span class='hl-code'>" + highlighted + "</span>";
|
|
2891
|
+
}
|
|
2892
|
+
|
|
2893
|
+
if (lang === "fortran") {
|
|
2894
|
+
const fPattern = /(!.*$)|("(?:[^"\\\\]|\\\\.)*"|'(?:[^'\\\\]|\\\\.)*')|(\\b(?:program|end|subroutine|function|module|use|implicit|none|integer|real|double|precision|complex|character|logical|dimension|allocatable|intent|in|out|inout|parameter|data|do|if|then|else|elseif|endif|enddo|call|return|write|read|print|format|stop|contains|type|class|select|case|where|forall|associate|block|procedure|interface|abstract|extends|allocate|deallocate|cycle|exit|go|to|common|equivalence|save|external|intrinsic)\\b)|(\\b\\d+(?:\\.\\d+)?(?:[dDeE][+-]?\\d+)?\\b)/gi;
|
|
2895
|
+
const highlighted = highlightCodeTokens(source, fPattern, (match) => {
|
|
2896
|
+
if (match[1]) return "hl-code-com";
|
|
2897
|
+
if (match[2]) return "hl-code-str";
|
|
2898
|
+
if (match[3]) return "hl-code-kw";
|
|
2899
|
+
if (match[4]) return "hl-code-num";
|
|
2900
|
+
return "hl-code";
|
|
2901
|
+
});
|
|
2902
|
+
return "<span class='hl-code'>" + highlighted + "</span>";
|
|
2903
|
+
}
|
|
2904
|
+
|
|
2905
|
+
if (lang === "r") {
|
|
2906
|
+
const rPattern = /(#.*$)|("(?:[^"\\\\]|\\\\.)*"|'(?:[^'\\\\]|\\\\.)*')|(\\b(?:function|if|else|for|while|repeat|in|next|break|return|TRUE|FALSE|NULL|NA|NA_integer_|NA_real_|NA_complex_|NA_character_|Inf|NaN|library|require|source|local|switch)\\b)|(<-|->|<<-|->>)|(\\b\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?[Li]?\\b)/g;
|
|
2907
|
+
const highlighted = highlightCodeTokens(source, rPattern, (match) => {
|
|
2908
|
+
if (match[1]) return "hl-code-com";
|
|
2909
|
+
if (match[2]) return "hl-code-str";
|
|
2910
|
+
if (match[3]) return "hl-code-kw";
|
|
2911
|
+
if (match[4]) return "hl-code-kw";
|
|
2912
|
+
if (match[5]) return "hl-code-num";
|
|
2913
|
+
return "hl-code";
|
|
2914
|
+
});
|
|
2915
|
+
return "<span class='hl-code'>" + highlighted + "</span>";
|
|
2916
|
+
}
|
|
2917
|
+
|
|
2918
|
+
if (lang === "matlab") {
|
|
2919
|
+
const matPattern = /(%.*$)|('(?:[^']|'')*'|"(?:[^"\\\\]|\\\\.)*")|(\\b(?:function|end|if|elseif|else|for|while|switch|case|otherwise|try|catch|return|break|continue|global|persistent|classdef|properties|methods|events|enumeration|true|false)\\b)|(\\b\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?[i]?\\b)/g;
|
|
2920
|
+
const highlighted = highlightCodeTokens(source, matPattern, (match) => {
|
|
2921
|
+
if (match[1]) return "hl-code-com";
|
|
2922
|
+
if (match[2]) return "hl-code-str";
|
|
2923
|
+
if (match[3]) return "hl-code-kw";
|
|
2924
|
+
if (match[4]) return "hl-code-num";
|
|
2925
|
+
return "hl-code";
|
|
2926
|
+
});
|
|
2927
|
+
return "<span class='hl-code'>" + highlighted + "</span>";
|
|
2928
|
+
}
|
|
2929
|
+
|
|
2459
2930
|
return wrapHighlight("hl-code", source);
|
|
2460
2931
|
}
|
|
2461
2932
|
|
|
@@ -2524,6 +2995,43 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
2524
2995
|
return out.join("<br>");
|
|
2525
2996
|
}
|
|
2526
2997
|
|
|
2998
|
+
function highlightCode(text, language) {
|
|
2999
|
+
const lines = String(text || "").replace(/\\r\\n/g, "\\n").split("\\n");
|
|
3000
|
+
const lang = normalizeFenceLanguage(language);
|
|
3001
|
+
const out = [];
|
|
3002
|
+
for (const line of lines) {
|
|
3003
|
+
if (line.length === 0) {
|
|
3004
|
+
out.push("");
|
|
3005
|
+
} else if (lang) {
|
|
3006
|
+
out.push(highlightCodeLine(line, lang));
|
|
3007
|
+
} else {
|
|
3008
|
+
out.push(escapeHtml(line));
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
3011
|
+
return out.join("<br>");
|
|
3012
|
+
}
|
|
3013
|
+
|
|
3014
|
+
function detectLanguageFromName(name) {
|
|
3015
|
+
if (!name) return "";
|
|
3016
|
+
const dot = name.lastIndexOf(".");
|
|
3017
|
+
if (dot < 0) return "";
|
|
3018
|
+
const ext = name.slice(dot + 1).toLowerCase();
|
|
3019
|
+
if (ext === "js" || ext === "mjs" || ext === "cjs" || ext === "jsx") return "javascript";
|
|
3020
|
+
if (ext === "ts" || ext === "mts" || ext === "cts" || ext === "tsx") return "typescript";
|
|
3021
|
+
if (ext === "py" || ext === "pyw") return "python";
|
|
3022
|
+
if (ext === "sh" || ext === "bash" || ext === "zsh") return "bash";
|
|
3023
|
+
if (ext === "json" || ext === "jsonc" || ext === "json5") return "json";
|
|
3024
|
+
if (ext === "rs") return "rust";
|
|
3025
|
+
if (ext === "c" || ext === "h") return "c";
|
|
3026
|
+
if (ext === "cpp" || ext === "cxx" || ext === "cc" || ext === "hpp" || ext === "hxx") return "cpp";
|
|
3027
|
+
if (ext === "jl") return "julia";
|
|
3028
|
+
if (ext === "f90" || ext === "f95" || ext === "f03" || ext === "f" || ext === "for") return "fortran";
|
|
3029
|
+
if (ext === "r" || ext === "R") return "r";
|
|
3030
|
+
if (ext === "m") return "matlab";
|
|
3031
|
+
if (ext === "md" || ext === "markdown" || ext === "mdx") return "markdown";
|
|
3032
|
+
return "";
|
|
3033
|
+
}
|
|
3034
|
+
|
|
2527
3035
|
function renderEditorHighlightNow() {
|
|
2528
3036
|
if (!sourceHighlightEl) return;
|
|
2529
3037
|
if (!editorHighlightEnabled || editorView !== "markdown") {
|
|
@@ -2538,7 +3046,11 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
2538
3046
|
return;
|
|
2539
3047
|
}
|
|
2540
3048
|
|
|
2541
|
-
|
|
3049
|
+
if (editorLanguage === "markdown" || !editorLanguage) {
|
|
3050
|
+
sourceHighlightEl.innerHTML = highlightMarkdown(text);
|
|
3051
|
+
} else {
|
|
3052
|
+
sourceHighlightEl.innerHTML = highlightCode(text, editorLanguage);
|
|
3053
|
+
}
|
|
2542
3054
|
syncEditorHighlightScroll();
|
|
2543
3055
|
}
|
|
2544
3056
|
|
|
@@ -2643,6 +3155,46 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
2643
3155
|
highlightSelect.value = editorHighlightEnabled ? "on" : "off";
|
|
2644
3156
|
}
|
|
2645
3157
|
updateEditorHighlightState();
|
|
3158
|
+
updateLangSelectVisibility();
|
|
3159
|
+
}
|
|
3160
|
+
|
|
3161
|
+
function readStoredEditorLanguage() {
|
|
3162
|
+
if (!window.localStorage) return null;
|
|
3163
|
+
try {
|
|
3164
|
+
const value = window.localStorage.getItem(EDITOR_LANGUAGE_STORAGE_KEY);
|
|
3165
|
+
if (value && SUPPORTED_LANGUAGES.indexOf(value) !== -1) return value;
|
|
3166
|
+
return null;
|
|
3167
|
+
} catch {
|
|
3168
|
+
return null;
|
|
3169
|
+
}
|
|
3170
|
+
}
|
|
3171
|
+
|
|
3172
|
+
function persistEditorLanguage(lang) {
|
|
3173
|
+
if (!window.localStorage) return;
|
|
3174
|
+
try {
|
|
3175
|
+
window.localStorage.setItem(EDITOR_LANGUAGE_STORAGE_KEY, lang || "markdown");
|
|
3176
|
+
} catch {}
|
|
3177
|
+
}
|
|
3178
|
+
|
|
3179
|
+
function setEditorLanguage(lang) {
|
|
3180
|
+
editorLanguage = (lang && SUPPORTED_LANGUAGES.indexOf(lang) !== -1) ? lang : "markdown";
|
|
3181
|
+
persistEditorLanguage(editorLanguage);
|
|
3182
|
+
if (langSelect) {
|
|
3183
|
+
langSelect.value = editorLanguage;
|
|
3184
|
+
}
|
|
3185
|
+
if (editorHighlightEnabled && editorView === "markdown") {
|
|
3186
|
+
scheduleEditorHighlightRender();
|
|
3187
|
+
}
|
|
3188
|
+
if (editorView === "preview") {
|
|
3189
|
+
scheduleSourcePreviewRender(0);
|
|
3190
|
+
}
|
|
3191
|
+
}
|
|
3192
|
+
|
|
3193
|
+
function updateLangSelectVisibility() {
|
|
3194
|
+
if (!langSelect) return;
|
|
3195
|
+
const highlightActive = editorHighlightEnabled && editorView === "markdown";
|
|
3196
|
+
const previewActive = editorView === "preview";
|
|
3197
|
+
langSelect.hidden = !(highlightActive || previewActive);
|
|
2646
3198
|
}
|
|
2647
3199
|
|
|
2648
3200
|
function setResponseHighlightEnabled(enabled) {
|
|
@@ -3103,6 +3655,12 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
3103
3655
|
});
|
|
3104
3656
|
}
|
|
3105
3657
|
|
|
3658
|
+
if (langSelect) {
|
|
3659
|
+
langSelect.addEventListener("change", () => {
|
|
3660
|
+
setEditorLanguage(langSelect.value);
|
|
3661
|
+
});
|
|
3662
|
+
}
|
|
3663
|
+
|
|
3106
3664
|
pullLatestBtn.addEventListener("click", () => {
|
|
3107
3665
|
if (queuedLatestResponse) {
|
|
3108
3666
|
if (applyLatestPayload(queuedLatestResponse)) {
|
|
@@ -3338,6 +3896,10 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
3338
3896
|
path: null,
|
|
3339
3897
|
});
|
|
3340
3898
|
refreshResponseUi();
|
|
3899
|
+
const detectedLang = detectLanguageFromName(file.name);
|
|
3900
|
+
if (detectedLang) {
|
|
3901
|
+
setEditorLanguage(detectedLang);
|
|
3902
|
+
}
|
|
3341
3903
|
setStatus("Loaded file " + file.name + ".", "success");
|
|
3342
3904
|
};
|
|
3343
3905
|
reader.onerror = () => {
|
|
@@ -3354,6 +3916,10 @@ function buildStudioHtml(initialDocument: InitialStudioDocument | null, theme?:
|
|
|
3354
3916
|
const initialHighlightEnabled = storedEditorHighlightEnabled ?? Boolean(highlightSelect && highlightSelect.value === "on");
|
|
3355
3917
|
setEditorHighlightEnabled(initialHighlightEnabled);
|
|
3356
3918
|
|
|
3919
|
+
const initialDetectedLang = detectLanguageFromName(initialSourceState.path || initialSourceState.label || "");
|
|
3920
|
+
const storedLang = readStoredEditorLanguage();
|
|
3921
|
+
setEditorLanguage(initialDetectedLang || storedLang || "markdown");
|
|
3922
|
+
|
|
3357
3923
|
const storedResponseHighlightEnabled = readStoredResponseHighlightEnabled();
|
|
3358
3924
|
const initialResponseHighlightEnabled = storedResponseHighlightEnabled ?? Boolean(responseHighlightSelect && responseHighlightSelect.value === "on");
|
|
3359
3925
|
setResponseHighlightEnabled(initialResponseHighlightEnabled);
|