mindmap / frontend /src /components /MindMapItem.tsx
Rsnarsna's picture
Upload 44 files
b0c3c39 verified
import React, { useState, useRef, useEffect } from 'react';
import styles from './MindMapItem.module.css';
interface MindMapItemProps {
id: string;
name: string;
updatedAt: string;
onSelect: () => void;
onDelete: () => void;
onRename: (newName: string) => void;
onShare: () => void;
isActive: boolean;
}
const MindMapItem: React.FC<MindMapItemProps> = ({
id,
name,
updatedAt,
onSelect,
onDelete,
onRename,
onShare,
isActive,
}) => {
const [isMenuOpen, setIsMenuOpen] = useState(false);
const [isEditing, setIsEditing] = useState(false);
const [editedName, setEditedName] = useState(name);
const menuRef = useRef<HTMLDivElement>(null);
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
setIsMenuOpen(false);
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
useEffect(() => {
if (isEditing && inputRef.current) {
inputRef.current.focus();
inputRef.current.select();
}
}, [isEditing]);
const handleMenuClick = (e: React.MouseEvent) => {
e.stopPropagation();
setIsMenuOpen(!isMenuOpen);
};
const handleRename = () => {
setIsEditing(true);
setIsMenuOpen(false);
};
const handleRenameSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (editedName.trim()) {
onRename(editedName.trim());
}
setIsEditing(false);
};
const handleDelete = () => {
setIsMenuOpen(false);
onDelete();
};
const handleShare = () => {
setIsMenuOpen(false);
onShare();
};
return (
<div className={`${styles.mindMapItem} ${isActive ? styles.active : ''}`} onClick={onSelect} style={{ position: 'relative' }}>
<div className={styles.mindMapInfo}>
<span className={styles.mindMapName}>{name}</span>
<span className={styles.mindMapDate}>
{new Date(updatedAt).toLocaleDateString()}
</span>
</div>
<div className={styles.verticalToolbar}>
{isEditing ? (
<form onSubmit={handleRenameSubmit} style={{ width: '100%' }}>
<input
ref={inputRef}
type="text"
value={editedName}
onChange={(e) => setEditedName(e.target.value)}
onBlur={handleRenameSubmit}
className={styles.renameInput}
placeholder="Rename mind map"
style={{ marginBottom: 8 }}
/>
</form>
) : null}
<button onClick={handleRename} className={styles.toolbarButton} aria-label="Rename mind map">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" /><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" /></svg>
</button>
<button onClick={handleShare} className={styles.toolbarButton} aria-label="Share mind map">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="18" cy="5" r="3" /><circle cx="6" cy="12" r="3" /><circle cx="18" cy="19" r="3" /><line x1="8.59" y1="13.51" x2="15.42" y2="17.49" /><line x1="15.41" y1="6.51" x2="8.59" y2="10.49" /></svg>
</button>
<button onClick={handleDelete} className={`${styles.toolbarButton} ${styles.delete}`} aria-label="Delete mind map">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="3 6 5 6 21 6" /><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" /></svg>
</button>
</div>
</div>
);
};
export default MindMapItem;