feat : support fixed menu and header (#1260)
* feat: support fixed menu and header * revert: power by * fix: designer not work * fix: cannot scroll * feat: fixed menu in center * fix: cannot scroll * fix: unused
This commit is contained in:
parent
6a0b38b7a2
commit
940f5f0152
@ -21,7 +21,7 @@
|
|||||||
"@formily/react": "2.0.20",
|
"@formily/react": "2.0.20",
|
||||||
"@nocobase/sdk": "0.8.0-alpha.13",
|
"@nocobase/sdk": "0.8.0-alpha.13",
|
||||||
"@nocobase/utils": "0.8.0-alpha.13",
|
"@nocobase/utils": "0.8.0-alpha.13",
|
||||||
"ahooks": "^3.0.5",
|
"ahooks": "^3.7.2",
|
||||||
"antd": "~4.19.5",
|
"antd": "~4.19.5",
|
||||||
"axios": "^0.26.1",
|
"axios": "^0.26.1",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
|
@ -287,51 +287,75 @@ const SettingsCenter = (props) => {
|
|||||||
}
|
}
|
||||||
const component = items[pluginName]?.tabs?.[tabName]?.component;
|
const component = items[pluginName]?.tabs?.[tabName]?.component;
|
||||||
return (
|
return (
|
||||||
<div>
|
<Layout>
|
||||||
<Layout>
|
<div
|
||||||
<Layout.Sider theme={'light'}>
|
style={
|
||||||
<Menu selectedKeys={[pluginName]} style={{ height: 'calc(100vh - 46px)' }}>
|
{
|
||||||
{Object.keys(items)
|
'--side-menu-width': '200px',
|
||||||
.sort()
|
} as Record<string, string>
|
||||||
.map((key) => {
|
}
|
||||||
const item = items[key];
|
className={css`
|
||||||
const tabKey = Object.keys(item.tabs).shift();
|
width: var(--side-menu-width);
|
||||||
return (
|
overflow: hidden;
|
||||||
<Menu.Item
|
flex: 0 0 var(--side-menu-width);
|
||||||
key={key}
|
max-width: var(--side-menu-width);
|
||||||
icon={item.icon ? <Icon type={item.icon} /> : null}
|
min-width: var(--side-menu-width);
|
||||||
onClick={() => {
|
pointer-events: none;
|
||||||
history.push(`/admin/settings/${key}/${tabKey}`);
|
`}
|
||||||
}}
|
></div>
|
||||||
>
|
<Layout.Sider
|
||||||
{compile(item.title)}
|
className={css`
|
||||||
</Menu.Item>
|
height: 100%;
|
||||||
);
|
position: fixed;
|
||||||
|
padding-top: 46px;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
background: rgba(0, 0, 0, 0);
|
||||||
|
z-index: 100;
|
||||||
|
`}
|
||||||
|
theme={'light'}
|
||||||
|
>
|
||||||
|
<Menu selectedKeys={[pluginName]} style={{ height: 'calc(100vh - 46px)' }}>
|
||||||
|
{Object.keys(items)
|
||||||
|
.sort()
|
||||||
|
.map((key) => {
|
||||||
|
const item = items[key];
|
||||||
|
const tabKey = Object.keys(item.tabs).shift();
|
||||||
|
return (
|
||||||
|
<Menu.Item
|
||||||
|
key={key}
|
||||||
|
icon={item.icon ? <Icon type={item.icon} /> : null}
|
||||||
|
onClick={() => {
|
||||||
|
history.push(`/admin/settings/${key}/${tabKey}`);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{compile(item.title)}
|
||||||
|
</Menu.Item>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Menu>
|
||||||
|
</Layout.Sider>
|
||||||
|
<Layout.Content>
|
||||||
|
<PageHeader
|
||||||
|
ghost={false}
|
||||||
|
title={compile(items[pluginName]?.title)}
|
||||||
|
footer={
|
||||||
|
<Tabs
|
||||||
|
activeKey={tabName}
|
||||||
|
onChange={(activeKey) => {
|
||||||
|
history.push(`/admin/settings/${pluginName}/${activeKey}`);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{Object.keys(items[pluginName]?.tabs).map((tabKey) => {
|
||||||
|
const tab = items[pluginName].tabs?.[tabKey];
|
||||||
|
return <Tabs.TabPane tab={compile(tab?.title)} key={tabKey} />;
|
||||||
})}
|
})}
|
||||||
</Menu>
|
</Tabs>
|
||||||
</Layout.Sider>
|
}
|
||||||
<Layout.Content>
|
/>
|
||||||
<PageHeader
|
<div style={{ margin: 24 }}>{component && React.createElement(component)}</div>
|
||||||
ghost={false}
|
</Layout.Content>
|
||||||
title={compile(items[pluginName]?.title)}
|
</Layout>
|
||||||
footer={
|
|
||||||
<Tabs
|
|
||||||
activeKey={tabName}
|
|
||||||
onChange={(activeKey) => {
|
|
||||||
history.push(`/admin/settings/${pluginName}/${activeKey}`);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{Object.keys(items[pluginName]?.tabs).map((tabKey) => {
|
|
||||||
const tab = items[pluginName].tabs?.[tabKey];
|
|
||||||
return <Tabs.TabPane tab={compile(tab?.title)} key={tabKey} />;
|
|
||||||
})}
|
|
||||||
</Tabs>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<div style={{ margin: 24 }}>{component && React.createElement(component)}</div>
|
|
||||||
</Layout.Content>
|
|
||||||
</Layout>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import { Layout, Spin } from 'antd';
|
import { Layout, Spin } from 'antd';
|
||||||
import React, { createContext, useContext, useMemo, useRef } from 'react';
|
import React, { createContext, useContext, useMemo, useRef, useState } from 'react';
|
||||||
import { useHistory, useRouteMatch } from 'react-router-dom';
|
import { useHistory, useRouteMatch } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
ACLAllowConfigure,
|
ACLAllowConfigure,
|
||||||
@ -22,6 +22,7 @@ import {
|
|||||||
} from '../../../';
|
} from '../../../';
|
||||||
import { useCollectionManager } from '../../../collection-manager';
|
import { useCollectionManager } from '../../../collection-manager';
|
||||||
import { PoweredBy } from '../../../powered-by';
|
import { PoweredBy } from '../../../powered-by';
|
||||||
|
import { useMutationObserver } from 'ahooks';
|
||||||
|
|
||||||
const filterByACL = (schema, options) => {
|
const filterByACL = (schema, options) => {
|
||||||
const { allowAll, allowConfigure, allowMenuItemIds = [] } = options;
|
const { allowAll, allowConfigure, allowMenuItemIds = [] } = options;
|
||||||
@ -123,11 +124,20 @@ const MenuEditor = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const InternalAdminLayout = (props: any) => {
|
const InternalAdminLayout = (props: any) => {
|
||||||
const route = useRoute();
|
const sideMenuRef = useRef<HTMLDivElement>();
|
||||||
const history = useHistory();
|
const [sideMenuWidth, setSideMenuWidth] = useState(0);
|
||||||
const match = useRouteMatch<any>();
|
|
||||||
const { setTitle } = useDocumentTitle();
|
useMutationObserver(
|
||||||
const sideMenuRef = useRef();
|
(value) => {
|
||||||
|
const width = (value[0].target as HTMLDivElement).offsetWidth;
|
||||||
|
setSideMenuWidth(width);
|
||||||
|
},
|
||||||
|
sideMenuRef,
|
||||||
|
{
|
||||||
|
childList: true,
|
||||||
|
attributes: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const result = useSystemSettings();
|
const result = useSystemSettings();
|
||||||
const { service } = useCollectionManager();
|
const { service } = useCollectionManager();
|
||||||
@ -142,65 +152,114 @@ const InternalAdminLayout = (props: any) => {
|
|||||||
.ant-menu-dark.ant-menu-horizontal > .ant-menu-item:hover {
|
.ant-menu-dark.ant-menu-horizontal > .ant-menu-item:hover {
|
||||||
background-color: rgba(255, 255, 255, 0.1);
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
height: 46px;
|
||||||
|
line-height: 46px;
|
||||||
|
padding: 0;
|
||||||
|
z-index: 100;
|
||||||
`}
|
`}
|
||||||
style={{ height: 46, lineHeight: '46px', position: 'relative', paddingLeft: 0 }}
|
|
||||||
>
|
>
|
||||||
<div style={{ position: 'relative', zIndex: 1, display: 'flex', height: '100%', width: 'calc(100vw - 300px)' }}>
|
<div
|
||||||
<div style={{ width: 200, display: 'inline-flex', color: '#fff', padding: '0', alignItems: 'center' }}>
|
|
||||||
<img
|
|
||||||
className={css`
|
|
||||||
padding: 0 16px;
|
|
||||||
object-fit: contain;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
`}
|
|
||||||
src={result?.data?.data?.logo?.url}
|
|
||||||
/>
|
|
||||||
{/* {result?.data?.data?.title} */}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
width: 'calc(100% - 590px)',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MenuEditor sideMenuRef={sideMenuRef} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style={{ position: 'absolute', zIndex: 10, top: 0, right: 0 }}>
|
|
||||||
<ACLAllowConfigure>
|
|
||||||
<RemotePluginManagerToolbar />
|
|
||||||
</ACLAllowConfigure>
|
|
||||||
<CurrentUser />
|
|
||||||
</div>
|
|
||||||
</Layout.Header>
|
|
||||||
<Layout>
|
|
||||||
<Layout.Sider style={{ display: 'none' }} theme={'light'} ref={sideMenuRef}></Layout.Sider>
|
|
||||||
<Layout.Content
|
|
||||||
className={css`
|
className={css`
|
||||||
min-height: calc(100vh - 46px);
|
|
||||||
padding-bottom: 42px;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
// padding-bottom: 70px;
|
width: 100%;
|
||||||
> div {
|
height: 100%;
|
||||||
position: relative;
|
|
||||||
// z-index: 1;
|
|
||||||
}
|
|
||||||
.ant-layout-footer {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
text-align: center;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 0;
|
|
||||||
padding: 0px 50px;
|
|
||||||
}
|
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
{service.contentLoading ? <Spin /> : props.children}
|
<div
|
||||||
<Layout.Footer>
|
style={{ position: 'relative', zIndex: 1, display: 'flex', height: '100%', width: 'calc(100vw - 300px)' }}
|
||||||
<PoweredBy />
|
>
|
||||||
</Layout.Footer>
|
<div style={{ width: 200, display: 'inline-flex', color: '#fff', padding: '0', alignItems: 'center' }}>
|
||||||
</Layout.Content>
|
<img
|
||||||
</Layout>
|
className={css`
|
||||||
|
padding: 0 16px;
|
||||||
|
object-fit: contain;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
`}
|
||||||
|
src={result?.data?.data?.logo?.url}
|
||||||
|
/>
|
||||||
|
{/* {result?.data?.data?.title} */}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: 'calc(100% - 590px)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MenuEditor sideMenuRef={sideMenuRef} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{ position: 'absolute', height: '100%', zIndex: 10, top: 0, right: 0 }}>
|
||||||
|
<ACLAllowConfigure>
|
||||||
|
<RemotePluginManagerToolbar />
|
||||||
|
</ACLAllowConfigure>
|
||||||
|
<CurrentUser />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Layout.Header>
|
||||||
|
<div
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
'--side-menu-width': `${sideMenuWidth}px`,
|
||||||
|
} as Record<string, string>
|
||||||
|
}
|
||||||
|
className={css`
|
||||||
|
width: var(--side-menu-width);
|
||||||
|
overflow: hidden;
|
||||||
|
flex: 0 0 var(--side-menu-width);
|
||||||
|
max-width: var(--side-menu-width);
|
||||||
|
min-width: var(--side-menu-width);
|
||||||
|
pointer-events: none;
|
||||||
|
transition: background-color 0.3s ease 0s, min-width 0.3s ease 0s,
|
||||||
|
max-width 0.3s cubic-bezier(0.645, 0.045, 0.355, 1) 0s;
|
||||||
|
`}
|
||||||
|
></div>
|
||||||
|
<Layout.Sider
|
||||||
|
className={css`
|
||||||
|
height: 100%;
|
||||||
|
position: fixed;
|
||||||
|
padding-top: 46px;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
background: rgba(0, 0, 0, 0);
|
||||||
|
z-index: 100;
|
||||||
|
`}
|
||||||
|
style={{ display: 'none' }}
|
||||||
|
theme={'light'}
|
||||||
|
ref={sideMenuRef}
|
||||||
|
></Layout.Sider>
|
||||||
|
<Layout.Content
|
||||||
|
className={css`
|
||||||
|
position: relative;
|
||||||
|
overflow-y: auto;
|
||||||
|
height: 100vh;
|
||||||
|
max-height: 100vh;
|
||||||
|
> div {
|
||||||
|
position: relative;
|
||||||
|
// z-index: 1;
|
||||||
|
}
|
||||||
|
.ant-layout-footer {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 0;
|
||||||
|
padding: 0px 50px;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<header
|
||||||
|
className={css`
|
||||||
|
height: 46px;
|
||||||
|
line-height: 46px;
|
||||||
|
background: transparent;
|
||||||
|
pointer-events: none;
|
||||||
|
`}
|
||||||
|
></header>
|
||||||
|
{service.contentLoading ? <Spin /> : props.children}
|
||||||
|
</Layout.Content>
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -290,6 +290,7 @@ export const Menu: ComposedMenu = observer((props) => {
|
|||||||
onSelect && onSelect(info);
|
onSelect && onSelect(info);
|
||||||
}}
|
}}
|
||||||
className={css`
|
className={css`
|
||||||
|
height: 100%;
|
||||||
.ant-menu-item {
|
.ant-menu-item {
|
||||||
> .ant-menu-title-content {
|
> .ant-menu-title-content {
|
||||||
margin-left: -24px;
|
margin-left: -24px;
|
||||||
|
@ -63,6 +63,7 @@ const pageDesignerCss = css`
|
|||||||
position: relative;
|
position: relative;
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
padding-top: 1px;
|
padding-top: 1px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
> .general-schema-designer {
|
> .general-schema-designer {
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -13,6 +13,6 @@
|
|||||||
"@emotion/css": "^11.7.1",
|
"@emotion/css": "^11.7.1",
|
||||||
"antd": "~4.19.5",
|
"antd": "~4.19.5",
|
||||||
"sequelize": "^6.9.0",
|
"sequelize": "^6.9.0",
|
||||||
"ahooks": "^3.0.5"
|
"ahooks": "^3.7.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
30
yarn.lock
30
yarn.lock
@ -5225,6 +5225,11 @@
|
|||||||
jest-diff "^26.0.0"
|
jest-diff "^26.0.0"
|
||||||
pretty-format "^26.0.0"
|
pretty-format "^26.0.0"
|
||||||
|
|
||||||
|
"@types/js-cookie@^2.x.x":
|
||||||
|
version "2.2.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.7.tgz#226a9e31680835a6188e887f3988e60c04d3f6a3"
|
||||||
|
integrity sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==
|
||||||
|
|
||||||
"@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8":
|
"@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8":
|
||||||
version "7.0.9"
|
version "7.0.9"
|
||||||
resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
|
resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
|
||||||
@ -6169,14 +6174,21 @@ aggregate-error@^3.0.0:
|
|||||||
clean-stack "^2.0.0"
|
clean-stack "^2.0.0"
|
||||||
indent-string "^4.0.0"
|
indent-string "^4.0.0"
|
||||||
|
|
||||||
ahooks@^3.0.5:
|
ahooks-v3-count@^1.0.0:
|
||||||
version "3.0.5"
|
version "1.0.0"
|
||||||
resolved "https://registry.npmjs.org/ahooks/-/ahooks-3.0.5.tgz#7cf1a057ae147ac02732c3eddb00a793006df9d6"
|
resolved "https://registry.yarnpkg.com/ahooks-v3-count/-/ahooks-v3-count-1.0.0.tgz#ddeb392e009ad6e748905b3cbf63a9fd8262ca80"
|
||||||
integrity sha512-/l8HoNPzJVoexChfw7zlRD1/VyX1X7F08AVNnwkRwgufu1AfUd96XcIStrRsmADqMQWllluLRodEzPbcKUGUzQ==
|
integrity sha512-V7uUvAwnimu6eh/PED4mCDjE7tokeZQLKlxg9lCTMPhN+NjsSbtdacByVlR1oluXQzD3MOw55wylDmQo4+S9ZQ==
|
||||||
|
|
||||||
|
ahooks@^3.7.2:
|
||||||
|
version "3.7.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/ahooks/-/ahooks-3.7.2.tgz#0afa42625e77ae1cc4b60b19c45cf12a8cf29b56"
|
||||||
|
integrity sha512-nJPsQJcmJnGaNXiqgZdfO7UMs+o926LQg6VyDYt2vzKhXU8Ze/U87NsA/FeIvlIZB0rQr/j7uotFb1bGPp627A==
|
||||||
dependencies:
|
dependencies:
|
||||||
|
"@types/js-cookie" "^2.x.x"
|
||||||
|
ahooks-v3-count "^1.0.0"
|
||||||
dayjs "^1.9.1"
|
dayjs "^1.9.1"
|
||||||
intersection-observer "^0.12.0"
|
intersection-observer "^0.12.0"
|
||||||
js-cookie "^3.0.0"
|
js-cookie "^2.x.x"
|
||||||
lodash "^4.17.21"
|
lodash "^4.17.21"
|
||||||
resize-observer-polyfill "^1.5.1"
|
resize-observer-polyfill "^1.5.1"
|
||||||
screenfull "^5.0.0"
|
screenfull "^5.0.0"
|
||||||
@ -14089,10 +14101,10 @@ js-base64@^2.5.2:
|
|||||||
resolved "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4"
|
resolved "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4"
|
||||||
integrity sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==
|
integrity sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==
|
||||||
|
|
||||||
js-cookie@^3.0.0:
|
js-cookie@^2.x.x:
|
||||||
version "3.0.1"
|
version "2.2.1"
|
||||||
resolved "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.1.tgz#9e39b4c6c2f56563708d7d31f6f5f21873a92414"
|
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
|
||||||
integrity sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==
|
integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
|
||||||
|
|
||||||
js-git@^0.7.8:
|
js-git@^0.7.8:
|
||||||
version "0.7.8"
|
version "0.7.8"
|
||||||
|
Loading…
Reference in New Issue
Block a user