nextblogkit 0.6.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.
Files changed (107) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +951 -0
  3. package/dist/admin/index.cjs +2465 -0
  4. package/dist/admin/index.cjs.map +1 -0
  5. package/dist/admin/index.d.cts +44 -0
  6. package/dist/admin/index.d.ts +44 -0
  7. package/dist/admin/index.js +2438 -0
  8. package/dist/admin/index.js.map +1 -0
  9. package/dist/api/categories.cjs +82 -0
  10. package/dist/api/categories.cjs.map +1 -0
  11. package/dist/api/categories.d.cts +27 -0
  12. package/dist/api/categories.d.ts +27 -0
  13. package/dist/api/categories.js +77 -0
  14. package/dist/api/categories.js.map +1 -0
  15. package/dist/api/media.cjs +113 -0
  16. package/dist/api/media.cjs.map +1 -0
  17. package/dist/api/media.d.cts +22 -0
  18. package/dist/api/media.d.ts +22 -0
  19. package/dist/api/media.js +109 -0
  20. package/dist/api/media.js.map +1 -0
  21. package/dist/api/posts.cjs +103 -0
  22. package/dist/api/posts.cjs.map +1 -0
  23. package/dist/api/posts.d.cts +27 -0
  24. package/dist/api/posts.d.ts +27 -0
  25. package/dist/api/posts.js +98 -0
  26. package/dist/api/posts.js.map +1 -0
  27. package/dist/api/rss.cjs +25 -0
  28. package/dist/api/rss.cjs.map +1 -0
  29. package/dist/api/rss.d.cts +5 -0
  30. package/dist/api/rss.d.ts +5 -0
  31. package/dist/api/rss.js +23 -0
  32. package/dist/api/rss.js.map +1 -0
  33. package/dist/api/settings.cjs +40 -0
  34. package/dist/api/settings.cjs.map +1 -0
  35. package/dist/api/settings.d.cts +17 -0
  36. package/dist/api/settings.d.ts +17 -0
  37. package/dist/api/settings.js +37 -0
  38. package/dist/api/settings.js.map +1 -0
  39. package/dist/api/sitemap.cjs +25 -0
  40. package/dist/api/sitemap.cjs.map +1 -0
  41. package/dist/api/sitemap.d.cts +5 -0
  42. package/dist/api/sitemap.d.ts +5 -0
  43. package/dist/api/sitemap.js +23 -0
  44. package/dist/api/sitemap.js.map +1 -0
  45. package/dist/chunk-4NKOJYWJ.js +68 -0
  46. package/dist/chunk-4NKOJYWJ.js.map +1 -0
  47. package/dist/chunk-4PY224XM.js +103 -0
  48. package/dist/chunk-4PY224XM.js.map +1 -0
  49. package/dist/chunk-64HUVJOZ.js +446 -0
  50. package/dist/chunk-64HUVJOZ.js.map +1 -0
  51. package/dist/chunk-6HKMZOI4.cjs +48 -0
  52. package/dist/chunk-6HKMZOI4.cjs.map +1 -0
  53. package/dist/chunk-A2S32RZN.js +138 -0
  54. package/dist/chunk-A2S32RZN.js.map +1 -0
  55. package/dist/chunk-E2QLTHKN.cjs +70 -0
  56. package/dist/chunk-E2QLTHKN.cjs.map +1 -0
  57. package/dist/chunk-JLPJKNRZ.js +37 -0
  58. package/dist/chunk-JLPJKNRZ.js.map +1 -0
  59. package/dist/chunk-JM7QRXXK.js +330 -0
  60. package/dist/chunk-JM7QRXXK.js.map +1 -0
  61. package/dist/chunk-KDZER3PU.cjs +43 -0
  62. package/dist/chunk-KDZER3PU.cjs.map +1 -0
  63. package/dist/chunk-N5MKAD7J.cjs +109 -0
  64. package/dist/chunk-N5MKAD7J.cjs.map +1 -0
  65. package/dist/chunk-QE4VLQYN.cjs +337 -0
  66. package/dist/chunk-QE4VLQYN.cjs.map +1 -0
  67. package/dist/chunk-R6MO3QIP.js +46 -0
  68. package/dist/chunk-R6MO3QIP.js.map +1 -0
  69. package/dist/chunk-U2ROR6AY.cjs +476 -0
  70. package/dist/chunk-U2ROR6AY.cjs.map +1 -0
  71. package/dist/chunk-ZP5XRVVH.cjs +141 -0
  72. package/dist/chunk-ZP5XRVVH.cjs.map +1 -0
  73. package/dist/cli/index.cjs +1308 -0
  74. package/dist/components/index.cjs +541 -0
  75. package/dist/components/index.cjs.map +1 -0
  76. package/dist/components/index.d.cts +165 -0
  77. package/dist/components/index.d.ts +165 -0
  78. package/dist/components/index.js +527 -0
  79. package/dist/components/index.js.map +1 -0
  80. package/dist/editor/index.cjs +1083 -0
  81. package/dist/editor/index.cjs.map +1 -0
  82. package/dist/editor/index.d.cts +133 -0
  83. package/dist/editor/index.d.ts +133 -0
  84. package/dist/editor/index.js +1051 -0
  85. package/dist/editor/index.js.map +1 -0
  86. package/dist/index-Cgzphklp.d.ts +266 -0
  87. package/dist/index-vjlZDWNr.d.cts +266 -0
  88. package/dist/index.cjs +368 -0
  89. package/dist/index.cjs.map +1 -0
  90. package/dist/index.d.cts +27 -0
  91. package/dist/index.d.ts +27 -0
  92. package/dist/index.js +208 -0
  93. package/dist/index.js.map +1 -0
  94. package/dist/lib/index.cjs +120 -0
  95. package/dist/lib/index.cjs.map +1 -0
  96. package/dist/lib/index.d.cts +4 -0
  97. package/dist/lib/index.d.ts +4 -0
  98. package/dist/lib/index.js +7 -0
  99. package/dist/lib/index.js.map +1 -0
  100. package/dist/styles/admin.css +657 -0
  101. package/dist/styles/blog.css +851 -0
  102. package/dist/styles/editor.css +452 -0
  103. package/dist/styles/globals.css +270 -0
  104. package/dist/styles/prose.css +299 -0
  105. package/dist/types-CBEEBR4A.d.cts +732 -0
  106. package/dist/types-CBEEBR4A.d.ts +732 -0
  107. package/package.json +134 -0
