fix: project loading and add editable project name
Fixed project loading to restore all track properties and added inline project name editing in header. **AudioEditor.tsx:** - Added `loadTracks` from useMultiTrack hook - Fixed `handleLoadProject` to use `loadTracks()` instead of recreating tracks - Now properly restores all track properties (effects, automation, volume, pan, etc.) - Shows track count in success toast message - Added editable project name input in header - Positioned between logo and track actions - Auto-sizes based on text length - Saves on blur (triggers auto-save) - Smooth hover/focus transitions - Muted color that brightens on interaction **useMultiTrack.ts:** - Added `loadTracks()` method to replace all tracks at once - Enables proper project loading with full state restoration - Maintains all track properties during load **Fixes:** - Projects now load correctly with all tracks and their audio buffers - Track properties (effects, automation, volume, pan, etc.) fully restored - Project name can be edited inline in header - Auto-save triggers when project name changes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -95,6 +95,7 @@ export function AudioEditor() {
|
|||||||
removeTrack,
|
removeTrack,
|
||||||
updateTrack,
|
updateTrack,
|
||||||
clearTracks,
|
clearTracks,
|
||||||
|
loadTracks,
|
||||||
} = useMultiTrack();
|
} = useMultiTrack();
|
||||||
|
|
||||||
// Track whether we should auto-select on next add (when project is empty)
|
// Track whether we should auto-select on next add (when project is empty)
|
||||||
@@ -955,15 +956,8 @@ export function AudioEditor() {
|
|||||||
throw new Error('Project not found');
|
throw new Error('Project not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear current state
|
// Load tracks with all their properties restored
|
||||||
clearTracks();
|
loadTracks(projectData.tracks);
|
||||||
|
|
||||||
// Load tracks
|
|
||||||
for (const track of projectData.tracks) {
|
|
||||||
if (track.audioBuffer) {
|
|
||||||
addTrackFromBufferOriginal(track.audioBuffer, track.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore settings
|
// Restore settings
|
||||||
setZoom(projectData.settings.zoom);
|
setZoom(projectData.settings.zoom);
|
||||||
@@ -976,7 +970,7 @@ export function AudioEditor() {
|
|||||||
|
|
||||||
addToast({
|
addToast({
|
||||||
title: 'Project Loaded',
|
title: 'Project Loaded',
|
||||||
description: `"${projectData.metadata.name}" loaded successfully`,
|
description: `"${projectData.metadata.name}" loaded successfully (${projectData.tracks.length} track${projectData.tracks.length !== 1 ? 's' : ''})`,
|
||||||
variant: 'success',
|
variant: 'success',
|
||||||
duration: 2000,
|
duration: 2000,
|
||||||
});
|
});
|
||||||
@@ -989,7 +983,7 @@ export function AudioEditor() {
|
|||||||
duration: 3000,
|
duration: 3000,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [clearTracks, addTrackFromBufferOriginal, addToast]);
|
}, [loadTracks, addToast]);
|
||||||
|
|
||||||
// Delete project
|
// Delete project
|
||||||
const handleDeleteProject = React.useCallback(async (projectId: string) => {
|
const handleDeleteProject = React.useCallback(async (projectId: string) => {
|
||||||
@@ -1252,6 +1246,19 @@ export function AudioEditor() {
|
|||||||
<h1 className="text-lg font-bold text-foreground">Audio UI</h1>
|
<h1 className="text-lg font-bold text-foreground">Audio UI</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Project Name */}
|
||||||
|
<div className="flex items-center gap-2 border-l border-border pl-4">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={currentProjectName}
|
||||||
|
onChange={(e) => setCurrentProjectName(e.target.value)}
|
||||||
|
onBlur={handleSaveProject}
|
||||||
|
className="bg-transparent border-none outline-none text-sm font-medium text-muted-foreground hover:text-foreground focus:text-foreground transition-colors px-2 py-1 rounded hover:bg-accent/50 focus:bg-accent"
|
||||||
|
placeholder="Untitled Project"
|
||||||
|
style={{ width: `${Math.max(12, currentProjectName.length)}ch` }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Track Actions */}
|
{/* Track Actions */}
|
||||||
<div className="flex items-center gap-2 border-l border-border pl-4">
|
<div className="flex items-center gap-2 border-l border-border pl-4">
|
||||||
<Button variant="outline" size="sm" onClick={handleOpenProjectsDialog}>
|
<Button variant="outline" size="sm" onClick={handleOpenProjectsDialog}>
|
||||||
|
|||||||
@@ -120,6 +120,10 @@ export function useMultiTrack() {
|
|||||||
);
|
);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const loadTracks = useCallback((tracksToLoad: Track[]) => {
|
||||||
|
setTracks(tracksToLoad);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
tracks,
|
tracks,
|
||||||
addTrack,
|
addTrack,
|
||||||
@@ -129,5 +133,6 @@ export function useMultiTrack() {
|
|||||||
clearTracks,
|
clearTracks,
|
||||||
reorderTracks,
|
reorderTracks,
|
||||||
setTrackBuffer,
|
setTrackBuffer,
|
||||||
|
loadTracks,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user