diff --git a/frontend/src/components/ConfirmDialog.tsx b/frontend/src/components/ConfirmDialog.tsx new file mode 100644 index 0000000..57c8bb6 --- /dev/null +++ b/frontend/src/components/ConfirmDialog.tsx @@ -0,0 +1,81 @@ +import { useEffect } from 'react' + +interface Props { + /** The element ref — call ref.current?.showModal() to open. */ + ref?: React.Ref + /** Title shown in the dialog header. */ + title: string + /** Body text explaining what will happen. */ + message: string + /** Label for the confirm button. Defaults to "Confirm". */ + confirmLabel?: string + /** Called when the user confirms. */ + onConfirm: () => void + /** Optional: called when the user cancels. */ + onCancel?: () => void + /** Danger style — makes confirm button red. Default true. */ + danger?: boolean +} + +export default function ConfirmDialog({ + ref, + title, + message, + confirmLabel = 'Confirm', + onConfirm, + onCancel, + danger = true, +}: Props) { + useEffect(() => { + const dialog = ref && 'current' in ref ? ref.current : null + if (!dialog) return + + const handleClose = () => onCancel?.() + dialog.addEventListener('close', handleClose) + return () => dialog.removeEventListener('close', handleClose) + }, [ref, onCancel]) + + const handleConfirm = () => { + if (ref && 'current' in ref && ref.current) ref.current.close('confirm') + onConfirm() + } + + const handleCancel = () => { + if (ref && 'current' in ref && ref.current) ref.current.close('cancel') + } + + return ( + { + if (ref && 'current' in ref && e.target === ref.current) handleCancel() + }} + > +
+

{title}

+

{message}

+
+ + +
+
+
+ ) +} \ No newline at end of file diff --git a/frontend/src/components/DetailPanel.tsx b/frontend/src/components/DetailPanel.tsx index dd2c78f..a17e116 100644 --- a/frontend/src/components/DetailPanel.tsx +++ b/frontend/src/components/DetailPanel.tsx @@ -1,5 +1,6 @@ import { useRef, useState, useEffect } from 'react' import { getKeyColor, getBPMColor } from '../utils/musicColors' +import ConfirmDialog from './ConfirmDialog' interface Clip { id: string @@ -47,6 +48,7 @@ export default function DetailPanel({ clip, isPlaying, currentClipId, onClose, o const artworkInputRef = useRef(null) const [isEditingTitle, setIsEditingTitle] = useState(false) const [editTitle, setEditTitle] = useState(clip.title || '') + const deleteDialogRef = useRef(null) const titleInputRef = useRef(null) // Focus and select when entering edit mode @@ -422,7 +424,7 @@ export default function DetailPanel({ clip, isPlaying, currentClipId, onClose, o Download MP3