Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/locales/de-DE/install.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"code_copy": "Code kopieren",
"code_collapse": "Einklappen",
"code_expand": "Ausklappen",
"code_fullscreen": "Code im Vollbild anzeigen",
"loading_title": "Skript wird geladen",
"loading_desc": "Skriptinhalt wird von der Quelle heruntergeladen und ausgewertet",
"loading_title_update": "Update-Details werden vorbereitet",
Expand Down
1 change: 1 addition & 0 deletions src/locales/en-US/install.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"code_copy": "Copy code",
"code_collapse": "Collapse",
"code_expand": "Expand",
"code_fullscreen": "View code full screen",
"loading_title": "Loading script",
"loading_desc": "Downloading and parsing the script content from the source",
"loading_title_update": "Preparing update details",
Expand Down
1 change: 1 addition & 0 deletions src/locales/ja-JP/install.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"code_copy": "コードをコピー",
"code_collapse": "折りたたむ",
"code_expand": "展開",
"code_fullscreen": "コードを全画面で表示",
"loading_title": "スクリプトを読み込み中",
"loading_desc": "ソースからスクリプトの内容をダウンロードして解析しています",
"loading_title_update": "更新の詳細を準備中",
Expand Down
1 change: 1 addition & 0 deletions src/locales/ko-KR/install.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"code_copy": "코드 복사",
"code_collapse": "접기",
"code_expand": "펼치기",
"code_fullscreen": "코드를 전체 화면으로 보기",
"loading_title": "스크립트 불러오는 중",
"loading_desc": "소스에서 스크립트 내용을 다운로드하고 분석하고 있습니다",
"loading_title_update": "업데이트 세부 정보를 준비하는 중",
Expand Down
1 change: 1 addition & 0 deletions src/locales/pt-BR/install.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"code_copy": "Copiar código",
"code_collapse": "Recolher",
"code_expand": "Expandir",
"code_fullscreen": "Ver código em tela cheia",
"loading_title": "Carregando script",
"loading_desc": "Baixando e analisando o conteúdo da origem do script",
"loading_title_update": "Preparando os detalhes da atualização",
Expand Down
1 change: 1 addition & 0 deletions src/locales/ru-RU/install.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"code_copy": "Копировать код",
"code_collapse": "Свернуть",
"code_expand": "Развернуть",
"code_fullscreen": "Открыть код на весь экран",
"loading_title": "Загрузка скрипта",
"loading_desc": "Загрузка и разбор содержимого скрипта из источника",
"loading_title_update": "Подготовка сведений об обновлении",
Expand Down
1 change: 1 addition & 0 deletions src/locales/tr-TR/install.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"code_copy": "Kodu kopyala",
"code_collapse": "Daralt",
"code_expand": "Genişlet",
"code_fullscreen": "Kodu tam ekran görüntüle",
"loading_title": "Betik yükleniyor",
"loading_desc": "Betik içeriği kaynaktan indiriliyor ve ayrıştırılıyor",
"loading_title_update": "Güncelleme ayrıntıları hazırlanıyor",
Expand Down
1 change: 1 addition & 0 deletions src/locales/vi-VN/install.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"code_copy": "Sao chép mã",
"code_collapse": "Thu gọn",
"code_expand": "Mở rộng",
"code_fullscreen": "Xem mã ở chế độ toàn màn hình",
"loading_title": "Đang tải script",
"loading_desc": "Đang tải xuống và phân tích nội dung script từ nguồn",
"loading_title_update": "Đang chuẩn bị chi tiết cập nhật",
Expand Down
1 change: 1 addition & 0 deletions src/locales/zh-CN/install.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"code_copy": "复制代码",
"code_collapse": "折叠",
"code_expand": "展开",
"code_fullscreen": "全屏查看代码",
"loading_title": "正在加载脚本",
"loading_desc": "正在从来源下载并解析脚本内容",
"loading_title_update": "正在准备更新详情",
Expand Down
1 change: 1 addition & 0 deletions src/locales/zh-TW/install.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"code_copy": "複製程式碼",
"code_collapse": "收合",
"code_expand": "展開",
"code_fullscreen": "全螢幕檢視程式碼",
"loading_title": "正在載入腳本",
"loading_desc": "正在從來源下載並解析腳本內容",
"loading_title_update": "正在準備更新詳情",
Expand Down
20 changes: 19 additions & 1 deletion src/pages/components/CodeEditor/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,16 @@ const h = vi.hoisted(() => {
removeDecorations: vi.fn(),
createDecorationsCollection: vi.fn(),
});
const diffModifiedEditor = makeEditor();
const diffEditor = {
...makeEditor(),
getModifiedEditor: vi.fn(() => diffModifiedEditor),
};
return {
resolvedTheme: "light" as string,
setTheme: vi.fn(),
createDiffEditor: vi.fn((_container?: unknown, _options?: any) => makeEditor()),
diffModifiedEditor,
createDiffEditor: vi.fn((_container?: unknown, _options?: any) => diffEditor),
create: vi.fn((_container?: unknown, _options?: any) => makeEditor()),
createModel: vi.fn(() => ({
dispose: vi.fn(),
Expand Down Expand Up @@ -125,4 +131,16 @@ describe("CodeEditor 可访问性与主题", () => {
});
expect(h.setTheme).toHaveBeenCalledWith("dark");
});

it("diff 编辑器创建后也应回调 onEditorMount", async () => {
const onEditorMount = vi.fn();

await act(async () => {
render(
<CodeEditor id="ed-diff-mount" code="const a = 2;" diffCode="const a = 1;" onEditorMount={onEditorMount} />
);
});

await waitFor(() => expect(onEditorMount).toHaveBeenCalledWith(h.diffModifiedEditor));
});
});
4 changes: 3 additions & 1 deletion src/pages/components/CodeEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ function CodeEditor({ id, className, code, diffCode, editable, onChange, onEdito

const initialTheme = resolveMonacoTheme(resolvedTheme);
if (diffCode) {
edit = editor.createDiffEditor(container, {
const diffEditor = editor.createDiffEditor(container, {
hideUnchangedRegions: { enabled: true },
enableSplitViewResizing: false,
renderSideBySide: false,
Expand All @@ -171,6 +171,7 @@ function CodeEditor({ id, className, code, diffCode, editable, onChange, onEdito
theme: initialTheme,
...commonEditorOptions,
});
edit = diffEditor;
// standalone model 不随 editor.dispose 自动清理,需手动跟踪并在 cleanup 释放
originalModel = editor.createModel(diffCode, "javascript");
modifiedModel = editor.createModel(code, "javascript");
Expand All @@ -180,6 +181,7 @@ function CodeEditor({ id, className, code, diffCode, editable, onChange, onEdito
});
editorInstanceRef.current = edit;
editorReadyRef.current = true;
onEditorMountRef.current?.(diffEditor.getModifiedEditor());
} else {
const standaloneEdit = editor.create(container, {
language: "javascript",
Expand Down
23 changes: 19 additions & 4 deletions src/pages/components/ui/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ function DialogPortal({ ...props }: React.ComponentProps<typeof DialogPrimitive.
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
}

function DialogTrigger({ ...props }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
}

function DialogOverlay({ className, ...props }: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
return (
<DialogPrimitive.Overlay
Expand All @@ -24,7 +28,13 @@ function DialogOverlay({ className, ...props }: React.ComponentProps<typeof Dial
);
}

function DialogContent({ className, children, ...props }: React.ComponentProps<typeof DialogPrimitive.Content>) {
function DialogContent({
className,
children,
closeLabel = "Close",
closeClassName,
...props
}: React.ComponentProps<typeof DialogPrimitive.Content> & { closeLabel?: string; closeClassName?: string }) {
return (
<DialogPortal>
<DialogOverlay />
Expand All @@ -37,9 +47,14 @@ function DialogContent({ className, children, ...props }: React.ComponentProps<t
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<DialogPrimitive.Close
className={cn(
"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground",
closeClassName
)}
>
<X className="h-4 w-4" />
<span className="sr-only">{"Close"}</span>
<span className="sr-only">{closeLabel}</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPortal>
Expand Down Expand Up @@ -86,4 +101,4 @@ function DialogDescription({ className, ...props }: React.ComponentProps<typeof
);
}

export { Dialog, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription };
export { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription };
72 changes: 71 additions & 1 deletion src/pages/install/components/CodePreview.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, it, expect, vi, beforeAll, afterEach } from "vitest";
import { render, screen, cleanup, fireEvent } from "@testing-library/react";
import { render, screen, cleanup, fireEvent, within, waitFor } from "@testing-library/react";
import { initTestLanguage } from "@Tests/initTestLanguage";

// Monaco 无法在 DOM 测试环境中渲染(需 worker),用轻量桩替换,仅暴露 props 供断言接线
Expand Down Expand Up @@ -54,6 +54,76 @@ describe("CodePreview 代码卡", () => {
expect(writeText).toHaveBeenCalledWith(code);
});

it("点击全页面查看后在占满视口的对话框中查看代码,并可退出", () => {
render(<CodePreview code={code} />);

const fullscreenButton = screen.getByTestId("code-fullscreen");
expect(fullscreenButton).toHaveAttribute("aria-label", "全屏查看代码");
fireEvent.click(fullscreenButton);

const dialog = screen.getByTestId("code-fullscreen-dialog");
expect(dialog).toHaveClass("left-0", "top-0", "h-dvh", "w-dvw", "max-w-none");
expect(within(dialog).getByRole("button", { name: "关闭" })).toHaveClass(
"rounded-md",
"flex",
"items-center",
"justify-center",
"text-muted-foreground",
"opacity-100",
"hover:bg-muted",
"hover:text-foreground",
"focus:ring-0",
"focus:ring-offset-0",
"focus-visible:outline-none",
"focus-visible:ring-2",
"focus-visible:ring-ring/50"
);
expect(within(dialog).getByTestId("code-body")).toHaveAttribute("data-code", code);

fireEvent.click(screen.getByRole("button", { name: "关闭" }));
expect(screen.queryByTestId("code-fullscreen-dialog")).not.toBeInTheDocument();
expect(screen.getByTestId("code-body")).toHaveAttribute("data-id", "install-code-preview");
});

it("更新态可在全屏预览中查看代码并隐藏加载骨架", () => {
const oldCode = "// old\nconst a = 0;";
render(<CodePreview code={code} oldCode={oldCode} />);

fireEvent.click(screen.getByTestId("code-fullscreen"));

const dialog = screen.getByTestId("code-fullscreen-dialog");
expect(within(dialog).getByTestId("code-body")).toHaveAttribute("data-diff", oldCode);
expect(within(dialog).queryByTestId("code-skeleton")).not.toBeInTheDocument();
});

it("按 Escape 关闭全屏并将焦点还给触发按钮", async () => {
render(<CodePreview code={code} />);

const fullscreenButton = screen.getByTestId("code-fullscreen");
fullscreenButton.focus();
fireEvent.click(fullscreenButton);
expect(screen.getByRole("dialog")).toHaveAttribute("aria-labelledby");

fireEvent.keyDown(document, { key: "Escape" });

await waitFor(() => {
expect(screen.queryByTestId("code-fullscreen-dialog")).not.toBeInTheDocument();
expect(document.activeElement).toBe(fullscreenButton);
});
});

it("默认折叠时仍可从全屏按钮打开代码", () => {
render(<CodePreview code={code} defaultCollapsed />);

expect(screen.queryByTestId("code-body")).not.toBeInTheDocument();
fireEvent.click(screen.getByTestId("code-fullscreen"));

expect(within(screen.getByTestId("code-fullscreen-dialog")).getByTestId("code-body")).toHaveAttribute(
"data-code",
code
);
});

it("提供 diff 统计时渲染 +N 与 −N", () => {
render(<CodePreview code={code} diffStat={{ added: 42, removed: 18 }} />);
expect(screen.getByText("+42")).toBeInTheDocument();
Expand Down
Loading
Loading