@sonordev/site-kit 3.0.2 → 3.0.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.
@@ -1,8 +1,8 @@
1
1
  export { BlogList, BlogListServerProps, BlogListStyles, BlogPost, BlogPostServerProps, BlogPostStyles, ClusterLandingPage, ClusterLandingPageProps, ClusterNavigation, ClusterNavigationProps } from './server-ui.mjs';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
3
  import React__default from 'react';
4
- import { A as AuthorCardProps, c as AuthorPageProps, B as BlogPost, d as TableOfContentsProps } from '../types-5P5B9RgV.mjs';
5
- export { m as BlogAnalytics, a as BlogAuthor, b as BlogCategory, f as BlogListOptions, j as BlogListProps, k as BlogListRenderProps, g as BlogListResult, h as BlogPostProps, i as BlogPostRenderProps, e as BlogTag, R as RelatedPostsProps, l as TocItem, T as TopicCluster } from '../types-5P5B9RgV.mjs';
4
+ import { A as AuthorCardProps, c as AuthorPageProps, B as BlogPost, d as TableOfContentsProps } from '../types-DYOumpUT.mjs';
5
+ export { m as BlogAnalytics, a as BlogAuthor, b as BlogCategory, f as BlogListOptions, j as BlogListProps, k as BlogListRenderProps, g as BlogListResult, h as BlogPostProps, i as BlogPostRenderProps, e as BlogTag, R as RelatedPostsProps, l as TocItem, T as TopicCluster } from '../types-DYOumpUT.mjs';
6
6
 
