Skip to content

Commit cf2df4f

Browse files
committed
fix(editor): improve formula source editing
Keep display math source editing open for line edits, add live source highlighting and preview behavior, and normalize related test fixtures to synthetic English content.
1 parent fb7f976 commit cf2df4f

19 files changed

Lines changed: 566 additions & 216 deletions

apps/desktop/src/App.test.tsx

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ describe("Markra workspace", () => {
156156
expect(screen.getByLabelText("Markdown editor")).toBeInTheDocument();
157157
expect(screen.getByLabelText("Markdown editor")).toHaveAttribute("data-editor-engine", "milkdown");
158158
expect(container.querySelector("[data-milkdown-root]")).toBeInTheDocument();
159-
expect(screen.queryByText("文件")).not.toBeInTheDocument();
159+
expect(screen.queryByText("File")).not.toBeInTheDocument();
160160
expect(container.querySelector(".native-title")).toBeInTheDocument();
161161
expect(screen.getByRole("button", { name: "Toggle file list" })).toBeInTheDocument();
162162
expect(container.querySelector(".quiet-status")?.closest(".editor-content-slot")).toBeInTheDocument();
@@ -546,14 +546,14 @@ describe("Markra workspace", () => {
546546
expect(document.documentElement).toHaveAttribute("data-window", "settings");
547547

548548
fireEvent.change(languageSelect!, {
549-
target: { value: "zh-CN" }
549+
target: { value: "fr" }
550550
});
551-
await waitFor(() => expect(mockedSaveStoredLanguage).toHaveBeenCalledWith("zh-CN"));
552-
await waitFor(() => expect(mockedNotifyAppLanguageChanged).toHaveBeenCalledWith("zh-CN"));
551+
await waitFor(() => expect(mockedSaveStoredLanguage).toHaveBeenCalledWith("fr"));
552+
await waitFor(() => expect(mockedNotifyAppLanguageChanged).toHaveBeenCalledWith("fr"));
553553

554554
fireEvent.click(categoryButtons[5]);
555555
expect(categoryButtons[5]).toHaveAttribute("aria-current", "page");
556-
const themeSelect = screen.getByRole("combobox", { name: "颜色主题" });
556+
const themeSelect = screen.getByRole("combobox");
557557
expect(themeSelect).toHaveValue("light");
558558
expect(screen.getByRole("option", { name: "Night" })).toBeInTheDocument();
559559
fireEvent.change(themeSelect, { target: { value: "night" } });
@@ -563,7 +563,7 @@ describe("Markra workspace", () => {
563563
await waitFor(() => expect(mockedNotifyAppThemeChanged).toHaveBeenCalledWith("night"));
564564

565565
fireEvent.change(themeSelect, { target: { value: "custom" } });
566-
const customCss = await screen.findByRole("textbox", { name: "自定义主题 CSS" });
566+
const customCss = await screen.findByRole("textbox");
567567
fireEvent.change(customCss, {
568568
target: { value: ":root[data-theme=\"custom\"] { --accent: #0969da; }" }
569569
});
@@ -2696,7 +2696,7 @@ describe("Markra workspace", () => {
26962696

26972697
it("saves expanded link source as markdown instead of escaped text", async () => {
26982698
mockOpenMarkdownFile({
2699-
content: "[关于我们](https://m.techflowpost.com/article/9424)",
2699+
content: "[About us](https://example.test/articles/about)",
27002700
name: "native.md",
27012701
path: mockNativePath
27022702
});
@@ -2708,11 +2708,11 @@ describe("Markra workspace", () => {
27082708

27092709
fireEvent.keyDown(window, { key: "o", metaKey: true });
27102710

2711-
const link = await screen.findByText("关于我们");
2711+
const link = await screen.findByText("About us");
27122712
fireEvent.click(link.closest("a")!);
27132713

27142714
expect(container.querySelector(".ProseMirror")?.textContent).toBe(
2715-
"[关于我们](https://m.techflowpost.com/article/9424)"
2715+
"[About us](https://example.test/articles/about)"
27162716
);
27172717

27182718
fireEvent.keyDown(window, { key: "s", metaKey: true });
@@ -2726,9 +2726,9 @@ describe("Markra workspace", () => {
27262726
)
27272727
);
27282728
const savedContents = mockedSaveNativeMarkdownFile.mock.calls.at(-1)?.[0].contents ?? "";
2729-
expect(savedContents).toContain("[关于我们](https://m.techflowpost.com/article/9424)");
2730-
expect(savedContents).not.toContain("\\[关于我们\\]");
2731-
expect(savedContents).not.toContain("\\(https\\://m.techflowpost.com/article/9424\\)");
2729+
expect(savedContents).toContain("[About us](https://example.test/articles/about)");
2730+
expect(savedContents).not.toContain("\\[About us\\]");
2731+
expect(savedContents).not.toContain("\\(https\\://example.test/articles/about\\)");
27322732
});
27332733

27342734
it("opens relative markdown links inside the current folder workspace", async () => {

apps/desktop/src/components/AiAgentPanel.test.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -305,13 +305,13 @@ describe("AiAgentPanel", () => {
305305

306306
it("does not send when Enter confirms an IME composition", () => {
307307
function Harness() {
308-
const [draft, setDraft] = useState("都有什么ai");
308+
const [draft, setDraft] = useState("Which AI models are available?");
309309
const [messages, setMessages] = useState<{ id: number; role: "assistant" | "user"; text: string }[]>([]);
310310

311311
return (
312312
<AiAgentPanel
313313
draft={draft}
314-
language="zh-CN"
314+
language="en"
315315
messages={messages}
316316
open
317317
onClose={() => {}}
@@ -329,13 +329,13 @@ describe("AiAgentPanel", () => {
329329

330330
render(<Harness />);
331331

332-
const input = screen.getByRole("textbox", { name: "Markra AI 消息" });
332+
const input = screen.getByRole("textbox", { name: "Markra AI message" });
333333
fireEvent.compositionStart(input);
334334
fireEvent.keyDown(input, { key: "Enter", nativeEvent: { isComposing: true, keyCode: 229 } });
335335
fireEvent.compositionEnd(input);
336336

337337
expect(screen.queryByRole("list")).not.toBeInTheDocument();
338-
expect(input).toHaveValue("都有什么ai");
338+
expect(input).toHaveValue("Which AI models are available?");
339339
});
340340

341341
it("keeps the transcript scrolled to the newest streamed message", async () => {

apps/desktop/src/components/AiCommandBar.test.tsx

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ describe("AiCommandBar", () => {
311311
it("shows a quiet thinking status while AI is running", () => {
312312
render(
313313
<AiCommandBar
314-
language="zh-CN"
314+
language="en"
315315
open
316316
prompt="rewrite"
317317
submitting
@@ -323,9 +323,9 @@ describe("AiCommandBar", () => {
323323

324324
const status = screen.getByRole("status");
325325

326-
expect(status).toHaveTextContent(/^$/);
326+
expect(status).toHaveTextContent(/^Thinking$/);
327327
expect(status).toHaveClass("text-(--text-secondary)");
328-
expect(screen.getByText("正在思考")).toHaveClass("ai-command-thinking-text");
328+
expect(screen.getByText("Thinking")).toHaveClass("ai-command-thinking-text");
329329
expect(screen.queryByText("Reading context")).not.toBeInTheDocument();
330330
expect(screen.queryByText("Generating suggestion")).not.toBeInTheDocument();
331331
});
@@ -334,23 +334,23 @@ describe("AiCommandBar", () => {
334334
render(
335335
<AiCommandBar
336336
externalActionPending
337-
language="zh-CN"
337+
language="en"
338338
open
339-
prompt="润色"
339+
prompt="Polish"
340340
submitting={false}
341341
onClose={vi.fn()}
342342
onPromptChange={vi.fn()}
343343
onSubmit={vi.fn()}
344344
/>
345345
);
346346

347-
const input = screen.getByRole("textbox", { name: "AI 命令" });
347+
const input = screen.getByRole("textbox", { name: "AI command" });
348348
const status = screen.getByRole("status");
349349
const commandBox = input.closest(".ai-command-box");
350350

351351
expect(input).toHaveAttribute("readonly");
352352
expect(input).toHaveAttribute("aria-busy", "true");
353-
expect(status).toHaveTextContent(/^$/);
353+
expect(status).toHaveTextContent(/^Thinking$/);
354354
expect(commandBox).toHaveClass("min-h-21", "rounded-lg", "border-(--ai-command-expanded-border)");
355355
expect(commandBox).not.toHaveClass("h-14", "rounded-xl");
356356
});
@@ -383,17 +383,17 @@ describe("AiCommandBar", () => {
383383

384384
render(
385385
<AiCommandBar
386-
language="zh-CN"
386+
language="en"
387387
open
388-
prompt="都有什么ai"
388+
prompt="Which AI models are available?"
389389
submitting={false}
390390
onClose={vi.fn()}
391391
onPromptChange={onPromptChange}
392392
onSubmit={onSubmit}
393393
/>
394394
);
395395

396-
const input = screen.getByRole("textbox", { name: "AI 命令" });
396+
const input = screen.getByRole("textbox", { name: "AI command" });
397397
fireEvent.compositionStart(input);
398398
fireEvent.keyDown(input, { key: "Enter", nativeEvent: { isComposing: true, keyCode: 229 } });
399399
fireEvent.compositionEnd(input);
@@ -537,7 +537,7 @@ describe("AiCommandBar", () => {
537537

538538
render(
539539
<AiCommandBar
540-
language="zh-CN"
540+
language="en"
541541
open
542542
prompt=""
543543
submitting={false}
@@ -547,26 +547,26 @@ describe("AiCommandBar", () => {
547547
/>
548548
);
549549

550-
fireEvent.click(screen.getByRole("textbox", { name: "AI 命令" }));
551-
fireEvent.click(await screen.findByRole("button", { name: "翻译" }));
550+
fireEvent.click(screen.getByRole("textbox", { name: "AI command" }));
551+
fireEvent.click(await screen.findByRole("button", { name: "Translate" }));
552552

553553
expect(onPromptChange).toHaveBeenCalledWith(
554-
defaultAiQuickActionPrompt("translate", "Simplified Chinese")
554+
defaultAiQuickActionPrompt("translate", "English")
555555
);
556556
expect(onSubmit).toHaveBeenCalledWith(
557-
defaultAiQuickActionPrompt("translate", "Simplified Chinese"),
557+
defaultAiQuickActionPrompt("translate", "English"),
558558
"translate"
559559
);
560560
});
561561

562562
it("keeps quick action generation in the compact input style", async () => {
563563
const onPromptChange = vi.fn();
564564
const onSubmit = vi.fn();
565-
const chinesePolishPrompt = defaultAiQuickActionPrompt("polish", "Simplified Chinese");
565+
const englishPolishPrompt = defaultAiQuickActionPrompt("polish", "English");
566566

567567
const { rerender } = render(
568568
<AiCommandBar
569-
language="zh-CN"
569+
language="en"
570570
open
571571
prompt=""
572572
submitting={false}
@@ -576,14 +576,14 @@ describe("AiCommandBar", () => {
576576
/>
577577
);
578578

579-
fireEvent.click(screen.getByRole("textbox", { name: "AI 命令" }));
580-
fireEvent.click(await screen.findByRole("button", { name: "润色" }));
579+
fireEvent.click(screen.getByRole("textbox", { name: "AI command" }));
580+
fireEvent.click(await screen.findByRole("button", { name: "Polish" }));
581581

582582
rerender(
583583
<AiCommandBar
584-
language="zh-CN"
584+
language="en"
585585
open
586-
prompt={chinesePolishPrompt}
586+
prompt={englishPolishPrompt}
587587
submitting
588588
onClose={vi.fn()}
589589
onInterrupt={vi.fn()}
@@ -595,14 +595,14 @@ describe("AiCommandBar", () => {
595595
const status = screen.getByRole("status");
596596
const commandBox = status.closest(".ai-command-box");
597597

598-
expect(onPromptChange).toHaveBeenCalledWith(chinesePolishPrompt);
599-
expect(onSubmit).toHaveBeenCalledWith(chinesePolishPrompt, "polish");
600-
expect(status).toHaveTextContent("润色中……");
601-
expect(screen.getByText("润色中……")).toHaveClass("ai-command-inline-loading-text");
598+
expect(onPromptChange).toHaveBeenCalledWith(englishPolishPrompt);
599+
expect(onSubmit).toHaveBeenCalledWith(englishPolishPrompt, "polish");
600+
expect(status).toHaveTextContent("Polishing...");
601+
expect(screen.getByText("Polishing...")).toHaveClass("ai-command-inline-loading-text");
602602
expect(commandBox).toHaveClass("h-14", "rounded-xl", "border-(--border-default)");
603603
expect(commandBox).not.toHaveClass("min-h-21", "border-(--ai-command-expanded-border)");
604-
expect(screen.queryByRole("combobox", { name: "AI 模型" })).not.toBeInTheDocument();
605-
expect(screen.getByRole("button", { name: "中断 AI 命令" })).toBeInTheDocument();
604+
expect(screen.queryByRole("combobox", { name: "AI model" })).not.toBeInTheDocument();
605+
expect(screen.getByRole("button", { name: "Stop AI command" })).toBeInTheDocument();
606606
});
607607

608608
it("keeps the compact command input vertically centered", () => {
@@ -680,9 +680,9 @@ describe("AiCommandBar", () => {
680680

681681
render(
682682
<AiCommandBar
683-
language="zh-CN"
683+
language="en"
684684
open
685-
prompt="润色"
685+
prompt="Polish"
686686
selectedProviderId="deepseek"
687687
submitting={false}
688688
supportsThinking
@@ -692,12 +692,12 @@ describe("AiCommandBar", () => {
692692
/>
693693
);
694694

695-
const input = screen.getByRole("textbox", { name: "AI 命令" });
695+
const input = screen.getByRole("textbox", { name: "AI command" });
696696
fireEvent.click(input);
697-
fireEvent.click(screen.getByRole("button", { name: "深度思考" }));
697+
fireEvent.click(screen.getByRole("button", { name: "Deep thinking" }));
698698
fireEvent.keyDown(input, { key: "Enter" });
699699

700-
expect(screen.getByRole("button", { name: "深度思考" })).toHaveAttribute("aria-pressed", "true");
700+
expect(screen.getByRole("button", { name: "Deep thinking" })).toHaveAttribute("aria-pressed", "true");
701701
expect(onSubmit).toHaveBeenCalledWith(undefined, "custom", { thinkingEnabled: true });
702702
});
703703
});

apps/desktop/src/components/AiSelectionToolbar.test.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,18 @@ describe("AiSelectionToolbar", () => {
4141
render(
4242
<AiSelectionToolbar
4343
anchor={anchor}
44-
language="zh-CN"
44+
language="en"
4545
open
4646
onOpenCommand={vi.fn()}
4747
onRunAction={onRunAction}
4848
/>
4949
);
5050

51-
fireEvent.click(screen.getByRole("button", { name: "翻译" }));
51+
fireEvent.click(screen.getByRole("button", { name: "Translate" }));
5252

5353
expect(onRunAction).toHaveBeenCalledWith(
5454
"translate",
55-
defaultAiQuickActionPrompt("translate", "Simplified Chinese")
55+
defaultAiQuickActionPrompt("translate", "English")
5656
);
5757
});
5858

@@ -62,20 +62,20 @@ describe("AiSelectionToolbar", () => {
6262
render(
6363
<AiSelectionToolbar
6464
anchor={anchor}
65-
language="zh-CN"
65+
language="en"
6666
open
6767
quickActionPrompts={{
6868
...defaultAiQuickActionPrompts,
69-
polish: "让选中的内容更清晰"
69+
polish: "Make the selected text clearer."
7070
}}
7171
onOpenCommand={vi.fn()}
7272
onRunAction={onRunAction}
7373
/>
7474
);
7575

76-
fireEvent.click(screen.getByRole("button", { name: "润色" }));
76+
fireEvent.click(screen.getByRole("button", { name: "Polish" }));
7777

78-
expect(onRunAction).toHaveBeenCalledWith("polish", "让选中的内容更清晰");
78+
expect(onRunAction).toHaveBeenCalledWith("polish", "Make the selected text clearer.");
7979
});
8080

8181
it("opens the full command input for a custom instruction", () => {

0 commit comments

Comments
 (0)