@fullstackdatasolutions/articles 0.4.2 → 0.5.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.
- package/README.md +138 -3
- package/dist/index.cjs +182 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -1
- package/dist/index.d.ts +50 -1
- package/dist/index.js +241 -110
- package/dist/index.js.map +1 -1
- package/dist/server.cjs +281 -189
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +37 -1
- package/dist/server.d.ts +37 -1
- package/dist/server.js +278 -189
- package/dist/server.js.map +1 -1
- package/package.json +5 -1
- package/src/ArticleContent.tsx +17 -0
- package/src/ArticleSchemas.tsx +97 -1
- package/src/ArticleSocialShare.tsx +1 -1
- package/src/ArticleTOC.tsx +29 -0
- package/src/ScrollToTop.tsx +25 -0
- package/src/__tests__/ArticleContent.test.tsx +91 -0
- package/src/__tests__/ArticleSchemas.test.tsx +212 -1
- package/src/__tests__/ArticleSocialShare.test.tsx +7 -7
- package/src/__tests__/ArticleTOC.test.tsx +75 -0
- package/src/__tests__/ScrollToTop.test.tsx +87 -0
- package/src/__tests__/seoUtils.test.ts +284 -0
- package/src/__tests__/server-articles.test.ts +98 -0
- package/src/articleTypes.ts +26 -0
- package/src/articlesConfig.ts +4 -0
- package/src/index.ts +10 -2
- package/src/markdown.ts +143 -130
- package/src/seoUtils.ts +79 -15
- package/src/server-articles.ts +81 -78
- package/src/server.ts +4 -2
package/dist/index.js
CHANGED
|
@@ -91,7 +91,7 @@ function ArticleCategoryGrid({ categories, pageSize = 8 }) {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
// src/ArticleSchemas.tsx
|
|
94
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
94
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
95
95
|
function ArticleSchema({ article, articleUrl, siteName }) {
|
|
96
96
|
const schema = __spreadProps(__spreadValues({
|
|
97
97
|
"@context": "https://schema.org",
|
|
@@ -131,6 +131,86 @@ function BreadcrumbSchema({ items }) {
|
|
|
131
131
|
}
|
|
132
132
|
);
|
|
133
133
|
}
|
|
134
|
+
function ArticleSEO({ article, articleUrl, siteName, siteLogo }) {
|
|
135
|
+
const publishedAt = article.date ? new Date(article.date).toISOString() : void 0;
|
|
136
|
+
const modifiedAt = article.lastmod ? new Date(article.lastmod).toISOString() : publishedAt;
|
|
137
|
+
const structuredData = __spreadValues(__spreadProps(__spreadValues(__spreadValues({
|
|
138
|
+
"@context": "https://schema.org",
|
|
139
|
+
"@type": article.articleType || "Article",
|
|
140
|
+
mainEntityOfPage: { "@type": "WebPage", "@id": articleUrl },
|
|
141
|
+
headline: article.title,
|
|
142
|
+
image: article.featuredImage ? { "@type": "ImageObject", url: article.featuredImage } : void 0
|
|
143
|
+
}, publishedAt && { datePublished: publishedAt }), modifiedAt && { dateModified: modifiedAt }), {
|
|
144
|
+
author: { "@type": "Person", name: article.author },
|
|
145
|
+
publisher: __spreadValues({
|
|
146
|
+
"@type": "Organization",
|
|
147
|
+
name: siteName
|
|
148
|
+
}, siteLogo && { logo: { "@type": "ImageObject", url: siteLogo } }),
|
|
149
|
+
description: article.excerpt
|
|
150
|
+
}), article.series && { isPartOf: { "@type": "Blog", name: article.series } });
|
|
151
|
+
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
152
|
+
/* @__PURE__ */ jsx2(
|
|
153
|
+
"script",
|
|
154
|
+
{
|
|
155
|
+
type: "application/ld+json",
|
|
156
|
+
dangerouslySetInnerHTML: { __html: JSON.stringify(structuredData) }
|
|
157
|
+
}
|
|
158
|
+
),
|
|
159
|
+
article.faq && article.faq.length > 0 && /* @__PURE__ */ jsx2(
|
|
160
|
+
"script",
|
|
161
|
+
{
|
|
162
|
+
type: "application/ld+json",
|
|
163
|
+
dangerouslySetInnerHTML: {
|
|
164
|
+
__html: JSON.stringify({
|
|
165
|
+
"@context": "https://schema.org",
|
|
166
|
+
"@type": "FAQPage",
|
|
167
|
+
mainEntity: article.faq.map(({ question, answer }) => ({
|
|
168
|
+
"@type": "Question",
|
|
169
|
+
name: question,
|
|
170
|
+
acceptedAnswer: { "@type": "Answer", text: answer }
|
|
171
|
+
}))
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
),
|
|
176
|
+
article.howTo && article.howTo.length > 0 && /* @__PURE__ */ jsx2(
|
|
177
|
+
"script",
|
|
178
|
+
{
|
|
179
|
+
type: "application/ld+json",
|
|
180
|
+
dangerouslySetInnerHTML: {
|
|
181
|
+
__html: JSON.stringify({
|
|
182
|
+
"@context": "https://schema.org",
|
|
183
|
+
"@type": "HowTo",
|
|
184
|
+
name: article.title,
|
|
185
|
+
step: article.howTo.map(({ name, text }) => ({
|
|
186
|
+
"@type": "HowToStep",
|
|
187
|
+
name,
|
|
188
|
+
text
|
|
189
|
+
}))
|
|
190
|
+
})
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
)
|
|
194
|
+
] });
|
|
195
|
+
}
|
|
196
|
+
function FAQPageSchema({ items }) {
|
|
197
|
+
const schema = {
|
|
198
|
+
"@context": "https://schema.org",
|
|
199
|
+
"@type": "FAQPage",
|
|
200
|
+
mainEntity: items.map(({ question, answer }) => ({
|
|
201
|
+
"@type": "Question",
|
|
202
|
+
name: question,
|
|
203
|
+
acceptedAnswer: { "@type": "Answer", text: answer }
|
|
204
|
+
}))
|
|
205
|
+
};
|
|
206
|
+
return /* @__PURE__ */ jsx2(
|
|
207
|
+
"script",
|
|
208
|
+
{
|
|
209
|
+
type: "application/ld+json",
|
|
210
|
+
dangerouslySetInnerHTML: { __html: JSON.stringify(schema) }
|
|
211
|
+
}
|
|
212
|
+
);
|
|
213
|
+
}
|
|
134
214
|
function CollectionPageSchema({
|
|
135
215
|
title,
|
|
136
216
|
description,
|
|
@@ -156,15 +236,15 @@ function CollectionPageSchema({
|
|
|
156
236
|
|
|
157
237
|
// src/ArticleSearchBar.tsx
|
|
158
238
|
import { Search, X } from "lucide-react";
|
|
159
|
-
import { jsx as jsx3, jsxs as
|
|
239
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
160
240
|
function ArticleSearchBar({
|
|
161
241
|
value,
|
|
162
242
|
onChange,
|
|
163
243
|
disabled,
|
|
164
244
|
resultCount
|
|
165
245
|
}) {
|
|
166
|
-
return /* @__PURE__ */ jsx3("section", { className: "py-8 bg-background border-b border-border", children: /* @__PURE__ */
|
|
167
|
-
/* @__PURE__ */
|
|
246
|
+
return /* @__PURE__ */ jsx3("section", { className: "py-8 bg-background border-b border-border", children: /* @__PURE__ */ jsxs3("div", { className: "max-w-4xl mx-auto px-4 sm:px-6 lg:px-8", children: [
|
|
247
|
+
/* @__PURE__ */ jsxs3("div", { className: "relative", children: [
|
|
168
248
|
/* @__PURE__ */ jsx3(Search, { className: "absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground h-5 w-5" }),
|
|
169
249
|
/* @__PURE__ */ jsx3(
|
|
170
250
|
"input",
|
|
@@ -194,17 +274,17 @@ function ArticleSearchBar({
|
|
|
194
274
|
|
|
195
275
|
// src/ArticlesHero.tsx
|
|
196
276
|
import Link2 from "next/link";
|
|
197
|
-
import { jsx as jsx4, jsxs as
|
|
277
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
198
278
|
var DEFAULT_TITLE = "Vox Populus Insights";
|
|
199
279
|
var DEFAULT_DESCRIPTION = "Expert analysis, campaign strategies, and voter engagement insights from the frontlines of democracy.";
|
|
200
280
|
function ArticlesHero({
|
|
201
281
|
title = DEFAULT_TITLE,
|
|
202
282
|
description = DEFAULT_DESCRIPTION
|
|
203
283
|
}) {
|
|
204
|
-
return /* @__PURE__ */ jsx4("section", { className: "bg-linear-to-r from-gray-50 to-gray-100 py-16 md:py-24", children: /* @__PURE__ */ jsx4("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */
|
|
284
|
+
return /* @__PURE__ */ jsx4("section", { className: "bg-linear-to-r from-gray-50 to-gray-100 py-16 md:py-24", children: /* @__PURE__ */ jsx4("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsxs4("div", { className: "max-w-3xl mx-auto text-center", children: [
|
|
205
285
|
/* @__PURE__ */ jsx4("h1", { className: "text-4xl md:text-5xl font-bold text-foreground mb-6", children: title }),
|
|
206
286
|
/* @__PURE__ */ jsx4("p", { className: "text-xl text-muted-foreground mb-8", children: description }),
|
|
207
|
-
/* @__PURE__ */
|
|
287
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex flex-col sm:flex-row gap-4 justify-center", children: [
|
|
208
288
|
/* @__PURE__ */ jsx4(
|
|
209
289
|
Link2,
|
|
210
290
|
{
|
|
@@ -229,28 +309,28 @@ function ArticlesHero({
|
|
|
229
309
|
import Link3 from "next/link";
|
|
230
310
|
import Image2 from "next/image";
|
|
231
311
|
import { ArrowRight, Calendar, Clock, User } from "lucide-react";
|
|
232
|
-
import { jsx as jsx5, jsxs as
|
|
312
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
233
313
|
function FeaturedArticle({ article }) {
|
|
234
|
-
return /* @__PURE__ */ jsx5("section", { className: "py-16 bg-background", children: /* @__PURE__ */ jsx5("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */
|
|
235
|
-
/* @__PURE__ */
|
|
314
|
+
return /* @__PURE__ */ jsx5("section", { className: "py-16 bg-background", children: /* @__PURE__ */ jsx5("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsxs5("div", { className: "grid lg:grid-cols-2 gap-12 items-center", children: [
|
|
315
|
+
/* @__PURE__ */ jsxs5("div", { children: [
|
|
236
316
|
/* @__PURE__ */ jsx5("span", { className: "inline-block bg-primary/10 text-primary text-sm font-medium px-3 py-1 rounded-full mb-4", children: "FEATURED ARTICLE" }),
|
|
237
317
|
/* @__PURE__ */ jsx5("h2", { className: "text-3xl font-bold text-foreground mb-4", children: article.title }),
|
|
238
318
|
/* @__PURE__ */ jsx5("p", { className: "text-lg text-muted-foreground mb-6", children: article.excerpt }),
|
|
239
|
-
/* @__PURE__ */
|
|
240
|
-
article.date && /* @__PURE__ */
|
|
319
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-6 text-sm text-muted-foreground mb-6", children: [
|
|
320
|
+
article.date && /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
|
|
241
321
|
/* @__PURE__ */ jsx5(Calendar, { className: "h-4 w-4" }),
|
|
242
322
|
/* @__PURE__ */ jsx5("span", { children: article.date })
|
|
243
323
|
] }),
|
|
244
|
-
/* @__PURE__ */
|
|
324
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
|
|
245
325
|
/* @__PURE__ */ jsx5(Clock, { className: "h-4 w-4" }),
|
|
246
326
|
/* @__PURE__ */ jsx5("span", { children: article.readTime })
|
|
247
327
|
] }),
|
|
248
|
-
/* @__PURE__ */
|
|
328
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
|
|
249
329
|
/* @__PURE__ */ jsx5(User, { className: "h-4 w-4" }),
|
|
250
330
|
/* @__PURE__ */ jsx5("span", { children: article.author })
|
|
251
331
|
] })
|
|
252
332
|
] }),
|
|
253
|
-
/* @__PURE__ */
|
|
333
|
+
/* @__PURE__ */ jsxs5(
|
|
254
334
|
Link3,
|
|
255
335
|
{
|
|
256
336
|
href: `/articles/${article.slug}`,
|
|
@@ -262,7 +342,7 @@ function FeaturedArticle({ article }) {
|
|
|
262
342
|
}
|
|
263
343
|
)
|
|
264
344
|
] }),
|
|
265
|
-
/* @__PURE__ */
|
|
345
|
+
/* @__PURE__ */ jsxs5("div", { className: "bg-card rounded-lg p-8", children: [
|
|
266
346
|
/* @__PURE__ */ jsx5(
|
|
267
347
|
Image2,
|
|
268
348
|
{
|
|
@@ -288,9 +368,9 @@ import { useState as useState2, useEffect as useEffect2 } from "react";
|
|
|
288
368
|
import Image3 from "next/image";
|
|
289
369
|
import Link4 from "next/link";
|
|
290
370
|
import { ArrowRight as ArrowRight2, Calendar as Calendar2, Clock as Clock2 } from "lucide-react";
|
|
291
|
-
import { jsx as jsx6, jsxs as
|
|
371
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
292
372
|
function ArticleCard({ article }) {
|
|
293
|
-
return /* @__PURE__ */
|
|
373
|
+
return /* @__PURE__ */ jsxs6("div", { className: "rounded-lg border border-border bg-card text-card-foreground shadow-sm hover:shadow-lg transition-shadow duration-300", children: [
|
|
294
374
|
/* @__PURE__ */ jsx6("div", { className: "p-0", children: /* @__PURE__ */ jsx6(
|
|
295
375
|
Image3,
|
|
296
376
|
{
|
|
@@ -301,7 +381,7 @@ function ArticleCard({ article }) {
|
|
|
301
381
|
height: 200
|
|
302
382
|
}
|
|
303
383
|
) }),
|
|
304
|
-
/* @__PURE__ */
|
|
384
|
+
/* @__PURE__ */ jsxs6("div", { className: "p-6", children: [
|
|
305
385
|
/* @__PURE__ */ jsx6("div", { className: "flex gap-2 mb-3", children: /* @__PURE__ */ jsx6("span", { className: "bg-primary/10 text-primary text-xs font-medium px-2 py-1 rounded", children: article.category }) }),
|
|
306
386
|
/* @__PURE__ */ jsx6("h3", { className: "text-lg font-semibold leading-none tracking-tight mb-2", children: /* @__PURE__ */ jsx6(
|
|
307
387
|
Link4,
|
|
@@ -312,13 +392,13 @@ function ArticleCard({ article }) {
|
|
|
312
392
|
}
|
|
313
393
|
) }),
|
|
314
394
|
/* @__PURE__ */ jsx6("p", { className: "text-muted-foreground mb-4 line-clamp-3", children: article.excerpt }),
|
|
315
|
-
/* @__PURE__ */
|
|
316
|
-
/* @__PURE__ */
|
|
317
|
-
article.date && /* @__PURE__ */
|
|
395
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between text-sm text-muted-foreground border-t pt-4", children: [
|
|
396
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-3", children: [
|
|
397
|
+
article.date && /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
|
|
318
398
|
/* @__PURE__ */ jsx6(Calendar2, { className: "h-3 w-3" }),
|
|
319
399
|
/* @__PURE__ */ jsx6("span", { children: article.date })
|
|
320
400
|
] }),
|
|
321
|
-
/* @__PURE__ */
|
|
401
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
|
|
322
402
|
/* @__PURE__ */ jsx6(Clock2, { className: "h-3 w-3" }),
|
|
323
403
|
/* @__PURE__ */ jsx6("span", { children: article.readTime })
|
|
324
404
|
] })
|
|
@@ -338,7 +418,7 @@ function ArticleCard({ article }) {
|
|
|
338
418
|
}
|
|
339
419
|
|
|
340
420
|
// src/LatestArticles.tsx
|
|
341
|
-
import { jsx as jsx7, jsxs as
|
|
421
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
342
422
|
function LatestArticles({ articles, pageSize }) {
|
|
343
423
|
const [visibleCount, setVisibleCount] = useState2(pageSize);
|
|
344
424
|
useEffect2(() => {
|
|
@@ -346,7 +426,7 @@ function LatestArticles({ articles, pageSize }) {
|
|
|
346
426
|
}, [articles, pageSize]);
|
|
347
427
|
const visible = articles.slice(0, visibleCount);
|
|
348
428
|
const hasMore = visibleCount < articles.length;
|
|
349
|
-
return /* @__PURE__ */
|
|
429
|
+
return /* @__PURE__ */ jsxs7("div", { children: [
|
|
350
430
|
/* @__PURE__ */ jsx7("div", { className: "grid md:grid-cols-2 lg:grid-cols-3 gap-8", children: visible.map((article) => /* @__PURE__ */ jsx7(ArticleCard, { article }, article.slug)) }),
|
|
351
431
|
hasMore && /* @__PURE__ */ jsx7("div", { className: "mt-10 text-center", children: /* @__PURE__ */ jsx7(
|
|
352
432
|
"button",
|
|
@@ -361,7 +441,7 @@ function LatestArticles({ articles, pageSize }) {
|
|
|
361
441
|
}
|
|
362
442
|
|
|
363
443
|
// src/LatestArticlesSection.tsx
|
|
364
|
-
import { jsx as jsx8, jsxs as
|
|
444
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
365
445
|
function DescriptionText({
|
|
366
446
|
searchQuery,
|
|
367
447
|
count
|
|
@@ -376,15 +456,15 @@ function LatestArticlesSection({
|
|
|
376
456
|
onClearSearch,
|
|
377
457
|
pageSize = 6
|
|
378
458
|
}) {
|
|
379
|
-
return /* @__PURE__ */ jsx8("section", { id: "latest", className: "py-16 bg-muted/50", children: /* @__PURE__ */
|
|
380
|
-
/* @__PURE__ */
|
|
459
|
+
return /* @__PURE__ */ jsx8("section", { id: "latest", className: "py-16 bg-muted/50", children: /* @__PURE__ */ jsxs8("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: [
|
|
460
|
+
/* @__PURE__ */ jsxs8("div", { className: "text-center mb-12", children: [
|
|
381
461
|
/* @__PURE__ */ jsx8("h2", { className: "text-3xl font-bold text-foreground mb-4", children: searchQuery ? "Search Results" : "Latest Articles" }),
|
|
382
462
|
/* @__PURE__ */ jsx8(DescriptionText, { searchQuery, count: articles.length })
|
|
383
463
|
] }),
|
|
384
|
-
articles.length === 0 && searchQuery ? /* @__PURE__ */ jsx8("div", { className: "text-center py-12", children: /* @__PURE__ */
|
|
464
|
+
articles.length === 0 && searchQuery ? /* @__PURE__ */ jsx8("div", { className: "text-center py-12", children: /* @__PURE__ */ jsxs8("div", { className: "max-w-md mx-auto", children: [
|
|
385
465
|
/* @__PURE__ */ jsx8(Search2, { className: "h-12 w-12 text-muted-foreground mx-auto mb-4" }),
|
|
386
466
|
/* @__PURE__ */ jsx8("h3", { className: "text-lg font-semibold text-foreground mb-2", children: "No articles found" }),
|
|
387
|
-
/* @__PURE__ */
|
|
467
|
+
/* @__PURE__ */ jsxs8("p", { className: "text-muted-foreground mb-4", children: [
|
|
388
468
|
`We couldn't find any articles matching "`,
|
|
389
469
|
searchQuery,
|
|
390
470
|
'". Try adjusting your search terms.'
|
|
@@ -482,7 +562,7 @@ function useArticles() {
|
|
|
482
562
|
}
|
|
483
563
|
|
|
484
564
|
// src/ArticlesPage.tsx
|
|
485
|
-
import { jsx as jsx9, jsxs as
|
|
565
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
486
566
|
function buildThemeVars(theme) {
|
|
487
567
|
if (!theme) return {};
|
|
488
568
|
const vars = {};
|
|
@@ -538,13 +618,13 @@ function renderSection(section, ctx, config) {
|
|
|
538
618
|
return articles.length > 0 && !searchQuery ? /* @__PURE__ */ jsx9(FeaturedArticle, { article: articles[0] }, "featured") : null;
|
|
539
619
|
case "latest":
|
|
540
620
|
if (loading && articles.length === 0) {
|
|
541
|
-
return /* @__PURE__ */ jsx9("section", { id: "latest", className: "py-16 bg-muted/50 flex-1", children: /* @__PURE__ */ jsx9("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex items-center justify-center py-24", children: /* @__PURE__ */
|
|
621
|
+
return /* @__PURE__ */ jsx9("section", { id: "latest", className: "py-16 bg-muted/50 flex-1", children: /* @__PURE__ */ jsx9("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex items-center justify-center py-24", children: /* @__PURE__ */ jsxs9("div", { className: "text-center", children: [
|
|
542
622
|
/* @__PURE__ */ jsx9("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-primary mx-auto mb-4" }),
|
|
543
623
|
/* @__PURE__ */ jsx9("p", { className: "text-muted-foreground", children: "Loading articles..." })
|
|
544
624
|
] }) }) }, "latest");
|
|
545
625
|
}
|
|
546
626
|
if (error) {
|
|
547
|
-
return /* @__PURE__ */ jsx9("section", { id: "latest", className: "py-16 bg-muted/50 flex-1", children: /* @__PURE__ */ jsx9("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex items-center justify-center", children: /* @__PURE__ */
|
|
627
|
+
return /* @__PURE__ */ jsx9("section", { id: "latest", className: "py-16 bg-muted/50 flex-1", children: /* @__PURE__ */ jsx9("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex items-center justify-center", children: /* @__PURE__ */ jsxs9("div", { className: "bg-red-50 border border-red-200 rounded-lg p-6 max-w-md text-center", children: [
|
|
548
628
|
/* @__PURE__ */ jsx9("h3", { className: "text-lg font-semibold text-red-800 mb-2", children: "Error Loading Articles" }),
|
|
549
629
|
/* @__PURE__ */ jsx9("p", { className: "text-red-600 mb-4", children: error }),
|
|
550
630
|
/* @__PURE__ */ jsx9(
|
|
@@ -593,7 +673,7 @@ function ArticlesPage({ config }) {
|
|
|
593
673
|
const articlesWithoutFeatured = hasFeatured ? state.articles.slice(1) : state.articles;
|
|
594
674
|
const displayedArticles = state.searchQuery ? state.articles : articlesWithoutFeatured;
|
|
595
675
|
const ctx = __spreadProps(__spreadValues({}, state), { displayedArticles, pageSize, categoriesPageSize });
|
|
596
|
-
return /* @__PURE__ */
|
|
676
|
+
return /* @__PURE__ */ jsxs9("div", { style: themeVars, children: [
|
|
597
677
|
layout.map((section) => renderSection(section, ctx, config)),
|
|
598
678
|
state.articles.length > 0 && /* @__PURE__ */ jsx9(
|
|
599
679
|
CollectionPageSchema,
|
|
@@ -611,7 +691,7 @@ function ArticlesPage({ config }) {
|
|
|
611
691
|
import Image4 from "next/image";
|
|
612
692
|
import Link5 from "next/link";
|
|
613
693
|
import { Calendar as Calendar3, Clock as Clock3, User as User2 } from "lucide-react";
|
|
614
|
-
import { jsx as jsx10, jsxs as
|
|
694
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
615
695
|
function toSlug(cat) {
|
|
616
696
|
return cat.toLowerCase().replaceAll(/\s+/g, "-").replaceAll(/[^a-z0-9-]/g, "");
|
|
617
697
|
}
|
|
@@ -620,7 +700,7 @@ function ArticleDetailHero({
|
|
|
620
700
|
categoryBasePath = "/articles/category",
|
|
621
701
|
showDate = false
|
|
622
702
|
}) {
|
|
623
|
-
return /* @__PURE__ */
|
|
703
|
+
return /* @__PURE__ */ jsxs10(
|
|
624
704
|
"section",
|
|
625
705
|
{
|
|
626
706
|
style: {
|
|
@@ -654,7 +734,7 @@ function ArticleDetailHero({
|
|
|
654
734
|
}
|
|
655
735
|
}
|
|
656
736
|
),
|
|
657
|
-
/* @__PURE__ */
|
|
737
|
+
/* @__PURE__ */ jsxs10(
|
|
658
738
|
"div",
|
|
659
739
|
{
|
|
660
740
|
style: {
|
|
@@ -699,7 +779,7 @@ function ArticleDetailHero({
|
|
|
699
779
|
}
|
|
700
780
|
),
|
|
701
781
|
/* @__PURE__ */ jsx10("h1", { className: "text-4xl md:text-5xl font-bold mb-4", children: article.title }),
|
|
702
|
-
/* @__PURE__ */
|
|
782
|
+
/* @__PURE__ */ jsxs10(
|
|
703
783
|
"div",
|
|
704
784
|
{
|
|
705
785
|
style: {
|
|
@@ -711,17 +791,17 @@ function ArticleDetailHero({
|
|
|
711
791
|
color: "rgba(255,255,255,0.8)"
|
|
712
792
|
},
|
|
713
793
|
children: [
|
|
714
|
-
showDate && article.date && /* @__PURE__ */
|
|
794
|
+
showDate && article.date && /* @__PURE__ */ jsxs10("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
|
|
715
795
|
/* @__PURE__ */ jsx10(Calendar3, { className: "h-4 w-4" }),
|
|
716
796
|
/* @__PURE__ */ jsx10("span", { children: article.date })
|
|
717
797
|
] }),
|
|
718
|
-
/* @__PURE__ */
|
|
798
|
+
/* @__PURE__ */ jsxs10("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
|
|
719
799
|
/* @__PURE__ */ jsx10(Clock3, { className: "h-4 w-4" }),
|
|
720
800
|
/* @__PURE__ */ jsx10("span", { children: article.readTime })
|
|
721
801
|
] }),
|
|
722
|
-
/* @__PURE__ */
|
|
802
|
+
/* @__PURE__ */ jsxs10("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
|
|
723
803
|
/* @__PURE__ */ jsx10(User2, { className: "h-4 w-4" }),
|
|
724
|
-
/* @__PURE__ */
|
|
804
|
+
/* @__PURE__ */ jsxs10("span", { children: [
|
|
725
805
|
"By ",
|
|
726
806
|
article.author
|
|
727
807
|
] })
|
|
@@ -740,7 +820,7 @@ function ArticleDetailHero({
|
|
|
740
820
|
// src/CategoryArticlesPage.tsx
|
|
741
821
|
import Image5 from "next/image";
|
|
742
822
|
import Link6 from "next/link";
|
|
743
|
-
import { jsx as jsx11, jsxs as
|
|
823
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
744
824
|
function getCategoryDescription(config, slug, categoryName) {
|
|
745
825
|
var _a;
|
|
746
826
|
const raw = (_a = config.categoryDescriptions) == null ? void 0 : _a[slug];
|
|
@@ -756,7 +836,7 @@ function CategoryArticlesPage({ category, articles, config }) {
|
|
|
756
836
|
const description = getCategoryDescription(config, category, categoryName);
|
|
757
837
|
const pageSize = (_a = config.pageSize) != null ? _a : DEFAULT_PAGE_SIZE;
|
|
758
838
|
const siteUrl = config.siteUrl.replace(/\/$/, "");
|
|
759
|
-
return /* @__PURE__ */
|
|
839
|
+
return /* @__PURE__ */ jsxs11("div", { children: [
|
|
760
840
|
/* @__PURE__ */ jsx11(
|
|
761
841
|
BreadcrumbSchema,
|
|
762
842
|
{
|
|
@@ -767,7 +847,7 @@ function CategoryArticlesPage({ category, articles, config }) {
|
|
|
767
847
|
]
|
|
768
848
|
}
|
|
769
849
|
),
|
|
770
|
-
/* @__PURE__ */
|
|
850
|
+
/* @__PURE__ */ jsxs11(
|
|
771
851
|
"section",
|
|
772
852
|
{
|
|
773
853
|
style: {
|
|
@@ -791,7 +871,7 @@ function CategoryArticlesPage({ category, articles, config }) {
|
|
|
791
871
|
}
|
|
792
872
|
),
|
|
793
873
|
/* @__PURE__ */ jsx11("div", { style: { position: "absolute", inset: 0, backgroundColor: "rgba(0,0,0,0.6)" } }),
|
|
794
|
-
/* @__PURE__ */
|
|
874
|
+
/* @__PURE__ */ jsxs11(
|
|
795
875
|
"div",
|
|
796
876
|
{
|
|
797
877
|
style: {
|
|
@@ -805,7 +885,7 @@ function CategoryArticlesPage({ category, articles, config }) {
|
|
|
805
885
|
/* @__PURE__ */ jsx11("p", { className: "text-sm font-semibold uppercase tracking-widest mb-3 opacity-80", children: "Category" }),
|
|
806
886
|
/* @__PURE__ */ jsx11("h1", { className: "text-4xl md:text-5xl font-bold mb-3", children: categoryName }),
|
|
807
887
|
description.long && /* @__PURE__ */ jsx11("p", { className: "text-lg opacity-90 max-w-2xl mx-auto mt-2", children: description.long }),
|
|
808
|
-
/* @__PURE__ */
|
|
888
|
+
/* @__PURE__ */ jsxs11("p", { className: "text-lg opacity-70 mt-2", children: [
|
|
809
889
|
articles.length,
|
|
810
890
|
" article",
|
|
811
891
|
articles.length === 1 ? "" : "s"
|
|
@@ -816,8 +896,8 @@ function CategoryArticlesPage({ category, articles, config }) {
|
|
|
816
896
|
]
|
|
817
897
|
}
|
|
818
898
|
),
|
|
819
|
-
/* @__PURE__ */ jsx11("section", { className: "py-16 bg-muted/50 flex-1", children: /* @__PURE__ */
|
|
820
|
-
/* @__PURE__ */
|
|
899
|
+
/* @__PURE__ */ jsx11("section", { className: "py-16 bg-muted/50 flex-1", children: /* @__PURE__ */ jsxs11("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: [
|
|
900
|
+
/* @__PURE__ */ jsxs11("div", { className: "mb-8 flex items-center justify-between", children: [
|
|
821
901
|
/* @__PURE__ */ jsx11(Link6, { href: "/articles", className: "text-sm text-primary hover:underline", children: "\u2190 All Articles" }),
|
|
822
902
|
/* @__PURE__ */ jsx11("p", { className: "text-sm text-muted-foreground", children: description.short })
|
|
823
903
|
] }),
|
|
@@ -829,7 +909,7 @@ function CategoryArticlesPage({ category, articles, config }) {
|
|
|
829
909
|
// src/ArticleSocialShare.tsx
|
|
830
910
|
import { useState as useState4 } from "react";
|
|
831
911
|
import { Share2, Copy, Check, Mail, MessageCircle, Users, FileText } from "lucide-react";
|
|
832
|
-
import { jsx as jsx12, jsxs as
|
|
912
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
833
913
|
function ArticleSocialShare({ title, url, excerpt, shareMessage }) {
|
|
834
914
|
const [copied, setCopied] = useState4(false);
|
|
835
915
|
const encodedTitle = encodeURIComponent(title);
|
|
@@ -853,40 +933,40 @@ function ArticleSocialShare({ title, url, excerpt, shareMessage }) {
|
|
|
853
933
|
}
|
|
854
934
|
});
|
|
855
935
|
const openShareWindow = (shareUrl) => {
|
|
856
|
-
|
|
936
|
+
globalThis.open(shareUrl, "_blank", "width=600,height=400,scrollbars=yes,resizable=yes");
|
|
857
937
|
};
|
|
858
938
|
const btnClass = "inline-flex items-center gap-2 px-3 py-1.5 text-sm rounded-md border border-border bg-background text-foreground hover:bg-primary/10 hover:border-primary hover:text-primary transition-colors cursor-pointer";
|
|
859
|
-
return /* @__PURE__ */
|
|
860
|
-
/* @__PURE__ */
|
|
939
|
+
return /* @__PURE__ */ jsxs12("div", { className: "border-t border-border pt-8 mt-8", children: [
|
|
940
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2 mb-4", children: [
|
|
861
941
|
/* @__PURE__ */ jsx12(Share2, { className: "h-5 w-5 text-muted-foreground" }),
|
|
862
942
|
/* @__PURE__ */ jsx12("h3", { className: "text-lg font-semibold text-foreground", children: "Share this article" })
|
|
863
943
|
] }),
|
|
864
|
-
/* @__PURE__ */
|
|
865
|
-
/* @__PURE__ */
|
|
944
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap gap-2", children: [
|
|
945
|
+
/* @__PURE__ */ jsxs12("button", { className: btnClass, onClick: () => openShareWindow(shareLinks.linkedin), children: [
|
|
866
946
|
/* @__PURE__ */ jsx12(Users, { className: "h-4 w-4" }),
|
|
867
947
|
"LinkedIn"
|
|
868
948
|
] }),
|
|
869
|
-
/* @__PURE__ */
|
|
949
|
+
/* @__PURE__ */ jsxs12("button", { className: btnClass, onClick: () => openShareWindow(shareLinks.facebook), children: [
|
|
870
950
|
/* @__PURE__ */ jsx12("span", { className: "text-xs font-bold", children: "f" }),
|
|
871
951
|
" Facebook"
|
|
872
952
|
] }),
|
|
873
|
-
/* @__PURE__ */
|
|
953
|
+
/* @__PURE__ */ jsxs12("button", { className: btnClass, onClick: () => openShareWindow(shareLinks.twitter), children: [
|
|
874
954
|
/* @__PURE__ */ jsx12(MessageCircle, { className: "h-4 w-4" }),
|
|
875
955
|
"Twitter"
|
|
876
956
|
] }),
|
|
877
|
-
/* @__PURE__ */
|
|
957
|
+
/* @__PURE__ */ jsxs12("button", { className: btnClass, onClick: () => openShareWindow(shareLinks.reddit), children: [
|
|
878
958
|
/* @__PURE__ */ jsx12(FileText, { className: "h-4 w-4" }),
|
|
879
959
|
"Reddit"
|
|
880
960
|
] }),
|
|
881
|
-
/* @__PURE__ */
|
|
961
|
+
/* @__PURE__ */ jsxs12("button", { className: btnClass, onClick: () => openShareWindow(shareLinks.whatsapp), children: [
|
|
882
962
|
/* @__PURE__ */ jsx12(MessageCircle, { className: "h-4 w-4" }),
|
|
883
963
|
"WhatsApp"
|
|
884
964
|
] }),
|
|
885
|
-
/* @__PURE__ */
|
|
965
|
+
/* @__PURE__ */ jsxs12("button", { className: btnClass, onClick: () => openShareWindow(shareLinks.telegram), children: [
|
|
886
966
|
/* @__PURE__ */ jsx12(MessageCircle, { className: "h-4 w-4" }),
|
|
887
967
|
"Telegram"
|
|
888
968
|
] }),
|
|
889
|
-
/* @__PURE__ */
|
|
969
|
+
/* @__PURE__ */ jsxs12(
|
|
890
970
|
"button",
|
|
891
971
|
{
|
|
892
972
|
className: btnClass,
|
|
@@ -899,7 +979,7 @@ function ArticleSocialShare({ title, url, excerpt, shareMessage }) {
|
|
|
899
979
|
]
|
|
900
980
|
}
|
|
901
981
|
),
|
|
902
|
-
/* @__PURE__ */
|
|
982
|
+
/* @__PURE__ */ jsxs12("button", { className: btnClass, onClick: copyToClipboard, children: [
|
|
903
983
|
copied ? /* @__PURE__ */ jsx12(Check, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx12(Copy, { className: "h-4 w-4" }),
|
|
904
984
|
copied ? "Copied!" : "Copy Link"
|
|
905
985
|
] })
|
|
@@ -911,34 +991,34 @@ function ArticleSocialShare({ title, url, excerpt, shareMessage }) {
|
|
|
911
991
|
// src/ArticleNavigation.tsx
|
|
912
992
|
import Link7 from "next/link";
|
|
913
993
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
914
|
-
import { jsx as jsx13, jsxs as
|
|
994
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
915
995
|
function truncateTitle(title, maxLength = 60) {
|
|
916
996
|
return title.length > maxLength ? `${title.substring(0, maxLength)}...` : title;
|
|
917
997
|
}
|
|
918
998
|
function ArticleNavigation({ previous, next, basePath }) {
|
|
919
999
|
if (!previous && !next) return null;
|
|
920
|
-
return /* @__PURE__ */ jsx13("nav", { className: "mt-12 pt-8 border-t border-border", "aria-label": "Article navigation", children: /* @__PURE__ */
|
|
921
|
-
/* @__PURE__ */ jsx13("div", { className: "flex-1 min-w-0", children: previous && /* @__PURE__ */
|
|
1000
|
+
return /* @__PURE__ */ jsx13("nav", { className: "mt-12 pt-8 border-t border-border", "aria-label": "Article navigation", children: /* @__PURE__ */ jsxs13("div", { className: "flex justify-between gap-4", children: [
|
|
1001
|
+
/* @__PURE__ */ jsx13("div", { className: "flex-1 min-w-0", children: previous && /* @__PURE__ */ jsxs13(
|
|
922
1002
|
Link7,
|
|
923
1003
|
{
|
|
924
1004
|
href: `${basePath}/${previous.slug}`,
|
|
925
1005
|
className: "group flex items-center gap-3 p-4 rounded-lg border border-border hover:border-primary/20 hover:bg-muted/50 transition-colors",
|
|
926
1006
|
children: [
|
|
927
1007
|
/* @__PURE__ */ jsx13(ChevronLeft, { className: "h-5 w-5 text-muted-foreground group-hover:text-primary shrink-0" }),
|
|
928
|
-
/* @__PURE__ */
|
|
1008
|
+
/* @__PURE__ */ jsxs13("div", { className: "min-w-0 flex-1", children: [
|
|
929
1009
|
/* @__PURE__ */ jsx13("div", { className: "text-sm text-muted-foreground mb-1", children: "Previous Article" }),
|
|
930
1010
|
/* @__PURE__ */ jsx13("div", { className: "font-medium text-foreground truncate", title: previous.title, children: truncateTitle(previous.title) })
|
|
931
1011
|
] })
|
|
932
1012
|
]
|
|
933
1013
|
}
|
|
934
1014
|
) }),
|
|
935
|
-
/* @__PURE__ */ jsx13("div", { className: "flex-1 min-w-0", children: next && /* @__PURE__ */
|
|
1015
|
+
/* @__PURE__ */ jsx13("div", { className: "flex-1 min-w-0", children: next && /* @__PURE__ */ jsxs13(
|
|
936
1016
|
Link7,
|
|
937
1017
|
{
|
|
938
1018
|
href: `${basePath}/${next.slug}`,
|
|
939
1019
|
className: "group flex items-center justify-end gap-3 p-4 rounded-lg border border-border hover:border-primary/20 hover:bg-muted/50 transition-colors",
|
|
940
1020
|
children: [
|
|
941
|
-
/* @__PURE__ */
|
|
1021
|
+
/* @__PURE__ */ jsxs13("div", { className: "min-w-0 flex-1 text-right", children: [
|
|
942
1022
|
/* @__PURE__ */ jsx13("div", { className: "text-sm text-muted-foreground mb-1", children: "Next Article" }),
|
|
943
1023
|
/* @__PURE__ */ jsx13("div", { className: "font-medium text-foreground truncate", title: next.title, children: truncateTitle(next.title) })
|
|
944
1024
|
] }),
|
|
@@ -949,13 +1029,60 @@ function ArticleNavigation({ previous, next, basePath }) {
|
|
|
949
1029
|
] }) });
|
|
950
1030
|
}
|
|
951
1031
|
|
|
1032
|
+
// src/ArticleTOC.tsx
|
|
1033
|
+
import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1034
|
+
function ArticleTOC({ toc, className }) {
|
|
1035
|
+
if (!toc.length) return null;
|
|
1036
|
+
return /* @__PURE__ */ jsxs14(
|
|
1037
|
+
"nav",
|
|
1038
|
+
{
|
|
1039
|
+
"aria-label": "Table of contents",
|
|
1040
|
+
className: `mb-8 rounded-lg border border-border bg-muted/40 px-6 py-4 ${className != null ? className : ""}`,
|
|
1041
|
+
children: [
|
|
1042
|
+
/* @__PURE__ */ jsx14("p", { className: "mb-3 text-sm font-semibold uppercase tracking-wide text-muted-foreground", children: "On this page" }),
|
|
1043
|
+
/* @__PURE__ */ jsx14("ul", { className: "space-y-1 text-sm", children: toc.map((item) => /* @__PURE__ */ jsx14("li", { style: { paddingLeft: `${Math.max(0, item.depth - 2) * 1}rem` }, children: /* @__PURE__ */ jsx14(
|
|
1044
|
+
"a",
|
|
1045
|
+
{
|
|
1046
|
+
href: `#${item.id}`,
|
|
1047
|
+
className: "text-muted-foreground hover:text-foreground transition-colors",
|
|
1048
|
+
children: item.text
|
|
1049
|
+
}
|
|
1050
|
+
) }, item.id)) })
|
|
1051
|
+
]
|
|
1052
|
+
}
|
|
1053
|
+
);
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
// src/ScrollToTop.tsx
|
|
1057
|
+
import { useEffect as useEffect4, useState as useState5 } from "react";
|
|
1058
|
+
import { ArrowUp } from "lucide-react";
|
|
1059
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
1060
|
+
function ScrollToTop() {
|
|
1061
|
+
const [visible, setVisible] = useState5(false);
|
|
1062
|
+
useEffect4(() => {
|
|
1063
|
+
const onScroll = () => setVisible(globalThis.scrollY > 300);
|
|
1064
|
+
globalThis.addEventListener("scroll", onScroll, { passive: true });
|
|
1065
|
+
return () => globalThis.removeEventListener("scroll", onScroll);
|
|
1066
|
+
}, []);
|
|
1067
|
+
if (!visible) return null;
|
|
1068
|
+
return /* @__PURE__ */ jsx15(
|
|
1069
|
+
"button",
|
|
1070
|
+
{
|
|
1071
|
+
"aria-label": "Scroll to top",
|
|
1072
|
+
onClick: () => globalThis.scrollTo({ top: 0, behavior: "smooth" }),
|
|
1073
|
+
className: "fixed bottom-8 right-8 z-50 rounded-full bg-primary p-2 shadow-md text-primary-foreground hover:bg-primary/90 transition-colors",
|
|
1074
|
+
children: /* @__PURE__ */ jsx15(ArrowUp, { className: "h-5 w-5" })
|
|
1075
|
+
}
|
|
1076
|
+
);
|
|
1077
|
+
}
|
|
1078
|
+
|
|
952
1079
|
// src/CommentsSection.tsx
|
|
953
1080
|
import { useSession, signIn } from "next-auth/react";
|
|
954
|
-
import { useCallback as useCallback2, useEffect as
|
|
1081
|
+
import { useCallback as useCallback2, useEffect as useEffect5, useState as useState8 } from "react";
|
|
955
1082
|
|
|
956
1083
|
// src/CommentForm.tsx
|
|
957
|
-
import { useState as
|
|
958
|
-
import { jsx as
|
|
1084
|
+
import { useState as useState6 } from "react";
|
|
1085
|
+
import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
959
1086
|
var MAX_LENGTH = 2e3;
|
|
960
1087
|
var WARN_THRESHOLD = 1800;
|
|
961
1088
|
function submitLabel(submitting, parentId) {
|
|
@@ -963,9 +1090,9 @@ function submitLabel(submitting, parentId) {
|
|
|
963
1090
|
return parentId ? "Reply" : "Post comment";
|
|
964
1091
|
}
|
|
965
1092
|
function CommentForm({ articleSlug, parentId, onSuccess, onCancel }) {
|
|
966
|
-
const [body, setBody] =
|
|
967
|
-
const [submitting, setSubmitting] =
|
|
968
|
-
const [error, setError] =
|
|
1093
|
+
const [body, setBody] = useState6("");
|
|
1094
|
+
const [submitting, setSubmitting] = useState6(false);
|
|
1095
|
+
const [error, setError] = useState6(null);
|
|
969
1096
|
const remaining = MAX_LENGTH - body.length;
|
|
970
1097
|
function handleSubmit(e) {
|
|
971
1098
|
return __async(this, null, function* () {
|
|
@@ -994,8 +1121,8 @@ function CommentForm({ articleSlug, parentId, onSuccess, onCancel }) {
|
|
|
994
1121
|
}
|
|
995
1122
|
});
|
|
996
1123
|
}
|
|
997
|
-
return /* @__PURE__ */
|
|
998
|
-
/* @__PURE__ */
|
|
1124
|
+
return /* @__PURE__ */ jsxs15("form", { onSubmit: handleSubmit, className: "space-y-2", children: [
|
|
1125
|
+
/* @__PURE__ */ jsx16(
|
|
999
1126
|
"textarea",
|
|
1000
1127
|
{
|
|
1001
1128
|
value: body,
|
|
@@ -1008,13 +1135,13 @@ function CommentForm({ articleSlug, parentId, onSuccess, onCancel }) {
|
|
|
1008
1135
|
"aria-label": parentId ? "Reply text" : "Comment text"
|
|
1009
1136
|
}
|
|
1010
1137
|
),
|
|
1011
|
-
remaining <= MAX_LENGTH - WARN_THRESHOLD && /* @__PURE__ */
|
|
1138
|
+
remaining <= MAX_LENGTH - WARN_THRESHOLD && /* @__PURE__ */ jsxs15("p", { className: `text-xs ${remaining < 0 ? "text-destructive" : "text-muted-foreground"}`, children: [
|
|
1012
1139
|
remaining,
|
|
1013
1140
|
" characters remaining"
|
|
1014
1141
|
] }),
|
|
1015
|
-
error && /* @__PURE__ */
|
|
1016
|
-
/* @__PURE__ */
|
|
1017
|
-
/* @__PURE__ */
|
|
1142
|
+
error && /* @__PURE__ */ jsx16("p", { className: "text-xs text-destructive", children: error }),
|
|
1143
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex gap-2", children: [
|
|
1144
|
+
/* @__PURE__ */ jsx16(
|
|
1018
1145
|
"button",
|
|
1019
1146
|
{
|
|
1020
1147
|
type: "submit",
|
|
@@ -1023,7 +1150,7 @@ function CommentForm({ articleSlug, parentId, onSuccess, onCancel }) {
|
|
|
1023
1150
|
children: submitLabel(submitting, parentId)
|
|
1024
1151
|
}
|
|
1025
1152
|
),
|
|
1026
|
-
onCancel && /* @__PURE__ */
|
|
1153
|
+
onCancel && /* @__PURE__ */ jsx16(
|
|
1027
1154
|
"button",
|
|
1028
1155
|
{
|
|
1029
1156
|
type: "button",
|
|
@@ -1037,8 +1164,8 @@ function CommentForm({ articleSlug, parentId, onSuccess, onCancel }) {
|
|
|
1037
1164
|
}
|
|
1038
1165
|
|
|
1039
1166
|
// src/CommentItem.tsx
|
|
1040
|
-
import { useState as
|
|
1041
|
-
import { Fragment, jsx as
|
|
1167
|
+
import { useState as useState7 } from "react";
|
|
1168
|
+
import { Fragment as Fragment2, jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1042
1169
|
function relativeTime(iso) {
|
|
1043
1170
|
const diff = Date.now() - new Date(iso).getTime();
|
|
1044
1171
|
const minutes = Math.floor(diff / 6e4);
|
|
@@ -1059,8 +1186,8 @@ function CommentItem({
|
|
|
1059
1186
|
isReply = false,
|
|
1060
1187
|
onRefresh
|
|
1061
1188
|
}) {
|
|
1062
|
-
const [showReplyForm, setShowReplyForm] =
|
|
1063
|
-
const [deleting, setDeleting] =
|
|
1189
|
+
const [showReplyForm, setShowReplyForm] = useState7(false);
|
|
1190
|
+
const [deleting, setDeleting] = useState7(false);
|
|
1064
1191
|
const replies = "replies" in comment ? comment.replies : [];
|
|
1065
1192
|
const canReply = !isReply && !!currentUserId && !comment.isDeleted;
|
|
1066
1193
|
const canDelete = !!currentUserId && currentUserId === comment.authorId && !comment.isDeleted;
|
|
@@ -1076,15 +1203,15 @@ function CommentItem({
|
|
|
1076
1203
|
}
|
|
1077
1204
|
});
|
|
1078
1205
|
}
|
|
1079
|
-
return /* @__PURE__ */
|
|
1080
|
-
/* @__PURE__ */
|
|
1081
|
-
/* @__PURE__ */
|
|
1082
|
-
/* @__PURE__ */
|
|
1083
|
-
/* @__PURE__ */
|
|
1206
|
+
return /* @__PURE__ */ jsxs16("div", { className: `${isReply ? "ml-8 border-l-2 border-border pl-4" : ""}`, children: [
|
|
1207
|
+
/* @__PURE__ */ jsx17("div", { className: "rounded-lg bg-muted/40 p-3 space-y-1", children: comment.isDeleted ? /* @__PURE__ */ jsx17("p", { className: "text-sm italic text-muted-foreground", children: "Comment removed" }) : /* @__PURE__ */ jsxs16(Fragment2, { children: [
|
|
1208
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex items-center justify-between gap-2", children: [
|
|
1209
|
+
/* @__PURE__ */ jsx17("span", { className: "text-sm font-medium text-foreground", children: comment.authorName }),
|
|
1210
|
+
/* @__PURE__ */ jsx17("span", { className: "text-xs text-muted-foreground", children: relativeTime(comment.createdAt) })
|
|
1084
1211
|
] }),
|
|
1085
|
-
/* @__PURE__ */
|
|
1086
|
-
/* @__PURE__ */
|
|
1087
|
-
canReply && /* @__PURE__ */
|
|
1212
|
+
/* @__PURE__ */ jsx17("p", { className: "text-sm text-foreground whitespace-pre-wrap break-words", children: comment.body }),
|
|
1213
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex gap-3 pt-1", children: [
|
|
1214
|
+
canReply && /* @__PURE__ */ jsx17(
|
|
1088
1215
|
"button",
|
|
1089
1216
|
{
|
|
1090
1217
|
onClick: () => setShowReplyForm((v) => !v),
|
|
@@ -1092,7 +1219,7 @@ function CommentItem({
|
|
|
1092
1219
|
children: showReplyForm ? "Cancel" : "Reply"
|
|
1093
1220
|
}
|
|
1094
1221
|
),
|
|
1095
|
-
canDelete && /* @__PURE__ */
|
|
1222
|
+
canDelete && /* @__PURE__ */ jsx17(
|
|
1096
1223
|
"button",
|
|
1097
1224
|
{
|
|
1098
1225
|
onClick: handleDelete,
|
|
@@ -1103,7 +1230,7 @@ function CommentItem({
|
|
|
1103
1230
|
)
|
|
1104
1231
|
] })
|
|
1105
1232
|
] }) }),
|
|
1106
|
-
showReplyForm && /* @__PURE__ */
|
|
1233
|
+
showReplyForm && /* @__PURE__ */ jsx17("div", { className: "mt-2 ml-2", children: /* @__PURE__ */ jsx17(
|
|
1107
1234
|
CommentForm,
|
|
1108
1235
|
{
|
|
1109
1236
|
articleSlug,
|
|
@@ -1115,7 +1242,7 @@ function CommentItem({
|
|
|
1115
1242
|
onCancel: () => setShowReplyForm(false)
|
|
1116
1243
|
}
|
|
1117
1244
|
) }),
|
|
1118
|
-
replies.length > 0 && /* @__PURE__ */
|
|
1245
|
+
replies.length > 0 && /* @__PURE__ */ jsx17("div", { className: "mt-2 space-y-2", children: replies.map((reply) => /* @__PURE__ */ jsx17(
|
|
1119
1246
|
CommentItem,
|
|
1120
1247
|
{
|
|
1121
1248
|
comment: __spreadProps(__spreadValues({}, reply), { replies: [] }),
|
|
@@ -1130,7 +1257,7 @@ function CommentItem({
|
|
|
1130
1257
|
}
|
|
1131
1258
|
|
|
1132
1259
|
// src/CommentThread.tsx
|
|
1133
|
-
import { jsx as
|
|
1260
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
1134
1261
|
function CommentThread({
|
|
1135
1262
|
comments,
|
|
1136
1263
|
articleSlug,
|
|
@@ -1138,9 +1265,9 @@ function CommentThread({
|
|
|
1138
1265
|
onRefresh
|
|
1139
1266
|
}) {
|
|
1140
1267
|
if (comments.length === 0) {
|
|
1141
|
-
return /* @__PURE__ */
|
|
1268
|
+
return /* @__PURE__ */ jsx18("p", { className: "text-sm text-muted-foreground text-center py-6", children: "No comments yet. Be the first to share your thoughts." });
|
|
1142
1269
|
}
|
|
1143
|
-
return /* @__PURE__ */
|
|
1270
|
+
return /* @__PURE__ */ jsx18("div", { className: "space-y-4", children: comments.map((comment) => /* @__PURE__ */ jsx18(
|
|
1144
1271
|
CommentItem,
|
|
1145
1272
|
{
|
|
1146
1273
|
comment,
|
|
@@ -1153,13 +1280,13 @@ function CommentThread({
|
|
|
1153
1280
|
}
|
|
1154
1281
|
|
|
1155
1282
|
// src/CommentsSection.tsx
|
|
1156
|
-
import { jsx as
|
|
1283
|
+
import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1157
1284
|
function CommentsSection({ articleSlug, config }) {
|
|
1158
1285
|
var _a, _b, _c, _d, _e, _f;
|
|
1159
1286
|
const { data: session, status } = useSession();
|
|
1160
|
-
const [comments, setComments] =
|
|
1161
|
-
const [loading, setLoading] =
|
|
1162
|
-
const [fetchError, setFetchError] =
|
|
1287
|
+
const [comments, setComments] = useState8([]);
|
|
1288
|
+
const [loading, setLoading] = useState8(true);
|
|
1289
|
+
const [fetchError, setFetchError] = useState8(null);
|
|
1163
1290
|
const perArticleEnabled = (_b = (_a = config.perArticleOverride) == null ? void 0 : _a[articleSlug]) != null ? _b : true;
|
|
1164
1291
|
const enabled = config.enabled && perArticleEnabled;
|
|
1165
1292
|
const currentUserId = (_f = (_e = (_c = session == null ? void 0 : session.user) == null ? void 0 : _c.email) != null ? _e : (_d = session == null ? void 0 : session.user) == null ? void 0 : _d.name) != null ? _f : void 0;
|
|
@@ -1177,7 +1304,7 @@ function CommentsSection({ articleSlug, config }) {
|
|
|
1177
1304
|
setLoading(false);
|
|
1178
1305
|
}
|
|
1179
1306
|
}), [articleSlug]);
|
|
1180
|
-
|
|
1307
|
+
useEffect5(() => {
|
|
1181
1308
|
if (enabled) {
|
|
1182
1309
|
fetchComments().catch(() => void 0);
|
|
1183
1310
|
}
|
|
@@ -1185,10 +1312,10 @@ function CommentsSection({ articleSlug, config }) {
|
|
|
1185
1312
|
if (!enabled) return null;
|
|
1186
1313
|
const count = comments.length;
|
|
1187
1314
|
const label = count === 1 ? "1 comment" : `${count} comments`;
|
|
1188
|
-
return /* @__PURE__ */
|
|
1189
|
-
/* @__PURE__ */
|
|
1190
|
-
status === "authenticated" ? /* @__PURE__ */
|
|
1191
|
-
/* @__PURE__ */
|
|
1315
|
+
return /* @__PURE__ */ jsxs17("section", { "aria-label": "Comments", className: "mt-12 pt-8 border-t border-border space-y-6", children: [
|
|
1316
|
+
/* @__PURE__ */ jsx19("h2", { className: "text-xl font-semibold text-foreground", children: loading ? "Comments" : label }),
|
|
1317
|
+
status === "authenticated" ? /* @__PURE__ */ jsx19(CommentForm, { articleSlug, onSuccess: fetchComments }) : /* @__PURE__ */ jsxs17("p", { className: "text-sm text-muted-foreground", children: [
|
|
1318
|
+
/* @__PURE__ */ jsx19(
|
|
1192
1319
|
"button",
|
|
1193
1320
|
{
|
|
1194
1321
|
onClick: () => signIn(),
|
|
@@ -1199,8 +1326,8 @@ function CommentsSection({ articleSlug, config }) {
|
|
|
1199
1326
|
" ",
|
|
1200
1327
|
"to join the discussion."
|
|
1201
1328
|
] }),
|
|
1202
|
-
fetchError && /* @__PURE__ */
|
|
1203
|
-
loading ? /* @__PURE__ */
|
|
1329
|
+
fetchError && /* @__PURE__ */ jsx19("p", { className: "text-sm text-destructive", children: fetchError }),
|
|
1330
|
+
loading ? /* @__PURE__ */ jsx19("p", { className: "text-sm text-muted-foreground", children: "Loading comments\u2026" }) : /* @__PURE__ */ jsx19(
|
|
1204
1331
|
CommentThread,
|
|
1205
1332
|
{
|
|
1206
1333
|
comments,
|
|
@@ -1216,9 +1343,11 @@ export {
|
|
|
1216
1343
|
ArticleCategoryGrid,
|
|
1217
1344
|
ArticleDetailHero,
|
|
1218
1345
|
ArticleNavigation,
|
|
1346
|
+
ArticleSEO,
|
|
1219
1347
|
ArticleSchema,
|
|
1220
1348
|
ArticleSearchBar,
|
|
1221
1349
|
ArticleSocialShare,
|
|
1350
|
+
ArticleTOC,
|
|
1222
1351
|
ArticlesHero,
|
|
1223
1352
|
ArticlesPage,
|
|
1224
1353
|
BreadcrumbSchema,
|
|
@@ -1231,9 +1360,11 @@ export {
|
|
|
1231
1360
|
DEFAULT_CATEGORIES_PAGE_SIZE,
|
|
1232
1361
|
DEFAULT_LAYOUT,
|
|
1233
1362
|
DEFAULT_PAGE_SIZE,
|
|
1363
|
+
FAQPageSchema,
|
|
1234
1364
|
FeaturedArticle,
|
|
1235
1365
|
LatestArticles,
|
|
1236
1366
|
LatestArticlesSection,
|
|
1367
|
+
ScrollToTop,
|
|
1237
1368
|
useArticles
|
|
1238
1369
|
};
|
|
1239
1370
|
//# sourceMappingURL=index.js.map
|