mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-11 03:24:16 +00:00
support custom renders inside sidebar
This commit is contained in:
parent
472050c8b0
commit
843ccd812a
@ -1,5 +1,5 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import { Menu, Avatar } from "antd"
|
import { Menu, Avatar, Button } from "antd"
|
||||||
import { Translation } from "react-i18next"
|
import { Translation } from "react-i18next"
|
||||||
import classnames from "classnames"
|
import classnames from "classnames"
|
||||||
|
|
||||||
@ -70,6 +70,8 @@ export default class Sidebar extends React.Component {
|
|||||||
toggleCollapse: this.toggleCollapse,
|
toggleCollapse: this.toggleCollapse,
|
||||||
isVisible: () => this.state.visible,
|
isVisible: () => this.state.visible,
|
||||||
isCollapsed: () => this.state.collapsed,
|
isCollapsed: () => this.state.collapsed,
|
||||||
|
setCustomRender: this.setRender,
|
||||||
|
closeCustomRender: this.closeRender,
|
||||||
}
|
}
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
@ -78,6 +80,9 @@ export default class Sidebar extends React.Component {
|
|||||||
collapsed: window.app.settings.get("collapseOnLooseFocus") ?? false,
|
collapsed: window.app.settings.get("collapseOnLooseFocus") ?? false,
|
||||||
pathResolvers: null,
|
pathResolvers: null,
|
||||||
menus: null,
|
menus: null,
|
||||||
|
|
||||||
|
customRenderTitle: null,
|
||||||
|
customRender: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle sidedrawer open/close
|
// handle sidedrawer open/close
|
||||||
@ -99,6 +104,38 @@ export default class Sidebar extends React.Component {
|
|||||||
}, 100)
|
}, 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setRender = (render, options = {}) => {
|
||||||
|
if (!typeof render === "function") {
|
||||||
|
throw new Error("Render is required to be a function")
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
customRenderTitle: <div className="render_content_header_title">
|
||||||
|
{
|
||||||
|
options.icon && createIconRender(options.icon)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
options.title && <h1>
|
||||||
|
<Translation>
|
||||||
|
{t => t(options.title)}
|
||||||
|
</Translation>
|
||||||
|
</h1>
|
||||||
|
}
|
||||||
|
</div>,
|
||||||
|
customRender: React.createElement(render, {
|
||||||
|
...options.props ?? {},
|
||||||
|
close: this.closeRender,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
closeRender = () => {
|
||||||
|
this.setState({
|
||||||
|
customRenderTitle: null,
|
||||||
|
customRender: null,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
loadItems = async () => {
|
loadItems = async () => {
|
||||||
const generation = generateItems()
|
const generation = generateItems()
|
||||||
|
|
||||||
@ -213,62 +250,87 @@ export default class Sidebar extends React.Component {
|
|||||||
classnames(
|
classnames(
|
||||||
"app_sidebar",
|
"app_sidebar",
|
||||||
{
|
{
|
||||||
|
["customRender"]: this.state.customRender,
|
||||||
["floating"]: window.app?.settings.get("sidebar.floating"),
|
["floating"]: window.app?.settings.get("sidebar.floating"),
|
||||||
["collapsed"]: this.state.visible && this.state.collapsed,
|
["collapsed"]: !this.state.customRender && this.state.visible && this.state.collapsed,
|
||||||
["elevated"]: this.state.visible && this.state.elevated,
|
["elevated"]: !this.state.visible && this.state.elevated,
|
||||||
["hidden"]: !this.state.visible,
|
["hidden"]: !this.state.visible,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="app_sidebar_header">
|
|
||||||
<div className={classnames("app_sidebar_header_logo", { ["collapsed"]: this.state.collapsed })}>
|
{
|
||||||
<img src={this.state.collapsed ? config.logo?.alt : config.logo?.full} />
|
this.state.customRender &&
|
||||||
|
<div className="render_content_wrapper">
|
||||||
|
<div className="render_content_header">
|
||||||
|
{
|
||||||
|
this.state.customRenderTitle ?? null
|
||||||
|
}
|
||||||
|
<Button
|
||||||
|
onClick={this.closeRender}
|
||||||
|
>
|
||||||
|
Close
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="render_content">
|
||||||
|
{this.state.customRender}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
}
|
||||||
|
|
||||||
<div key="menu" className="app_sidebar_menu_wrapper">
|
{
|
||||||
<Menu selectable={true} mode="inline" onClick={this.handleClick}>
|
!this.state.customRender && <>
|
||||||
{this.renderMenuItems(this.state.menus)}
|
<div className="app_sidebar_header">
|
||||||
</Menu>
|
<div className={classnames("app_sidebar_header_logo", { ["collapsed"]: this.state.collapsed })}>
|
||||||
</div>
|
<img src={this.state.collapsed ? config.logo?.alt : config.logo?.full} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div key="bottom" className={classnames("app_sidebar_menu_wrapper", "bottom")}>
|
<div key="menu" className="app_sidebar_menu_wrapper">
|
||||||
<Menu selectable={false} mode="inline" onClick={this.handleClick}>
|
<Menu selectable={true} mode="inline" onClick={this.handleClick}>
|
||||||
<Menu.Item key="search" icon={<Icons.Search />} override_event="app.openSearcher" >
|
{this.renderMenuItems(this.state.menus)}
|
||||||
<Translation>
|
</Menu>
|
||||||
{(t) => t("Search")}
|
</div>
|
||||||
</Translation>
|
|
||||||
</Menu.Item>
|
<div key="bottom" className={classnames("app_sidebar_menu_wrapper", "bottom")}>
|
||||||
<Menu.Item key="create" icon={<Icons.PlusCircle />} override_event="app.openCreator" >
|
<Menu selectable={false} mode="inline" onClick={this.handleClick}>
|
||||||
<Translation>
|
<Menu.Item key="search" icon={<Icons.Search />} override_event="app.openSearcher" >
|
||||||
{(t) => t("Create")}
|
<Translation>
|
||||||
</Translation>
|
{(t) => t("Search")}
|
||||||
</Menu.Item>
|
</Translation>
|
||||||
<Menu.Item key="notifications" icon={<Icons.Bell />} override_event="app.openNotifications">
|
</Menu.Item>
|
||||||
<Translation>
|
<Menu.Item key="create" icon={<Icons.PlusCircle />} override_event="app.openCreator" >
|
||||||
{t => t("Notifications")}
|
<Translation>
|
||||||
</Translation>
|
{(t) => t("Create")}
|
||||||
</Menu.Item>
|
</Translation>
|
||||||
<Menu.Item key="settings" icon={<Icons.Settings />}>
|
</Menu.Item>
|
||||||
<Translation>
|
<Menu.Item key="notifications" icon={<Icons.Bell />} override_event="app.openNotifications">
|
||||||
{t => t("Settings")}
|
<Translation>
|
||||||
</Translation>
|
{t => t("Notifications")}
|
||||||
</Menu.Item>
|
</Translation>
|
||||||
{
|
</Menu.Item>
|
||||||
app.userData && <Menu.Item key="account" className="user_avatar">
|
<Menu.Item key="settings" icon={<Icons.Settings />}>
|
||||||
<Avatar shape="square" src={app.userData?.avatar} />
|
<Translation>
|
||||||
</Menu.Item>
|
{t => t("Settings")}
|
||||||
}
|
</Translation>
|
||||||
{
|
</Menu.Item>
|
||||||
!app.userData && <Menu.Item key="login" icon={<Icons.LogIn />}>
|
{
|
||||||
<Translation>
|
app.userData && <Menu.Item key="account" className="user_avatar">
|
||||||
{t => t("Login")}
|
<Avatar shape="square" src={app.userData?.avatar} />
|
||||||
</Translation>
|
</Menu.Item>
|
||||||
</Menu.Item>
|
}
|
||||||
}
|
{
|
||||||
</Menu>
|
!app.userData && <Menu.Item key="login" icon={<Icons.LogIn />}>
|
||||||
</div>
|
<Translation>
|
||||||
|
{t => t("Login")}
|
||||||
|
</Translation>
|
||||||
|
</Menu.Item>
|
||||||
|
}
|
||||||
|
</Menu>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
&.hidden {
|
||||||
flex: 0 !important;
|
flex: 0 !important;
|
||||||
min-width: 0 !important;
|
min-width: 0 !important;
|
||||||
@ -55,6 +74,52 @@
|
|||||||
box-shadow: 0 0 5px 4px rgba(0, 0, 0, 0.1) !important;
|
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 {
|
.app_sidebar_header {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -178,4 +243,24 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
flex: 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;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user