@fullstackdatasolutions/articles 0.11.0 → 1.0.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/CHANGELOG.md +30 -0
- package/README.md +568 -6
- package/dist/index.cjs +970 -389
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +375 -21
- package/dist/index.d.ts +375 -21
- package/dist/index.js +954 -377
- package/dist/index.js.map +1 -1
- package/dist/nextjs.cjs +74 -6
- package/dist/nextjs.cjs.map +1 -1
- package/dist/nextjs.d.cts +141 -0
- package/dist/nextjs.d.ts +141 -0
- package/dist/nextjs.js +74 -6
- package/dist/nextjs.js.map +1 -1
- package/dist/server.cjs +665 -27
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +349 -3
- package/dist/server.d.ts +349 -3
- package/dist/server.js +643 -29
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
- package/src/ArticleCard.tsx +37 -1
- package/src/ArticleContent.tsx +144 -5
- package/src/ArticleDetailHero.tsx +23 -0
- package/src/ArticleNavigation.tsx +32 -1
- package/src/ArticleSchemas.tsx +43 -39
- package/src/ArticleSocialShare.tsx +54 -10
- package/src/ArticlesPage.tsx +65 -7
- package/src/AuthorArticlesPage.tsx +308 -14
- package/src/AuthorCard.tsx +1 -1
- package/src/CategoryArticlesPage.tsx +34 -2
- package/src/LatestArticles.tsx +28 -1
- package/src/LatestArticlesSection.tsx +15 -1
- package/src/PaginationNav.tsx +78 -0
- package/src/RelatedArticlesSection.tsx +55 -0
- package/src/SeriesArticlesPage.tsx +66 -0
- package/src/__tests__/ArticleCard.test.tsx +63 -3
- package/src/__tests__/ArticleContent.test.tsx +143 -0
- package/src/__tests__/ArticleDetailHero.test.tsx +30 -0
- package/src/__tests__/ArticleNavigation.test.tsx +81 -3
- package/src/__tests__/ArticleSchemas.test.tsx +155 -81
- package/src/__tests__/ArticleSocialShare.test.tsx +54 -0
- package/src/__tests__/ArticlesPage.test.tsx +148 -0
- package/src/__tests__/AuthorArticlesPage.test.tsx +304 -3
- package/src/__tests__/CategoryArticlesPage.test.tsx +116 -1
- package/src/__tests__/LatestArticles.test.tsx +52 -0
- package/src/__tests__/LatestArticlesSection.test.tsx +28 -0
- package/src/__tests__/PaginationNav.test.tsx +73 -0
- package/src/__tests__/RelatedArticlesSection.test.tsx +132 -0
- package/src/__tests__/SeriesArticlesPage.test.tsx +121 -0
- package/src/__tests__/eventTracking.test.tsx +145 -0
- package/src/__tests__/events.test.ts +82 -0
- package/src/__tests__/markdown.test.ts +78 -1
- package/src/__tests__/pagination.test.ts +178 -0
- package/src/__tests__/seoUtils-authors.test.ts +37 -0
- package/src/__tests__/seoUtils.test.ts +246 -0
- package/src/__tests__/server-articles.test.ts +356 -1
- package/src/__tests__/useArticles.test.ts +28 -0
- package/src/__tests__/validateArticles.test.ts +312 -0
- package/src/articleTypes.ts +109 -0
- package/src/articlesConfig.ts +37 -1
- package/src/eventTracking.tsx +97 -0
- package/src/events.ts +105 -0
- package/src/index.ts +26 -1
- package/src/markdown.ts +41 -0
- package/src/pagination.ts +93 -0
- package/src/seoUtils.ts +198 -11
- package/src/server-articles.ts +199 -6
- package/src/server.ts +46 -2
- package/src/useArticles.ts +10 -5
- package/src/validateArticles.ts +260 -0
package/dist/index.cjs
CHANGED
|
@@ -75,10 +75,10 @@ __export(src_exports, {
|
|
|
75
75
|
ArticleDetailHero: () => ArticleDetailHero,
|
|
76
76
|
ArticleNavigation: () => ArticleNavigation,
|
|
77
77
|
ArticleSEO: () => ArticleSEO,
|
|
78
|
-
ArticleSchema: () => ArticleSchema,
|
|
79
78
|
ArticleSearchBar: () => ArticleSearchBar,
|
|
80
79
|
ArticleSocialShare: () => ArticleSocialShare,
|
|
81
80
|
ArticleTOC: () => ArticleTOC,
|
|
81
|
+
ArticleViewTracker: () => ArticleViewTracker,
|
|
82
82
|
ArticlesHero: () => ArticlesHero,
|
|
83
83
|
ArticlesPage: () => ArticlesPage,
|
|
84
84
|
AuthorArticlesPage: () => AuthorArticlesPage,
|
|
@@ -93,6 +93,7 @@ __export(src_exports, {
|
|
|
93
93
|
CommentItem: () => CommentItem,
|
|
94
94
|
CommentThread: () => CommentThread,
|
|
95
95
|
CommentsSection: () => CommentsSection,
|
|
96
|
+
CtaViewTracker: () => CtaViewTracker,
|
|
96
97
|
DEFAULT_CATEGORIES_PAGE_SIZE: () => DEFAULT_CATEGORIES_PAGE_SIZE,
|
|
97
98
|
DEFAULT_LAYOUT: () => DEFAULT_LAYOUT,
|
|
98
99
|
DEFAULT_PAGE_SIZE: () => DEFAULT_PAGE_SIZE,
|
|
@@ -100,7 +101,10 @@ __export(src_exports, {
|
|
|
100
101
|
FeaturedArticle: () => FeaturedArticle,
|
|
101
102
|
LatestArticles: () => LatestArticles,
|
|
102
103
|
LatestArticlesSection: () => LatestArticlesSection,
|
|
104
|
+
PaginationNav: () => PaginationNav,
|
|
105
|
+
RelatedArticlesSection: () => RelatedArticlesSection,
|
|
103
106
|
ScrollToTop: () => ScrollToTop,
|
|
107
|
+
SeriesArticlesPage: () => SeriesArticlesPage,
|
|
104
108
|
breadcrumbsAreEnabled: () => breadcrumbsAreEnabled,
|
|
105
109
|
getBreadcrumbsConfig: () => getBreadcrumbsConfig,
|
|
106
110
|
useArticles: () => useArticles
|
|
@@ -297,43 +301,17 @@ function BreadcrumbSchema({ items }) {
|
|
|
297
301
|
|
|
298
302
|
// src/ArticleSchemas.tsx
|
|
299
303
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
300
|
-
function getPersonSchemas(article, authors) {
|
|
304
|
+
function getPersonSchemas(article, authors, config) {
|
|
301
305
|
let resolvedAuthors = [];
|
|
302
306
|
if (authors == null ? void 0 : authors.length) {
|
|
303
307
|
resolvedAuthors = [...authors];
|
|
304
308
|
} else if (article.author) {
|
|
305
309
|
resolvedAuthors = [{ name: article.author, slug: "", bio: "" }];
|
|
306
310
|
}
|
|
307
|
-
return resolvedAuthors.map((author) => __spreadValues(__spreadValues({
|
|
311
|
+
return resolvedAuthors.map((author) => __spreadValues(__spreadValues(__spreadValues({
|
|
308
312
|
"@type": "Person",
|
|
309
313
|
name: author.name
|
|
310
|
-
}, author.url && { url: author.url }), getAuthorSameAs(author).length > 0 && { sameAs: getAuthorSameAs(author) }));
|
|
311
|
-
}
|
|
312
|
-
function ArticleSchema({
|
|
313
|
-
article,
|
|
314
|
-
articleUrl,
|
|
315
|
-
siteName,
|
|
316
|
-
showAuthor = true,
|
|
317
|
-
authors
|
|
318
|
-
}) {
|
|
319
|
-
const personSchemas = getPersonSchemas(article, authors);
|
|
320
|
-
const schema = __spreadProps(__spreadValues(__spreadValues({
|
|
321
|
-
"@context": "https://schema.org",
|
|
322
|
-
"@type": "Article",
|
|
323
|
-
headline: article.title,
|
|
324
|
-
description: article.excerpt,
|
|
325
|
-
image: article.featuredImage
|
|
326
|
-
}, article.date && { datePublished: new Date(article.date).toISOString() }), showAuthor && personSchemas.length > 0 && { author: personSchemas }), {
|
|
327
|
-
publisher: { "@type": "Organization", name: siteName },
|
|
328
|
-
mainEntityOfPage: { "@type": "WebPage", "@id": articleUrl }
|
|
329
|
-
});
|
|
330
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
331
|
-
"script",
|
|
332
|
-
{
|
|
333
|
-
type: "application/ld+json",
|
|
334
|
-
dangerouslySetInnerHTML: { __html: JSON.stringify(schema) }
|
|
335
|
-
}
|
|
336
|
-
);
|
|
314
|
+
}, author.url && { url: author.url }), getAuthorAvatar(author, config) && { image: getAuthorAvatar(author, config) }), getAuthorSameAs(author).length > 0 && { sameAs: getAuthorSameAs(author) }));
|
|
337
315
|
}
|
|
338
316
|
function ArticleSEO({
|
|
339
317
|
article,
|
|
@@ -341,12 +319,13 @@ function ArticleSEO({
|
|
|
341
319
|
siteName,
|
|
342
320
|
siteLogo,
|
|
343
321
|
showAuthor = true,
|
|
344
|
-
authors
|
|
322
|
+
authors,
|
|
323
|
+
config
|
|
345
324
|
}) {
|
|
346
325
|
const publishedAt = article.date ? new Date(article.date).toISOString() : void 0;
|
|
347
326
|
const modifiedAt = article.lastmod ? new Date(article.lastmod).toISOString() : publishedAt;
|
|
348
|
-
const personSchemas = getPersonSchemas(article, authors);
|
|
349
|
-
const structuredData = __spreadValues(__spreadProps(__spreadValues(__spreadValues(__spreadValues({
|
|
327
|
+
const personSchemas = getPersonSchemas(article, authors, config);
|
|
328
|
+
const structuredData = __spreadValues(__spreadValues(__spreadValues(__spreadProps(__spreadValues(__spreadValues(__spreadValues({
|
|
350
329
|
"@context": "https://schema.org",
|
|
351
330
|
"@type": article.articleType || "Article",
|
|
352
331
|
mainEntityOfPage: { "@type": "WebPage", "@id": articleUrl },
|
|
@@ -357,8 +336,9 @@ function ArticleSEO({
|
|
|
357
336
|
"@type": "Organization",
|
|
358
337
|
name: siteName
|
|
359
338
|
}, siteLogo && { logo: { "@type": "ImageObject", url: siteLogo } }),
|
|
360
|
-
description: article.excerpt
|
|
361
|
-
|
|
339
|
+
description: article.excerpt,
|
|
340
|
+
articleSection: article.category
|
|
341
|
+
}), article.tags && article.tags.length > 0 && { keywords: article.tags.join(", ") }), article.wordCount !== void 0 && { wordCount: article.wordCount }), article.series && { isPartOf: { "@type": "Blog", name: article.series } });
|
|
362
342
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
363
343
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
364
344
|
"script",
|
|
@@ -426,16 +406,27 @@ function CollectionPageSchema({
|
|
|
426
406
|
title,
|
|
427
407
|
description,
|
|
428
408
|
url,
|
|
429
|
-
articleCount
|
|
409
|
+
articleCount,
|
|
410
|
+
items
|
|
430
411
|
}) {
|
|
431
|
-
const schema = {
|
|
412
|
+
const schema = __spreadValues({
|
|
432
413
|
"@context": "https://schema.org",
|
|
433
414
|
"@type": "CollectionPage",
|
|
434
415
|
name: title,
|
|
435
416
|
description,
|
|
436
417
|
url,
|
|
437
418
|
numberOfItems: articleCount
|
|
438
|
-
}
|
|
419
|
+
}, items && items.length > 0 && {
|
|
420
|
+
mainEntity: {
|
|
421
|
+
"@type": "ItemList",
|
|
422
|
+
itemListElement: items.map((item) => ({
|
|
423
|
+
"@type": "ListItem",
|
|
424
|
+
position: item.position,
|
|
425
|
+
url: item.url,
|
|
426
|
+
name: item.name
|
|
427
|
+
}))
|
|
428
|
+
}
|
|
429
|
+
});
|
|
439
430
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
440
431
|
"script",
|
|
441
432
|
{
|
|
@@ -570,20 +561,98 @@ function FeaturedArticle({ article, showAuthor = true }) {
|
|
|
570
561
|
}
|
|
571
562
|
|
|
572
563
|
// src/LatestArticlesSection.tsx
|
|
573
|
-
var
|
|
564
|
+
var import_lucide_react6 = require("lucide-react");
|
|
574
565
|
|
|
575
566
|
// src/LatestArticles.tsx
|
|
576
567
|
var import_react2 = require("react");
|
|
577
568
|
|
|
578
569
|
// src/ArticleCard.tsx
|
|
570
|
+
var import_image4 = __toESM(require("next/image"), 1);
|
|
571
|
+
var import_link6 = __toESM(require("next/link"), 1);
|
|
572
|
+
var import_lucide_react4 = require("lucide-react");
|
|
573
|
+
|
|
574
|
+
// src/AuthorCard.tsx
|
|
579
575
|
var import_image3 = __toESM(require("next/image"), 1);
|
|
580
576
|
var import_link5 = __toESM(require("next/link"), 1);
|
|
581
577
|
var import_lucide_react3 = require("lucide-react");
|
|
582
578
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
583
|
-
function
|
|
584
|
-
return
|
|
585
|
-
|
|
579
|
+
function getInitials(name) {
|
|
580
|
+
return name.split(" ").filter(Boolean).slice(0, 2).map((part) => part.charAt(0).toUpperCase()).join("");
|
|
581
|
+
}
|
|
582
|
+
function AuthorCard({
|
|
583
|
+
author,
|
|
584
|
+
linkToPage = true,
|
|
585
|
+
showBio = false,
|
|
586
|
+
showSocial = false
|
|
587
|
+
}) {
|
|
588
|
+
const avatar = getAuthorAvatar(author);
|
|
589
|
+
const name = linkToPage ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_link5.default, { href: getAuthorUrl(author), className: "font-medium text-foreground hover:text-primary", children: author.name }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "font-medium text-foreground", children: author.name });
|
|
590
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-start gap-3 rounded-lg border border-border bg-card p-4 text-card-foreground", children: [
|
|
591
|
+
avatar ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
586
592
|
import_image3.default,
|
|
593
|
+
{
|
|
594
|
+
src: avatar,
|
|
595
|
+
alt: author.name,
|
|
596
|
+
width: 48,
|
|
597
|
+
height: 48,
|
|
598
|
+
className: "h-12 w-12 rounded-full object-cover"
|
|
599
|
+
}
|
|
600
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-muted text-sm font-semibold text-muted-foreground", children: getInitials(author.name) }),
|
|
601
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "min-w-0 flex-1", children: [
|
|
602
|
+
name,
|
|
603
|
+
showBio && author.bio && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "mt-1 line-clamp-2 text-sm text-muted-foreground", children: author.bio }),
|
|
604
|
+
showSocial && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AuthorSocialLinks, { author })
|
|
605
|
+
] })
|
|
606
|
+
] });
|
|
607
|
+
}
|
|
608
|
+
var SOCIAL_ICONS = {
|
|
609
|
+
Website: import_lucide_react3.Globe,
|
|
610
|
+
Facebook: import_lucide_react3.Facebook,
|
|
611
|
+
Twitter: import_lucide_react3.Twitter,
|
|
612
|
+
X: import_lucide_react3.Twitter,
|
|
613
|
+
LinkedIn: import_lucide_react3.Linkedin,
|
|
614
|
+
Instagram: import_lucide_react3.Instagram,
|
|
615
|
+
YouTube: import_lucide_react3.Youtube,
|
|
616
|
+
GitHub: import_lucide_react3.Github,
|
|
617
|
+
Newsletter: import_lucide_react3.Mail
|
|
618
|
+
};
|
|
619
|
+
function getSocialIcon(label) {
|
|
620
|
+
var _a;
|
|
621
|
+
return (_a = SOCIAL_ICONS[label]) != null ? _a : import_lucide_react3.MessageCircle;
|
|
622
|
+
}
|
|
623
|
+
function AuthorSocialLinks({ author }) {
|
|
624
|
+
const links = getAuthorSocialLinks(author);
|
|
625
|
+
if (links.length === 0) return null;
|
|
626
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "mt-3 flex items-center gap-2", children: links.map(({ href, label }) => {
|
|
627
|
+
const Icon = getSocialIcon(label);
|
|
628
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
629
|
+
import_link5.default,
|
|
630
|
+
{
|
|
631
|
+
href,
|
|
632
|
+
className: "inline-flex h-8 w-8 items-center justify-center rounded-md border border-border text-muted-foreground hover:bg-accent hover:text-accent-foreground",
|
|
633
|
+
"aria-label": `${author.name} on ${label}`,
|
|
634
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { className: "h-4 w-4" })
|
|
635
|
+
},
|
|
636
|
+
`${label}-${href}`
|
|
637
|
+
);
|
|
638
|
+
}) });
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// src/events.ts
|
|
642
|
+
function emitArticleEvent(handler, event) {
|
|
643
|
+
if (!handler) return;
|
|
644
|
+
try {
|
|
645
|
+
handler(__spreadProps(__spreadValues({}, event), { timestamp: Date.now() }));
|
|
646
|
+
} catch (e) {
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// src/ArticleCard.tsx
|
|
651
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
652
|
+
function ArticleCard({ article, config }) {
|
|
653
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "rounded-lg border border-border bg-card text-card-foreground shadow-sm hover:shadow-lg transition-shadow duration-300", children: [
|
|
654
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "p-0", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
655
|
+
import_image4.default,
|
|
587
656
|
{
|
|
588
657
|
src: article.featuredImage,
|
|
589
658
|
alt: article.title,
|
|
@@ -592,35 +661,67 @@ function ArticleCard({ article }) {
|
|
|
592
661
|
height: 200
|
|
593
662
|
}
|
|
594
663
|
) }),
|
|
595
|
-
/* @__PURE__ */ (0,
|
|
596
|
-
/* @__PURE__ */ (0,
|
|
597
|
-
/* @__PURE__ */ (0,
|
|
598
|
-
|
|
664
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "p-6", children: [
|
|
665
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "flex gap-2 mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "bg-primary/10 text-primary text-xs font-medium px-2 py-1 rounded", children: article.category }) }),
|
|
666
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { className: "text-lg font-semibold leading-none tracking-tight mb-2", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
667
|
+
import_link6.default,
|
|
599
668
|
{
|
|
600
669
|
href: `/articles/${article.slug}`,
|
|
601
670
|
className: "hover:text-indigo-600 transition-colors",
|
|
602
671
|
children: article.title
|
|
603
672
|
}
|
|
604
673
|
) }),
|
|
605
|
-
/* @__PURE__ */ (0,
|
|
606
|
-
/* @__PURE__ */ (0,
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
674
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-muted-foreground mb-4 line-clamp-3", children: article.excerpt }),
|
|
675
|
+
article.authorSlug && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
676
|
+
import_link6.default,
|
|
677
|
+
{
|
|
678
|
+
href: `/articles/authors/${article.authorSlug}`,
|
|
679
|
+
className: "mb-4 flex items-center gap-2 text-sm text-muted-foreground hover:text-primary transition-colors",
|
|
680
|
+
onClick: () => emitArticleEvent(config == null ? void 0 : config.onEvent, {
|
|
681
|
+
name: "author_clicked",
|
|
682
|
+
articleSlug: article.slug,
|
|
683
|
+
authorSlug: article.authorSlug
|
|
684
|
+
}),
|
|
685
|
+
children: [
|
|
686
|
+
article.authorAvatar ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
687
|
+
import_image4.default,
|
|
688
|
+
{
|
|
689
|
+
src: article.authorAvatar,
|
|
690
|
+
alt: "",
|
|
691
|
+
width: 24,
|
|
692
|
+
height: 24,
|
|
693
|
+
className: "h-6 w-6 rounded-full object-cover"
|
|
694
|
+
}
|
|
695
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
696
|
+
"span",
|
|
697
|
+
{
|
|
698
|
+
"aria-hidden": "true",
|
|
699
|
+
className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-muted text-[10px] font-semibold text-muted-foreground",
|
|
700
|
+
children: getInitials(article.author)
|
|
701
|
+
}
|
|
702
|
+
),
|
|
703
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: article.author })
|
|
704
|
+
]
|
|
705
|
+
}
|
|
706
|
+
),
|
|
707
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center justify-between text-sm text-muted-foreground border-t pt-4", children: [
|
|
708
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
709
|
+
article.date && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
710
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react4.Calendar, { className: "h-3 w-3" }),
|
|
711
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: article.date })
|
|
611
712
|
] }),
|
|
612
|
-
/* @__PURE__ */ (0,
|
|
613
|
-
/* @__PURE__ */ (0,
|
|
614
|
-
/* @__PURE__ */ (0,
|
|
713
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
714
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react4.Clock, { className: "h-3 w-3" }),
|
|
715
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: article.readTime })
|
|
615
716
|
] })
|
|
616
717
|
] }),
|
|
617
|
-
/* @__PURE__ */ (0,
|
|
618
|
-
|
|
718
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
719
|
+
import_link6.default,
|
|
619
720
|
{
|
|
620
721
|
href: `/articles/${article.slug}`,
|
|
621
722
|
className: "inline-flex items-center justify-center h-8 w-8 p-0 rounded-md hover:bg-accent transition-colors",
|
|
622
723
|
"aria-label": `Read ${article.title}`,
|
|
623
|
-
children: /* @__PURE__ */ (0,
|
|
724
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react4.ArrowRight, { className: "h-4 w-4" })
|
|
624
725
|
}
|
|
625
726
|
)
|
|
626
727
|
] })
|
|
@@ -628,18 +729,114 @@ function ArticleCard({ article }) {
|
|
|
628
729
|
] });
|
|
629
730
|
}
|
|
630
731
|
|
|
732
|
+
// src/PaginationNav.tsx
|
|
733
|
+
var import_link7 = __toESM(require("next/link"), 1);
|
|
734
|
+
var import_lucide_react5 = require("lucide-react");
|
|
735
|
+
|
|
736
|
+
// src/pagination.ts
|
|
737
|
+
function buildPageUrl(basePath, page) {
|
|
738
|
+
const base = basePath.replace(/\/$/, "");
|
|
739
|
+
return page > 1 ? `${base}/page/${page}` : base;
|
|
740
|
+
}
|
|
741
|
+
function buildPaginationLinks(basePath, page, totalPages) {
|
|
742
|
+
return {
|
|
743
|
+
canonicalUrl: buildPageUrl(basePath, page),
|
|
744
|
+
prevUrl: page > 1 ? buildPageUrl(basePath, page - 1) : null,
|
|
745
|
+
nextUrl: page < totalPages ? buildPageUrl(basePath, page + 1) : null
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// src/PaginationNav.tsx
|
|
750
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
751
|
+
function PaginationNav({ basePath, page, totalPages }) {
|
|
752
|
+
if (totalPages <= 1) return null;
|
|
753
|
+
const { prevUrl, nextUrl } = buildPaginationLinks(basePath, page, totalPages);
|
|
754
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
755
|
+
"nav",
|
|
756
|
+
{
|
|
757
|
+
className: "mt-10 flex items-center justify-center gap-4",
|
|
758
|
+
"aria-label": "Article listing pagination",
|
|
759
|
+
children: [
|
|
760
|
+
prevUrl && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("link", { rel: "prev", href: prevUrl }),
|
|
761
|
+
nextUrl && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("link", { rel: "next", href: nextUrl }),
|
|
762
|
+
prevUrl ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
763
|
+
import_link7.default,
|
|
764
|
+
{
|
|
765
|
+
href: prevUrl,
|
|
766
|
+
className: "inline-flex items-center gap-1 px-4 py-2 border border-input bg-background hover:bg-accent rounded-md font-medium text-sm transition-colors",
|
|
767
|
+
children: [
|
|
768
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react5.ChevronLeft, { className: "h-4 w-4", "aria-hidden": "true" }),
|
|
769
|
+
"Previous"
|
|
770
|
+
]
|
|
771
|
+
}
|
|
772
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
773
|
+
"span",
|
|
774
|
+
{
|
|
775
|
+
"aria-hidden": "true",
|
|
776
|
+
className: "inline-flex items-center gap-1 px-4 py-2 rounded-md font-medium text-sm text-muted-foreground opacity-50",
|
|
777
|
+
children: [
|
|
778
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react5.ChevronLeft, { className: "h-4 w-4" }),
|
|
779
|
+
"Previous"
|
|
780
|
+
]
|
|
781
|
+
}
|
|
782
|
+
),
|
|
783
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "text-sm text-muted-foreground", children: [
|
|
784
|
+
"Page ",
|
|
785
|
+
page,
|
|
786
|
+
" of ",
|
|
787
|
+
totalPages
|
|
788
|
+
] }),
|
|
789
|
+
nextUrl ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
790
|
+
import_link7.default,
|
|
791
|
+
{
|
|
792
|
+
href: nextUrl,
|
|
793
|
+
className: "inline-flex items-center gap-1 px-4 py-2 border border-input bg-background hover:bg-accent rounded-md font-medium text-sm transition-colors",
|
|
794
|
+
children: [
|
|
795
|
+
"Next",
|
|
796
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react5.ChevronRight, { className: "h-4 w-4", "aria-hidden": "true" })
|
|
797
|
+
]
|
|
798
|
+
}
|
|
799
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
800
|
+
"span",
|
|
801
|
+
{
|
|
802
|
+
"aria-hidden": "true",
|
|
803
|
+
className: "inline-flex items-center gap-1 px-4 py-2 rounded-md font-medium text-sm text-muted-foreground opacity-50",
|
|
804
|
+
children: [
|
|
805
|
+
"Next",
|
|
806
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_lucide_react5.ChevronRight, { className: "h-4 w-4" })
|
|
807
|
+
]
|
|
808
|
+
}
|
|
809
|
+
)
|
|
810
|
+
]
|
|
811
|
+
}
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
|
|
631
815
|
// src/LatestArticles.tsx
|
|
632
|
-
var
|
|
633
|
-
function LatestArticles({ articles, pageSize }) {
|
|
816
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
817
|
+
function LatestArticles({ articles, pageSize, pagination }) {
|
|
634
818
|
const [visibleCount, setVisibleCount] = (0, import_react2.useState)(pageSize);
|
|
635
819
|
(0, import_react2.useEffect)(() => {
|
|
636
820
|
setVisibleCount(pageSize);
|
|
637
821
|
}, [articles, pageSize]);
|
|
822
|
+
if (pagination) {
|
|
823
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
|
|
824
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "grid md:grid-cols-2 lg:grid-cols-3 gap-8", children: articles.map((article) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ArticleCard, { article }, article.slug)) }),
|
|
825
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
826
|
+
PaginationNav,
|
|
827
|
+
{
|
|
828
|
+
basePath: pagination.basePath,
|
|
829
|
+
page: pagination.page,
|
|
830
|
+
totalPages: pagination.totalPages
|
|
831
|
+
}
|
|
832
|
+
)
|
|
833
|
+
] });
|
|
834
|
+
}
|
|
638
835
|
const visible = articles.slice(0, visibleCount);
|
|
639
836
|
const hasMore = visibleCount < articles.length;
|
|
640
|
-
return /* @__PURE__ */ (0,
|
|
641
|
-
/* @__PURE__ */ (0,
|
|
642
|
-
hasMore && /* @__PURE__ */ (0,
|
|
837
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
|
|
838
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "grid md:grid-cols-2 lg:grid-cols-3 gap-8", children: visible.map((article) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ArticleCard, { article }, article.slug)) }),
|
|
839
|
+
hasMore && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mt-10 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
643
840
|
"button",
|
|
644
841
|
{
|
|
645
842
|
type: "button",
|
|
@@ -652,35 +849,36 @@ function LatestArticles({ articles, pageSize }) {
|
|
|
652
849
|
}
|
|
653
850
|
|
|
654
851
|
// src/LatestArticlesSection.tsx
|
|
655
|
-
var
|
|
852
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
656
853
|
function DescriptionText({
|
|
657
854
|
searchQuery,
|
|
658
855
|
count
|
|
659
856
|
}) {
|
|
660
857
|
const pluralSuffix = count === 1 ? "" : "s";
|
|
661
858
|
const text = searchQuery ? `Found ${count} article${pluralSuffix} matching your search.` : "Stay informed with our latest insights on voter engagement, campaign strategies, and civic technology.";
|
|
662
|
-
return /* @__PURE__ */ (0,
|
|
859
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-lg text-muted-foreground", children: text });
|
|
663
860
|
}
|
|
664
861
|
function LatestArticlesSection({
|
|
665
862
|
articles,
|
|
666
863
|
searchQuery,
|
|
667
864
|
onClearSearch,
|
|
668
|
-
pageSize = 6
|
|
865
|
+
pageSize = 6,
|
|
866
|
+
pagination
|
|
669
867
|
}) {
|
|
670
|
-
return /* @__PURE__ */ (0,
|
|
671
|
-
/* @__PURE__ */ (0,
|
|
672
|
-
/* @__PURE__ */ (0,
|
|
673
|
-
/* @__PURE__ */ (0,
|
|
868
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("section", { id: "latest", className: "py-16 bg-muted/50", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: [
|
|
869
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "text-center mb-12", children: [
|
|
870
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h2", { className: "text-3xl font-bold text-foreground mb-4", children: searchQuery ? "Search Results" : "Latest Articles" }),
|
|
871
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(DescriptionText, { searchQuery, count: articles.length })
|
|
674
872
|
] }),
|
|
675
|
-
articles.length === 0 && searchQuery ? /* @__PURE__ */ (0,
|
|
676
|
-
/* @__PURE__ */ (0,
|
|
677
|
-
/* @__PURE__ */ (0,
|
|
678
|
-
/* @__PURE__ */ (0,
|
|
873
|
+
articles.length === 0 && searchQuery ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "text-center py-12", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "max-w-md mx-auto", children: [
|
|
874
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react6.Search, { className: "h-12 w-12 text-muted-foreground mx-auto mb-4" }),
|
|
875
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h3", { className: "text-lg font-semibold text-foreground mb-2", children: "No articles found" }),
|
|
876
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("p", { className: "text-muted-foreground mb-4", children: [
|
|
679
877
|
`We couldn't find any articles matching "`,
|
|
680
878
|
searchQuery,
|
|
681
879
|
'". Try adjusting your search terms.'
|
|
682
880
|
] }),
|
|
683
|
-
/* @__PURE__ */ (0,
|
|
881
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
684
882
|
"button",
|
|
685
883
|
{
|
|
686
884
|
type: "button",
|
|
@@ -689,7 +887,15 @@ function LatestArticlesSection({
|
|
|
689
887
|
children: "Clear search"
|
|
690
888
|
}
|
|
691
889
|
)
|
|
692
|
-
] }) }) : /* @__PURE__ */ (0,
|
|
890
|
+
] }) }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
891
|
+
LatestArticles,
|
|
892
|
+
{
|
|
893
|
+
articles,
|
|
894
|
+
pageSize,
|
|
895
|
+
pagination: searchQuery ? void 0 : pagination
|
|
896
|
+
},
|
|
897
|
+
searchQuery
|
|
898
|
+
)
|
|
693
899
|
] }) });
|
|
694
900
|
}
|
|
695
901
|
|
|
@@ -715,12 +921,12 @@ function getBreadcrumbsConfig(config) {
|
|
|
715
921
|
|
|
716
922
|
// src/useArticles.ts
|
|
717
923
|
var import_react3 = require("react");
|
|
718
|
-
function useArticles() {
|
|
924
|
+
function useArticles(initialArticles, initialCategories) {
|
|
719
925
|
const [searchQuery, setSearchQuery] = (0, import_react3.useState)("");
|
|
720
926
|
const debounceRef = (0, import_react3.useRef)(null);
|
|
721
|
-
const [articles, setArticles] = (0, import_react3.useState)([]);
|
|
722
|
-
const [categories, setCategories] = (0, import_react3.useState)([]);
|
|
723
|
-
const [loading, setLoading] = (0, import_react3.useState)(
|
|
927
|
+
const [articles, setArticles] = (0, import_react3.useState)(initialArticles != null ? initialArticles : []);
|
|
928
|
+
const [categories, setCategories] = (0, import_react3.useState)(initialCategories != null ? initialCategories : []);
|
|
929
|
+
const [loading, setLoading] = (0, import_react3.useState)(initialArticles === void 0);
|
|
724
930
|
const [error, setError] = (0, import_react3.useState)(null);
|
|
725
931
|
const fetchArticles = (0, import_react3.useCallback)((query) => __async(this, null, function* () {
|
|
726
932
|
try {
|
|
@@ -758,7 +964,7 @@ function useArticles() {
|
|
|
758
964
|
}
|
|
759
965
|
}), []);
|
|
760
966
|
(0, import_react3.useEffect)(() => {
|
|
761
|
-
fetchArticles("");
|
|
967
|
+
if (initialArticles === void 0) fetchArticles("");
|
|
762
968
|
}, [fetchArticles]);
|
|
763
969
|
const handleSearch = (0, import_react3.useCallback)(
|
|
764
970
|
(query) => {
|
|
@@ -782,7 +988,7 @@ function useArticles() {
|
|
|
782
988
|
}
|
|
783
989
|
|
|
784
990
|
// src/ArticlesPage.tsx
|
|
785
|
-
var
|
|
991
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
786
992
|
function buildThemeVars(theme) {
|
|
787
993
|
if (!theme) return {};
|
|
788
994
|
const vars = {};
|
|
@@ -811,11 +1017,12 @@ function renderSection(section, ctx, config) {
|
|
|
811
1017
|
error,
|
|
812
1018
|
handleSearch,
|
|
813
1019
|
pageSize,
|
|
814
|
-
categoriesPageSize
|
|
1020
|
+
categoriesPageSize,
|
|
1021
|
+
pagination
|
|
815
1022
|
} = ctx;
|
|
816
1023
|
switch (section) {
|
|
817
1024
|
case "hero":
|
|
818
|
-
return /* @__PURE__ */ (0,
|
|
1025
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
819
1026
|
ArticlesHero,
|
|
820
1027
|
{
|
|
821
1028
|
title: (_a = config.hero) == null ? void 0 : _a.title,
|
|
@@ -824,7 +1031,7 @@ function renderSection(section, ctx, config) {
|
|
|
824
1031
|
"hero"
|
|
825
1032
|
);
|
|
826
1033
|
case "search":
|
|
827
|
-
return /* @__PURE__ */ (0,
|
|
1034
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
828
1035
|
ArticleSearchBar,
|
|
829
1036
|
{
|
|
830
1037
|
value: searchQuery,
|
|
@@ -835,7 +1042,7 @@ function renderSection(section, ctx, config) {
|
|
|
835
1042
|
"search"
|
|
836
1043
|
);
|
|
837
1044
|
case "featured":
|
|
838
|
-
return articles.length > 0 && !searchQuery ? /* @__PURE__ */ (0,
|
|
1045
|
+
return articles.length > 0 && !searchQuery ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
839
1046
|
FeaturedArticle,
|
|
840
1047
|
{
|
|
841
1048
|
article: articles[0],
|
|
@@ -845,16 +1052,16 @@ function renderSection(section, ctx, config) {
|
|
|
845
1052
|
) : null;
|
|
846
1053
|
case "latest":
|
|
847
1054
|
if (loading && articles.length === 0) {
|
|
848
|
-
return /* @__PURE__ */ (0,
|
|
849
|
-
/* @__PURE__ */ (0,
|
|
850
|
-
/* @__PURE__ */ (0,
|
|
1055
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("section", { id: "latest", className: "py-16 bg-muted/50 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex items-center justify-center py-24", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "text-center", children: [
|
|
1056
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-primary mx-auto mb-4" }),
|
|
1057
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-muted-foreground", children: "Loading articles..." })
|
|
851
1058
|
] }) }) }, "latest");
|
|
852
1059
|
}
|
|
853
1060
|
if (error) {
|
|
854
|
-
return /* @__PURE__ */ (0,
|
|
855
|
-
/* @__PURE__ */ (0,
|
|
856
|
-
/* @__PURE__ */ (0,
|
|
857
|
-
/* @__PURE__ */ (0,
|
|
1061
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("section", { id: "latest", className: "py-16 bg-muted/50 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "bg-red-50 border border-red-200 rounded-lg p-6 max-w-md text-center", children: [
|
|
1062
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h3", { className: "text-lg font-semibold text-red-800 mb-2", children: "Error Loading Articles" }),
|
|
1063
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-red-600 mb-4", children: error }),
|
|
1064
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
858
1065
|
"button",
|
|
859
1066
|
{
|
|
860
1067
|
type: "button",
|
|
@@ -865,18 +1072,19 @@ function renderSection(section, ctx, config) {
|
|
|
865
1072
|
)
|
|
866
1073
|
] }) }) }, "latest");
|
|
867
1074
|
}
|
|
868
|
-
return /* @__PURE__ */ (0,
|
|
1075
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
869
1076
|
LatestArticlesSection,
|
|
870
1077
|
{
|
|
871
1078
|
articles: displayedArticles,
|
|
872
1079
|
searchQuery,
|
|
873
1080
|
onClearSearch: () => handleSearch(""),
|
|
874
|
-
pageSize
|
|
1081
|
+
pageSize,
|
|
1082
|
+
pagination
|
|
875
1083
|
},
|
|
876
1084
|
"latest"
|
|
877
1085
|
);
|
|
878
1086
|
case "categories":
|
|
879
|
-
return searchQuery ? null : /* @__PURE__ */ (0,
|
|
1087
|
+
return searchQuery ? null : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
880
1088
|
ArticleCategoryGrid,
|
|
881
1089
|
{
|
|
882
1090
|
categories,
|
|
@@ -889,26 +1097,48 @@ function renderSection(section, ctx, config) {
|
|
|
889
1097
|
return null;
|
|
890
1098
|
}
|
|
891
1099
|
}
|
|
892
|
-
function ArticlesPage({
|
|
1100
|
+
function ArticlesPage({
|
|
1101
|
+
config,
|
|
1102
|
+
initialArticles,
|
|
1103
|
+
initialCategories,
|
|
1104
|
+
page,
|
|
1105
|
+
totalPages,
|
|
1106
|
+
totalCount
|
|
1107
|
+
}) {
|
|
893
1108
|
var _a, _b, _c;
|
|
894
|
-
const state = useArticles();
|
|
1109
|
+
const state = useArticles(initialArticles, initialCategories);
|
|
895
1110
|
const layout = (_a = config.layout) != null ? _a : DEFAULT_LAYOUT;
|
|
896
1111
|
const pageSize = (_b = config.pageSize) != null ? _b : DEFAULT_PAGE_SIZE;
|
|
897
1112
|
const categoriesPageSize = (_c = config.categoriesPageSize) != null ? _c : DEFAULT_CATEGORIES_PAGE_SIZE;
|
|
898
1113
|
const themeVars = buildThemeVars(config.theme);
|
|
899
|
-
const
|
|
1114
|
+
const isPagesMode = config.listingPagination === "pages" && page !== void 0 && totalPages !== void 0;
|
|
1115
|
+
const currentPage = page != null ? page : 1;
|
|
1116
|
+
const effectiveLayout = isPagesMode && currentPage > 1 ? layout.filter((section) => section !== "featured") : layout;
|
|
1117
|
+
const hasFeatured = effectiveLayout.includes("featured");
|
|
900
1118
|
const articlesWithoutFeatured = hasFeatured ? state.articles.slice(1) : state.articles;
|
|
901
1119
|
const displayedArticles = state.searchQuery ? state.articles : articlesWithoutFeatured;
|
|
902
|
-
const
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
1120
|
+
const pagination = isPagesMode ? { page: currentPage, totalPages, basePath: "/articles" } : void 0;
|
|
1121
|
+
const ctx = __spreadProps(__spreadValues({}, state), {
|
|
1122
|
+
displayedArticles,
|
|
1123
|
+
pageSize,
|
|
1124
|
+
categoriesPageSize,
|
|
1125
|
+
pagination
|
|
1126
|
+
});
|
|
1127
|
+
const articleCount = totalCount != null ? totalCount : state.articles.length;
|
|
1128
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: themeVars, children: [
|
|
1129
|
+
effectiveLayout.map((section) => renderSection(section, ctx, config)),
|
|
1130
|
+
state.articles.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
906
1131
|
CollectionPageSchema,
|
|
907
1132
|
{
|
|
908
1133
|
title: `Articles | ${config.siteName}`,
|
|
909
|
-
description: `Browse all ${
|
|
1134
|
+
description: `Browse all ${articleCount} articles on ${config.siteName}.`,
|
|
910
1135
|
url: `${config.siteUrl}/articles`,
|
|
911
|
-
articleCount
|
|
1136
|
+
articleCount,
|
|
1137
|
+
items: displayedArticles.slice(0, pageSize).map((article, index) => ({
|
|
1138
|
+
position: index + 1,
|
|
1139
|
+
url: `${config.siteUrl}/articles/${article.slug}`,
|
|
1140
|
+
name: article.title
|
|
1141
|
+
}))
|
|
912
1142
|
}
|
|
913
1143
|
)
|
|
914
1144
|
] });
|
|
@@ -916,10 +1146,10 @@ function ArticlesPage({ config }) {
|
|
|
916
1146
|
|
|
917
1147
|
// src/ArticleDetailHero.tsx
|
|
918
1148
|
var import_react4 = require("react");
|
|
919
|
-
var
|
|
920
|
-
var
|
|
921
|
-
var
|
|
922
|
-
var
|
|
1149
|
+
var import_image5 = __toESM(require("next/image"), 1);
|
|
1150
|
+
var import_link8 = __toESM(require("next/link"), 1);
|
|
1151
|
+
var import_lucide_react7 = require("lucide-react");
|
|
1152
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
923
1153
|
function toSlug(cat) {
|
|
924
1154
|
return cat.toLowerCase().replaceAll(/\s+/g, "-").replaceAll(/[^a-z0-9-]/g, "");
|
|
925
1155
|
}
|
|
@@ -932,7 +1162,7 @@ function ArticleDetailHero({
|
|
|
932
1162
|
}) {
|
|
933
1163
|
const showConfiguredAuthors = showAuthor && authors.length > 0;
|
|
934
1164
|
const showLegacyAuthor = showAuthor && authors.length === 0 && article.author.trim().length > 0;
|
|
935
|
-
return /* @__PURE__ */ (0,
|
|
1165
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
936
1166
|
"section",
|
|
937
1167
|
{
|
|
938
1168
|
style: {
|
|
@@ -944,8 +1174,8 @@ function ArticleDetailHero({
|
|
|
944
1174
|
overflow: "hidden"
|
|
945
1175
|
},
|
|
946
1176
|
children: [
|
|
947
|
-
/* @__PURE__ */ (0,
|
|
948
|
-
|
|
1177
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1178
|
+
import_image5.default,
|
|
949
1179
|
{
|
|
950
1180
|
src: article.featuredImage,
|
|
951
1181
|
alt: article.title,
|
|
@@ -956,7 +1186,7 @@ function ArticleDetailHero({
|
|
|
956
1186
|
priority: true
|
|
957
1187
|
}
|
|
958
1188
|
),
|
|
959
|
-
/* @__PURE__ */ (0,
|
|
1189
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
960
1190
|
"div",
|
|
961
1191
|
{
|
|
962
1192
|
style: {
|
|
@@ -966,7 +1196,7 @@ function ArticleDetailHero({
|
|
|
966
1196
|
}
|
|
967
1197
|
}
|
|
968
1198
|
),
|
|
969
|
-
/* @__PURE__ */ (0,
|
|
1199
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
970
1200
|
"div",
|
|
971
1201
|
{
|
|
972
1202
|
style: {
|
|
@@ -980,7 +1210,7 @@ function ArticleDetailHero({
|
|
|
980
1210
|
width: "100%"
|
|
981
1211
|
},
|
|
982
1212
|
children: [
|
|
983
|
-
article.categories && article.categories.length > 0 && /* @__PURE__ */ (0,
|
|
1213
|
+
article.categories && article.categories.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
984
1214
|
"div",
|
|
985
1215
|
{
|
|
986
1216
|
style: {
|
|
@@ -991,15 +1221,15 @@ function ArticleDetailHero({
|
|
|
991
1221
|
marginBottom: "1rem"
|
|
992
1222
|
},
|
|
993
1223
|
children: article.categories.slice(0, 4).map(
|
|
994
|
-
(cat) => categoryBasePath ? /* @__PURE__ */ (0,
|
|
995
|
-
|
|
1224
|
+
(cat) => categoryBasePath ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1225
|
+
import_link8.default,
|
|
996
1226
|
{
|
|
997
1227
|
href: `${categoryBasePath}/${toSlug(cat)}`,
|
|
998
1228
|
className: "inline-block bg-white/20 text-white text-sm font-medium px-3 py-1 rounded-full hover:bg-white/30 transition-colors",
|
|
999
1229
|
children: cat
|
|
1000
1230
|
},
|
|
1001
1231
|
cat
|
|
1002
|
-
) : /* @__PURE__ */ (0,
|
|
1232
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1003
1233
|
"span",
|
|
1004
1234
|
{
|
|
1005
1235
|
className: "inline-block bg-white/20 text-white text-sm font-medium px-3 py-1 rounded-full",
|
|
@@ -1010,8 +1240,8 @@ function ArticleDetailHero({
|
|
|
1010
1240
|
)
|
|
1011
1241
|
}
|
|
1012
1242
|
),
|
|
1013
|
-
/* @__PURE__ */ (0,
|
|
1014
|
-
/* @__PURE__ */ (0,
|
|
1243
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h1", { className: "text-4xl md:text-5xl font-bold mb-4", children: article.title }),
|
|
1244
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1015
1245
|
"div",
|
|
1016
1246
|
{
|
|
1017
1247
|
style: {
|
|
@@ -1023,23 +1253,23 @@ function ArticleDetailHero({
|
|
|
1023
1253
|
color: "rgba(255,255,255,0.8)"
|
|
1024
1254
|
},
|
|
1025
1255
|
children: [
|
|
1026
|
-
showDate && article.date && /* @__PURE__ */ (0,
|
|
1027
|
-
/* @__PURE__ */ (0,
|
|
1028
|
-
/* @__PURE__ */ (0,
|
|
1256
|
+
showDate && article.date && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
|
|
1257
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.Calendar, { className: "h-4 w-4" }),
|
|
1258
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: article.date })
|
|
1029
1259
|
] }),
|
|
1030
|
-
/* @__PURE__ */ (0,
|
|
1031
|
-
/* @__PURE__ */ (0,
|
|
1032
|
-
/* @__PURE__ */ (0,
|
|
1260
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
|
|
1261
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.Clock, { className: "h-4 w-4" }),
|
|
1262
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: article.readTime })
|
|
1033
1263
|
] }),
|
|
1034
|
-
showConfiguredAuthors && /* @__PURE__ */ (0,
|
|
1035
|
-
/* @__PURE__ */ (0,
|
|
1036
|
-
/* @__PURE__ */ (0,
|
|
1264
|
+
showConfiguredAuthors && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
|
|
1265
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.User, { className: "h-4 w-4" }),
|
|
1266
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { children: [
|
|
1037
1267
|
"By",
|
|
1038
1268
|
" ",
|
|
1039
|
-
authors.map((author, index) => /* @__PURE__ */ (0,
|
|
1269
|
+
authors.map((author, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react4.Fragment, { children: [
|
|
1040
1270
|
index > 0 && ", ",
|
|
1041
|
-
/* @__PURE__ */ (0,
|
|
1042
|
-
|
|
1271
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1272
|
+
import_link8.default,
|
|
1043
1273
|
{
|
|
1044
1274
|
href: `/articles/authors/${author.slug}`,
|
|
1045
1275
|
className: "font-medium text-white underline-offset-4 hover:underline",
|
|
@@ -1049,15 +1279,26 @@ function ArticleDetailHero({
|
|
|
1049
1279
|
] }, author.slug))
|
|
1050
1280
|
] })
|
|
1051
1281
|
] }),
|
|
1052
|
-
showLegacyAuthor && /* @__PURE__ */ (0,
|
|
1053
|
-
/* @__PURE__ */ (0,
|
|
1054
|
-
/* @__PURE__ */ (0,
|
|
1282
|
+
showLegacyAuthor && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem" }, children: [
|
|
1283
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react7.User, { className: "h-4 w-4" }),
|
|
1284
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { children: [
|
|
1055
1285
|
"By ",
|
|
1056
1286
|
article.author
|
|
1057
1287
|
] })
|
|
1058
1288
|
] })
|
|
1059
1289
|
]
|
|
1060
1290
|
}
|
|
1291
|
+
),
|
|
1292
|
+
showConfiguredAuthors && authors.length === 1 && authors[0].promise && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1293
|
+
"p",
|
|
1294
|
+
{
|
|
1295
|
+
style: {
|
|
1296
|
+
marginTop: "0.75rem",
|
|
1297
|
+
fontSize: "0.9375rem",
|
|
1298
|
+
color: "rgba(255,255,255,0.85)"
|
|
1299
|
+
},
|
|
1300
|
+
children: authors[0].promise
|
|
1301
|
+
}
|
|
1061
1302
|
)
|
|
1062
1303
|
]
|
|
1063
1304
|
}
|
|
@@ -1068,9 +1309,9 @@ function ArticleDetailHero({
|
|
|
1068
1309
|
}
|
|
1069
1310
|
|
|
1070
1311
|
// src/CategoryArticlesPage.tsx
|
|
1071
|
-
var
|
|
1072
|
-
var
|
|
1073
|
-
var
|
|
1312
|
+
var import_image6 = __toESM(require("next/image"), 1);
|
|
1313
|
+
var import_link9 = __toESM(require("next/link"), 1);
|
|
1314
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1074
1315
|
function getCategoryDescription(config, slug, categoryName) {
|
|
1075
1316
|
var _a;
|
|
1076
1317
|
const raw = (_a = config.categoryDescriptions) == null ? void 0 : _a[slug];
|
|
@@ -1112,7 +1353,14 @@ function buildCategoryBreadcrumbEntry(entry, context) {
|
|
|
1112
1353
|
}
|
|
1113
1354
|
return [{ name: context.categoryName }];
|
|
1114
1355
|
}
|
|
1115
|
-
function CategoryArticlesPage({
|
|
1356
|
+
function CategoryArticlesPage({
|
|
1357
|
+
category,
|
|
1358
|
+
articles,
|
|
1359
|
+
config,
|
|
1360
|
+
page,
|
|
1361
|
+
totalPages,
|
|
1362
|
+
totalCount
|
|
1363
|
+
}) {
|
|
1116
1364
|
var _a;
|
|
1117
1365
|
if (articles.length === 0) return null;
|
|
1118
1366
|
const categoryName = articles[0].category;
|
|
@@ -1121,8 +1369,25 @@ function CategoryArticlesPage({ category, articles, config }) {
|
|
|
1121
1369
|
const pageSize = (_a = config.pageSize) != null ? _a : DEFAULT_PAGE_SIZE;
|
|
1122
1370
|
const breadcrumbConfig = getBreadcrumbsConfig(config);
|
|
1123
1371
|
const breadcrumbItems = buildCategoryBreadcrumbItems(config, categoryName);
|
|
1124
|
-
|
|
1125
|
-
|
|
1372
|
+
const siteUrl = config.siteUrl.replace(/\/$/, "");
|
|
1373
|
+
const articleCount = totalCount != null ? totalCount : articles.length;
|
|
1374
|
+
const pagination = config.listingPagination === "pages" && page !== void 0 && totalPages !== void 0 ? { page, totalPages, basePath: `/articles/category/${category}` } : void 0;
|
|
1375
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
|
|
1376
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1377
|
+
CollectionPageSchema,
|
|
1378
|
+
{
|
|
1379
|
+
title: `${categoryName} | ${config.siteName}`,
|
|
1380
|
+
description: description.short,
|
|
1381
|
+
url: `${siteUrl}/articles/category/${category}`,
|
|
1382
|
+
articleCount,
|
|
1383
|
+
items: articles.slice(0, pageSize).map((article, index) => ({
|
|
1384
|
+
position: index + 1,
|
|
1385
|
+
url: `${siteUrl}/articles/${article.slug}`,
|
|
1386
|
+
name: article.title
|
|
1387
|
+
}))
|
|
1388
|
+
}
|
|
1389
|
+
),
|
|
1390
|
+
breadcrumbsAreEnabled(config) && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1126
1391
|
Breadcrumb,
|
|
1127
1392
|
{
|
|
1128
1393
|
items: breadcrumbItems,
|
|
@@ -1130,7 +1395,7 @@ function CategoryArticlesPage({ category, articles, config }) {
|
|
|
1130
1395
|
showSchema: breadcrumbConfig.showSchema !== false
|
|
1131
1396
|
}
|
|
1132
1397
|
),
|
|
1133
|
-
/* @__PURE__ */ (0,
|
|
1398
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1134
1399
|
"section",
|
|
1135
1400
|
{
|
|
1136
1401
|
style: {
|
|
@@ -1142,8 +1407,8 @@ function CategoryArticlesPage({ category, articles, config }) {
|
|
|
1142
1407
|
overflow: "hidden"
|
|
1143
1408
|
},
|
|
1144
1409
|
children: [
|
|
1145
|
-
/* @__PURE__ */ (0,
|
|
1146
|
-
|
|
1410
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1411
|
+
import_image6.default,
|
|
1147
1412
|
{
|
|
1148
1413
|
src: heroImage,
|
|
1149
1414
|
alt: categoryName,
|
|
@@ -1153,8 +1418,8 @@ function CategoryArticlesPage({ category, articles, config }) {
|
|
|
1153
1418
|
priority: true
|
|
1154
1419
|
}
|
|
1155
1420
|
),
|
|
1156
|
-
/* @__PURE__ */ (0,
|
|
1157
|
-
/* @__PURE__ */ (0,
|
|
1421
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { position: "absolute", inset: 0, backgroundColor: "rgba(0,0,0,0.6)" } }),
|
|
1422
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1158
1423
|
"div",
|
|
1159
1424
|
{
|
|
1160
1425
|
style: {
|
|
@@ -1165,10 +1430,10 @@ function CategoryArticlesPage({ category, articles, config }) {
|
|
|
1165
1430
|
padding: "0 1rem"
|
|
1166
1431
|
},
|
|
1167
1432
|
children: [
|
|
1168
|
-
/* @__PURE__ */ (0,
|
|
1169
|
-
/* @__PURE__ */ (0,
|
|
1170
|
-
description.long && /* @__PURE__ */ (0,
|
|
1171
|
-
/* @__PURE__ */ (0,
|
|
1433
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm font-semibold uppercase tracking-widest mb-3 opacity-80", children: "Category" }),
|
|
1434
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h1", { className: "text-4xl md:text-5xl font-bold mb-3", children: categoryName }),
|
|
1435
|
+
description.long && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-lg opacity-90 max-w-2xl mx-auto mt-2", children: description.long }),
|
|
1436
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("p", { className: "text-lg opacity-70 mt-2", children: [
|
|
1172
1437
|
articles.length,
|
|
1173
1438
|
" article",
|
|
1174
1439
|
articles.length === 1 ? "" : "s"
|
|
@@ -1179,140 +1444,75 @@ function CategoryArticlesPage({ category, articles, config }) {
|
|
|
1179
1444
|
]
|
|
1180
1445
|
}
|
|
1181
1446
|
),
|
|
1182
|
-
/* @__PURE__ */ (0,
|
|
1183
|
-
/* @__PURE__ */ (0,
|
|
1184
|
-
/* @__PURE__ */ (0,
|
|
1185
|
-
/* @__PURE__ */ (0,
|
|
1447
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("section", { className: "py-16 bg-muted/50 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: [
|
|
1448
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "mb-8 flex items-center justify-between", children: [
|
|
1449
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_link9.default, { href: "/articles", className: "text-sm text-primary hover:underline", children: "\u2190 All Articles" }),
|
|
1450
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm text-muted-foreground", children: description.short })
|
|
1186
1451
|
] }),
|
|
1187
|
-
/* @__PURE__ */ (0,
|
|
1452
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(LatestArticles, { articles, pageSize, pagination })
|
|
1188
1453
|
] }) })
|
|
1189
1454
|
] });
|
|
1190
1455
|
}
|
|
1191
1456
|
|
|
1192
|
-
// src/
|
|
1193
|
-
var
|
|
1194
|
-
var
|
|
1195
|
-
function
|
|
1196
|
-
var _a, _b;
|
|
1197
|
-
return __spreadProps(__spreadValues(__spreadValues({
|
|
1198
|
-
"@context": "https://schema.org",
|
|
1199
|
-
"@type": "Person",
|
|
1200
|
-
name: author.name,
|
|
1201
|
-
description: author.bio,
|
|
1202
|
-
url: (_a = author.url) != null ? _a : getAuthorUrl(author)
|
|
1203
|
-
}, getAuthorAvatar(author, config) && { image: getAuthorAvatar(author, config) }), getAuthorSameAs(author).length > 0 && { sameAs: getAuthorSameAs(author) }), {
|
|
1204
|
-
knowsAbout: config.siteName,
|
|
1205
|
-
mainEntityOfPage: (_b = author.url) != null ? _b : `${config.siteUrl.replace(/\/$/, "")}/articles/authors/${author.slug}`,
|
|
1206
|
-
interactionStatistic: {
|
|
1207
|
-
"@type": "InteractionCounter",
|
|
1208
|
-
interactionType: "https://schema.org/WriteAction",
|
|
1209
|
-
userInteractionCount: articleCount
|
|
1210
|
-
}
|
|
1211
|
-
});
|
|
1212
|
-
}
|
|
1213
|
-
function AuthorArticlesPage({ author, articles, config }) {
|
|
1457
|
+
// src/SeriesArticlesPage.tsx
|
|
1458
|
+
var import_link10 = __toESM(require("next/link"), 1);
|
|
1459
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1460
|
+
function SeriesArticlesPage({ seriesSlug, articles, config }) {
|
|
1214
1461
|
var _a;
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1462
|
+
if (articles.length === 0) return null;
|
|
1463
|
+
const seriesName = (_a = articles[0].series) != null ? _a : seriesSlug;
|
|
1464
|
+
const siteUrl = config.siteUrl.replace(/\/$/, "");
|
|
1465
|
+
const seriesUrl = `${siteUrl}/articles/series/${seriesSlug}`;
|
|
1466
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
|
|
1467
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1468
|
+
CollectionPageSchema,
|
|
1219
1469
|
{
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1470
|
+
title: `${seriesName} | ${config.siteName}`,
|
|
1471
|
+
description: `Follow the ${seriesName} series on ${config.siteName}.`,
|
|
1472
|
+
url: seriesUrl,
|
|
1473
|
+
articleCount: articles.length,
|
|
1474
|
+
items: articles.map((article, index) => ({
|
|
1475
|
+
position: index + 1,
|
|
1476
|
+
url: `${siteUrl}/articles/${article.slug}`,
|
|
1477
|
+
name: article.title
|
|
1478
|
+
}))
|
|
1224
1479
|
}
|
|
1225
1480
|
),
|
|
1226
|
-
/* @__PURE__ */ (0,
|
|
1227
|
-
/* @__PURE__ */ (0,
|
|
1228
|
-
/* @__PURE__ */ (0,
|
|
1229
|
-
/* @__PURE__ */ (0,
|
|
1230
|
-
|
|
1231
|
-
|
|
1481
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("section", { className: "py-16 bg-muted/50 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: [
|
|
1482
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "mb-8 flex items-center justify-between", children: [
|
|
1483
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_link10.default, { href: "/articles", className: "text-sm text-primary hover:underline", children: "\u2190 All Articles" }),
|
|
1484
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("p", { className: "text-sm text-muted-foreground", children: [
|
|
1485
|
+
articles.length,
|
|
1486
|
+
" article",
|
|
1487
|
+
articles.length === 1 ? "" : "s",
|
|
1488
|
+
" in this series"
|
|
1232
1489
|
] })
|
|
1233
1490
|
] }),
|
|
1234
|
-
/* @__PURE__ */ (0,
|
|
1491
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h1", { className: "text-3xl font-bold text-foreground mb-8", children: seriesName }),
|
|
1492
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1493
|
+
LatestArticles,
|
|
1494
|
+
{
|
|
1495
|
+
articles,
|
|
1496
|
+
pageSize: Math.max(articles.length, DEFAULT_PAGE_SIZE)
|
|
1497
|
+
}
|
|
1498
|
+
)
|
|
1235
1499
|
] }) })
|
|
1236
1500
|
] });
|
|
1237
1501
|
}
|
|
1238
1502
|
|
|
1239
|
-
// src/
|
|
1240
|
-
var
|
|
1241
|
-
var import_link9 = __toESM(require("next/link"), 1);
|
|
1242
|
-
var import_lucide_react6 = require("lucide-react");
|
|
1243
|
-
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1244
|
-
function getInitials(name) {
|
|
1245
|
-
return name.split(" ").filter(Boolean).slice(0, 2).map((part) => part.charAt(0).toUpperCase()).join("");
|
|
1246
|
-
}
|
|
1247
|
-
function AuthorCard({
|
|
1248
|
-
author,
|
|
1249
|
-
linkToPage = true,
|
|
1250
|
-
showBio = false,
|
|
1251
|
-
showSocial = false
|
|
1252
|
-
}) {
|
|
1253
|
-
const avatar = getAuthorAvatar(author);
|
|
1254
|
-
const name = linkToPage ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_link9.default, { href: getAuthorUrl(author), className: "font-medium text-foreground hover:text-primary", children: author.name }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "font-medium text-foreground", children: author.name });
|
|
1255
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex items-start gap-3 rounded-lg border border-border bg-card p-4 text-card-foreground", children: [
|
|
1256
|
-
avatar ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1257
|
-
import_image6.default,
|
|
1258
|
-
{
|
|
1259
|
-
src: avatar,
|
|
1260
|
-
alt: author.name,
|
|
1261
|
-
width: 48,
|
|
1262
|
-
height: 48,
|
|
1263
|
-
className: "h-12 w-12 rounded-full object-cover"
|
|
1264
|
-
}
|
|
1265
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-muted text-sm font-semibold text-muted-foreground", children: getInitials(author.name) }),
|
|
1266
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "min-w-0 flex-1", children: [
|
|
1267
|
-
name,
|
|
1268
|
-
showBio && author.bio && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "mt-1 line-clamp-2 text-sm text-muted-foreground", children: author.bio }),
|
|
1269
|
-
showSocial && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(AuthorSocialLinks, { author })
|
|
1270
|
-
] })
|
|
1271
|
-
] });
|
|
1272
|
-
}
|
|
1273
|
-
var SOCIAL_ICONS = {
|
|
1274
|
-
Website: import_lucide_react6.Globe,
|
|
1275
|
-
Facebook: import_lucide_react6.Facebook,
|
|
1276
|
-
Twitter: import_lucide_react6.Twitter,
|
|
1277
|
-
X: import_lucide_react6.Twitter,
|
|
1278
|
-
LinkedIn: import_lucide_react6.Linkedin,
|
|
1279
|
-
Instagram: import_lucide_react6.Instagram,
|
|
1280
|
-
YouTube: import_lucide_react6.Youtube,
|
|
1281
|
-
GitHub: import_lucide_react6.Github,
|
|
1282
|
-
Newsletter: import_lucide_react6.Mail
|
|
1283
|
-
};
|
|
1284
|
-
function getSocialIcon(label) {
|
|
1285
|
-
var _a;
|
|
1286
|
-
return (_a = SOCIAL_ICONS[label]) != null ? _a : import_lucide_react6.MessageCircle;
|
|
1287
|
-
}
|
|
1288
|
-
function AuthorSocialLinks({ author }) {
|
|
1289
|
-
const links = getAuthorSocialLinks(author);
|
|
1290
|
-
if (links.length === 0) return null;
|
|
1291
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "mt-3 flex items-center gap-2", children: links.map(({ href, label }) => {
|
|
1292
|
-
const Icon = getSocialIcon(label);
|
|
1293
|
-
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1294
|
-
import_link9.default,
|
|
1295
|
-
{
|
|
1296
|
-
href,
|
|
1297
|
-
className: "inline-flex h-8 w-8 items-center justify-center rounded-md border border-border text-muted-foreground hover:bg-accent hover:text-accent-foreground",
|
|
1298
|
-
"aria-label": `${author.name} on ${label}`,
|
|
1299
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Icon, { className: "h-4 w-4" })
|
|
1300
|
-
},
|
|
1301
|
-
`${label}-${href}`
|
|
1302
|
-
);
|
|
1303
|
-
}) });
|
|
1304
|
-
}
|
|
1503
|
+
// src/AuthorArticlesPage.tsx
|
|
1504
|
+
var import_link11 = __toESM(require("next/link"), 1);
|
|
1305
1505
|
|
|
1306
1506
|
// src/AuthorDetailHero.tsx
|
|
1307
1507
|
var import_image7 = __toESM(require("next/image"), 1);
|
|
1308
|
-
var
|
|
1508
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1309
1509
|
function getInitials2(name) {
|
|
1310
1510
|
return name.split(" ").filter(Boolean).slice(0, 2).map((part) => part.charAt(0).toUpperCase()).join("");
|
|
1311
1511
|
}
|
|
1312
1512
|
function AuthorDetailHero({ author, articleCount }) {
|
|
1313
1513
|
const avatar = getAuthorAvatar(author);
|
|
1314
|
-
return /* @__PURE__ */ (0,
|
|
1315
|
-
avatar ? /* @__PURE__ */ (0,
|
|
1514
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("section", { className: "bg-muted/40 py-16", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "mx-auto flex max-w-4xl flex-col items-center gap-6 px-4 text-center sm:px-6 lg:px-8", children: [
|
|
1515
|
+
avatar ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1316
1516
|
import_image7.default,
|
|
1317
1517
|
{
|
|
1318
1518
|
src: avatar,
|
|
@@ -1322,27 +1522,303 @@ function AuthorDetailHero({ author, articleCount }) {
|
|
|
1322
1522
|
className: "h-28 w-28 rounded-full object-cover",
|
|
1323
1523
|
priority: true
|
|
1324
1524
|
}
|
|
1325
|
-
) : /* @__PURE__ */ (0,
|
|
1326
|
-
/* @__PURE__ */ (0,
|
|
1327
|
-
/* @__PURE__ */ (0,
|
|
1328
|
-
/* @__PURE__ */ (0,
|
|
1329
|
-
/* @__PURE__ */ (0,
|
|
1330
|
-
typeof articleCount === "number" && /* @__PURE__ */ (0,
|
|
1525
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "flex h-28 w-28 items-center justify-center rounded-full bg-card text-3xl font-semibold text-muted-foreground shadow-sm", children: getInitials2(author.name) }),
|
|
1526
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
|
|
1527
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "mb-3 text-sm font-semibold uppercase tracking-widest text-muted-foreground", children: "Author" }),
|
|
1528
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h1", { className: "text-4xl font-bold text-foreground md:text-5xl", children: author.name }),
|
|
1529
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "mx-auto mt-4 max-w-2xl text-lg text-muted-foreground", children: author.bio }),
|
|
1530
|
+
typeof articleCount === "number" && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("p", { className: "mt-3 text-sm text-muted-foreground", children: [
|
|
1331
1531
|
articleCount,
|
|
1332
1532
|
" article",
|
|
1333
1533
|
articleCount === 1 ? "" : "s"
|
|
1334
1534
|
] })
|
|
1335
1535
|
] }),
|
|
1336
|
-
/* @__PURE__ */ (0,
|
|
1536
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AuthorSocialLinks, { author })
|
|
1337
1537
|
] }) });
|
|
1338
1538
|
}
|
|
1339
1539
|
|
|
1340
|
-
// src/
|
|
1540
|
+
// src/eventTracking.tsx
|
|
1341
1541
|
var import_react5 = require("react");
|
|
1342
|
-
var
|
|
1343
|
-
var
|
|
1344
|
-
|
|
1345
|
-
|
|
1542
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1543
|
+
var AVERAGE_WORDS_PER_MINUTE = 200;
|
|
1544
|
+
var DEFAULT_MEANINGFUL_READ_MS = 15e3;
|
|
1545
|
+
function ArticleViewTracker({ article, config }) {
|
|
1546
|
+
const firedMeaningfulRead = (0, import_react5.useRef)(false);
|
|
1547
|
+
(0, import_react5.useEffect)(() => {
|
|
1548
|
+
emitArticleEvent(config == null ? void 0 : config.onEvent, {
|
|
1549
|
+
name: "article_viewed",
|
|
1550
|
+
articleSlug: article.slug,
|
|
1551
|
+
category: article.category,
|
|
1552
|
+
seriesSlug: article.seriesSlug
|
|
1553
|
+
});
|
|
1554
|
+
const estimatedMs = article.wordCount ? article.wordCount / AVERAGE_WORDS_PER_MINUTE * 6e4 * 0.5 : DEFAULT_MEANINGFUL_READ_MS;
|
|
1555
|
+
const timer = setTimeout(() => {
|
|
1556
|
+
if (firedMeaningfulRead.current) return;
|
|
1557
|
+
firedMeaningfulRead.current = true;
|
|
1558
|
+
emitArticleEvent(config == null ? void 0 : config.onEvent, { name: "meaningful_read", articleSlug: article.slug });
|
|
1559
|
+
}, estimatedMs);
|
|
1560
|
+
return () => clearTimeout(timer);
|
|
1561
|
+
}, [article.slug]);
|
|
1562
|
+
return null;
|
|
1563
|
+
}
|
|
1564
|
+
function CtaViewTracker({ ctaId, articleSlug, config, children }) {
|
|
1565
|
+
const ref = (0, import_react5.useRef)(null);
|
|
1566
|
+
const fired = (0, import_react5.useRef)(false);
|
|
1567
|
+
(0, import_react5.useEffect)(() => {
|
|
1568
|
+
const node = ref.current;
|
|
1569
|
+
if (!node) return;
|
|
1570
|
+
function fire() {
|
|
1571
|
+
if (fired.current) return;
|
|
1572
|
+
fired.current = true;
|
|
1573
|
+
emitArticleEvent(config == null ? void 0 : config.onEvent, { name: "cta_viewed", ctaId, articleSlug });
|
|
1574
|
+
}
|
|
1575
|
+
if (typeof IntersectionObserver === "undefined") {
|
|
1576
|
+
fire();
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
const observer = new IntersectionObserver(
|
|
1580
|
+
(entries) => {
|
|
1581
|
+
if (entries.some((entry) => entry.isIntersecting)) fire();
|
|
1582
|
+
},
|
|
1583
|
+
{ threshold: 0.5 }
|
|
1584
|
+
);
|
|
1585
|
+
observer.observe(node);
|
|
1586
|
+
return () => observer.disconnect();
|
|
1587
|
+
}, [ctaId, articleSlug]);
|
|
1588
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { ref, children });
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
// src/AuthorArticlesPage.tsx
|
|
1592
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1593
|
+
function getPersonSchema(author, config, articleCount) {
|
|
1594
|
+
var _a, _b;
|
|
1595
|
+
return __spreadProps(__spreadValues(__spreadValues({
|
|
1596
|
+
"@context": "https://schema.org",
|
|
1597
|
+
"@type": "Person",
|
|
1598
|
+
name: author.name,
|
|
1599
|
+
description: author.bio,
|
|
1600
|
+
url: (_a = author.url) != null ? _a : getAuthorUrl(author)
|
|
1601
|
+
}, getAuthorAvatar(author, config) && { image: getAuthorAvatar(author, config) }), getAuthorSameAs(author).length > 0 && { sameAs: getAuthorSameAs(author) }), {
|
|
1602
|
+
knowsAbout: config.siteName,
|
|
1603
|
+
mainEntityOfPage: (_b = author.url) != null ? _b : `${config.siteUrl.replace(/\/$/, "")}/articles/authors/${author.slug}`,
|
|
1604
|
+
interactionStatistic: {
|
|
1605
|
+
"@type": "InteractionCounter",
|
|
1606
|
+
interactionType: "https://schema.org/WriteAction",
|
|
1607
|
+
userInteractionCount: articleCount
|
|
1608
|
+
}
|
|
1609
|
+
});
|
|
1610
|
+
}
|
|
1611
|
+
function renderHeroSection(author, articleCount) {
|
|
1612
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(AuthorDetailHero, { author, articleCount }, "hero");
|
|
1613
|
+
}
|
|
1614
|
+
function renderPromiseSection(author) {
|
|
1615
|
+
return author.promise ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("section", { "aria-label": "Author promise", className: "bg-background py-12", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "mx-auto max-w-3xl px-4 text-center sm:px-6 lg:px-8", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-xl font-medium text-foreground md:text-2xl", children: author.promise }) }) }, "promise") : null;
|
|
1616
|
+
}
|
|
1617
|
+
function renderServesWhoSection(author) {
|
|
1618
|
+
return author.servesWho && author.servesWho.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("section", { "aria-label": "Who this author serves", className: "bg-muted/40 py-12", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "mx-auto max-w-3xl px-4 sm:px-6 lg:px-8", children: [
|
|
1619
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h2", { className: "mb-4 text-center text-2xl font-bold text-foreground", children: "Who I help" }),
|
|
1620
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("ul", { className: "grid gap-3 sm:grid-cols-2", children: author.servesWho.map((who) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1621
|
+
"li",
|
|
1622
|
+
{
|
|
1623
|
+
className: "rounded-lg border border-border bg-card px-4 py-3 text-sm text-card-foreground",
|
|
1624
|
+
children: who
|
|
1625
|
+
},
|
|
1626
|
+
who
|
|
1627
|
+
)) })
|
|
1628
|
+
] }) }, "servesWho") : null;
|
|
1629
|
+
}
|
|
1630
|
+
function renderOriginStorySection(author) {
|
|
1631
|
+
return author.originStory && author.originStory.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("section", { "aria-label": "Author origin story", className: "bg-background py-12", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "mx-auto max-w-3xl px-4 sm:px-6 lg:px-8", children: [
|
|
1632
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h2", { className: "mb-6 text-2xl font-bold text-foreground", children: "My story" }),
|
|
1633
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "space-y-6", children: author.originStory.map((block, blockIndex) => {
|
|
1634
|
+
var _a;
|
|
1635
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
|
|
1636
|
+
block.heading && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h3", { className: "mb-2 text-lg font-semibold text-foreground", children: block.heading }),
|
|
1637
|
+
block.paragraphs.map((paragraph, paragraphIndex) => {
|
|
1638
|
+
var _a2;
|
|
1639
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1640
|
+
"p",
|
|
1641
|
+
{
|
|
1642
|
+
className: "mb-3 text-muted-foreground",
|
|
1643
|
+
children: paragraph
|
|
1644
|
+
},
|
|
1645
|
+
`${(_a2 = block.heading) != null ? _a2 : blockIndex}-${paragraph.slice(0, 40)}-${paragraphIndex}`
|
|
1646
|
+
);
|
|
1647
|
+
})
|
|
1648
|
+
] }, (_a = block.heading) != null ? _a : blockIndex);
|
|
1649
|
+
}) })
|
|
1650
|
+
] }) }, "originStory") : null;
|
|
1651
|
+
}
|
|
1652
|
+
function renderPrinciplesSection(author) {
|
|
1653
|
+
return author.principles && author.principles.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("section", { "aria-label": "Author principles", className: "bg-muted/40 py-12", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "mx-auto max-w-3xl px-4 sm:px-6 lg:px-8", children: [
|
|
1654
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h2", { className: "mb-4 text-center text-2xl font-bold text-foreground", children: "What I believe" }),
|
|
1655
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("ul", { className: "space-y-3", children: author.principles.map((principle) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1656
|
+
"li",
|
|
1657
|
+
{
|
|
1658
|
+
className: "rounded-lg border border-border bg-card px-4 py-3 text-sm text-card-foreground",
|
|
1659
|
+
children: principle
|
|
1660
|
+
},
|
|
1661
|
+
principle
|
|
1662
|
+
)) })
|
|
1663
|
+
] }) }, "principles") : null;
|
|
1664
|
+
}
|
|
1665
|
+
function renderProofSection(author) {
|
|
1666
|
+
return author.proof && author.proof.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("section", { "aria-label": "Author proof", className: "bg-background py-12", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "mx-auto max-w-4xl px-4 sm:px-6 lg:px-8", children: [
|
|
1667
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h2", { className: "mb-6 text-center text-2xl font-bold text-foreground", children: "Proof" }),
|
|
1668
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "grid gap-4 sm:grid-cols-2", children: author.proof.map((item) => {
|
|
1669
|
+
var _a, _b, _c;
|
|
1670
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
1671
|
+
"div",
|
|
1672
|
+
{
|
|
1673
|
+
className: "rounded-lg border border-border bg-card p-4 text-card-foreground",
|
|
1674
|
+
children: [
|
|
1675
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "font-medium", children: item.claim }),
|
|
1676
|
+
(item.source || item.url) && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "mt-1 text-sm text-muted-foreground", children: item.url ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_link11.default, { href: item.url, className: "hover:text-primary hover:underline", children: (_c = item.source) != null ? _c : item.url }) : item.source })
|
|
1677
|
+
]
|
|
1678
|
+
},
|
|
1679
|
+
`${item.claim}-${(_b = (_a = item.url) != null ? _a : item.source) != null ? _b : ""}`
|
|
1680
|
+
);
|
|
1681
|
+
}) })
|
|
1682
|
+
] }) }, "proof") : null;
|
|
1683
|
+
}
|
|
1684
|
+
function renderCtaSection(author, config) {
|
|
1685
|
+
return author.primaryCta ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(CtaViewTracker, { ctaId: `author-cta:${author.slug}`, config, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("section", { "aria-label": "Author call to action", className: "bg-muted/40 py-12", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "mx-auto max-w-2xl px-4 text-center sm:px-6 lg:px-8", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1686
|
+
import_link11.default,
|
|
1687
|
+
{
|
|
1688
|
+
href: author.primaryCta.href,
|
|
1689
|
+
onClick: () => emitArticleEvent(config == null ? void 0 : config.onEvent, {
|
|
1690
|
+
name: "cta_clicked",
|
|
1691
|
+
ctaId: `author-cta:${author.slug}`
|
|
1692
|
+
}),
|
|
1693
|
+
className: "inline-flex items-center justify-center rounded-md bg-primary px-6 py-3 text-sm font-semibold text-primary-foreground hover:bg-primary/90",
|
|
1694
|
+
children: author.primaryCta.label
|
|
1695
|
+
}
|
|
1696
|
+
) }) }) }, "cta") : null;
|
|
1697
|
+
}
|
|
1698
|
+
function renderArticlesSection(author, articles, pageSize, pagination) {
|
|
1699
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("section", { "aria-label": "Articles by this author", className: "bg-background py-16", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "mx-auto max-w-7xl px-4 sm:px-6 lg:px-8", children: [
|
|
1700
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "mb-8 flex items-center justify-between gap-4", children: [
|
|
1701
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_link11.default, { href: "/articles", className: "text-sm text-primary hover:underline", children: "All Articles" }),
|
|
1702
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("p", { className: "text-sm text-muted-foreground", children: [
|
|
1703
|
+
"Articles by ",
|
|
1704
|
+
author.name
|
|
1705
|
+
] })
|
|
1706
|
+
] }),
|
|
1707
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(LatestArticles, { articles, pageSize, pagination })
|
|
1708
|
+
] }) }, "articles");
|
|
1709
|
+
}
|
|
1710
|
+
function renderAuthorSection(section, ctx) {
|
|
1711
|
+
const { author, articleCount, articles, pageSize, pagination, customSection, config } = ctx;
|
|
1712
|
+
switch (section) {
|
|
1713
|
+
case "hero":
|
|
1714
|
+
return renderHeroSection(author, articleCount);
|
|
1715
|
+
case "promise":
|
|
1716
|
+
return renderPromiseSection(author);
|
|
1717
|
+
case "servesWho":
|
|
1718
|
+
return renderServesWhoSection(author);
|
|
1719
|
+
case "originStory":
|
|
1720
|
+
return renderOriginStorySection(author);
|
|
1721
|
+
case "principles":
|
|
1722
|
+
return renderPrinciplesSection(author);
|
|
1723
|
+
case "proof":
|
|
1724
|
+
return renderProofSection(author);
|
|
1725
|
+
case "cta":
|
|
1726
|
+
return renderCtaSection(author, config);
|
|
1727
|
+
case "articles":
|
|
1728
|
+
return renderArticlesSection(author, articles, pageSize, pagination);
|
|
1729
|
+
case "custom":
|
|
1730
|
+
return customSection != null ? customSection : null;
|
|
1731
|
+
default:
|
|
1732
|
+
return null;
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
function AuthorArticlesPage({
|
|
1736
|
+
author,
|
|
1737
|
+
articles,
|
|
1738
|
+
config,
|
|
1739
|
+
page,
|
|
1740
|
+
totalPages,
|
|
1741
|
+
totalCount,
|
|
1742
|
+
sections,
|
|
1743
|
+
customSection
|
|
1744
|
+
}) {
|
|
1745
|
+
var _a, _b;
|
|
1746
|
+
const pageSize = (_a = config.pageSize) != null ? _a : DEFAULT_PAGE_SIZE;
|
|
1747
|
+
const siteUrl = config.siteUrl.replace(/\/$/, "");
|
|
1748
|
+
const articleCount = totalCount != null ? totalCount : articles.length;
|
|
1749
|
+
const pagination = config.listingPagination === "pages" && page !== void 0 && totalPages !== void 0 ? { page, totalPages, basePath: `/articles/authors/${author.slug}` } : void 0;
|
|
1750
|
+
const schemas = /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
|
|
1751
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1752
|
+
"script",
|
|
1753
|
+
{
|
|
1754
|
+
type: "application/ld+json",
|
|
1755
|
+
dangerouslySetInnerHTML: {
|
|
1756
|
+
__html: JSON.stringify(getPersonSchema(author, config, articleCount))
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
),
|
|
1760
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
1761
|
+
CollectionPageSchema,
|
|
1762
|
+
{
|
|
1763
|
+
title: `${author.name} | ${config.siteName}`,
|
|
1764
|
+
description: `Articles by ${author.name} on ${config.siteName}.`,
|
|
1765
|
+
url: (_b = author.url) != null ? _b : `${siteUrl}/articles/authors/${author.slug}`,
|
|
1766
|
+
articleCount,
|
|
1767
|
+
items: articles.slice(0, pageSize).map((article, index) => ({
|
|
1768
|
+
position: index + 1,
|
|
1769
|
+
url: `${siteUrl}/articles/${article.slug}`,
|
|
1770
|
+
name: article.title
|
|
1771
|
+
}))
|
|
1772
|
+
}
|
|
1773
|
+
)
|
|
1774
|
+
] });
|
|
1775
|
+
if (!sections) {
|
|
1776
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
|
|
1777
|
+
schemas,
|
|
1778
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("section", { className: "bg-background py-16", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "mx-auto max-w-7xl px-4 sm:px-6 lg:px-8", children: [
|
|
1779
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "mb-8 flex items-center justify-between gap-4", children: [
|
|
1780
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_link11.default, { href: "/articles", className: "text-sm text-primary hover:underline", children: "All Articles" }),
|
|
1781
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("p", { className: "text-sm text-muted-foreground", children: [
|
|
1782
|
+
"Articles by ",
|
|
1783
|
+
author.name
|
|
1784
|
+
] })
|
|
1785
|
+
] }),
|
|
1786
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(LatestArticles, { articles, pageSize, pagination })
|
|
1787
|
+
] }) })
|
|
1788
|
+
] });
|
|
1789
|
+
}
|
|
1790
|
+
const sectionCtx = {
|
|
1791
|
+
author,
|
|
1792
|
+
articleCount,
|
|
1793
|
+
articles,
|
|
1794
|
+
pageSize,
|
|
1795
|
+
pagination,
|
|
1796
|
+
customSection,
|
|
1797
|
+
config
|
|
1798
|
+
};
|
|
1799
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
|
|
1800
|
+
schemas,
|
|
1801
|
+
sections.map((section) => renderAuthorSection(section, sectionCtx))
|
|
1802
|
+
] });
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
// src/ArticleSocialShare.tsx
|
|
1806
|
+
var import_react6 = require("react");
|
|
1807
|
+
var import_lucide_react8 = require("lucide-react");
|
|
1808
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1809
|
+
function ArticleSocialShare({
|
|
1810
|
+
title,
|
|
1811
|
+
url,
|
|
1812
|
+
excerpt,
|
|
1813
|
+
shareMessage,
|
|
1814
|
+
config,
|
|
1815
|
+
articleSlug
|
|
1816
|
+
}) {
|
|
1817
|
+
const [copied, setCopied] = (0, import_react6.useState)(false);
|
|
1818
|
+
function trackShare(channel) {
|
|
1819
|
+
if (!articleSlug) return;
|
|
1820
|
+
emitArticleEvent(config == null ? void 0 : config.onEvent, { name: "shared", articleSlug, channel });
|
|
1821
|
+
}
|
|
1346
1822
|
const encodedTitle = encodeURIComponent(title);
|
|
1347
1823
|
const encodedUrl = encodeURIComponent(url);
|
|
1348
1824
|
const encodedExcerpt = encodeURIComponent(excerpt || "");
|
|
@@ -1359,102 +1835,203 @@ function ArticleSocialShare({ title, url, excerpt, shareMessage }) {
|
|
|
1359
1835
|
try {
|
|
1360
1836
|
yield navigator.clipboard.writeText(url);
|
|
1361
1837
|
setCopied(true);
|
|
1838
|
+
trackShare("copy-link");
|
|
1362
1839
|
setTimeout(() => setCopied(false), 2e3);
|
|
1363
1840
|
} catch (e) {
|
|
1364
1841
|
}
|
|
1365
1842
|
});
|
|
1366
|
-
const openShareWindow = (shareUrl) => {
|
|
1843
|
+
const openShareWindow = (shareUrl, channel) => {
|
|
1844
|
+
trackShare(channel);
|
|
1367
1845
|
globalThis.open(shareUrl, "_blank", "width=600,height=400,scrollbars=yes,resizable=yes");
|
|
1368
1846
|
};
|
|
1369
1847
|
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";
|
|
1370
|
-
return /* @__PURE__ */ (0,
|
|
1371
|
-
/* @__PURE__ */ (0,
|
|
1372
|
-
/* @__PURE__ */ (0,
|
|
1373
|
-
/* @__PURE__ */ (0,
|
|
1848
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "border-t border-border pt-8 mt-8", children: [
|
|
1849
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2 mb-4", children: [
|
|
1850
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react8.Share2, { className: "h-5 w-5 text-muted-foreground" }),
|
|
1851
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h3", { className: "text-lg font-semibold text-foreground", children: "Share this article" })
|
|
1374
1852
|
] }),
|
|
1375
|
-
/* @__PURE__ */ (0,
|
|
1376
|
-
/* @__PURE__ */ (0,
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
/* @__PURE__ */ (0,
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
/* @__PURE__ */ (0,
|
|
1401
|
-
|
|
1853
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex flex-wrap gap-2", children: [
|
|
1854
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
1855
|
+
"button",
|
|
1856
|
+
{
|
|
1857
|
+
type: "button",
|
|
1858
|
+
className: btnClass,
|
|
1859
|
+
onClick: () => openShareWindow(shareLinks.linkedin, "linkedin"),
|
|
1860
|
+
children: [
|
|
1861
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react8.Users, { className: "h-4 w-4" }),
|
|
1862
|
+
"LinkedIn"
|
|
1863
|
+
]
|
|
1864
|
+
}
|
|
1865
|
+
),
|
|
1866
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
1867
|
+
"button",
|
|
1868
|
+
{
|
|
1869
|
+
type: "button",
|
|
1870
|
+
className: btnClass,
|
|
1871
|
+
onClick: () => openShareWindow(shareLinks.facebook, "facebook"),
|
|
1872
|
+
children: [
|
|
1873
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-xs font-bold", children: "f" }),
|
|
1874
|
+
" Facebook"
|
|
1875
|
+
]
|
|
1876
|
+
}
|
|
1877
|
+
),
|
|
1878
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
1879
|
+
"button",
|
|
1880
|
+
{
|
|
1881
|
+
type: "button",
|
|
1882
|
+
className: btnClass,
|
|
1883
|
+
onClick: () => openShareWindow(shareLinks.twitter, "twitter"),
|
|
1884
|
+
children: [
|
|
1885
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react8.MessageCircle, { className: "h-4 w-4" }),
|
|
1886
|
+
"Twitter"
|
|
1887
|
+
]
|
|
1888
|
+
}
|
|
1889
|
+
),
|
|
1890
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
1891
|
+
"button",
|
|
1892
|
+
{
|
|
1893
|
+
type: "button",
|
|
1894
|
+
className: btnClass,
|
|
1895
|
+
onClick: () => openShareWindow(shareLinks.reddit, "reddit"),
|
|
1896
|
+
children: [
|
|
1897
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react8.FileText, { className: "h-4 w-4" }),
|
|
1898
|
+
"Reddit"
|
|
1899
|
+
]
|
|
1900
|
+
}
|
|
1901
|
+
),
|
|
1902
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
1903
|
+
"button",
|
|
1904
|
+
{
|
|
1905
|
+
type: "button",
|
|
1906
|
+
className: btnClass,
|
|
1907
|
+
onClick: () => openShareWindow(shareLinks.whatsapp, "whatsapp"),
|
|
1908
|
+
children: [
|
|
1909
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react8.MessageCircle, { className: "h-4 w-4" }),
|
|
1910
|
+
"WhatsApp"
|
|
1911
|
+
]
|
|
1912
|
+
}
|
|
1913
|
+
),
|
|
1914
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
1915
|
+
"button",
|
|
1916
|
+
{
|
|
1917
|
+
type: "button",
|
|
1918
|
+
className: btnClass,
|
|
1919
|
+
onClick: () => openShareWindow(shareLinks.telegram, "telegram"),
|
|
1920
|
+
children: [
|
|
1921
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react8.MessageCircle, { className: "h-4 w-4" }),
|
|
1922
|
+
"Telegram"
|
|
1923
|
+
]
|
|
1924
|
+
}
|
|
1925
|
+
),
|
|
1926
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("a", { className: btnClass, href: shareLinks.email, onClick: () => trackShare("email"), children: [
|
|
1927
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react8.Mail, { className: "h-4 w-4" }),
|
|
1402
1928
|
"Email"
|
|
1403
1929
|
] }),
|
|
1404
|
-
/* @__PURE__ */ (0,
|
|
1405
|
-
copied ? /* @__PURE__ */ (0,
|
|
1930
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("button", { type: "button", className: btnClass, onClick: copyToClipboard, children: [
|
|
1931
|
+
copied ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react8.Check, { className: "h-4 w-4" }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react8.Copy, { className: "h-4 w-4" }),
|
|
1406
1932
|
copied ? "Copied!" : "Copy Link"
|
|
1407
1933
|
] })
|
|
1408
1934
|
] }),
|
|
1409
|
-
shareMessage && /* @__PURE__ */ (0,
|
|
1935
|
+
shareMessage && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-sm text-muted-foreground mt-3", children: shareMessage })
|
|
1410
1936
|
] });
|
|
1411
1937
|
}
|
|
1412
1938
|
|
|
1413
1939
|
// src/ArticleNavigation.tsx
|
|
1414
|
-
var
|
|
1415
|
-
var
|
|
1416
|
-
var
|
|
1940
|
+
var import_link12 = __toESM(require("next/link"), 1);
|
|
1941
|
+
var import_lucide_react9 = require("lucide-react");
|
|
1942
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1417
1943
|
function truncateTitle(title, maxLength = 60) {
|
|
1418
1944
|
return title.length > maxLength ? `${title.substring(0, maxLength)}...` : title;
|
|
1419
1945
|
}
|
|
1420
|
-
function ArticleNavigation({
|
|
1946
|
+
function ArticleNavigation({
|
|
1947
|
+
previous,
|
|
1948
|
+
next,
|
|
1949
|
+
basePath,
|
|
1950
|
+
fromSlug,
|
|
1951
|
+
pathKey,
|
|
1952
|
+
config
|
|
1953
|
+
}) {
|
|
1421
1954
|
if (!previous && !next) return null;
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1955
|
+
function emitStep(toSlug2, direction) {
|
|
1956
|
+
if (!pathKey || !fromSlug) return;
|
|
1957
|
+
emitArticleEvent(config == null ? void 0 : config.onEvent, {
|
|
1958
|
+
name: "path_step_advanced",
|
|
1959
|
+
pathKey,
|
|
1960
|
+
fromSlug,
|
|
1961
|
+
toSlug: toSlug2,
|
|
1962
|
+
direction
|
|
1963
|
+
});
|
|
1964
|
+
}
|
|
1965
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("nav", { className: "mt-12 pt-8 border-t border-border", "aria-label": "Article navigation", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex justify-between gap-4", children: [
|
|
1966
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex-1 min-w-0", children: previous && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
1967
|
+
import_link12.default,
|
|
1425
1968
|
{
|
|
1426
1969
|
href: `${basePath}/${previous.slug}`,
|
|
1970
|
+
onClick: () => emitStep(previous.slug, "previous"),
|
|
1427
1971
|
className: "group flex items-center gap-3 p-4 rounded-lg border border-border hover:border-primary/20 hover:bg-muted/50 transition-colors",
|
|
1428
1972
|
children: [
|
|
1429
|
-
/* @__PURE__ */ (0,
|
|
1430
|
-
/* @__PURE__ */ (0,
|
|
1431
|
-
/* @__PURE__ */ (0,
|
|
1432
|
-
/* @__PURE__ */ (0,
|
|
1973
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.ChevronLeft, { className: "h-5 w-5 text-muted-foreground group-hover:text-primary shrink-0" }),
|
|
1974
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "min-w-0 flex-1", children: [
|
|
1975
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "text-sm text-muted-foreground mb-1", children: "Previous Article" }),
|
|
1976
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "font-medium text-foreground truncate", title: previous.title, children: truncateTitle(previous.title) })
|
|
1433
1977
|
] })
|
|
1434
1978
|
]
|
|
1435
1979
|
}
|
|
1436
1980
|
) }),
|
|
1437
|
-
/* @__PURE__ */ (0,
|
|
1438
|
-
|
|
1981
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex-1 min-w-0", children: next && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
1982
|
+
import_link12.default,
|
|
1439
1983
|
{
|
|
1440
1984
|
href: `${basePath}/${next.slug}`,
|
|
1985
|
+
onClick: () => emitStep(next.slug, "next"),
|
|
1441
1986
|
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",
|
|
1442
1987
|
children: [
|
|
1443
|
-
/* @__PURE__ */ (0,
|
|
1444
|
-
/* @__PURE__ */ (0,
|
|
1445
|
-
/* @__PURE__ */ (0,
|
|
1988
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "min-w-0 flex-1 text-right", children: [
|
|
1989
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "text-sm text-muted-foreground mb-1", children: "Next Article" }),
|
|
1990
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "font-medium text-foreground truncate", title: next.title, children: truncateTitle(next.title) })
|
|
1446
1991
|
] }),
|
|
1447
|
-
/* @__PURE__ */ (0,
|
|
1992
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react9.ChevronRight, { className: "h-5 w-5 text-muted-foreground group-hover:text-primary shrink-0" })
|
|
1448
1993
|
]
|
|
1449
1994
|
}
|
|
1450
1995
|
) })
|
|
1451
1996
|
] }) });
|
|
1452
1997
|
}
|
|
1453
1998
|
|
|
1999
|
+
// src/RelatedArticlesSection.tsx
|
|
2000
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
2001
|
+
function RelatedArticlesSection({
|
|
2002
|
+
articles,
|
|
2003
|
+
category,
|
|
2004
|
+
heading,
|
|
2005
|
+
config,
|
|
2006
|
+
fromSlug,
|
|
2007
|
+
source = "category"
|
|
2008
|
+
}) {
|
|
2009
|
+
if (articles.length === 0) return null;
|
|
2010
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("section", { className: "mt-12 pt-8 border-t border-border", "aria-label": "Related articles", children: [
|
|
2011
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h2", { className: "text-xl font-semibold text-foreground mb-6", children: heading != null ? heading : `More in ${category}` }),
|
|
2012
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "grid gap-6 sm:grid-cols-2 lg:grid-cols-3", children: articles.map((article) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2013
|
+
"div",
|
|
2014
|
+
{
|
|
2015
|
+
onClickCapture: () => {
|
|
2016
|
+
if (!fromSlug) return;
|
|
2017
|
+
emitArticleEvent(config == null ? void 0 : config.onEvent, {
|
|
2018
|
+
name: "related_article_clicked",
|
|
2019
|
+
fromSlug,
|
|
2020
|
+
toSlug: article.slug,
|
|
2021
|
+
source
|
|
2022
|
+
});
|
|
2023
|
+
},
|
|
2024
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ArticleCard, { article, config })
|
|
2025
|
+
},
|
|
2026
|
+
article.slug
|
|
2027
|
+
)) })
|
|
2028
|
+
] });
|
|
2029
|
+
}
|
|
2030
|
+
|
|
1454
2031
|
// src/ArticleBackLink.tsx
|
|
1455
|
-
var
|
|
1456
|
-
var
|
|
1457
|
-
var
|
|
2032
|
+
var import_link13 = __toESM(require("next/link"), 1);
|
|
2033
|
+
var import_lucide_react10 = require("lucide-react");
|
|
2034
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
1458
2035
|
function ArticleBackLink({
|
|
1459
2036
|
config,
|
|
1460
2037
|
href = "/articles",
|
|
@@ -1462,13 +2039,13 @@ function ArticleBackLink({
|
|
|
1462
2039
|
className
|
|
1463
2040
|
}) {
|
|
1464
2041
|
if (config.showBackToArticles === false) return null;
|
|
1465
|
-
return /* @__PURE__ */ (0,
|
|
1466
|
-
|
|
2042
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
2043
|
+
import_link13.default,
|
|
1467
2044
|
{
|
|
1468
2045
|
href,
|
|
1469
2046
|
className: className != null ? className : "inline-flex items-center gap-2 mb-6 -ml-3 px-3 py-2 rounded-md text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-muted/50 transition-colors",
|
|
1470
2047
|
children: [
|
|
1471
|
-
/* @__PURE__ */ (0,
|
|
2048
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_lucide_react10.ArrowLeft, { className: "h-4 w-4" }),
|
|
1472
2049
|
label
|
|
1473
2050
|
]
|
|
1474
2051
|
}
|
|
@@ -1476,17 +2053,17 @@ function ArticleBackLink({
|
|
|
1476
2053
|
}
|
|
1477
2054
|
|
|
1478
2055
|
// src/ArticleTOC.tsx
|
|
1479
|
-
var
|
|
2056
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1480
2057
|
function ArticleTOC({ toc, className }) {
|
|
1481
2058
|
if (!toc.length) return null;
|
|
1482
|
-
return /* @__PURE__ */ (0,
|
|
2059
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
1483
2060
|
"nav",
|
|
1484
2061
|
{
|
|
1485
2062
|
"aria-label": "Table of contents",
|
|
1486
2063
|
className: `mb-8 rounded-lg border border-border bg-muted/40 px-6 py-4 ${className != null ? className : ""}`,
|
|
1487
2064
|
children: [
|
|
1488
|
-
/* @__PURE__ */ (0,
|
|
1489
|
-
/* @__PURE__ */ (0,
|
|
2065
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "mb-3 text-sm font-semibold uppercase tracking-wide text-muted-foreground", children: "On this page" }),
|
|
2066
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("ul", { className: "space-y-1 text-sm", children: toc.map((item) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("li", { style: { paddingLeft: `${Math.max(0, item.depth - 2) * 1}rem` }, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1490
2067
|
"a",
|
|
1491
2068
|
{
|
|
1492
2069
|
href: `#${item.id}`,
|
|
@@ -1500,35 +2077,35 @@ function ArticleTOC({ toc, className }) {
|
|
|
1500
2077
|
}
|
|
1501
2078
|
|
|
1502
2079
|
// src/ScrollToTop.tsx
|
|
1503
|
-
var
|
|
1504
|
-
var
|
|
1505
|
-
var
|
|
2080
|
+
var import_react7 = require("react");
|
|
2081
|
+
var import_lucide_react11 = require("lucide-react");
|
|
2082
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1506
2083
|
function ScrollToTop() {
|
|
1507
|
-
const [visible, setVisible] = (0,
|
|
1508
|
-
(0,
|
|
2084
|
+
const [visible, setVisible] = (0, import_react7.useState)(false);
|
|
2085
|
+
(0, import_react7.useEffect)(() => {
|
|
1509
2086
|
const onScroll = () => setVisible(globalThis.scrollY > 300);
|
|
1510
2087
|
globalThis.addEventListener("scroll", onScroll, { passive: true });
|
|
1511
2088
|
return () => globalThis.removeEventListener("scroll", onScroll);
|
|
1512
2089
|
}, []);
|
|
1513
2090
|
if (!visible) return null;
|
|
1514
|
-
return /* @__PURE__ */ (0,
|
|
2091
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
1515
2092
|
"button",
|
|
1516
2093
|
{
|
|
1517
2094
|
"aria-label": "Scroll to top",
|
|
1518
2095
|
onClick: () => globalThis.scrollTo({ top: 0, behavior: "smooth" }),
|
|
1519
2096
|
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",
|
|
1520
|
-
children: /* @__PURE__ */ (0,
|
|
2097
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react11.ArrowUp, { className: "h-5 w-5" })
|
|
1521
2098
|
}
|
|
1522
2099
|
);
|
|
1523
2100
|
}
|
|
1524
2101
|
|
|
1525
2102
|
// src/CommentsSection.tsx
|
|
1526
|
-
var
|
|
1527
|
-
var
|
|
2103
|
+
var import_react10 = require("next-auth/react");
|
|
2104
|
+
var import_react11 = require("react");
|
|
1528
2105
|
|
|
1529
2106
|
// src/CommentForm.tsx
|
|
1530
|
-
var
|
|
1531
|
-
var
|
|
2107
|
+
var import_react8 = require("react");
|
|
2108
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1532
2109
|
var MAX_LENGTH = 2e3;
|
|
1533
2110
|
var WARN_THRESHOLD = 1800;
|
|
1534
2111
|
function submitLabel(submitting, parentId) {
|
|
@@ -1536,9 +2113,9 @@ function submitLabel(submitting, parentId) {
|
|
|
1536
2113
|
return parentId ? "Reply" : "Post comment";
|
|
1537
2114
|
}
|
|
1538
2115
|
function CommentForm({ articleSlug, parentId, onSuccess, onCancel }) {
|
|
1539
|
-
const [body, setBody] = (0,
|
|
1540
|
-
const [submitting, setSubmitting] = (0,
|
|
1541
|
-
const [error, setError] = (0,
|
|
2116
|
+
const [body, setBody] = (0, import_react8.useState)("");
|
|
2117
|
+
const [submitting, setSubmitting] = (0, import_react8.useState)(false);
|
|
2118
|
+
const [error, setError] = (0, import_react8.useState)(null);
|
|
1542
2119
|
const remaining = MAX_LENGTH - body.length;
|
|
1543
2120
|
function handleSubmit(e) {
|
|
1544
2121
|
return __async(this, null, function* () {
|
|
@@ -1567,8 +2144,8 @@ function CommentForm({ articleSlug, parentId, onSuccess, onCancel }) {
|
|
|
1567
2144
|
}
|
|
1568
2145
|
});
|
|
1569
2146
|
}
|
|
1570
|
-
return /* @__PURE__ */ (0,
|
|
1571
|
-
/* @__PURE__ */ (0,
|
|
2147
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("form", { onSubmit: handleSubmit, className: "space-y-2", children: [
|
|
2148
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1572
2149
|
"textarea",
|
|
1573
2150
|
{
|
|
1574
2151
|
value: body,
|
|
@@ -1581,13 +2158,13 @@ function CommentForm({ articleSlug, parentId, onSuccess, onCancel }) {
|
|
|
1581
2158
|
"aria-label": parentId ? "Reply text" : "Comment text"
|
|
1582
2159
|
}
|
|
1583
2160
|
),
|
|
1584
|
-
remaining <= MAX_LENGTH - WARN_THRESHOLD && /* @__PURE__ */ (0,
|
|
2161
|
+
remaining <= MAX_LENGTH - WARN_THRESHOLD && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("p", { className: `text-xs ${remaining < 0 ? "text-destructive" : "text-muted-foreground"}`, children: [
|
|
1585
2162
|
remaining,
|
|
1586
2163
|
" characters remaining"
|
|
1587
2164
|
] }),
|
|
1588
|
-
error && /* @__PURE__ */ (0,
|
|
1589
|
-
/* @__PURE__ */ (0,
|
|
1590
|
-
/* @__PURE__ */ (0,
|
|
2165
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { className: "text-xs text-destructive", children: error }),
|
|
2166
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex gap-2", children: [
|
|
2167
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1591
2168
|
"button",
|
|
1592
2169
|
{
|
|
1593
2170
|
type: "submit",
|
|
@@ -1596,7 +2173,7 @@ function CommentForm({ articleSlug, parentId, onSuccess, onCancel }) {
|
|
|
1596
2173
|
children: submitLabel(submitting, parentId)
|
|
1597
2174
|
}
|
|
1598
2175
|
),
|
|
1599
|
-
onCancel && /* @__PURE__ */ (0,
|
|
2176
|
+
onCancel && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1600
2177
|
"button",
|
|
1601
2178
|
{
|
|
1602
2179
|
type: "button",
|
|
@@ -1610,8 +2187,8 @@ function CommentForm({ articleSlug, parentId, onSuccess, onCancel }) {
|
|
|
1610
2187
|
}
|
|
1611
2188
|
|
|
1612
2189
|
// src/CommentItem.tsx
|
|
1613
|
-
var
|
|
1614
|
-
var
|
|
2190
|
+
var import_react9 = require("react");
|
|
2191
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1615
2192
|
function relativeTime(iso) {
|
|
1616
2193
|
const diff = Date.now() - new Date(iso).getTime();
|
|
1617
2194
|
const minutes = Math.floor(diff / 6e4);
|
|
@@ -1632,8 +2209,8 @@ function CommentItem({
|
|
|
1632
2209
|
isReply = false,
|
|
1633
2210
|
onRefresh
|
|
1634
2211
|
}) {
|
|
1635
|
-
const [showReplyForm, setShowReplyForm] = (0,
|
|
1636
|
-
const [deleting, setDeleting] = (0,
|
|
2212
|
+
const [showReplyForm, setShowReplyForm] = (0, import_react9.useState)(false);
|
|
2213
|
+
const [deleting, setDeleting] = (0, import_react9.useState)(false);
|
|
1637
2214
|
const replies = "replies" in comment ? comment.replies : [];
|
|
1638
2215
|
const canReply = !isReply && !!currentUserId && !comment.isDeleted;
|
|
1639
2216
|
const canDelete = !!currentUserId && currentUserId === comment.authorId && !comment.isDeleted;
|
|
@@ -1649,15 +2226,15 @@ function CommentItem({
|
|
|
1649
2226
|
}
|
|
1650
2227
|
});
|
|
1651
2228
|
}
|
|
1652
|
-
return /* @__PURE__ */ (0,
|
|
1653
|
-
/* @__PURE__ */ (0,
|
|
1654
|
-
/* @__PURE__ */ (0,
|
|
1655
|
-
/* @__PURE__ */ (0,
|
|
1656
|
-
/* @__PURE__ */ (0,
|
|
2229
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: `${isReply ? "ml-8 border-l-2 border-border pl-4" : ""}`, children: [
|
|
2230
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "rounded-lg bg-muted/40 p-3 space-y-1", children: comment.isDeleted ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "text-sm italic text-muted-foreground", children: "Comment removed" }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
|
|
2231
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
|
|
2232
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-sm font-medium text-foreground", children: comment.authorName }),
|
|
2233
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "text-xs text-muted-foreground", children: relativeTime(comment.createdAt) })
|
|
1657
2234
|
] }),
|
|
1658
|
-
/* @__PURE__ */ (0,
|
|
1659
|
-
/* @__PURE__ */ (0,
|
|
1660
|
-
canReply && /* @__PURE__ */ (0,
|
|
2235
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { className: "text-sm text-foreground whitespace-pre-wrap break-words", children: comment.body }),
|
|
2236
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex gap-3 pt-1", children: [
|
|
2237
|
+
canReply && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1661
2238
|
"button",
|
|
1662
2239
|
{
|
|
1663
2240
|
onClick: () => setShowReplyForm((v) => !v),
|
|
@@ -1665,7 +2242,7 @@ function CommentItem({
|
|
|
1665
2242
|
children: showReplyForm ? "Cancel" : "Reply"
|
|
1666
2243
|
}
|
|
1667
2244
|
),
|
|
1668
|
-
canDelete && /* @__PURE__ */ (0,
|
|
2245
|
+
canDelete && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1669
2246
|
"button",
|
|
1670
2247
|
{
|
|
1671
2248
|
onClick: handleDelete,
|
|
@@ -1676,7 +2253,7 @@ function CommentItem({
|
|
|
1676
2253
|
)
|
|
1677
2254
|
] })
|
|
1678
2255
|
] }) }),
|
|
1679
|
-
showReplyForm && /* @__PURE__ */ (0,
|
|
2256
|
+
showReplyForm && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "mt-2 ml-2", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1680
2257
|
CommentForm,
|
|
1681
2258
|
{
|
|
1682
2259
|
articleSlug,
|
|
@@ -1688,7 +2265,7 @@ function CommentItem({
|
|
|
1688
2265
|
onCancel: () => setShowReplyForm(false)
|
|
1689
2266
|
}
|
|
1690
2267
|
) }),
|
|
1691
|
-
replies.length > 0 && /* @__PURE__ */ (0,
|
|
2268
|
+
replies.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "mt-2 space-y-2", children: replies.map((reply) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1692
2269
|
CommentItem,
|
|
1693
2270
|
{
|
|
1694
2271
|
comment: __spreadProps(__spreadValues({}, reply), { replies: [] }),
|
|
@@ -1703,7 +2280,7 @@ function CommentItem({
|
|
|
1703
2280
|
}
|
|
1704
2281
|
|
|
1705
2282
|
// src/CommentThread.tsx
|
|
1706
|
-
var
|
|
2283
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1707
2284
|
function CommentThread({
|
|
1708
2285
|
comments,
|
|
1709
2286
|
articleSlug,
|
|
@@ -1711,9 +2288,9 @@ function CommentThread({
|
|
|
1711
2288
|
onRefresh
|
|
1712
2289
|
}) {
|
|
1713
2290
|
if (comments.length === 0) {
|
|
1714
|
-
return /* @__PURE__ */ (0,
|
|
2291
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "text-sm text-muted-foreground text-center py-6", children: "No comments yet. Be the first to share your thoughts." });
|
|
1715
2292
|
}
|
|
1716
|
-
return /* @__PURE__ */ (0,
|
|
2293
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "space-y-4", children: comments.map((comment) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1717
2294
|
CommentItem,
|
|
1718
2295
|
{
|
|
1719
2296
|
comment,
|
|
@@ -1726,17 +2303,17 @@ function CommentThread({
|
|
|
1726
2303
|
}
|
|
1727
2304
|
|
|
1728
2305
|
// src/CommentsSection.tsx
|
|
1729
|
-
var
|
|
2306
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1730
2307
|
function CommentsSection({ articleSlug, config }) {
|
|
1731
2308
|
var _a, _b, _c, _d, _e, _f;
|
|
1732
|
-
const { data: session, status } = (0,
|
|
1733
|
-
const [comments, setComments] = (0,
|
|
1734
|
-
const [loading, setLoading] = (0,
|
|
1735
|
-
const [fetchError, setFetchError] = (0,
|
|
2309
|
+
const { data: session, status } = (0, import_react10.useSession)();
|
|
2310
|
+
const [comments, setComments] = (0, import_react11.useState)([]);
|
|
2311
|
+
const [loading, setLoading] = (0, import_react11.useState)(true);
|
|
2312
|
+
const [fetchError, setFetchError] = (0, import_react11.useState)(null);
|
|
1736
2313
|
const perArticleEnabled = (_b = (_a = config.perArticleOverride) == null ? void 0 : _a[articleSlug]) != null ? _b : true;
|
|
1737
2314
|
const enabled = config.enabled && perArticleEnabled;
|
|
1738
2315
|
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;
|
|
1739
|
-
const fetchComments = (0,
|
|
2316
|
+
const fetchComments = (0, import_react11.useCallback)(() => __async(this, null, function* () {
|
|
1740
2317
|
setLoading(true);
|
|
1741
2318
|
setFetchError(null);
|
|
1742
2319
|
try {
|
|
@@ -1750,7 +2327,7 @@ function CommentsSection({ articleSlug, config }) {
|
|
|
1750
2327
|
setLoading(false);
|
|
1751
2328
|
}
|
|
1752
2329
|
}), [articleSlug]);
|
|
1753
|
-
(0,
|
|
2330
|
+
(0, import_react11.useEffect)(() => {
|
|
1754
2331
|
if (enabled) {
|
|
1755
2332
|
fetchComments().catch(() => void 0);
|
|
1756
2333
|
}
|
|
@@ -1758,13 +2335,13 @@ function CommentsSection({ articleSlug, config }) {
|
|
|
1758
2335
|
if (!enabled) return null;
|
|
1759
2336
|
const count = comments.length;
|
|
1760
2337
|
const label = count === 1 ? "1 comment" : `${count} comments`;
|
|
1761
|
-
return /* @__PURE__ */ (0,
|
|
1762
|
-
/* @__PURE__ */ (0,
|
|
1763
|
-
status === "authenticated" ? /* @__PURE__ */ (0,
|
|
1764
|
-
/* @__PURE__ */ (0,
|
|
2338
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("section", { "aria-label": "Comments", className: "mt-12 pt-8 border-t border-border space-y-6", children: [
|
|
2339
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("h2", { className: "text-xl font-semibold text-foreground", children: loading ? "Comments" : label }),
|
|
2340
|
+
status === "authenticated" ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(CommentForm, { articleSlug, onSuccess: fetchComments }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("p", { className: "text-sm text-muted-foreground", children: [
|
|
2341
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1765
2342
|
"button",
|
|
1766
2343
|
{
|
|
1767
|
-
onClick: () => (0,
|
|
2344
|
+
onClick: () => (0, import_react10.signIn)(),
|
|
1768
2345
|
className: "text-primary underline hover:no-underline focus:outline-none",
|
|
1769
2346
|
children: "Sign in"
|
|
1770
2347
|
}
|
|
@@ -1772,8 +2349,8 @@ function CommentsSection({ articleSlug, config }) {
|
|
|
1772
2349
|
" ",
|
|
1773
2350
|
"to join the discussion."
|
|
1774
2351
|
] }),
|
|
1775
|
-
fetchError && /* @__PURE__ */ (0,
|
|
1776
|
-
loading ? /* @__PURE__ */ (0,
|
|
2352
|
+
fetchError && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "text-sm text-destructive", children: fetchError }),
|
|
2353
|
+
loading ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("p", { className: "text-sm text-muted-foreground", children: "Loading comments\u2026" }) : /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1777
2354
|
CommentThread,
|
|
1778
2355
|
{
|
|
1779
2356
|
comments,
|
|
@@ -1792,10 +2369,10 @@ function CommentsSection({ articleSlug, config }) {
|
|
|
1792
2369
|
ArticleDetailHero,
|
|
1793
2370
|
ArticleNavigation,
|
|
1794
2371
|
ArticleSEO,
|
|
1795
|
-
ArticleSchema,
|
|
1796
2372
|
ArticleSearchBar,
|
|
1797
2373
|
ArticleSocialShare,
|
|
1798
2374
|
ArticleTOC,
|
|
2375
|
+
ArticleViewTracker,
|
|
1799
2376
|
ArticlesHero,
|
|
1800
2377
|
ArticlesPage,
|
|
1801
2378
|
AuthorArticlesPage,
|
|
@@ -1810,6 +2387,7 @@ function CommentsSection({ articleSlug, config }) {
|
|
|
1810
2387
|
CommentItem,
|
|
1811
2388
|
CommentThread,
|
|
1812
2389
|
CommentsSection,
|
|
2390
|
+
CtaViewTracker,
|
|
1813
2391
|
DEFAULT_CATEGORIES_PAGE_SIZE,
|
|
1814
2392
|
DEFAULT_LAYOUT,
|
|
1815
2393
|
DEFAULT_PAGE_SIZE,
|
|
@@ -1817,7 +2395,10 @@ function CommentsSection({ articleSlug, config }) {
|
|
|
1817
2395
|
FeaturedArticle,
|
|
1818
2396
|
LatestArticles,
|
|
1819
2397
|
LatestArticlesSection,
|
|
2398
|
+
PaginationNav,
|
|
2399
|
+
RelatedArticlesSection,
|
|
1820
2400
|
ScrollToTop,
|
|
2401
|
+
SeriesArticlesPage,
|
|
1821
2402
|
breadcrumbsAreEnabled,
|
|
1822
2403
|
getBreadcrumbsConfig,
|
|
1823
2404
|
useArticles
|