import React from "react" import { Menu, Avatar, Button, Dropdown } from "antd" import { Translation } from "react-i18next" import classnames from "classnames" import config from "config" import { Icons, createIconRender } from "components/Icons" import sidebarItems from "schemas/sidebar" import "./index.less" const onClickHandlers = { settings: () => { window.app.navigation.goToSettings() }, notifications: () => { window.app.controls.openNotifications() }, search: () => { window.app.controls.openSearcher() }, create: () => { window.app.controls.openCreator() }, account: () => { window.app.navigation.goToAccount() }, login: () => { window.app.navigation.goAuth() } } const getSidebarComponents = () => { const items = {} sidebarItems.forEach((item, index) => { items[item.id] = { ...item, index, content: ( <> {createIconRender(item.icon)} {item.title} ), } }) return items } const generateItems = () => { const components = getSidebarComponents() const itemsMap = [] const pathResolvers = {} Object.keys(components).forEach((key, index) => { const component = components[key] if (typeof component.path !== "undefined") { pathResolvers[component.id] = component.path } itemsMap.push(component) }) return { itemsMap, pathResolvers, } } const CustomRender = (props) => { const handleClickOutside = (event) => { if (props.sidebarRef.current && !props.sidebarRef.current.contains(event.target)) { if (event.target.closest(".ant-select-item")) { return } props.closeRender() } } React.useEffect(() => { document.addEventListener("mousedown", handleClickOutside) return () => { document.removeEventListener("mousedown", handleClickOutside) } }, []) return
{ props.customRenderTitle ?? null }
{props.children}
} export default class Sidebar extends React.Component { constructor(props) { super(props) this.controller = window.app["SidebarController"] = { toggleVisibility: this.toggleVisibility, toggleElevation: this.toggleElevation, toggleCollapse: this.toggleExpanded, isVisible: () => this.state.visible, isExpanded: () => this.state.expanded, setCustomRender: this.setRender, closeCustomRender: this.closeRender, updateBackgroundItem: (children, props) => { let updatedValue = this.state.backgroundItem if (typeof children !== "undefined") { updatedValue.children = children } if (typeof props !== "undefined") { updatedValue.props = props } this.setState({ backgroundItem: updatedValue }) }, setBackgroundItem: (children, props) => { this.setState({ backgroundItem: { children: children, props: props, }, }) }, clearBackgroundItem: () => { this.setState({ backgroundItem: null, }) } } this.state = { visible: false, elevated: false, expanded: false, pathResolvers: null, menus: null, customRenderTitle: null, customRender: null, backgroundItem: null, } // handle sidedrawer open/close window.app.eventBus.on("sidedrawer.hasDrawers", () => { this.toggleElevation(true) }) window.app.eventBus.on("sidedrawer.noDrawers", () => { this.toggleElevation(false) }) } sidebarRef = React.createRef() collapseDebounce = null componentDidMount = async () => { await this.loadItems() setTimeout(() => { this.controller.toggleVisibility(true) }, 100) } setRender = async (render, options = {}) => { if (!typeof render === "function") { throw new Error("Render is required to be a function") } await this.setState({ customRenderTitle:
{ options.icon && createIconRender(options.icon) } { options.title &&

{t => t(options.title)}

}
, customRender: React.createElement(render, { ...options.props ?? {}, close: this.closeRender, }) }) } closeRender = () => { this.setState({ customRenderTitle: null, customRender: null, }) } loadItems = async () => { const generation = generateItems() // update states await this.setState({ menus: generation.itemsMap, pathResolvers: generation.pathResolvers, }) } renderMenuItems(items) { const handleRenderIcon = (icon) => { if (typeof icon === "undefined") { return null } return createIconRender(icon) } return items.map((item) => { if (Array.isArray(item.children)) { return {t => t(item.title)} } {...item.props} > {this.renderMenuItems(item.children)} } return {t => t(item.title ?? item.id)} }) } handleClick = (e) => { if (e.item.props.ignoreClick) { return } if (e.item.props.override_event) { return app.eventBus.emit(e.item.props.override_event, e.item.props.override_event_props) } if (typeof e.key === "undefined") { window.app.eventBus.emit("invalidSidebarKey", e) return false } if (typeof onClickHandlers[e.key] === "function") { return onClickHandlers[e.key](e) } window.app.cores.sound.useUIAudio("sidebar.switch_tab") if (typeof this.state.pathResolvers === "object") { if (typeof this.state.pathResolvers[e.key] !== "undefined") { return window.app.setLocation(`/${this.state.pathResolvers[e.key]}`, 150) } } return window.app.setLocation(`/${e.key}`, 150) } toggleExpanded = (to) => { this.setState({ expanded: to ?? !this.state.expanded }) } toggleVisibility = (to) => { this.setState({ visible: to ?? !this.state.visible }) } toggleElevation = (to) => { this.setState({ elevated: to ?? !this.state.elevated }) } onMouseEnter = () => { if (!this.state.visible) return if (window.app.cores.settings.is("collapseOnLooseFocus", false)) return clearTimeout(this.collapseDebounce) this.collapseDebounce = null if (!this.state.expanded) { this.toggleExpanded(true) } } handleMouseLeave = () => { if (!this.state.visible) return if (window.app.cores.settings.is("collapseOnLooseFocus", false)) return if (this.state.expanded) { this.collapseDebounce = setTimeout(() => { this.toggleExpanded(false) }, window.app.cores.settings.get("autoCollapseDelay") ?? 500) } } render() { if (!this.state.menus) return null const defaultSelectedKey = window.location.pathname.replace("/", "") return
{ this.state.customRender && {this.state.customRender} } { !this.state.customRender && <>
{this.renderMenuItems(this.state.menus)}
{ this.state.backgroundItem?.children } } > {(t) => t("Search")} }> {t => t("Notifications")} }> {t => t("Settings")} { app.userData && { window.app.navigation.goToAccount() }} > } { !app.userData && }> {t => t("Login")} }
}
} }