feat: implement Phase 12.3 - Project Export/Import

Added full export/import functionality for projects:

Export Features:
- Export button for each project in Projects dialog
- Downloads project as JSON file with all data
- Includes tracks, audio buffers, effects, automation, settings
- Filename format: {project_name}_{timestamp}.json

Import Features:
- Import button in Projects dialog header
- File picker for .json files
- Automatically generates new project ID to avoid conflicts
- Appends "(Imported)" to project name
- Preserves all project data

This enables:
- Backup of projects outside the browser
- Sharing projects with collaborators
- Migration between computers/browsers
- Version snapshots at different stages

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-19 10:25:06 +01:00
parent 9ad504478d
commit a626427142
3 changed files with 150 additions and 1 deletions

View File

@@ -210,3 +210,64 @@ export async function duplicateProject(sourceProjectId: string, newName: string)
await saveProject(newProject);
return newId;
}
/**
* Export project as JSON file
*/
export async function exportProjectAsJSON(projectId: string): Promise<void> {
const project = await loadProject(projectId);
if (!project) throw new Error('Project not found');
// Convert the project to JSON
const json = JSON.stringify(project, null, 2);
// Create blob and download
const blob = new Blob([json], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${project.metadata.name.replace(/[^a-z0-9]/gi, '_').toLowerCase()}_${Date.now()}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
/**
* Import project from JSON file
*/
export async function importProjectFromJSON(file: File): Promise<string> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = async (e) => {
try {
const json = e.target?.result as string;
const project = JSON.parse(json) as ProjectData;
// Generate new ID to avoid conflicts
const newId = generateProjectId();
const now = Date.now();
const importedProject: ProjectData = {
...project,
metadata: {
...project.metadata,
id: newId,
name: `${project.metadata.name} (Imported)`,
createdAt: now,
updatedAt: now,
},
};
await saveProject(importedProject);
resolve(newId);
} catch (error) {
reject(new Error('Failed to parse project file'));
}
};
reader.onerror = () => reject(new Error('Failed to read file'));
reader.readAsText(file);
});
}