rework navmenu to use header

This commit is contained in:
SrGooglo 2023-08-17 17:53:20 +00:00
parent 5d4809e574
commit f207ebb037
7 changed files with 128 additions and 229 deletions

View File

@ -1,27 +1,52 @@
import React from "react" import React from "react"
import classnames from "classnames" import classnames from "classnames"
import { Motion, spring } from "react-motion"
import useLayoutInterface from "hooks/useLayoutInterface"
import "./index.less" import "./index.less"
export default (props) => { export default (props) => {
const [visible, setVisible] = React.useState(false) const [render, setRender] = React.useState(null)
const headerInterface = { useLayoutInterface("header", {
toggle: (to) => setVisible((prevValue) => to ?? !prevValue), render: (component, options) => {
} if (component === null) {
return setRender(null)
React.useEffect(() => {
app.layout.header = headerInterface
}, [])
return <div
className={classnames(
"page_header",
{
["visible"]: visible,
} }
)}
return setRender({
component,
options
})
}
})
return <Motion
style={{
y: spring(render ? 0 : 100,),
}}
> >
{String(window.location.pathname).toTitleCase()} {({ y, height }) => {
</div> return <div
className={classnames(
"page_header_wrapper",
{
["hidden"]: !render,
}
)}
style={{
WebkitTransform: `translateY(-${y}px)`,
transform: `translateY(-${y}px)`,
}}
>
{
render?.component && React.cloneElement(
render?.component,
render?.options?.props ?? {}
)
}
</div>
}}
</Motion>
} }

View File

@ -1,4 +1,4 @@
.page_header { .page_header_wrapper {
position: sticky; position: sticky;
z-index: 100; z-index: 100;
@ -6,26 +6,24 @@
top: 0; top: 0;
left: 0; left: 0;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
overflow: hidden;
// hidden values
padding: 0;
opacity: 0;
height: 0px;
width: 100%; width: 100%;
transition: all 150ms ease-in-out; margin-bottom: 20px;
padding: 5px;
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
&.visible { background-color: rgba(var(--background-color-accent-values), 0.8);
opacity: 1;
height: 50px; border-radius: 12px;
padding: 20px; border: 1px solid var(--border-color);
overflow: hidden;
&.hidden {
opacity: 0;
height: 0;
padding: 0;
margin: 0;
} }
} }

View File

