feat(ui): refactor AppDetail layout and add download with save dialog

- Remove Tabs component, merge JS/CSS sections into single scrollable list
- Add sub-page navigation for code viewing with back button
- Put app name and buttons on same row to save vertical space
- Reduce DomainForm spacing (marginMD -> marginSM)
- Use FileCode/FileText icons to indicate JS/CSS file types
- Add save dialog for single file download with loading state
- Add IPC handlers: showSaveDialog, saveFileContent
- Fix duplicate file extension issue in download filenames
- Add i18n keys: backToList, downloadSuccess, downloadFailed, downloadAllSuccess
This commit is contained in:
2026-03-16 00:07:49 +08:00
parent 345f0b344c
commit 43820127f4
13 changed files with 377 additions and 136 deletions

View File

@@ -4,7 +4,7 @@
* Based on REQUIREMENTS.md:228-268
*/
import { ipcMain } from "electron";
import { ipcMain, dialog } from "electron";
import { v4 as uuidv4 } from "uuid";
import {
saveDomain,
@@ -573,6 +573,39 @@ export function registerIpcHandlers(): void {
registerGetLocale();
registerSetLocale();
// Dialog
registerShowSaveDialog();
registerSaveFileContent();
console.log("IPC handlers registered");
}
// ==================== Dialog IPC Handlers ====================
/**
* Show save dialog
*/
function registerShowSaveDialog(): void {
handle<{ defaultPath?: string }, string | null>("showSaveDialog", async (params) => {
const result = await dialog.showSaveDialog({
defaultPath: params.defaultPath,
filters: [
{ name: "JavaScript", extensions: ["js"] },
{ name: "CSS", extensions: ["css"] },
{ name: "All Files", extensions: ["*"] },
],
});
return result.filePath || null;
});
}
/**
* Save file content to disk
*/
function registerSaveFileContent(): void {
handle<{ filePath: string; content: string }, void>("saveFileContent", async (params) => {
const fs = await import("fs");
const buffer = Buffer.from(params.content, "base64");
await fs.promises.writeFile(params.filePath, buffer);
});
}