276 lines
7.6 KiB
TypeScript
276 lines
7.6 KiB
TypeScript
import React, { useState } from "react";
|
|
import { useNavigate } from "react-router-dom";
|
|
import { ArrowIcon } from "../../icons/ExportCommonIcons";
|
|
import { toggleTheme } from "../../../utils/theme";
|
|
import useVersionHistoryStore, {
|
|
useShortcutStore,
|
|
useVersionStore,
|
|
} from "../../../store/builder/store";
|
|
import { useSubModuleStore } from "../../../store/useModuleStore";
|
|
import { generateUniqueId } from "../../../functions/generateUniqueId";
|
|
|
|
interface MenuBarProps {
|
|
setOpenMenu: (isOpen: boolean) => void;
|
|
}
|
|
|
|
interface MenuItem {
|
|
label: string;
|
|
onClick?: string;
|
|
shortcut?: string;
|
|
submenu?: MenuItem[];
|
|
action?: () => void;
|
|
}
|
|
|
|
const MenuBar: React.FC<MenuBarProps> = ({ setOpenMenu }) => {
|
|
const userName = localStorage.getItem("userName") ?? "Anonymous";
|
|
|
|
const navigate = useNavigate();
|
|
const [activeMenu, setActiveMenu] = useState<string | null>(null);
|
|
const [activeSubMenu, setActiveSubMenu] = useState<string | null>(null);
|
|
const [selectedItems, setSelectedItems] = useState<Record<string, boolean>>(
|
|
{}
|
|
);
|
|
|
|
const { setVersionHistory } = useVersionHistoryStore();
|
|
const { setSubModule } = useSubModuleStore();
|
|
const { showShortcuts, setShowShortcuts } = useShortcutStore();
|
|
|
|
const savedTheme = localStorage.getItem("theme") ?? "light";
|
|
|
|
const toggleSelection = (itemName: string) => {
|
|
setSelectedItems((prev) => ({
|
|
...prev,
|
|
[itemName]: !prev[itemName],
|
|
}));
|
|
};
|
|
|
|
// functions
|
|
const handleThemeChange = () => {
|
|
toggleTheme();
|
|
window.location.reload();
|
|
};
|
|
|
|
const handleLogout = () => {
|
|
localStorage.clear();
|
|
navigate("/");
|
|
};
|
|
|
|
function handleShotcutsHelper() {
|
|
setShowShortcuts(!showShortcuts);
|
|
}
|
|
|
|
const menus: Record<string, MenuItem[]> = {
|
|
File: [
|
|
{ label: "New File", shortcut: "Ctrl + N" },
|
|
{ label: "Open Local File", shortcut: "Ctrl + O" },
|
|
{
|
|
label: "Save Version",
|
|
action: () => {
|
|
const versionStore = useVersionStore.getState();
|
|
const versionCount = versionStore.versions.length;
|
|
|
|
const newVersion = {
|
|
id: generateUniqueId(),
|
|
versionLabel: `v${versionCount + 1}.0`,
|
|
timestamp: `${new Date().toLocaleTimeString("en-US", {
|
|
hour: "numeric",
|
|
minute: "2-digit",
|
|
hour12: true,
|
|
})} ${new Date().toLocaleDateString("en-US", {
|
|
year: "numeric",
|
|
month: "long",
|
|
day: "2-digit",
|
|
})}`,
|
|
|
|
savedBy: userName,
|
|
};
|
|
|
|
console.log("newVersion: ", newVersion);
|
|
versionStore.addVersion(newVersion);
|
|
},
|
|
},
|
|
{ label: "Make a Copy" },
|
|
{ label: "Share" },
|
|
{ label: "Rename" },
|
|
{ label: "Import" },
|
|
{ label: "Close File" },
|
|
],
|
|
Edit: [
|
|
{ label: "Undo", shortcut: "Ctrl + Z" },
|
|
{ label: "Redo", shortcut: "Ctrl + Shift + Z" },
|
|
{ label: "Undo History" },
|
|
{ label: "Redo History" },
|
|
{ label: "Find", shortcut: "Ctrl + F" },
|
|
{ label: "Delete" },
|
|
{ label: "Select by..." },
|
|
{ label: "Keymap" },
|
|
],
|
|
View: [
|
|
{ label: "Grid" },
|
|
{
|
|
label: "Gizmo",
|
|
submenu: [
|
|
{ label: "Visibility" },
|
|
{ label: "Cube view" },
|
|
{ label: "Sphere view" },
|
|
],
|
|
},
|
|
{ label: "Zoom" },
|
|
{ label: "Full Screen", shortcut: "F11" },
|
|
],
|
|
Help: [
|
|
{
|
|
label: "Shortcuts",
|
|
shortcut: "Ctrl + Shift + ?",
|
|
action: handleShotcutsHelper,
|
|
},
|
|
{ label: "Manual" },
|
|
{ label: "Video Tutorials" },
|
|
{ label: "Report a bug" },
|
|
],
|
|
};
|
|
|
|
// render menu item and sub menu item component
|
|
const renderMenuItem = ({ label, shortcut, action }: MenuItem) => (
|
|
<button
|
|
id={label}
|
|
className="menu-item-container"
|
|
key={label}
|
|
onClick={() => {
|
|
toggleSelection(label);
|
|
action && action();
|
|
}}
|
|
>
|
|
<div className="menu-item">
|
|
<span>
|
|
{selectedItems[label] ? "✓ " : ""}
|
|
{label}
|
|
</span>
|
|
{shortcut && (
|
|
<div className="menu-item-right">
|
|
<span className="shortcut">{shortcut}</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</button>
|
|
);
|
|
|
|
const renderSubMenu = (submenu: MenuItem[], parentLabel: string) => (
|
|
<div className="submenu">
|
|
{submenu.map((item) => (
|
|
<button
|
|
id={item.label}
|
|
key={item.label}
|
|
className="submenu-item"
|
|
onClick={() => {
|
|
console.log("hi", item.onClick);
|
|
toggleSelection(item.label);
|
|
}}
|
|
>
|
|
<span>
|
|
{selectedItems[item.label] ? "✓ " : ""}
|
|
{item.label}
|
|
</span>
|
|
</button>
|
|
))}
|
|
</div>
|
|
);
|
|
|
|
return (
|
|
<div className="menu-bar" onPointerLeave={() => setOpenMenu(false)}>
|
|
<div className="menu-buttons">
|
|
{Object.entries(menus).map(([menu, items]) => (
|
|
<button
|
|
id={menu}
|
|
key={menu}
|
|
className="menu-button-container"
|
|
onMouseEnter={() => setActiveMenu(menu)}
|
|
onMouseLeave={() => {
|
|
setActiveMenu(null);
|
|
setActiveSubMenu(null);
|
|
}}
|
|
>
|
|
<div className="menu-button">
|
|
{menu}
|
|
<span className="dropdown-icon">
|
|
<ArrowIcon />
|
|
</span>
|
|
</div>
|
|
|
|
{activeMenu === menu && (
|
|
<div className="dropdown-menu">
|
|
{items.map((item) =>
|
|
item.submenu ? (
|
|
<button
|
|
id={item.label}
|
|
key={item.label}
|
|
className="menu-item-container"
|
|
onMouseEnter={() => setActiveSubMenu(item.label)}
|
|
onMouseLeave={() => setActiveSubMenu(null)}
|
|
>
|
|
<div className="menu-item">
|
|
<span>{item.label}</span>
|
|
<span className="dropdown-icon">
|
|
<ArrowIcon />
|
|
</span>
|
|
</div>
|
|
{activeSubMenu === item.label &&
|
|
renderSubMenu(item.submenu, item.label)}
|
|
</button>
|
|
) : (
|
|
renderMenuItem(item)
|
|
)
|
|
)}
|
|
</div>
|
|
)}
|
|
</button>
|
|
))}
|
|
|
|
{/* Version History */}
|
|
<button
|
|
id="version-history"
|
|
className="menu-button-container"
|
|
onMouseEnter={() => setActiveMenu("Version history")}
|
|
onMouseLeave={() => {
|
|
setActiveMenu(null);
|
|
setActiveSubMenu(null);
|
|
}}
|
|
onClick={() => {
|
|
setVersionHistory(true);
|
|
setSubModule("properties");
|
|
}}
|
|
>
|
|
<div className="menu-button">Version history</div>
|
|
</button>
|
|
|
|
{/* Theme */}
|
|
<button
|
|
id="theme-btn"
|
|
className="menu-button-container"
|
|
onMouseEnter={() => setActiveMenu("Theme")}
|
|
onMouseLeave={() => {
|
|
setActiveMenu(null);
|
|
setActiveSubMenu(null);
|
|
}}
|
|
onClick={handleThemeChange}
|
|
>
|
|
<div className="menu-button">
|
|
Theme <div className="value">{savedTheme}</div>
|
|
</div>
|
|
</button>
|
|
|
|
{/* Log out */}
|
|
<button
|
|
id="logout"
|
|
className="menu-button-container"
|
|
onClick={handleLogout}
|
|
>
|
|
<div className="menu-button">Log out</div>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default MenuBar;
|