@fullstackdatasolutions/articles 0.3.0 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -6
- package/dist/index.cjs +287 -105
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -2
- package/dist/index.d.ts +24 -2
- package/dist/index.js +280 -100
- package/dist/index.js.map +1 -1
- package/dist/server.cjs +63 -3
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +3 -2
- package/dist/server.d.ts +3 -2
- package/dist/server.js +62 -3
- package/dist/server.js.map +1 -1
- package/package.json +3 -2
- package/src/ArticleDetailHero.tsx +31 -5
- package/src/ArticleNavigation.tsx +56 -0
- package/src/ArticleSocialShare.tsx +96 -0
- package/src/CategoryArticlesPage.tsx +21 -4
- package/src/__tests__/ArticleCategoryGrid.test.tsx +34 -1
- package/src/__tests__/ArticleDetailHero.test.tsx +42 -10
- package/src/__tests__/ArticleNavigation.test.tsx +127 -0
- package/src/__tests__/ArticleSocialShare.test.tsx +187 -0
- package/src/__tests__/ArticlesPage.test.tsx +147 -1
- package/src/__tests__/CommentItem.test.tsx +110 -0
- package/src/__tests__/seoUtils.test.ts +63 -0
- package/src/index.ts +3 -0
- package/src/seoUtils.ts +66 -2
- package/src/server.ts +1 -0
package/README.md
CHANGED
|
@@ -62,8 +62,11 @@ export const siteConfig: ArticlesConfig = {
|
|
|
62
62
|
|
|
63
63
|
```tsx
|
|
64
64
|
// app/articles/page.tsx
|
|
65
|
+
import type { Metadata } from 'next'
|
|
65
66
|
import { ArticlesPage } from '@fullstackdatasolutions/articles'
|
|
67
|
+
import { generateArticlesIndexMetadata } from '@fullstackdatasolutions/articles/server'
|
|
66
68
|
import { siteConfig } from '@/config/articles'
|
|
69
|
+
export const metadata: Metadata = generateArticlesIndexMetadata(siteConfig)
|
|
67
70
|
export default function Page() {
|
|
68
71
|
return <ArticlesPage config={siteConfig} />
|
|
69
72
|
}
|
|
@@ -173,7 +176,7 @@ hero: {
|
|
|
173
176
|
|
|
174
177
|
## ArticleDetailHero
|
|
175
178
|
|
|
176
|
-
`ArticleDetailHero` renders the article's featured image full-width behind the title, category tags, and metadata (date, read time, author).
|
|
179
|
+
`ArticleDetailHero` renders the article's featured image full-width behind the title, category tags, and metadata (date, read time, author). When you render `ArticleDetailHero` exactly as shown below the hero image and linked categories appear automatically—no additional styling or extra `<Link>` wiring is required in the consuming app. Just pass the article payload and `categoryBasePath` (defaults to `/articles/category`) so the tags render as links.
|
|
177
180
|
|
|
178
181
|
```tsx
|
|
179
182
|
import { ArticleDetailHero } from '@fullstackdatasolutions/articles'
|
|
@@ -187,10 +190,61 @@ import { ArticleDetailHero } from '@fullstackdatasolutions/articles'
|
|
|
187
190
|
| Prop | Type | Required | Description |
|
|
188
191
|
|---|---|---|---|
|
|
189
192
|
| `article` | `Article` | yes | Article object returned by `getArticleMetadata` |
|
|
190
|
-
| `categoryBasePath` | `string` | no | Base path for category links
|
|
193
|
+
| `categoryBasePath` | `string` | no | Base path for category links. Defaults to `"/articles/category"`. Pass `""` to render categories as plain text. |
|
|
194
|
+
| `showDate` | `boolean` | no | Show the article date. Defaults to `false` (hidden). |
|
|
191
195
|
|
|
192
196
|
- Category tags are capped at 4. When an article has more than 4 categories, only the first 4 are shown.
|
|
197
|
+
- The date field is hidden by default. Pass `showDate={true}` to display it.
|
|
193
198
|
- All layout styles are inline so the component renders correctly regardless of whether `@source` is configured for the package.
|
|
199
|
+
- Hero image / categories behave automatically once you use this component; apps do not need to reimplement the hero section for those features.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## ArticleSocialShare
|
|
204
|
+
|
|
205
|
+
`ArticleSocialShare` renders a row of sharing buttons (LinkedIn, Facebook, Twitter, Reddit, WhatsApp, Telegram, Email, Copy Link). Use it below the article body in your `app/articles/[slug]/page.tsx`.
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
import { ArticleSocialShare } from '@fullstackdatasolutions/articles'
|
|
209
|
+
|
|
210
|
+
<ArticleSocialShare
|
|
211
|
+
title={article.title}
|
|
212
|
+
url={articleUrl}
|
|
213
|
+
excerpt={article.excerpt}
|
|
214
|
+
shareMessage="Optional footer note shown below the buttons."
|
|
215
|
+
/>
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
| Prop | Type | Required | Description |
|
|
219
|
+
|---|---|---|---|
|
|
220
|
+
| `title` | `string` | yes | Article title - used in share text |
|
|
221
|
+
| `url` | `string` | yes | Canonical URL to share |
|
|
222
|
+
| `excerpt` | `string` | no | Used as email body pre-fill |
|
|
223
|
+
| `shareMessage` | `string` | no | Optional paragraph rendered below the share buttons |
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## ArticleNavigation
|
|
228
|
+
|
|
229
|
+
`ArticleNavigation` renders previous/next article links at the bottom of an article. Returns `null` when both `previous` and `next` are absent (no output, no wrapper element). Use `getAdjacentArticles` from the server entry to fetch the data.
|
|
230
|
+
|
|
231
|
+
```tsx
|
|
232
|
+
import { ArticleNavigation } from '@fullstackdatasolutions/articles'
|
|
233
|
+
import { getAdjacentArticles } from '@fullstackdatasolutions/articles/server'
|
|
234
|
+
|
|
235
|
+
const { previous, next } = await getAdjacentArticles(slug)
|
|
236
|
+
|
|
237
|
+
<ArticleNavigation previous={previous} next={next} basePath="/articles" />
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
| Prop | Type | Required | Description |
|
|
241
|
+
|---|---|---|---|
|
|
242
|
+
| `previous` | `{ slug: string; title: string } \| null` | yes | Previous article, or `null` |
|
|
243
|
+
| `next` | `{ slug: string; title: string } \| null` | yes | Next article, or `null` |
|
|
244
|
+
| `basePath` | `string` | yes | Route prefix (e.g. `"/articles"`) prepended to each slug |
|
|
245
|
+
|
|
246
|
+
- Titles longer than 60 characters are truncated with an ellipsis.
|
|
247
|
+
- No output is rendered when both `previous` and `next` are `null`.
|
|
194
248
|
|
|
195
249
|
---
|
|
196
250
|
|
|
@@ -226,6 +280,21 @@ app/api/articles/[slug]/comments/[commentId]/route.ts ← DELETE (soft)
|
|
|
226
280
|
|
|
227
281
|
## SEO utilities
|
|
228
282
|
|
|
283
|
+
### Articles index metadata
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
// app/articles/page.tsx
|
|
287
|
+
import type { Metadata } from 'next'
|
|
288
|
+
import { generateArticlesIndexMetadata } from '@fullstackdatasolutions/articles/server'
|
|
289
|
+
import { siteConfig } from '@/config/articles'
|
|
290
|
+
export const metadata: Metadata = generateArticlesIndexMetadata(siteConfig)
|
|
291
|
+
// Produces: title, description, full OpenGraph (type: 'website'), Twitter Card,
|
|
292
|
+
// canonical URL (/articles), and robots directives.
|
|
293
|
+
// Description falls back to config.hero?.description when set.
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Article and category metadata
|
|
297
|
+
|
|
229
298
|
```ts
|
|
230
299
|
// app/articles/[slug]/page.tsx
|
|
231
300
|
import { generateArticleMetadata } from '@fullstackdatasolutions/articles/server'
|
|
@@ -237,15 +306,31 @@ export const generateMetadata = ({ params }) =>
|
|
|
237
306
|
import { generateCategoryMetadata } from '@fullstackdatasolutions/articles/server'
|
|
238
307
|
export const generateMetadata = ({ params }) =>
|
|
239
308
|
generateCategoryMetadata(params.category, siteConfig)
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Sitemaps
|
|
240
312
|
|
|
313
|
+
Use `getArticleSitemapEntries` to generate article and category sitemap entries. Pass your `ArticlesConfig` object (preferred) or a plain URL string.
|
|
314
|
+
|
|
315
|
+
```ts
|
|
241
316
|
// app/sitemap.ts
|
|
242
317
|
import { getArticleSitemapEntries } from '@fullstackdatasolutions/articles/server'
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
318
|
+
import { siteConfig } from '@/config/articles'
|
|
319
|
+
import type { MetadataRoute } from 'next'
|
|
320
|
+
|
|
321
|
+
const staticPages: MetadataRoute.Sitemap = [
|
|
322
|
+
{ url: 'https://yoursite.com', changeFrequency: 'weekly', priority: 1.0 },
|
|
323
|
+
{ url: 'https://yoursite.com/about', changeFrequency: 'monthly', priority: 0.8 },
|
|
324
|
+
]
|
|
325
|
+
|
|
326
|
+
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
|
327
|
+
const articleEntries = await getArticleSitemapEntries(siteConfig)
|
|
328
|
+
return [...staticPages, ...articleEntries]
|
|
246
329
|
}
|
|
247
330
|
```
|
|
248
331
|
|
|
332
|
+
Returns article entries (priority 0.8, changeFrequency 'weekly') and category entries (priority 0.7, changeFrequency 'weekly'). Alternative: pass a plain URL string instead of `siteConfig`: `getArticleSitemapEntries('https://yoursite.com')`.
|
|
333
|
+
|
|
249
334
|
JSON-LD structured data (`ArticleSchema`, `BreadcrumbSchema`, `CollectionPageSchema`) is rendered automatically inside the library components — no extra wiring required.
|
|
250
335
|
|
|
251
336
|
---
|
|
@@ -278,6 +363,7 @@ import {
|
|
|
278
363
|
searchArticles,
|
|
279
364
|
categoryToSlug,
|
|
280
365
|
getArticleSitemapEntries,
|
|
366
|
+
generateArticlesIndexMetadata,
|
|
281
367
|
generateArticleMetadata,
|
|
282
368
|
generateCategoryMetadata,
|
|
283
369
|
} from '@fullstackdatasolutions/articles/server'
|
|
@@ -330,7 +416,10 @@ This app uses `@fullstackdatasolutions/articles` for the articles section.
|
|
|
330
416
|
The package ships its source TypeScript files so Tailwind can scan them.
|
|
331
417
|
`app/globals.css` contains:
|
|
332
418
|
@source "./node_modules/@fullstackdatasolutions/articles/src";
|
|
333
|
-
If this line is missing, most component classes will not render correctly. Note: `ArticleCategoryGrid` image
|
|
419
|
+
If this line is missing, most component classes will not render correctly. Note: `ArticleCategoryGrid` images, `CategoryArticlesPage` hero, and `ArticleDetailHero` image use inline styles for critical layout so they render correctly without this line. All other styling still requires it.
|
|
420
|
+
|
|
421
|
+
### Server utilities
|
|
422
|
+
For sitemaps and metadata: `import { getArticleSitemapEntries, generateArticlesIndexMetadata, generateArticleMetadata, generateCategoryMetadata } from '@fullstackdatasolutions/articles/server'`. See README for usage examples.
|
|
334
423
|
|
|
335
424
|
### Rules
|
|
336
425
|
- Change `config/articles.ts` first; only edit library source if config cannot express the need.
|