@@ -0,0 +1,541 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var react = require('react');
6
+
7
+ // src/components/BlogCard.tsx
8
+ function BlogCard({
9
+ post,
10
+ layout = "vertical",
11
+ basePath = "/blog",
12
+ className = ""
13
+ }) {
14
+ const date = post.publishedAt ? new Date(post.publishedAt).toLocaleDateString("en-US", {
15
+ year: "numeric",
16
+ month: "long",
17
+ day: "numeric"
18
+ }) : "";
19
+ return /* @__PURE__ */ jsxRuntime.jsx("article", { className: `nbk-card nbk-card-${layout} ${className}`, children: /* @__PURE__ */ jsxRuntime.jsxs("a", { href: `${basePath}/${post.slug}`, className: "nbk-card-link", children: [
20
+ post.coverImage?.url && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nbk-card-image", children: /* @__PURE__ */ jsxRuntime.jsx(
21
+ "img",
22
+ {
23
+ src: post.coverImage.url,
24
+ alt: post.coverImage.alt || post.title,
25
+ loading: "lazy"
26
+ }
27
+ ) }),
28
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nbk-card-content", children: [
29
+ post.categories.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nbk-card-categories", children: post.categories.map((cat) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nbk-card-category", children: cat }, cat)) }),
30
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "nbk-card-title", children: post.title }),
31
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "nbk-card-excerpt", children: post.excerpt }),
32
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nbk-card-meta", children: [
33
+ post.author.avatar && /* @__PURE__ */ jsxRuntime.jsx(
34
+ "img",
35
+ {
36
+ src: post.author.avatar,
37
+ alt: post.author.name,
38
+ className: "nbk-card-avatar"
39
+ }
40
+ ),
41
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nbk-card-author", children: post.author.name }),
42
+ date && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
43
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nbk-card-sep", children: "\xB7" }),
44
+ /* @__PURE__ */ jsxRuntime.jsx("time", { className: "nbk-card-date", children: date })
45
+ ] }),
46
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nbk-card-sep", children: "\xB7" }),
47
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "nbk-card-reading-time", children: [
48
+ post.readingTime,
49
+ " min read"
50
+ ] })
51
+ ] })
52
+ ] })
53
+ ] }) });
54
+ }
55
+ function BlogSearch({
56
+ onSearch,
57
+ apiPath = "/api/blog",
58
+ placeholder = "Search posts...",
59
+ className = ""
60
+ }) {
61
+ const [query, setQuery] = react.useState("");
62
+ const [results, setResults] = react.useState([]);
63
+ const [showResults, setShowResults] = react.useState(false);
64
+ const [loading, setLoading] = react.useState(false);
65
+ const debounceRef = react.useRef();
66
+ const containerRef = react.useRef(null);
67
+ const search = react.useCallback(
68
+ async (q) => {
69
+ if (!q.trim()) {
70
+ setResults([]);
71
+ setShowResults(false);
72
+ return;
73
+ }
74
+ setLoading(true);
75
+ try {
76
+ const res = await fetch(`${apiPath}/posts?q=${encodeURIComponent(q)}&limit=5&status=published`);
77
+ const data = await res.json();
78
+ if (data.success) {
79
+ setResults(data.data || []);
80
+ setShowResults(true);
81
+ }
82
+ } catch {
83
+ setResults([]);
84
+ } finally {
85
+ setLoading(false);
86
+ }
87
+ },
88
+ [apiPath]
89
+ );
90
+ const handleChange = (e) => {
91
+ const value = e.target.value;
92
+ setQuery(value);
93
+ if (debounceRef.current) clearTimeout(debounceRef.current);
94
+ debounceRef.current = setTimeout(() => {
95
+ search(value);
96
+ onSearch?.(value);
97
+ }, 300);
98
+ };
99
+ const handleSubmit = (e) => {
100
+ e.preventDefault();
101
+ onSearch?.(query);
102
+ setShowResults(false);
103
+ };
104
+ react.useEffect(() => {
105
+ function handleClickOutside(e) {
106
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
107
+ setShowResults(false);
108
+ }
109
+ }
110
+ document.addEventListener("mousedown", handleClickOutside);
111
+ return () => document.removeEventListener("mousedown", handleClickOutside);
112
+ }, []);
113
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `nbk-search ${className}`, ref: containerRef, children: [
114
+ /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "nbk-search-form", children: [
115
+ /* @__PURE__ */ jsxRuntime.jsx(
116
+ "input",
117
+ {
118
+ type: "search",
119
+ value: query,
120
+ onChange: handleChange,
121
+ placeholder,
122
+ className: "nbk-search-input",
123
+ onFocus: () => results.length > 0 && setShowResults(true)
124
+ }
125
+ ),
126
+ loading && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nbk-search-spinner" })
127
+ ] }),
128
+ showResults && results.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nbk-search-results", children: results.map((result) => /* @__PURE__ */ jsxRuntime.jsxs(
129
+ "a",
130
+ {
131
+ href: `/blog/${result.slug}`,
132
+ className: "nbk-search-result",
133
+ onClick: () => setShowResults(false),
134
+ children: [
135
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nbk-search-result-title", children: result.title }),
136
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nbk-search-result-excerpt", children: result.excerpt?.slice(0, 100) })
137
+ ]
138
+ },
139
+ result.slug
140
+ )) })
141
+ ] });
142
+ }
143
+ function TableOfContentsComponent({ headings, className = "" }) {
144
+ const [activeId, setActiveId] = react.useState("");
145
+ react.useEffect(() => {
146
+ const observer = new IntersectionObserver(
147
+ (entries) => {
148
+ for (const entry of entries) {
149
+ if (entry.isIntersecting) {
150
+ setActiveId(entry.target.id);
151
+ }
152
+ }
153
+ },
154
+ { rootMargin: "-80px 0px -80% 0px" }
155
+ );
156
+ headings.forEach(({ id }) => {
157
+ const el = document.getElementById(id);
158
+ if (el) observer.observe(el);
159
+ });
160
+ return () => observer.disconnect();
161
+ }, [headings]);
162
+ if (headings.length === 0) return null;
163
+ return /* @__PURE__ */ jsxRuntime.jsxs("nav", { className: `nbk-toc ${className}`, children: [
164
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "nbk-toc-title", children: "Table of Contents" }),
165
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "nbk-toc-list", children: headings.map((heading) => /* @__PURE__ */ jsxRuntime.jsx(
166
+ "li",
167
+ {
168
+ className: `nbk-toc-item nbk-toc-level-${heading.level} ${activeId === heading.id ? "active" : ""}`,
169
+ children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: `#${heading.id}`, className: "nbk-toc-link", children: heading.text })
170
+ },
171
+ heading.id
172
+ )) })
173
+ ] });
174
+ }
175
+ function ShareButtons({ url, title, className = "" }) {
176
+ const [copied, setCopied] = react.useState(false);
177
+ const encodedUrl = encodeURIComponent(url);
178
+ const encodedTitle = encodeURIComponent(title);
179
+ const share = (platform) => {
180
+ const urls = {
181
+ twitter: `https://twitter.com/intent/tweet?text=${encodedTitle}&url=${encodedUrl}`,
182
+ linkedin: `https://www.linkedin.com/sharing/share-offsite/?url=${encodedUrl}`,
183
+ facebook: `https://www.facebook.com/sharer/sharer.php?u=${encodedUrl}`
184
+ };
185
+ const shareUrl = urls[platform];
186
+ if (shareUrl) {
187
+ window.open(shareUrl, "_blank", "width=600,height=400");
188
+ }
189
+ };
190
+ const copyLink = async () => {
191
+ try {
192
+ await navigator.clipboard.writeText(url);
193
+ setCopied(true);
194
+ setTimeout(() => setCopied(false), 2e3);
195
+ } catch {
196
+ const input = document.createElement("input");
197
+ input.value = url;
198
+ document.body.appendChild(input);
199
+ input.select();
200
+ document.execCommand("copy");
201
+ document.body.removeChild(input);
202
+ setCopied(true);
203
+ setTimeout(() => setCopied(false), 2e3);
204
+ }
205
+ };
206
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `nbk-share ${className}`, children: [
207
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nbk-share-label", children: "Share this post:" }),
208
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nbk-share-buttons", children: [
209
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => share("twitter"), className: "nbk-share-btn nbk-share-twitter", title: "Share on Twitter", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", width: "18", height: "18", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" }) }) }),
210
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => share("linkedin"), className: "nbk-share-btn nbk-share-linkedin", title: "Share on LinkedIn", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", width: "18", height: "18", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" }) }) }),
211
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => share("facebook"), className: "nbk-share-btn nbk-share-facebook", title: "Share on Facebook", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", width: "18", height: "18", fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z" }) }) }),
212
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: copyLink, className: "nbk-share-btn nbk-share-copy", title: copied ? "Copied!" : "Copy link", children: copied ? /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", width: "18", height: "18", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 6L9 17l-5-5" }) }) : /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", width: "18", height: "18", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
213
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
214
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1" })
215
+ ] }) })
216
+ ] })
217
+ ] });
218
+ }
219
+ function ReadingProgressBar({ className = "" }) {
220
+ const [progress, setProgress] = react.useState(0);
221
+ react.useEffect(() => {
222
+ function handleScroll() {
223
+ const scrollTop = window.scrollY;
224
+ const docHeight = document.documentElement.scrollHeight - window.innerHeight;
225
+ if (docHeight > 0) {
226
+ setProgress(Math.min(scrollTop / docHeight * 100, 100));
227
+ }
228
+ }
229
+ window.addEventListener("scroll", handleScroll, { passive: true });
230
+ return () => window.removeEventListener("scroll", handleScroll);
231
+ }, []);
232
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `nbk-progress-bar ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx(
233
+ "div",
234
+ {
235
+ className: "nbk-progress-fill",
236
+ style: { width: `${progress}%` }
237
+ }
238
+ ) });
239
+ }
240
+ function buildHref(basePath, page, category) {
241
+ const params = new URLSearchParams();
242
+ if (page > 1) params.set("page", String(page));
243
+ if (category) params.set("category", category);
244
+ const qs = params.toString();
245
+ return qs ? `${basePath}?${qs}` : basePath;
246
+ }
247
+ function Pagination({
248
+ currentPage,
249
+ totalPages,
250
+ basePath = "/blog",
251
+ category,
252
+ className = ""
253
+ }) {
254
+ if (totalPages <= 1) return null;
255
+ const pages = [];
256
+ const maxVisible = 5;
257
+ if (totalPages <= maxVisible + 2) {
258
+ for (let i = 1; i <= totalPages; i++) pages.push(i);
259
+ } else {
260
+ pages.push(1);
261
+ const start = Math.max(2, currentPage - 1);
262
+ const end = Math.min(totalPages - 1, currentPage + 1);
263
+ if (start > 2) pages.push("...");
264
+ for (let i = start; i <= end; i++) pages.push(i);
265
+ if (end < totalPages - 1) pages.push("...");
266
+ pages.push(totalPages);
267
+ }
268
+ return /* @__PURE__ */ jsxRuntime.jsxs("nav", { className: `nbk-pagination ${className}`, children: [
269
+ currentPage > 1 ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: buildHref(basePath, currentPage - 1, category), className: "nbk-pagination-btn", children: "Previous" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nbk-pagination-btn disabled", children: "Previous" }),
270
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nbk-pagination-pages", children: pages.map(
271
+ (page, idx) => typeof page === "string" ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nbk-pagination-ellipsis", children: "..." }, `ellipsis-${idx}`) : page === currentPage ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nbk-pagination-page active", children: page }, page) : /* @__PURE__ */ jsxRuntime.jsx(
272
+ "a",
273
+ {
274
+ href: buildHref(basePath, page, category),
275
+ className: "nbk-pagination-page",
276
+ children: page
277
+ },
278
+ page
279
+ )
280
+ ) }),
281
+ currentPage < totalPages ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: buildHref(basePath, currentPage + 1, category), className: "nbk-pagination-btn", children: "Next" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nbk-pagination-btn disabled", children: "Next" })
282
+ ] });
283
+ }
284
+ function AuthorCard({ author, className = "" }) {
285
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `nbk-author-card ${className}`, children: [
286
+ author.avatar && /* @__PURE__ */ jsxRuntime.jsx("img", { src: author.avatar, alt: author.name, className: "nbk-author-avatar" }),
287
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nbk-author-info", children: [
288
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nbk-author-name", children: author.url ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: author.url, target: "_blank", rel: "noopener noreferrer", children: author.name }) : author.name }),
289
+ author.bio && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "nbk-author-bio", children: author.bio })
290
+ ] })
291
+ ] });
292
+ }
293
+ function BreadcrumbNav({ items, className = "" }) {
294
+ return /* @__PURE__ */ jsxRuntime.jsx("nav", { className: `nbk-breadcrumb ${className}`, "aria-label": "Breadcrumb", children: /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "nbk-breadcrumb-list", children: items.map((item, idx) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "nbk-breadcrumb-item", children: [
295
+ idx > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nbk-breadcrumb-sep", children: "/" }),
296
+ item.href ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: item.href, className: "nbk-breadcrumb-link", children: item.label }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nbk-breadcrumb-current", children: item.label })
297
+ ] }, idx)) }) });
298
+ }
299
+ function CategoryList({
300
+ categories,
301
+ activeCategory,
302
+ basePath = "/blog",
303
+ className = ""
304
+ }) {
305
+ if (categories.length === 0) return null;
306
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `nbk-category-list ${className}`, children: [
307
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "nbk-category-list-title", children: "Categories" }),
308
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "nbk-category-items", children: categories.map((cat) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "nbk-category-item", children: /* @__PURE__ */ jsxRuntime.jsxs(
309
+ "a",
310
+ {
311
+ href: `${basePath}/category/${cat.slug}`,
312
+ className: `nbk-category-btn ${activeCategory === cat.slug ? "active" : ""}`,
313
+ children: [
314
+ cat.name,
315
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nbk-category-count", children: cat.postCount })
316
+ ]
317
+ }
318
+ ) }, cat.slug)) })
319
+ ] });
320
+ }
321
+ function TagCloud({ tags, basePath = "/blog", className = "" }) {
322
+ if (tags.length === 0) return null;
323
+ const maxCount = Math.max(...tags.map((t) => t.count));
324
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `nbk-tag-cloud ${className}`, children: [
325
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "nbk-tag-cloud-title", children: "Tags" }),
326
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nbk-tags", children: tags.map((tag) => {
327
+ const size = 0.8 + tag.count / maxCount * 0.6;
328
+ return /* @__PURE__ */ jsxRuntime.jsxs(
329
+ "a",
330
+ {
331
+ href: `${basePath}?tag=${tag.name}`,
332
+ className: "nbk-tag",
333
+ style: { fontSize: `${size}rem` },
334
+ children: [
335
+ "#",
336
+ tag.name
337
+ ]
338
+ },
339
+ tag.name
340
+ );
341
+ }) })
342
+ ] });
343
+ }
344
+ function CodeBlock({
345
+ code,
346
+ language = "plaintext",
347
+ filename,
348
+ className = ""
349
+ }) {
350
+ const [copied, setCopied] = react.useState(false);
351
+ const handleCopy = async () => {
352
+ try {
353
+ await navigator.clipboard.writeText(code);
354
+ setCopied(true);
355
+ setTimeout(() => setCopied(false), 2e3);
356
+ } catch {
357
+ }
358
+ };
359
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `nbk-code-block ${className}`, children: [
360
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nbk-code-header", children: [
361
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nbk-code-lang", children: filename || language }),
362
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: handleCopy, className: "nbk-code-copy", children: copied ? "Copied!" : "Copy" })
363
+ ] }),
364
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: `nbk-code-pre language-${language}`, children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: code }) })
365
+ ] });
366
+ }
367
+ function BlogListPage({
368
+ posts,
369
+ total,
370
+ page = 1,
371
+ postsPerPage = 10,
372
+ categories = [],
373
+ activeCategory,
374
+ showCategories = true,
375
+ showSearch = true,
376
+ layout = "grid",
377
+ basePath = "/blog",
378
+ apiPath = "/api/blog",
379
+ className = "",
380
+ slots
381
+ }) {
382
+ const totalPages = Math.ceil(total / postsPerPage);
383
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
384
+ slots?.header,
385
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `nbk-blog-list ${className}`, children: [
386
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nbk-blog-header", children: showSearch && /* @__PURE__ */ jsxRuntime.jsx(BlogSearch, { apiPath }) }),
387
+ slots?.beforePosts,
388
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nbk-blog-layout", children: [
389
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nbk-blog-main", children: [
390
+ posts.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nbk-empty-state", children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "No posts found." }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: `nbk-posts-${layout}`, children: posts.map(
391
+ (post) => slots?.renderCard ? slots.renderCard(post) : /* @__PURE__ */ jsxRuntime.jsx(
392
+ BlogCard,
393
+ {
394
+ post,
395
+ layout: layout === "list" ? "horizontal" : "vertical",
396
+ basePath
397
+ },
398
+ String(post._id || post.slug)
399
+ )
400
+ ) }),
401
+ totalPages > 1 && /* @__PURE__ */ jsxRuntime.jsx(
402
+ Pagination,
403
+ {
404
+ currentPage: page,
405
+ totalPages,
406
+ basePath,
407
+ category: activeCategory
408
+ }
409
+ )
410
+ ] }),
411
+ slots?.sidebar || showCategories && categories.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("aside", { className: "nbk-blog-sidebar", children: /* @__PURE__ */ jsxRuntime.jsx(
412
+ CategoryList,
413
+ {
414
+ categories,
415
+ activeCategory,
416
+ basePath
417
+ }
418
+ ) })
419
+ ] }),
420
+ slots?.afterPosts
421
+ ] }),
422
+ slots?.footer
423
+ ] });
424
+ }
425
+ function BlogPostPage({
426
+ post,
427
+ relatedPosts = [],
428
+ showTOC = true,
429
+ tocPosition = "sidebar",
430
+ showAuthor = true,
431
+ showRelatedPosts = true,
432
+ showShareButtons = true,
433
+ showReadingProgress = true,
434
+ basePath = "/blog",
435
+ className = "",
436
+ slots
437
+ }) {
438
+ if (!post) {
439
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nbk-not-found", children: "Post not found" });
440
+ }
441
+ const headings = [];
442
+ const headingRegex = /<h([2-4])\s+id="([^"]*)"[^>]*>(.*?)<\/h[2-4]>/gi;
443
+ let match;
444
+ while ((match = headingRegex.exec(post.contentHTML || "")) !== null) {
445
+ headings.push({
446
+ level: parseInt(match[1]),
447
+ id: match[2],
448
+ text: match[3].replace(/<[^>]+>/g, "")
449
+ });
450
+ }
451
+ const date = post.publishedAt ? new Date(post.publishedAt).toLocaleDateString("en-US", {
452
+ year: "numeric",
453
+ month: "long",
454
+ day: "numeric"
455
+ }) : "";
456
+ const postUrl = `${basePath}/${post.slug}`;
457
+ const hasTOC = showTOC && tocPosition !== "none" && headings.length > 2;
458
+ const hasSidebarTOC = hasTOC && tocPosition === "sidebar";
459
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
460
+ slots?.header,
461
+ /* @__PURE__ */ jsxRuntime.jsxs("article", { className: `nbk-post ${hasSidebarTOC ? "nbk-post-with-toc" : ""} ${className}`, children: [
462
+ showReadingProgress && /* @__PURE__ */ jsxRuntime.jsx(ReadingProgressBar, {}),
463
+ /* @__PURE__ */ jsxRuntime.jsx(
464
+ BreadcrumbNav,
465
+ {
466
+ items: [
467
+ { label: "Home", href: "/" },
468
+ { label: "Blog", href: basePath },
469
+ ...post.categories?.[0] ? [{ label: post.categories[0], href: `${basePath}/category/${post.categories[0]}` }] : [],
470
+ { label: post.title }
471
+ ]
472
+ }
473
+ ),
474
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "nbk-post-header", children: [
475
+ post.categories?.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nbk-post-categories", children: post.categories.map((cat) => /* @__PURE__ */ jsxRuntime.jsx("a", { href: `${basePath}/category/${cat}`, className: "nbk-post-category", children: cat }, cat)) }),
476
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "nbk-post-title", children: post.title }),
477
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nbk-post-meta", children: [
478
+ post.author?.avatar && /* @__PURE__ */ jsxRuntime.jsx("img", { src: post.author.avatar, alt: post.author.name, className: "nbk-post-avatar" }),
479
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nbk-post-author", children: post.author?.name }),
480
+ date && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
481
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nbk-post-sep", children: "\xB7" }),
482
+ /* @__PURE__ */ jsxRuntime.jsx("time", { className: "nbk-post-date", dateTime: String(post.publishedAt), children: date })
483
+ ] }),
484
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nbk-post-sep", children: "\xB7" }),
485
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "nbk-post-reading-time", children: [
486
+ post.readingTime,
487
+ " min read"
488
+ ] })
489
+ ] })
490
+ ] }),
491
+ post.coverImage?.url && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nbk-post-cover", children: /* @__PURE__ */ jsxRuntime.jsx(
492
+ "img",
493
+ {
494
+ src: post.coverImage.url,
495
+ alt: post.coverImage.alt || post.title,
496
+ className: "nbk-post-cover-img"
497
+ }
498
+ ) }),
499
+ hasTOC && tocPosition === "top" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nbk-post-toc-inline", children: /* @__PURE__ */ jsxRuntime.jsx(TableOfContentsComponent, { headings }) }),
500
+ slots?.beforeContent,
501
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "nbk-post-layout", children: [
502
+ hasSidebarTOC && /* @__PURE__ */ jsxRuntime.jsx("aside", { className: "nbk-post-toc-sidebar", children: /* @__PURE__ */ jsxRuntime.jsx(TableOfContentsComponent, { headings }) }),
503
+ /* @__PURE__ */ jsxRuntime.jsx(
504
+ "div",
505
+ {
506
+ className: "nbk-post-content",
507
+ dangerouslySetInnerHTML: { __html: post.contentHTML || "" }
508
+ }
509
+ )
510
+ ] }),
511
+ slots?.afterContent,
512
+ post.tags?.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nbk-post-tags", children: post.tags.map((tag) => /* @__PURE__ */ jsxRuntime.jsxs("a", { href: `${basePath}?tag=${tag}`, className: "nbk-tag", children: [
513
+ "#",
514
+ tag
515
+ ] }, tag)) }),
516
+ showShareButtons && /* @__PURE__ */ jsxRuntime.jsx(ShareButtons, { url: postUrl, title: post.title }),
517
+ showAuthor && post.author && /* @__PURE__ */ jsxRuntime.jsx(AuthorCard, { author: post.author }),
518
+ showRelatedPosts && relatedPosts.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "nbk-related", children: [
519
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "nbk-related-title", children: "Related Posts" }),
520
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "nbk-related-grid", children: relatedPosts.map((p) => /* @__PURE__ */ jsxRuntime.jsx(BlogCard, { post: p, basePath }, String(p._id || p.slug))) })
521
+ ] })
522
+ ] }),
523
+ slots?.footer
524
+ ] });
525
+ }
526
+
527
+ exports.AuthorCard = AuthorCard;
528
+ exports.BlogCard = BlogCard;
529
+ exports.BlogListPage = BlogListPage;
530
+ exports.BlogPostPage = BlogPostPage;
531
+ exports.BlogSearch = BlogSearch;
532
+ exports.BreadcrumbNav = BreadcrumbNav;
533
+ exports.CategoryList = CategoryList;
534
+ exports.CodeBlock = CodeBlock;
535
+ exports.Pagination = Pagination;
536
+ exports.ReadingProgressBar = ReadingProgressBar;
537
+ exports.ShareButtons = ShareButtons;
538
+ exports.TableOfContents = TableOfContentsComponent;
539
+ exports.TagCloud = TagCloud;
540
+ //# sourceMappingURL=index.cjs.map
541
+ //# sourceMappingURL=index.cjs.map