@sonordev/site-kit 8.2.0 → 8.3.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/AGENTS.md +13 -1
- package/CHANGELOG.md +5 -0
- package/README.md +9 -5
- package/agent-manifest.json +47 -8
- package/dist/{AnalyticsProvider-6TAA3XYB.js → AnalyticsProvider-QXO33JUF.js} +6 -6
- package/dist/{ArticleFaqSection-3Q26DP7P.js → ArticleFaqSection-DEWE5B4Q.js} +1 -1
- package/dist/{ArticleViewTracker-H4N7YCLC.js → ArticleViewTracker-KN6ENIRS.js} +17 -6
- package/dist/{BlocksPopup-FJT5YQD3.js → BlocksPopup-3RPN6YVJ.js} +6 -6
- package/dist/{ChatWidget-THQHHTAA.js → ChatWidget-D2X445PO.js} +6 -6
- package/dist/{FileField-OZXXJGUM.js → FileField-UNGSNGJ5.js} +4 -4
- package/dist/{FormSpotlight-MLDJS246.js → FormSpotlight-JFH2ENKQ.js} +1 -1
- package/dist/{FormStage-6RVY7M3R.js → FormStage-RC3WHHXP.js} +1 -1
- package/dist/{ManagedForm-3VV54RVH.js → ManagedForm-FOQZ2IYG.js} +7 -7
- package/dist/{ManagedNewsletterForm-RTJDGMGG.js → ManagedNewsletterForm-NFNF33V3.js} +16 -7
- package/dist/{SignalCore-T7ZOCA44.js → SignalCore-5KABGX5C.js} +4 -4
- package/dist/SiteChat-JQ46ZIJ4.js +6 -0
- package/dist/SiteDesignReporter-N7L6DR4J.js +12 -0
- package/dist/{SitePopups-K6ADAWFK.js → SitePopups-WZBKX5Q3.js} +6 -6
- package/dist/SitemapSync-GY6UADRI.js +9 -0
- package/dist/_client/booking-widget.js +6 -6
- package/dist/_client/testimonial-section.js +3 -3
- package/dist/affiliates/index.js +4 -4
- package/dist/analytics/index.js +6 -6
- package/dist/{article-styles-GFXJJDLE.js → article-styles-7QONZJR5.js} +3 -3
- package/dist/article-tables-6XHVULPU.js +2 -0
- package/dist/articles/Article.d.ts +2 -89
- package/dist/articles/ArticleFAQ.d.ts +2 -41
- package/dist/articles/ArticleFaqSection.d.ts +2 -2
- package/dist/articles/ArticleList.d.ts +2 -79
- package/dist/articles/ArticleViewTracker.d.ts +2 -15
- package/dist/articles/AuthorCard.d.ts +2 -10
- package/dist/articles/AuthorPage.d.ts +2 -8
- package/dist/articles/ClusterLandingPage.d.ts +2 -40
- package/dist/articles/ClusterNavigation.d.ts +2 -37
- package/dist/articles/ManagedNewsletterForm.d.ts +3 -12
- package/dist/articles/NewsletterShell.d.ts +2 -17
- package/dist/articles/NewsletterWidget.d.ts +2 -30
- package/dist/articles/PublicationLayout.d.ts +2 -67
- package/dist/articles/PublicationSidebar.d.ts +2 -36
- package/dist/articles/RelatedPosts.d.ts +2 -22
- package/dist/articles/ServiceCallout.d.ts +2 -56
- package/dist/articles/TableOfContents.d.ts +2 -6
- package/dist/articles/article-photos.d.ts +2 -9
- package/dist/articles/article-styles.d.ts +2 -21
- package/dist/articles/article-tables.d.ts +2 -12
- package/dist/articles/artwork.d.ts +2 -13
- package/dist/articles/author-schema.d.ts +2 -72
- package/dist/articles/author-social.d.ts +2 -14
- package/dist/articles/excerpt.d.ts +2 -17
- package/dist/articles/index.d.ts +2 -79
- package/dist/articles/index.js +16 -11
- package/dist/articles/news-sitemap.d.ts +2 -46
- package/dist/articles/processArticleHtml.d.ts +2 -34
- package/dist/articles/public-reads.d.ts +2 -26
- package/dist/articles/reading-time.d.ts +2 -9
- package/dist/articles/routes.d.ts +2 -52
- package/dist/articles/server-core.d.ts +2 -461
- package/dist/articles/server-ui.d.ts +2 -30
- package/dist/articles/server-ui.js +26 -17
- package/dist/articles/server.d.ts +2 -461
- package/dist/articles/server.js +14 -5
- package/dist/articles/types.d.ts +2 -316
- package/dist/articles/widget-styles.d.ts +2 -8
- package/dist/chat/index.js +8 -8
- package/dist/{chunk-575L73NT.js → chunk-2JMCBJM5.js} +1 -1
- package/dist/chunk-34ZYJTQR.js +1 -0
- package/dist/{chunk-7FSB2EXS.js → chunk-3OY52UFM.js} +1 -1
- package/dist/{chunk-WMVK77ND.js → chunk-4K735O3J.js} +1 -1
- package/dist/{chunk-66G47P5C.js → chunk-4PVMUPC6.js} +2 -2
- package/dist/{chunk-L5UOHS6E.js → chunk-5D7ZISUP.js} +1 -1
- package/dist/{chunk-SMYX3AAO.js → chunk-5RYSTKVU.js} +1 -1
- package/dist/{chunk-6CJGZFOU.js → chunk-A4MPHIVP.js} +1 -1
- package/dist/chunk-B7T2SFUF.js +1 -0
- package/dist/{chunk-FV2VD7WM.js → chunk-BC7JMY4Z.js} +3 -3
- package/dist/{chunk-57K4GW3D.js → chunk-BOCYBDKV.js} +1 -1
- package/dist/{chunk-NFRJTOTB.js → chunk-BSQP6PRA.js} +1 -1
- package/dist/{chunk-GKGSXUVQ.js → chunk-BVB5FBAA.js} +1 -1
- package/dist/{chunk-Q72M5KBS.js → chunk-C2UROFGZ.js} +1 -1
- package/dist/{chunk-3EU6S5YC.js → chunk-C4AFNZT2.js} +1 -1
- package/dist/{chunk-WACWV5EP.js → chunk-D6ZIQMHB.js} +3 -3
- package/dist/{chunk-GYF2ULVO.js → chunk-DJAYFHVF.js} +1 -1
- package/dist/{chunk-JC2VS2SB.js → chunk-DPSNMOMZ.js} +1 -1
- package/dist/{chunk-NNEIBXGU.js → chunk-E3UR37RX.js} +2 -2
- package/dist/{chunk-Y3INC4QJ.js → chunk-E4PTMORJ.js} +1 -1
- package/dist/{chunk-EBILJHUF.js → chunk-EA6FZMYA.js} +2 -2
- package/dist/{chunk-X7VKRHFF.js → chunk-FHUTOXS7.js} +1 -1
- package/dist/{chunk-JBEUZJS3.js → chunk-GKJVSZ7H.js} +3 -3
- package/dist/chunk-H72ZFO3F.js +1 -0
- package/dist/{chunk-FVXFLVXF.js → chunk-HND6BDXC.js} +3 -3
- package/dist/chunk-IEGDPRQB.js +14 -0
- package/dist/{chunk-CAH4Y4PY.js → chunk-JO76F5WP.js} +1 -1
- package/dist/{chunk-FQUGGPBM.js → chunk-KJVUOJMW.js} +58 -58
- package/dist/{chunk-SC4MZGWZ.js → chunk-LBDWAXAO.js} +1 -1
- package/dist/{chunk-WSNG2K3T.js → chunk-LPKKSYKX.js} +3 -3
- package/dist/{chunk-HUBMKTPW.js → chunk-M5SF7NCC.js} +1 -1
- package/dist/{chunk-YBAFUM3Z.js → chunk-MQ4REMTH.js} +2 -2
- package/dist/{chunk-BQZPHICL.js → chunk-NA4Z4CQG.js} +1 -1
- package/dist/{chunk-727R7C5R.js → chunk-OIWFXUVD.js} +2 -2
- package/dist/{chunk-H4R2GPAB.js → chunk-QBCWVT2S.js} +2 -2
- package/dist/{chunk-WYZ4OUON.js → chunk-QCZHYO5M.js} +1 -1
- package/dist/{chunk-I6QFPSUU.js → chunk-QDILCQBL.js} +9 -9
- package/dist/{chunk-WK3N3Y7V.js → chunk-SCTVADDL.js} +2 -2
- package/dist/{chunk-QXMIKDOL.js → chunk-SNRE3ZVZ.js} +3 -3
- package/dist/{chunk-WBC5B3JD.js → chunk-TT4JZDKM.js} +3 -3
- package/dist/{chunk-5ZCY36TY.js → chunk-U7Y3QG3A.js} +1 -1
- package/dist/{chunk-3G7YABRA.js → chunk-W7OPEMGJ.js} +4 -1
- package/dist/{chunk-XWIRU6UT.js → chunk-WBUG7XRL.js} +2 -2
- package/dist/{chunk-ZM2FNWIQ.js → chunk-WSOZ3FQN.js} +1 -1
- package/dist/chunk-X4IJS7LV.js +319 -0
- package/dist/{chunk-JIH32RH2.js → chunk-XA7Q2VQA.js} +1 -1
- package/dist/{chunk-GWP2VBFH.js → chunk-XLAXYPTK.js} +3 -3
- package/dist/client/index.js +4 -16
- package/dist/fleet/index.js +6 -6
- package/dist/forms/index.js +9 -325
- package/dist/forms/server.js +2 -2
- package/dist/images/index.js +4 -4
- package/dist/index.js +1 -1
- package/dist/layout/client.js +9 -9
- package/dist/layout/index.js +10 -10
- package/dist/llms/index.js +8 -8
- package/dist/maps/index.js +4 -4
- package/dist/mcp/sonor.d.ts +42 -3
- package/dist/mcp/sonor.js +25 -20
- package/dist/mcp/transport.d.ts +1 -1
- package/dist/press-kit/articles/Article.d.ts +89 -0
- package/dist/press-kit/articles/ArticleFAQ.d.ts +41 -0
- package/dist/press-kit/articles/ArticleFaqSection.d.ts +2 -0
- package/dist/press-kit/articles/ArticleList.d.ts +79 -0
- package/dist/press-kit/articles/ArticleViewTracker.d.ts +15 -0
- package/dist/press-kit/articles/AuthorCard.d.ts +10 -0
- package/dist/press-kit/articles/AuthorPage.d.ts +8 -0
- package/dist/press-kit/articles/ClusterLandingPage.d.ts +40 -0
- package/dist/press-kit/articles/ClusterNavigation.d.ts +37 -0
- package/dist/press-kit/articles/ManagedNewsletterForm.d.ts +12 -0
- package/dist/press-kit/articles/NewsletterShell.d.ts +17 -0
- package/dist/press-kit/articles/NewsletterWidget.d.ts +30 -0
- package/dist/press-kit/articles/PublicationLayout.d.ts +67 -0
- package/dist/press-kit/articles/PublicationSidebar.d.ts +36 -0
- package/dist/press-kit/articles/RelatedPosts.d.ts +22 -0
- package/dist/press-kit/articles/ServiceCallout.d.ts +56 -0
- package/dist/press-kit/articles/TableOfContents.d.ts +6 -0
- package/dist/press-kit/articles/article-photos.d.ts +9 -0
- package/dist/press-kit/articles/article-styles.d.ts +21 -0
- package/dist/press-kit/articles/article-tables.d.ts +12 -0
- package/dist/press-kit/articles/artwork.d.ts +13 -0
- package/dist/press-kit/articles/author-schema.d.ts +72 -0
- package/dist/press-kit/articles/author-social.d.ts +14 -0
- package/dist/press-kit/articles/excerpt.d.ts +17 -0
- package/dist/press-kit/articles/index.d.ts +79 -0
- package/dist/press-kit/articles/news-sitemap.d.ts +46 -0
- package/dist/press-kit/articles/processArticleHtml.d.ts +34 -0
- package/dist/press-kit/articles/public-reads.d.ts +26 -0
- package/dist/press-kit/articles/reading-time.d.ts +9 -0
- package/dist/press-kit/articles/routes.d.ts +52 -0
- package/dist/press-kit/articles/server-core.d.ts +461 -0
- package/dist/press-kit/articles/server-ui.d.ts +31 -0
- package/dist/press-kit/articles/types.d.ts +316 -0
- package/dist/press-kit/articles/widget-styles.d.ts +8 -0
- package/dist/reputation/index.js +3 -3
- package/dist/reputation/server.js +2 -2
- package/dist/revalidate/index.js +2 -2
- package/dist/runtime/index.js +5 -4
- package/dist/seo/client.js +6 -6
- package/dist/seo/index.js +7 -7
- package/dist/seo/llms.js +8 -8
- package/dist/seo/register-sitemap-cli.js +1 -1
- package/dist/seo/sitemap.js +6 -6
- package/dist/server/index.js +3 -2
- package/dist/shared/build-entries.d.ts +2 -1
- package/dist/shared/clientApiConfig.d.ts +2 -0
- package/dist/shared/import-specifiers.d.ts +1 -1
- package/dist/shared/index.d.ts +6 -0
- package/dist/shared/index.js +8 -0
- package/dist/shared/version.d.ts +1 -1
- package/dist/signal/index.js +2 -2
- package/dist/sitemap/index.js +6 -6
- package/dist/sync/index.js +6 -6
- package/dist/website/images.js +4 -4
- package/dist/website/index.js +7 -7
- package/dist/website/popups.js +6 -6
- package/dist/{writeLLMsTxt-DGKLYXIW.js → writeLLMsTxt-VKHCM5IS.js} +5 -5
- package/docs/MIGRATING-TO-PRESS-KIT.md +83 -0
- package/docs.json +145 -29
- package/package.json +15 -5
- package/src/articles/README.md +5 -360
- package/src/mcp/README.md +16 -0
- package/src/og/README.md +1 -1
- package/src/runtime/README.md +4 -0
- package/dist/SiteChat-JSHPGAE3.js +0 -6
- package/dist/SiteDesignReporter-L2JBAKKK.js +0 -12
- package/dist/SitemapSync-VV2YSMIW.js +0 -9
- package/dist/article-tables-AXSZOGNW.js +0 -2
package/dist/mcp/sonor.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { fetchReviews, fetchReviewStats } from '../chunk-
|
|
1
|
+
import { fetchReviews, fetchReviewStats } from '../chunk-BSQP6PRA.js';
|
|
2
2
|
import { toolErrorResult } from '../chunk-FYAB6CXS.js';
|
|
3
|
-
import { fetchBookingTypes, fetchAvailability } from '../chunk-
|
|
4
|
-
import { getLLMsData, getServices, getFAQItems, getPageSummaries } from '../chunk-
|
|
5
|
-
import { getFormConfig } from '../chunk-
|
|
6
|
-
import '../chunk-
|
|
3
|
+
import { fetchBookingTypes, fetchAvailability } from '../chunk-WBUG7XRL.js';
|
|
4
|
+
import { getLLMsData, getServices, getFAQItems, getPageSummaries } from '../chunk-XA7Q2VQA.js';
|
|
5
|
+
import { getFormConfig } from '../chunk-NA4Z4CQG.js';
|
|
6
|
+
import '../chunk-5RYSTKVU.js';
|
|
7
7
|
import '../chunk-C2FZBUSS.js';
|
|
8
8
|
import '../chunk-YC7ELZS3.js';
|
|
9
9
|
import '../chunk-LNSF6BJC.js';
|
|
@@ -12,23 +12,17 @@ import '../chunk-TYAVHRWH.js';
|
|
|
12
12
|
import '../chunk-5SQK3D53.js';
|
|
13
13
|
import '../chunk-HW7B43E5.js';
|
|
14
14
|
import '../chunk-NJCTQH2P.js';
|
|
15
|
-
import { getAllArticles, getArticle } from '../chunk-FQUGGPBM.js';
|
|
16
|
-
import '../chunk-HUBMKTPW.js';
|
|
17
|
-
import '../chunk-Y3INC4QJ.js';
|
|
18
|
-
import '../chunk-QXMIKDOL.js';
|
|
19
|
-
import '../chunk-WMVK77ND.js';
|
|
20
15
|
import { resolveFetch } from '../chunk-UAYAJPEP.js';
|
|
21
16
|
import '../chunk-NZ4RXN3G.js';
|
|
22
|
-
import '../chunk-VWWITFWM.js';
|
|
23
17
|
import '../chunk-MJP63SSS.js';
|
|
24
18
|
import { resolveServerApiConfig } from '../chunk-C7TLGL3R.js';
|
|
25
19
|
import '../chunk-MH2DSGC6.js';
|
|
26
20
|
import { resolveSiteHost } from '../chunk-FESKKJAS.js';
|
|
27
21
|
import '../chunk-A4CC4ZG3.js';
|
|
28
|
-
import '../chunk-
|
|
29
|
-
import '../chunk-
|
|
30
|
-
import '../chunk-
|
|
31
|
-
import { SITE_KIT_VERSION } from '../chunk-
|
|
22
|
+
import '../chunk-OIWFXUVD.js';
|
|
23
|
+
import '../chunk-C4AFNZT2.js';
|
|
24
|
+
import '../chunk-W7OPEMGJ.js';
|
|
25
|
+
import { SITE_KIT_VERSION } from '../chunk-C2UROFGZ.js';
|
|
32
26
|
import '../chunk-PKBMQBKP.js';
|
|
33
27
|
import 'server-only';
|
|
34
28
|
import { after } from 'next/server.js';
|
|
@@ -74,6 +68,10 @@ function reportToolCallsToSonor(options = {}) {
|
|
|
74
68
|
}
|
|
75
69
|
|
|
76
70
|
// src/mcp/sonor.ts
|
|
71
|
+
var legacyArticleReaders = {
|
|
72
|
+
readMany: async (options) => (await import('../articles/server.js')).getAllArticles(options),
|
|
73
|
+
readOne: async (slug, options) => (await import('../articles/server.js')).getArticle(slug, options)
|
|
74
|
+
};
|
|
77
75
|
var SEARCH_LIMIT_MAX = 20;
|
|
78
76
|
var ARTICLE_CONTENT_MAX = 12e3;
|
|
79
77
|
var REPORTED_BY = "from the business\u2019s Sonor workspace";
|
|
@@ -199,7 +197,7 @@ function findPages(ctx) {
|
|
|
199
197
|
}
|
|
200
198
|
};
|
|
201
199
|
}
|
|
202
|
-
function listArticles(ctx, basePath) {
|
|
200
|
+
function listArticles(ctx, basePath, readers) {
|
|
203
201
|
return {
|
|
204
202
|
name: "list_articles",
|
|
205
203
|
title: "List articles",
|
|
@@ -207,7 +205,7 @@ function listArticles(ctx, basePath) {
|
|
|
207
205
|
inputSchema: { type: "object", properties: { query: QUERY, limit: LIMIT }, additionalProperties: false },
|
|
208
206
|
annotations: READ,
|
|
209
207
|
handler: async (args) => {
|
|
210
|
-
const posts = await
|
|
208
|
+
const posts = await readers.readMany({ maxPosts: 100, site: ctx.site });
|
|
211
209
|
const picked = rankByQuery(posts, text(args.query, 200), (p) => [p.title, [p.excerpt, nameOf(p.category)].filter(Boolean).join(" ")], limitOf(args.limit, 5));
|
|
212
210
|
return {
|
|
213
211
|
articles: picked.map((p) => ({
|
|
@@ -222,7 +220,7 @@ function listArticles(ctx, basePath) {
|
|
|
222
220
|
}
|
|
223
221
|
};
|
|
224
222
|
}
|
|
225
|
-
function getArticleTool(ctx, basePath) {
|
|
223
|
+
function getArticleTool(ctx, basePath, readers) {
|
|
226
224
|
return {
|
|
227
225
|
name: "get_article",
|
|
228
226
|
title: "Read an article",
|
|
@@ -236,7 +234,7 @@ function getArticleTool(ctx, basePath) {
|
|
|
236
234
|
annotations: READ,
|
|
237
235
|
handler: async (args) => {
|
|
238
236
|
const slug = text(args.slug, 200).replace(/^\/+|\/+$/g, "").split("/").pop() ?? "";
|
|
239
|
-
const post = slug ? await
|
|
237
|
+
const post = slug ? await readers.readOne(slug, { site: ctx.site }) : null;
|
|
240
238
|
if (!post) return { found: false, note: `No published article with the slug "${slug}". Call list_articles for the slugs that exist.` };
|
|
241
239
|
const content = post.content ?? "";
|
|
242
240
|
return {
|
|
@@ -445,6 +443,13 @@ function sendInquiry(ctx, form, purpose) {
|
|
|
445
443
|
}
|
|
446
444
|
};
|
|
447
445
|
}
|
|
446
|
+
function articleReaders(articles) {
|
|
447
|
+
if (!articles || articles.readMany === void 0 && articles.readOne === void 0) return legacyArticleReaders;
|
|
448
|
+
if (typeof articles.readMany !== "function" || typeof articles.readOne !== "function") {
|
|
449
|
+
throw new Error("sonorMcpServer: pass both articles.readMany and articles.readOne: getAllArticles and getArticle from '@sonordev/press-kit/articles/server'.");
|
|
450
|
+
}
|
|
451
|
+
return { readMany: articles.readMany, readOne: articles.readOne };
|
|
452
|
+
}
|
|
448
453
|
function offeringsReader(offerings) {
|
|
449
454
|
if (typeof offerings.read !== "function") {
|
|
450
455
|
throw new Error(
|
|
@@ -462,7 +467,7 @@ function sonorMcpTools(options) {
|
|
|
462
467
|
listServices(ctx),
|
|
463
468
|
searchFaq(ctx),
|
|
464
469
|
findPages(ctx),
|
|
465
|
-
...articlesPath !== null ? [listArticles(ctx, articlesPath), getArticleTool(ctx, articlesPath)] : [],
|
|
470
|
+
...articlesPath !== null ? [listArticles(ctx, articlesPath, articleReaders(options.articles || void 0)), getArticleTool(ctx, articlesPath, articleReaders(options.articles || void 0))] : [],
|
|
466
471
|
...options.reviews === false ? [] : [getReviews(ctx)],
|
|
467
472
|
...options.offerings ? [listOfferings(ctx, (options.offerings.path ?? "/shop").replace(/\/+$/, ""), offeringsReader(options.offerings))] : [],
|
|
468
473
|
...options.booking ? [checkAvailability(ctx, options.booking.path)] : [],
|
package/dist/mcp/transport.d.ts
CHANGED
|
@@ -126,7 +126,7 @@ export declare function protectMcpHandlers(handlers: McpRouteHandlerSet, options
|
|
|
126
126
|
* @example
|
|
127
127
|
* ```ts
|
|
128
128
|
* // app/api/mcp-internal/route.ts
|
|
129
|
-
* import * as mcp from '
|
|
129
|
+
* import * as mcp from './route'
|
|
130
130
|
* export const { POST, GET, DELETE, OPTIONS } = createMcpInternalRoute(mcp)
|
|
131
131
|
* ```
|
|
132
132
|
*/
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sonordev/press-kit/articles - Article Component
|
|
3
|
+
*
|
|
4
|
+
* Fetches and displays a single article with full content, table of contents,
|
|
5
|
+
* author info, related posts, and SEO metadata support.
|
|
6
|
+
*
|
|
7
|
+
* Ships with world-class default styling via scoped `.sk-article-*` classes.
|
|
8
|
+
* No configuration needed — just `<Article slug={slug} />`.
|
|
9
|
+
*
|
|
10
|
+
* Override with `styles` prop (per-element class names) or `unstyled` for
|
|
11
|
+
* complete control. The `children` render prop gives full data access.
|
|
12
|
+
*/
|
|
13
|
+
import React from 'react';
|
|
14
|
+
import type { Article as ArticleType, TocItem } from './types';
|
|
15
|
+
import { type PublicationRoutingOptions } from './routes';
|
|
16
|
+
export interface ArticleStyles {
|
|
17
|
+
article?: string;
|
|
18
|
+
header?: string;
|
|
19
|
+
breadcrumb?: string;
|
|
20
|
+
breadcrumbLink?: string;
|
|
21
|
+
title?: string;
|
|
22
|
+
subtitle?: string;
|
|
23
|
+
meta?: string;
|
|
24
|
+
metaItem?: string;
|
|
25
|
+
featuredImageWrapper?: string;
|
|
26
|
+
featuredImage?: string;
|
|
27
|
+
contentLayout?: string;
|
|
28
|
+
content?: string;
|
|
29
|
+
tocSidebar?: string;
|
|
30
|
+
tocTitle?: string;
|
|
31
|
+
tocList?: string;
|
|
32
|
+
tocItem?: string;
|
|
33
|
+
tocLink?: string;
|
|
34
|
+
tags?: string;
|
|
35
|
+
tag?: string;
|
|
36
|
+
faqSection?: string;
|
|
37
|
+
faqTitle?: string;
|
|
38
|
+
faqItem?: string;
|
|
39
|
+
faqQuestion?: string;
|
|
40
|
+
faqAnswer?: string;
|
|
41
|
+
authorCard?: string;
|
|
42
|
+
relatedSection?: string;
|
|
43
|
+
relatedTitle?: string;
|
|
44
|
+
relatedGrid?: string;
|
|
45
|
+
relatedCard?: string;
|
|
46
|
+
notFound?: string;
|
|
47
|
+
}
|
|
48
|
+
export interface ArticleServerProps {
|
|
49
|
+
apiUrl?: string;
|
|
50
|
+
apiKey?: string;
|
|
51
|
+
slug: string;
|
|
52
|
+
showToc?: boolean;
|
|
53
|
+
showRelated?: boolean;
|
|
54
|
+
relatedCount?: number;
|
|
55
|
+
showAuthor?: boolean;
|
|
56
|
+
basePath?: string;
|
|
57
|
+
routing?: PublicationRoutingOptions;
|
|
58
|
+
/** The publication's name in the breadcrumb (e.g. "The Forge"). Default "Articles". */
|
|
59
|
+
publicationName?: string;
|
|
60
|
+
className?: string;
|
|
61
|
+
styles?: ArticleStyles;
|
|
62
|
+
unstyled?: boolean;
|
|
63
|
+
siteUrl?: string;
|
|
64
|
+
/**
|
|
65
|
+
* Sub-site host for multi-site projects (e.g. `charlotte.example.com`). Scopes
|
|
66
|
+
* the post, related-posts and view-count calls to that host. Omit to resolve
|
|
67
|
+
* from NEXT_PUBLIC_SITE_URL. Separate from `siteUrl`, which only decides
|
|
68
|
+
* which links in the body open in a new tab.
|
|
69
|
+
*/
|
|
70
|
+
site?: string;
|
|
71
|
+
/**
|
|
72
|
+
* What to render when the post doesn't exist. Default true: call Next's
|
|
73
|
+
* `notFound()`, so the route answers 404 with `noindex` instead of a
|
|
74
|
+
* "Post Not Found" message on a 200 (a soft 404). False renders that
|
|
75
|
+
* message, for a page that wants its own missing-post state.
|
|
76
|
+
*
|
|
77
|
+
* For a guaranteed 404 status, also call `requireArticle(slug)` from
|
|
78
|
+
* `@sonordev/press-kit/articles/server` in `generateMetadata`: metadata resolves
|
|
79
|
+
* before anything streams. Thrown from inside a Suspense boundary that has
|
|
80
|
+
* already streamed, `notFound()` can only add `noindex` to a 200.
|
|
81
|
+
*/
|
|
82
|
+
notFound?: boolean;
|
|
83
|
+
children?: (props: {
|
|
84
|
+
post: ArticleType;
|
|
85
|
+
tableOfContents: TocItem[];
|
|
86
|
+
relatedPosts: ArticleType[];
|
|
87
|
+
}) => React.ReactNode;
|
|
88
|
+
}
|
|
89
|
+
export declare function Article({ apiUrl, apiKey, slug, showToc, showRelated, relatedCount, showAuthor, basePath, publicationName, routing, className, styles, unstyled, siteUrl, site, notFound, children, }: ArticleServerProps): Promise<React.JSX.Element | null>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sonordev/press-kit/articles - Article FAQ Component
|
|
3
|
+
*
|
|
4
|
+
* Renders FAQ items with collapsible accordion behavior.
|
|
5
|
+
* Content is always in the DOM (not display:none) for SEO crawlability.
|
|
6
|
+
* Uses CSS max-height transitions — no JS animation library required.
|
|
7
|
+
*
|
|
8
|
+
* Pairs with FAQPage schema (generated by Signal AI in the publication pipeline)
|
|
9
|
+
* for Google's "People Also Ask" featured snippets.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* <ArticleFAQ items={post.faqItems} />
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
import React from 'react';
|
|
17
|
+
export interface FaqItem {
|
|
18
|
+
question: string;
|
|
19
|
+
answer: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ArticleFAQProps {
|
|
22
|
+
items: FaqItem[];
|
|
23
|
+
/** Section title */
|
|
24
|
+
title?: string;
|
|
25
|
+
/** Allow multiple items open simultaneously */
|
|
26
|
+
allowMultiple?: boolean;
|
|
27
|
+
/** Override styles with Tailwind classes */
|
|
28
|
+
styles?: {
|
|
29
|
+
section?: string;
|
|
30
|
+
title?: string;
|
|
31
|
+
list?: string;
|
|
32
|
+
item?: string;
|
|
33
|
+
question?: string;
|
|
34
|
+
questionText?: string;
|
|
35
|
+
icon?: string;
|
|
36
|
+
answer?: string;
|
|
37
|
+
answerInner?: string;
|
|
38
|
+
};
|
|
39
|
+
unstyled?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export declare function ArticleFAQ({ items, title, allowMultiple, styles, unstyled, }: ArticleFAQProps): React.JSX.Element | null;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sonordev/press-kit/articles - Article List Component
|
|
3
|
+
*
|
|
4
|
+
* Fetches and displays a list of articles with pagination, filtering, and sorting.
|
|
5
|
+
*
|
|
6
|
+
* Ships with world-class default styling via scoped `.sk-article-list-*` classes.
|
|
7
|
+
* No configuration needed — just `<ArticleList basePath="/article" />`.
|
|
8
|
+
*
|
|
9
|
+
* Override with `styles` prop (per-element class names) or `unstyled` for
|
|
10
|
+
* complete control. The `children` render prop gives full data access.
|
|
11
|
+
*/
|
|
12
|
+
import React from 'react';
|
|
13
|
+
import type { ArticleListResult, Article, ArticleCategory } from './types';
|
|
14
|
+
import { type PublicationRoutingOptions } from './routes';
|
|
15
|
+
export interface ArticleListStyles {
|
|
16
|
+
container?: string;
|
|
17
|
+
categoryNav?: string;
|
|
18
|
+
categoryLink?: string;
|
|
19
|
+
categoryLinkActive?: string;
|
|
20
|
+
categoryLinkInactive?: string;
|
|
21
|
+
grid?: string;
|
|
22
|
+
card?: string;
|
|
23
|
+
cardImageWrapper?: string;
|
|
24
|
+
cardImage?: string;
|
|
25
|
+
cardBody?: string;
|
|
26
|
+
cardMeta?: string;
|
|
27
|
+
cardCategory?: string;
|
|
28
|
+
cardDate?: string;
|
|
29
|
+
cardTitle?: string;
|
|
30
|
+
cardTitleLink?: string;
|
|
31
|
+
cardExcerpt?: string;
|
|
32
|
+
cardFooter?: string;
|
|
33
|
+
cardAuthor?: string;
|
|
34
|
+
cardReadingTime?: string;
|
|
35
|
+
cardReadMore?: string;
|
|
36
|
+
pagination?: string;
|
|
37
|
+
paginationLink?: string;
|
|
38
|
+
paginationInfo?: string;
|
|
39
|
+
emptyState?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface ArticleListServerProps {
|
|
42
|
+
apiUrl?: string;
|
|
43
|
+
apiKey?: string;
|
|
44
|
+
category?: string;
|
|
45
|
+
tag?: string;
|
|
46
|
+
/** Author slug (preferred) or display name; slug filtering requires the current Sonor API */
|
|
47
|
+
author?: string;
|
|
48
|
+
featured?: boolean;
|
|
49
|
+
search?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Topic cluster slug — pairs with getTopicCluster. Note: an unknown slug
|
|
52
|
+
* yields an UNfiltered list (pre-existing API behavior).
|
|
53
|
+
*/
|
|
54
|
+
cluster?: string;
|
|
55
|
+
page?: number;
|
|
56
|
+
perPage?: number;
|
|
57
|
+
orderBy?: 'published_at' | 'title' | 'view_count';
|
|
58
|
+
order?: 'asc' | 'desc';
|
|
59
|
+
/**
|
|
60
|
+
* Sub-site host for multi-site projects (e.g. `charlotte.example.com`): the list
|
|
61
|
+
* shows that host's posts plus project-wide ones. Omit to resolve from
|
|
62
|
+
* NEXT_PUBLIC_SITE_URL.
|
|
63
|
+
*/
|
|
64
|
+
site?: string;
|
|
65
|
+
showCategoryFilter?: boolean;
|
|
66
|
+
showPagination?: boolean;
|
|
67
|
+
className?: string;
|
|
68
|
+
basePath?: string;
|
|
69
|
+
routing?: PublicationRoutingOptions;
|
|
70
|
+
styles?: ArticleListStyles;
|
|
71
|
+
unstyled?: boolean;
|
|
72
|
+
renderPost?: (post: Article) => React.ReactNode;
|
|
73
|
+
children?: (props: {
|
|
74
|
+
posts: Article[];
|
|
75
|
+
pagination: ArticleListResult['pagination'];
|
|
76
|
+
categories: ArticleCategory[];
|
|
77
|
+
}) => React.ReactNode;
|
|
78
|
+
}
|
|
79
|
+
export declare function ArticleList({ apiUrl, apiKey, category, tag, author, featured, search, cluster, page, perPage, orderBy, order, site, showCategoryFilter, showPagination, className, basePath, routing, styles, unstyled, renderPost, children, }: ArticleListServerProps): Promise<string | number | bigint | boolean | React.JSX.Element | Iterable<React.ReactNode> | null | undefined>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface ArticleViewTrackerProps {
|
|
2
|
+
slug: string;
|
|
3
|
+
/**
|
|
4
|
+
* Sub-site host the view counts toward. Omit to use the host SiteKitLayout
|
|
5
|
+
* published (`__SITE_KIT_SITE__`, the same one analytics tags page views
|
|
6
|
+
* with), then NEXT_PUBLIC_SITE_URL, then `window.location.host`.
|
|
7
|
+
*/
|
|
8
|
+
site?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The effect body, exported for tests (the package's vitest runs in node, so
|
|
12
|
+
* the component's mount path can't be exercised directly).
|
|
13
|
+
*/
|
|
14
|
+
export declare function trackArticleView(slug: string, site?: string): void;
|
|
15
|
+
export declare function ArticleViewTracker({ slug, site }: ArticleViewTrackerProps): null;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sonordev/press-kit/articles - Author Card Component
|
|
3
|
+
*/
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import type { AuthorCardProps, ArticleAuthor } from './types';
|
|
6
|
+
declare function TrustBlock({ author }: {
|
|
7
|
+
author: ArticleAuthor;
|
|
8
|
+
}): React.JSX.Element | null;
|
|
9
|
+
export declare function AuthorCard({ author, showBio, showSocial, showTrustBlock, className }: AuthorCardProps): React.JSX.Element;
|
|
10
|
+
export { TrustBlock };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sonordev/press-kit/articles - Author Page Component (Server Component)
|
|
3
|
+
*
|
|
4
|
+
* Full author profile page with hero, trust block, social links, and articles grid.
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import type { AuthorPageProps } from './types';
|
|
8
|
+
export declare function AuthorPage({ author, posts, basePath, routing, siteUrl, siteName, jsonLd }: AuthorPageProps): React.JSX.Element;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sonordev/press-kit/articles - Cluster Landing Page Component
|
|
3
|
+
*
|
|
4
|
+
* Pre-built page component for `/article/cluster/[slug]` routes.
|
|
5
|
+
* Renders a topic cluster overview with:
|
|
6
|
+
* - Cluster hero (name, topic, description)
|
|
7
|
+
* - Pillar article (featured, large card)
|
|
8
|
+
* - Support articles (grid, categorized by article_type or funnel_stage)
|
|
9
|
+
*
|
|
10
|
+
* Server component — fetches cluster data from Sonor API.
|
|
11
|
+
* Ships with `.sk-cluster-landing-*` scoped styles.
|
|
12
|
+
*/
|
|
13
|
+
import React from 'react';
|
|
14
|
+
import { type PublicationRoutingOptions } from './routes';
|
|
15
|
+
import type { TopicCluster } from './types';
|
|
16
|
+
export interface ClusterLandingPageProps {
|
|
17
|
+
/** Cluster slug to fetch */
|
|
18
|
+
slug: string;
|
|
19
|
+
/** Sub-site host for multi-site projects. Omit to resolve from NEXT_PUBLIC_SITE_URL. */
|
|
20
|
+
site?: string;
|
|
21
|
+
/** Base path for article URLs (default: /article) */
|
|
22
|
+
basePath?: string;
|
|
23
|
+
routing?: PublicationRoutingOptions;
|
|
24
|
+
/**
|
|
25
|
+
* Include each article's own category segment in its URL:
|
|
26
|
+
* {basePath}/{category}/{slug}. Enable on sites whose article routes are
|
|
27
|
+
* category-segmented (e.g. /insights/{category}/{slug}) —
|
|
28
|
+
* without it, links point at {basePath}/{slug} and 404 on such sites.
|
|
29
|
+
*/
|
|
30
|
+
categoryInPath?: boolean;
|
|
31
|
+
/** Disable default styles */
|
|
32
|
+
unstyled?: boolean;
|
|
33
|
+
/** Custom class name */
|
|
34
|
+
className?: string;
|
|
35
|
+
/** Render prop for full data access */
|
|
36
|
+
children?: (props: {
|
|
37
|
+
cluster: TopicCluster;
|
|
38
|
+
}) => React.ReactNode;
|
|
39
|
+
}
|
|
40
|
+
export declare function ClusterLandingPage({ slug, site, basePath, routing, categoryInPath, unstyled, className, children, }: ClusterLandingPageProps): Promise<string | number | bigint | boolean | React.JSX.Element | Iterable<React.ReactNode> | null | undefined>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sonordev/press-kit/articles - Cluster Navigation Component
|
|
3
|
+
*
|
|
4
|
+
* Renders cluster context on article pages:
|
|
5
|
+
* - "Full Guide" pillar backlink (on support articles only)
|
|
6
|
+
* - Sibling article list with article_type badges
|
|
7
|
+
*
|
|
8
|
+
* Adapts to light/dark themes automatically using the same --sk-* variables
|
|
9
|
+
* as the rest of site-kit, with currentColor-based fallbacks.
|
|
10
|
+
*/
|
|
11
|
+
import React from 'react';
|
|
12
|
+
import type { ClusterNavigation as ClusterNavigationType } from './types';
|
|
13
|
+
import { type PublicationRoutingOptions } from './routes';
|
|
14
|
+
export interface ClusterNavigationProps {
|
|
15
|
+
/** Cluster navigation data */
|
|
16
|
+
navigation: ClusterNavigationType;
|
|
17
|
+
/** Base path for article URLs (default: /article) */
|
|
18
|
+
basePath?: string;
|
|
19
|
+
routing?: PublicationRoutingOptions;
|
|
20
|
+
/**
|
|
21
|
+
* Fallback category slug for URL building (optional). Each linked article's
|
|
22
|
+
* OWN category takes precedence when present — applying one category to
|
|
23
|
+
* every sibling produced wrong-category URLs (duplicate content / redirect
|
|
24
|
+
* chains) on category-segmented sites whenever a cluster spans categories.
|
|
25
|
+
*/
|
|
26
|
+
category?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Append a trailing slash to article URLs. Defaults to the site's
|
|
29
|
+
* next.config `trailingSlash`, so it rarely needs setting.
|
|
30
|
+
*/
|
|
31
|
+
trailingSlash?: boolean;
|
|
32
|
+
/** Disable default styles */
|
|
33
|
+
unstyled?: boolean;
|
|
34
|
+
/** Custom class name */
|
|
35
|
+
className?: string;
|
|
36
|
+
}
|
|
37
|
+
export declare function ClusterNavigation({ navigation, basePath, routing, category, trailingSlash: trailingSlashProp, unstyled, className, }: ClusterNavigationProps): React.JSX.Element | null;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Managed-forms mode of NewsletterWidget — its own module, loaded via
|
|
3
|
+
* React.lazy, so the useForm graph (forms engine, sonorFetch, site token)
|
|
4
|
+
* stays out of the publication entry's eager bundle. Article consumers only pay for
|
|
5
|
+
* it when a formSlug newsletter actually mounts (enforced by the
|
|
6
|
+
* integration harness's bundle budget, which measures the eager
|
|
7
|
+
* static-import graph).
|
|
8
|
+
*/
|
|
9
|
+
import React from 'react';
|
|
10
|
+
import { type NewsletterShellProps } from './NewsletterShell';
|
|
11
|
+
import type { NewsletterWidgetProps } from './NewsletterWidget';
|
|
12
|
+
export default function ManagedNewsletterForm({ formSlug, title, description, buttonText, successMessage, }: Required<Pick<NewsletterWidgetProps, 'formSlug'>> & Pick<NewsletterShellProps, 'title' | 'description' | 'buttonText' | 'successMessage'>): React.JSX.Element | null;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Presentational shell shared by NewsletterWidget's two modes. No data
|
|
3
|
+
* imports — keep it that way, it renders in the eager article bundle.
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
export interface NewsletterShellProps {
|
|
7
|
+
title: string;
|
|
8
|
+
description: string;
|
|
9
|
+
buttonText: string;
|
|
10
|
+
email: string;
|
|
11
|
+
onEmailChange: (value: string) => void;
|
|
12
|
+
onFormSubmit: (e: React.FormEvent) => void;
|
|
13
|
+
status: 'idle' | 'submitting' | 'success' | 'error';
|
|
14
|
+
successMessage: string;
|
|
15
|
+
errorMessage?: string | null;
|
|
16
|
+
}
|
|
17
|
+
export declare function NewsletterShell({ title, description, buttonText, email, onEmailChange, onFormSubmit, status, successMessage, errorMessage, }: NewsletterShellProps): React.JSX.Element;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sonordev/site-kit article — newsletter signup widget
|
|
3
|
+
*
|
|
4
|
+
* Two working modes (the old version rendered a form whose submit handler
|
|
5
|
+
* discarded the email):
|
|
6
|
+
*
|
|
7
|
+
* - `onSubmit`: the site owns delivery — we await the callback.
|
|
8
|
+
* - `formSlug`: the widget drives the managed-forms rail (useForm), so
|
|
9
|
+
* submissions inherit Sonor's newsletter routing (email_subscribers),
|
|
10
|
+
* honeypot, reCAPTCHA, and attribution for free.
|
|
11
|
+
*
|
|
12
|
+
* `onSubmit` wins when both are set. With neither, the widget renders
|
|
13
|
+
* nothing and warns — a dead form that swallows emails must not resurrect.
|
|
14
|
+
*
|
|
15
|
+
* Lives in its own module (not PublicationSidebar.tsx) on purpose: it needs hooks,
|
|
16
|
+
* and PublicationSidebar is also bundled into the un-stamped server entry
|
|
17
|
+
* articles/server-ui, where hooks would enter the react-server graph.
|
|
18
|
+
*/
|
|
19
|
+
import React from 'react';
|
|
20
|
+
export interface NewsletterWidgetProps {
|
|
21
|
+
title?: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
buttonText?: string;
|
|
24
|
+
/** Site-owned delivery. Wins over formSlug when both are set. */
|
|
25
|
+
onSubmit?: (email: string) => Promise<void>;
|
|
26
|
+
/** Slug of a managed Sonor form (newsletter routing) to submit through. */
|
|
27
|
+
formSlug?: string;
|
|
28
|
+
successMessage?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare function NewsletterWidget({ title, description, buttonText, onSubmit, formSlug, successMessage, }: NewsletterWidgetProps): React.JSX.Element | null;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sonordev/press-kit/articles - Article Layout Component
|
|
3
|
+
*
|
|
4
|
+
* A complete article layout with sidebar, responsive design, and optional hero.
|
|
5
|
+
* Use this to wrap your article pages for consistent styling.
|
|
6
|
+
*/
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import { PublicationSidebarProps } from './PublicationSidebar';
|
|
9
|
+
import type { PublicationRoutingOptions } from './routes';
|
|
10
|
+
export interface PublicationLayoutProps {
|
|
11
|
+
/** Sonor API URL */
|
|
12
|
+
apiUrl?: string;
|
|
13
|
+
/** Project API key */
|
|
14
|
+
apiKey?: string;
|
|
15
|
+
/** Sub-site host for multi-site projects, passed to the sidebar. Omit to resolve from NEXT_PUBLIC_SITE_URL. */
|
|
16
|
+
site?: string;
|
|
17
|
+
/** Layout style: 'sidebar-right', 'sidebar-left', 'full-width' */
|
|
18
|
+
layout?: 'sidebar-right' | 'sidebar-left' | 'full-width';
|
|
19
|
+
/** Show sidebar */
|
|
20
|
+
showSidebar?: boolean;
|
|
21
|
+
/** Sidebar props */
|
|
22
|
+
sidebarProps?: Partial<PublicationSidebarProps>;
|
|
23
|
+
/** Hero section config */
|
|
24
|
+
hero?: {
|
|
25
|
+
title?: string;
|
|
26
|
+
subtitle?: string;
|
|
27
|
+
backgroundImage?: string;
|
|
28
|
+
backgroundColor?: string;
|
|
29
|
+
};
|
|
30
|
+
/** Max width for content */
|
|
31
|
+
maxWidth?: number;
|
|
32
|
+
/** Base URL for article links */
|
|
33
|
+
basePath?: string;
|
|
34
|
+
routing?: PublicationRoutingOptions;
|
|
35
|
+
/** Custom class name */
|
|
36
|
+
className?: string;
|
|
37
|
+
/** Current category (for sidebar highlighting) */
|
|
38
|
+
currentCategory?: string;
|
|
39
|
+
/** Main content */
|
|
40
|
+
children: React.ReactNode;
|
|
41
|
+
}
|
|
42
|
+
export declare function PublicationLayout({ apiUrl, apiKey, site, layout, showSidebar, sidebarProps, hero, maxWidth, basePath, routing, className, currentCategory, children, }: PublicationLayoutProps): Promise<React.JSX.Element>;
|
|
43
|
+
/**
|
|
44
|
+
* Convenience wrapper for a complete publication index page
|
|
45
|
+
*/
|
|
46
|
+
export interface PublicationPageProps extends Omit<PublicationLayoutProps, 'children'> {
|
|
47
|
+
/** List component to render */
|
|
48
|
+
listComponent: React.ReactNode;
|
|
49
|
+
}
|
|
50
|
+
export declare function PublicationPage({ listComponent, ...layoutProps }: PublicationPageProps): Promise<React.JSX.Element>;
|
|
51
|
+
/**
|
|
52
|
+
* Convenience wrapper for a single article page
|
|
53
|
+
*/
|
|
54
|
+
export interface ArticlePageProps extends Omit<PublicationLayoutProps, 'children'> {
|
|
55
|
+
/** Post component to render */
|
|
56
|
+
postComponent: React.ReactNode;
|
|
57
|
+
}
|
|
58
|
+
export declare function ArticlePage({ postComponent, ...layoutProps }: ArticlePageProps): Promise<React.JSX.Element>;
|
|
59
|
+
export interface CategoryPageProps extends PublicationLayoutProps {
|
|
60
|
+
/** Category slug being viewed */
|
|
61
|
+
category: string;
|
|
62
|
+
/** Category display name */
|
|
63
|
+
categoryName?: string;
|
|
64
|
+
/** List component */
|
|
65
|
+
listComponent: React.ReactNode;
|
|
66
|
+
}
|
|
67
|
+
export declare function CategoryPage({ category, categoryName, listComponent, hero, ...layoutProps }: CategoryPageProps): Promise<React.JSX.Element>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sonordev/press-kit/articles - Article Sidebar Component
|
|
3
|
+
*
|
|
4
|
+
* A reusable sidebar for article pages with categories, recent posts,
|
|
5
|
+
* tags, newsletter signup, and custom widgets.
|
|
6
|
+
*/
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import { type PublicationRoutingOptions } from './routes';
|
|
9
|
+
export interface PublicationSidebarProps {
|
|
10
|
+
/** Sonor API URL */
|
|
11
|
+
apiUrl?: string;
|
|
12
|
+
/** Project API key */
|
|
13
|
+
apiKey?: string;
|
|
14
|
+
/** Sub-site host for multi-site projects. Omit to resolve from NEXT_PUBLIC_SITE_URL. */
|
|
15
|
+
site?: string;
|
|
16
|
+
/** Show categories widget */
|
|
17
|
+
showCategories?: boolean;
|
|
18
|
+
/** Show recent posts widget */
|
|
19
|
+
showRecentPosts?: boolean;
|
|
20
|
+
/** Number of recent posts to show */
|
|
21
|
+
recentPostsCount?: number;
|
|
22
|
+
/** Show tags widget */
|
|
23
|
+
showTags?: boolean;
|
|
24
|
+
/** Show search widget */
|
|
25
|
+
showSearch?: boolean;
|
|
26
|
+
/** Base URL for article links */
|
|
27
|
+
basePath?: string;
|
|
28
|
+
routing?: PublicationRoutingOptions;
|
|
29
|
+
/** Custom class name */
|
|
30
|
+
className?: string;
|
|
31
|
+
/** Current category filter (for highlighting) */
|
|
32
|
+
currentCategory?: string;
|
|
33
|
+
/** Additional widgets to render */
|
|
34
|
+
children?: React.ReactNode;
|
|
35
|
+
}
|
|
36
|
+
export declare function PublicationSidebar({ apiUrl, apiKey, site, showCategories, showRecentPosts, recentPostsCount, showTags, showSearch, basePath, routing, className, currentCategory, children, }: PublicationSidebarProps): Promise<React.JSX.Element | null>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sonordev/press-kit/articles - Related articles component
|
|
3
|
+
*
|
|
4
|
+
* Fetches and displays related articles via Sonor API
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import type { Article } from './types';
|
|
8
|
+
import { type PublicationRoutingOptions } from './routes';
|
|
9
|
+
interface RelatedPostsServerProps {
|
|
10
|
+
apiUrl?: string;
|
|
11
|
+
apiKey?: string;
|
|
12
|
+
currentPostId: string;
|
|
13
|
+
limit?: number;
|
|
14
|
+
/** Sub-site host for multi-site projects. Omit to resolve from NEXT_PUBLIC_SITE_URL. */
|
|
15
|
+
site?: string;
|
|
16
|
+
className?: string;
|
|
17
|
+
basePath?: string;
|
|
18
|
+
routing?: PublicationRoutingOptions;
|
|
19
|
+
renderItem?: (post: Article) => React.ReactNode;
|
|
20
|
+
}
|
|
21
|
+
export declare function RelatedPosts({ apiUrl, apiKey, currentPostId, limit, site, className, basePath, routing, renderItem, }: RelatedPostsServerProps): Promise<React.JSX.Element | null>;
|
|
22
|
+
export {};
|