@ -4,30 +4,8 @@ import * as antd from "antd"
import "./index.less" import "./index.less"
const NavMenu = (props) => {
const handleOnClickItem = (event) => {
return props.onClickItem(event.key)
}
return <div className="navmenu_wrapper"> export default (props) => {
<div className="card">
{
props.header && <div className="card_header">
{props.header}
</div>
}
<antd.Menu
mode="inline"
selectedKeys={[props.activeKey]}
onClick={handleOnClickItem}
items={props.items}
/>
</div>
</div>
}
const NavMenuMobile = (props) => {
function handleClickItem(item) { function handleClickItem(item) {
if (item.children && Array.isArray(item.children)) { if (item.children && Array.isArray(item.children)) {
return false return false
@ -38,7 +16,7 @@ const NavMenuMobile = (props) => {
return <div return <div
className={classnames( className={classnames(
"__mobile__navmenu_wrapper", "navmenu_wrapper",
)} )}
> >
{ {
@ -56,7 +34,7 @@ const NavMenuMobile = (props) => {
<antd.Button <antd.Button
key={item.key} key={item.key}
className={classnames( className={classnames(
"__mobile__navmenu_item", "navmenu_item",
item.key === props.activeKey && "active", item.key === props.activeKey && "active",
)} )}
type="ghost" type="ghost"
@ -65,6 +43,14 @@ const NavMenuMobile = (props) => {
<div className="icon"> <div className="icon">
{item.icon} {item.icon}
</div> </div>
{
props.renderNames && <div className="label">
<p>
{item.label ?? item.id}
</p>
</div>
}
</antd.Button> </antd.Button>
</antd.Dropdown> </antd.Dropdown>
} }
@ -72,7 +58,7 @@ const NavMenuMobile = (props) => {
return <antd.Button return <antd.Button
key={item.key} key={item.key}
className={classnames( className={classnames(
"__mobile__navmenu_item", "navmenu_item",
item.key === props.activeKey && "active", item.key === props.activeKey && "active",
)} )}
onClick={() => handleClickItem(item)} onClick={() => handleClickItem(item)}
@ -82,10 +68,16 @@ const NavMenuMobile = (props) => {
<div className="icon"> <div className="icon">
{item.icon} {item.icon}
</div> </div>
{
props.renderNames && <div className="label">
<p>
{item.label ?? item.id}
</p>
</div>
}
</antd.Button> </antd.Button>
}) })
} }
</div> </div>
} }
export default app.isMobile ? NavMenuMobile : NavMenu

View File

@ -1,64 +1,6 @@
@import "theme/vars.less"; @import "theme/vars.less";
.navmenu_wrapper { .navmenu_wrapper {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
.card {
display: flex;
flex-direction: column;
background-color: var(--background-color-accent);
border-radius: 12px;
padding: 20px;
width: 100%;
h1,
h2 {
width: fit-content;
margin: 0;
}
.card_header {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
view-transition-name: main-header;
h1 {
view-transition-name: main-header-text;
}
}
&.content {
position: relative;
transform: translateY(-30px);
padding-top: 35px;
z-index: 45;
}
}
&.card:last-child {
margin-bottom: 0;
}
}
.__mobile__navmenu_wrapper {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -66,9 +8,10 @@
width: 100%; width: 100%;
.__mobile__navmenu_item { .navmenu_item {
font-size: 0.7rem;
display: flex; display: flex;
flex-direction: column; flex-direction: row;
align-items: center; align-items: center;
@ -82,10 +25,16 @@
color: var(--colorPrimary); color: var(--colorPrimary);
} }
p {
margin: 0;
}
.icon { .icon {
margin: 0; margin: 0;
line-height: 1rem; line-height: 1rem;
font-size: 1.5rem; font-size: 1.5rem;
font-size: 1rem;
} }
.label { .label {

View File

@ -72,6 +72,8 @@ export class PagePanelWithNavMenu extends React.Component {
if (app.isMobile) { if (app.isMobile) {
app.layout.top_bar.shouldUseTopBarSpacer(true) app.layout.top_bar.shouldUseTopBarSpacer(true)
} else {
app.layout.header.render(null)
} }
} }
@ -119,7 +121,10 @@ export class PagePanelWithNavMenu extends React.Component {
const componentProps = tab.props ?? this.props.tabProps const componentProps = tab.props ?? this.props.tabProps
return React.createElement(tab.component, componentProps) return React.createElement(tab.component, {
...componentProps,
ref: this.primaryPanelRef,
})
} }
replaceQueryTypeToCurrentTab = () => { replaceQueryTypeToCurrentTab = () => {
@ -186,16 +191,23 @@ export class PagePanelWithNavMenu extends React.Component {
} }
render() { render() {
const panels = [ return <>
{ {
children: <> app.isMobile && app.layout.top_bar.render(<NavMenu
<NavMenu activeKey={this.state.activeTab}
header={this.props.navMenuHeader} items={this.getItems(this.props.tabs)}
activeKey={this.state.activeTab} onClickItem={(key) => this.handleTabChange(key)}
items={this.getItems(this.props.tabs)} />)
onClickItem={(key) => this.handleTabChange(key)} }
/>
{
!app.isMobile && app.layout.header.render(<NavMenu
header={this.props.navMenuHeader}
activeKey={this.state.activeTab}
items={this.getItems(this.props.tabs)}
onClickItem={(key) => this.handleTabChange(key)}
renderNames
>
{ {
Array.isArray(this.state.renders) && [ Array.isArray(this.state.renders) && [
this.state.renders.map((render, index) => { this.state.renders.map((render, index) => {
@ -206,98 +218,14 @@ export class PagePanelWithNavMenu extends React.Component {
}) })
] ]
} }
</> </NavMenu>)
}, }
{
props: { {
ref: this.primaryPanelRef, this.renderActiveTab()
className: this.props.transition ? "fade-opacity-enter" : undefined,
},
children: this.renderActiveTab()
},
]
if (app.isMobile) {
delete panels[0]
}
if (this.props.extraPanel) {
panels.push(this.props.extraPanel)
}
return <>
{
app.isMobile && app.layout.top_bar.render(<NavMenu
activeKey={this.state.activeTab}
items={this.getItems(this.props.tabs)}
onClickItem={(key) => this.handleTabChange(key)}
/>)
} }
<PagePanels
primaryPanelClassName={this.props.primaryPanelClassName}
panels={panels}
masked={this.props.masked}
no_top_padding={this.props.no_top_padding}
/>
</> </>
} }
} }
export default class PagePanels extends React.Component { export default PagePanelWithNavMenu
generateGridStyle = () => {
switch (this.props.panels.length) {
case 1: {
return {
gridTemplateColumns: "1fr",
}
}
case 2: {
return {
gridTemplateColumns: "1fr 3fr",
}
}
case 3: {
return {
gridTemplateColumns: "0.5fr 1fr 0.5fr",
}
}
}
}
render() {
if (!this.props.panels) {
return null
}
return <div
className={classnames(
"pagePanels",
{
["masked"]: this.props.masked,
["withTopPadding"]: !!!this.props.no_top_padding
}
)}
style={this.generateGridStyle()}
>
{
this.props.panels[0] && <Panel
{...this.props.panels[0]}
align="left"
/>
}
{
this.props.panels[1] && <Panel
{...this.props.panels[1]}
className={this.props.primaryPanelClassName}
align="center"
/>
}
{
this.props.panels[2] && <Panel
{...this.props.panels[2]}
align="right"
/>
}
</div>
}
}

View File

@ -53,12 +53,8 @@ html {
} }
.pagePanels { .pagePanels {
display: grid; display: flex;
flex-direction: column;
grid-template-columns: 1fr 3fr;
grid-template-rows: 1fr;
grid-column-gap: 20px;
grid-row-gap: 0px;
width: 100%; width: 100%;

View File

@ -2,7 +2,15 @@ import React from "react"
import classnames from "classnames" import classnames from "classnames"
import { Layout } from "antd" import { Layout } from "antd"
import { Sidebar, Drawer, Sidedrawer, BottomBar, TopBar, ToolsBar } from "components/Layout" import {
Sidebar,
Drawer,
Sidedrawer,
BottomBar,
TopBar,
ToolsBar,
Header,
} from "components/Layout"
import BackgroundDecorator from "components/BackgroundDecorator" import BackgroundDecorator from "components/BackgroundDecorator"
@ -27,6 +35,7 @@ const DesktopLayout = (props) => {
<Drawer /> <Drawer />
<Sidebar /> <Sidebar />
<Sidedrawer /> <Sidedrawer />
<Layout.Content <Layout.Content
id="content_layout" id="content_layout"
className={classnames( className={classnames(
@ -35,6 +44,8 @@ const DesktopLayout = (props) => {
"fade-transverse-active", "fade-transverse-active",
)} )}
> >
<Header />
{ {
props.children && React.cloneElement(props.children, props) props.children && React.cloneElement(props.children, props)
} }