@zohodesk/docs-builder
Version:
docs-builder is used to build your own docs
209 lines (183 loc) • 8.64 kB
JavaScript
import React, { useState, useMemo, useEffect } from "react";
import { Link, useLocation, useHistory } from "react-router-dom";
import style from "./Sidebar.module.css";
import image from "../../assets/icons/desk.png";
import docsObjectConvertor from "./docsObjectConvertor";
export default function Sidebar(_ref) {
let {
components
} = _ref;
const [searchQuery, setSearchQuery] = useState("");
const [openFolders, setOpenFolders] = useState({});
const [openGroups, setOpenGroups] = useState({});
const location = useLocation();
const history = useHistory(); // Filter components based on search query
const filteredComponents = useMemo(() => {
if (!searchQuery.trim()) return components;
return searchFilter(searchQuery);
}, [components, searchQuery]); // Convert filtered components to docs object structure
const organizedDocs = useMemo(() => docsObjectConvertor(filteredComponents), [filteredComponents]); // Handle component route navigation
const navigateToComponent = componentName => {
if (componentName) {
history.push(`/all/${componentName}`);
}
}; // Clear search input
const clearSearch = () => {
setSearchQuery("");
}; // Toggle folder open/closed state
const toggleFolder = folderName => {
setOpenFolders(prevState => {
const newOpenFolders = { ...prevState
};
newOpenFolders[folderName] = !prevState[folderName]; // Close other folders when opening a new one
Object.keys(prevState).forEach(prevFolder => {
if (prevFolder !== folderName && newOpenFolders[folderName]) {
newOpenFolders[prevFolder] = false;
}
});
return newOpenFolders;
});
}; // Toggle group open/closed state within a folder
const toggleGroup = (folderName, groupName) => {
const groupKey = `${folderName}_${groupName}`;
setOpenGroups(prevState => {
const newOpenGroups = { ...prevState
};
newOpenGroups[groupKey] = !prevState[groupKey]; // Close other groups in the same folder when opening a new one
Object.keys(prevState).forEach(prevGroup => {
if (prevGroup.startsWith(`${folderName}_`) && prevGroup !== groupKey && newOpenGroups[groupKey]) {
newOpenGroups[prevGroup] = false;
}
});
return newOpenGroups;
});
}; // Filter components by search query
function searchFilter(searchQuery) {
const filteredData = Object.entries(components).filter(_ref2 => {
let [compId, component] = _ref2;
const lowercaseName = component.name ? component.name.toLowerCase() : "";
const lowercaseQuery = searchQuery.toLowerCase();
return lowercaseName.includes(lowercaseQuery);
});
return Object.fromEntries(filteredData);
} // Extract the base component name from path (ignore tab routing)
const getComponentNameFromPath = path => {
// First, split by "/"
const pathParts = path.split("/"); // Get the component name (expected to be the last part or the one before a tab name)
let componentName = pathParts[pathParts.length - 1]; // Check if this is a tab route and get the actual component name
if (["proptypes", "code", "playground"].includes(componentName)) {
componentName = pathParts[pathParts.length - 2];
}
return componentName;
}; // Auto-expand folders and groups based on current URL path
useEffect(() => {
const pathParts = location.pathname.split("/");
const isAllRoute = pathParts.length <= 2 || pathParts[1] === "all" && pathParts.length === 2; // If navigating to /all route, close all folders
if (isAllRoute) {
setOpenFolders({});
setOpenGroups({});
return;
}
const componentName = getComponentNameFromPath(location.pathname); // Only proceed if this is a component path
if (!componentName || componentName === "all") return; // Reset open state
const newOpenFolders = {};
const newOpenGroups = {}; // Find and open the folder and group containing the current component
for (const [folderName, groups] of Object.entries(organizedDocs)) {
for (const [groupName, components] of Object.entries(groups)) {
if (components.hasOwnProperty(componentName)) {
newOpenFolders[folderName] = true;
newOpenGroups[`${folderName}_${groupName}`] = true;
break;
}
}
}
setOpenFolders(newOpenFolders);
setOpenGroups(newOpenGroups);
}, [location.pathname, organizedDocs]);
return /*#__PURE__*/React.createElement("div", {
className: style.sidebar
}, /*#__PURE__*/React.createElement("div", {
className: style.sidebarContent
}, /*#__PURE__*/React.createElement(Link, {
to: "/all",
className: style.logoContainer
}, /*#__PURE__*/React.createElement("img", {
className: style.logo,
src: image,
alt: "Logo"
}), /*#__PURE__*/React.createElement("div", {
className: style.docsVersion
}, "Docs v2.0.0"), /*#__PURE__*/React.createElement("i", {
className: `fa-solid fa-house ${style.homeIcon}`
})), /*#__PURE__*/React.createElement("div", {
className: style.navigationContainer
}, /*#__PURE__*/React.createElement("div", {
className: style.searchContainer
}, /*#__PURE__*/React.createElement("i", {
className: `fa-solid fa-magnifying-glass ${style.searchIcon}`
}), /*#__PURE__*/React.createElement("input", {
type: "text",
placeholder: "Search components...",
className: style.searchInput,
value: searchQuery,
onChange: e => setSearchQuery(e.target.value)
}), searchQuery && /*#__PURE__*/React.createElement("button", {
className: style.clearButton,
onClick: clearSearch
}, /*#__PURE__*/React.createElement("i", {
className: "fa-solid fa-times"
}))), /*#__PURE__*/React.createElement("div", {
className: style.componentList
}, Object.entries(organizedDocs).map(_ref3 => {
let [folderName, groups] = _ref3;
return /*#__PURE__*/React.createElement("div", {
key: folderName,
className: `${style.folder} ${openFolders[folderName] ? style.folderOpen : ""}`
}, /*#__PURE__*/React.createElement("div", {
className: style.folderHeader,
onClick: () => toggleFolder(folderName)
}, /*#__PURE__*/React.createElement("i", {
className: `fa-regular fa-folder ${style.folderIcon}`
}), /*#__PURE__*/React.createElement("span", {
className: style.folderName
}, folderName), /*#__PURE__*/React.createElement("span", {
className: style.itemCount
}, Object.keys(groups).length), /*#__PURE__*/React.createElement("i", {
className: `fa-solid fa-chevron-right ${style.chevron} ${openFolders[folderName] ? style.chevronOpen : ""}`
})), (searchQuery || openFolders[folderName]) && /*#__PURE__*/React.createElement("div", {
className: style.groupsContainer
}, Object.entries(groups).map(_ref4 => {
let [groupName, components] = _ref4;
return /*#__PURE__*/React.createElement("div", {
key: groupName,
className: `${style.group} ${openGroups[`${folderName}_${groupName}`] ? style.groupOpen : ""}`
}, /*#__PURE__*/React.createElement("div", {
className: style.groupHeader,
onClick: () => toggleGroup(folderName, groupName)
}, /*#__PURE__*/React.createElement("i", {
className: `fa-regular fa-file ${style.groupIcon}`
}), /*#__PURE__*/React.createElement("span", {
className: style.groupName
}, groupName), /*#__PURE__*/React.createElement("span", {
className: style.itemCount
}, Object.keys(components).length), /*#__PURE__*/React.createElement("i", {
className: `fa-solid fa-chevron-right ${style.chevron} ${openGroups[`${folderName}_${groupName}`] ? style.chevronOpen : ""}`
})), (searchQuery || openGroups[`${folderName}_${groupName}`]) && /*#__PURE__*/React.createElement("div", {
className: style.componentsContainer
}, Object.keys(components).map(compId => {
const componentName = compId.split("__")[1] || compId;
const currentCompInPath = getComponentNameFromPath(location.pathname);
const isActive = compId === currentCompInPath;
return /*#__PURE__*/React.createElement("div", {
key: compId,
className: `${style.component} ${isActive ? style.componentActive : ""}`,
onClick: () => navigateToComponent(compId)
}, /*#__PURE__*/React.createElement("i", {
className: `fa-brands fa-react ${style.componentIcon}`
}), /*#__PURE__*/React.createElement("span", {
className: style.componentName
}, componentName));
})));
})));
})))));
}