Added comprehensive undo/redo functionality: - Command pattern interface and base classes - HistoryManager with 50-operation stack - EditCommand for all edit operations (cut, delete, paste, trim) - Full keyboard shortcuts (Ctrl+Z undo, Ctrl+Y/Ctrl+Shift+Z redo) - HistoryControls UI component with visual feedback - Integrated history system with all edit operations - Toast notifications for undo/redo actions - History state tracking and display New files: - lib/history/command.ts - Command interface and BaseCommand - lib/history/history-manager.ts - HistoryManager class - lib/history/commands/edit-command.ts - EditCommand and factory functions - lib/hooks/useHistory.ts - React hook for history management - components/editor/HistoryControls.tsx - History UI component Modified files: - components/editor/AudioEditor.tsx - Integrated history system - components/editor/EditControls.tsx - Updated keyboard shortcuts display 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
140 lines
3.9 KiB
TypeScript
140 lines
3.9 KiB
TypeScript
'use client';
|
|
|
|
import * as React from 'react';
|
|
import { Scissors, Copy, Clipboard, Trash2, CropIcon, Info } from 'lucide-react';
|
|
import { Button } from '@/components/ui/Button';
|
|
import { cn } from '@/lib/utils/cn';
|
|
import type { Selection } from '@/types/selection';
|
|
import { formatDuration } from '@/lib/audio/decoder';
|
|
|
|
export interface EditControlsProps {
|
|
selection: Selection | null;
|
|
hasClipboard: boolean;
|
|
onCut: () => void;
|
|
onCopy: () => void;
|
|
onPaste: () => void;
|
|
onDelete: () => void;
|
|
onTrim: () => void;
|
|
onClearSelection: () => void;
|
|
className?: string;
|
|
}
|
|
|
|
export function EditControls({
|
|
selection,
|
|
hasClipboard,
|
|
onCut,
|
|
onCopy,
|
|
onPaste,
|
|
onDelete,
|
|
onTrim,
|
|
onClearSelection,
|
|
className,
|
|
}: EditControlsProps) {
|
|
const hasSelection = selection !== null;
|
|
const selectionDuration = selection ? selection.end - selection.start : 0;
|
|
|
|
return (
|
|
<div className={cn('space-y-4', className)}>
|
|
{/* Selection Info */}
|
|
{hasSelection && (
|
|
<div className="rounded-lg border border-info bg-info/10 p-3">
|
|
<div className="flex items-start gap-2">
|
|
<Info className="h-4 w-4 text-info-foreground mt-0.5 flex-shrink-0" />
|
|
<div className="flex-1 min-w-0 text-sm">
|
|
<p className="font-medium text-info-foreground">Selection Active</p>
|
|
<p className="text-info-foreground/90 mt-1">
|
|
Duration: {formatDuration(selectionDuration)} |
|
|
Start: {formatDuration(selection.start)} |
|
|
End: {formatDuration(selection.end)}
|
|
</p>
|
|
<p className="text-xs text-info-foreground/75 mt-1">
|
|
Tip: Hold Shift and drag on the waveform to select a region
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Edit Buttons */}
|
|
<div className="grid grid-cols-2 gap-2">
|
|
<Button
|
|
variant="outline"
|
|
onClick={onCut}
|
|
disabled={!hasSelection}
|
|
title="Cut (Ctrl+X)"
|
|
className="justify-start"
|
|
>
|
|
<Scissors className="h-4 w-4 mr-2" />
|
|
Cut
|
|
</Button>
|
|
|
|
<Button
|
|
variant="outline"
|
|
onClick={onCopy}
|
|
disabled={!hasSelection}
|
|
title="Copy (Ctrl+C)"
|
|
className="justify-start"
|
|
>
|
|
<Copy className="h-4 w-4 mr-2" />
|
|
Copy
|
|
</Button>
|
|
|
|
<Button
|
|
variant="outline"
|
|
onClick={onPaste}
|
|
disabled={!hasClipboard}
|
|
title="Paste (Ctrl+V)"
|
|
className="justify-start"
|
|
>
|
|
<Clipboard className="h-4 w-4 mr-2" />
|
|
Paste
|
|
</Button>
|
|
|
|
<Button
|
|
variant="outline"
|
|
onClick={onDelete}
|
|
disabled={!hasSelection}
|
|
title="Delete (Del)"
|
|
className="justify-start"
|
|
>
|
|
<Trash2 className="h-4 w-4 mr-2" />
|
|
Delete
|
|
</Button>
|
|
|
|
<Button
|
|
variant="outline"
|
|
onClick={onTrim}
|
|
disabled={!hasSelection}
|
|
title="Trim to Selection"
|
|
className="justify-start"
|
|
>
|
|
<CropIcon className="h-4 w-4 mr-2" />
|
|
Trim
|
|
</Button>
|
|
|
|
<Button
|
|
variant="outline"
|
|
onClick={onClearSelection}
|
|
disabled={!hasSelection}
|
|
title="Clear Selection (Esc)"
|
|
className="justify-start"
|
|
>
|
|
Clear
|
|
</Button>
|
|
</div>
|
|
|
|
{/* Keyboard Shortcuts Info */}
|
|
<div className="text-xs text-muted-foreground space-y-1 p-3 rounded-lg bg-muted/30">
|
|
<p className="font-medium mb-2">Edit Shortcuts:</p>
|
|
<p>• Shift+Drag: Select region</p>
|
|
<p>• Ctrl+A: Select all</p>
|
|
<p>• Ctrl+X: Cut</p>
|
|
<p>• Ctrl+C: Copy</p>
|
|
<p>• Ctrl+V: Paste</p>
|
|
<p>• Delete: Delete selection</p>
|
|
<p>• Escape: Clear selection</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|