Skip to content

Commit be4d225

Browse files
committed
refactor: update ConvertView to accept state as props, conditionally render empty/populated UI, and prepare conversion payload for Electron IPC.
1 parent 93c6d69 commit be4d225

9 files changed

Lines changed: 316 additions & 281 deletions

File tree

dist-electron/main.js

Lines changed: 60 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,57 @@
1-
import { app, BrowserWindow, ipcMain, dialog } from "electron";
2-
import path from "path";
3-
import { fileURLToPath } from "url";
4-
import fs from "fs/promises";
5-
const __dirname$1 = path.dirname(fileURLToPath(import.meta.url));
6-
const isDev = !!process.env.VITE_DEV_SERVER_URL;
7-
let mainWindow = null;
8-
function createWindow() {
9-
mainWindow = new BrowserWindow({
1+
import { app as l, BrowserWindow as a, ipcMain as n, dialog as d } from "electron";
2+
import t from "path";
3+
import { fileURLToPath as w } from "url";
4+
import c from "fs/promises";
5+
const r = t.dirname(w(import.meta.url)), m = !!process.env.VITE_DEV_SERVER_URL;
6+
let e = null;
7+
function p() {
8+
e = new a({
109
width: 1100,
1110
height: 750,
1211
minWidth: 800,
1312
minHeight: 600,
14-
frame: false,
13+
frame: !1,
1514
backgroundColor: "#0a0a0b",
1615
webPreferences: {
17-
preload: path.join(__dirname$1, "preload.js"),
18-
contextIsolation: true,
19-
nodeIntegration: false,
20-
sandbox: false
21-
}
22-
});
23-
mainWindow.on("maximize", () => {
24-
mainWindow?.webContents.send("window-maximized-changed", true);
25-
});
26-
mainWindow.on("unmaximize", () => {
27-
mainWindow?.webContents.send("window-maximized-changed", false);
28-
});
29-
mainWindow.on("closed", () => {
30-
mainWindow = null;
31-
});
32-
console.log("[main] isDev:", isDev);
33-
console.log("[main] VITE_DEV_SERVER_URL:", process.env.VITE_DEV_SERVER_URL);
34-
if (isDev) {
35-
mainWindow.loadURL(process.env.VITE_DEV_SERVER_URL);
36-
console.log("[main] Loaded dev URL, opening DevTools...");
37-
mainWindow?.webContents.openDevTools({ mode: "undocked" });
38-
} else {
39-
mainWindow.loadFile(path.join(__dirname$1, "../dist/index.html"));
40-
}
41-
mainWindow.once("ready-to-show", () => {
42-
console.log("[main] Window ready-to-show, opening DevTools...");
43-
mainWindow?.webContents.openDevTools({ mode: "undocked" });
44-
});
45-
ipcMain.on("toggle-dev-tools", () => {
46-
console.log("[main] toggle-dev-tools IPC received");
47-
if (mainWindow?.webContents.isDevToolsOpened()) {
48-
mainWindow.webContents.closeDevTools();
49-
} else {
50-
mainWindow?.webContents.openDevTools({ mode: "undocked" });
16+
preload: t.join(r, "preload.js"),
17+
contextIsolation: !0,
18+
nodeIntegration: !1,
19+
sandbox: !1,
20+
devTools: !0
5121
}
22+
}), e.on("maximize", () => {
23+
e?.webContents.send("window-maximized-changed", !0);
24+
}), e.on("unmaximize", () => {
25+
e?.webContents.send("window-maximized-changed", !1);
26+
}), e.on("closed", () => {
27+
e = null;
28+
}), console.log("[main] isDev:", m), console.log("[main] VITE_DEV_SERVER_URL:", process.env.VITE_DEV_SERVER_URL), m ? (e.loadURL(process.env.VITE_DEV_SERVER_URL), console.log("[main] Dev server URL loaded.")) : e.loadFile(t.join(r, "../dist/index.html"));
29+
let o = null;
30+
n.removeAllListeners("toggle-dev-tools"), n.on("toggle-dev-tools", () => {
31+
console.log("[main] toggle-dev-tools IPC received"), e && (e.webContents.isDevToolsOpened() ? (console.log("[main] Closing DevTools"), e.webContents.closeDevTools(), o && !o.isDestroyed() && o.close(), o = null) : (console.log("[main] Opening Custom DevTools Window"), (!o || o.isDestroyed()) && (o = new a({
32+
width: 800,
33+
height: 600,
34+
title: "OpenConvert Developer Tools"
35+
}), o.on("closed", () => {
36+
o = null;
37+
})), e.webContents.setDevToolsWebContents(o.webContents), e.webContents.openDevTools({ mode: "detach" })));
5238
});
5339
}
54-
app.whenReady().then(createWindow);
55-
app.on("window-all-closed", () => {
56-
if (process.platform !== "darwin") {
57-
app.quit();
58-
}
40+
l.whenReady().then(p);
41+
l.on("window-all-closed", () => {
42+
process.platform !== "darwin" && l.quit();
5943
});
60-
app.on("activate", () => {
61-
if (BrowserWindow.getAllWindows().length === 0) {
62-
createWindow();
63-
}
44+
l.on("activate", () => {
45+
a.getAllWindows().length === 0 && p();
6446
});
65-
ipcMain.on("window-minimize", () => mainWindow?.minimize());
66-
ipcMain.on("window-maximize", () => {
67-
if (mainWindow?.isMaximized()) {
68-
mainWindow.unmaximize();
69-
} else {
70-
mainWindow?.maximize();
71-
}
47+
n.on("window-minimize", () => e?.minimize());
48+
n.on("window-maximize", () => {
49+
e?.isMaximized() ? e.unmaximize() : e?.maximize();
7250
});
73-
ipcMain.on("window-close", () => mainWindow?.close());
74-
ipcMain.handle("open-file-dialog", async () => {
75-
if (!mainWindow) return [];
76-
const result = await dialog.showOpenDialog(mainWindow, {
51+
n.on("window-close", () => e?.close());
52+
n.handle("open-file-dialog", async () => {
53+
if (!e) return [];
54+
const o = await d.showOpenDialog(e, {
7755
properties: ["openFile", "multiSelections"],
7856
filters: [
7957
{
@@ -125,38 +103,36 @@ ipcMain.handle("open-file-dialog", async () => {
125103
{ name: "All Files", extensions: ["*"] }
126104
]
127105
});
128-
if (result.canceled) return [];
129-
const fileInfos = await Promise.all(
130-
result.filePaths.map(async (filePath) => {
131-
const stat = await fs.stat(filePath);
106+
return o.canceled ? [] : await Promise.all(
107+
o.filePaths.map(async (s) => {
108+
const f = await c.stat(s);
132109
return {
133-
path: filePath,
134-
name: path.basename(filePath),
135-
ext: path.extname(filePath).slice(1).toLowerCase(),
136-
size: stat.size
110+
path: s,
111+
name: t.basename(s),
112+
ext: t.extname(s).slice(1).toLowerCase(),
113+
size: f.size
137114
};
138115
})
139116
);
140-
return fileInfos;
141117
});
142-
ipcMain.handle("select-output-dir", async () => {
143-
if (!mainWindow) return null;
144-
const result = await dialog.showOpenDialog(mainWindow, {
118+
n.handle("select-output-dir", async () => {
119+
if (!e) return null;
120+
const o = await d.showOpenDialog(e, {
145121
properties: ["openDirectory", "createDirectory"]
146122
});
147-
if (result.canceled) return null;
148-
return result.filePaths[0];
123+
return o.canceled ? null : o.filePaths[0];
149124
});
150-
ipcMain.handle("get-file-info", async (_event, filePath) => {
125+
n.handle("get-file-info", async (o, i) => {
151126
try {
152-
const stat = await fs.stat(filePath);
127+
const s = await c.stat(i);
153128
return {
154-
path: filePath,
155-
name: path.basename(filePath),
156-
ext: path.extname(filePath).slice(1).toLowerCase(),
157-
size: stat.size
129+
path: i,
130+
name: t.basename(i),
131+
ext: t.extname(i).slice(1).toLowerCase(),
132+
size: s.size
158133
};
159134
} catch {
160135
return null;
161136
}
162137
});
138+
n.handle("convert-files", async (o, i) => (console.log("[main] Received conversion payload:", JSON.stringify(i, null, 2)), { success: !0 }));

dist-electron/preload.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
import { contextBridge, ipcRenderer } from "electron";
2-
contextBridge.exposeInMainWorld("electronAPI", {
1+
import { contextBridge as t, ipcRenderer as e } from "electron";
2+
t.exposeInMainWorld("electronAPI", {
33
// Window controls
4-
minimize: () => ipcRenderer.send("window-minimize"),
5-
maximize: () => ipcRenderer.send("window-maximize"),
6-
close: () => ipcRenderer.send("window-close"),
7-
toggleDevTools: () => ipcRenderer.send("toggle-dev-tools"),
4+
minimize: () => e.send("window-minimize"),
5+
maximize: () => e.send("window-maximize"),
6+
close: () => e.send("window-close"),
7+
toggleDevTools: () => e.send("toggle-dev-tools"),
88
// Window state listener
9-
onMaximizeChange: (callback) => {
10-
const handler = (_event, isMaximized) => callback(isMaximized);
11-
ipcRenderer.on("window-maximized-changed", handler);
12-
return () => ipcRenderer.removeListener("window-maximized-changed", handler);
9+
onMaximizeChange: (i) => {
10+
const n = (d, o) => i(o);
11+
return e.on("window-maximized-changed", n), () => e.removeListener("window-maximized-changed", n);
1312
},
1413
// File operations
15-
openFileDialog: () => ipcRenderer.invoke("open-file-dialog"),
16-
selectOutputDir: () => ipcRenderer.invoke("select-output-dir"),
17-
getFileInfo: (filePath) => ipcRenderer.invoke("get-file-info", filePath)
14+
openFileDialog: () => e.invoke("open-file-dialog"),
15+
selectOutputDir: () => e.invoke("select-output-dir"),
16+
getFileInfo: (i) => e.invoke("get-file-info", i),
17+
convertFiles: (i) => e.invoke("convert-files", i)
1818
});

electron/main.ts

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ function createWindow() {
2121
contextIsolation: true,
2222
nodeIntegration: false,
2323
sandbox: false,
24+
devTools: true,
2425
},
2526
})
2627

@@ -42,25 +43,41 @@ function createWindow() {
4243

4344
if (isDev) {
4445
mainWindow.loadURL(process.env.VITE_DEV_SERVER_URL!)
45-
console.log('[main] Loaded dev URL, opening DevTools...')
46-
mainWindow?.webContents.openDevTools({ mode: 'undocked' })
46+
console.log('[main] Dev server URL loaded.')
4747
} else {
4848
mainWindow.loadFile(path.join(__dirname, '../dist/index.html'))
4949
}
5050

51-
// Fallback: open DevTools after window is ready, unconditionally
52-
mainWindow.once('ready-to-show', () => {
53-
console.log('[main] Window ready-to-show, opening DevTools...')
54-
mainWindow?.webContents.openDevTools({ mode: 'undocked' })
55-
})
51+
let devToolsWindow: BrowserWindow | null = null
5652

57-
// Toggle DevTools via IPC from renderer
53+
ipcMain.removeAllListeners('toggle-dev-tools')
5854
ipcMain.on('toggle-dev-tools', () => {
5955
console.log('[main] toggle-dev-tools IPC received')
60-
if (mainWindow?.webContents.isDevToolsOpened()) {
56+
57+
if (!mainWindow) return
58+
59+
if (mainWindow.webContents.isDevToolsOpened()) {
60+
console.log('[main] Closing DevTools')
6161
mainWindow.webContents.closeDevTools()
62+
if (devToolsWindow && !devToolsWindow.isDestroyed()) {
63+
devToolsWindow.close()
64+
}
65+
devToolsWindow = null
6266
} else {
63-
mainWindow?.webContents.openDevTools({ mode: 'undocked' })
67+
console.log('[main] Opening Custom DevTools Window')
68+
if (!devToolsWindow || devToolsWindow.isDestroyed()) {
69+
devToolsWindow = new BrowserWindow({
70+
width: 800,
71+
height: 600,
72+
title: "OpenConvert Developer Tools"
73+
})
74+
devToolsWindow.on('closed', () => {
75+
devToolsWindow = null
76+
})
77+
}
78+
79+
mainWindow.webContents.setDevToolsWebContents(devToolsWindow.webContents)
80+
mainWindow.webContents.openDevTools({ mode: 'detach' })
6481
}
6582
})
6683
}
@@ -157,3 +174,13 @@ ipcMain.handle('get-file-info', async (_event, filePath: string) => {
157174
return null
158175
}
159176
})
177+
178+
// Convert files payload receiver
179+
ipcMain.handle('convert-files', async (_event, payload: { targetDirectory: string, filesToConvert: { sourcePath: string, targetFormat: string }[] }) => {
180+
console.log('[main] Received conversion payload:', JSON.stringify(payload, null, 2))
181+
182+
// TODO: Implement actual conversion logic here
183+
184+
// Simulate successful conversion for now
185+
return { success: true }
186+
})

electron/preload.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ contextBridge.exposeInMainWorld('electronAPI', {
1919
openFileDialog: () => ipcRenderer.invoke('open-file-dialog'),
2020
selectOutputDir: () => ipcRenderer.invoke('select-output-dir'),
2121
getFileInfo: (filePath: string) => ipcRenderer.invoke('get-file-info', filePath),
22+
convertFiles: (payload: { targetDirectory: string, filesToConvert: { sourcePath: string, targetFormat: string }[] }) => ipcRenderer.invoke('convert-files', payload),
2223
})

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
"main": "dist-electron/main.js",
77
"scripts": {
88
"dev": "vite",
9-
"build": "tsc -b && vite build",
10-
"build:electron": "tsc -b && vite build && electron-builder",
9+
"build:ts": "tsc -b && vite build",
10+
"build": "tsc -b && vite build && electron-builder",
1111
"lint": "eslint .",
1212
"preview": "vite preview"
1313
},

src/App.tsx

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,25 @@ import ConvertView from '@/views/ConvertView'
77
import PluginsView from '@/views/PluginsView'
88
import HistoryView from '@/views/HistoryView'
99
import SettingsView from '@/views/SettingsView'
10+
import type { ConvertFile } from '@/components/FileList'
1011

11-
function renderView(activeTab: Tab) {
12+
function renderView(
13+
activeTab: Tab,
14+
files: ConvertFile[],
15+
setFiles: React.Dispatch<React.SetStateAction<ConvertFile[]>>,
16+
outputDir: string | null,
17+
setOutputDir: React.Dispatch<React.SetStateAction<string | null>>
18+
) {
1219
switch (activeTab) {
1320
case 'convert':
14-
return <ConvertView />
21+
return (
22+
<ConvertView
23+
files={files}
24+
setFiles={setFiles}
25+
outputDir={outputDir}
26+
setOutputDir={setOutputDir}
27+
/>
28+
)
1529
case 'plugins':
1630
return <PluginsView />
1731
case 'history':
@@ -25,16 +39,32 @@ function App() {
2539
const [activeTab, setActiveTab] = useState<Tab>('convert')
2640
const [isSidebarExpanded, setIsSidebarExpanded] = useState(true)
2741

28-
// F12 / Ctrl+Shift+I to toggle DevTools (dev mode only)
42+
// Lifted state from ConvertView
43+
const [files, setFiles] = useState<ConvertFile[]>([])
44+
const [outputDir, setOutputDir] = useState<string | null>(null)
45+
46+
// Global handlers
2947
useEffect(() => {
48+
// F12 / Ctrl+Shift+I to toggle DevTools (dev mode only)
3049
const handleKeyDown = (e: KeyboardEvent) => {
3150
if (e.key === 'F12' || (e.ctrlKey && e.shiftKey && e.key === 'I')) {
3251
e.preventDefault()
3352
window.electronAPI.toggleDevTools()
3453
}
3554
}
55+
56+
// Prevent Electron from navigating when a file is dropped outside ConvertView
57+
const preventDragDrop = (e: DragEvent) => e.preventDefault()
58+
3659
window.addEventListener('keydown', handleKeyDown)
37-
return () => window.removeEventListener('keydown', handleKeyDown)
60+
window.addEventListener('dragover', preventDragDrop)
61+
window.addEventListener('drop', preventDragDrop)
62+
63+
return () => {
64+
window.removeEventListener('keydown', handleKeyDown)
65+
window.removeEventListener('dragover', preventDragDrop)
66+
window.removeEventListener('drop', preventDragDrop)
67+
}
3868
}, [])
3969

4070
return (
@@ -52,8 +82,8 @@ function App() {
5282
isSidebarExpanded={isSidebarExpanded}
5383
/>
5484

55-
<main className="flex-1 overflow-y-auto custom-scrollbar">
56-
{renderView(activeTab)}
85+
<main className="flex-1 flex flex-col overflow-y-auto custom-scrollbar">
86+
{renderView(activeTab, files, setFiles, outputDir, setOutputDir)}
5787
</main>
5888
</div>
5989
</div>

0 commit comments

Comments
 (0)