@fullstackdatasolutions/articles 0.8.2 → 0.10.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 +237 -0
- package/README.md +209 -78
- package/dist/index.cjs +635 -274
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +164 -56
- package/dist/index.d.ts +164 -56
- package/dist/index.js +614 -250
- package/dist/index.js.map +1 -1
- package/dist/nextjs.cjs +113 -38
- package/dist/nextjs.cjs.map +1 -1
- package/dist/nextjs.d.cts +71 -0
- package/dist/nextjs.d.ts +71 -0
- package/dist/nextjs.js +113 -38
- package/dist/nextjs.js.map +1 -1
- package/dist/server.cjs +394 -52
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +96 -6
- package/dist/server.d.ts +96 -6
- package/dist/server.js +382 -52
- package/dist/server.js.map +1 -1
- package/package.json +8 -5
- package/src/ArticleContent.tsx +8 -3
- package/src/ArticleDetailHero.tsx +27 -2
- package/src/ArticleSchemas.tsx +27 -27
- package/src/AuthorArticlesPage.tsx +60 -0
- package/src/AuthorCard.tsx +112 -0
- package/src/AuthorDetailHero.tsx +56 -0
- package/src/Breadcrumb.tsx +78 -0
- package/src/CategoryArticlesPage.tsx +62 -11
- package/src/__tests__/ArticleContent.test.tsx +18 -2
- package/src/__tests__/ArticleDetailHero.test.tsx +21 -1
- package/src/__tests__/ArticleSchemas.test.tsx +47 -2
- package/src/__tests__/AuthorArticlesPage.test.tsx +74 -0
- package/src/__tests__/AuthorCard.test.tsx +98 -0
- package/src/__tests__/AuthorDetailHero.test.tsx +51 -0
- package/src/__tests__/CategoryArticlesPage.test.tsx +31 -5
- package/src/__tests__/authorUtils.test.ts +89 -0
- package/src/__tests__/markdown.test.ts +79 -3
- package/src/__tests__/renderMdx.test.tsx +57 -0
- package/src/__tests__/seoUtils-authors.test.ts +160 -0
- package/src/__tests__/seoUtils.test.ts +106 -0
- package/src/__tests__/server-articles.test.ts +174 -3
- package/src/articleTypes.ts +33 -0
- package/src/articlesConfig.ts +67 -0
- package/src/authorUtils.ts +95 -0
- package/src/index.ts +32 -9
- package/src/markdown.ts +67 -8
- package/src/renderMdx.tsx +6 -3
- package/src/seoUtils.ts +279 -6
- package/src/server-articles.ts +124 -34
- package/src/server.ts +21 -2
package/dist/server.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ interface Article {
|
|
|
21
21
|
date?: string;
|
|
22
22
|
lastmod?: string;
|
|
23
23
|
author: string;
|
|
24
|
+
authors?: string[];
|
|
24
25
|
category: string;
|
|
25
26
|
categories: string[];
|
|
26
27
|
readTime: string;
|
|
@@ -45,6 +46,35 @@ interface CategoryInfo {
|
|
|
45
46
|
count: number;
|
|
46
47
|
featuredImage: string;
|
|
47
48
|
}
|
|
49
|
+
interface AuthorSocial {
|
|
50
|
+
website?: string;
|
|
51
|
+
facebook?: string;
|
|
52
|
+
twitter?: string;
|
|
53
|
+
x?: string;
|
|
54
|
+
linkedin?: string;
|
|
55
|
+
instagram?: string;
|
|
56
|
+
youtube?: string;
|
|
57
|
+
tiktok?: string;
|
|
58
|
+
github?: string;
|
|
59
|
+
bluesky?: string;
|
|
60
|
+
threads?: string;
|
|
61
|
+
mastodon?: string;
|
|
62
|
+
medium?: string;
|
|
63
|
+
newsletter?: string;
|
|
64
|
+
other?: Record<string, string>;
|
|
65
|
+
}
|
|
66
|
+
interface AuthorProfile {
|
|
67
|
+
name: string;
|
|
68
|
+
slug: string;
|
|
69
|
+
bio: string;
|
|
70
|
+
avatar?: string;
|
|
71
|
+
url?: string;
|
|
72
|
+
social?: AuthorSocial;
|
|
73
|
+
}
|
|
74
|
+
interface BreadcrumbItem {
|
|
75
|
+
name: string;
|
|
76
|
+
url?: string;
|
|
77
|
+
}
|
|
48
78
|
|
|
49
79
|
/** Keys for each renderable section of the articles listing page. */
|
|
50
80
|
type ArticlesSection = 'hero' | 'search' | 'featured' | 'latest' | 'categories' | 'newsletter';
|
|
@@ -104,6 +134,41 @@ interface HeroConfig {
|
|
|
104
134
|
/** Subheading paragraph displayed beneath the title. Default: the built-in description. */
|
|
105
135
|
description?: string;
|
|
106
136
|
}
|
|
137
|
+
/** Controls how article body links set target/rel attributes. */
|
|
138
|
+
type LinkTargetStrategy = 'external-new-tab' | 'all-new-tab' | 'same-tab';
|
|
139
|
+
type ArticleBreadcrumbToken = 'home' | 'articles' | 'primaryCategory' | 'folderPath' | 'articleTitle';
|
|
140
|
+
type CategoryBreadcrumbToken = 'home' | 'articles' | 'category';
|
|
141
|
+
type AuthorBreadcrumbToken = 'home' | 'articles' | 'authors' | 'authorName';
|
|
142
|
+
interface CustomBreadcrumbItem {
|
|
143
|
+
/** Label displayed in the breadcrumb trail. */
|
|
144
|
+
name: string;
|
|
145
|
+
/** Custom URL. Relative paths are resolved against `siteUrl` by server builders. */
|
|
146
|
+
url: string;
|
|
147
|
+
}
|
|
148
|
+
type ArticleBreadcrumbEntry = ArticleBreadcrumbToken | CustomBreadcrumbItem;
|
|
149
|
+
type CategoryBreadcrumbEntry = CategoryBreadcrumbToken | CustomBreadcrumbItem;
|
|
150
|
+
type AuthorBreadcrumbEntry = AuthorBreadcrumbToken | CustomBreadcrumbItem;
|
|
151
|
+
interface BreadcrumbLabels {
|
|
152
|
+
home?: string;
|
|
153
|
+
articles?: string;
|
|
154
|
+
authors?: string;
|
|
155
|
+
}
|
|
156
|
+
interface BreadcrumbsConfig {
|
|
157
|
+
/** Set to false to hide visible breadcrumbs and breadcrumb JSON-LD generated by the helper builders. */
|
|
158
|
+
show?: boolean;
|
|
159
|
+
/** Separator used by the visible Breadcrumb component. Default: '>'. */
|
|
160
|
+
separator?: string;
|
|
161
|
+
/** Set to false to render visible breadcrumbs without JSON-LD. Default: true. */
|
|
162
|
+
showSchema?: boolean;
|
|
163
|
+
/** Article breadcrumb trail. Example: ['primaryCategory', { name: 'Guides', url: '/guides' }, 'articleTitle']. */
|
|
164
|
+
article?: ArticleBreadcrumbEntry[];
|
|
165
|
+
/** Category breadcrumb trail. Default: ['home', 'articles', 'category']. */
|
|
166
|
+
category?: CategoryBreadcrumbEntry[];
|
|
167
|
+
/** Author breadcrumb trail. Default: ['home', 'articles', 'authors', 'authorName']. */
|
|
168
|
+
author?: AuthorBreadcrumbEntry[];
|
|
169
|
+
/** Optional label overrides for built-in breadcrumb items. */
|
|
170
|
+
labels?: BreadcrumbLabels;
|
|
171
|
+
}
|
|
107
172
|
/** Top-level configuration object. Pass one instance to every library component. */
|
|
108
173
|
interface ArticlesConfig {
|
|
109
174
|
/** Canonical base URL of the site, used in metadata and JSON-LD. Example: `'https://yoursite.com'` */
|
|
@@ -139,12 +204,26 @@ interface ArticlesConfig {
|
|
|
139
204
|
showBackToArticles?: boolean;
|
|
140
205
|
/** Set to false to hide author names from UI and metadata. Default: true. */
|
|
141
206
|
showAuthor?: boolean;
|
|
207
|
+
/** Author profiles keyed by slug. Omit to keep plain string author display. */
|
|
208
|
+
authors?: Record<string, AuthorProfile>;
|
|
209
|
+
/** Author slug used when article frontmatter omits author fields. */
|
|
210
|
+
defaultAuthor?: string;
|
|
211
|
+
/** Set to false to disable copied author page routes in consuming apps. Default: true. */
|
|
212
|
+
showAuthorPage?: boolean;
|
|
213
|
+
/** Set to false to disable breadcrumbs, or pass a config object to customize breadcrumb trails. */
|
|
214
|
+
breadcrumbs?: false | BreadcrumbsConfig;
|
|
215
|
+
/** Article body link target behavior. Default: `'external-new-tab'`. */
|
|
216
|
+
linkTargetStrategy?: LinkTargetStrategy;
|
|
142
217
|
}
|
|
218
|
+
declare function getBreadcrumbsConfig(config: ArticlesConfig): BreadcrumbsConfig;
|
|
143
219
|
|
|
144
220
|
declare function sanitizeImagePath(rawPath: string, articleSlug: string): string | null;
|
|
145
221
|
declare function getAvailableArticleSlugs(): string[];
|
|
146
|
-
declare
|
|
147
|
-
declare
|
|
222
|
+
declare function getAuthorBySlug(slug: string, config: ArticlesConfig): AuthorProfile | null;
|
|
223
|
+
declare function getArticleAuthors(article: Article, config: ArticlesConfig): AuthorProfile[];
|
|
224
|
+
declare function getAllAuthors(config: ArticlesConfig): AuthorProfile[];
|
|
225
|
+
declare const getArticleMetadata: (slug: string, config?: ArticlesConfig) => Promise<Article | null>;
|
|
226
|
+
declare const getAllArticles: (config?: ArticlesConfig) => Promise<Article[]>;
|
|
148
227
|
declare function getAdjacentArticles(currentSlug: string): Promise<{
|
|
149
228
|
previous: Article | null;
|
|
150
229
|
next: Article | null;
|
|
@@ -157,20 +236,30 @@ declare function getAiRobotsTxtRules(): Promise<string>;
|
|
|
157
236
|
declare function searchArticles(query: string, config?: ArticlesConfig): Promise<Article[]>;
|
|
158
237
|
declare function categoryToSlug(category: string): string;
|
|
159
238
|
declare function getAllCategories(): Promise<CategoryInfo[]>;
|
|
160
|
-
declare function getArticlesByCategory(categorySlug: string): Promise<Article[]>;
|
|
239
|
+
declare function getArticlesByCategory(categorySlug: string, config?: ArticlesConfig): Promise<Article[]>;
|
|
240
|
+
declare function getArticlesByAuthor(authorSlug: string, config: ArticlesConfig): Promise<Article[]>;
|
|
161
241
|
|
|
242
|
+
declare function generateRssFeed(articles: Article[], config: ArticlesConfig): string;
|
|
162
243
|
declare function generateArticleStaticParams(): {
|
|
163
244
|
slug: string;
|
|
164
245
|
}[];
|
|
165
246
|
declare function generateCategoryStaticParams(): Promise<{
|
|
166
247
|
category: string;
|
|
167
248
|
}[]>;
|
|
249
|
+
declare function generateAuthorStaticParams(config: ArticlesConfig): {
|
|
250
|
+
author: string;
|
|
251
|
+
}[];
|
|
168
252
|
declare function generateArticleMetadata(slug: string, config: ArticlesConfig): Promise<Metadata>;
|
|
169
253
|
declare function generateArticlesIndexMetadata(config: ArticlesConfig): Metadata;
|
|
170
254
|
declare function generateCategoryMetadata(categorySlug: string, config: ArticlesConfig): Promise<Metadata>;
|
|
255
|
+
declare function generateAuthorMetadata(authorSlug: string, config: ArticlesConfig): Promise<Metadata>;
|
|
256
|
+
declare function buildArticleBreadcrumbs(article: Pick<Article, 'slug' | 'title' | 'category'>, config: ArticlesConfig): BreadcrumbItem[];
|
|
257
|
+
declare function buildCategoryBreadcrumbs(category: string, config: ArticlesConfig, categoryName?: string): BreadcrumbItem[];
|
|
258
|
+
declare function buildAuthorBreadcrumbs(author: AuthorProfile, config: ArticlesConfig): BreadcrumbItem[];
|
|
259
|
+
declare function resolveAuthorAvatar(author: AuthorProfile, config: ArticlesConfig): string;
|
|
171
260
|
declare function getArticleSitemapEntries(baseUrlOrConfig: string | ArticlesConfig): Promise<MetadataRoute.Sitemap>;
|
|
172
261
|
|
|
173
|
-
declare function markdownToHtml(markdown: string, articleSlug?: string): Promise<string>;
|
|
262
|
+
declare function markdownToHtml(markdown: string, articleSlug?: string, config?: ArticlesConfig): Promise<string>;
|
|
174
263
|
declare function extractToc(markdown: string): Promise<TocItem[]>;
|
|
175
264
|
|
|
176
265
|
type ArticlesErrorCode = 'article-directory-read-failed' | 'article-load-failed' | 'article-markdown-load-failed' | 'markdown-conversion-failed' | 'unsafe-image-path';
|
|
@@ -187,8 +276,9 @@ declare function setArticlesErrorHandler(handler?: ArticlesErrorHandler): void;
|
|
|
187
276
|
type ArticleContentProps = Readonly<{
|
|
188
277
|
article: Article;
|
|
189
278
|
className?: string;
|
|
279
|
+
config?: ArticlesConfig;
|
|
190
280
|
}>;
|
|
191
|
-
declare function ArticleContent({ article, className }: ArticleContentProps): Promise<react_jsx_runtime.JSX.Element>;
|
|
281
|
+
declare function ArticleContent({ article, className, config }: ArticleContentProps): Promise<react_jsx_runtime.JSX.Element>;
|
|
192
282
|
|
|
193
283
|
type ArticleTOCProps = Readonly<{
|
|
194
284
|
toc: TocItem[];
|
|
@@ -196,4 +286,4 @@ type ArticleTOCProps = Readonly<{
|
|
|
196
286
|
}>;
|
|
197
287
|
declare function ArticleTOC({ toc, className }: ArticleTOCProps): react_jsx_runtime.JSX.Element | null;
|
|
198
288
|
|
|
199
|
-
export { type Article, ArticleContent, ArticleTOC, type ArticlesConfig, type ArticlesErrorCode, type ArticlesErrorContext, type ArticlesErrorHandler, type ArticlesErrorReport, type CategoryInfo, type TocItem, categoryToSlug, extractToc, generateArticleMetadata, generateArticleStaticParams, generateArticlesIndexMetadata, generateCategoryMetadata, generateCategoryStaticParams, getAdjacentArticles, getAiRobotsTxtRules, getAllArticles, getAllCategories, getArticleAiHeaders, getArticleMarkdown, getArticleMarkdownResponse, getArticleMarkdownUrl, getArticleMetadata, getArticleSitemapEntries, getArticlesByCategory, getAvailableArticleSlugs, markdownToHtml, sanitizeImagePath, searchArticles, setArticlesErrorHandler };
|
|
289
|
+
export { type Article, ArticleContent, ArticleTOC, type ArticlesConfig, type ArticlesErrorCode, type ArticlesErrorContext, type ArticlesErrorHandler, type ArticlesErrorReport, type AuthorProfile, type AuthorSocial, type BreadcrumbItem, type CategoryInfo, type LinkTargetStrategy, type TocItem, buildArticleBreadcrumbs, buildAuthorBreadcrumbs, buildCategoryBreadcrumbs, categoryToSlug, extractToc, generateArticleMetadata, generateArticleStaticParams, generateArticlesIndexMetadata, generateAuthorMetadata, generateAuthorStaticParams, generateCategoryMetadata, generateCategoryStaticParams, generateRssFeed, getAdjacentArticles, getAiRobotsTxtRules, getAllArticles, getAllAuthors, getAllCategories, getArticleAiHeaders, getArticleAuthors, getArticleMarkdown, getArticleMarkdownResponse, getArticleMarkdownUrl, getArticleMetadata, getArticleSitemapEntries, getArticlesByAuthor, getArticlesByCategory, getAuthorBySlug, getAvailableArticleSlugs, getBreadcrumbsConfig, markdownToHtml, resolveAuthorAvatar, sanitizeImagePath, searchArticles, setArticlesErrorHandler };
|