nextblogkit 0.6.2 → 0.7.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/README.md +83 -21
- package/dist/admin/index.cjs +366 -10
- package/dist/admin/index.cjs.map +1 -1
- package/dist/admin/index.d.cts +7 -3
- package/dist/admin/index.d.ts +7 -3
- package/dist/admin/index.js +365 -11
- package/dist/admin/index.js.map +1 -1
- package/dist/api/categories.cjs +32 -32
- package/dist/api/categories.cjs.map +1 -1
- package/dist/api/categories.d.cts +1 -1
- package/dist/api/categories.d.ts +1 -1
- package/dist/api/categories.js +6 -6
- package/dist/api/categories.js.map +1 -1
- package/dist/api/media.cjs +37 -30
- package/dist/api/media.cjs.map +1 -1
- package/dist/api/media.d.cts +1 -1
- package/dist/api/media.d.ts +1 -1
- package/dist/api/media.js +13 -6
- package/dist/api/media.js.map +1 -1
- package/dist/api/posts.cjs +39 -39
- package/dist/api/posts.cjs.map +1 -1
- package/dist/api/posts.d.cts +1 -1
- package/dist/api/posts.d.ts +1 -1
- package/dist/api/posts.js +6 -6
- package/dist/api/posts.js.map +1 -1
- package/dist/api/rss.cjs +3 -3
- package/dist/api/rss.js +2 -2
- package/dist/api/settings.cjs +13 -13
- package/dist/api/settings.cjs.map +1 -1
- package/dist/api/settings.d.cts +1 -1
- package/dist/api/settings.d.ts +1 -1
- package/dist/api/settings.js +5 -5
- package/dist/api/settings.js.map +1 -1
- package/dist/api/sitemap.cjs +3 -3
- package/dist/api/sitemap.js +2 -2
- package/dist/api/tokens.cjs +56 -0
- package/dist/api/tokens.cjs.map +1 -0
- package/dist/api/tokens.d.cts +22 -0
- package/dist/api/tokens.d.ts +22 -0
- package/dist/api/tokens.js +52 -0
- package/dist/api/tokens.js.map +1 -0
- package/dist/{chunk-6HKMZOI4.cjs → chunk-3BKPNOES.cjs} +8 -7
- package/dist/chunk-3BKPNOES.cjs.map +1 -0
- package/dist/{chunk-N5MKAD7J.cjs → chunk-DR7QNI32.cjs} +6 -2
- package/dist/chunk-DR7QNI32.cjs.map +1 -0
- package/dist/{chunk-QE4VLQYN.cjs → chunk-F47RPOTU.cjs} +13 -10
- package/dist/chunk-F47RPOTU.cjs.map +1 -0
- package/dist/{chunk-64HUVJOZ.js → chunk-JI2RK6KX.js} +80 -13
- package/dist/chunk-JI2RK6KX.js.map +1 -0
- package/dist/{chunk-R6MO3QIP.js → chunk-NSR7NYSB.js} +6 -5
- package/dist/chunk-NSR7NYSB.js.map +1 -0
- package/dist/{chunk-4PY224XM.js → chunk-O3XES5O2.js} +6 -3
- package/dist/chunk-O3XES5O2.js.map +1 -0
- package/dist/{chunk-4NKOJYWJ.js → chunk-OOUJYUGP.js} +8 -7
- package/dist/chunk-OOUJYUGP.js.map +1 -0
- package/dist/{chunk-A2S32RZN.js → chunk-OWWWTTUT.js} +8 -3
- package/dist/chunk-OWWWTTUT.js.map +1 -0
- package/dist/{chunk-E2QLTHKN.cjs → chunk-QBZLGBHQ.cjs} +11 -10
- package/dist/chunk-QBZLGBHQ.cjs.map +1 -0
- package/dist/{chunk-ZP5XRVVH.cjs → chunk-SUJT6LWH.cjs} +12 -7
- package/dist/chunk-SUJT6LWH.cjs.map +1 -0
- package/dist/{chunk-JM7QRXXK.js → chunk-TVHY4BR2.js} +10 -7
- package/dist/chunk-TVHY4BR2.js.map +1 -0
- package/dist/{chunk-JLPJKNRZ.js → chunk-UMIBGO4S.js} +18 -5
- package/dist/chunk-UMIBGO4S.js.map +1 -0
- package/dist/{chunk-U2ROR6AY.cjs → chunk-VWKVU3SE.cjs} +86 -12
- package/dist/chunk-VWKVU3SE.cjs.map +1 -0
- package/dist/{chunk-KDZER3PU.cjs → chunk-YTJQ426D.cjs} +19 -5
- package/dist/chunk-YTJQ426D.cjs.map +1 -0
- package/dist/cli/index.cjs +90 -19
- package/dist/components/index.cjs +3 -2
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.cts +2 -1
- package/dist/components/index.d.ts +2 -1
- package/dist/components/index.js +3 -2
- package/dist/components/index.js.map +1 -1
- package/dist/db-OUSQPM53.js +3 -0
- package/dist/db-OUSQPM53.js.map +1 -0
- package/dist/db-RFY6O5UE.cjs +108 -0
- package/dist/db-RFY6O5UE.cjs.map +1 -0
- package/dist/editor/index.cjs +1 -0
- package/dist/editor/index.cjs.map +1 -1
- package/dist/editor/index.js +1 -0
- package/dist/editor/index.js.map +1 -1
- package/dist/{index-vjlZDWNr.d.cts → index-Bk8gOqBq.d.cts} +25 -21
- package/dist/{index-Cgzphklp.d.ts → index-DsnG2kdW.d.ts} +25 -21
- package/dist/index.cjs +47 -47
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +5 -5
- package/dist/lib/index.cjs +39 -35
- package/dist/lib/index.d.cts +2 -2
- package/dist/lib/index.d.ts +2 -2
- package/dist/lib/index.js +5 -5
- package/dist/{types-CBEEBR4A.d.ts → types-Cu515Egx.d.cts} +16 -1
- package/dist/{types-CBEEBR4A.d.cts → types-Cu515Egx.d.ts} +16 -1
- package/package.json +1 -1
- package/dist/chunk-4NKOJYWJ.js.map +0 -1
- package/dist/chunk-4PY224XM.js.map +0 -1
- package/dist/chunk-64HUVJOZ.js.map +0 -1
- package/dist/chunk-6HKMZOI4.cjs.map +0 -1
- package/dist/chunk-A2S32RZN.js.map +0 -1
- package/dist/chunk-E2QLTHKN.cjs.map +0 -1
- package/dist/chunk-JLPJKNRZ.js.map +0 -1
- package/dist/chunk-JM7QRXXK.js.map +0 -1
- package/dist/chunk-KDZER3PU.cjs.map +0 -1
- package/dist/chunk-N5MKAD7J.cjs.map +0 -1
- package/dist/chunk-QE4VLQYN.cjs.map +0 -1
- package/dist/chunk-R6MO3QIP.js.map +0 -1
- package/dist/chunk-U2ROR6AY.cjs.map +0 -1
- package/dist/chunk-ZP5XRVVH.cjs.map +0 -1
package/dist/admin/index.d.cts
CHANGED
|
@@ -6,8 +6,9 @@ interface AdminLayoutProps {
|
|
|
6
6
|
apiKey?: string;
|
|
7
7
|
apiPath?: string;
|
|
8
8
|
adminPath?: string;
|
|
9
|
+
basePath?: string;
|
|
9
10
|
}
|
|
10
|
-
declare function AdminLayout({ children, apiKey, apiPath, adminPath }: AdminLayoutProps): react_jsx_runtime.JSX.Element;
|
|
11
|
+
declare function AdminLayout({ children, apiKey, apiPath, adminPath, basePath }: AdminLayoutProps): react_jsx_runtime.JSX.Element;
|
|
11
12
|
|
|
12
13
|
declare function Dashboard(): react_jsx_runtime.JSX.Element;
|
|
13
14
|
|
|
@@ -30,10 +31,13 @@ interface SEOPanelProps {
|
|
|
30
31
|
title: string;
|
|
31
32
|
slug: string;
|
|
32
33
|
excerpt: string;
|
|
34
|
+
basePath?: string;
|
|
33
35
|
}
|
|
34
|
-
declare function SEOPanel({ seo, onChange, title, slug, excerpt }: SEOPanelProps): react_jsx_runtime.JSX.Element;
|
|
36
|
+
declare function SEOPanel({ seo, onChange, title, slug, excerpt, basePath }: SEOPanelProps): react_jsx_runtime.JSX.Element;
|
|
35
37
|
|
|
36
38
|
declare function setApiBase(path: string): void;
|
|
39
|
+
declare function setBasePath(path: string): void;
|
|
40
|
+
declare function getBasePath(): string;
|
|
37
41
|
declare function useAdminApi(): {
|
|
38
42
|
get: (path: string) => Promise<any>;
|
|
39
43
|
post: (path: string, body?: unknown) => Promise<any>;
|
|
@@ -41,4 +45,4 @@ declare function useAdminApi(): {
|
|
|
41
45
|
del: (path: string) => Promise<any>;
|
|
42
46
|
};
|
|
43
47
|
|
|
44
|
-
export { AdminLayout, CategoryManager, Dashboard, MediaLibrary, PostEditor, PostList, SEOPanel, SettingsPage, setApiBase, useAdminApi };
|
|
48
|
+
export { AdminLayout, CategoryManager, Dashboard, MediaLibrary, PostEditor, PostList, SEOPanel, SettingsPage, getBasePath, setApiBase, setBasePath, useAdminApi };
|
package/dist/admin/index.d.ts
CHANGED
|
@@ -6,8 +6,9 @@ interface AdminLayoutProps {
|
|
|
6
6
|
apiKey?: string;
|
|
7
7
|
apiPath?: string;
|
|
8
8
|
adminPath?: string;
|
|
9
|
+
basePath?: string;
|
|
9
10
|
}
|
|
10
|
-
declare function AdminLayout({ children, apiKey, apiPath, adminPath }: AdminLayoutProps): react_jsx_runtime.JSX.Element;
|
|
11
|
+
declare function AdminLayout({ children, apiKey, apiPath, adminPath, basePath }: AdminLayoutProps): react_jsx_runtime.JSX.Element;
|
|
11
12
|
|
|
12
13
|
declare function Dashboard(): react_jsx_runtime.JSX.Element;
|
|
13
14
|
|
|
@@ -30,10 +31,13 @@ interface SEOPanelProps {
|
|
|
30
31
|
title: string;
|
|
31
32
|
slug: string;
|
|
32
33
|
excerpt: string;
|
|
34
|
+
basePath?: string;
|
|
33
35
|
}
|
|
34
|
-
declare function SEOPanel({ seo, onChange, title, slug, excerpt }: SEOPanelProps): react_jsx_runtime.JSX.Element;
|
|
36
|
+
declare function SEOPanel({ seo, onChange, title, slug, excerpt, basePath }: SEOPanelProps): react_jsx_runtime.JSX.Element;
|
|
35
37
|
|
|
36
38
|
declare function setApiBase(path: string): void;
|
|
39
|
+
declare function setBasePath(path: string): void;
|
|
40
|
+
declare function getBasePath(): string;
|
|
37
41
|
declare function useAdminApi(): {
|
|
38
42
|
get: (path: string) => Promise<any>;
|
|
39
43
|
post: (path: string, body?: unknown) => Promise<any>;
|
|
@@ -41,4 +45,4 @@ declare function useAdminApi(): {
|
|
|
41
45
|
del: (path: string) => Promise<any>;
|
|
42
46
|
};
|
|
43
47
|
|
|
44
|
-
export { AdminLayout, CategoryManager, Dashboard, MediaLibrary, PostEditor, PostList, SEOPanel, SettingsPage, setApiBase, useAdminApi };
|
|
48
|
+
export { AdminLayout, CategoryManager, Dashboard, MediaLibrary, PostEditor, PostList, SEOPanel, SettingsPage, getBasePath, setApiBase, setBasePath, useAdminApi };
|
package/dist/admin/index.js
CHANGED
|
@@ -21,9 +21,16 @@ import CodeBlockLowlight from '@tiptap/extension-code-block';
|
|
|
21
21
|
|
|
22
22
|
// src/admin/AdminLayout.tsx
|
|
23
23
|
var _apiBase = "/api/blog";
|
|
24
|
+
var _basePath = "/blog";
|
|
24
25
|
function setApiBase(path) {
|
|
25
26
|
_apiBase = path;
|
|
26
27
|
}
|
|
28
|
+
function setBasePath(path) {
|
|
29
|
+
_basePath = path;
|
|
30
|
+
}
|
|
31
|
+
function getBasePath() {
|
|
32
|
+
return _basePath;
|
|
33
|
+
}
|
|
27
34
|
function getApiKey() {
|
|
28
35
|
if (typeof window === "undefined") return "";
|
|
29
36
|
return sessionStorage.getItem("nbk_api_key") || "";
|
|
@@ -84,7 +91,7 @@ function buildNavItems(adminPath) {
|
|
|
84
91
|
{ label: "Settings", href: `${adminPath}/settings`, icon: "\u2699\uFE0F" }
|
|
85
92
|
];
|
|
86
93
|
}
|
|
87
|
-
function AdminLayout({ children, apiKey, apiPath, adminPath = "/admin/blog" }) {
|
|
94
|
+
function AdminLayout({ children, apiKey, apiPath, adminPath = "/admin/blog", basePath = "/blog" }) {
|
|
88
95
|
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
|
89
96
|
const [inputKey, setInputKey] = useState("");
|
|
90
97
|
const [sidebarOpen, setSidebarOpen] = useState(true);
|
|
@@ -93,7 +100,10 @@ function AdminLayout({ children, apiKey, apiPath, adminPath = "/admin/blog" }) {
|
|
|
93
100
|
if (apiPath) {
|
|
94
101
|
setApiBase(apiPath);
|
|
95
102
|
}
|
|
96
|
-
|
|
103
|
+
if (basePath) {
|
|
104
|
+
setBasePath(basePath);
|
|
105
|
+
}
|
|
106
|
+
}, [apiPath, basePath]);
|
|
97
107
|
useEffect(() => {
|
|
98
108
|
if (typeof window !== "undefined") {
|
|
99
109
|
setCurrentPath(window.location.pathname);
|
|
@@ -431,7 +441,7 @@ function PostList() {
|
|
|
431
441
|
/* @__PURE__ */ jsx(
|
|
432
442
|
"a",
|
|
433
443
|
{
|
|
434
|
-
href:
|
|
444
|
+
href: `${getBasePath()}/${post.slug}`,
|
|
435
445
|
target: "_blank",
|
|
436
446
|
rel: "noopener noreferrer",
|
|
437
447
|
className: "nbk-btn nbk-btn-sm",
|
|
@@ -979,6 +989,7 @@ function BlogEditor({
|
|
|
979
989
|
const lastSavedRef = useRef("");
|
|
980
990
|
const defaultUpload = useCallback(async (file) => {
|
|
981
991
|
if (!uploadImage) {
|
|
992
|
+
console.warn("[NextBlogKit] No uploadImage handler provided. Using blob URL \u2014 image will not persist across page reloads. Configure Cloudflare R2 for persistent image storage.");
|
|
982
993
|
return { url: URL.createObjectURL(file), alt: file.name };
|
|
983
994
|
}
|
|
984
995
|
return uploadImage(file);
|
|
@@ -1432,7 +1443,7 @@ function stripTags(html) {
|
|
|
1432
1443
|
function slugify(text) {
|
|
1433
1444
|
return text.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_]+/g, "-").replace(/-+/g, "-");
|
|
1434
1445
|
}
|
|
1435
|
-
function SEOPanel({ seo, onChange, title, slug, excerpt }) {
|
|
1446
|
+
function SEOPanel({ seo, onChange, title, slug, excerpt, basePath = "/blog" }) {
|
|
1436
1447
|
const metaTitle = seo.metaTitle || "";
|
|
1437
1448
|
const metaDescription = seo.metaDescription || "";
|
|
1438
1449
|
const focusKeyword = seo.focusKeyword || "";
|
|
@@ -1441,7 +1452,7 @@ function SEOPanel({ seo, onChange, title, slug, excerpt }) {
|
|
|
1441
1452
|
const noIndex = seo.noIndex || false;
|
|
1442
1453
|
const displayTitle = metaTitle || title || "Post Title";
|
|
1443
1454
|
const displayDesc = metaDescription || excerpt || "Post description will appear here...";
|
|
1444
|
-
const displayUrl =
|
|
1455
|
+
const displayUrl = `${basePath}/${slug || "post-url"}`;
|
|
1445
1456
|
const titleLength = displayTitle.length;
|
|
1446
1457
|
const descLength = displayDesc.length;
|
|
1447
1458
|
const titleColor = titleLength >= 50 && titleLength <= 60 ? "nbk-count-good" : titleLength > 70 ? "nbk-count-bad" : "nbk-count-warn";
|
|
@@ -1653,10 +1664,20 @@ function PostEditor({ postId }) {
|
|
|
1653
1664
|
[postId]
|
|
1654
1665
|
);
|
|
1655
1666
|
const uploadImage = async (file) => {
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1667
|
+
try {
|
|
1668
|
+
const formData = new FormData();
|
|
1669
|
+
formData.append("file", file);
|
|
1670
|
+
const res = await api.post("/media", formData);
|
|
1671
|
+
return { url: res.data.url, alt: res.data.alt || file.name };
|
|
1672
|
+
} catch (err) {
|
|
1673
|
+
const msg = err.message || "Upload failed";
|
|
1674
|
+
if (msg.includes("R2") || msg.includes("STORAGE_NOT_CONFIGURED")) {
|
|
1675
|
+
setError("Image upload requires Cloudflare R2 configuration. Set R2 environment variables or use an external image URL instead.");
|
|
1676
|
+
} else {
|
|
1677
|
+
setError(msg);
|
|
1678
|
+
}
|
|
1679
|
+
throw err;
|
|
1680
|
+
}
|
|
1660
1681
|
};
|
|
1661
1682
|
if (loading) {
|
|
1662
1683
|
return /* @__PURE__ */ jsxs("div", { className: "nbk-post-editor", children: [
|
|
@@ -1878,7 +1899,8 @@ function PostEditor({ postId }) {
|
|
|
1878
1899
|
onChange: setSeo,
|
|
1879
1900
|
title,
|
|
1880
1901
|
slug,
|
|
1881
|
-
excerpt
|
|
1902
|
+
excerpt,
|
|
1903
|
+
basePath: getBasePath()
|
|
1882
1904
|
}
|
|
1883
1905
|
)
|
|
1884
1906
|
] })
|
|
@@ -2237,6 +2259,333 @@ function CategoryManager() {
|
|
|
2237
2259
|
] })
|
|
2238
2260
|
] });
|
|
2239
2261
|
}
|
|
2262
|
+
function ApiTokensSection() {
|
|
2263
|
+
const api = useAdminApi();
|
|
2264
|
+
const [tokens, setTokens] = useState([]);
|
|
2265
|
+
const [loading, setLoading] = useState(true);
|
|
2266
|
+
const [tokenName, setTokenName] = useState("");
|
|
2267
|
+
const [generating, setGenerating] = useState(false);
|
|
2268
|
+
const [newToken, setNewToken] = useState("");
|
|
2269
|
+
const [copied, setCopied] = useState(false);
|
|
2270
|
+
const [error, setError] = useState("");
|
|
2271
|
+
const [showDialog, setShowDialog] = useState(false);
|
|
2272
|
+
const [revoking, setRevoking] = useState(null);
|
|
2273
|
+
const fetchTokens = useCallback(async () => {
|
|
2274
|
+
try {
|
|
2275
|
+
const res = await api.get("/tokens");
|
|
2276
|
+
setTokens(res.data || []);
|
|
2277
|
+
} catch (err) {
|
|
2278
|
+
setError(err.message || "Failed to load tokens");
|
|
2279
|
+
} finally {
|
|
2280
|
+
setLoading(false);
|
|
2281
|
+
}
|
|
2282
|
+
}, []);
|
|
2283
|
+
useEffect(() => {
|
|
2284
|
+
fetchTokens();
|
|
2285
|
+
}, [fetchTokens]);
|
|
2286
|
+
const handleGenerate = async () => {
|
|
2287
|
+
if (!tokenName.trim()) return;
|
|
2288
|
+
setGenerating(true);
|
|
2289
|
+
setError("");
|
|
2290
|
+
try {
|
|
2291
|
+
const res = await api.post("/tokens", { name: tokenName.trim() });
|
|
2292
|
+
setNewToken(res.data.plainToken);
|
|
2293
|
+
setTokenName("");
|
|
2294
|
+
fetchTokens();
|
|
2295
|
+
} catch (err) {
|
|
2296
|
+
setError(err.message || "Failed to generate token");
|
|
2297
|
+
} finally {
|
|
2298
|
+
setGenerating(false);
|
|
2299
|
+
}
|
|
2300
|
+
};
|
|
2301
|
+
const handleRevoke = async (id) => {
|
|
2302
|
+
if (!confirm("Are you sure you want to revoke this token? Any integrations using it will stop working.")) return;
|
|
2303
|
+
setRevoking(id);
|
|
2304
|
+
setError("");
|
|
2305
|
+
try {
|
|
2306
|
+
await api.del(`/tokens?id=${id}`);
|
|
2307
|
+
setTokens((prev) => prev.filter((t) => t._id !== id));
|
|
2308
|
+
} catch (err) {
|
|
2309
|
+
setError(err.message || "Failed to revoke token");
|
|
2310
|
+
} finally {
|
|
2311
|
+
setRevoking(null);
|
|
2312
|
+
}
|
|
2313
|
+
};
|
|
2314
|
+
const copyToken = () => {
|
|
2315
|
+
navigator.clipboard.writeText(newToken);
|
|
2316
|
+
setCopied(true);
|
|
2317
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
2318
|
+
};
|
|
2319
|
+
const formatDate = (d) => {
|
|
2320
|
+
if (!d) return "Never";
|
|
2321
|
+
return new Date(d).toLocaleDateString("en-US", {
|
|
2322
|
+
month: "short",
|
|
2323
|
+
day: "numeric",
|
|
2324
|
+
year: "numeric",
|
|
2325
|
+
hour: "2-digit",
|
|
2326
|
+
minute: "2-digit"
|
|
2327
|
+
});
|
|
2328
|
+
};
|
|
2329
|
+
return /* @__PURE__ */ jsxs("div", { className: "nbk-settings-section", children: [
|
|
2330
|
+
/* @__PURE__ */ jsx("h2", { className: "nbk-section-title", children: "API Tokens" }),
|
|
2331
|
+
/* @__PURE__ */ jsx("p", { style: { color: "var(--nbk-text-muted)", fontSize: "0.875rem", marginBottom: "1rem" }, children: "Generate tokens for external services (CI pipelines, automation tools, CMS integrations). Tokens can access the API like the master key but cannot manage other tokens." }),
|
|
2332
|
+
error && /* @__PURE__ */ jsx("div", { className: "nbk-error", style: { marginBottom: "1rem" }, children: error }),
|
|
2333
|
+
newToken && /* @__PURE__ */ jsxs("div", { style: {
|
|
2334
|
+
background: "var(--nbk-bg-secondary)",
|
|
2335
|
+
border: "1px solid var(--nbk-warning, #f59e0b)",
|
|
2336
|
+
borderRadius: "var(--nbk-radius)",
|
|
2337
|
+
padding: "1rem",
|
|
2338
|
+
marginBottom: "1rem"
|
|
2339
|
+
}, children: [
|
|
2340
|
+
/* @__PURE__ */ jsx("div", { style: { fontWeight: 600, marginBottom: "0.5rem", color: "var(--nbk-warning, #f59e0b)" }, children: "Save this token \u2014 it will only be shown once" }),
|
|
2341
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "0.5rem", alignItems: "center" }, children: [
|
|
2342
|
+
/* @__PURE__ */ jsx("code", { style: {
|
|
2343
|
+
flex: 1,
|
|
2344
|
+
background: "var(--nbk-bg)",
|
|
2345
|
+
padding: "0.5rem 0.75rem",
|
|
2346
|
+
borderRadius: "var(--nbk-radius)",
|
|
2347
|
+
border: "1px solid var(--nbk-border)",
|
|
2348
|
+
fontSize: "0.813rem",
|
|
2349
|
+
fontFamily: "var(--nbk-font-code)",
|
|
2350
|
+
wordBreak: "break-all"
|
|
2351
|
+
}, children: newToken }),
|
|
2352
|
+
/* @__PURE__ */ jsx("button", { onClick: copyToken, className: "nbk-btn nbk-btn-primary", style: { whiteSpace: "nowrap" }, children: copied ? "Copied!" : "Copy" })
|
|
2353
|
+
] }),
|
|
2354
|
+
/* @__PURE__ */ jsx(
|
|
2355
|
+
"button",
|
|
2356
|
+
{
|
|
2357
|
+
onClick: () => setNewToken(""),
|
|
2358
|
+
style: {
|
|
2359
|
+
marginTop: "0.5rem",
|
|
2360
|
+
background: "none",
|
|
2361
|
+
border: "none",
|
|
2362
|
+
color: "var(--nbk-text-muted)",
|
|
2363
|
+
cursor: "pointer",
|
|
2364
|
+
fontSize: "0.813rem",
|
|
2365
|
+
padding: 0
|
|
2366
|
+
},
|
|
2367
|
+
children: "Dismiss"
|
|
2368
|
+
}
|
|
2369
|
+
)
|
|
2370
|
+
] }),
|
|
2371
|
+
!showDialog ? /* @__PURE__ */ jsx("button", { onClick: () => setShowDialog(true), className: "nbk-btn nbk-btn-primary", style: { marginBottom: "1rem" }, children: "Generate New Token" }) : /* @__PURE__ */ jsxs("div", { style: {
|
|
2372
|
+
display: "flex",
|
|
2373
|
+
gap: "0.5rem",
|
|
2374
|
+
marginBottom: "1rem",
|
|
2375
|
+
alignItems: "flex-end"
|
|
2376
|
+
}, children: [
|
|
2377
|
+
/* @__PURE__ */ jsxs("div", { style: { flex: 1 }, children: [
|
|
2378
|
+
/* @__PURE__ */ jsx("label", { className: "nbk-label", children: "Token Name" }),
|
|
2379
|
+
/* @__PURE__ */ jsx(
|
|
2380
|
+
"input",
|
|
2381
|
+
{
|
|
2382
|
+
type: "text",
|
|
2383
|
+
value: tokenName,
|
|
2384
|
+
onChange: (e) => setTokenName(e.target.value),
|
|
2385
|
+
className: "nbk-input",
|
|
2386
|
+
placeholder: "e.g. CI Pipeline, n8n Automation",
|
|
2387
|
+
onKeyDown: (e) => e.key === "Enter" && handleGenerate(),
|
|
2388
|
+
autoFocus: true
|
|
2389
|
+
}
|
|
2390
|
+
)
|
|
2391
|
+
] }),
|
|
2392
|
+
/* @__PURE__ */ jsx("button", { onClick: handleGenerate, className: "nbk-btn nbk-btn-primary", disabled: generating || !tokenName.trim(), children: generating ? "Generating..." : "Generate" }),
|
|
2393
|
+
/* @__PURE__ */ jsx(
|
|
2394
|
+
"button",
|
|
2395
|
+
{
|
|
2396
|
+
onClick: () => {
|
|
2397
|
+
setShowDialog(false);
|
|
2398
|
+
setTokenName("");
|
|
2399
|
+
},
|
|
2400
|
+
className: "nbk-btn",
|
|
2401
|
+
style: { background: "var(--nbk-bg-secondary)", border: "1px solid var(--nbk-border)" },
|
|
2402
|
+
children: "Cancel"
|
|
2403
|
+
}
|
|
2404
|
+
)
|
|
2405
|
+
] }),
|
|
2406
|
+
loading ? /* @__PURE__ */ jsx("div", { style: { color: "var(--nbk-text-muted)" }, children: "Loading tokens..." }) : tokens.length === 0 ? /* @__PURE__ */ jsx("div", { style: { color: "var(--nbk-text-muted)", fontSize: "0.875rem" }, children: "No API tokens generated yet." }) : /* @__PURE__ */ jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxs("table", { style: {
|
|
2407
|
+
width: "100%",
|
|
2408
|
+
borderCollapse: "collapse",
|
|
2409
|
+
fontSize: "0.875rem"
|
|
2410
|
+
}, children: [
|
|
2411
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { style: { borderBottom: "2px solid var(--nbk-border)" }, children: [
|
|
2412
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "0.5rem 0.75rem", fontWeight: 600 }, children: "Name" }),
|
|
2413
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "0.5rem 0.75rem", fontWeight: 600 }, children: "Key Prefix" }),
|
|
2414
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "0.5rem 0.75rem", fontWeight: 600 }, children: "Last Used" }),
|
|
2415
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "0.5rem 0.75rem", fontWeight: 600 }, children: "Created" }),
|
|
2416
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "right", padding: "0.5rem 0.75rem", fontWeight: 600 } })
|
|
2417
|
+
] }) }),
|
|
2418
|
+
/* @__PURE__ */ jsx("tbody", { children: tokens.map((t) => /* @__PURE__ */ jsxs("tr", { style: { borderBottom: "1px solid var(--nbk-border)" }, children: [
|
|
2419
|
+
/* @__PURE__ */ jsx("td", { style: { padding: "0.5rem 0.75rem" }, children: t.name }),
|
|
2420
|
+
/* @__PURE__ */ jsx("td", { style: { padding: "0.5rem 0.75rem" }, children: /* @__PURE__ */ jsxs("code", { style: { fontFamily: "var(--nbk-font-code)", fontSize: "0.813rem" }, children: [
|
|
2421
|
+
t.prefix,
|
|
2422
|
+
"..."
|
|
2423
|
+
] }) }),
|
|
2424
|
+
/* @__PURE__ */ jsx("td", { style: { padding: "0.5rem 0.75rem", color: "var(--nbk-text-muted)" }, children: formatDate(t.lastUsedAt) }),
|
|
2425
|
+
/* @__PURE__ */ jsx("td", { style: { padding: "0.5rem 0.75rem", color: "var(--nbk-text-muted)" }, children: formatDate(t.createdAt) }),
|
|
2426
|
+
/* @__PURE__ */ jsx("td", { style: { padding: "0.5rem 0.75rem", textAlign: "right" }, children: /* @__PURE__ */ jsx(
|
|
2427
|
+
"button",
|
|
2428
|
+
{
|
|
2429
|
+
onClick: () => handleRevoke(t._id),
|
|
2430
|
+
disabled: revoking === t._id,
|
|
2431
|
+
style: {
|
|
2432
|
+
background: "none",
|
|
2433
|
+
border: "1px solid var(--nbk-danger, #ef4444)",
|
|
2434
|
+
color: "var(--nbk-danger, #ef4444)",
|
|
2435
|
+
padding: "0.25rem 0.75rem",
|
|
2436
|
+
borderRadius: "var(--nbk-radius)",
|
|
2437
|
+
cursor: "pointer",
|
|
2438
|
+
fontSize: "0.813rem"
|
|
2439
|
+
},
|
|
2440
|
+
children: revoking === t._id ? "Revoking..." : "Revoke"
|
|
2441
|
+
}
|
|
2442
|
+
) })
|
|
2443
|
+
] }, t._id)) })
|
|
2444
|
+
] }) })
|
|
2445
|
+
] });
|
|
2446
|
+
}
|
|
2447
|
+
function ApiReferenceSection() {
|
|
2448
|
+
const [open, setOpen] = useState(false);
|
|
2449
|
+
const [copiedCurl, setCopiedCurl] = useState(false);
|
|
2450
|
+
const [copiedJson, setCopiedJson] = useState(false);
|
|
2451
|
+
const sampleJson = `{
|
|
2452
|
+
"title": "My Blog Post",
|
|
2453
|
+
"content": [{ "type": "paragraph", "content": [{ "type": "text", "text": "Hello world!" }] }],
|
|
2454
|
+
"contentHTML": "<p>Hello world!</p>",
|
|
2455
|
+
"excerpt": "A short summary of the post",
|
|
2456
|
+
"status": "published",
|
|
2457
|
+
"categories": ["tech"],
|
|
2458
|
+
"tags": ["nextjs", "blog"],
|
|
2459
|
+
"author": {
|
|
2460
|
+
"name": "John Doe",
|
|
2461
|
+
"bio": "Software engineer",
|
|
2462
|
+
"avatar": "https://example.com/avatar.jpg"
|
|
2463
|
+
},
|
|
2464
|
+
"seo": {
|
|
2465
|
+
"metaTitle": "My Blog Post | MySite",
|
|
2466
|
+
"metaDescription": "A short summary for search engines",
|
|
2467
|
+
"focusKeyword": "blog post"
|
|
2468
|
+
}
|
|
2469
|
+
}`;
|
|
2470
|
+
const sampleCurl = `curl -X POST https://yoursite.com/api/blog/posts \\
|
|
2471
|
+
-H "Authorization: Bearer nbk_your-token-here" \\
|
|
2472
|
+
-H "Content-Type: application/json" \\
|
|
2473
|
+
-d '{ "title": "My Post", "content": [{"type":"paragraph","content":[{"type":"text","text":"Hello!"}]}], "contentHTML": "<p>Hello!</p>", "status": "published" }'`;
|
|
2474
|
+
const copyText = (text, setCopied) => {
|
|
2475
|
+
navigator.clipboard.writeText(text);
|
|
2476
|
+
setCopied(true);
|
|
2477
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
2478
|
+
};
|
|
2479
|
+
return /* @__PURE__ */ jsxs("div", { className: "nbk-settings-section", children: [
|
|
2480
|
+
/* @__PURE__ */ jsxs(
|
|
2481
|
+
"h2",
|
|
2482
|
+
{
|
|
2483
|
+
className: "nbk-section-title",
|
|
2484
|
+
onClick: () => setOpen(!open),
|
|
2485
|
+
style: { cursor: "pointer", userSelect: "none", display: "flex", alignItems: "center", gap: "0.5rem" },
|
|
2486
|
+
children: [
|
|
2487
|
+
/* @__PURE__ */ jsx("span", { style: { transform: open ? "rotate(90deg)" : "rotate(0deg)", transition: "transform 0.2s", display: "inline-block" }, children: "\u25B6" }),
|
|
2488
|
+
"API Reference"
|
|
2489
|
+
]
|
|
2490
|
+
}
|
|
2491
|
+
),
|
|
2492
|
+
open && /* @__PURE__ */ jsxs("div", { style: { marginTop: "1rem" }, children: [
|
|
2493
|
+
/* @__PURE__ */ jsx("h3", { style: { fontSize: "0.938rem", fontWeight: 600, marginBottom: "0.75rem" }, children: "Create Post \u2014 POST /api/blog/posts" }),
|
|
2494
|
+
/* @__PURE__ */ jsxs("div", { style: { marginBottom: "1rem" }, children: [
|
|
2495
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "0.25rem" }, children: [
|
|
2496
|
+
/* @__PURE__ */ jsx("span", { style: { fontSize: "0.813rem", fontWeight: 600, color: "var(--nbk-text-muted)" }, children: "Sample JSON Body" }),
|
|
2497
|
+
/* @__PURE__ */ jsx(
|
|
2498
|
+
"button",
|
|
2499
|
+
{
|
|
2500
|
+
onClick: () => copyText(sampleJson, setCopiedJson),
|
|
2501
|
+
style: {
|
|
2502
|
+
background: "none",
|
|
2503
|
+
border: "1px solid var(--nbk-border)",
|
|
2504
|
+
borderRadius: "var(--nbk-radius)",
|
|
2505
|
+
padding: "0.125rem 0.5rem",
|
|
2506
|
+
cursor: "pointer",
|
|
2507
|
+
fontSize: "0.75rem",
|
|
2508
|
+
color: "var(--nbk-text-muted)"
|
|
2509
|
+
},
|
|
2510
|
+
children: copiedJson ? "Copied!" : "Copy"
|
|
2511
|
+
}
|
|
2512
|
+
)
|
|
2513
|
+
] }),
|
|
2514
|
+
/* @__PURE__ */ jsx("pre", { style: {
|
|
2515
|
+
background: "var(--nbk-bg-secondary)",
|
|
2516
|
+
border: "1px solid var(--nbk-border)",
|
|
2517
|
+
borderRadius: "var(--nbk-radius)",
|
|
2518
|
+
padding: "0.75rem",
|
|
2519
|
+
overflow: "auto",
|
|
2520
|
+
fontSize: "0.813rem",
|
|
2521
|
+
fontFamily: "var(--nbk-font-code)",
|
|
2522
|
+
lineHeight: 1.5,
|
|
2523
|
+
maxHeight: "400px"
|
|
2524
|
+
}, children: sampleJson })
|
|
2525
|
+
] }),
|
|
2526
|
+
/* @__PURE__ */ jsxs("div", { style: { marginBottom: "1rem" }, children: [
|
|
2527
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "0.25rem" }, children: [
|
|
2528
|
+
/* @__PURE__ */ jsx("span", { style: { fontSize: "0.813rem", fontWeight: 600, color: "var(--nbk-text-muted)" }, children: "Sample curl Command" }),
|
|
2529
|
+
/* @__PURE__ */ jsx(
|
|
2530
|
+
"button",
|
|
2531
|
+
{
|
|
2532
|
+
onClick: () => copyText(sampleCurl, setCopiedCurl),
|
|
2533
|
+
style: {
|
|
2534
|
+
background: "none",
|
|
2535
|
+
border: "1px solid var(--nbk-border)",
|
|
2536
|
+
borderRadius: "var(--nbk-radius)",
|
|
2537
|
+
padding: "0.125rem 0.5rem",
|
|
2538
|
+
cursor: "pointer",
|
|
2539
|
+
fontSize: "0.75rem",
|
|
2540
|
+
color: "var(--nbk-text-muted)"
|
|
2541
|
+
},
|
|
2542
|
+
children: copiedCurl ? "Copied!" : "Copy"
|
|
2543
|
+
}
|
|
2544
|
+
)
|
|
2545
|
+
] }),
|
|
2546
|
+
/* @__PURE__ */ jsx("pre", { style: {
|
|
2547
|
+
background: "var(--nbk-bg-secondary)",
|
|
2548
|
+
border: "1px solid var(--nbk-border)",
|
|
2549
|
+
borderRadius: "var(--nbk-radius)",
|
|
2550
|
+
padding: "0.75rem",
|
|
2551
|
+
overflow: "auto",
|
|
2552
|
+
fontSize: "0.813rem",
|
|
2553
|
+
fontFamily: "var(--nbk-font-code)",
|
|
2554
|
+
lineHeight: 1.5
|
|
2555
|
+
}, children: sampleCurl })
|
|
2556
|
+
] }),
|
|
2557
|
+
/* @__PURE__ */ jsx("h3", { style: { fontSize: "0.938rem", fontWeight: 600, marginBottom: "0.75rem" }, children: "Field Reference" }),
|
|
2558
|
+
/* @__PURE__ */ jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxs("table", { style: { width: "100%", borderCollapse: "collapse", fontSize: "0.813rem" }, children: [
|
|
2559
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { style: { borderBottom: "2px solid var(--nbk-border)" }, children: [
|
|
2560
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "0.5rem 0.75rem", fontWeight: 600 }, children: "Field" }),
|
|
2561
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "0.5rem 0.75rem", fontWeight: 600 }, children: "Type" }),
|
|
2562
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "0.5rem 0.75rem", fontWeight: 600 }, children: "Required" }),
|
|
2563
|
+
/* @__PURE__ */ jsx("th", { style: { textAlign: "left", padding: "0.5rem 0.75rem", fontWeight: 600 }, children: "Description" })
|
|
2564
|
+
] }) }),
|
|
2565
|
+
/* @__PURE__ */ jsx("tbody", { children: [
|
|
2566
|
+
["title", "string", "Yes", "Post title"],
|
|
2567
|
+
["content", "BlockContent[]", "No", "TipTap JSON content blocks"],
|
|
2568
|
+
["contentHTML", "string", "No", "HTML version of the content"],
|
|
2569
|
+
["excerpt", "string", "No", "Short summary (auto-generated if omitted)"],
|
|
2570
|
+
["slug", "string", "No", "URL slug (auto-generated from title if omitted)"],
|
|
2571
|
+
["status", '"draft" | "published" | "scheduled"', "No", 'Defaults to "draft"'],
|
|
2572
|
+
["categories", "string[]", "No", "Category slugs"],
|
|
2573
|
+
["tags", "string[]", "No", "Tag strings"],
|
|
2574
|
+
["author", "{ name, bio?, avatar?, url? }", "No", "Post author info"],
|
|
2575
|
+
["seo", "{ metaTitle?, metaDescription?, focusKeyword?, ... }", "No", "SEO metadata"],
|
|
2576
|
+
["coverImage", "{ _id, url, alt?, caption? }", "No", "Cover image reference"],
|
|
2577
|
+
["publishedAt", "ISO date string", "No", 'Publish date (auto-set when status is "published")'],
|
|
2578
|
+
["scheduledAt", "ISO date string", "No", "Schedule date for future publishing"]
|
|
2579
|
+
].map(([field, type, required, desc]) => /* @__PURE__ */ jsxs("tr", { style: { borderBottom: "1px solid var(--nbk-border)" }, children: [
|
|
2580
|
+
/* @__PURE__ */ jsx("td", { style: { padding: "0.5rem 0.75rem" }, children: /* @__PURE__ */ jsx("code", { style: { fontFamily: "var(--nbk-font-code)", fontSize: "0.813rem" }, children: field }) }),
|
|
2581
|
+
/* @__PURE__ */ jsx("td", { style: { padding: "0.5rem 0.75rem", color: "var(--nbk-text-muted)" }, children: type }),
|
|
2582
|
+
/* @__PURE__ */ jsx("td", { style: { padding: "0.5rem 0.75rem" }, children: required }),
|
|
2583
|
+
/* @__PURE__ */ jsx("td", { style: { padding: "0.5rem 0.75rem", color: "var(--nbk-text-muted)" }, children: desc })
|
|
2584
|
+
] }, field)) })
|
|
2585
|
+
] }) })
|
|
2586
|
+
] })
|
|
2587
|
+
] });
|
|
2588
|
+
}
|
|
2240
2589
|
function SettingsPage() {
|
|
2241
2590
|
const api = useAdminApi();
|
|
2242
2591
|
const [settings, setSettings] = useState({});
|
|
@@ -2429,10 +2778,15 @@ function SettingsPage() {
|
|
|
2429
2778
|
placeholder: "/* Custom CSS styles */"
|
|
2430
2779
|
}
|
|
2431
2780
|
) })
|
|
2781
|
+
] }),
|
|
2782
|
+
/* @__PURE__ */ jsxs("div", { style: { marginTop: "2rem" }, children: [
|
|
2783
|
+
/* @__PURE__ */ jsx("h2", { className: "nbk-page-title", style: { fontSize: "1.25rem", marginBottom: "1rem" }, children: "API Access" }),
|
|
2784
|
+
/* @__PURE__ */ jsx(ApiTokensSection, {}),
|
|
2785
|
+
/* @__PURE__ */ jsx(ApiReferenceSection, {})
|
|
2432
2786
|
] })
|
|
2433
2787
|
] });
|
|
2434
2788
|
}
|
|
2435
2789
|
|
|
2436
|
-
export { AdminLayout, CategoryManager, Dashboard, MediaLibrary, PostEditor, PostList, SEOPanel, SettingsPage, setApiBase, useAdminApi };
|
|
2790
|
+
export { AdminLayout, CategoryManager, Dashboard, MediaLibrary, PostEditor, PostList, SEOPanel, SettingsPage, getBasePath, setApiBase, setBasePath, useAdminApi };
|
|
2437
2791
|
//# sourceMappingURL=index.js.map
|
|
2438
2792
|
//# sourceMappingURL=index.js.map
|