@refinedev/antd 5.6.0 → 5.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/dist/components/index.d.ts +5 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/themedLayout/header/index.d.ts +3 -0
- package/dist/components/themedLayout/header/index.d.ts.map +1 -1
- package/dist/components/themedLayout/index.d.ts +3 -0
- package/dist/components/themedLayout/index.d.ts.map +1 -1
- package/dist/components/themedLayout/sider/index.d.ts +3 -0
- package/dist/components/themedLayout/sider/index.d.ts.map +1 -1
- package/dist/components/themedLayout/title/index.d.ts +3 -0
- package/dist/components/themedLayout/title/index.d.ts.map +1 -1
- package/dist/components/themedLayoutV2/header/index.d.ts +4 -0
- package/dist/components/themedLayoutV2/header/index.d.ts.map +1 -0
- package/dist/components/themedLayoutV2/index.d.ts +4 -0
- package/dist/components/themedLayoutV2/index.d.ts.map +1 -0
- package/dist/components/themedLayoutV2/sider/index.d.ts +4 -0
- package/dist/components/themedLayoutV2/sider/index.d.ts.map +1 -0
- package/dist/components/themedLayoutV2/sider/styles.d.ts +3 -0
- package/dist/components/themedLayoutV2/sider/styles.d.ts.map +1 -0
- package/dist/components/themedLayoutV2/title/index.d.ts +4 -0
- package/dist/components/themedLayoutV2/title/index.d.ts.map +1 -0
- package/dist/components/themedLayoutV2/types.d.ts +3 -0
- package/dist/components/themedLayoutV2/types.d.ts.map +1 -0
- package/dist/contexts/index.d.ts +2 -0
- package/dist/contexts/index.d.ts.map +1 -0
- package/dist/contexts/themedLayoutContext/IThemedLayoutContext.d.ts +7 -0
- package/dist/contexts/themedLayoutContext/IThemedLayoutContext.d.ts.map +1 -0
- package/dist/contexts/themedLayoutContext/index.d.ts +7 -0
- package/dist/contexts/themedLayoutContext/index.d.ts.map +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/useSiderVisible/index.d.ts +4 -0
- package/dist/hooks/useSiderVisible/index.d.ts.map +1 -0
- package/dist/iife/index.js +12 -6
- package/dist/iife/index.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/refine.config.js +122 -1
- package/src/components/index.ts +6 -0
- package/src/components/themedLayout/header/index.tsx +3 -0
- package/src/components/themedLayout/index.tsx +3 -0
- package/src/components/themedLayout/sider/index.tsx +3 -0
- package/src/components/themedLayout/title/index.tsx +3 -0
- package/src/components/themedLayoutV2/header/index.tsx +44 -0
- package/src/components/themedLayoutV2/index.tsx +44 -0
- package/src/components/themedLayoutV2/sider/index.tsx +324 -0
- package/src/components/themedLayoutV2/sider/styles.ts +9 -0
- package/src/components/themedLayoutV2/title/index.tsx +85 -0
- package/src/components/themedLayoutV2/types.ts +13 -0
- package/src/contexts/index.ts +4 -0
- package/src/contexts/themedLayoutContext/IThemedLayoutContext.ts +6 -0
- package/src/contexts/themedLayoutContext/index.tsx +28 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useSiderVisible/index.ts +22 -0
- package/src/index.tsx +1 -0
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@refinedev/antd",
|
3
|
-
"version": "5.
|
3
|
+
"version": "5.7.0",
|
4
4
|
"description": "refine is a React-based framework for building internal tools, rapidly. It ships with Ant Design System, an enterprise-level UI toolkit.",
|
5
5
|
"private": false,
|
6
6
|
"main": "dist/index.js",
|
@@ -23,7 +23,7 @@
|
|
23
23
|
"react-dom": "^17.0.0 || ^18.0.0"
|
24
24
|
},
|
25
25
|
"devDependencies": {
|
26
|
-
"@refinedev/cli": "^2.1
|
26
|
+
"@refinedev/cli": "^2.5.1",
|
27
27
|
"@refinedev/ui-tests": "^1.3.2",
|
28
28
|
"@refinedev/core": "^4.8.0",
|
29
29
|
"@esbuild-plugins/node-resolve": "^0.1.4",
|
@@ -49,7 +49,7 @@
|
|
49
49
|
"dependencies": {
|
50
50
|
"@ant-design/icons": "^5.0.1",
|
51
51
|
"@ant-design/pro-layout": "7.8.3",
|
52
|
-
"@refinedev/ui-types": "^1.
|
52
|
+
"@refinedev/ui-types": "^1.8.0",
|
53
53
|
"@tanstack/react-query": "^4.10.1",
|
54
54
|
"antd": "^5.0.5",
|
55
55
|
"dayjs": "^1.10.7",
|
package/refine.config.js
CHANGED
@@ -560,7 +560,128 @@ module.exports = {
|
|
560
560
|
},
|
561
561
|
{
|
562
562
|
group: "Other",
|
563
|
-
label: "
|
563
|
+
label: "ThemedLayoutV2",
|
564
|
+
message: `
|
565
|
+
**\`Warning:\`**
|
566
|
+
If you want to change the default layout;
|
567
|
+
You should pass layout related components to the **<ThemedLayoutV2 />** component's props.
|
568
|
+
|
569
|
+
\`\`\`
|
570
|
+
// title: App.tsx
|
571
|
+
import { ThemedLayoutV2 } from "components/themedLayout";
|
572
|
+
import { ThemedHeaderV2 } from "components/themedLayout/header";
|
573
|
+
import { ThemedSiderV2 } from "components/themedLayout/sider";
|
574
|
+
import { ThemedTitleV2 } from "components/themedLayout/title";
|
575
|
+
|
576
|
+
const App = () => {
|
577
|
+
return (
|
578
|
+
<Refine
|
579
|
+
/* ... */
|
580
|
+
>
|
581
|
+
<ThemedLayoutV2 Header={ThemedHeaderV2} Sider={ThemedSiderV2} Title={ThemedTitleV2}>
|
582
|
+
/* ... */
|
583
|
+
</ThemedLayoutV2>
|
584
|
+
</Refine>
|
585
|
+
);
|
586
|
+
}
|
587
|
+
\`\`\`
|
588
|
+
`,
|
589
|
+
files: [
|
590
|
+
{
|
591
|
+
src: "./src/components/themedLayoutV2/sider/index.tsx",
|
592
|
+
dest: "./components/themedLayout/sider.tsx",
|
593
|
+
transform: (content) => {
|
594
|
+
let newContent = content;
|
595
|
+
const imports = getImports(content);
|
596
|
+
|
597
|
+
imports.map((importItem) => {
|
598
|
+
// handle @components import replacement
|
599
|
+
if (
|
600
|
+
importItem.importPath === "@components" ||
|
601
|
+
importItem.importPath === "@hooks"
|
602
|
+
) {
|
603
|
+
const newStatement = `import ${importItem.namedImports} from "@refinedev/antd";`;
|
604
|
+
|
605
|
+
newContent = newContent.replace(
|
606
|
+
importItem.statement,
|
607
|
+
newStatement,
|
608
|
+
);
|
609
|
+
}
|
610
|
+
|
611
|
+
// add content of ./styles.ts and remove import
|
612
|
+
if (importItem.importPath === "./styles") {
|
613
|
+
newContent = newContent.replace(
|
614
|
+
importItem.statement,
|
615
|
+
"",
|
616
|
+
);
|
617
|
+
|
618
|
+
let appending = "";
|
619
|
+
|
620
|
+
try {
|
621
|
+
const stylesContent = getFileContent(
|
622
|
+
join(
|
623
|
+
dirname(
|
624
|
+
"./src/components/themedLayoutV2/sider/index.tsx",
|
625
|
+
),
|
626
|
+
"/styles.ts",
|
627
|
+
),
|
628
|
+
"utf-8",
|
629
|
+
).replace("export const", "const");
|
630
|
+
|
631
|
+
appending = stylesContent;
|
632
|
+
} catch (err) {
|
633
|
+
// console.log(err);
|
634
|
+
}
|
635
|
+
|
636
|
+
newContent = appendAfterImports(
|
637
|
+
newContent,
|
638
|
+
appending,
|
639
|
+
);
|
640
|
+
}
|
641
|
+
});
|
642
|
+
|
643
|
+
return newContent;
|
644
|
+
},
|
645
|
+
},
|
646
|
+
{
|
647
|
+
src: "./src/components/themedLayoutV2/header/index.tsx",
|
648
|
+
dest: "./components/themedLayout/header.tsx",
|
649
|
+
},
|
650
|
+
{
|
651
|
+
src: "./src/components/themedLayoutV2/title/index.tsx",
|
652
|
+
dest: "./components/themedLayout/title.tsx",
|
653
|
+
},
|
654
|
+
{
|
655
|
+
src: "./src/components/themedLayoutV2/index.tsx",
|
656
|
+
dest: "./components/themedLayout/index.tsx",
|
657
|
+
transform: (content) => {
|
658
|
+
let newContent = content;
|
659
|
+
const imports = getImports(content);
|
660
|
+
|
661
|
+
imports.map((importItem) => {
|
662
|
+
// handle @components import replacement
|
663
|
+
if (
|
664
|
+
importItem.importPath === "@components" ||
|
665
|
+
importItem.importPath === "@contexts" ||
|
666
|
+
importItem.importPath === "@hooks"
|
667
|
+
) {
|
668
|
+
const newStatement = `import ${importItem.namedImports} from "@refinedev/antd";`;
|
669
|
+
|
670
|
+
newContent = newContent.replace(
|
671
|
+
importItem.statement,
|
672
|
+
newStatement,
|
673
|
+
);
|
674
|
+
}
|
675
|
+
});
|
676
|
+
|
677
|
+
return newContent;
|
678
|
+
},
|
679
|
+
},
|
680
|
+
],
|
681
|
+
},
|
682
|
+
{
|
683
|
+
group: "Other",
|
684
|
+
label: "Themed Layout (deprecated use ThemedLayoutV2 instead)",
|
564
685
|
message: `
|
565
686
|
**\`Warning:\`**
|
566
687
|
If you want to change the default layout;
|
package/src/components/index.ts
CHANGED
@@ -11,6 +11,12 @@ export { ThemedSider } from "./themedLayout/sider";
|
|
11
11
|
export { ThemedTitle } from "./themedLayout/title";
|
12
12
|
export * from "./themedLayout/types";
|
13
13
|
|
14
|
+
export { ThemedLayoutV2 } from "./themedLayoutV2";
|
15
|
+
export { ThemedHeaderV2 } from "./themedLayoutV2/header";
|
16
|
+
export { ThemedSiderV2 } from "./themedLayoutV2/sider";
|
17
|
+
export { ThemedTitleV2 } from "./themedLayoutV2/title";
|
18
|
+
export * from "./themedLayoutV2/types";
|
19
|
+
|
14
20
|
export * from "./buttons";
|
15
21
|
export * from "./crud";
|
16
22
|
export * from "./fields";
|
@@ -6,6 +6,9 @@ import { RefineThemedLayoutHeaderProps } from "../types";
|
|
6
6
|
const { Text } = Typography;
|
7
7
|
const { useToken } = theme;
|
8
8
|
|
9
|
+
/**
|
10
|
+
* @deprecated It is recommended to use the improved `ThemedLayoutV2`. Review migration guidelines. https://refine.dev/docs/api-reference/antd/components/antd-themed-layout/#migrate-themedlayout-to-themedlayoutv2
|
11
|
+
*/
|
9
12
|
export const ThemedHeader: React.FC<RefineThemedLayoutHeaderProps> = () => {
|
10
13
|
const { token } = useToken();
|
11
14
|
|
@@ -5,6 +5,9 @@ import { ThemedSider as DefaultSider } from "./sider";
|
|
5
5
|
import { ThemedHeader as DefaultHeader } from "./header";
|
6
6
|
import { RefineThemedLayoutProps } from "./types";
|
7
7
|
|
8
|
+
/**
|
9
|
+
* @deprecated It is recommended to use the improved `ThemedLayoutV2`. Review migration guidelines. https://refine.dev/docs/api-reference/antd/components/antd-themed-layout/#migrate-themedlayout-to-themedlayoutv2
|
10
|
+
*/
|
8
11
|
export const ThemedLayout: React.FC<RefineThemedLayoutProps> = ({
|
9
12
|
children,
|
10
13
|
Header,
|
@@ -32,6 +32,9 @@ import { ThemedTitle } from "@components";
|
|
32
32
|
const { SubMenu } = Menu;
|
33
33
|
const { useToken } = theme;
|
34
34
|
|
35
|
+
/**
|
36
|
+
* @deprecated It is recommended to use the improved `ThemedLayoutV2`. Review migration guidelines. https://refine.dev/docs/api-reference/antd/components/antd-themed-layout/#migrate-themedlayout-to-themedlayoutv2
|
37
|
+
*/
|
35
38
|
export const ThemedSider: React.FC<RefineThemedLayoutSiderProps> = ({
|
36
39
|
Title: TitleFromProps,
|
37
40
|
render,
|
@@ -29,6 +29,9 @@ const defaultIcon = (
|
|
29
29
|
</svg>
|
30
30
|
);
|
31
31
|
|
32
|
+
/**
|
33
|
+
* @deprecated It is recommended to use the improved `ThemedLayoutV2`. Review migration guidelines. https://refine.dev/docs/api-reference/antd/components/antd-themed-layout/#migrate-themedlayout-to-themedlayoutv2
|
34
|
+
*/
|
32
35
|
export const ThemedTitle: React.FC<RefineLayoutThemedTitleProps> = ({
|
33
36
|
collapsed,
|
34
37
|
icon = defaultIcon,
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import React from "react";
|
2
|
+
import { Layout as AntdLayout, Typography, Avatar, Space, theme } from "antd";
|
3
|
+
import { useActiveAuthProvider, useGetIdentity } from "@refinedev/core";
|
4
|
+
import { RefineThemedLayoutV2HeaderProps } from "../types";
|
5
|
+
|
6
|
+
const { Text } = Typography;
|
7
|
+
const { useToken } = theme;
|
8
|
+
|
9
|
+
export const ThemedHeaderV2: React.FC<RefineThemedLayoutV2HeaderProps> = () => {
|
10
|
+
const { token } = useToken();
|
11
|
+
|
12
|
+
const authProvider = useActiveAuthProvider();
|
13
|
+
const { data: user } = useGetIdentity({
|
14
|
+
v3LegacyAuthProviderCompatible: Boolean(authProvider?.isLegacy),
|
15
|
+
});
|
16
|
+
|
17
|
+
const shouldRenderHeader = user && (user.name || user.avatar);
|
18
|
+
|
19
|
+
if (!shouldRenderHeader) {
|
20
|
+
return null;
|
21
|
+
}
|
22
|
+
|
23
|
+
return (
|
24
|
+
<AntdLayout.Header
|
25
|
+
style={{
|
26
|
+
backgroundColor: token.colorBgElevated,
|
27
|
+
display: "flex",
|
28
|
+
justifyContent: "flex-end",
|
29
|
+
alignItems: "center",
|
30
|
+
padding: "0px 24px",
|
31
|
+
height: "64px",
|
32
|
+
}}
|
33
|
+
>
|
34
|
+
<Space>
|
35
|
+
<Space size="middle">
|
36
|
+
{user?.name && <Text strong>{user.name}</Text>}
|
37
|
+
{user?.avatar && (
|
38
|
+
<Avatar src={user?.avatar} alt={user?.name} />
|
39
|
+
)}
|
40
|
+
</Space>
|
41
|
+
</Space>
|
42
|
+
</AntdLayout.Header>
|
43
|
+
);
|
44
|
+
};
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import React from "react";
|
2
|
+
import { Grid, Layout as AntdLayout } from "antd";
|
3
|
+
|
4
|
+
import { ThemedSiderV2 as DefaultSider } from "./sider";
|
5
|
+
import { ThemedHeaderV2 as DefaultHeader } from "./header";
|
6
|
+
import { RefineThemedLayoutV2Props } from "./types";
|
7
|
+
import { ThemedLayoutContextProvider } from "@contexts";
|
8
|
+
|
9
|
+
export const ThemedLayoutV2: React.FC<RefineThemedLayoutV2Props> = ({
|
10
|
+
children,
|
11
|
+
Header,
|
12
|
+
Sider,
|
13
|
+
Title,
|
14
|
+
Footer,
|
15
|
+
OffLayoutArea,
|
16
|
+
}) => {
|
17
|
+
const breakpoint = Grid.useBreakpoint();
|
18
|
+
const SiderToRender = Sider ?? DefaultSider;
|
19
|
+
const HeaderToRender = Header ?? DefaultHeader;
|
20
|
+
const isSmall = typeof breakpoint.sm === "undefined" ? true : breakpoint.sm;
|
21
|
+
|
22
|
+
return (
|
23
|
+
<ThemedLayoutContextProvider>
|
24
|
+
<AntdLayout style={{ minHeight: "100vh" }}>
|
25
|
+
<SiderToRender Title={Title} />
|
26
|
+
<AntdLayout>
|
27
|
+
<HeaderToRender />
|
28
|
+
<AntdLayout.Content>
|
29
|
+
<div
|
30
|
+
style={{
|
31
|
+
minHeight: 360,
|
32
|
+
padding: isSmall ? 24 : 12,
|
33
|
+
}}
|
34
|
+
>
|
35
|
+
{children}
|
36
|
+
</div>
|
37
|
+
{OffLayoutArea && <OffLayoutArea />}
|
38
|
+
</AntdLayout.Content>
|
39
|
+
{Footer && <Footer />}
|
40
|
+
</AntdLayout>
|
41
|
+
</AntdLayout>
|
42
|
+
</ThemedLayoutContextProvider>
|
43
|
+
);
|
44
|
+
};
|
@@ -0,0 +1,324 @@
|
|
1
|
+
import React from "react";
|
2
|
+
import { Layout, Menu, Grid, Drawer, Button, theme } from "antd";
|
3
|
+
import {
|
4
|
+
DashboardOutlined,
|
5
|
+
LogoutOutlined,
|
6
|
+
UnorderedListOutlined,
|
7
|
+
BarsOutlined,
|
8
|
+
LeftOutlined,
|
9
|
+
RightOutlined,
|
10
|
+
} from "@ant-design/icons";
|
11
|
+
import {
|
12
|
+
useTranslate,
|
13
|
+
useLogout,
|
14
|
+
useTitle,
|
15
|
+
CanAccess,
|
16
|
+
ITreeMenu,
|
17
|
+
useIsExistAuthentication,
|
18
|
+
useRouterContext,
|
19
|
+
useMenu,
|
20
|
+
useRefineContext,
|
21
|
+
useLink,
|
22
|
+
useRouterType,
|
23
|
+
useActiveAuthProvider,
|
24
|
+
pickNotDeprecated,
|
25
|
+
useWarnAboutChange,
|
26
|
+
} from "@refinedev/core";
|
27
|
+
|
28
|
+
import { drawerButtonStyles } from "./styles";
|
29
|
+
import { RefineThemedLayoutV2SiderProps } from "../types";
|
30
|
+
import { ThemedTitleV2 } from "@components";
|
31
|
+
import { useSiderVisible } from "@hooks";
|
32
|
+
|
33
|
+
const { SubMenu } = Menu;
|
34
|
+
const { useToken } = theme;
|
35
|
+
|
36
|
+
export const ThemedSiderV2: React.FC<RefineThemedLayoutV2SiderProps> = ({
|
37
|
+
Title: TitleFromProps,
|
38
|
+
render,
|
39
|
+
meta,
|
40
|
+
}) => {
|
41
|
+
const { token } = useToken();
|
42
|
+
const {
|
43
|
+
siderVisible,
|
44
|
+
setSiderVisible,
|
45
|
+
drawerSiderVisible,
|
46
|
+
setDrawerSiderVisible,
|
47
|
+
} = useSiderVisible();
|
48
|
+
|
49
|
+
const isExistAuthentication = useIsExistAuthentication();
|
50
|
+
const routerType = useRouterType();
|
51
|
+
const NewLink = useLink();
|
52
|
+
const { warnWhen, setWarnWhen } = useWarnAboutChange();
|
53
|
+
const { Link: LegacyLink } = useRouterContext();
|
54
|
+
const Link = routerType === "legacy" ? LegacyLink : NewLink;
|
55
|
+
const TitleFromContext = useTitle();
|
56
|
+
const translate = useTranslate();
|
57
|
+
const { menuItems, selectedKey, defaultOpenKeys } = useMenu({ meta });
|
58
|
+
const breakpoint = Grid.useBreakpoint();
|
59
|
+
const { hasDashboard } = useRefineContext();
|
60
|
+
const authProvider = useActiveAuthProvider();
|
61
|
+
const { mutate: mutateLogout } = useLogout({
|
62
|
+
v3LegacyAuthProviderCompatible: Boolean(authProvider?.isLegacy),
|
63
|
+
});
|
64
|
+
|
65
|
+
const isMobile =
|
66
|
+
typeof breakpoint.lg === "undefined" ? false : !breakpoint.lg;
|
67
|
+
|
68
|
+
const RenderToTitle = TitleFromProps ?? TitleFromContext ?? ThemedTitleV2;
|
69
|
+
|
70
|
+
const renderTreeView = (tree: ITreeMenu[], selectedKey?: string) => {
|
71
|
+
return tree.map((item: ITreeMenu) => {
|
72
|
+
const {
|
73
|
+
icon,
|
74
|
+
label,
|
75
|
+
route,
|
76
|
+
key,
|
77
|
+
name,
|
78
|
+
children,
|
79
|
+
parentName,
|
80
|
+
meta,
|
81
|
+
options,
|
82
|
+
} = item;
|
83
|
+
|
84
|
+
if (children.length > 0) {
|
85
|
+
return (
|
86
|
+
<CanAccess
|
87
|
+
key={item.key}
|
88
|
+
resource={name.toLowerCase()}
|
89
|
+
action="list"
|
90
|
+
params={{
|
91
|
+
resource: item,
|
92
|
+
}}
|
93
|
+
>
|
94
|
+
<SubMenu
|
95
|
+
key={item.key}
|
96
|
+
icon={icon ?? <UnorderedListOutlined />}
|
97
|
+
title={label}
|
98
|
+
>
|
99
|
+
{renderTreeView(children, selectedKey)}
|
100
|
+
</SubMenu>
|
101
|
+
</CanAccess>
|
102
|
+
);
|
103
|
+
}
|
104
|
+
const isSelected = key === selectedKey;
|
105
|
+
const isRoute = !(
|
106
|
+
pickNotDeprecated(meta?.parent, options?.parent, parentName) !==
|
107
|
+
undefined && children.length === 0
|
108
|
+
);
|
109
|
+
|
110
|
+
return (
|
111
|
+
<CanAccess
|
112
|
+
key={item.key}
|
113
|
+
resource={name.toLowerCase()}
|
114
|
+
action="list"
|
115
|
+
params={{
|
116
|
+
resource: item,
|
117
|
+
}}
|
118
|
+
>
|
119
|
+
<Menu.Item
|
120
|
+
key={item.key}
|
121
|
+
icon={icon ?? (isRoute && <UnorderedListOutlined />)}
|
122
|
+
>
|
123
|
+
<Link to={route ?? ""}>{label}</Link>
|
124
|
+
{!drawerSiderVisible && isSelected && (
|
125
|
+
<div className="ant-menu-tree-arrow" />
|
126
|
+
)}
|
127
|
+
</Menu.Item>
|
128
|
+
</CanAccess>
|
129
|
+
);
|
130
|
+
});
|
131
|
+
};
|
132
|
+
|
133
|
+
const handleLogout = () => {
|
134
|
+
if (warnWhen) {
|
135
|
+
const confirm = window.confirm(
|
136
|
+
translate(
|
137
|
+
"warnWhenUnsavedChanges",
|
138
|
+
"Are you sure you want to leave? You have unsaved changes.",
|
139
|
+
),
|
140
|
+
);
|
141
|
+
|
142
|
+
if (confirm) {
|
143
|
+
setWarnWhen(false);
|
144
|
+
mutateLogout();
|
145
|
+
}
|
146
|
+
} else {
|
147
|
+
mutateLogout();
|
148
|
+
}
|
149
|
+
};
|
150
|
+
|
151
|
+
const logout = isExistAuthentication && (
|
152
|
+
<Menu.Item
|
153
|
+
key="logout"
|
154
|
+
onClick={() => handleLogout()}
|
155
|
+
icon={<LogoutOutlined />}
|
156
|
+
>
|
157
|
+
{translate("buttons.logout", "Logout")}
|
158
|
+
</Menu.Item>
|
159
|
+
);
|
160
|
+
|
161
|
+
const dashboard = hasDashboard ? (
|
162
|
+
<Menu.Item key="dashboard" icon={<DashboardOutlined />}>
|
163
|
+
<Link to="/">{translate("dashboard.title", "Dashboard")}</Link>
|
164
|
+
{!drawerSiderVisible && selectedKey === "/" && (
|
165
|
+
<div className="ant-menu-tree-arrow" />
|
166
|
+
)}
|
167
|
+
</Menu.Item>
|
168
|
+
) : null;
|
169
|
+
|
170
|
+
const items = renderTreeView(menuItems, selectedKey);
|
171
|
+
|
172
|
+
const renderSider = () => {
|
173
|
+
if (render) {
|
174
|
+
return render({
|
175
|
+
dashboard,
|
176
|
+
items,
|
177
|
+
logout,
|
178
|
+
collapsed: drawerSiderVisible,
|
179
|
+
});
|
180
|
+
}
|
181
|
+
return (
|
182
|
+
<>
|
183
|
+
{dashboard}
|
184
|
+
{items}
|
185
|
+
{logout}
|
186
|
+
</>
|
187
|
+
);
|
188
|
+
};
|
189
|
+
|
190
|
+
const renderMenu = () => {
|
191
|
+
return (
|
192
|
+
<>
|
193
|
+
<Menu
|
194
|
+
selectedKeys={selectedKey ? [selectedKey] : []}
|
195
|
+
defaultOpenKeys={defaultOpenKeys}
|
196
|
+
mode="inline"
|
197
|
+
style={{
|
198
|
+
marginTop: "8px",
|
199
|
+
border: "none",
|
200
|
+
}}
|
201
|
+
onClick={() => {
|
202
|
+
setSiderVisible?.(false);
|
203
|
+
if (!breakpoint.lg) {
|
204
|
+
setDrawerSiderVisible?.(true);
|
205
|
+
}
|
206
|
+
}}
|
207
|
+
>
|
208
|
+
{renderSider()}
|
209
|
+
</Menu>
|
210
|
+
</>
|
211
|
+
);
|
212
|
+
};
|
213
|
+
|
214
|
+
const renderDrawerSider = () => {
|
215
|
+
return (
|
216
|
+
<>
|
217
|
+
<Drawer
|
218
|
+
open={siderVisible}
|
219
|
+
onClose={() => setSiderVisible?.(false)}
|
220
|
+
placement="left"
|
221
|
+
closable={false}
|
222
|
+
width={200}
|
223
|
+
bodyStyle={{
|
224
|
+
padding: 0,
|
225
|
+
}}
|
226
|
+
maskClosable={true}
|
227
|
+
>
|
228
|
+
<Layout>
|
229
|
+
<Layout.Sider
|
230
|
+
style={{
|
231
|
+
height: "100vh",
|
232
|
+
overflow: "hidden",
|
233
|
+
backgroundColor: token.colorBgContainer,
|
234
|
+
borderRight: `1px solid ${token.colorBgElevated}`,
|
235
|
+
}}
|
236
|
+
>
|
237
|
+
<div
|
238
|
+
style={{
|
239
|
+
width: "200px",
|
240
|
+
padding: "0 16px",
|
241
|
+
display: "flex",
|
242
|
+
justifyContent: "flex-start",
|
243
|
+
alignItems: "center",
|
244
|
+
height: "64px",
|
245
|
+
backgroundColor: token.colorBgElevated,
|
246
|
+
}}
|
247
|
+
>
|
248
|
+
<RenderToTitle collapsed={false} />
|
249
|
+
</div>
|
250
|
+
{renderMenu()}
|
251
|
+
</Layout.Sider>
|
252
|
+
</Layout>
|
253
|
+
</Drawer>
|
254
|
+
<Button
|
255
|
+
style={drawerButtonStyles}
|
256
|
+
size="large"
|
257
|
+
onClick={() => setSiderVisible?.(true)}
|
258
|
+
icon={<BarsOutlined />}
|
259
|
+
></Button>
|
260
|
+
</>
|
261
|
+
);
|
262
|
+
};
|
263
|
+
|
264
|
+
if (isMobile) {
|
265
|
+
return renderDrawerSider();
|
266
|
+
}
|
267
|
+
|
268
|
+
return (
|
269
|
+
<Layout.Sider
|
270
|
+
style={{
|
271
|
+
backgroundColor: token.colorBgContainer,
|
272
|
+
borderRight: `1px solid ${token.colorBgElevated}`,
|
273
|
+
}}
|
274
|
+
collapsible
|
275
|
+
collapsed={drawerSiderVisible}
|
276
|
+
onCollapse={(collapsed) => setDrawerSiderVisible?.(collapsed)}
|
277
|
+
collapsedWidth={80}
|
278
|
+
breakpoint="lg"
|
279
|
+
trigger={
|
280
|
+
<Button
|
281
|
+
type="text"
|
282
|
+
style={{
|
283
|
+
borderRadius: 0,
|
284
|
+
height: "100%",
|
285
|
+
width: "100%",
|
286
|
+
backgroundColor: token.colorBgElevated,
|
287
|
+
}}
|
288
|
+
>
|
289
|
+
{drawerSiderVisible ? (
|
290
|
+
<RightOutlined
|
291
|
+
style={{
|
292
|
+
color: token.colorPrimary,
|
293
|
+
}}
|
294
|
+
/>
|
295
|
+
) : (
|
296
|
+
<LeftOutlined
|
297
|
+
style={{
|
298
|
+
color: token.colorPrimary,
|
299
|
+
}}
|
300
|
+
/>
|
301
|
+
)}
|
302
|
+
</Button>
|
303
|
+
}
|
304
|
+
>
|
305
|
+
<div
|
306
|
+
style={{
|
307
|
+
width: drawerSiderVisible ? "80px" : "200px",
|
308
|
+
padding: drawerSiderVisible ? "0" : "0 16px",
|
309
|
+
display: "flex",
|
310
|
+
justifyContent: drawerSiderVisible
|
311
|
+
? "center"
|
312
|
+
: "flex-start",
|
313
|
+
alignItems: "center",
|
314
|
+
height: "64px",
|
315
|
+
backgroundColor: token.colorBgElevated,
|
316
|
+
fontSize: "14px",
|
317
|
+
}}
|
318
|
+
>
|
319
|
+
<RenderToTitle collapsed={drawerSiderVisible} />
|
320
|
+
</div>
|
321
|
+
{renderMenu()}
|
322
|
+
</Layout.Sider>
|
323
|
+
);
|
324
|
+
};
|