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