From 168a43e0e1e6685c8d08b40675a7e0a1bba176a2 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 23 Mar 2026 09:51:12 -0700 Subject: [PATCH] Save project: pick folder instead of file Changed save dialog from file picker (.vtn) to folder picker. The project name is derived from the folder name. Files are created inside the chosen folder: Folder/ Folder.vtn audio.wav Also: save-in-place for already-saved projects (Ctrl+S just saves, no dialog). Extracted buildProjectData() helper for reuse. Co-Authored-By: Claude Opus 4.6 --- src/routes/+page.svelte | 57 +++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 3fb5768..2fa5c79 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -140,23 +140,8 @@ // Speaker color palette for auto-assignment const speakerColors = ['#e94560', '#4ecdc4', '#ffe66d', '#a8e6cf', '#ff8b94', '#c7ceea', '#ffd93d', '#6bcb77']; - async function saveProject() { - const defaultName = currentProjectName || 'Untitled'; - const outputPath = await save({ - defaultPath: `${defaultName}.vtn`, - filters: [{ name: 'Voice to Notes Project', extensions: ['vtn'] }], - }); - if (!outputPath) return; - - // Derive folder path and file name from the chosen .vtn path - const vtnFileName = outputPath.split(/[\\/]/).pop() || `${defaultName}.vtn`; - const projectName = vtnFileName.replace(/\.vtn$/i, ''); - const parentDir = outputPath.replace(/[\\/][^\\/]+$/, ''); - const folderPath = `${parentDir}/${projectName}`; - const vtnInsideFolder = `${folderPath}/${vtnFileName}`; - const wavInsideFolder = `${folderPath}/audio.wav`; - - const projectData = { + function buildProjectData(projectName: string) { + return { version: 2, name: projectName, source_file: audioFilePath, @@ -184,10 +169,44 @@ color: s.color || '#e94560', })), }; + } + + async function saveProject() { + const defaultName = currentProjectName || 'Untitled'; + + // If already saved, save in place + if (currentProjectPath) { + const folderPath = currentProjectPath.replace(/[\\/][^\\/]+$/, ''); + const projectName = currentProjectPath.split(/[\\/]/).pop()?.replace(/\.vtn$/i, '') || defaultName; + const wavInsideFolder = `${folderPath}/audio.wav`; + + const projectData = buildProjectData(projectName); + try { + if (audioWavPath && audioWavPath !== wavInsideFolder) { + await invoke('copy_file', { src: audioWavPath, dst: wavInsideFolder }); + } + await invoke('save_project_file', { path: currentProjectPath, project: projectData }); + } catch (err) { + alert(`Failed to save: ${err}`); + } + return; + } + + // Pick a folder for the new project + const folderPath = await open({ + directory: true, + title: 'Choose a folder to save the project', + }); + if (!folderPath) return; + + // Use the folder name as the project name + const projectName = (folderPath as string).split(/[\\/]/).pop() || defaultName; + const vtnInsideFolder = `${folderPath}/${projectName}.vtn`; + const wavInsideFolder = `${folderPath}/audio.wav`; + + const projectData = buildProjectData(projectName); try { - // Create the project folder - await invoke('create_dir', { path: folderPath }); // Copy the extracted WAV into the project folder if (audioWavPath) {