@wikex/admin-kit 0.2.0 → 0.2.1
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 +4 -0
- package/dist/admin/before-login.d.ts +5 -0
- package/dist/admin/before-login.js +26 -0
- package/dist/admin/brand.d.ts +19 -0
- package/dist/admin/brand.js +15 -0
- package/dist/admin/header.d.ts +5 -0
- package/dist/admin/header.js +87 -0
- package/dist/admin/logout-button.d.ts +8 -0
- package/dist/admin/logout-button.js +7 -0
- package/dist/admin/nav.d.ts +19 -0
- package/dist/admin/nav.js +285 -0
- package/dist/admin/theme-toggle.d.ts +5 -0
- package/dist/admin/theme-toggle.js +7 -0
- package/dist/admin/view-site.d.ts +5 -0
- package/dist/admin/view-site.js +6 -0
- package/dist/chunk-7FEACJUN.js +151 -0
- package/dist/chunk-BUD6BMFV.js +117 -0
- package/dist/chunk-GGSOO4FQ.js +27 -0
- package/dist/chunk-IL2CUCDG.js +2062 -0
- package/dist/chunk-JJLHSZ3T.js +40 -0
- package/dist/chunk-LC2CP5SR.js +13 -0
- package/dist/chunk-LP22Y3NO.js +61 -0
- package/dist/chunk-MDMKKWPU.js +12 -0
- package/dist/chunk-W4ZKDOWJ.js +37 -0
- package/dist/chunk-XGKGKCQ6.js +50 -0
- package/dist/chunk-YMBJCWN3.js +73 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +44 -0
- package/dist/live-preview.d.ts +50 -0
- package/dist/live-preview.js +19 -0
- package/dist/project.d.ts +34 -0
- package/dist/project.js +8 -0
- package/dist/rich-text-client.d.ts +5 -0
- package/dist/rich-text-client.js +165 -0
- package/dist/rich-text.d.ts +5 -0
- package/dist/rich-text.js +6 -0
- package/dist/runtimeConfig-BwjQepcW.d.ts +30 -0
- package/dist/starter-client.d.ts +15 -0
- package/dist/starter-client.js +25 -0
- package/dist/starter.d.ts +40 -0
- package/dist/starter.js +62 -0
- package/dist/text-style-runtime.d.ts +5 -0
- package/dist/text-style-runtime.js +8 -0
- package/dist/text-styles.d.ts +86 -0
- package/dist/text-styles.js +22 -0
- package/package.json +23 -19
- package/src/TextStyleRuntime.tsx +0 -90
- package/src/admin/BeforeLogin.tsx +0 -19
- package/src/admin/Brand.tsx +0 -74
- package/src/admin/Header.tsx +0 -87
- package/src/admin/LogoutButton.tsx +0 -41
- package/src/admin/Nav.tsx +0 -35
- package/src/admin/NavClient.tsx +0 -288
- package/src/admin/ThemeToggle.tsx +0 -31
- package/src/admin/ViewSite.tsx +0 -11
- package/src/admin/useAdminBrand.ts +0 -81
- package/src/adminExperience.ts +0 -117
- package/src/index.ts +0 -11
- package/src/live-preview/GlobalInlineInspector.tsx +0 -334
- package/src/live-preview/LivePreviewEditor.tsx +0 -2088
- package/src/live-preview/TextStyleInspector.tsx +0 -289
- package/src/live-preview/index.ts +0 -23
- package/src/live-preview/runtimeConfig.ts +0 -52
- package/src/plugin.ts +0 -70
- package/src/project.ts +0 -82
- package/src/rich-text/client.tsx +0 -202
- package/src/rich-text/index.ts +0 -10
- package/src/starter/client.tsx +0 -22
- package/src/starter.ts +0 -95
- package/src/textStyles.ts +0 -161
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
Các thay đổi đáng chú ý của `@wikex/admin-kit` được ghi tại đây theo Semantic Versioning.
|
|
4
4
|
|
|
5
|
+
## 0.2.1 - 2026-09-12
|
|
6
|
+
|
|
7
|
+
- Publish JavaScript build và type declarations để Payload CLI chạy được trong project độc lập.
|
|
8
|
+
|
|
5
9
|
## 0.2.0 - 2026-09-12
|
|
6
10
|
|
|
7
11
|
- Thêm `createWikexStarter`: một factory cấu hình content schema, SEO, redirect, admin UI,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
useAdminBrand
|
|
4
|
+
} from "../chunk-XGKGKCQ6.js";
|
|
5
|
+
|
|
6
|
+
// src/admin/BeforeLogin.tsx
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
var BeforeLogin = () => {
|
|
9
|
+
const { siteName } = useAdminBrand();
|
|
10
|
+
return /* @__PURE__ */ jsxs("div", { className: "admin-login-intro", children: [
|
|
11
|
+
/* @__PURE__ */ jsxs("span", { className: "admin-login-intro__eyebrow", children: [
|
|
12
|
+
siteName,
|
|
13
|
+
" \xB7 Trung t\xE2m n\u1ED9i dung"
|
|
14
|
+
] }),
|
|
15
|
+
/* @__PURE__ */ jsx("h1", { children: "Ch\xE0o m\u1EEBng tr\u1EDF l\u1EA1i." }),
|
|
16
|
+
/* @__PURE__ */ jsxs("p", { children: [
|
|
17
|
+
"\u0110\u0103ng nh\u1EADp \u0111\u1EC3 qu\u1EA3n l\xFD n\u1ED9i dung, h\xECnh \u1EA3nh v\xE0 xu\u1EA5t b\u1EA3n c\u1EE7a ",
|
|
18
|
+
siteName,
|
|
19
|
+
"."
|
|
20
|
+
] })
|
|
21
|
+
] });
|
|
22
|
+
};
|
|
23
|
+
var BeforeLogin_default = BeforeLogin;
|
|
24
|
+
export {
|
|
25
|
+
BeforeLogin_default as default
|
|
26
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
type AdminBrandSettings = {
|
|
4
|
+
logo: AdminBrandAsset;
|
|
5
|
+
siteName: string;
|
|
6
|
+
};
|
|
7
|
+
declare const configureAdminBrand: (brand: AdminBrandSettings) => void;
|
|
8
|
+
declare const useAdminBrand: () => AdminBrandSettings;
|
|
9
|
+
|
|
10
|
+
type AdminBrandAsset = {
|
|
11
|
+
alt: string;
|
|
12
|
+
height: number;
|
|
13
|
+
url: string;
|
|
14
|
+
width: number;
|
|
15
|
+
};
|
|
16
|
+
declare const AdminIcon: React.FC;
|
|
17
|
+
declare const AdminLogo: React.FC;
|
|
18
|
+
|
|
19
|
+
export { type AdminBrandAsset, type AdminBrandSettings, AdminIcon, AdminLogo, configureAdminBrand, useAdminBrand };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
AdminIcon,
|
|
4
|
+
AdminLogo
|
|
5
|
+
} from "../chunk-LP22Y3NO.js";
|
|
6
|
+
import {
|
|
7
|
+
configureAdminBrand,
|
|
8
|
+
useAdminBrand
|
|
9
|
+
} from "../chunk-XGKGKCQ6.js";
|
|
10
|
+
export {
|
|
11
|
+
AdminIcon,
|
|
12
|
+
AdminLogo,
|
|
13
|
+
configureAdminBrand,
|
|
14
|
+
useAdminBrand
|
|
15
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
ThemeToggle_default
|
|
4
|
+
} from "../chunk-GGSOO4FQ.js";
|
|
5
|
+
import {
|
|
6
|
+
ViewSite_default
|
|
7
|
+
} from "../chunk-MDMKKWPU.js";
|
|
8
|
+
import {
|
|
9
|
+
AdminIcon
|
|
10
|
+
} from "../chunk-LP22Y3NO.js";
|
|
11
|
+
import "../chunk-XGKGKCQ6.js";
|
|
12
|
+
|
|
13
|
+
// src/admin/Header.tsx
|
|
14
|
+
import { Link, useAuth, useConfig, useNav } from "@payloadcms/ui";
|
|
15
|
+
import { Menu, Settings2 } from "lucide-react";
|
|
16
|
+
import { formatAdminURL } from "payload/shared";
|
|
17
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
18
|
+
var getInitials = (name, email) => {
|
|
19
|
+
const source = name?.trim() || email?.split("@")[0] || "AD";
|
|
20
|
+
return source.split(/\s+/).slice(0, 2).map((part) => part.charAt(0).toUpperCase()).join("");
|
|
21
|
+
};
|
|
22
|
+
var AdminHeader = () => {
|
|
23
|
+
const { user } = useAuth();
|
|
24
|
+
const { setNavOpen } = useNav();
|
|
25
|
+
const {
|
|
26
|
+
config: {
|
|
27
|
+
admin: { routes: adminRoutes },
|
|
28
|
+
routes: { admin: adminRoute }
|
|
29
|
+
}
|
|
30
|
+
} = useConfig();
|
|
31
|
+
const userLabel = user?.name?.trim() || user?.email?.split("@")[0] || "Qu\u1EA3n tr\u1ECB vi\xEAn";
|
|
32
|
+
const initials = getInitials(user?.name, user?.email);
|
|
33
|
+
return /* @__PURE__ */ jsxs("header", { className: "minimal-admin-header", children: [
|
|
34
|
+
/* @__PURE__ */ jsxs("div", { className: "minimal-admin-header__left", children: [
|
|
35
|
+
/* @__PURE__ */ jsx(
|
|
36
|
+
"button",
|
|
37
|
+
{
|
|
38
|
+
"aria-label": "M\u1EDF menu qu\u1EA3n tr\u1ECB",
|
|
39
|
+
className: "minimal-admin-header__menu",
|
|
40
|
+
onClick: () => setNavOpen(true),
|
|
41
|
+
type: "button",
|
|
42
|
+
children: /* @__PURE__ */ jsx(Menu, { "aria-hidden": "true" })
|
|
43
|
+
}
|
|
44
|
+
),
|
|
45
|
+
/* @__PURE__ */ jsx(
|
|
46
|
+
Link,
|
|
47
|
+
{
|
|
48
|
+
"aria-label": "V\u1EC1 dashboard",
|
|
49
|
+
className: "minimal-admin-header__mobile-brand",
|
|
50
|
+
href: adminRoute,
|
|
51
|
+
prefetch: false,
|
|
52
|
+
children: /* @__PURE__ */ jsx(AdminIcon, {})
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
] }),
|
|
56
|
+
/* @__PURE__ */ jsxs("div", { className: "minimal-admin-header__actions", children: [
|
|
57
|
+
/* @__PURE__ */ jsx(ViewSite_default, {}),
|
|
58
|
+
/* @__PURE__ */ jsx(ThemeToggle_default, {}),
|
|
59
|
+
/* @__PURE__ */ jsx(
|
|
60
|
+
Link,
|
|
61
|
+
{
|
|
62
|
+
"aria-label": `M\u1EDF t\xE0i kho\u1EA3n ${userLabel}`,
|
|
63
|
+
className: "minimal-admin-header__settings",
|
|
64
|
+
href: formatAdminURL({ adminRoute, path: adminRoutes.account }),
|
|
65
|
+
prefetch: false,
|
|
66
|
+
title: "C\xE0i \u0111\u1EB7t t\xE0i kho\u1EA3n",
|
|
67
|
+
children: /* @__PURE__ */ jsx(Settings2, { "aria-hidden": "true" })
|
|
68
|
+
}
|
|
69
|
+
),
|
|
70
|
+
/* @__PURE__ */ jsx(
|
|
71
|
+
Link,
|
|
72
|
+
{
|
|
73
|
+
"aria-label": `M\u1EDF t\xE0i kho\u1EA3n ${userLabel}`,
|
|
74
|
+
className: "minimal-admin-header__account",
|
|
75
|
+
href: formatAdminURL({ adminRoute, path: adminRoutes.account }),
|
|
76
|
+
prefetch: false,
|
|
77
|
+
title: userLabel,
|
|
78
|
+
children: /* @__PURE__ */ jsx("span", { children: initials })
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
] })
|
|
82
|
+
] });
|
|
83
|
+
};
|
|
84
|
+
var Header_default = AdminHeader;
|
|
85
|
+
export {
|
|
86
|
+
Header_default as default
|
|
87
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ServerProps } from 'payload';
|
|
3
|
+
|
|
4
|
+
type AdminNavGroup = {
|
|
5
|
+
items: Array<{
|
|
6
|
+
label: string;
|
|
7
|
+
slug: string;
|
|
8
|
+
type: 'collections' | 'globals';
|
|
9
|
+
}>;
|
|
10
|
+
label: string;
|
|
11
|
+
};
|
|
12
|
+
type AdminNavClientProps = {
|
|
13
|
+
groups: AdminNavGroup[];
|
|
14
|
+
};
|
|
15
|
+
declare const AdminNavClient: ({ groups }: AdminNavClientProps) => react_jsx_runtime.JSX.Element;
|
|
16
|
+
|
|
17
|
+
declare const AdminNav: ({ i18n, payload, permissions, visibleEntities }: ServerProps) => react_jsx_runtime.JSX.Element | null;
|
|
18
|
+
|
|
19
|
+
export { AdminNavClient, type AdminNavGroup, AdminNav as default };
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AdminIcon,
|
|
3
|
+
AdminLogo
|
|
4
|
+
} from "../chunk-LP22Y3NO.js";
|
|
5
|
+
import {
|
|
6
|
+
useAdminBrand
|
|
7
|
+
} from "../chunk-XGKGKCQ6.js";
|
|
8
|
+
import {
|
|
9
|
+
LogoutButton_default
|
|
10
|
+
} from "../chunk-W4ZKDOWJ.js";
|
|
11
|
+
|
|
12
|
+
// src/admin/Nav.tsx
|
|
13
|
+
import { getNavGroups } from "@payloadcms/ui/shared";
|
|
14
|
+
|
|
15
|
+
// src/admin/NavClient.tsx
|
|
16
|
+
import { Link, useAuth, useConfig, useNav } from "@payloadcms/ui";
|
|
17
|
+
import {
|
|
18
|
+
BookOpenText,
|
|
19
|
+
BriefcaseBusiness,
|
|
20
|
+
ChevronLeft,
|
|
21
|
+
ChevronRight,
|
|
22
|
+
FileText,
|
|
23
|
+
FolderKanban,
|
|
24
|
+
GalleryVerticalEnd,
|
|
25
|
+
Home,
|
|
26
|
+
Image,
|
|
27
|
+
LayoutDashboard,
|
|
28
|
+
Library,
|
|
29
|
+
Menu,
|
|
30
|
+
PanelBottom,
|
|
31
|
+
PanelTop,
|
|
32
|
+
Settings2,
|
|
33
|
+
Tags,
|
|
34
|
+
Users,
|
|
35
|
+
X
|
|
36
|
+
} from "lucide-react";
|
|
37
|
+
import { usePathname } from "next/navigation";
|
|
38
|
+
import { formatAdminURL } from "payload/shared";
|
|
39
|
+
import { useEffect, useMemo, useState } from "react";
|
|
40
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
41
|
+
var iconBySlug = {
|
|
42
|
+
categories: Tags,
|
|
43
|
+
footer: PanelBottom,
|
|
44
|
+
header: PanelTop,
|
|
45
|
+
homepage: Home,
|
|
46
|
+
media: Image,
|
|
47
|
+
pages: FileText,
|
|
48
|
+
posts: BookOpenText,
|
|
49
|
+
projects: FolderKanban,
|
|
50
|
+
services: BriefcaseBusiness,
|
|
51
|
+
settings: Settings2,
|
|
52
|
+
users: Users
|
|
53
|
+
};
|
|
54
|
+
var translateGroupLabel = (label) => label === "Collections" ? "B\u1ED9 s\u01B0u t\u1EADp" : label === "Globals" ? "Thi\u1EBFt l\u1EADp chung" : label;
|
|
55
|
+
var getInitials = (name, email) => {
|
|
56
|
+
const source = name?.trim() || email?.split("@")[0] || "AD";
|
|
57
|
+
return source.split(/\s+/).slice(0, 2).map((part) => part.charAt(0).toUpperCase()).join("");
|
|
58
|
+
};
|
|
59
|
+
var AdminNavClient = ({ groups }) => {
|
|
60
|
+
const pathname = usePathname();
|
|
61
|
+
const brand = useAdminBrand();
|
|
62
|
+
const { user } = useAuth();
|
|
63
|
+
const { hydrated, navOpen, navRef, setNavOpen, shouldAnimate } = useNav();
|
|
64
|
+
const {
|
|
65
|
+
config: {
|
|
66
|
+
admin: { routes: adminRoutes },
|
|
67
|
+
folders,
|
|
68
|
+
routes: { admin: adminRoute }
|
|
69
|
+
}
|
|
70
|
+
} = useConfig();
|
|
71
|
+
const [isMini, setIsMini] = useState(false);
|
|
72
|
+
const [isMobile, setIsMobile] = useState(false);
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
const storedValue = window.localStorage.getItem("minimal-admin-nav-mini");
|
|
75
|
+
setIsMini(storedValue === "true");
|
|
76
|
+
}, []);
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
const mediaQuery = window.matchMedia("(max-width: 768px)");
|
|
79
|
+
const syncViewport = () => setIsMobile(mediaQuery.matches);
|
|
80
|
+
syncViewport();
|
|
81
|
+
mediaQuery.addEventListener("change", syncViewport);
|
|
82
|
+
return () => mediaQuery.removeEventListener("change", syncViewport);
|
|
83
|
+
}, []);
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
document.documentElement.style.setProperty("--nav-width", isMini ? "88px" : "280px");
|
|
86
|
+
window.localStorage.setItem("minimal-admin-nav-mini", String(isMini));
|
|
87
|
+
return () => {
|
|
88
|
+
document.documentElement.style.removeProperty("--nav-width");
|
|
89
|
+
};
|
|
90
|
+
}, [isMini]);
|
|
91
|
+
const userLabel = user?.name?.trim() || user?.email?.split("@")[0] || "Qu\u1EA3n tr\u1ECB vi\xEAn";
|
|
92
|
+
const initials = useMemo(() => getInitials(user?.name, user?.email), [user?.email, user?.name]);
|
|
93
|
+
const closeMobileNav = () => {
|
|
94
|
+
if (window.matchMedia("(max-width: 768px)").matches) setNavOpen(false);
|
|
95
|
+
};
|
|
96
|
+
const classes = [
|
|
97
|
+
"minimal-nav",
|
|
98
|
+
navOpen && "minimal-nav--open",
|
|
99
|
+
isMini && "minimal-nav--mini",
|
|
100
|
+
shouldAnimate && "minimal-nav--animate",
|
|
101
|
+
hydrated && "minimal-nav--hydrated"
|
|
102
|
+
].filter(Boolean).join(" ");
|
|
103
|
+
const isActive = (href) => pathname === href || href !== adminRoute && pathname.startsWith(`${href}/`);
|
|
104
|
+
return /* @__PURE__ */ jsxs(
|
|
105
|
+
"aside",
|
|
106
|
+
{
|
|
107
|
+
"aria-label": "\u0110i\u1EC1u h\u01B0\u1EDBng qu\u1EA3n tr\u1ECB",
|
|
108
|
+
className: classes,
|
|
109
|
+
inert: isMobile && !navOpen || void 0,
|
|
110
|
+
children: [
|
|
111
|
+
/* @__PURE__ */ jsxs("div", { className: "minimal-nav__scroll", ref: navRef, children: [
|
|
112
|
+
/* @__PURE__ */ jsxs("div", { className: "minimal-nav__brand-row", children: [
|
|
113
|
+
/* @__PURE__ */ jsxs(
|
|
114
|
+
Link,
|
|
115
|
+
{
|
|
116
|
+
"aria-label": `V\u1EC1 dashboard ${brand.siteName}`,
|
|
117
|
+
className: "minimal-nav__brand",
|
|
118
|
+
href: adminRoute,
|
|
119
|
+
onClick: closeMobileNav,
|
|
120
|
+
prefetch: false,
|
|
121
|
+
children: [
|
|
122
|
+
/* @__PURE__ */ jsx("span", { className: "minimal-nav__brand-full", children: /* @__PURE__ */ jsx(AdminLogo, {}) }),
|
|
123
|
+
/* @__PURE__ */ jsx("span", { className: "minimal-nav__brand-icon", children: /* @__PURE__ */ jsx(AdminIcon, {}) })
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
),
|
|
127
|
+
/* @__PURE__ */ jsx(
|
|
128
|
+
"button",
|
|
129
|
+
{
|
|
130
|
+
"aria-label": "\u0110\xF3ng menu",
|
|
131
|
+
className: "minimal-nav__mobile-close",
|
|
132
|
+
onClick: () => setNavOpen(false),
|
|
133
|
+
type: "button",
|
|
134
|
+
children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true" })
|
|
135
|
+
}
|
|
136
|
+
)
|
|
137
|
+
] }),
|
|
138
|
+
/* @__PURE__ */ jsxs(
|
|
139
|
+
Link,
|
|
140
|
+
{
|
|
141
|
+
className: "minimal-nav__workspace",
|
|
142
|
+
href: adminRoute,
|
|
143
|
+
onClick: closeMobileNav,
|
|
144
|
+
prefetch: false,
|
|
145
|
+
title: brand.siteName,
|
|
146
|
+
children: [
|
|
147
|
+
/* @__PURE__ */ jsx("span", { className: "minimal-nav__workspace-icon", children: /* @__PURE__ */ jsx(GalleryVerticalEnd, { "aria-hidden": "true" }) }),
|
|
148
|
+
/* @__PURE__ */ jsxs("span", { className: "minimal-nav__workspace-copy", children: [
|
|
149
|
+
/* @__PURE__ */ jsx("small", { children: "Kh\xF4ng gian l\xE0m vi\u1EC7c" }),
|
|
150
|
+
/* @__PURE__ */ jsx("strong", { children: brand.siteName })
|
|
151
|
+
] }),
|
|
152
|
+
/* @__PURE__ */ jsx(Menu, { "aria-hidden": "true", className: "minimal-nav__workspace-menu" })
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
),
|
|
156
|
+
/* @__PURE__ */ jsxs("nav", { className: "minimal-nav__menu", children: [
|
|
157
|
+
/* @__PURE__ */ jsxs("div", { className: "minimal-nav__group", children: [
|
|
158
|
+
/* @__PURE__ */ jsx("span", { className: "minimal-nav__group-label", children: "T\u1ED5ng quan" }),
|
|
159
|
+
/* @__PURE__ */ jsxs(
|
|
160
|
+
Link,
|
|
161
|
+
{
|
|
162
|
+
"aria-current": pathname === adminRoute ? "page" : void 0,
|
|
163
|
+
className: `minimal-nav__item ${pathname === adminRoute ? "minimal-nav__item--active" : ""}`,
|
|
164
|
+
href: adminRoute,
|
|
165
|
+
onClick: closeMobileNav,
|
|
166
|
+
prefetch: false,
|
|
167
|
+
title: "Dashboard",
|
|
168
|
+
children: [
|
|
169
|
+
/* @__PURE__ */ jsx(LayoutDashboard, { "aria-hidden": "true" }),
|
|
170
|
+
/* @__PURE__ */ jsx("span", { children: "T\u1ED5ng quan" })
|
|
171
|
+
]
|
|
172
|
+
}
|
|
173
|
+
)
|
|
174
|
+
] }),
|
|
175
|
+
groups.map((group) => /* @__PURE__ */ jsxs("div", { className: "minimal-nav__group", children: [
|
|
176
|
+
/* @__PURE__ */ jsx("span", { className: "minimal-nav__group-label", children: translateGroupLabel(group.label) }),
|
|
177
|
+
group.items.map((item) => {
|
|
178
|
+
const href = formatAdminURL({
|
|
179
|
+
adminRoute,
|
|
180
|
+
path: `/${item.type}/${item.slug}`
|
|
181
|
+
});
|
|
182
|
+
const Icon = iconBySlug[item.slug] || FileText;
|
|
183
|
+
const active = isActive(href);
|
|
184
|
+
return /* @__PURE__ */ jsxs(
|
|
185
|
+
Link,
|
|
186
|
+
{
|
|
187
|
+
"aria-current": active ? "page" : void 0,
|
|
188
|
+
className: `minimal-nav__item ${active ? "minimal-nav__item--active" : ""}`,
|
|
189
|
+
href,
|
|
190
|
+
onClick: closeMobileNav,
|
|
191
|
+
prefetch: false,
|
|
192
|
+
title: item.label,
|
|
193
|
+
children: [
|
|
194
|
+
/* @__PURE__ */ jsx(Icon, { "aria-hidden": "true" }),
|
|
195
|
+
/* @__PURE__ */ jsx("span", { children: item.label })
|
|
196
|
+
]
|
|
197
|
+
},
|
|
198
|
+
`${item.type}-${item.slug}`
|
|
199
|
+
);
|
|
200
|
+
})
|
|
201
|
+
] }, group.label)),
|
|
202
|
+
folders && folders.browseByFolder && /* @__PURE__ */ jsxs("div", { className: "minimal-nav__group", children: [
|
|
203
|
+
/* @__PURE__ */ jsx("span", { className: "minimal-nav__group-label", children: "Th\u01B0 vi\u1EC7n" }),
|
|
204
|
+
/* @__PURE__ */ jsxs(
|
|
205
|
+
Link,
|
|
206
|
+
{
|
|
207
|
+
"aria-current": isActive(formatAdminURL({ adminRoute, path: adminRoutes.browseByFolder })) ? "page" : void 0,
|
|
208
|
+
className: `minimal-nav__item ${isActive(formatAdminURL({ adminRoute, path: adminRoutes.browseByFolder })) ? "minimal-nav__item--active" : ""}`,
|
|
209
|
+
href: formatAdminURL({ adminRoute, path: adminRoutes.browseByFolder }),
|
|
210
|
+
onClick: closeMobileNav,
|
|
211
|
+
prefetch: false,
|
|
212
|
+
title: "Duy\u1EC7t theo th\u01B0 m\u1EE5c",
|
|
213
|
+
children: [
|
|
214
|
+
/* @__PURE__ */ jsx(Library, { "aria-hidden": "true" }),
|
|
215
|
+
/* @__PURE__ */ jsx("span", { children: "Duy\u1EC7t theo th\u01B0 m\u1EE5c" })
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
)
|
|
219
|
+
] })
|
|
220
|
+
] }),
|
|
221
|
+
/* @__PURE__ */ jsxs("div", { className: "minimal-nav__footer", children: [
|
|
222
|
+
/* @__PURE__ */ jsxs(
|
|
223
|
+
Link,
|
|
224
|
+
{
|
|
225
|
+
className: "minimal-nav__account",
|
|
226
|
+
href: formatAdminURL({ adminRoute, path: adminRoutes.account }),
|
|
227
|
+
onClick: closeMobileNav,
|
|
228
|
+
prefetch: false,
|
|
229
|
+
title: userLabel,
|
|
230
|
+
children: [
|
|
231
|
+
/* @__PURE__ */ jsx("span", { className: "minimal-nav__avatar", children: initials }),
|
|
232
|
+
/* @__PURE__ */ jsxs("span", { className: "minimal-nav__account-copy", children: [
|
|
233
|
+
/* @__PURE__ */ jsx("strong", { children: userLabel }),
|
|
234
|
+
/* @__PURE__ */ jsx("small", { children: user?.email || "T\xE0i kho\u1EA3n qu\u1EA3n tr\u1ECB" })
|
|
235
|
+
] })
|
|
236
|
+
]
|
|
237
|
+
}
|
|
238
|
+
),
|
|
239
|
+
/* @__PURE__ */ jsx("div", { className: "minimal-nav__logout", children: /* @__PURE__ */ jsx(LogoutButton_default, {}) })
|
|
240
|
+
] })
|
|
241
|
+
] }),
|
|
242
|
+
/* @__PURE__ */ jsx(
|
|
243
|
+
"button",
|
|
244
|
+
{
|
|
245
|
+
"aria-label": isMini ? "M\u1EDF r\u1ED9ng menu" : "Thu g\u1ECDn menu",
|
|
246
|
+
className: "minimal-nav__collapse",
|
|
247
|
+
onClick: () => setIsMini((current) => !current),
|
|
248
|
+
title: isMini ? "M\u1EDF r\u1ED9ng menu" : "Thu g\u1ECDn menu",
|
|
249
|
+
type: "button",
|
|
250
|
+
children: isMini ? /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(ChevronLeft, { "aria-hidden": "true" })
|
|
251
|
+
}
|
|
252
|
+
)
|
|
253
|
+
]
|
|
254
|
+
}
|
|
255
|
+
);
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
// src/admin/Nav.tsx
|
|
259
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
260
|
+
var localizeLabel = (label, language) => {
|
|
261
|
+
if (typeof label === "string") return label;
|
|
262
|
+
return label[language] || Object.values(label)[0] || "";
|
|
263
|
+
};
|
|
264
|
+
var AdminNav = ({ i18n, payload, permissions, visibleEntities }) => {
|
|
265
|
+
if (!permissions || !visibleEntities) return null;
|
|
266
|
+
const groups = getNavGroups(
|
|
267
|
+
permissions,
|
|
268
|
+
visibleEntities,
|
|
269
|
+
payload.config,
|
|
270
|
+
i18n
|
|
271
|
+
).map((group) => ({
|
|
272
|
+
items: group.entities.map((entity) => ({
|
|
273
|
+
label: localizeLabel(entity.label, i18n.language),
|
|
274
|
+
slug: entity.slug,
|
|
275
|
+
type: entity.type
|
|
276
|
+
})),
|
|
277
|
+
label: group.label
|
|
278
|
+
}));
|
|
279
|
+
return /* @__PURE__ */ jsx2(AdminNavClient, { groups });
|
|
280
|
+
};
|
|
281
|
+
var Nav_default = AdminNav;
|
|
282
|
+
export {
|
|
283
|
+
AdminNavClient,
|
|
284
|
+
Nav_default as default
|
|
285
|
+
};
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// src/adminExperience.ts
|
|
2
|
+
var IMAGE_UPLOAD_GUIDANCE = "Y\xEAu c\u1EA7u \u0111\u1EC3 \u1EA3nh hi\u1EC3n th\u1ECB r\xF5: hero/banner n\xEAn t\u1EEB 1920 \xD7 1080 px; \u1EA3nh n\u1ED9i dung n\xEAn r\u1ED9ng t\u1ED1i thi\u1EC3u 1200 px. \u01AFu ti\xEAn WebP ho\u1EB7c JPEG, dung l\u01B0\u1EE3ng d\u01B0\u1EDBi 500 KB.";
|
|
3
|
+
var labelTranslations = {
|
|
4
|
+
"Archive Block": "Kh\u1ED1i l\u01B0u tr\u1EEF",
|
|
5
|
+
Content: "N\u1ED9i dung",
|
|
6
|
+
Description: "M\xF4 t\u1EA3",
|
|
7
|
+
Hero: "M\u1EDF \u0111\u1EA7u",
|
|
8
|
+
"Hero Image": "\u1EA2nh \u0111\u1EA1i di\u1EC7n",
|
|
9
|
+
Image: "H\xECnh \u1EA3nh",
|
|
10
|
+
Layout: "B\u1ED1 c\u1EE5c",
|
|
11
|
+
Link: "Li\xEAn k\u1EBFt",
|
|
12
|
+
Media: "H\xECnh \u1EA3nh",
|
|
13
|
+
Meta: "Th\xF4ng tin b\u1ED5 sung",
|
|
14
|
+
Title: "Ti\xEAu \u0111\u1EC1"
|
|
15
|
+
};
|
|
16
|
+
var fieldNameLabels = {
|
|
17
|
+
alt: "V\u0103n b\u1EA3n thay th\u1EBF",
|
|
18
|
+
authors: "T\xE1c gi\u1EA3",
|
|
19
|
+
caption: "Ch\xFA th\xEDch",
|
|
20
|
+
categories: "Chuy\xEAn m\u1EE5c",
|
|
21
|
+
content: "N\u1ED9i dung",
|
|
22
|
+
coverImage: "\u1EA2nh b\xECa",
|
|
23
|
+
defaultOgImage: "\u1EA2nh chia s\u1EBB m\u1EB7c \u0111\u1ECBnh",
|
|
24
|
+
description: "M\xF4 t\u1EA3",
|
|
25
|
+
excerpt: "T\xF3m t\u1EAFt",
|
|
26
|
+
featuredImage: "\u1EA2nh n\u1ED5i b\u1EADt",
|
|
27
|
+
heroImage: "\u1EA2nh \u0111\u1EA1i di\u1EC7n",
|
|
28
|
+
image: "H\xECnh \u1EA3nh",
|
|
29
|
+
logo: "Logo",
|
|
30
|
+
media: "H\xECnh \u1EA3nh",
|
|
31
|
+
appearance: "Ki\u1EC3u hi\u1EC3n th\u1ECB",
|
|
32
|
+
links: "Li\xEAn k\u1EBFt",
|
|
33
|
+
newTab: "M\u1EDF trong tab m\u1EDBi",
|
|
34
|
+
publishedAt: "Ng\xE0y xu\u1EA5t b\u1EA3n",
|
|
35
|
+
relatedPosts: "B\xE0i vi\u1EBFt li\xEAn quan",
|
|
36
|
+
slug: "\u0110\u01B0\u1EDDng d\u1EABn",
|
|
37
|
+
summary: "M\xF4 t\u1EA3 ng\u1EAFn",
|
|
38
|
+
title: "Ti\xEAu \u0111\u1EC1",
|
|
39
|
+
type: "Lo\u1EA1i"
|
|
40
|
+
};
|
|
41
|
+
var entityLabels = {
|
|
42
|
+
"form-submissions": { plural: "D\u1EEF li\u1EC7u bi\u1EC3u m\u1EABu", singular: "D\u1EEF li\u1EC7u bi\u1EC3u m\u1EABu" },
|
|
43
|
+
forms: { plural: "Bi\u1EC3u m\u1EABu", singular: "Bi\u1EC3u m\u1EABu" },
|
|
44
|
+
redirects: { plural: "Chuy\u1EC3n h\u01B0\u1EDBng", singular: "Chuy\u1EC3n h\u01B0\u1EDBng" },
|
|
45
|
+
search: { plural: "K\u1EBFt qu\u1EA3 t\xECm ki\u1EBFm", singular: "K\u1EBFt qu\u1EA3 t\xECm ki\u1EBFm" }
|
|
46
|
+
};
|
|
47
|
+
var translateLabel = (label) => typeof label === "string" ? labelTranslations[label] || label : label;
|
|
48
|
+
var enhanceFields = (fields) => {
|
|
49
|
+
for (const field of fields) {
|
|
50
|
+
if ("name" in field) {
|
|
51
|
+
field.label = field.label === void 0 ? fieldNameLabels[field.name] : translateLabel(field.label);
|
|
52
|
+
} else if ("label" in field) {
|
|
53
|
+
field.label = translateLabel(field.label);
|
|
54
|
+
}
|
|
55
|
+
if (field.type === "upload" && field.relationTo === "media") {
|
|
56
|
+
const currentDescription = field.admin?.description;
|
|
57
|
+
field.admin = {
|
|
58
|
+
...field.admin,
|
|
59
|
+
description: typeof currentDescription === "string" && !currentDescription.includes(IMAGE_UPLOAD_GUIDANCE) ? `${currentDescription} ${IMAGE_UPLOAD_GUIDANCE}` : IMAGE_UPLOAD_GUIDANCE
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (field.type === "tabs") {
|
|
63
|
+
for (const tab of field.tabs) {
|
|
64
|
+
tab.label = translateLabel(tab.label);
|
|
65
|
+
enhanceFields(tab.fields);
|
|
66
|
+
}
|
|
67
|
+
} else if ("fields" in field && Array.isArray(field.fields)) {
|
|
68
|
+
enhanceFields(field.fields);
|
|
69
|
+
}
|
|
70
|
+
if (field.type === "blocks") {
|
|
71
|
+
for (const block of field.blocks ?? []) {
|
|
72
|
+
if (block.labels) {
|
|
73
|
+
block.labels = {
|
|
74
|
+
plural: translateLabel(block.labels.plural),
|
|
75
|
+
singular: translateLabel(block.labels.singular)
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
enhanceFields(block.fields);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
var adminExperiencePlugin = (config) => {
|
|
84
|
+
for (const collection of config.collections ?? []) {
|
|
85
|
+
const translatedLabels = entityLabels[collection.slug];
|
|
86
|
+
if (translatedLabels) collection.labels = translatedLabels;
|
|
87
|
+
enhanceFields(collection.fields);
|
|
88
|
+
if (collection.slug === "media") {
|
|
89
|
+
collection.admin = {
|
|
90
|
+
...collection.admin,
|
|
91
|
+
description: IMAGE_UPLOAD_GUIDANCE
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
for (const global of config.globals ?? []) enhanceFields(global.fields);
|
|
96
|
+
return config;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// src/plugin.ts
|
|
100
|
+
var appendUnique = (current, additions) => [
|
|
101
|
+
.../* @__PURE__ */ new Set([...current ?? [], ...additions])
|
|
102
|
+
];
|
|
103
|
+
var wikexAdminPlugin = (options = {}) => {
|
|
104
|
+
return (config) => {
|
|
105
|
+
if (options.enabled === false) return config;
|
|
106
|
+
const admin = config.admin ?? {};
|
|
107
|
+
const components = admin.components ?? {};
|
|
108
|
+
const beforeDashboard = options.components?.beforeDashboard;
|
|
109
|
+
const provider = options.components?.provider;
|
|
110
|
+
return {
|
|
111
|
+
...config,
|
|
112
|
+
admin: {
|
|
113
|
+
...admin,
|
|
114
|
+
components: {
|
|
115
|
+
...components,
|
|
116
|
+
Nav: components.Nav ?? "@wikex/admin-kit/admin/nav",
|
|
117
|
+
actions: appendUnique(components.actions, [
|
|
118
|
+
"@wikex/admin-kit/admin/theme-toggle",
|
|
119
|
+
"@wikex/admin-kit/admin/view-site"
|
|
120
|
+
]),
|
|
121
|
+
beforeDashboard: typeof beforeDashboard !== "string" ? components.beforeDashboard : appendUnique(components.beforeDashboard, [beforeDashboard]),
|
|
122
|
+
beforeLogin: appendUnique(components.beforeLogin, [
|
|
123
|
+
"@wikex/admin-kit/admin/before-login"
|
|
124
|
+
]),
|
|
125
|
+
graphics: {
|
|
126
|
+
Icon: components.graphics?.Icon ?? "@wikex/admin-kit/admin/brand#AdminIcon",
|
|
127
|
+
Logo: components.graphics?.Logo ?? "@wikex/admin-kit/admin/brand#AdminLogo"
|
|
128
|
+
},
|
|
129
|
+
header: appendUnique(components.header, ["@wikex/admin-kit/admin/header"]),
|
|
130
|
+
logout: {
|
|
131
|
+
Button: components.logout?.Button ?? "@wikex/admin-kit/admin/logout-button"
|
|
132
|
+
},
|
|
133
|
+
providers: typeof provider !== "string" ? components.providers : appendUnique(components.providers, [provider])
|
|
134
|
+
},
|
|
135
|
+
livePreview: admin.livePreview ?? {
|
|
136
|
+
breakpoints: [
|
|
137
|
+
{ height: 667, label: "\u0110i\u1EC7n tho\u1EA1i", name: "mobile", width: 375 },
|
|
138
|
+
{ height: 1024, label: "M\xE1y t\xEDnh b\u1EA3ng", name: "tablet", width: 768 },
|
|
139
|
+
{ height: 900, label: "M\xE1y t\xEDnh", name: "desktop", width: 1440 }
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export {
|
|
148
|
+
IMAGE_UPLOAD_GUIDANCE,
|
|
149
|
+
adminExperiencePlugin,
|
|
150
|
+
wikexAdminPlugin
|
|
151
|
+
};
|