2025-12-08 22:08:30 +00:00
|
|
|
import React from "react";
|
2025-12-22 15:23:40 +00:00
|
|
|
import { Note } from "../../api/notes";
|
|
|
|
|
import { useCreateNote, useDeleteNote } from "../../hooks/useFolders";
|
|
|
|
|
import { useUIStore } from "../../stores/uiStore";
|
2025-12-08 22:08:30 +00:00
|
|
|
|
|
|
|
|
interface NoteContextMenuProps {
|
|
|
|
|
x: number;
|
|
|
|
|
y: number;
|
2025-12-22 15:23:40 +00:00
|
|
|
note: Note;
|
2025-12-08 22:08:30 +00:00
|
|
|
onClose: () => void;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const NoteContextMenu: React.FC<NoteContextMenuProps> = ({
|
|
|
|
|
x,
|
|
|
|
|
y,
|
|
|
|
|
note,
|
|
|
|
|
onClose,
|
|
|
|
|
}) => {
|
2025-12-22 15:23:40 +00:00
|
|
|
const { setSelectedNote } = useUIStore();
|
|
|
|
|
const deleteNoteMutation = useDeleteNote();
|
|
|
|
|
const createNoteMutation = useCreateNote();
|
2025-12-08 22:08:30 +00:00
|
|
|
|
|
|
|
|
const handleDelete = async () => {
|
|
|
|
|
try {
|
2025-12-22 15:23:40 +00:00
|
|
|
await deleteNoteMutation.mutateAsync(note.id);
|
|
|
|
|
// Clear selection if this note was selected
|
|
|
|
|
setSelectedNote(null);
|
2025-12-08 22:08:30 +00:00
|
|
|
onClose();
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Failed to delete note:", error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleDuplicate = async () => {
|
|
|
|
|
try {
|
2025-12-22 15:23:40 +00:00
|
|
|
await createNoteMutation.mutateAsync({
|
2025-12-08 22:08:30 +00:00
|
|
|
title: `${note.title} (Copy)`,
|
|
|
|
|
content: note.content,
|
2026-01-15 22:26:08 +00:00
|
|
|
folderId: note.folderId || null,
|
2025-12-08 22:08:30 +00:00
|
|
|
});
|
|
|
|
|
onClose();
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("Failed to duplicate note:", error);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleRename = () => {
|
|
|
|
|
setSelectedNote(note);
|
|
|
|
|
onClose();
|
|
|
|
|
// Focus will be handled by the editor
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
position: "fixed",
|
|
|
|
|
top: y,
|
|
|
|
|
left: x,
|
|
|
|
|
}}
|
2026-01-15 22:26:08 +00:00
|
|
|
className="bg-overlay0 border border-surface1 rounded-md shadow-lg py-1 min-w-[160px] z-50"
|
2025-12-08 22:08:30 +00:00
|
|
|
onClick={(e) => e.stopPropagation()}
|
|
|
|
|
>
|
|
|
|
|
<button
|
|
|
|
|
onClick={handleRename}
|
2026-01-15 22:26:08 +00:00
|
|
|
className="w-full text-left px-3 py-1.5 hover:bg-surface1 text-sm text-text transition-colors"
|
2025-12-08 22:08:30 +00:00
|
|
|
>
|
|
|
|
|
Rename
|
|
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
onClick={handleDuplicate}
|
2026-01-15 22:26:08 +00:00
|
|
|
className="w-full text-left px-3 py-1.5 hover:bg-surface1 text-sm text-text transition-colors"
|
2025-12-08 22:08:30 +00:00
|
|
|
>
|
|
|
|
|
Duplicate
|
|
|
|
|
</button>
|
2026-01-15 22:26:08 +00:00
|
|
|
<div className="border-t border-surface1 my-1" />
|
2025-12-08 22:08:30 +00:00
|
|
|
<button
|
|
|
|
|
onClick={handleDelete}
|
2026-01-15 22:26:08 +00:00
|
|
|
className="w-full text-left px-3 py-1.5 hover:bg-danger hover:text-base text-sm text-danger transition-colors"
|
2025-12-08 22:08:30 +00:00
|
|
|
>
|
|
|
|
|
Delete
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|