@pnkx-lib/ui 1.9.410 → 1.9.412
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/dist/style.css +2 -2
- package/es/chunks/BellIcon-Bv07EhTB.js +45 -0
- package/es/chunks/{bundle-mjs-BBFHkixS.js → bundle-mjs-BME7zF0Z.js} +1 -1
- package/es/chunks/{index.esm-o4O8pXMN.js → index.esm-AaUjBMaK.js} +39 -21
- package/es/chunks/{layout-C0dbwkpb.js → layout-2jUdRxjk.js} +11 -5
- package/es/fields/CascaderField.js +1 -1
- package/es/fields/Checkbox.js +1 -1
- package/es/fields/DatePicker.js +26 -5
- package/es/fields/DateRangePicker.js +1 -1
- package/es/fields/Input.js +1 -1
- package/es/fields/InputRangePicker.js +1 -1
- package/es/fields/PnkxField.js +1 -1
- package/es/fields/Select.js +1 -1
- package/es/fields/SliderRanger.js +1 -1
- package/es/fields/SliderSingle.js +1 -1
- package/es/fields/Switch.js +1 -1
- package/es/fields/Textarea.js +1 -1
- package/es/fields/TimePicker.js +1 -1
- package/es/fields/TimeRangePicker.js +1 -1
- package/es/fields/TinyMCE.js +35 -16
- package/es/ui/Button.js +1 -1
- package/es/ui/Cascader.js +1 -1
- package/es/ui/CategoryStatus.js +1 -1
- package/es/ui/Container.js +1 -1
- package/es/ui/Label.js +1 -1
- package/es/ui/Layout.js +1 -1
- package/es/ui/Modal.js +1 -1
- package/es/ui/SearchFilterForm.js +1 -1
- package/es/ui/SelectSingleTable.js +1 -1
- package/es/ui/SelectTable.js +1 -1
- package/es/ui/Sidebar.js +2 -2
- package/es/ui/SidebarV2.js +6 -48
- package/es/ui/SidebarV3/index.js +490 -0
- package/es/ui/UploadComponent.js +1 -1
- package/es/ui/UploadImage.js +1 -1
- package/es/ui/index.js +1 -1
- package/package.json +2 -2
- package/types/components/ui/SidebarV3/ContentArea.d.ts +8 -0
- package/types/components/ui/SidebarV3/Example.d.ts +2 -0
- package/types/components/ui/SidebarV3/Header.d.ts +12 -0
- package/types/components/ui/SidebarV3/MainSidebar.d.ts +12 -0
- package/types/components/ui/SidebarV3/SearchHeader.d.ts +11 -0
- package/types/components/ui/SidebarV3/SidebarV3.d.ts +3 -0
- package/types/components/ui/SidebarV3/SubMenu.d.ts +13 -0
- package/types/components/ui/SidebarV3/UserInfoSection.d.ts +6 -0
- package/types/components/ui/SidebarV3/hooks.d.ts +9 -0
- package/types/components/ui/SidebarV3/index.d.ts +3 -0
- package/types/components/ui/SidebarV3/types.d.ts +25 -0
- package/types/components/ui/SidebarV3/utils.d.ts +2 -0
- package/types/ui/SidebarV3/index.d.ts +2 -0
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { useMemo, useState } from 'react';
|
|
3
|
+
import { useLocation, Link, useNavigate } from 'react-router';
|
|
4
|
+
import { S as SearchIcon, V as VietNamIcon, D as DownOutlinedIcon, l as logoHeaderText, R as RefIcon, u as useDebounce } from '../../chunks/logo-header-DG8abRGF.js';
|
|
5
|
+
import { Flex, AutoComplete, Divider, Dropdown } from 'antd';
|
|
6
|
+
import { Layout } from '../Layout.js';
|
|
7
|
+
import { Input } from '../../fields/Input.js';
|
|
8
|
+
import { t as twMerge } from '../../chunks/bundle-mjs-BME7zF0Z.js';
|
|
9
|
+
import { F as ForwardRef, R as RefIcon$2 } from '../../chunks/BellIcon-Bv07EhTB.js';
|
|
10
|
+
import { R as RefIcon$1 } from '../../chunks/DownOutlined-CkHKgaSi.js';
|
|
11
|
+
|
|
12
|
+
const useMenuFilter = (menu) => {
|
|
13
|
+
const sidebarMenu = useMemo(
|
|
14
|
+
() => menu?.filter((route) => route?.isShow)?.flatMap((route) => route?.children)?.filter(Boolean),
|
|
15
|
+
[menu]
|
|
16
|
+
);
|
|
17
|
+
return { sidebarMenu };
|
|
18
|
+
};
|
|
19
|
+
const usePathUtils = () => {
|
|
20
|
+
const normalizePath = (path) => {
|
|
21
|
+
return path.trim().replace(/^\/+|\/+$/g, "").replace(/\/{2,}/g, "/").toLowerCase();
|
|
22
|
+
};
|
|
23
|
+
const comparePaths = (a, b) => {
|
|
24
|
+
return normalizePath(a) === normalizePath(b);
|
|
25
|
+
};
|
|
26
|
+
return { normalizePath, comparePaths };
|
|
27
|
+
};
|
|
28
|
+
const classNames = (...classes) => {
|
|
29
|
+
return classes.filter(Boolean).join(" ");
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const Title = (props) => /* @__PURE__ */ jsx(Flex, { align: "center", justify: "space-between", children: props.title });
|
|
33
|
+
const renderItem = (title, path) => ({
|
|
34
|
+
value: title,
|
|
35
|
+
label: /* @__PURE__ */ jsx(Flex, { align: "center", justify: "space-between", children: title }),
|
|
36
|
+
path
|
|
37
|
+
});
|
|
38
|
+
const getDataOption = (menu, searchValue) => {
|
|
39
|
+
return menu.reduce((acc, itemMenu) => {
|
|
40
|
+
const groupName = itemMenu.name;
|
|
41
|
+
(itemMenu.children ?? []).forEach((itemChildren) => {
|
|
42
|
+
(itemChildren.children ?? []).forEach(
|
|
43
|
+
(itemSub) => {
|
|
44
|
+
if (!searchValue || itemSub.name.toLowerCase().includes(searchValue.toLowerCase())) {
|
|
45
|
+
let group = acc.find((g) => g.label.props.title === groupName);
|
|
46
|
+
if (!group) {
|
|
47
|
+
group = {
|
|
48
|
+
label: /* @__PURE__ */ jsx(Title, { title: groupName }),
|
|
49
|
+
options: []
|
|
50
|
+
};
|
|
51
|
+
acc.push(group);
|
|
52
|
+
}
|
|
53
|
+
const path = `${itemChildren.path}/${itemSub.path}`;
|
|
54
|
+
group.options.push(renderItem(itemSub.name, path));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
return acc;
|
|
60
|
+
}, []);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const SearchHeader = ({
|
|
64
|
+
dataOption,
|
|
65
|
+
valueSearch,
|
|
66
|
+
onSearchChange,
|
|
67
|
+
onSelect
|
|
68
|
+
}) => {
|
|
69
|
+
return /* @__PURE__ */ jsx("div", { className: "flex items-end", children: /* @__PURE__ */ jsx(
|
|
70
|
+
AutoComplete,
|
|
71
|
+
{
|
|
72
|
+
classNames: {
|
|
73
|
+
popup: { root: "certain-category-search-dropdown" }
|
|
74
|
+
},
|
|
75
|
+
popupMatchSelectWidth: 500,
|
|
76
|
+
style: { width: 500 },
|
|
77
|
+
options: dataOption ?? [],
|
|
78
|
+
onSelect,
|
|
79
|
+
onChange: onSearchChange,
|
|
80
|
+
value: valueSearch,
|
|
81
|
+
children: /* @__PURE__ */ jsx(
|
|
82
|
+
Input,
|
|
83
|
+
{
|
|
84
|
+
className: "!placeholder:bg-[#E7F0FF] !bg-[#E7F0FF] !border !border-[#BDE3FF]",
|
|
85
|
+
placeholder: "Tìm kiếm theo chức năng,module của hệ thống",
|
|
86
|
+
iconStartInput: /* @__PURE__ */ jsx("div", { className: "w-5 h-5", children: /* @__PURE__ */ jsx(SearchIcon, { className: "w-5 text-[#116DFF]" }) })
|
|
87
|
+
}
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
) });
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const userInfo = {
|
|
94
|
+
name: "admin",
|
|
95
|
+
avatar: "http://10.1.15.154:9000/image/logo-phenikaa-mec.webp"
|
|
96
|
+
};
|
|
97
|
+
const items = [
|
|
98
|
+
{ key: "1", label: "Hồ sơ" },
|
|
99
|
+
{ key: "4", label: "Cài đặt" },
|
|
100
|
+
{ key: "2", label: "Đăng xuất" }
|
|
101
|
+
];
|
|
102
|
+
const UserInfoSection = ({
|
|
103
|
+
hoverOpenMenu
|
|
104
|
+
}) => {
|
|
105
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
106
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsx("li", { className: "list-none cursor-pointer group flex items-center", children: /* @__PURE__ */ jsxs(
|
|
107
|
+
"div",
|
|
108
|
+
{
|
|
109
|
+
className: twMerge(
|
|
110
|
+
hoverOpenMenu ? "" : "justify-center",
|
|
111
|
+
"text-black flex items-center rounded-md gap-2"
|
|
112
|
+
),
|
|
113
|
+
children: [
|
|
114
|
+
/* @__PURE__ */ jsx(Divider, { type: "vertical" }),
|
|
115
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-center gap-4 items-center", children: [
|
|
116
|
+
/* @__PURE__ */ jsx(VietNamIcon, { className: "w-6 h-6" }),
|
|
117
|
+
/* @__PURE__ */ jsx(ForwardRef, { className: "w-6 h-6" })
|
|
118
|
+
] })
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
) }) }),
|
|
122
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center z-[9999]", children: /* @__PURE__ */ jsx("a", { onClick: (e) => e.preventDefault(), children: /* @__PURE__ */ jsx("li", { className: "list-none cursor-pointer group flex items-center", children: /* @__PURE__ */ jsxs(
|
|
123
|
+
"div",
|
|
124
|
+
{
|
|
125
|
+
className: twMerge(
|
|
126
|
+
hoverOpenMenu ? "" : "justify-center",
|
|
127
|
+
"text-black flex items-center rounded-md gap-2"
|
|
128
|
+
),
|
|
129
|
+
children: [
|
|
130
|
+
/* @__PURE__ */ jsx(Divider, { type: "vertical" }),
|
|
131
|
+
/* @__PURE__ */ jsx("div", { className: "flex justify-center w-[30px] h-[30px] rounded-full", children: /* @__PURE__ */ jsx("img", { src: userInfo?.avatar, alt: "default_avatar" }) }),
|
|
132
|
+
/* @__PURE__ */ jsx("p", { children: userInfo?.name }),
|
|
133
|
+
/* @__PURE__ */ jsx(Dropdown, { menu: { items }, children: /* @__PURE__ */ jsx(DownOutlinedIcon, { className: "w-6 h-6" }) })
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
) }) }) })
|
|
137
|
+
] });
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const Header = ({
|
|
141
|
+
dataOption,
|
|
142
|
+
valueSearch,
|
|
143
|
+
onSearchChange,
|
|
144
|
+
onSelect,
|
|
145
|
+
hoverOpenMenu
|
|
146
|
+
}) => {
|
|
147
|
+
return /* @__PURE__ */ jsx(
|
|
148
|
+
Layout.Header,
|
|
149
|
+
{
|
|
150
|
+
style: {
|
|
151
|
+
backgroundColor: "#FFFFFF",
|
|
152
|
+
display: "flex",
|
|
153
|
+
width: "100%",
|
|
154
|
+
borderBottom: "1px solid white",
|
|
155
|
+
boxShadow: "0 1px 2px rgba(0, 0, 0, 0.15)",
|
|
156
|
+
height: "56px",
|
|
157
|
+
position: "fixed",
|
|
158
|
+
zIndex: 2e3
|
|
159
|
+
},
|
|
160
|
+
children: /* @__PURE__ */ jsxs("div", { className: "w-full flex items-center justify-between", children: [
|
|
161
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center ml-[-2rem]", children: /* @__PURE__ */ jsx("img", { src: logoHeaderText, alt: "logo", width: 200 }) }),
|
|
162
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
|
|
163
|
+
/* @__PURE__ */ jsx(
|
|
164
|
+
SearchHeader,
|
|
165
|
+
{
|
|
166
|
+
dataOption,
|
|
167
|
+
valueSearch,
|
|
168
|
+
onSearchChange,
|
|
169
|
+
onSelect
|
|
170
|
+
}
|
|
171
|
+
),
|
|
172
|
+
/* @__PURE__ */ jsx(UserInfoSection, { hoverOpenMenu })
|
|
173
|
+
] })
|
|
174
|
+
] })
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const MainSidebar = ({
|
|
180
|
+
sidebarMenu,
|
|
181
|
+
hoverOpenMenu,
|
|
182
|
+
activeModule,
|
|
183
|
+
onMouseEnter,
|
|
184
|
+
onMouseLeave,
|
|
185
|
+
onNavigateModule
|
|
186
|
+
}) => {
|
|
187
|
+
return /* @__PURE__ */ jsx(
|
|
188
|
+
"div",
|
|
189
|
+
{
|
|
190
|
+
className: twMerge(
|
|
191
|
+
"fixed inset-y-0 flex h-screen flex-col transition-all duration-300 ease-in-out z-[999]",
|
|
192
|
+
hoverOpenMenu ? "w-[225px]" : "w-[62px]"
|
|
193
|
+
),
|
|
194
|
+
onMouseLeave,
|
|
195
|
+
onMouseEnter,
|
|
196
|
+
children: /* @__PURE__ */ jsx("div", { className: "flex grow flex-col mt-14 gap-y-5 bg-[#001523] px-6 pb-4 relative", children: /* @__PURE__ */ jsx("nav", { className: "flex flex-1 flex-col mt-4", children: /* @__PURE__ */ jsx("ul", { role: "list", className: "-mx-3 space-y-1", children: sidebarMenu.map((item) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
|
|
197
|
+
"a",
|
|
198
|
+
{
|
|
199
|
+
onClick: () => {
|
|
200
|
+
onNavigateModule(item);
|
|
201
|
+
},
|
|
202
|
+
className: classNames(
|
|
203
|
+
item.path === activeModule ? "bg-[#007BE5] text-white" : "text-gray-400 hover:text-white hover:bg-[#007BE5]",
|
|
204
|
+
"group flex items-center gap-x-3 rounded-md px-1.5 py-2 text-sm font-semibold"
|
|
205
|
+
),
|
|
206
|
+
children: [
|
|
207
|
+
item.icon,
|
|
208
|
+
/* @__PURE__ */ jsx(
|
|
209
|
+
"span",
|
|
210
|
+
{
|
|
211
|
+
className: twMerge(
|
|
212
|
+
"whitespace-nowrap overflow-hidden transition-opacity duration-200",
|
|
213
|
+
hoverOpenMenu && "opacity-100"
|
|
214
|
+
),
|
|
215
|
+
children: item.name
|
|
216
|
+
}
|
|
217
|
+
)
|
|
218
|
+
]
|
|
219
|
+
}
|
|
220
|
+
) }, item.name)) }) }) })
|
|
221
|
+
}
|
|
222
|
+
);
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const SubMenu = ({
|
|
226
|
+
sidebarMenu,
|
|
227
|
+
showSubmenu,
|
|
228
|
+
hoverOpenMenu,
|
|
229
|
+
activeModule,
|
|
230
|
+
openDropdownMenu,
|
|
231
|
+
onCloseSubmenu,
|
|
232
|
+
onClickDropdownMenu
|
|
233
|
+
}) => {
|
|
234
|
+
const location = useLocation();
|
|
235
|
+
const pathName = location.pathname;
|
|
236
|
+
const { comparePaths } = usePathUtils();
|
|
237
|
+
if (!showSubmenu || sidebarMenu.length === 0) {
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
return /* @__PURE__ */ jsxs(
|
|
241
|
+
"div",
|
|
242
|
+
{
|
|
243
|
+
className: twMerge(
|
|
244
|
+
"fixed w-[217px] pt-15 left-[62px] h-full bg-[#FFFFFF] z-[50] flex flex-col",
|
|
245
|
+
hoverOpenMenu && "opacity-0"
|
|
246
|
+
),
|
|
247
|
+
onMouseLeave: () => onCloseSubmenu,
|
|
248
|
+
children: [
|
|
249
|
+
sidebarMenu.map((moduleMenu) => {
|
|
250
|
+
const isActiveMainMenu = activeModule === moduleMenu.path;
|
|
251
|
+
if (!isActiveMainMenu) return null;
|
|
252
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
253
|
+
/* @__PURE__ */ jsx("span", { className: "block px-4 h-[42px] shadow-[0px_4px_6px_0px_#0006241f] py-2 text-[16px] font-semibold text-[#1F1F1F]", children: moduleMenu.name }),
|
|
254
|
+
/* @__PURE__ */ jsx("ul", { className: "mt-4", children: moduleMenu.children?.map((subMenu) => {
|
|
255
|
+
const pathActive = comparePaths(pathName, subMenu.path);
|
|
256
|
+
const isDropdown = subMenu.isShow;
|
|
257
|
+
const activeMenu = pathName.startsWith(subMenu.path);
|
|
258
|
+
return /* @__PURE__ */ jsxs("li", { children: [
|
|
259
|
+
/* @__PURE__ */ jsxs(
|
|
260
|
+
"div",
|
|
261
|
+
{
|
|
262
|
+
onClick: () => onClickDropdownMenu(isDropdown, subMenu),
|
|
263
|
+
className: twMerge(
|
|
264
|
+
"px-4 py-2 mt-1 items-center gap-2 cursor-pointer flex text-sm hover:bg-[#E5F4FF] hover:text-[#007BE5]",
|
|
265
|
+
pathActive && !isDropdown ? "!text-[#007BE5] !bg-[#E5F4FF]" : isDropdown && (pathActive || activeMenu) ? "!text-[#007BE5]" : "text-[#1F1F1F]"
|
|
266
|
+
),
|
|
267
|
+
children: [
|
|
268
|
+
subMenu.icon,
|
|
269
|
+
subMenu.name,
|
|
270
|
+
isDropdown && openDropdownMenu === subMenu.path ? /* @__PURE__ */ jsx(RefIcon, { className: "w-4 h-4 ml-auto" }) : isDropdown && /* @__PURE__ */ jsx(RefIcon$1, { className: "w-4 h-4 ml-auto" })
|
|
271
|
+
]
|
|
272
|
+
}
|
|
273
|
+
),
|
|
274
|
+
isDropdown && openDropdownMenu === subMenu.path && subMenu.children?.map((dropdownItem) => {
|
|
275
|
+
const pathActiveDropdown = comparePaths(
|
|
276
|
+
pathName,
|
|
277
|
+
subMenu.path
|
|
278
|
+
);
|
|
279
|
+
const path = `${subMenu.path}/${dropdownItem.path}`;
|
|
280
|
+
return /* @__PURE__ */ jsxs(
|
|
281
|
+
Link,
|
|
282
|
+
{
|
|
283
|
+
to: path,
|
|
284
|
+
className: twMerge(
|
|
285
|
+
"px-4 py-2 mt-1 items-center gap-2 flex text-sm hover:bg-[#E5F4FF] hover:text-[#007BE5]",
|
|
286
|
+
pathActiveDropdown || activeMenu ? "!text-[#007BE5] !bg-[#E5F4FF]" : "text-[#1F1F1F]"
|
|
287
|
+
),
|
|
288
|
+
children: [
|
|
289
|
+
dropdownItem.icon,
|
|
290
|
+
dropdownItem.name
|
|
291
|
+
]
|
|
292
|
+
},
|
|
293
|
+
dropdownItem.path
|
|
294
|
+
);
|
|
295
|
+
})
|
|
296
|
+
] }, subMenu.path);
|
|
297
|
+
}) })
|
|
298
|
+
] }, moduleMenu.path);
|
|
299
|
+
}),
|
|
300
|
+
/* @__PURE__ */ jsxs(
|
|
301
|
+
"div",
|
|
302
|
+
{
|
|
303
|
+
className: "mt-auto select-none px-4 py-2 shadow-[0px_0px_12px_0px_#0006241f] flex space-x-2 cursor-pointer",
|
|
304
|
+
onClick: onCloseSubmenu,
|
|
305
|
+
children: [
|
|
306
|
+
/* @__PURE__ */ jsx(RefIcon$2, {}),
|
|
307
|
+
/* @__PURE__ */ jsx("span", { className: "text-[#131313]", children: "Thu gọn menu" })
|
|
308
|
+
]
|
|
309
|
+
}
|
|
310
|
+
)
|
|
311
|
+
]
|
|
312
|
+
}
|
|
313
|
+
);
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
const ContentArea = ({
|
|
317
|
+
children,
|
|
318
|
+
hoverOpenMenu,
|
|
319
|
+
showSubmenu
|
|
320
|
+
}) => {
|
|
321
|
+
const getContentMargin = () => {
|
|
322
|
+
if (hoverOpenMenu) return "ml-[225px]";
|
|
323
|
+
if (showSubmenu) return "ml-[279px]";
|
|
324
|
+
return "ml-[62px]";
|
|
325
|
+
};
|
|
326
|
+
return /* @__PURE__ */ jsx(
|
|
327
|
+
"div",
|
|
328
|
+
{
|
|
329
|
+
className: twMerge(
|
|
330
|
+
"transition-all duration-300 ease-in-out pt-14 h-screen",
|
|
331
|
+
getContentMargin()
|
|
332
|
+
),
|
|
333
|
+
children
|
|
334
|
+
}
|
|
335
|
+
);
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
const SidebarV3 = ({ menu, children }) => {
|
|
339
|
+
const [hoverOpenMenu, setHoverOpenMenu] = useState(false);
|
|
340
|
+
const [valueSearch, setValueSearch] = useState("");
|
|
341
|
+
const searchSidebar = useDebounce(valueSearch, 300);
|
|
342
|
+
const [showSubmenu, setShowSubmenu] = useState(false);
|
|
343
|
+
const [activeModule, setActiveModule] = useState("");
|
|
344
|
+
const [openDropdownMenu, setOpenDropdownMenu] = useState(null);
|
|
345
|
+
const navigate = useNavigate();
|
|
346
|
+
const { sidebarMenu } = useMenuFilter(menu);
|
|
347
|
+
const dataOption = useMemo(
|
|
348
|
+
() => getDataOption(sidebarMenu, searchSidebar),
|
|
349
|
+
[sidebarMenu, searchSidebar]
|
|
350
|
+
);
|
|
351
|
+
const handleSelect = (_value, path) => {
|
|
352
|
+
navigate(path.path);
|
|
353
|
+
};
|
|
354
|
+
const handleClickDropdownMenu = (isDropdown, item) => {
|
|
355
|
+
if (isDropdown) {
|
|
356
|
+
setOpenDropdownMenu((prev) => prev === item.path ? null : item.path);
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
navigate(item.path);
|
|
360
|
+
};
|
|
361
|
+
const handleNavigateModule = (item) => {
|
|
362
|
+
setShowSubmenu(true);
|
|
363
|
+
setHoverOpenMenu(false);
|
|
364
|
+
setActiveModule(item.path);
|
|
365
|
+
};
|
|
366
|
+
const handleCloseSubmenu = () => {
|
|
367
|
+
setShowSubmenu(false);
|
|
368
|
+
};
|
|
369
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
370
|
+
/* @__PURE__ */ jsx(
|
|
371
|
+
Header,
|
|
372
|
+
{
|
|
373
|
+
dataOption,
|
|
374
|
+
valueSearch,
|
|
375
|
+
onSearchChange: setValueSearch,
|
|
376
|
+
onSelect: handleSelect,
|
|
377
|
+
hoverOpenMenu
|
|
378
|
+
}
|
|
379
|
+
),
|
|
380
|
+
/* @__PURE__ */ jsx(
|
|
381
|
+
MainSidebar,
|
|
382
|
+
{
|
|
383
|
+
sidebarMenu,
|
|
384
|
+
hoverOpenMenu,
|
|
385
|
+
activeModule,
|
|
386
|
+
onMouseEnter: () => setHoverOpenMenu(true),
|
|
387
|
+
onMouseLeave: () => setHoverOpenMenu(false),
|
|
388
|
+
onNavigateModule: handleNavigateModule
|
|
389
|
+
}
|
|
390
|
+
),
|
|
391
|
+
/* @__PURE__ */ jsx(
|
|
392
|
+
SubMenu,
|
|
393
|
+
{
|
|
394
|
+
sidebarMenu,
|
|
395
|
+
showSubmenu,
|
|
396
|
+
hoverOpenMenu,
|
|
397
|
+
activeModule,
|
|
398
|
+
openDropdownMenu,
|
|
399
|
+
onCloseSubmenu: handleCloseSubmenu,
|
|
400
|
+
onClickDropdownMenu: handleClickDropdownMenu
|
|
401
|
+
}
|
|
402
|
+
),
|
|
403
|
+
/* @__PURE__ */ jsx(ContentArea, { hoverOpenMenu, showSubmenu, children })
|
|
404
|
+
] });
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
const DashboardIcon = () => /* @__PURE__ */ jsx("span", { children: "📊" });
|
|
408
|
+
const UsersIcon = () => /* @__PURE__ */ jsx("span", { children: "👥" });
|
|
409
|
+
const SettingsIcon = () => /* @__PURE__ */ jsx("span", { children: "⚙️" });
|
|
410
|
+
const exampleMenu = [
|
|
411
|
+
{
|
|
412
|
+
name: "Dashboard",
|
|
413
|
+
path: "/dashboard",
|
|
414
|
+
isShow: true,
|
|
415
|
+
icon: /* @__PURE__ */ jsx(DashboardIcon, {}),
|
|
416
|
+
children: [
|
|
417
|
+
{
|
|
418
|
+
name: "Analytics",
|
|
419
|
+
path: "/dashboard/analytics",
|
|
420
|
+
isShow: true,
|
|
421
|
+
icon: /* @__PURE__ */ jsx(DashboardIcon, {}),
|
|
422
|
+
children: [
|
|
423
|
+
{ name: "Reports", path: "reports" },
|
|
424
|
+
{ name: "Charts", path: "charts" }
|
|
425
|
+
]
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
name: "Overview",
|
|
429
|
+
path: "/dashboard/overview",
|
|
430
|
+
isShow: false,
|
|
431
|
+
// Dropdown menu
|
|
432
|
+
icon: /* @__PURE__ */ jsx(DashboardIcon, {}),
|
|
433
|
+
children: [
|
|
434
|
+
{ name: "Summary", path: "summary" },
|
|
435
|
+
{ name: "Details", path: "details" }
|
|
436
|
+
]
|
|
437
|
+
}
|
|
438
|
+
]
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
name: "Users",
|
|
442
|
+
path: "/users",
|
|
443
|
+
isShow: true,
|
|
444
|
+
icon: /* @__PURE__ */ jsx(UsersIcon, {}),
|
|
445
|
+
children: [
|
|
446
|
+
{
|
|
447
|
+
name: "Management",
|
|
448
|
+
path: "/users/management",
|
|
449
|
+
isShow: true,
|
|
450
|
+
icon: /* @__PURE__ */ jsx(UsersIcon, {}),
|
|
451
|
+
children: [
|
|
452
|
+
{ name: "List", path: "list" },
|
|
453
|
+
{ name: "Roles", path: "roles" }
|
|
454
|
+
]
|
|
455
|
+
}
|
|
456
|
+
]
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
name: "Settings",
|
|
460
|
+
path: "/settings",
|
|
461
|
+
isShow: true,
|
|
462
|
+
icon: /* @__PURE__ */ jsx(SettingsIcon, {}),
|
|
463
|
+
children: [
|
|
464
|
+
{
|
|
465
|
+
name: "General",
|
|
466
|
+
path: "/settings/general",
|
|
467
|
+
isShow: true,
|
|
468
|
+
icon: /* @__PURE__ */ jsx(SettingsIcon, {})
|
|
469
|
+
}
|
|
470
|
+
]
|
|
471
|
+
}
|
|
472
|
+
];
|
|
473
|
+
const ExampleContent = () => /* @__PURE__ */ jsxs("div", { className: "p-6", children: [
|
|
474
|
+
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold mb-4", children: "Main Content Area" }),
|
|
475
|
+
/* @__PURE__ */ jsx("p", { className: "text-gray-600", children: "Đây là nội dung chính của ứng dụng. Sidebar sẽ tự động điều chỉnh margin của content area này dựa trên trạng thái hiển thị." }),
|
|
476
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-6 p-4 bg-gray-100 rounded", children: [
|
|
477
|
+
/* @__PURE__ */ jsx("h2", { className: "font-semibold", children: "Features:" }),
|
|
478
|
+
/* @__PURE__ */ jsxs("ul", { className: "mt-2 space-y-1", children: [
|
|
479
|
+
/* @__PURE__ */ jsx("li", { children: "• Hover sidebar để mở rộng" }),
|
|
480
|
+
/* @__PURE__ */ jsx("li", { children: "• Click module để hiển thị submenu" }),
|
|
481
|
+
/* @__PURE__ */ jsx("li", { children: "• Sử dụng search để tìm nhanh chức năng" }),
|
|
482
|
+
/* @__PURE__ */ jsx("li", { children: '• Click "Thu gọn menu" để đóng submenu' })
|
|
483
|
+
] })
|
|
484
|
+
] })
|
|
485
|
+
] });
|
|
486
|
+
const SidebarV3Example = () => {
|
|
487
|
+
return /* @__PURE__ */ jsx(SidebarV3, { menu: exampleMenu, children: /* @__PURE__ */ jsx(ExampleContent, {}) });
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
export { SidebarV3, SidebarV3Example };
|
package/es/ui/UploadComponent.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { Upload, Image, Tooltip } from 'antd';
|
|
3
3
|
import { Spin } from './Spin.js';
|
|
4
|
-
import { t as twMerge } from '../chunks/bundle-mjs-
|
|
4
|
+
import { t as twMerge } from '../chunks/bundle-mjs-BME7zF0Z.js';
|
|
5
5
|
import { Label } from './Label.js';
|
|
6
6
|
import { R as RefIcon } from '../chunks/CloseOutlined-D9hb-IcI.js';
|
|
7
7
|
|
package/es/ui/UploadImage.js
CHANGED
package/es/ui/index.js
CHANGED
|
@@ -59,7 +59,7 @@ import { CATEGORY_LIST_ENUM } from './CategoryStatus.js';
|
|
|
59
59
|
export { CategoryStatus, badgeStatusCategoryConfig } from './CategoryStatus.js';
|
|
60
60
|
import { useToggle } from '@pnkx-lib/core';
|
|
61
61
|
import { isEmpty, isBoolean } from 'lodash';
|
|
62
|
-
import { t as twMerge } from '../chunks/bundle-mjs-
|
|
62
|
+
import { t as twMerge } from '../chunks/bundle-mjs-BME7zF0Z.js';
|
|
63
63
|
export { BreadcrumbHeading } from './BreadcrumbHeading.js';
|
|
64
64
|
export { Card } from './Card.js';
|
|
65
65
|
export { ConfigProvider } from './ConfigProvider.js';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnkx-lib/ui",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.9.
|
|
4
|
+
"version": "1.9.412",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./es/index.js",
|
|
7
7
|
"module": "./es/index.js",
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
]
|
|
118
118
|
},
|
|
119
119
|
"peerDependencies": {
|
|
120
|
-
"@pnkx-lib/core": "^1.1.
|
|
120
|
+
"@pnkx-lib/core": "^1.1.107",
|
|
121
121
|
"@tailwindcss/vite": "^4.0.17",
|
|
122
122
|
"antd": "^5.24.4",
|
|
123
123
|
"react": "^18.3.1",
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
interface HeaderProps {
|
|
3
|
+
dataOption: any[];
|
|
4
|
+
valueSearch: string;
|
|
5
|
+
onSearchChange: (value: string) => void;
|
|
6
|
+
onSelect: (value: string, option: {
|
|
7
|
+
path: string;
|
|
8
|
+
}) => void;
|
|
9
|
+
hoverOpenMenu: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare const Header: React.FC<HeaderProps>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { MenuTypeV3 } from './types';
|
|
3
|
+
interface MainSidebarProps {
|
|
4
|
+
sidebarMenu: MenuTypeV3[];
|
|
5
|
+
hoverOpenMenu: boolean;
|
|
6
|
+
activeModule: string;
|
|
7
|
+
onMouseEnter: () => void;
|
|
8
|
+
onMouseLeave: () => void;
|
|
9
|
+
onNavigateModule: (item: MenuTypeV3) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare const MainSidebar: React.FC<MainSidebarProps>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
interface SearchHeaderProps {
|
|
3
|
+
dataOption: any[];
|
|
4
|
+
valueSearch: string;
|
|
5
|
+
onSearchChange: (value: string) => void;
|
|
6
|
+
onSelect: (value: string, option: {
|
|
7
|
+
path: string;
|
|
8
|
+
}) => void;
|
|
9
|
+
}
|
|
10
|
+
export declare const SearchHeader: React.FC<SearchHeaderProps>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { MenuTypeV3 } from './types';
|
|
3
|
+
interface SubMenuProps {
|
|
4
|
+
sidebarMenu: MenuTypeV3[];
|
|
5
|
+
showSubmenu: boolean;
|
|
6
|
+
hoverOpenMenu: boolean;
|
|
7
|
+
activeModule: string;
|
|
8
|
+
openDropdownMenu: string | null;
|
|
9
|
+
onCloseSubmenu: () => void;
|
|
10
|
+
onClickDropdownMenu: (isDropdown: boolean | undefined, item: MenuTypeV3) => void;
|
|
11
|
+
}
|
|
12
|
+
export declare const SubMenu: React.FC<SubMenuProps>;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { MenuTypeV3 } from './types';
|
|
2
|
+
export declare const useMenuFilter: (menu: MenuTypeV3[]) => {
|
|
3
|
+
sidebarMenu: MenuTypeV3[];
|
|
4
|
+
};
|
|
5
|
+
export declare const usePathUtils: () => {
|
|
6
|
+
normalizePath: (path: string) => string;
|
|
7
|
+
comparePaths: (a: string, b: string) => boolean;
|
|
8
|
+
};
|
|
9
|
+
export declare const classNames: (...classes: unknown[]) => string;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export type MenuTypeV3 = {
|
|
3
|
+
name: string;
|
|
4
|
+
path: string;
|
|
5
|
+
isShow?: boolean;
|
|
6
|
+
isPrivateRoute?: boolean;
|
|
7
|
+
icon?: ReactNode;
|
|
8
|
+
code?: string;
|
|
9
|
+
isShowLabel?: boolean;
|
|
10
|
+
isModule?: boolean;
|
|
11
|
+
component?: React.LazyExoticComponent<React.MemoExoticComponent<any>> | React.ExoticComponent<any> | ReactNode | React.FC;
|
|
12
|
+
componentProps?: Record<string, any>;
|
|
13
|
+
children?: MenuTypeV3[];
|
|
14
|
+
};
|
|
15
|
+
export interface SidebarV3Props {
|
|
16
|
+
menu: MenuTypeV3[];
|
|
17
|
+
children: React.ReactNode;
|
|
18
|
+
}
|
|
19
|
+
export interface SidebarState {
|
|
20
|
+
hoverOpenMenu: boolean;
|
|
21
|
+
valueSearch: string;
|
|
22
|
+
showSubmenu: boolean;
|
|
23
|
+
activeModule: string;
|
|
24
|
+
openDropdownMenu: string | null;
|
|
25
|
+
}
|