|
|
import React from 'react';
|
|
|
import { useNavigate, useLocation } from 'react-router-dom';
|
|
|
import { Node, Edge } from 'reactflow';
|
|
|
import styles from './SidePane.module.css';
|
|
|
import MindMapList from './MindMapList';
|
|
|
import axios from '../utils/axios';
|
|
|
import { MindMapData } from '../utils/jsonUtils';
|
|
|
|
|
|
|
|
|
const HomeIcon = () => (
|
|
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
|
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
|
|
|
<polyline points="9 22 9 12 15 12 15 22" />
|
|
|
</svg>
|
|
|
);
|
|
|
|
|
|
const MindMapIcon = () => (
|
|
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
|
<circle cx="12" cy="12" r="10" />
|
|
|
<path d="M12 2v20M2 12h20" />
|
|
|
<path d="M12 2a10 10 0 0 1 10 10M12 22a10 10 0 0 1-10-10" />
|
|
|
</svg>
|
|
|
);
|
|
|
|
|
|
const LogoutIcon = () => (
|
|
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
|
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
|
|
|
<polyline points="16 17 21 12 16 7" />
|
|
|
<line x1="21" y1="12" x2="9" y2="12" />
|
|
|
</svg>
|
|
|
);
|
|
|
|
|
|
const ChevronIcon = ({ isCollapsed }: { isCollapsed: boolean }) => (
|
|
|
<svg
|
|
|
width="16"
|
|
|
height="16"
|
|
|
viewBox="0 0 24 24"
|
|
|
fill="none"
|
|
|
stroke="currentColor"
|
|
|
strokeWidth="2"
|
|
|
strokeLinecap="round"
|
|
|
strokeLinejoin="round"
|
|
|
style={{
|
|
|
transform: isCollapsed ? 'rotate(180deg)' : 'rotate(0deg)',
|
|
|
transition: 'transform 0.3s ease',
|
|
|
}}
|
|
|
>
|
|
|
<polyline points="15 18 9 12 15 6" />
|
|
|
</svg>
|
|
|
);
|
|
|
|
|
|
interface SidePaneProps {
|
|
|
onSelectMindMap: (mindMap: MindMapData) => void;
|
|
|
onNewMindMap: () => void;
|
|
|
isCollapsed: boolean;
|
|
|
setIsCollapsed: (collapsed: boolean) => void;
|
|
|
onDeleteMindMap: (id: string) => void;
|
|
|
}
|
|
|
|
|
|
const SidePane: React.FC<SidePaneProps> = ({ onSelectMindMap, onNewMindMap, isCollapsed, setIsCollapsed, onDeleteMindMap }) => {
|
|
|
const navigate = useNavigate();
|
|
|
const location = useLocation();
|
|
|
const isEditor = location.pathname === '/editor';
|
|
|
|
|
|
const handleLogout = async () => {
|
|
|
try {
|
|
|
await axios.post('/logout');
|
|
|
} catch (error) {
|
|
|
|
|
|
}
|
|
|
localStorage.removeItem('token');
|
|
|
navigate('/');
|
|
|
};
|
|
|
|
|
|
const handleNavigation = (path: string) => (e: React.MouseEvent) => {
|
|
|
e.preventDefault();
|
|
|
try {
|
|
|
navigate(path);
|
|
|
} catch (error) {
|
|
|
console.error('Navigation error:', error);
|
|
|
|
|
|
window.location.href = path;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
return (
|
|
|
<div className={`${styles.sidePane} ${isCollapsed ? styles.collapsed : styles.expanded}`}>
|
|
|
<button
|
|
|
className={styles.toggleButton}
|
|
|
onClick={() => setIsCollapsed(!isCollapsed)}
|
|
|
aria-label={isCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}
|
|
|
>
|
|
|
<ChevronIcon isCollapsed={isCollapsed} />
|
|
|
</button>
|
|
|
|
|
|
<div className={styles.menuItems}>
|
|
|
<a
|
|
|
href="/"
|
|
|
className={`${styles.menuItem} ${location.pathname === '/' ? styles.active : ''}`}
|
|
|
onClick={handleNavigation('/')}
|
|
|
>
|
|
|
<span className={styles.icon}>
|
|
|
<HomeIcon />
|
|
|
</span>
|
|
|
<span className={styles.label}>Home</span>
|
|
|
</a>
|
|
|
|
|
|
<a
|
|
|
href="/editor"
|
|
|
className={`${styles.menuItem} ${location.pathname === '/editor' ? styles.active : ''}`}
|
|
|
onClick={handleNavigation('/editor')}
|
|
|
>
|
|
|
<span className={styles.icon}>
|
|
|
<MindMapIcon />
|
|
|
</span>
|
|
|
<span className={styles.label}>Mind Map</span>
|
|
|
</a>
|
|
|
|
|
|
{isEditor && (
|
|
|
<MindMapList
|
|
|
isCollapsed={isCollapsed}
|
|
|
onSelectMindMap={onSelectMindMap}
|
|
|
onNewMindMap={onNewMindMap}
|
|
|
onDeleteMindMap={onDeleteMindMap}
|
|
|
/>
|
|
|
)}
|
|
|
</div>
|
|
|
|
|
|
<div className={`${styles.logoutButton} ${isCollapsed ? styles.collapsed : ''}`}>
|
|
|
<button onClick={handleLogout} aria-label="Logout">
|
|
|
<span className={styles.icon}>
|
|
|
<LogoutIcon />
|
|
|
</span>
|
|
|
<span className={styles.label}>Logout</span>
|
|
|
</button>
|
|
|
</div>
|
|
|
</div>
|
|
|
);
|
|
|
};
|
|
|
|
|
|
export default SidePane; |