| 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; |