feat: add manual save with Ctrl+S and suppress auto-save toasts
Changes: - Modified handleSaveProject to accept showToast parameter (default: false) - Auto-saves now run silently without toast notifications - Added Ctrl+S / Cmd+S keyboard shortcut for manual save with toast - Added "Save Project" and "Open Projects" to command palette - Error toasts still shown for all save failures This provides the best of both worlds: - Automatic background saves don't interrupt the user - Manual saves (Ctrl+S or command palette) provide confirmation - Users can work without being constantly notified 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -887,7 +887,7 @@ export function AudioEditor() {
|
|||||||
currentTimeRef.current = currentTime;
|
currentTimeRef.current = currentTime;
|
||||||
}, [currentTime]);
|
}, [currentTime]);
|
||||||
|
|
||||||
const handleSaveProject = React.useCallback(async () => {
|
const handleSaveProject = React.useCallback(async (showToast = false) => {
|
||||||
if (tracks.length === 0) return;
|
if (tracks.length === 0) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -920,14 +920,18 @@ export function AudioEditor() {
|
|||||||
// Save last project ID to localStorage for auto-load on next visit
|
// Save last project ID to localStorage for auto-load on next visit
|
||||||
localStorage.setItem('audio-ui-last-project', projectId);
|
localStorage.setItem('audio-ui-last-project', projectId);
|
||||||
|
|
||||||
addToast({
|
// Only show toast for manual saves
|
||||||
title: 'Project Saved',
|
if (showToast) {
|
||||||
description: `"${currentProjectName}" saved successfully`,
|
addToast({
|
||||||
variant: 'success',
|
title: 'Project Saved',
|
||||||
duration: 2000,
|
description: `"${currentProjectName}" saved successfully`,
|
||||||
});
|
variant: 'success',
|
||||||
|
duration: 2000,
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to save project:', error);
|
console.error('Failed to save project:', error);
|
||||||
|
// Always show error toasts
|
||||||
addToast({
|
addToast({
|
||||||
title: 'Save Failed',
|
title: 'Save Failed',
|
||||||
description: 'Could not save project',
|
description: 'Could not save project',
|
||||||
@@ -1173,6 +1177,22 @@ export function AudioEditor() {
|
|||||||
category: 'playback',
|
category: 'playback',
|
||||||
action: stop,
|
action: stop,
|
||||||
},
|
},
|
||||||
|
// Project
|
||||||
|
{
|
||||||
|
id: 'save-project',
|
||||||
|
label: 'Save Project',
|
||||||
|
description: 'Save current project',
|
||||||
|
shortcut: 'Ctrl+S',
|
||||||
|
category: 'file',
|
||||||
|
action: () => handleSaveProject(true),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'open-projects',
|
||||||
|
label: 'Open Projects',
|
||||||
|
description: 'Open projects dialog',
|
||||||
|
category: 'file',
|
||||||
|
action: handleOpenProjectsDialog,
|
||||||
|
},
|
||||||
// View
|
// View
|
||||||
{
|
{
|
||||||
id: 'zoom-in',
|
id: 'zoom-in',
|
||||||
@@ -1219,7 +1239,7 @@ export function AudioEditor() {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
return actions;
|
return actions;
|
||||||
}, [play, pause, stop, handleZoomIn, handleZoomOut, handleFitToView, handleImportTracks, handleClearTracks, addTrack]);
|
}, [play, pause, stop, handleSaveProject, handleOpenProjectsDialog, handleZoomIn, handleZoomOut, handleFitToView, handleImportTracks, handleClearTracks, addTrack]);
|
||||||
|
|
||||||
// Keyboard shortcuts
|
// Keyboard shortcuts
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
@@ -1275,6 +1295,13 @@ export function AudioEditor() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ctrl/Cmd+S: Save project (manual save with toast)
|
||||||
|
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
|
||||||
|
e.preventDefault();
|
||||||
|
handleSaveProject(true); // Show toast for manual saves
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Ctrl/Cmd+D: Duplicate
|
// Ctrl/Cmd+D: Duplicate
|
||||||
if ((e.ctrlKey || e.metaKey) && e.key === 'd') {
|
if ((e.ctrlKey || e.metaKey) && e.key === 'd') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -1298,7 +1325,7 @@ export function AudioEditor() {
|
|||||||
|
|
||||||
window.addEventListener('keydown', handleKeyDown);
|
window.addEventListener('keydown', handleKeyDown);
|
||||||
return () => window.removeEventListener('keydown', handleKeyDown);
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
||||||
}, [togglePlayPause, canUndo, canRedo, undo, redo, handleCut, handleCopy, handlePaste, handleDelete, handleDuplicate]);
|
}, [togglePlayPause, canUndo, canRedo, undo, redo, handleCut, handleCopy, handlePaste, handleDelete, handleDuplicate, handleSaveProject]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
Reference in New Issue
Block a user