diff --git a/packages/app/src/components/Layout/sidebar/index.jsx b/packages/app/src/components/Layout/sidebar/index.jsx index 8a44498d..cfb75cc8 100755 --- a/packages/app/src/components/Layout/sidebar/index.jsx +++ b/packages/app/src/components/Layout/sidebar/index.jsx @@ -1,5 +1,5 @@ import React from "react" -import { Menu, Avatar } from "antd" +import { Menu, Avatar, Button } from "antd" import { Translation } from "react-i18next" import classnames from "classnames" @@ -70,6 +70,8 @@ export default class Sidebar extends React.Component { toggleCollapse: this.toggleCollapse, isVisible: () => this.state.visible, isCollapsed: () => this.state.collapsed, + setCustomRender: this.setRender, + closeCustomRender: this.closeRender, } this.state = { @@ -78,6 +80,9 @@ export default class Sidebar extends React.Component { collapsed: window.app.settings.get("collapseOnLooseFocus") ?? false, pathResolvers: null, menus: null, + + customRenderTitle: null, + customRender: null, } // handle sidedrawer open/close @@ -99,6 +104,38 @@ export default class Sidebar extends React.Component { }, 100) } + setRender = (render, options = {}) => { + if (!typeof render === "function") { + throw new Error("Render is required to be a function") + } + + 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() @@ -213,62 +250,87 @@ export default class Sidebar extends React.Component { classnames( "app_sidebar", { + ["customRender"]: this.state.customRender, ["floating"]: window.app?.settings.get("sidebar.floating"), - ["collapsed"]: this.state.visible && this.state.collapsed, - ["elevated"]: this.state.visible && this.state.elevated, + ["collapsed"]: !this.state.customRender && this.state.visible && this.state.collapsed, + ["elevated"]: !this.state.visible && this.state.elevated, ["hidden"]: !this.state.visible, } ) } > -
-
- + + { + this.state.customRender && +
+
+ { + this.state.customRenderTitle ?? null + } + +
+
+ {this.state.customRender} +
-
+ } -
- - {this.renderMenuItems(this.state.menus)} - -
+ { + !this.state.customRender && <> +
+
+ +
+
-
- - } override_event="app.openSearcher" > - - {(t) => t("Search")} - - - } override_event="app.openCreator" > - - {(t) => t("Create")} - - - } override_event="app.openNotifications"> - - {t => t("Notifications")} - - - }> - - {t => t("Settings")} - - - { - app.userData && - - - } - { - !app.userData && }> - - {t => t("Login")} - - - } - -
+
+ + {this.renderMenuItems(this.state.menus)} + +
+ +
+ + } override_event="app.openSearcher" > + + {(t) => t("Search")} + + + } override_event="app.openCreator" > + + {(t) => t("Create")} + + + } override_event="app.openNotifications"> + + {t => t("Notifications")} + + + }> + + {t => t("Settings")} + + + { + app.userData && + + + } + { + !app.userData && }> + + {t => t("Login")} + + + } + +
+ + }
) } diff --git a/packages/app/src/components/Layout/sidebar/index.less b/packages/app/src/components/Layout/sidebar/index.less index b81306b2..e0a3c535 100755 --- a/packages/app/src/components/Layout/sidebar/index.less +++ b/packages/app/src/components/Layout/sidebar/index.less @@ -44,6 +44,25 @@ } } + &.customRender { + display: flex; + position: relative; + + width: 100%; + min-width: 34vw; + + padding: 20px; + max-width: 60vw; + + .app_sidebar_menu_wrapper { + animation: disappear 0.3s ease-out forwards; + } + + .render_content_wrapper { + animation: appear 0.3s ease-out forwards; + } + } + &.hidden { flex: 0 !important; min-width: 0 !important; @@ -55,6 +74,52 @@ box-shadow: 0 0 5px 4px rgba(0, 0, 0, 0.1) !important; } + .render_content_wrapper { + display: flex; + flex-direction: column; + + opacity: 0; + transition: all 150ms ease-in-out; + + overflow-y: hidden; + + .render_content_header { + display: inline-flex; + flex-direction: row; + + align-items: center; + justify-content: space-between; + + .render_content_header_title { + display: inline-flex; + flex-direction: row; + + align-items: center; + + h1, + h2, + h3 { + font-size: 1.8; + margin: 0 !important; + } + + svg { + font-size: 1.8rem; + } + } + } + + .render_content { + height: 100%; + + padding: 20px; + padding-left: 0; + + overflow-x: hidden; + overflow-y: scroll; + } + } + .app_sidebar_header { display: flex; flex-direction: column; @@ -178,4 +243,24 @@ margin: 0; flex: 0; } +} + +@keyframes appear { + 0% { + opacity: 0; + width: 0px; + margin: 0; + } + + 5% { + opacity: 0; + width: 0px; + margin: 0; + } + + 100% { + opacity: 1; + width: 100%; + margin: 0; + } } \ No newline at end of file