-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathWorkspaceMenu.tsx
More file actions
120 lines (102 loc) · 4.11 KB
/
Copy pathWorkspaceMenu.tsx
File metadata and controls
120 lines (102 loc) · 4.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
import { useEffect, useState } from 'react';
import { FaAngleDown, FaAngleUp } from 'react-icons/fa';
import ComingSoon from './ComingSoon';
import { NavItem, navItems } from './navigation';
import { useWorkspace } from '../../hooks/useWorkspace';
import './WorkspaceMenu.scss';
const SELECTED_MENU_PATH_STORAGE_KEY = 'workspaceUiSelectedMenuPath';
const findNavItemByPath = (items: NavItem[], path: string[]): NavItem | undefined => {
if (!path.length) return undefined;
let currentItems = items;
let foundItem: NavItem | undefined;
for (const segment of path) {
foundItem = currentItems.find((item) => item.label === segment);
if (!foundItem) return undefined;
currentItems = foundItem.subItems ?? [];
}
return foundItem;
};
export const WorkspaceMenu = () => {
const { selectedItemPath, setSelectedItemPath, setContent } = useWorkspace();
const [expandedSet, setExpandedSet] = useState<Set<string>>(new Set());
useEffect(() => {
if (navItems.length > 0) {
const storedPath = localStorage.getItem(SELECTED_MENU_PATH_STORAGE_KEY);
const parsedPath = storedPath ? storedPath.split('/').filter(Boolean) : [];
const matchedItem = findNavItemByPath(navItems, parsedPath);
const initialPath = matchedItem ? parsedPath : [navItems[0].label];
const initialItem = matchedItem ?? navItems[0];
setSelectedItemPath(initialPath);
setContent(initialItem.content || <ComingSoon title={initialItem.label} />);
}
}, [setContent, setSelectedItemPath]);
useEffect(() => {
if (!selectedItemPath.length) return;
localStorage.setItem(SELECTED_MENU_PATH_STORAGE_KEY, selectedItemPath.join('/'));
}, [selectedItemPath]);
const handleToggle = (label: string) => {
setExpandedSet((prev) => {
const next = new Set(prev);
if (next.has(label)) {
next.delete(label);
} else {
next.add(label);
}
return next;
});
};
const renderNavItems = (items: NavItem[], parentPath: string[] = []) => {
return items.map((item) => {
const currentPath = [...parentPath, item.label];
const hasSubItems = item.subItems && item.subItems.length > 0;
const isExpanded = hasSubItems && expandedSet.has(item.label);
const isSelected = selectedItemPath.join('/') === currentPath.join('/');
const isSubItemSelected = selectedItemPath.join('/').startsWith(currentPath.join('/'));
return (
<div
key={item.label}
className={`workspace-menu__item ${parentPath.length > 0 ? 'workspace-menu__subitem' : ''}`}
>
<div
className={`workspace-menu__item-header ${isSelected ? 'active' : ''}`}
onClick={() => {
if (hasSubItems && isExpanded && !isSubItemSelected) {
setContent(item.content || <ComingSoon title={item.label} />);
return;
} else if (hasSubItems && isSubItemSelected) {
handleToggle(item.label);
return;
} else if (hasSubItems) {
handleToggle(item.label);
}
setSelectedItemPath(currentPath);
setContent(item.content || <ComingSoon title={item.label} />);
}}
>
{item.icon && (
<img alt={item.label} className="workspace-menu__item-icon" src={item.icon} />
)}
<span className="workspace-menu__item-label">{item.label}</span>
{hasSubItems && (
<span className="workspace-menu__item-chevron">
{isExpanded ? <FaAngleUp /> : <FaAngleDown />}
</span>
)}
</div>
{hasSubItems && isExpanded && (
<div className="workspace-menu__subitems">
{renderNavItems(item.subItems!, currentPath)}
</div>
)}
</div>
);
});
};
return (
<div className="workspace-menu content-border">
<div className="workspace-menu__sidebar">{renderNavItems(navItems)}</div>
</div>
);
};