7
7
  interface BlogSidebarProps {
8
8
  /** Portal API URL */
@@ -1,8 +1,8 @@
1
1
  export { BlogList, BlogListServerProps, BlogListStyles, BlogPost, BlogPostServerProps, BlogPostStyles, ClusterLandingPage, ClusterLandingPageProps, ClusterNavigation, ClusterNavigationProps } from './server-ui.js';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
3
  import React__default from 'react';
4
- import { A as AuthorCardProps, c as AuthorPageProps, B as BlogPost, d as TableOfContentsProps } from '../types-5P5B9RgV.js';
5
- export { m as BlogAnalytics, a as BlogAuthor, b as BlogCategory, f as BlogListOptions, j as BlogListProps, k as BlogListRenderProps, g as BlogListResult, h as BlogPostProps, i as BlogPostRenderProps, e as BlogTag, R as RelatedPostsProps, l as TocItem, T as TopicCluster } from '../types-5P5B9RgV.js';
4
+ import { A as AuthorCardProps, c as AuthorPageProps, B as BlogPost, d as TableOfContentsProps } from '../types-DYOumpUT.js';
5
+ export { m as BlogAnalytics, a as BlogAuthor, b as BlogCategory, f as BlogListOptions, j as BlogListProps, k as BlogListRenderProps, g as BlogListResult, h as BlogPostProps, i as BlogPostRenderProps, e as BlogTag, R as RelatedPostsProps, l as TocItem, T as TopicCluster } from '../types-DYOumpUT.js';
6
6
 
7
7
  interface BlogSidebarProps {
8
8
  /** Portal API URL */
@@ -2,7 +2,7 @@
2
2
  'use strict';
3
3
 
4
4
  var chunkUJQYSVYV_js = require('../chunk-UJQYSVYV.js');
5
- var chunkPBF2H23N_js = require('../chunk-PBF2H23N.js');
5
+ var chunkI5TJIESQ_js = require('../chunk-I5TJIESQ.js');
6
6
  var chunkIB4FRJDV_js = require('../chunk-IB4FRJDV.js');
7
7
  var chunkJ7QI3GDX_js = require('../chunk-J7QI3GDX.js');
8
8
  require('../chunk-ZSMWDLMK.js');
@@ -884,39 +884,39 @@ Object.defineProperty(exports, "BlogFAQ", {
884
884
  });
885
885
  Object.defineProperty(exports, "BlogList", {
886
886
  enumerable: true,
887
- get: function () { return chunkPBF2H23N_js.BlogList; }
887
+ get: function () { return chunkI5TJIESQ_js.BlogList; }
888
888
  });
889
889
  Object.defineProperty(exports, "BlogPost", {
890
890
  enumerable: true,
891
- get: function () { return chunkPBF2H23N_js.BlogPost; }
891
+ get: function () { return chunkI5TJIESQ_js.BlogPost; }
892
892
  });
893
893
  Object.defineProperty(exports, "ClusterLandingPage", {
894
894
  enumerable: true,
895
- get: function () { return chunkPBF2H23N_js.ClusterLandingPage; }
895
+ get: function () { return chunkI5TJIESQ_js.ClusterLandingPage; }
896
896
  });
897
897
  Object.defineProperty(exports, "ClusterNavigation", {
898
898
  enumerable: true,
899
- get: function () { return chunkPBF2H23N_js.ClusterNavigation; }
899
+ get: function () { return chunkI5TJIESQ_js.ClusterNavigation; }
900
900
  });
901
901
  Object.defineProperty(exports, "ServiceCallout", {
902
902
  enumerable: true,
903
- get: function () { return chunkPBF2H23N_js.ServiceCallout; }
903
+ get: function () { return chunkI5TJIESQ_js.ServiceCallout; }
904
904
  });
905
905
  Object.defineProperty(exports, "ServiceCallouts", {
906
906
  enumerable: true,
907
- get: function () { return chunkPBF2H23N_js.ServiceCallouts; }
907
+ get: function () { return chunkI5TJIESQ_js.ServiceCallouts; }
908
908
  });
909
909
  Object.defineProperty(exports, "addExternalLinkTargets", {
910
910
  enumerable: true,
911
- get: function () { return chunkPBF2H23N_js.addExternalLinkTargets; }
911
+ get: function () { return chunkI5TJIESQ_js.addExternalLinkTargets; }
912
912
  });
913
913
  Object.defineProperty(exports, "normalizeSiteHost", {
914
914
  enumerable: true,
915
- get: function () { return chunkPBF2H23N_js.normalizeSiteHost; }
915
+ get: function () { return chunkI5TJIESQ_js.normalizeSiteHost; }
916
916
  });
917
917
  Object.defineProperty(exports, "resolveBlogSiteUrl", {
918
918
  enumerable: true,
919
- get: function () { return chunkPBF2H23N_js.resolveBlogSiteUrl; }
919
+ get: function () { return chunkI5TJIESQ_js.resolveBlogSiteUrl; }
920
920
  });
921
921
  exports.AuthorCard = AuthorCard;
922
922
  exports.AuthorPage = AuthorPage;
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  export { BlogFAQ } from '../chunk-PST3NOEM.mjs';
3
- export { BlogList, BlogPost, ClusterLandingPage, ClusterNavigation, ServiceCallout, ServiceCallouts, addExternalLinkTargets, normalizeSiteHost, resolveBlogSiteUrl } from '../chunk-EKJOYPPV.mjs';
3
+ export { BlogList, BlogPost, ClusterLandingPage, ClusterNavigation, ServiceCallout, ServiceCallouts, addExternalLinkTargets, normalizeSiteHost, resolveBlogSiteUrl } from '../chunk-FT5JNCD4.mjs';
4
4
  import { generateAuthorSchema } from '../chunk-SH4VZDVX.mjs';
5
5
  import { safeJsonLd } from '../chunk-662YHKWW.mjs';
6
6
  import '../chunk-4XPGGLVP.mjs';
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React__default from 'react';
3
- import { B as BlogPost$1, l as TocItem, g as BlogListResult, b as BlogCategory, C as ClusterNavigation$1, T as TopicCluster } from '../types-5P5B9RgV.mjs';
3
+ import { B as BlogPost$1, l as TocItem, g as BlogListResult, b as BlogCategory, C as ClusterNavigation$1, T as TopicCluster } from '../types-DYOumpUT.mjs';
4
4
 
5
5
  interface BlogPostStyles {
6
6
  article?: string;
@@ -113,20 +113,34 @@ interface ClusterNavigationProps {
113
113
  navigation: ClusterNavigation$1;
114
114
  /** Base path for blog URLs (default: /blog) */
115
115
  basePath?: string;
116
- /** Category slug for URL building (optional) */
116
+ /**
117
+ * Fallback category slug for URL building (optional). Each linked article's
118
+ * OWN category takes precedence when present — applying one category to
119
+ * every sibling produced wrong-category URLs (duplicate content / redirect
120
+ * chains) on category-segmented sites whenever a cluster spans categories.
121
+ */
117
122
  category?: string;
123
+ /** Append a trailing slash to article URLs (only for trailingSlash sites) */
124
+ trailingSlash?: boolean;
118
125
  /** Disable default styles */
119
126
  unstyled?: boolean;
120
127
  /** Custom class name */
121
128
  className?: string;
122
129
  }
123
- declare function ClusterNavigation({ navigation, basePath, category, unstyled, className, }: ClusterNavigationProps): react_jsx_runtime.JSX.Element | null;
130
+ declare function ClusterNavigation({ navigation, basePath, category, trailingSlash, unstyled, className, }: ClusterNavigationProps): react_jsx_runtime.JSX.Element | null;
124
131
 
125
132
  interface ClusterLandingPageProps {
126
133
  /** Cluster slug to fetch */
127
134
  slug: string;
128
135
  /** Base path for blog URLs (default: /blog) */
129
136
  basePath?: string;
137
+ /**
138
+ * Include each article's own category segment in its URL:
139
+ * {basePath}/{category}/{slug}. Enable on sites whose blog routes are
140
+ * category-segmented (e.g. upforge.io /insights/{category}/{slug}) —
141
+ * without it, links point at {basePath}/{slug} and 404 on such sites.
142
+ */
143
+ categoryInPath?: boolean;
130
144
  /** Disable default styles */
131
145
  unstyled?: boolean;
132
146
  /** Custom class name */
@@ -136,6 +150,6 @@ interface ClusterLandingPageProps {
136
150
  cluster: TopicCluster;
137
151
  }) => React__default.ReactNode;
138
152
  }
139
- declare function ClusterLandingPage({ slug, basePath, unstyled, className, children, }: ClusterLandingPageProps): Promise<string | number | bigint | boolean | Iterable<React__default.ReactNode> | react_jsx_runtime.JSX.Element | null | undefined>;
153
+ declare function ClusterLandingPage({ slug, basePath, categoryInPath, unstyled, className, children, }: ClusterLandingPageProps): Promise<string | number | bigint | boolean | Iterable<React__default.ReactNode> | react_jsx_runtime.JSX.Element | null | undefined>;
140
154
 
141
155
  export { BlogList, type BlogListServerProps, type BlogListStyles, BlogPost, type BlogPostServerProps, type BlogPostStyles, ClusterLandingPage, type ClusterLandingPageProps, ClusterNavigation, type ClusterNavigationProps };
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React__default from 'react';
3
- import { B as BlogPost$1, l as TocItem, g as BlogListResult, b as BlogCategory, C as ClusterNavigation$1, T as TopicCluster } from '../types-5P5B9RgV.js';
3
+ import { B as BlogPost$1, l as TocItem, g as BlogListResult, b as BlogCategory, C as ClusterNavigation$1, T as TopicCluster } from '../types-DYOumpUT.js';
4
4
 
5
5
  interface BlogPostStyles {
6
6
  article?: string;
@@ -113,20 +113,34 @@ interface ClusterNavigationProps {
113
113
  navigation: ClusterNavigation$1;
114
114
  /** Base path for blog URLs (default: /blog) */
115
115
  basePath?: string;
116
- /** Category slug for URL building (optional) */
116
+ /**
117
+ * Fallback category slug for URL building (optional). Each linked article's
118
+ * OWN category takes precedence when present — applying one category to
119
+ * every sibling produced wrong-category URLs (duplicate content / redirect
120
+ * chains) on category-segmented sites whenever a cluster spans categories.
121
+ */
117
122
  category?: string;
123
+ /** Append a trailing slash to article URLs (only for trailingSlash sites) */
124
+ trailingSlash?: boolean;
118
125
  /** Disable default styles */
119
126
  unstyled?: boolean;
120
127
  /** Custom class name */
121
128
  className?: string;
122
129
  }
123
- declare function ClusterNavigation({ navigation, basePath, category, unstyled, className, }: ClusterNavigationProps): react_jsx_runtime.JSX.Element | null;
130
+ declare function ClusterNavigation({ navigation, basePath, category, trailingSlash, unstyled, className, }: ClusterNavigationProps): react_jsx_runtime.JSX.Element | null;
124
131
 
125
132
  interface ClusterLandingPageProps {
126
133
  /** Cluster slug to fetch */
127
134
  slug: string;
128
135
  /** Base path for blog URLs (default: /blog) */
129
136
  basePath?: string;
137
+ /**
138
+ * Include each article's own category segment in its URL:
139
+ * {basePath}/{category}/{slug}. Enable on sites whose blog routes are
140
+ * category-segmented (e.g. upforge.io /insights/{category}/{slug}) —
141
+ * without it, links point at {basePath}/{slug} and 404 on such sites.
142
+ */
143
+ categoryInPath?: boolean;
130
144
  /** Disable default styles */
131
145
  unstyled?: boolean;
132
146
  /** Custom class name */
@@ -136,6 +150,6 @@ interface ClusterLandingPageProps {
136
150
  cluster: TopicCluster;
137
151
  }) => React__default.ReactNode;
138
152
  }
139
- declare function ClusterLandingPage({ slug, basePath, unstyled, className, children, }: ClusterLandingPageProps): Promise<string | number | bigint | boolean | Iterable<React__default.ReactNode> | react_jsx_runtime.JSX.Element | null | undefined>;
153
+ declare function ClusterLandingPage({ slug, basePath, categoryInPath, unstyled, className, children, }: ClusterLandingPageProps): Promise<string | number | bigint | boolean | Iterable<React__default.ReactNode> | react_jsx_runtime.JSX.Element | null | undefined>;
140
154
 
141
155
  export { BlogList, type BlogListServerProps, type BlogListStyles, BlogPost, type BlogPostServerProps, type BlogPostStyles, ClusterLandingPage, type ClusterLandingPageProps, ClusterNavigation, type ClusterNavigationProps };
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkPBF2H23N_js = require('../chunk-PBF2H23N.js');
3
+ var chunkI5TJIESQ_js = require('../chunk-I5TJIESQ.js');
4
4
  require('../chunk-IB4FRJDV.js');
5
5
  require('../chunk-ZSMWDLMK.js');
6
6
 
@@ -8,19 +8,19 @@ require('../chunk-ZSMWDLMK.js');
8
8
 
9
9
  Object.defineProperty(exports, "BlogList", {
10
10
  enumerable: true,
11
- get: function () { return chunkPBF2H23N_js.BlogList; }
11
+ get: function () { return chunkI5TJIESQ_js.BlogList; }
12
12
  });
13
13
  Object.defineProperty(exports, "BlogPost", {
14
14
  enumerable: true,
15
- get: function () { return chunkPBF2H23N_js.BlogPost; }
15
+ get: function () { return chunkI5TJIESQ_js.BlogPost; }
16
16
  });
17
17
  Object.defineProperty(exports, "ClusterLandingPage", {
18
18
  enumerable: true,
19
- get: function () { return chunkPBF2H23N_js.ClusterLandingPage; }
19
+ get: function () { return chunkI5TJIESQ_js.ClusterLandingPage; }
20
20
  });
21
21
  Object.defineProperty(exports, "ClusterNavigation", {
22
22
  enumerable: true,
23
- get: function () { return chunkPBF2H23N_js.ClusterNavigation; }
23
+ get: function () { return chunkI5TJIESQ_js.ClusterNavigation; }
24
24
  });
25
25
  //# sourceMappingURL=server-ui.js.map
26
26
  //# sourceMappingURL=server-ui.js.map
@@ -1,4 +1,4 @@
1
- export { BlogList, BlogPost, ClusterLandingPage, ClusterNavigation } from '../chunk-EKJOYPPV.mjs';
1
+ export { BlogList, BlogPost, ClusterLandingPage, ClusterNavigation } from '../chunk-FT5JNCD4.mjs';
2
2
  import '../chunk-SH4VZDVX.mjs';
3
3
  import '../chunk-4XPGGLVP.mjs';
4
4
  //# sourceMappingURL=server-ui.mjs.map
@@ -1,5 +1,5 @@
1
1
  import { Metadata } from 'next';
2
- import { B as BlogPost, T as TopicCluster, C as ClusterNavigation, a as BlogAuthor } from '../types-5P5B9RgV.mjs';
2
+ import { B as BlogPost, T as TopicCluster, C as ClusterNavigation, a as BlogAuthor } from '../types-DYOumpUT.mjs';
3
3
 
4
4
  /**
5
5
  * @sonordev/site-kit/blog/server
@@ -1,5 +1,5 @@
1
1
  import { Metadata } from 'next';
2
- import { B as BlogPost, T as TopicCluster, C as ClusterNavigation, a as BlogAuthor } from '../types-5P5B9RgV.js';
2
+ import { B as BlogPost, T as TopicCluster, C as ClusterNavigation, a as BlogAuthor } from '../types-DYOumpUT.js';
3
3
 
4
4
  /**
5
5
  * @sonordev/site-kit/blog/server
@@ -289,6 +289,7 @@ function ClusterNavigation({
289
289
  navigation,
290
290
  basePath = "/blog",
291
291
  category,
292
+ trailingSlash = false,
292
293
  unstyled = false,
293
294
  className
294
295
  }) {
@@ -299,19 +300,23 @@ function ClusterNavigation({
299
300
  const hasPillarLink = !navigation.is_pillar && navigation.pillar;
300
301
  const hasSiblings = siblings.length > 0;
301
302
  if (!hasPillarLink && !hasSiblings) return null;
302
- const articleUrl = (slug) => category ? `${basePath}/${category}/${slug}/` : `${basePath}/${slug}/`;
303
+ const articleUrl = (article) => {
304
+ const cat = article.category || category;
305
+ const path = cat ? `${basePath}/${cat}/${article.slug}` : `${basePath}/${article.slug}`;
306
+ return trailingSlash ? `${path}/` : path;
307
+ };
303
308
  return /* @__PURE__ */ jsxs(Fragment, { children: [
304
309
  !unstyled && /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: clusterNavCss } }),
305
310
  /* @__PURE__ */ jsxs("nav", { className: `${unstyled ? "" : "sk-cluster-nav"} ${className || ""}`, children: [
306
311
  hasPillarLink && navigation.pillar && /* @__PURE__ */ jsxs("div", { className: unstyled ? "" : "sk-cluster-pillar-link", children: [
307
312
  /* @__PURE__ */ jsx("p", { className: unstyled ? "" : "sk-cluster-pillar-link-label", children: "Full Guide" }),
308
- /* @__PURE__ */ jsx("a", { href: articleUrl(navigation.pillar.slug), children: navigation.pillar.title })
313
+ /* @__PURE__ */ jsx("a", { href: articleUrl(navigation.pillar), children: navigation.pillar.title })
309
314
  ] }),
310
315
  hasSiblings && /* @__PURE__ */ jsxs("div", { children: [
311
316
  /* @__PURE__ */ jsx("p", { className: unstyled ? "" : "sk-cluster-siblings-title", children: navigation.is_pillar ? "Deep Dives" : "More in This Series" }),
312
317
  /* @__PURE__ */ jsx("ul", { className: unstyled ? "" : "sk-cluster-siblings-list", children: siblings.map((sibling) => /* @__PURE__ */ jsxs("li", { className: unstyled ? "" : "sk-cluster-siblings-item", children: [
313
318
  /* @__PURE__ */ jsx("span", { className: unstyled ? "" : "sk-cluster-type-badge", children: sibling.article_type }),
314
- /* @__PURE__ */ jsx("a", { href: articleUrl(sibling.slug), children: sibling.title })
319
+ /* @__PURE__ */ jsx("a", { href: articleUrl(sibling), children: sibling.title })
315
320
  ] }, sibling.slug)) })
316
321
  ] })
317
322
  ] })
@@ -1538,9 +1543,16 @@ var clusterLandingCss = `
1538
1543
  font-size: 0.75rem; color: #9ca3af;
1539
1544
  }
1540
1545
  `;
1546
+ function categorySlugOf(post) {
1547
+ const c = post?.category;
1548
+ if (!c) return null;
1549
+ if (typeof c === "string") return c;
1550
+ return c.slug || null;
1551
+ }
1541
1552
  async function ClusterLandingPage({
1542
1553
  slug,
1543
1554
  basePath = "/blog",
1555
+ categoryInPath = false,
1544
1556
  unstyled = false,
1545
1557
  className,
1546
1558
  children
@@ -1554,6 +1566,10 @@ async function ClusterLandingPage({
1554
1566
  }
1555
1567
  const pillar = cluster.pillar;
1556
1568
  const supports = cluster.supports || [];
1569
+ const articleUrl = (post) => {
1570
+ const cat = categoryInPath ? categorySlugOf(post) : null;
1571
+ return cat ? `${basePath}/${cat}/${post.slug}` : `${basePath}/${post.slug}`;
1572
+ };
1557
1573
  return /* @__PURE__ */ jsxs(Fragment, { children: [
1558
1574
  !unstyled && /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: clusterLandingCss } }),
1559
1575
  /* @__PURE__ */ jsxs("div", { className: `${unstyled ? "" : "sk-cluster-landing"} ${className || ""}`, children: [
@@ -1572,7 +1588,7 @@ async function ClusterLandingPage({
1572
1588
  cluster.geo_target && /* @__PURE__ */ jsx("span", { children: cluster.geo_target })
1573
1589
  ] })
1574
1590
  ] }),
1575
- pillar && /* @__PURE__ */ jsxs("a", { href: `${basePath}/${pillar.slug}`, className: unstyled ? "" : "sk-cluster-pillar-card", children: [
1591
+ pillar && /* @__PURE__ */ jsxs("a", { href: articleUrl(pillar), className: unstyled ? "" : "sk-cluster-pillar-card", children: [
1576
1592
  /* @__PURE__ */ jsx("span", { className: unstyled ? "" : "sk-cluster-pillar-label", children: "Pillar Guide" }),
1577
1593
  /* @__PURE__ */ jsx("h2", { className: unstyled ? "" : "sk-cluster-pillar-title", children: pillar.title }),
1578
1594
  pillar.excerpt && /* @__PURE__ */ jsx("p", { className: unstyled ? "" : "sk-cluster-pillar-excerpt", children: pillar.excerpt }),
@@ -1592,7 +1608,7 @@ async function ClusterLandingPage({
1592
1608
  /* @__PURE__ */ jsx("div", { className: unstyled ? "" : "sk-cluster-supports-grid", children: supports.map((post) => /* @__PURE__ */ jsxs(
1593
1609
  "a",
1594
1610
  {
1595
- href: `${basePath}/${post.slug}`,
1611
+ href: articleUrl(post),
1596
1612
  className: unstyled ? "" : "sk-cluster-support-card",
1597
1613
  children: [
1598
1614
  /* @__PURE__ */ jsxs("div", { className: unstyled ? "" : "sk-cluster-support-card-header", children: [
@@ -1618,5 +1634,5 @@ async function ClusterLandingPage({
1618
1634
  }
1619
1635
 
1620
1636
  export { BlogList, BlogPost, ClusterLandingPage, ClusterNavigation, ServiceCallout, ServiceCallouts, addExternalLinkTargets, normalizeSiteHost, resolveBlogSiteUrl };
1621
- //# sourceMappingURL=chunk-EKJOYPPV.mjs.map
1622
- //# sourceMappingURL=chunk-EKJOYPPV.mjs.map
1637
+ //# sourceMappingURL=chunk-FT5JNCD4.mjs.map
1638
+ //# sourceMappingURL=chunk-FT5JNCD4.mjs.map