finch-markdown-editor 0.2.5 → 0.2.6
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/dist/bmmd/bin/bmmd.mjs +3 -3
- package/dist/bmmd/bin/dist-BoUxJM-2.mjs +71 -0
- package/dist/bmmd/bin/{html-BUXlQGSS.mjs → html-CGVTbdd7.mjs} +143 -143
- package/dist/codemirror.js +25 -25
- package/dist/index.js +142 -19
- package/dist/panel.css +4 -4
- package/dist/panel.js +21 -21
- package/package.json +7 -2
- package/dist/bmmd/bin/dist-B0xJMeoM.mjs +0 -134
package/dist/index.js
CHANGED
|
@@ -204,12 +204,55 @@ function substituteFinchFileImagesForBm(markdown) {
|
|
|
204
204
|
});
|
|
205
205
|
return { markdown: substituted, urls };
|
|
206
206
|
}
|
|
207
|
+
var MERMAID_THEME_BY_STYLE = {
|
|
208
|
+
kami: "solarized-light",
|
|
209
|
+
bauhaus: "github-light",
|
|
210
|
+
blueprint: "nord",
|
|
211
|
+
botanical: "catppuccin-latte",
|
|
212
|
+
newsprint: "github-light",
|
|
213
|
+
retro: "solarized-dark",
|
|
214
|
+
sketch: "github-light",
|
|
215
|
+
terminal: "one-dark"
|
|
216
|
+
};
|
|
217
|
+
var MERMAID_THEME_COLORS = {
|
|
218
|
+
"zinc-dark": { bg: "#18181B", fg: "#FAFAFA" },
|
|
219
|
+
"tokyo-night": { bg: "#1a1b26", fg: "#a9b1d6", line: "#3d59a1", accent: "#7aa2f7", muted: "#565f89" },
|
|
220
|
+
"tokyo-night-storm": { bg: "#24283b", fg: "#a9b1d6", line: "#3d59a1", accent: "#7aa2f7", muted: "#565f89" },
|
|
221
|
+
"tokyo-night-light": { bg: "#d5d6db", fg: "#343b58", line: "#34548a", accent: "#34548a", muted: "#9699a3" },
|
|
222
|
+
"catppuccin-mocha": { bg: "#1e1e2e", fg: "#cdd6f4", line: "#585b70", accent: "#cba6f7", muted: "#6c7086" },
|
|
223
|
+
"catppuccin-latte": { bg: "#eff1f5", fg: "#4c4f69", line: "#9ca0b0", accent: "#8839ef", muted: "#9ca0b0" },
|
|
224
|
+
nord: { bg: "#2e3440", fg: "#d8dee9", line: "#4c566a", accent: "#88c0d0", muted: "#616e88" },
|
|
225
|
+
"nord-light": { bg: "#eceff4", fg: "#2e3440", line: "#aab1c0", accent: "#5e81ac", muted: "#7b88a1" },
|
|
226
|
+
dracula: { bg: "#282a36", fg: "#f8f8f2", line: "#6272a4", accent: "#bd93f9", muted: "#6272a4" },
|
|
227
|
+
"github-light": { bg: "#ffffff", fg: "#1f2328", line: "#d1d9e0", accent: "#0969da", muted: "#59636e" },
|
|
228
|
+
"github-dark": { bg: "#0d1117", fg: "#e6edf3", line: "#3d444d", accent: "#4493f8", muted: "#9198a1" },
|
|
229
|
+
"solarized-light": { bg: "#fdf6e3", fg: "#657b83", line: "#93a1a1", accent: "#268bd2", muted: "#93a1a1" },
|
|
230
|
+
"solarized-dark": { bg: "#002b36", fg: "#839496", line: "#586e75", accent: "#268bd2", muted: "#586e75" },
|
|
231
|
+
"one-dark": { bg: "#282c34", fg: "#abb2bf", line: "#4b5263", accent: "#c678dd", muted: "#5c6370" }
|
|
232
|
+
};
|
|
233
|
+
var MERMAID_FIGURE_SVG_STYLE_RE = /(<figure class="figure-mermaid"[^>]*>\s*<svg\b[^>]*?\sstyle=")/g;
|
|
234
|
+
function applyMermaidThemeVars(html, themeId) {
|
|
235
|
+
const colors = MERMAID_THEME_COLORS[themeId];
|
|
236
|
+
if (!colors) return html;
|
|
237
|
+
const vars = [
|
|
238
|
+
`--bg:${colors.bg};`,
|
|
239
|
+
`--fg:${colors.fg};`,
|
|
240
|
+
colors.line ? `--line:${colors.line};` : "",
|
|
241
|
+
colors.accent ? `--accent:${colors.accent};` : "",
|
|
242
|
+
colors.muted ? `--muted:${colors.muted};` : ""
|
|
243
|
+
].filter(Boolean).join("");
|
|
244
|
+
return html.replace(MERMAID_FIGURE_SVG_STYLE_RE, (_match, prefix) => `${prefix}${vars}`);
|
|
245
|
+
}
|
|
207
246
|
async function renderWithBm(markdown, markdownStyle, customCss) {
|
|
208
|
-
const
|
|
247
|
+
const style = markdownStyle || "kami";
|
|
248
|
+
const args = ["render", "--platform", "wechat", "--markdown-style", style];
|
|
249
|
+
const mermaidTheme = MERMAID_THEME_BY_STYLE[style];
|
|
250
|
+
if (mermaidTheme) args.push("--mermaid-theme", mermaidTheme);
|
|
209
251
|
if (customCss && customCss.trim()) args.push("--custom-css", customCss);
|
|
210
252
|
const sized = prepareObsidianImageWidths(markdown);
|
|
211
253
|
const prepared = substituteFinchFileImagesForBm(sized.markdown);
|
|
212
254
|
let html = await runBmmd(args, prepared.markdown);
|
|
255
|
+
if (mermaidTheme) html = applyMermaidThemeVars(html, mermaidTheme);
|
|
213
256
|
html = applyObsidianImageWidths(html, sized.markers);
|
|
214
257
|
for (const [placeholder, originalUrl] of prepared.urls) html = html.split(placeholder).join(originalUrl);
|
|
215
258
|
return html;
|
|
@@ -273,6 +316,7 @@ async function openMarkdownImagePreview(ctx, rawUrl) {
|
|
|
273
316
|
var STYLE_SLOT_COUNT = 3;
|
|
274
317
|
var WRITING_STYLE_IDS = /* @__PURE__ */ new Set(["kami", "bauhaus", "blueprint", "botanical", "newsprint", "retro", "sketch", "terminal", "custom"]);
|
|
275
318
|
var MAX_CUSTOM_STYLE_CSS_LENGTH = 2e5;
|
|
319
|
+
var MAX_LIBRARY_GROUP_IDS = 500;
|
|
276
320
|
function result(message, isError = false) {
|
|
277
321
|
return { content: [{ type: "text", text: message }], isError };
|
|
278
322
|
}
|
|
@@ -285,6 +329,33 @@ function styleSlotsFile(ctx) {
|
|
|
285
329
|
function writingPreferencesFile(ctx) {
|
|
286
330
|
return path3.join(ctx.storagePath, "writing-preferences.json");
|
|
287
331
|
}
|
|
332
|
+
function libraryGroupsFile(ctx) {
|
|
333
|
+
return path3.join(ctx.storagePath, "library-groups.json");
|
|
334
|
+
}
|
|
335
|
+
function normalizeLibraryGroups(raw) {
|
|
336
|
+
const value = raw && typeof raw === "object" ? raw : {};
|
|
337
|
+
const order = Array.isArray(value.order) ? value.order.filter((id) => typeof id === "string").slice(0, MAX_LIBRARY_GROUP_IDS) : [];
|
|
338
|
+
const collapsedRaw = value.collapsed && typeof value.collapsed === "object" ? value.collapsed : {};
|
|
339
|
+
const collapsed = {};
|
|
340
|
+
Object.keys(collapsedRaw).slice(0, MAX_LIBRARY_GROUP_IDS).forEach((id) => {
|
|
341
|
+
collapsed[id] = collapsedRaw[id] === true;
|
|
342
|
+
});
|
|
343
|
+
return { order, collapsed };
|
|
344
|
+
}
|
|
345
|
+
async function readLibraryGroups(ctx) {
|
|
346
|
+
try {
|
|
347
|
+
const raw = await readFile2(libraryGroupsFile(ctx), "utf8");
|
|
348
|
+
return normalizeLibraryGroups(JSON.parse(raw));
|
|
349
|
+
} catch {
|
|
350
|
+
return void 0;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
async function writeLibraryGroups(ctx, raw) {
|
|
354
|
+
const state = normalizeLibraryGroups(raw);
|
|
355
|
+
await mkdir2(ctx.storagePath, { recursive: true });
|
|
356
|
+
await writeFile2(libraryGroupsFile(ctx), JSON.stringify(state), "utf8");
|
|
357
|
+
return state;
|
|
358
|
+
}
|
|
288
359
|
function normalizeWritingPreferences(raw) {
|
|
289
360
|
const value = raw && typeof raw === "object" ? raw : {};
|
|
290
361
|
const fontSize = value.fontSize === 16 || value.fontSize === 18 ? value.fontSize : 14;
|
|
@@ -684,9 +755,10 @@ async function getAssistantName(ctx) {
|
|
|
684
755
|
}
|
|
685
756
|
async function sendReady(ctx, panel) {
|
|
686
757
|
const pickFileSupported = ctx.api.supports("ui.pickFile");
|
|
687
|
-
const [styleSlots, writingPreferences, assistantName] = await Promise.all([
|
|
758
|
+
const [styleSlots, writingPreferences, libraryGroups, assistantName] = await Promise.all([
|
|
688
759
|
readStyleSlots(ctx),
|
|
689
760
|
readWritingPreferences(ctx),
|
|
761
|
+
readLibraryGroups(ctx),
|
|
690
762
|
getAssistantName(ctx)
|
|
691
763
|
]);
|
|
692
764
|
ctx.logger.info(`sending ready to panel; pickFileSupported = ${pickFileSupported}`);
|
|
@@ -696,6 +768,7 @@ async function sendReady(ctx, panel) {
|
|
|
696
768
|
pickFileSupported,
|
|
697
769
|
styleSlots,
|
|
698
770
|
writingPreferences,
|
|
771
|
+
libraryGroups,
|
|
699
772
|
assistantName,
|
|
700
773
|
// So the page can render `cwd` the OS-friendly way (`~/…`) without a
|
|
701
774
|
// round trip — it never needs the raw value for anything but display.
|
|
@@ -717,6 +790,22 @@ async function revealInFileManager(ctx, targetPath) {
|
|
|
717
790
|
ctx.logger.warn(`Could not open file manager for ${targetPath}: ${String(error)}`);
|
|
718
791
|
}
|
|
719
792
|
}
|
|
793
|
+
async function rememberLastAiSession(ctx, sourcePath, sessionId) {
|
|
794
|
+
try {
|
|
795
|
+
await mutateState(ctx, (state) => {
|
|
796
|
+
state.lastAiSessions = { ...state.lastAiSessions, [sourcePath]: { sessionId, at: Date.now() } };
|
|
797
|
+
});
|
|
798
|
+
} catch (error) {
|
|
799
|
+
ctx.logger.warn(`Could not persist last AI session: ${String(error)}`);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
async function readLastAiSession(ctx, sourcePath) {
|
|
803
|
+
const state = await readLastPathState(ctx);
|
|
804
|
+
const id = state.lastAiSessions?.[sourcePath]?.sessionId;
|
|
805
|
+
if (!id) return void 0;
|
|
806
|
+
const session = await ctx.sessions.get(id).catch(() => void 0);
|
|
807
|
+
return session ? id : void 0;
|
|
808
|
+
}
|
|
720
809
|
async function readRewriteSession(ctx, sourcePath) {
|
|
721
810
|
const state = await readLastPathState(ctx);
|
|
722
811
|
const id = state.rewriteSessions?.[sourcePath];
|
|
@@ -780,6 +869,36 @@ async function notifyRewritePanels(sourcePath, message) {
|
|
|
780
869
|
await Promise.all(targets.map((panel) => panel.postMessage(message).catch(() => {
|
|
781
870
|
})));
|
|
782
871
|
}
|
|
872
|
+
async function restoreInFlightOperations(ctx, panel, sourcePath) {
|
|
873
|
+
const state = await readLastPathState(ctx);
|
|
874
|
+
const operation = state.rewriteOperations?.[sourcePath];
|
|
875
|
+
if (operation) await panel.postMessage({
|
|
876
|
+
type: "rewriteSessionStarted",
|
|
877
|
+
sessionId: operation.sessionId,
|
|
878
|
+
turnId: operation.turnId,
|
|
879
|
+
startLine: operation.startLine,
|
|
880
|
+
endLine: operation.endLine,
|
|
881
|
+
rewriteMode: operation.rewriteMode
|
|
882
|
+
});
|
|
883
|
+
const styleOperation = state.styleOperations?.[sourcePath];
|
|
884
|
+
if (styleOperation) await panel.postMessage({ type: "styleSessionStarted", sessionId: styleOperation.sessionId });
|
|
885
|
+
const pendingStyle = state.pendingStyles?.[sourcePath];
|
|
886
|
+
if (pendingStyle) await panel.postMessage({ type: "customStyleSet", css: pendingStyle.css, label: pendingStyle.label });
|
|
887
|
+
const lastSessionId = await readLastAiSession(ctx, sourcePath);
|
|
888
|
+
await panel.postMessage({ type: "lastSessionInfo", sessionId: lastSessionId ?? null });
|
|
889
|
+
}
|
|
890
|
+
async function cancelRewriteSession(ctx, panel, message) {
|
|
891
|
+
const sourcePath = String(message.path ?? "").trim();
|
|
892
|
+
const sessionId = String(message.sessionId ?? "").trim();
|
|
893
|
+
const turnId = String(message.turnId ?? "").trim();
|
|
894
|
+
if (panel.view !== "appView" || !path3.isAbsolute(sourcePath) || !sessionId || !turnId) return;
|
|
895
|
+
const operation = (await readLastPathState(ctx)).rewriteOperations?.[sourcePath];
|
|
896
|
+
if (!operation || operation.sessionId !== sessionId || operation.turnId !== turnId) return;
|
|
897
|
+
const accepted = await ctx.sessions.cancelTurn(sessionId, turnId);
|
|
898
|
+
if (accepted) {
|
|
899
|
+
await notifyRewritePanels(sourcePath, { type: "rewriteCancellationRequested", sessionId, turnId });
|
|
900
|
+
}
|
|
901
|
+
}
|
|
783
902
|
async function startRewriteSession(ctx, panel, message) {
|
|
784
903
|
const sourcePath = String(message.path ?? "").trim();
|
|
785
904
|
const selectedText = String(message.selectedText ?? "").trim();
|
|
@@ -796,12 +915,13 @@ async function startRewriteSession(ctx, panel, message) {
|
|
|
796
915
|
const session = await ctx.sessions.create({
|
|
797
916
|
...scope.spaceId ? { space: { spaceId: scope.spaceId } } : {},
|
|
798
917
|
title: `\u6539\u5199\uFF1A${path3.basename(sourcePath)}`,
|
|
799
|
-
activity: "
|
|
918
|
+
activity: "background",
|
|
800
919
|
permissionMode: "acceptCalls"
|
|
801
920
|
});
|
|
802
921
|
sessionId = session.sessionId;
|
|
803
922
|
await rememberRewriteSession(ctx, sourcePath, sessionId);
|
|
804
923
|
}
|
|
924
|
+
await rememberLastAiSession(ctx, sourcePath, sessionId);
|
|
805
925
|
const lineText = message.startLine ? `\u4F4D\u7F6E\uFF1A\u7B2C ${message.startLine}${message.endLine && message.endLine !== message.startLine ? `\u2013${message.endLine}` : ""} \u884C\u3002` : "";
|
|
806
926
|
const prompt = rewriteMode === "continue" ? `\u8BF7\u5728\u4E0B\u9762\u8FD9\u4EFD Markdown \u6587\u4EF6\u7684\u6307\u5B9A\u4F4D\u7F6E\u7EED\u5199\u5185\u5BB9\uFF0C\u5E76\u628A\u7ED3\u679C\u5199\u56DE\u6587\u4EF6\u3002
|
|
807
927
|
|
|
@@ -839,6 +959,7 @@ ${selectedText}
|
|
|
839
959
|
await notifyRewritePanels(sourcePath, {
|
|
840
960
|
type: "rewriteSessionStarted",
|
|
841
961
|
sessionId,
|
|
962
|
+
turnId: receipt.turnId,
|
|
842
963
|
spaceName: scope.spaceName,
|
|
843
964
|
title: `${rewriteMode === "continue" ? "\u7EED\u5199" : "\u6539\u5199"}\uFF1A${path3.basename(sourcePath)}`,
|
|
844
965
|
startLine: operation.startLine,
|
|
@@ -851,6 +972,7 @@ ${selectedText}
|
|
|
851
972
|
await notifyRewritePanels(sourcePath, {
|
|
852
973
|
type: result2.state === "completed" ? "rewriteSessionFinished" : "rewriteSessionFailed",
|
|
853
974
|
sessionId,
|
|
975
|
+
turnId: receipt.turnId,
|
|
854
976
|
message: result2.state === "completed" ? `${verb}\u5DF2\u5B8C\u6210\u3002` : result2.state === "timeout" ? `${verb}\u4ECD\u5728\u4F1A\u8BDD\u4E2D\u7EE7\u7EED\u3002` : `${verb}\u4F1A\u8BDD\u672A\u5B8C\u6210\u3002`
|
|
855
977
|
});
|
|
856
978
|
});
|
|
@@ -886,12 +1008,13 @@ async function startStyleSession(ctx, panel, message) {
|
|
|
886
1008
|
const session = await ctx.sessions.create({
|
|
887
1009
|
...scope.spaceId ? { space: { spaceId: scope.spaceId } } : {},
|
|
888
1010
|
title: `\u8BBE\u8BA1\u6392\u7248\uFF1A${path3.basename(sourcePath)}`,
|
|
889
|
-
activity: "
|
|
1011
|
+
activity: "background",
|
|
890
1012
|
permissionMode: "acceptCalls"
|
|
891
1013
|
});
|
|
892
1014
|
sessionId = session.sessionId;
|
|
893
1015
|
await rememberStyleSession(ctx, sourcePath, sessionId);
|
|
894
1016
|
}
|
|
1017
|
+
await rememberLastAiSession(ctx, sourcePath, sessionId);
|
|
895
1018
|
const prompt = `\u8BF7\u4E3A\u8FD9\u7BC7\u516C\u4F17\u53F7\u6587\u7AE0\u8BBE\u8BA1\u4E00\u5957\u81EA\u5B9A\u4E49\u6392\u7248 CSS\u3002${baseNote ? baseNote + "\uFF0C" : ""}\u4F60\u7684 CSS \u4F1A\u53E0\u52A0\u5728\u57FA\u7840\u98CE\u683C\u4E4B\u4E0A\u3002\u8981\u6C42\uFF1A\u53EA\u5199\u666E\u901A CSS \u89C4\u5219\uFF0C\u9009\u62E9\u5668\u9650\u5B9A\u5728 #bm-md \u4E0B\u7684\u6807\u7B7E/\u7ED3\u6784\uFF08\u5982 #bm-md h1\u3001#bm-md p\u3001#bm-md blockquote\u3001#bm-md pre code\u3001#bm-md a\u3001#bm-md strong\u3001#bm-md table \u7B49\uFF09\uFF0C\u4E0D\u8981\u4F7F\u7528 class\uFF0C\u5FC5\u8981\u65F6\u7528 !important \u8986\u76D6\u57FA\u7840\u98CE\u683C\u3002\u53EF\u53C2\u8003 bm.md \u5185\u7F6E\u98CE\u683C\u7684\u8BBE\u8BA1\u8BED\u8A00\uFF1Akami\uFF08\u6696\u8272\u7EB8\u611F\uFF09\u3001bauhaus\uFF08\u51E0\u4F55\u649E\u8272\uFF09\u3001blueprint\uFF08\u6280\u672F\u84DD\u56FE\u7F51\u683C\uFF09\u3001botanical\uFF08\u6E05\u65B0\u7EFF\u610F\uFF09\u3001newsprint\uFF08\u62A5\u520A\u886C\u7EBF\uFF09\u3001retro\uFF08\u590D\u53E4\u6000\u65E7\uFF09\u3001sketch\uFF08\u624B\u7ED8\u98CE\uFF09\u3001terminal\uFF08\u7B49\u5BBD\u6697\u8272\u7EC8\u7AEF\u98CE\uFF09\u3002\u6587\u7AE0\u8DEF\u5F84\uFF1A${sourcePath}\u3002\u8981\u6C42\uFF1A${requirement}\u3002\u8BBE\u8BA1\u597D\u540E\u76F4\u63A5\u8C03\u7528 markdown_editor_document \u7684 set_style\uFF08\u4F20 path="${sourcePath}"\uFF0Ccss \u548C\u7B80\u77ED label\uFF0C\u4E0D\u8981\u4F20 slot\u2014\u2014\u4F20 path \u662F\u4E3A\u4E86\u8BA9\u5B83\u80FD\u627E\u5230\u8FD9\u7BC7\u6587\u6863\u5BF9\u5E94\u7684\u9884\u89C8\u7A97\u53E3\uFF0C\u5373\u4F7F\u7528\u6237\u5DF2\u7ECF\u5207\u6362\u5230\u522B\u7684\u754C\u9762\uFF09\uFF0C\u8BA9\u5B83\u5E94\u7528\u5230\u9884\u89C8\uFF1B\u4E0D\u8981\u5728\u8FD9\u91CC\u8BE2\u95EE\u8981\u8986\u76D6\u54EA\u4E2A\u69FD\u4F4D\u2014\u2014\u9762\u677F\u4F1A\u81EA\u5DF1\u7ED9\u7528\u6237\u4E00\u4E2A\u8F7B\u91CF\u7684\u201C\u4FDD\u5B58\u4E3A\u81EA\u5B9A\u4E49\u98CE\u683C\u201D\u6309\u94AE\uFF0C\u7528\u6237\u56DE\u5230\u8FD9\u7BC7\u6587\u6863\u65F6\u4E5F\u8FD8\u80FD\u770B\u5230\u3002\u5B8C\u6210\u540E\u7528\u4E00\u4E24\u53E5\u8BDD\u7B80\u77ED\u8BF4\u660E\u8BBE\u8BA1\u601D\u8DEF\u5373\u53EF\u3002`;
|
|
896
1019
|
const receipt = await ctx.sessions.send(sessionId, {
|
|
897
1020
|
text: prompt,
|
|
@@ -936,21 +1059,7 @@ async function handleMessage(ctx, panel, raw) {
|
|
|
936
1059
|
await panel.postMessage({ type: "lastFileUnavailable" });
|
|
937
1060
|
}
|
|
938
1061
|
const currentPath = livePanelDocuments.get(panel.id)?.path;
|
|
939
|
-
if (currentPath)
|
|
940
|
-
const state = await readLastPathState(ctx);
|
|
941
|
-
const operation = state.rewriteOperations?.[currentPath];
|
|
942
|
-
if (operation) await panel.postMessage({
|
|
943
|
-
type: "rewriteSessionStarted",
|
|
944
|
-
sessionId: operation.sessionId,
|
|
945
|
-
startLine: operation.startLine,
|
|
946
|
-
endLine: operation.endLine,
|
|
947
|
-
rewriteMode: operation.rewriteMode
|
|
948
|
-
});
|
|
949
|
-
const styleOperation = state.styleOperations?.[currentPath];
|
|
950
|
-
if (styleOperation) await panel.postMessage({ type: "styleSessionStarted", sessionId: styleOperation.sessionId });
|
|
951
|
-
const pendingStyle = state.pendingStyles?.[currentPath];
|
|
952
|
-
if (pendingStyle) await panel.postMessage({ type: "customStyleSet", css: pendingStyle.css, label: pendingStyle.label });
|
|
953
|
-
}
|
|
1062
|
+
if (currentPath) await restoreInFlightOperations(ctx, panel, currentPath);
|
|
954
1063
|
return;
|
|
955
1064
|
}
|
|
956
1065
|
case "openImage": {
|
|
@@ -1000,6 +1109,7 @@ async function handleMessage(ctx, panel, raw) {
|
|
|
1000
1109
|
watchSource(ctx, panel, sourcePath);
|
|
1001
1110
|
await rememberLastPath(ctx, panel, sourcePath);
|
|
1002
1111
|
await sendDocument(panel, { path: sourcePath, markdown, title: documentTitle(markdown, sourcePath), draftRestored, draftConflict, diskMarkdown });
|
|
1112
|
+
await restoreInFlightOperations(ctx, panel, sourcePath);
|
|
1003
1113
|
} catch (error) {
|
|
1004
1114
|
ctx.logger.error(`pickFile() threw: ${error instanceof Error ? error.stack ?? error.message : String(error)}`);
|
|
1005
1115
|
await panel.postMessage({
|
|
@@ -1021,6 +1131,7 @@ async function handleMessage(ctx, panel, raw) {
|
|
|
1021
1131
|
watchSource(ctx, panel, sourcePath);
|
|
1022
1132
|
await rememberLastPath(ctx, panel, sourcePath);
|
|
1023
1133
|
await sendDocument(panel, { path: sourcePath, markdown, title: documentTitle(markdown, sourcePath), draftRestored, draftConflict, diskMarkdown });
|
|
1134
|
+
await restoreInFlightOperations(ctx, panel, sourcePath);
|
|
1024
1135
|
} catch (error) {
|
|
1025
1136
|
await panel.postMessage({ type: "error", message: `Cannot read file: ${error instanceof Error ? error.message : String(error)}` });
|
|
1026
1137
|
}
|
|
@@ -1077,6 +1188,10 @@ async function handleMessage(ctx, panel, raw) {
|
|
|
1077
1188
|
await startRewriteSession(ctx, panel, message);
|
|
1078
1189
|
return;
|
|
1079
1190
|
}
|
|
1191
|
+
case "cancelRewrite": {
|
|
1192
|
+
await cancelRewriteSession(ctx, panel, message);
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1080
1195
|
case "requestStyleSession": {
|
|
1081
1196
|
await startStyleSession(ctx, panel, message);
|
|
1082
1197
|
return;
|
|
@@ -1102,6 +1217,14 @@ async function handleMessage(ctx, panel, raw) {
|
|
|
1102
1217
|
}
|
|
1103
1218
|
return;
|
|
1104
1219
|
}
|
|
1220
|
+
case "saveLibraryGroups": {
|
|
1221
|
+
try {
|
|
1222
|
+
await writeLibraryGroups(ctx, message.libraryGroups);
|
|
1223
|
+
} catch (error) {
|
|
1224
|
+
ctx.logger.warn(`Could not save library group order: ${String(error)}`);
|
|
1225
|
+
}
|
|
1226
|
+
return;
|
|
1227
|
+
}
|
|
1105
1228
|
case "saveDraft": {
|
|
1106
1229
|
const sourcePath = String(message.path ?? "").trim();
|
|
1107
1230
|
if (!path3.isAbsolute(sourcePath)) return;
|
package/dist/panel.css
CHANGED
|
@@ -138,7 +138,7 @@ body.app-view .status-inline-btn:hover{background:var(--finch-bg-hover,var(--bg)
|
|
|
138
138
|
@media (prefers-reduced-motion:reduce){.confirm-overlay,.confirm-card{animation:none}}
|
|
139
139
|
.confirm-card p{margin:0 0 16px;font-size:13px;line-height:1.6;color:var(--text)}
|
|
140
140
|
.confirm-actions{display:flex;justify-content:flex-end;gap:8px}
|
|
141
|
-
.confirm-actions button{font:inherit;font-size:13px;border:1px solid var(--border);background:transparent;color:var(--text);border-radius:7px;padding:6px 12px;cursor:pointer}
|
|
141
|
+
.confirm-actions button{flex:none;white-space:nowrap;font:inherit;font-size:13px;border:1px solid var(--border);background:transparent;color:var(--text);border-radius:7px;padding:6px 12px;cursor:pointer}
|
|
142
142
|
.confirm-actions button:hover{background:var(--bg)}
|
|
143
143
|
.confirm-actions button.primary{border-color:var(--accent);background:var(--accent);color:#fff}
|
|
144
144
|
.confirm-actions button.primary:hover{filter:brightness(1.06)}
|
|
@@ -192,7 +192,7 @@ body.app-view .app-toolbar{display:flex!important}
|
|
|
192
192
|
.app-tool svg{display:block;width:17px;height:17px;stroke-width:1.8}.app-tool:hover:not(:disabled){background:var(--finch-bg-hover,var(--bg))}
|
|
193
193
|
.app-tool:disabled{opacity:.4;cursor:default}.app-tool.checked{color:var(--text);background:var(--finch-bg-active,color-mix(in srgb,var(--text) 10%,transparent))}.app-tool.dirty{background:transparent}
|
|
194
194
|
.app-tool-label{min-width:auto;padding:0 9px}.ic-save,.ic-save-check{display:inline-flex;align-items:center}.ic-save[hidden],.ic-save-check[hidden]{display:none}.app-menu-wrap{position:relative}.app-menu{position:absolute;z-index:32;top:calc(100% + 7px);right:0;min-width:174px;padding:5px;border:1px solid var(--border);border-radius:9px;background:var(--card);box-shadow:0 2px 8px rgba(0,0,0,.12)}
|
|
195
|
-
.app-menu button{display:flex;width:100%;align-items:center;justify-content:space-between;gap:12px;padding:7px 9px;border:0;border-radius:6px;background:transparent;color:var(--text);font:12px var(--finch-font-body,system-ui);text-align:left;cursor:pointer}.app-menu button:hover{background:var(--finch-bg-hover,var(--bg))}.app-menu button.checked{color:var(--text);background:var(--finch-bg-active,color-mix(in srgb,var(--text) 10%,transparent));font-weight:600}.app-menu hr{margin:5px 3px;border:0;border-top:1px solid var(--border)}
|
|
195
|
+
.app-menu button{display:flex;width:100%;align-items:center;justify-content:space-between;gap:12px;padding:7px 9px;border:0;border-radius:6px;background:transparent;color:var(--text);font:12px var(--finch-font-body,system-ui);text-align:left;cursor:pointer}.app-menu button:hover{background:var(--finch-bg-hover,var(--bg))}.app-menu button.checked{color:var(--text);background:var(--finch-bg-active,color-mix(in srgb,var(--text) 10%,transparent));font-weight:600}.app-menu button:disabled{color:var(--muted);cursor:default;opacity:.5}.app-menu button:disabled:hover{background:transparent}.app-menu hr{margin:5px 3px;border:0;border-top:1px solid var(--border)}
|
|
196
196
|
.app-document-meta{min-width:0;display:flex;flex-direction:column;gap:1px}.app-document-meta strong,.app-document-meta span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.app-document-meta strong{font-size:13px}.app-document-meta span{max-width:34vw;color:var(--muted);font-size:11px}
|
|
197
197
|
body.app-view .stage{display:grid;grid-template-columns:minmax(0,1fr) 6px var(--preview-width,480px);background:var(--bg)}
|
|
198
198
|
body.app-view .pane{position:relative;inset:auto;min-width:0;min-height:0}
|
|
@@ -219,7 +219,7 @@ body.app-view .empty{grid-column:1/-1;background:var(--bg);padding:54px 38px}
|
|
|
219
219
|
body.app-view .home{max-width:1040px}body.app-view #emptyNew{display:none}
|
|
220
220
|
body.app-view .actions{right:28px;bottom:28px}
|
|
221
221
|
.library-backdrop{position:fixed;z-index:39;inset:0;background:rgba(0,0,0,.24)}
|
|
222
|
-
.library-drawer{position:fixed;z-index:40;top:0;bottom:0;left:0;width:min(
|
|
222
|
+
.library-drawer{position:fixed;z-index:40;top:0;bottom:0;left:0;width:min(310px,88vw);padding:0;background:var(--card);border-right:1px solid var(--border);transform:translateX(-102%);transition:transform .18s ease;display:flex;flex-direction:column}
|
|
223
223
|
.library-drawer.open{transform:translateX(0)}.library-drawer>header{height:58px;display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border-bottom:1px solid var(--border)}
|
|
224
224
|
.library-drawer>header div{display:flex;flex-direction:column}.library-drawer>header span{font-size:11px;color:var(--muted)}.library-drawer>header>button{border:0;background:transparent;color:var(--muted);font-size:24px;cursor:pointer}
|
|
225
225
|
/* Specificity note: `.library-drawer>header div` above sets
|
|
@@ -248,7 +248,7 @@ body.app-view .actions{right:28px;bottom:28px}
|
|
|
248
248
|
path + time metadata instead of cramming all three into one text run. */
|
|
249
249
|
.library-groups{flex:1;overflow:auto;padding:10px 12px 20px}
|
|
250
250
|
.library-group{margin:0 0 8px;border:0;border-radius:9px}.library-group[open]{background:color-mix(in srgb,var(--text) 2%,transparent)}
|
|
251
|
-
.library-group summary{display:flex;align-items:center;gap:7px;min-height:32px;padding:0 9px;list-style:none;color:var(--muted);font-size:12px;font-weight:600;cursor:pointer;user-select:none;touch-action:none}.library-group summary::-webkit-details-marker{display:none}.library-group summary::before{content:'›';color:var(--muted);font-size:17px;font-weight:400;line-height:1;transform:rotate(0deg);transition:transform .14s ease}.library-group[open] summary::before{transform:rotate(90deg)}.library-group summary:hover{background:var(--finch-bg-hover,var(--bg));border-radius:8px}.library-group
|
|
251
|
+
.library-group summary{display:flex;align-items:center;gap:7px;min-height:32px;padding:0 9px;list-style:none;color:var(--muted);font-size:12px;font-weight:600;cursor:pointer;user-select:none;touch-action:none}.library-group summary::-webkit-details-marker{display:none}.library-group summary::before{content:'›';color:var(--muted);font-size:17px;font-weight:400;line-height:1;transform:rotate(0deg);transition:transform .14s ease}.library-group[open] summary::before{transform:rotate(90deg)}.library-group summary:hover{background:var(--finch-bg-hover,var(--bg));border-radius:8px}.library-group.dragging{opacity:.32}
|
|
252
252
|
.library-group-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--muted)}.library-group-count{margin-left:auto;color:var(--muted);font-size:11px;font-weight:400}.library-items{padding:0 4px 4px}
|
|
253
253
|
/* Custom drag ghost: a floating clone that follows the pointer, replacing
|
|
254
254
|
the browser's native (unstylable) HTML5 drag screenshot. Collapsed
|