@sonordev/site-kit 3.7.0 → 3.8.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/agent-manifest.json +1 -1
- package/dist/AnalyticsProvider-4KMGMQVD.js +31 -0
- package/dist/{AnalyticsProvider-JWXDXOIR.js.map → AnalyticsProvider-4KMGMQVD.js.map} +1 -1
- package/dist/AnalyticsProvider-M4BFCRKM.mjs +10 -0
- package/dist/{AnalyticsProvider-OIRXQE7O.mjs.map → AnalyticsProvider-M4BFCRKM.mjs.map} +1 -1
- package/dist/ChatWidget-I6YFEKW6.js +19 -0
- package/dist/{ChatWidget-K2BFJXGB.js.map → ChatWidget-I6YFEKW6.js.map} +1 -1
- package/dist/ChatWidget-IV3LIMLK.mjs +10 -0
- package/dist/{ChatWidget-FFCUDCT6.mjs.map → ChatWidget-IV3LIMLK.mjs.map} +1 -1
- package/dist/EngageWidget-AWVB35ZM.mjs +9 -0
- package/dist/{EngageWidget-QKRXI3NB.mjs.map → EngageWidget-AWVB35ZM.mjs.map} +1 -1
- package/dist/EngageWidget-TQW76BUU.js +18 -0
- package/dist/{EngageWidget-XRXXVVUK.js.map → EngageWidget-TQW76BUU.js.map} +1 -1
- package/dist/{SignalCore-6MUAX656.mjs → SignalCore-4FUGFP5E.mjs} +5 -5
- package/dist/{SignalCore-6MUAX656.mjs.map → SignalCore-4FUGFP5E.mjs.map} +1 -1
- package/dist/{SignalCore-BXCBV6GR.js → SignalCore-VX7ZL5HE.js} +11 -11
- package/dist/{SignalCore-BXCBV6GR.js.map → SignalCore-VX7ZL5HE.js.map} +1 -1
- package/dist/SitemapSync-CXDEUYM2.mjs +8 -0
- package/dist/{SitemapSync-KS7KTJBK.mjs.map → SitemapSync-CXDEUYM2.mjs.map} +1 -1
- package/dist/SitemapSync-XRH577AB.js +17 -0
- package/dist/{SitemapSync-WEZHTSFL.js.map → SitemapSync-XRH577AB.js.map} +1 -1
- package/dist/analytics/index.js +12 -12
- package/dist/analytics/index.mjs +5 -5
- package/dist/blog/server-ui.js +6 -6
- package/dist/blog/server-ui.js.map +1 -1
- package/dist/blog/server-ui.mjs +5 -5
- package/dist/blog/server-ui.mjs.map +1 -1
- package/dist/blog/server.d.mts +20 -1
- package/dist/blog/server.d.ts +20 -1
- package/dist/blog/server.js +43 -39
- package/dist/blog/server.mjs +1 -1
- package/dist/{chunk-AJPPCSVW.mjs → chunk-2LQGFCEA.mjs} +3 -3
- package/dist/{chunk-AJPPCSVW.mjs.map → chunk-2LQGFCEA.mjs.map} +1 -1
- package/dist/{chunk-VZU2EHB6.js → chunk-2WMLHR72.js} +4 -4
- package/dist/{chunk-VZU2EHB6.js.map → chunk-2WMLHR72.js.map} +1 -1
- package/dist/{chunk-TA6KXHCY.js → chunk-5GJ6V7FI.js} +7 -7
- package/dist/{chunk-TA6KXHCY.js.map → chunk-5GJ6V7FI.js.map} +1 -1
- package/dist/{chunk-3MYZS6PD.js → chunk-77CIIDE6.js} +15 -3
- package/dist/chunk-77CIIDE6.js.map +1 -0
- package/dist/{chunk-JFAAPREU.mjs → chunk-7UKIAZ6E.mjs} +4 -4
- package/dist/{chunk-JFAAPREU.mjs.map → chunk-7UKIAZ6E.mjs.map} +1 -1
- package/dist/{chunk-R3CXRMP7.js → chunk-A2FHTQGB.js} +3 -3
- package/dist/{chunk-R3CXRMP7.js.map → chunk-A2FHTQGB.js.map} +1 -1
- package/dist/{chunk-AKBGYQLC.js → chunk-ATOUXWFR.js} +15 -15
- package/dist/{chunk-AKBGYQLC.js.map → chunk-ATOUXWFR.js.map} +1 -1
- package/dist/{chunk-GZHLVOW3.js → chunk-BB2C5JUA.js} +4 -4
- package/dist/{chunk-GZHLVOW3.js.map → chunk-BB2C5JUA.js.map} +1 -1
- package/dist/{chunk-FP523A7G.mjs → chunk-BVOUZL2S.mjs} +3 -3
- package/dist/{chunk-FP523A7G.mjs.map → chunk-BVOUZL2S.mjs.map} +1 -1
- package/dist/{chunk-2PQUCJJF.js → chunk-D4V37TBD.js} +5 -5
- package/dist/{chunk-2PQUCJJF.js.map → chunk-D4V37TBD.js.map} +1 -1
- package/dist/{chunk-XREO3QRA.mjs → chunk-DGFHYNQY.mjs} +3 -3
- package/dist/{chunk-XREO3QRA.mjs.map → chunk-DGFHYNQY.mjs.map} +1 -1
- package/dist/{chunk-UWL37MUR.mjs → chunk-GH5RO5OW.mjs} +3 -3
- package/dist/{chunk-UWL37MUR.mjs.map → chunk-GH5RO5OW.mjs.map} +1 -1
- package/dist/{chunk-TQS2X5A3.js → chunk-GSOLN2FC.js} +5 -5
- package/dist/{chunk-TQS2X5A3.js.map → chunk-GSOLN2FC.js.map} +1 -1
- package/dist/{chunk-ATG4FJY6.js → chunk-H6AU3WKF.js} +35 -3
- package/dist/chunk-H6AU3WKF.js.map +1 -0
- package/dist/{chunk-CDKWTLWF.mjs → chunk-HQB24QUN.mjs} +4 -4
- package/dist/{chunk-CDKWTLWF.mjs.map → chunk-HQB24QUN.mjs.map} +1 -1
- package/dist/{chunk-LSWTMMKJ.mjs → chunk-HQJS7VWB.mjs} +3 -3
- package/dist/{chunk-LSWTMMKJ.mjs.map → chunk-HQJS7VWB.mjs.map} +1 -1
- package/dist/{chunk-C3QMG4HS.js → chunk-I5KJ5YFU.js} +15 -15
- package/dist/{chunk-C3QMG4HS.js.map → chunk-I5KJ5YFU.js.map} +1 -1
- package/dist/chunk-JVT6CUNN.mjs +6 -0
- package/dist/{chunk-2HH4VVJT.mjs.map → chunk-JVT6CUNN.mjs.map} +1 -1
- package/dist/{chunk-TZTO5CDS.mjs → chunk-JXN6OCFB.mjs} +3 -3
- package/dist/{chunk-TZTO5CDS.mjs.map → chunk-JXN6OCFB.mjs.map} +1 -1
- package/dist/chunk-JXT2WWXW.js +8 -0
- package/dist/{chunk-SCMHZBTN.js.map → chunk-JXT2WWXW.js.map} +1 -1
- package/dist/{chunk-ON6WW7IE.js → chunk-MP6NHVHD.js} +6 -6
- package/dist/{chunk-ON6WW7IE.js.map → chunk-MP6NHVHD.js.map} +1 -1
- package/dist/{chunk-7UZV6JXD.js → chunk-MRVO3QO3.js} +14 -14
- package/dist/{chunk-7UZV6JXD.js.map → chunk-MRVO3QO3.js.map} +1 -1
- package/dist/{chunk-XOBW75J2.js → chunk-NEV2OEBF.js} +9 -9
- package/dist/{chunk-XOBW75J2.js.map → chunk-NEV2OEBF.js.map} +1 -1
- package/dist/{chunk-YE7KZQZ3.mjs → chunk-OLQBP2JQ.mjs} +4 -4
- package/dist/{chunk-YE7KZQZ3.mjs.map → chunk-OLQBP2JQ.mjs.map} +1 -1
- package/dist/{chunk-6BIPAKL4.mjs → chunk-OVIDFJIK.mjs} +15 -4
- package/dist/chunk-OVIDFJIK.mjs.map +1 -0
- package/dist/{chunk-GUXB3QH7.mjs → chunk-PA7ENTUZ.mjs} +41 -9
- package/dist/chunk-PA7ENTUZ.mjs.map +1 -0
- package/dist/{chunk-3K7WF6KB.mjs → chunk-PEFC5T7R.mjs} +8 -8
- package/dist/{chunk-3K7WF6KB.mjs.map → chunk-PEFC5T7R.mjs.map} +1 -1
- package/dist/{chunk-H23ZT2I2.mjs → chunk-PENNTSJE.mjs} +35 -3
- package/dist/chunk-PENNTSJE.mjs.map +1 -0
- package/dist/{chunk-4NUHZ24M.js → chunk-Q6KS7FMY.js} +13 -13
- package/dist/{chunk-4NUHZ24M.js.map → chunk-Q6KS7FMY.js.map} +1 -1
- package/dist/{chunk-5Y5GCSH6.mjs → chunk-R26NFTOR.mjs} +3 -3
- package/dist/{chunk-5Y5GCSH6.mjs.map → chunk-R26NFTOR.mjs.map} +1 -1
- package/dist/{chunk-NM7L2XKF.mjs → chunk-RSFSXEV2.mjs} +4 -4
- package/dist/{chunk-NM7L2XKF.mjs.map → chunk-RSFSXEV2.mjs.map} +1 -1
- package/dist/{chunk-AUBFDSTJ.js → chunk-S3J7MEOD.js} +8 -8
- package/dist/{chunk-AUBFDSTJ.js.map → chunk-S3J7MEOD.js.map} +1 -1
- package/dist/{chunk-34IUDOBC.mjs → chunk-SP3MXF3A.mjs} +34 -5
- package/dist/chunk-SP3MXF3A.mjs.map +1 -0
- package/dist/{chunk-QPT5QX2W.js → chunk-TA6CENL3.js} +12 -12
- package/dist/{chunk-QPT5QX2W.js.map → chunk-TA6CENL3.js.map} +1 -1
- package/dist/{chunk-QAYCRXT4.mjs → chunk-TKP3YFNS.mjs} +3 -3
- package/dist/{chunk-QAYCRXT4.mjs.map → chunk-TKP3YFNS.mjs.map} +1 -1
- package/dist/{chunk-XAWB2HFQ.js → chunk-TMKLH6MY.js} +41 -8
- package/dist/chunk-TMKLH6MY.js.map +1 -0
- package/dist/{chunk-WQ64SU6E.js → chunk-ULY2QZWA.js} +4 -4
- package/dist/{chunk-WQ64SU6E.js.map → chunk-ULY2QZWA.js.map} +1 -1
- package/dist/{chunk-ZKAZGLHI.js → chunk-V6CWHT6B.js} +9 -9
- package/dist/{chunk-ZKAZGLHI.js.map → chunk-V6CWHT6B.js.map} +1 -1
- package/dist/{chunk-54ZC6LPR.mjs → chunk-W5ZYM276.mjs} +3 -3
- package/dist/{chunk-54ZC6LPR.mjs.map → chunk-W5ZYM276.mjs.map} +1 -1
- package/dist/{chunk-2EYHSGQ3.mjs → chunk-WYRUQCL4.mjs} +3 -3
- package/dist/{chunk-2EYHSGQ3.mjs.map → chunk-WYRUQCL4.mjs.map} +1 -1
- package/dist/{chunk-HWJF7WMI.js → chunk-XDQP4JQH.js} +14 -14
- package/dist/{chunk-HWJF7WMI.js.map → chunk-XDQP4JQH.js.map} +1 -1
- package/dist/{chunk-6T4NVCAT.js → chunk-XMBYDIV6.js} +40 -11
- package/dist/chunk-XMBYDIV6.js.map +1 -0
- package/dist/{chunk-LFFBDQM3.mjs → chunk-Y4V5TFHP.mjs} +4 -4
- package/dist/{chunk-LFFBDQM3.mjs.map → chunk-Y4V5TFHP.mjs.map} +1 -1
- package/dist/{chunk-2CNKJMGT.mjs → chunk-YUSX3NZA.mjs} +3 -3
- package/dist/{chunk-2CNKJMGT.mjs.map → chunk-YUSX3NZA.mjs.map} +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.mjs +1 -1
- package/dist/client/index.js +4 -4
- package/dist/client/index.mjs +3 -3
- package/dist/commerce/index.js +51 -51
- package/dist/commerce/index.mjs +6 -6
- package/dist/config/index.d.mts +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.js +2 -2
- package/dist/config/index.mjs +1 -1
- package/dist/engage/index.js +9 -9
- package/dist/engage/index.mjs +6 -6
- package/dist/fleet/index.js +8 -8
- package/dist/fleet/index.mjs +4 -4
- package/dist/forms/index.js +13 -13
- package/dist/forms/index.mjs +5 -5
- package/dist/images/index.js +11 -11
- package/dist/images/index.mjs +4 -4
- package/dist/index.js +64 -64
- package/dist/index.mjs +10 -10
- package/dist/layout/client.js +8 -8
- package/dist/layout/client.mjs +7 -7
- package/dist/layout/index.js +10 -10
- package/dist/layout/index.mjs +8 -8
- package/dist/llms/contract.js +9 -9
- package/dist/llms/contract.mjs +1 -1
- package/dist/llms/index.d.mts +131 -40
- package/dist/llms/index.d.ts +131 -40
- package/dist/llms/index.js +125 -21
- package/dist/llms/index.js.map +1 -1
- package/dist/llms/index.mjs +102 -4
- package/dist/llms/index.mjs.map +1 -1
- package/dist/maps/index.js +5 -5
- package/dist/maps/index.mjs +3 -3
- package/dist/middleware/index.d.mts +2 -1
- package/dist/middleware/index.d.ts +2 -1
- package/dist/middleware/index.js +6 -2
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/index.mjs +2 -1
- package/dist/middleware/index.mjs.map +1 -1
- package/dist/securityHeaders-CwsFdDcJ.d.mts +49 -0
- package/dist/securityHeaders-CwsFdDcJ.d.ts +49 -0
- package/dist/seo/client.js +5 -5
- package/dist/seo/client.mjs +4 -4
- package/dist/seo/index.js +7 -7
- package/dist/seo/index.mjs +5 -5
- package/dist/server/index.js +3 -3
- package/dist/server/index.mjs +2 -2
- package/dist/signal/index.js +11 -11
- package/dist/signal/index.mjs +2 -2
- package/dist/sitemap/index.d.mts +8 -1
- package/dist/sitemap/index.d.ts +8 -1
- package/dist/sitemap/index.js +5 -4
- package/dist/sitemap/index.js.map +1 -1
- package/dist/sitemap/index.mjs +4 -3
- package/dist/sitemap/index.mjs.map +1 -1
- package/dist/sync/index.js +16 -16
- package/dist/sync/index.mjs +4 -4
- package/dist/{types-xcP_owwn.d.ts → writeLLMsTxt-BFaNr4re.d.ts} +53 -1
- package/dist/{types-DhCAWUmd.d.mts → writeLLMsTxt-SpMdyHQT.d.mts} +53 -1
- package/package.json +1 -1
- package/dist/AnalyticsProvider-JWXDXOIR.js +0 -31
- package/dist/AnalyticsProvider-OIRXQE7O.mjs +0 -10
- package/dist/ChatWidget-FFCUDCT6.mjs +0 -10
- package/dist/ChatWidget-K2BFJXGB.js +0 -19
- package/dist/EngageWidget-QKRXI3NB.mjs +0 -9
- package/dist/EngageWidget-XRXXVVUK.js +0 -18
- package/dist/SitemapSync-KS7KTJBK.mjs +0 -8
- package/dist/SitemapSync-WEZHTSFL.js +0 -17
- package/dist/chunk-2HH4VVJT.mjs +0 -6
- package/dist/chunk-34IUDOBC.mjs.map +0 -1
- package/dist/chunk-3MYZS6PD.js.map +0 -1
- package/dist/chunk-6BIPAKL4.mjs.map +0 -1
- package/dist/chunk-6T4NVCAT.js.map +0 -1
- package/dist/chunk-ATG4FJY6.js.map +0 -1
- package/dist/chunk-GUXB3QH7.mjs.map +0 -1
- package/dist/chunk-H23ZT2I2.mjs.map +0 -1
- package/dist/chunk-SCMHZBTN.js +0 -8
- package/dist/chunk-XAWB2HFQ.js.map +0 -1
- package/dist/securityHeaders-nwZ6nP4g.d.mts +0 -24
- package/dist/securityHeaders-nwZ6nP4g.d.ts +0 -24
package/dist/analytics/index.js
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
5
|
-
var
|
|
4
|
+
var chunk2WMLHR72_js = require('../chunk-2WMLHR72.js');
|
|
5
|
+
var chunkQ6KS7FMY_js = require('../chunk-Q6KS7FMY.js');
|
|
6
6
|
var chunkHMFFAUCD_js = require('../chunk-HMFFAUCD.js');
|
|
7
7
|
require('../chunk-XB57AM6T.js');
|
|
8
8
|
require('../chunk-VJMPIRSD.js');
|
|
9
|
-
require('../chunk-
|
|
10
|
-
require('../chunk-
|
|
11
|
-
require('../chunk-
|
|
9
|
+
require('../chunk-ATOUXWFR.js');
|
|
10
|
+
require('../chunk-BB2C5JUA.js');
|
|
11
|
+
require('../chunk-JXT2WWXW.js');
|
|
12
12
|
require('../chunk-ZSMWDLMK.js');
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
Object.defineProperty(exports, "ContactTracking", {
|
|
17
17
|
enumerable: true,
|
|
18
|
-
get: function () { return
|
|
18
|
+
get: function () { return chunk2WMLHR72_js.ContactTracking; }
|
|
19
19
|
});
|
|
20
20
|
Object.defineProperty(exports, "useContactTracking", {
|
|
21
21
|
enumerable: true,
|
|
22
|
-
get: function () { return
|
|
22
|
+
get: function () { return chunk2WMLHR72_js.useContactTracking; }
|
|
23
23
|
});
|
|
24
24
|
Object.defineProperty(exports, "AnalyticsProvider", {
|
|
25
25
|
enumerable: true,
|
|
26
|
-
get: function () { return
|
|
26
|
+
get: function () { return chunkQ6KS7FMY_js.AnalyticsProvider; }
|
|
27
27
|
});
|
|
28
28
|
Object.defineProperty(exports, "WebVitals", {
|
|
29
29
|
enumerable: true,
|
|
30
|
-
get: function () { return
|
|
30
|
+
get: function () { return chunkQ6KS7FMY_js.WebVitals; }
|
|
31
31
|
});
|
|
32
32
|
Object.defineProperty(exports, "useAnalytics", {
|
|
33
33
|
enumerable: true,
|
|
34
|
-
get: function () { return
|
|
34
|
+
get: function () { return chunkQ6KS7FMY_js.useAnalytics; }
|
|
35
35
|
});
|
|
36
36
|
Object.defineProperty(exports, "useAnalyticsOptional", {
|
|
37
37
|
enumerable: true,
|
|
38
|
-
get: function () { return
|
|
38
|
+
get: function () { return chunkQ6KS7FMY_js.useAnalyticsOptional; }
|
|
39
39
|
});
|
|
40
40
|
Object.defineProperty(exports, "useTrackEvent", {
|
|
41
41
|
enumerable: true,
|
|
42
|
-
get: function () { return
|
|
42
|
+
get: function () { return chunkQ6KS7FMY_js.useTrackEvent; }
|
|
43
43
|
});
|
|
44
44
|
Object.defineProperty(exports, "trackConversion", {
|
|
45
45
|
enumerable: true,
|
package/dist/analytics/index.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
export { ContactTracking, useContactTracking } from '../chunk-
|
|
3
|
-
export { AnalyticsProvider, WebVitals, useAnalytics, useAnalyticsOptional, useTrackEvent } from '../chunk-
|
|
2
|
+
export { ContactTracking, useContactTracking } from '../chunk-WYRUQCL4.mjs';
|
|
3
|
+
export { AnalyticsProvider, WebVitals, useAnalytics, useAnalyticsOptional, useTrackEvent } from '../chunk-GH5RO5OW.mjs';
|
|
4
4
|
export { trackConversion, trackEvent } from '../chunk-3DPXOZAU.mjs';
|
|
5
5
|
import '../chunk-AX4AROLH.mjs';
|
|
6
6
|
import '../chunk-6EDVCUAG.mjs';
|
|
7
|
-
import '../chunk-
|
|
8
|
-
import '../chunk-
|
|
9
|
-
import '../chunk-
|
|
7
|
+
import '../chunk-RSFSXEV2.mjs';
|
|
8
|
+
import '../chunk-TKP3YFNS.mjs';
|
|
9
|
+
import '../chunk-JVT6CUNN.mjs';
|
|
10
10
|
import '../chunk-4XPGGLVP.mjs';
|
|
11
11
|
//# sourceMappingURL=index.mjs.map
|
|
12
12
|
//# sourceMappingURL=index.mjs.map
|
package/dist/blog/server-ui.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkMMON6EVI_js = require('../chunk-MMON6EVI.js');
|
|
4
|
-
var
|
|
4
|
+
var chunkTMKLH6MY_js = require('../chunk-TMKLH6MY.js');
|
|
5
5
|
require('../chunk-TPL2IHFI.js');
|
|
6
6
|
require('../chunk-QPIKPWAZ.js');
|
|
7
7
|
require('../chunk-ZSMWDLMK.js');
|
|
@@ -122,7 +122,7 @@ async function ClusterLandingPage({
|
|
|
122
122
|
className,
|
|
123
123
|
children
|
|
124
124
|
}) {
|
|
125
|
-
const cluster = await
|
|
125
|
+
const cluster = await chunkTMKLH6MY_js.getTopicCluster(slug);
|
|
126
126
|
if (!cluster) {
|
|
127
127
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "4rem 1rem", textAlign: "center", color: "#6b7280" }, children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Topic cluster not found." }) });
|
|
128
128
|
}
|
|
@@ -158,8 +158,8 @@ async function ClusterLandingPage({
|
|
|
158
158
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: unstyled ? "" : "sk-cluster-pillar-title", children: pillar.title }),
|
|
159
159
|
pillar.excerpt && /* @__PURE__ */ jsxRuntime.jsx("p", { className: unstyled ? "" : "sk-cluster-pillar-excerpt", children: pillar.excerpt }),
|
|
160
160
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: unstyled ? "" : "sk-cluster-pillar-meta", children: [
|
|
161
|
-
pillar.reading_time_minutes && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
162
|
-
pillar.reading_time_minutes,
|
|
161
|
+
(pillar.reading_time_minutes ?? pillar.reading_time) && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
162
|
+
pillar.reading_time_minutes ?? pillar.reading_time,
|
|
163
163
|
" min read"
|
|
164
164
|
] }),
|
|
165
165
|
pillar.word_count && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
@@ -183,8 +183,8 @@ async function ClusterLandingPage({
|
|
|
183
183
|
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: unstyled ? "" : "sk-cluster-support-title", children: post.title }),
|
|
184
184
|
post.excerpt && /* @__PURE__ */ jsxRuntime.jsx("p", { className: unstyled ? "" : "sk-cluster-support-excerpt", children: post.excerpt }),
|
|
185
185
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: unstyled ? "" : "sk-cluster-support-meta", children: [
|
|
186
|
-
post.reading_time_minutes && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
187
|
-
post.reading_time_minutes,
|
|
186
|
+
(post.reading_time_minutes ?? post.reading_time) && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
187
|
+
post.reading_time_minutes ?? post.reading_time,
|
|
188
188
|
" min read"
|
|
189
189
|
] }),
|
|
190
190
|
post.relationship_to_pillar && /* @__PURE__ */ jsxRuntime.jsx("span", { children: post.relationship_to_pillar })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/blog/ClusterLandingPage.tsx"],"names":["getTopicCluster","jsx","jsxs","Fragment"],"mappings":"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","file":"server-ui.js","sourcesContent":["/**\n * @sonordev/site-kit/blog - Cluster Landing Page Component\n *\n * Pre-built page component for `/blog/cluster/[slug]` routes.\n * Renders a topic cluster overview with:\n * - Cluster hero (name, topic, description)\n * - Pillar article (featured, large card)\n * - Support articles (grid, categorized by article_type or funnel_stage)\n *\n * Server component — fetches cluster data from Portal API.\n * Ships with `.sk-cluster-landing-*` scoped styles.\n */\n\nimport React from 'react'\nimport { getTopicCluster } from './server-core'\nimport type { TopicCluster, BlogPost } from './types'\n\n// ============================================================================\n// CSS\n// ============================================================================\n\nconst clusterLandingCss = `\n.sk-cluster-landing { max-width: 72rem; margin: 0 auto; padding: 2rem 1rem; }\n\n.sk-cluster-hero { margin-bottom: 3rem; text-align: center; }\n.sk-cluster-hero-label {\n display: inline-flex; align-items: center; gap: 0.375rem;\n font-size: 0.75rem; font-weight: 600; text-transform: uppercase;\n letter-spacing: 0.05em; color: #6366f1; margin-bottom: 0.75rem;\n}\n.sk-cluster-hero-title {\n font-size: 2.25rem; font-weight: 800; color: #111827;\n line-height: 1.2; margin: 0 0 0.75rem 0;\n}\n.sk-cluster-hero-desc {\n font-size: 1.125rem; color: #6b7280; max-width: 40rem;\n margin: 0 auto; line-height: 1.6;\n}\n.sk-cluster-hero-meta {\n display: flex; justify-content: center; gap: 1.5rem;\n margin-top: 1rem; font-size: 0.875rem; color: #9ca3af;\n}\n\n.sk-cluster-pillar-card {\n display: block; text-decoration: none; color: inherit;\n padding: 2rem; border-radius: 0.75rem;\n background: linear-gradient(135deg, rgba(99,102,241,0.04), rgba(99,102,241,0.01));\n border: 2px solid rgba(99,102,241,0.2);\n margin-bottom: 3rem; transition: border-color 0.2s, box-shadow 0.2s;\n}\n.sk-cluster-pillar-card:hover {\n border-color: rgba(99,102,241,0.4);\n box-shadow: 0 4px 24px rgba(99,102,241,0.08);\n}\n.sk-cluster-pillar-label {\n display: inline-flex; align-items: center; gap: 0.375rem;\n font-size: 0.6875rem; font-weight: 700; text-transform: uppercase;\n letter-spacing: 0.05em; color: #6366f1; margin-bottom: 0.75rem;\n padding: 0.25rem 0.5rem; border-radius: 9999px;\n background: rgba(99,102,241,0.08);\n}\n.sk-cluster-pillar-title {\n font-size: 1.5rem; font-weight: 700; color: #111827;\n margin: 0 0 0.5rem 0; line-height: 1.3;\n}\n.sk-cluster-pillar-excerpt {\n font-size: 1rem; color: #6b7280; line-height: 1.6;\n margin: 0 0 1rem 0;\n}\n.sk-cluster-pillar-meta {\n display: flex; gap: 1rem; font-size: 0.8125rem; color: #9ca3af;\n}\n\n.sk-cluster-supports-section { margin-bottom: 2rem; }\n.sk-cluster-supports-title {\n font-size: 1.25rem; font-weight: 700; color: #111827;\n margin: 0 0 1.25rem 0;\n}\n.sk-cluster-supports-grid {\n display: grid; gap: 1.25rem;\n grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));\n}\n.sk-cluster-support-card {\n display: block; text-decoration: none; color: inherit;\n padding: 1.25rem; border-radius: 0.5rem;\n border: 1px solid #e5e7eb; background: #fff;\n transition: border-color 0.2s, box-shadow 0.2s;\n}\n.sk-cluster-support-card:hover {\n border-color: #c7d2fe;\n box-shadow: 0 2px 12px rgba(0,0,0,0.04);\n}\n.sk-cluster-support-card-header {\n display: flex; align-items: center; gap: 0.5rem;\n margin-bottom: 0.5rem;\n}\n.sk-cluster-support-type {\n display: inline-flex; align-items: center;\n padding: 0.125rem 0.375rem; border-radius: 9999px;\n font-size: 0.6875rem; font-weight: 500;\n background: rgba(99,102,241,0.06); color: #6366f1;\n border: 1px solid rgba(99,102,241,0.12);\n text-transform: capitalize;\n}\n.sk-cluster-support-intent {\n font-size: 0.6875rem; color: #9ca3af;\n text-transform: capitalize;\n}\n.sk-cluster-support-title {\n font-size: 1rem; font-weight: 600; color: #111827;\n margin: 0 0 0.375rem 0; line-height: 1.4;\n}\n.sk-cluster-support-excerpt {\n font-size: 0.875rem; color: #6b7280; line-height: 1.5;\n margin: 0; display: -webkit-box; -webkit-line-clamp: 2;\n -webkit-box-orient: vertical; overflow: hidden;\n}\n.sk-cluster-support-meta {\n display: flex; gap: 0.75rem; margin-top: 0.75rem;\n font-size: 0.75rem; color: #9ca3af;\n}\n`\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport interface ClusterLandingPageProps {\n /** Cluster slug to fetch */\n slug: string\n /** Base path for blog URLs (default: /blog) */\n basePath?: string\n /**\n * Include each article's own category segment in its URL:\n * {basePath}/{category}/{slug}. Enable on sites whose blog routes are\n * category-segmented (e.g. upforge.io /insights/{category}/{slug}) —\n * without it, links point at {basePath}/{slug} and 404 on such sites.\n */\n categoryInPath?: boolean\n /** Disable default styles */\n unstyled?: boolean\n /** Custom class name */\n className?: string\n /** Render prop for full data access */\n children?: (props: { cluster: TopicCluster }) => React.ReactNode\n}\n\n/** Category slug of a post — handles both string and object category shapes. */\nfunction categorySlugOf(post: { category?: unknown } | null | undefined): string | null {\n const c = post?.category as { slug?: string } | string | undefined\n if (!c) return null\n if (typeof c === 'string') return c\n return c.slug || null\n}\n\nexport async function ClusterLandingPage({\n slug,\n basePath = '/blog',\n categoryInPath = false,\n unstyled = false,\n className,\n children,\n}: ClusterLandingPageProps) {\n const cluster = await getTopicCluster(slug)\n\n if (!cluster) {\n return (\n <div style={{ padding: '4rem 1rem', textAlign: 'center', color: '#6b7280' }}>\n <p>Topic cluster not found.</p>\n </div>\n )\n }\n\n // Custom render\n if (children) {\n return children({ cluster })\n }\n\n const pillar = cluster.pillar\n const supports = cluster.supports || []\n\n const articleUrl = (post: { slug: string; category?: unknown }) => {\n const cat = categoryInPath ? categorySlugOf(post) : null\n return cat ? `${basePath}/${cat}/${post.slug}` : `${basePath}/${post.slug}`\n }\n\n return (\n <>\n {!unstyled && <style dangerouslySetInnerHTML={{ __html: clusterLandingCss }} />}\n\n <div className={`${unstyled ? '' : 'sk-cluster-landing'} ${className || ''}`}>\n {/* Hero */}\n <header className={unstyled ? '' : 'sk-cluster-hero'}>\n <p className={unstyled ? '' : 'sk-cluster-hero-label'}>\n Topic Cluster\n </p>\n <h1 className={unstyled ? '' : 'sk-cluster-hero-title'}>\n {cluster.cluster_name}\n </h1>\n <p className={unstyled ? '' : 'sk-cluster-hero-desc'}>\n {cluster.core_topic}\n {cluster.geo_target ? ` in ${cluster.geo_target}` : ''}\n </p>\n <div className={unstyled ? '' : 'sk-cluster-hero-meta'}>\n <span>{cluster.article_count} articles</span>\n {cluster.geo_target && <span>{cluster.geo_target}</span>}\n </div>\n </header>\n\n {/* Pillar article (hero card) */}\n {pillar && (\n <a href={articleUrl(pillar)} className={unstyled ? '' : 'sk-cluster-pillar-card'}>\n <span className={unstyled ? '' : 'sk-cluster-pillar-label'}>\n Pillar Guide\n </span>\n <h2 className={unstyled ? '' : 'sk-cluster-pillar-title'}>\n {pillar.title}\n </h2>\n {pillar.excerpt && (\n <p className={unstyled ? '' : 'sk-cluster-pillar-excerpt'}>\n {pillar.excerpt}\n </p>\n )}\n <div className={unstyled ? '' : 'sk-cluster-pillar-meta'}>\n {pillar.reading_time_minutes && (\n <span>{pillar.reading_time_minutes} min read</span>\n )}\n {pillar.word_count && (\n <span>{pillar.word_count.toLocaleString()} words</span>\n )}\n </div>\n </a>\n )}\n\n {/* Support articles */}\n {supports.length > 0 && (\n <section className={unstyled ? '' : 'sk-cluster-supports-section'}>\n <h2 className={unstyled ? '' : 'sk-cluster-supports-title'}>\n Deep Dives\n </h2>\n <div className={unstyled ? '' : 'sk-cluster-supports-grid'}>\n {supports.map((post) => (\n <a\n key={post.id || post.slug}\n href={articleUrl(post)}\n className={unstyled ? '' : 'sk-cluster-support-card'}\n >\n <div className={unstyled ? '' : 'sk-cluster-support-card-header'}>\n {post.article_type && (\n <span className={unstyled ? '' : 'sk-cluster-support-type'}>\n {post.article_type}\n </span>\n )}\n {post.search_intent && (\n <span className={unstyled ? '' : 'sk-cluster-support-intent'}>\n {post.search_intent}\n </span>\n )}\n </div>\n <h3 className={unstyled ? '' : 'sk-cluster-support-title'}>\n {post.title}\n </h3>\n {post.excerpt && (\n <p className={unstyled ? '' : 'sk-cluster-support-excerpt'}>\n {post.excerpt}\n </p>\n )}\n <div className={unstyled ? '' : 'sk-cluster-support-meta'}>\n {post.reading_time_minutes && (\n <span>{post.reading_time_minutes} min read</span>\n )}\n {post.relationship_to_pillar && (\n <span>{post.relationship_to_pillar}</span>\n )}\n </div>\n </a>\n ))}\n </div>\n </section>\n )}\n </div>\n </>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/blog/ClusterLandingPage.tsx"],"names":["getTopicCluster","jsx","jsxs","Fragment"],"mappings":"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","file":"server-ui.js","sourcesContent":["/**\n * @sonordev/site-kit/blog - Cluster Landing Page Component\n *\n * Pre-built page component for `/blog/cluster/[slug]` routes.\n * Renders a topic cluster overview with:\n * - Cluster hero (name, topic, description)\n * - Pillar article (featured, large card)\n * - Support articles (grid, categorized by article_type or funnel_stage)\n *\n * Server component — fetches cluster data from Portal API.\n * Ships with `.sk-cluster-landing-*` scoped styles.\n */\n\nimport React from 'react'\nimport { getTopicCluster } from './server-core'\nimport type { TopicCluster, BlogPost } from './types'\n\n// ============================================================================\n// CSS\n// ============================================================================\n\nconst clusterLandingCss = `\n.sk-cluster-landing { max-width: 72rem; margin: 0 auto; padding: 2rem 1rem; }\n\n.sk-cluster-hero { margin-bottom: 3rem; text-align: center; }\n.sk-cluster-hero-label {\n display: inline-flex; align-items: center; gap: 0.375rem;\n font-size: 0.75rem; font-weight: 600; text-transform: uppercase;\n letter-spacing: 0.05em; color: #6366f1; margin-bottom: 0.75rem;\n}\n.sk-cluster-hero-title {\n font-size: 2.25rem; font-weight: 800; color: #111827;\n line-height: 1.2; margin: 0 0 0.75rem 0;\n}\n.sk-cluster-hero-desc {\n font-size: 1.125rem; color: #6b7280; max-width: 40rem;\n margin: 0 auto; line-height: 1.6;\n}\n.sk-cluster-hero-meta {\n display: flex; justify-content: center; gap: 1.5rem;\n margin-top: 1rem; font-size: 0.875rem; color: #9ca3af;\n}\n\n.sk-cluster-pillar-card {\n display: block; text-decoration: none; color: inherit;\n padding: 2rem; border-radius: 0.75rem;\n background: linear-gradient(135deg, rgba(99,102,241,0.04), rgba(99,102,241,0.01));\n border: 2px solid rgba(99,102,241,0.2);\n margin-bottom: 3rem; transition: border-color 0.2s, box-shadow 0.2s;\n}\n.sk-cluster-pillar-card:hover {\n border-color: rgba(99,102,241,0.4);\n box-shadow: 0 4px 24px rgba(99,102,241,0.08);\n}\n.sk-cluster-pillar-label {\n display: inline-flex; align-items: center; gap: 0.375rem;\n font-size: 0.6875rem; font-weight: 700; text-transform: uppercase;\n letter-spacing: 0.05em; color: #6366f1; margin-bottom: 0.75rem;\n padding: 0.25rem 0.5rem; border-radius: 9999px;\n background: rgba(99,102,241,0.08);\n}\n.sk-cluster-pillar-title {\n font-size: 1.5rem; font-weight: 700; color: #111827;\n margin: 0 0 0.5rem 0; line-height: 1.3;\n}\n.sk-cluster-pillar-excerpt {\n font-size: 1rem; color: #6b7280; line-height: 1.6;\n margin: 0 0 1rem 0;\n}\n.sk-cluster-pillar-meta {\n display: flex; gap: 1rem; font-size: 0.8125rem; color: #9ca3af;\n}\n\n.sk-cluster-supports-section { margin-bottom: 2rem; }\n.sk-cluster-supports-title {\n font-size: 1.25rem; font-weight: 700; color: #111827;\n margin: 0 0 1.25rem 0;\n}\n.sk-cluster-supports-grid {\n display: grid; gap: 1.25rem;\n grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));\n}\n.sk-cluster-support-card {\n display: block; text-decoration: none; color: inherit;\n padding: 1.25rem; border-radius: 0.5rem;\n border: 1px solid #e5e7eb; background: #fff;\n transition: border-color 0.2s, box-shadow 0.2s;\n}\n.sk-cluster-support-card:hover {\n border-color: #c7d2fe;\n box-shadow: 0 2px 12px rgba(0,0,0,0.04);\n}\n.sk-cluster-support-card-header {\n display: flex; align-items: center; gap: 0.5rem;\n margin-bottom: 0.5rem;\n}\n.sk-cluster-support-type {\n display: inline-flex; align-items: center;\n padding: 0.125rem 0.375rem; border-radius: 9999px;\n font-size: 0.6875rem; font-weight: 500;\n background: rgba(99,102,241,0.06); color: #6366f1;\n border: 1px solid rgba(99,102,241,0.12);\n text-transform: capitalize;\n}\n.sk-cluster-support-intent {\n font-size: 0.6875rem; color: #9ca3af;\n text-transform: capitalize;\n}\n.sk-cluster-support-title {\n font-size: 1rem; font-weight: 600; color: #111827;\n margin: 0 0 0.375rem 0; line-height: 1.4;\n}\n.sk-cluster-support-excerpt {\n font-size: 0.875rem; color: #6b7280; line-height: 1.5;\n margin: 0; display: -webkit-box; -webkit-line-clamp: 2;\n -webkit-box-orient: vertical; overflow: hidden;\n}\n.sk-cluster-support-meta {\n display: flex; gap: 0.75rem; margin-top: 0.75rem;\n font-size: 0.75rem; color: #9ca3af;\n}\n`\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport interface ClusterLandingPageProps {\n /** Cluster slug to fetch */\n slug: string\n /** Base path for blog URLs (default: /blog) */\n basePath?: string\n /**\n * Include each article's own category segment in its URL:\n * {basePath}/{category}/{slug}. Enable on sites whose blog routes are\n * category-segmented (e.g. upforge.io /insights/{category}/{slug}) —\n * without it, links point at {basePath}/{slug} and 404 on such sites.\n */\n categoryInPath?: boolean\n /** Disable default styles */\n unstyled?: boolean\n /** Custom class name */\n className?: string\n /** Render prop for full data access */\n children?: (props: { cluster: TopicCluster }) => React.ReactNode\n}\n\n/** Category slug of a post — handles both string and object category shapes. */\nfunction categorySlugOf(post: { category?: unknown } | null | undefined): string | null {\n const c = post?.category as { slug?: string } | string | undefined\n if (!c) return null\n if (typeof c === 'string') return c\n return c.slug || null\n}\n\nexport async function ClusterLandingPage({\n slug,\n basePath = '/blog',\n categoryInPath = false,\n unstyled = false,\n className,\n children,\n}: ClusterLandingPageProps) {\n const cluster = await getTopicCluster(slug)\n\n if (!cluster) {\n return (\n <div style={{ padding: '4rem 1rem', textAlign: 'center', color: '#6b7280' }}>\n <p>Topic cluster not found.</p>\n </div>\n )\n }\n\n // Custom render\n if (children) {\n return children({ cluster })\n }\n\n const pillar = cluster.pillar\n const supports = cluster.supports || []\n\n const articleUrl = (post: { slug: string; category?: unknown }) => {\n const cat = categoryInPath ? categorySlugOf(post) : null\n return cat ? `${basePath}/${cat}/${post.slug}` : `${basePath}/${post.slug}`\n }\n\n return (\n <>\n {!unstyled && <style dangerouslySetInnerHTML={{ __html: clusterLandingCss }} />}\n\n <div className={`${unstyled ? '' : 'sk-cluster-landing'} ${className || ''}`}>\n {/* Hero */}\n <header className={unstyled ? '' : 'sk-cluster-hero'}>\n <p className={unstyled ? '' : 'sk-cluster-hero-label'}>\n Topic Cluster\n </p>\n <h1 className={unstyled ? '' : 'sk-cluster-hero-title'}>\n {cluster.cluster_name}\n </h1>\n <p className={unstyled ? '' : 'sk-cluster-hero-desc'}>\n {cluster.core_topic}\n {cluster.geo_target ? ` in ${cluster.geo_target}` : ''}\n </p>\n <div className={unstyled ? '' : 'sk-cluster-hero-meta'}>\n <span>{cluster.article_count} articles</span>\n {cluster.geo_target && <span>{cluster.geo_target}</span>}\n </div>\n </header>\n\n {/* Pillar article (hero card) */}\n {pillar && (\n <a href={articleUrl(pillar)} className={unstyled ? '' : 'sk-cluster-pillar-card'}>\n <span className={unstyled ? '' : 'sk-cluster-pillar-label'}>\n Pillar Guide\n </span>\n <h2 className={unstyled ? '' : 'sk-cluster-pillar-title'}>\n {pillar.title}\n </h2>\n {pillar.excerpt && (\n <p className={unstyled ? '' : 'sk-cluster-pillar-excerpt'}>\n {pillar.excerpt}\n </p>\n )}\n <div className={unstyled ? '' : 'sk-cluster-pillar-meta'}>\n {(pillar.reading_time_minutes ?? pillar.reading_time) && (\n <span>{pillar.reading_time_minutes ?? pillar.reading_time} min read</span>\n )}\n {pillar.word_count && (\n <span>{pillar.word_count.toLocaleString()} words</span>\n )}\n </div>\n </a>\n )}\n\n {/* Support articles */}\n {supports.length > 0 && (\n <section className={unstyled ? '' : 'sk-cluster-supports-section'}>\n <h2 className={unstyled ? '' : 'sk-cluster-supports-title'}>\n Deep Dives\n </h2>\n <div className={unstyled ? '' : 'sk-cluster-supports-grid'}>\n {supports.map((post) => (\n <a\n key={post.id || post.slug}\n href={articleUrl(post)}\n className={unstyled ? '' : 'sk-cluster-support-card'}\n >\n <div className={unstyled ? '' : 'sk-cluster-support-card-header'}>\n {post.article_type && (\n <span className={unstyled ? '' : 'sk-cluster-support-type'}>\n {post.article_type}\n </span>\n )}\n {post.search_intent && (\n <span className={unstyled ? '' : 'sk-cluster-support-intent'}>\n {post.search_intent}\n </span>\n )}\n </div>\n <h3 className={unstyled ? '' : 'sk-cluster-support-title'}>\n {post.title}\n </h3>\n {post.excerpt && (\n <p className={unstyled ? '' : 'sk-cluster-support-excerpt'}>\n {post.excerpt}\n </p>\n )}\n <div className={unstyled ? '' : 'sk-cluster-support-meta'}>\n {(post.reading_time_minutes ?? post.reading_time) && (\n <span>{post.reading_time_minutes ?? post.reading_time} min read</span>\n )}\n {post.relationship_to_pillar && (\n <span>{post.relationship_to_pillar}</span>\n )}\n </div>\n </a>\n ))}\n </div>\n </section>\n )}\n </div>\n </>\n )\n}\n"]}
|
package/dist/blog/server-ui.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { BlogList, BlogPost, ClusterNavigation } from '../chunk-WTR7QJ32.mjs';
|
|
2
|
-
import { getTopicCluster } from '../chunk-
|
|
2
|
+
import { getTopicCluster } from '../chunk-PA7ENTUZ.mjs';
|
|
3
3
|
import '../chunk-CGCYZJYX.mjs';
|
|
4
4
|
import '../chunk-UDBUK5ZJ.mjs';
|
|
5
5
|
import '../chunk-4XPGGLVP.mjs';
|
|
@@ -156,8 +156,8 @@ async function ClusterLandingPage({
|
|
|
156
156
|
/* @__PURE__ */ jsx("h2", { className: unstyled ? "" : "sk-cluster-pillar-title", children: pillar.title }),
|
|
157
157
|
pillar.excerpt && /* @__PURE__ */ jsx("p", { className: unstyled ? "" : "sk-cluster-pillar-excerpt", children: pillar.excerpt }),
|
|
158
158
|
/* @__PURE__ */ jsxs("div", { className: unstyled ? "" : "sk-cluster-pillar-meta", children: [
|
|
159
|
-
pillar.reading_time_minutes && /* @__PURE__ */ jsxs("span", { children: [
|
|
160
|
-
pillar.reading_time_minutes,
|
|
159
|
+
(pillar.reading_time_minutes ?? pillar.reading_time) && /* @__PURE__ */ jsxs("span", { children: [
|
|
160
|
+
pillar.reading_time_minutes ?? pillar.reading_time,
|
|
161
161
|
" min read"
|
|
162
162
|
] }),
|
|
163
163
|
pillar.word_count && /* @__PURE__ */ jsxs("span", { children: [
|
|
@@ -181,8 +181,8 @@ async function ClusterLandingPage({
|
|
|
181
181
|
/* @__PURE__ */ jsx("h3", { className: unstyled ? "" : "sk-cluster-support-title", children: post.title }),
|
|
182
182
|
post.excerpt && /* @__PURE__ */ jsx("p", { className: unstyled ? "" : "sk-cluster-support-excerpt", children: post.excerpt }),
|
|
183
183
|
/* @__PURE__ */ jsxs("div", { className: unstyled ? "" : "sk-cluster-support-meta", children: [
|
|
184
|
-
post.reading_time_minutes && /* @__PURE__ */ jsxs("span", { children: [
|
|
185
|
-
post.reading_time_minutes,
|
|
184
|
+
(post.reading_time_minutes ?? post.reading_time) && /* @__PURE__ */ jsxs("span", { children: [
|
|
185
|
+
post.reading_time_minutes ?? post.reading_time,
|
|
186
186
|
" min read"
|
|
187
187
|
] }),
|
|
188
188
|
post.relationship_to_pillar && /* @__PURE__ */ jsx("span", { children: post.relationship_to_pillar })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/blog/ClusterLandingPage.tsx"],"names":[],"mappings":"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","file":"server-ui.mjs","sourcesContent":["/**\n * @sonordev/site-kit/blog - Cluster Landing Page Component\n *\n * Pre-built page component for `/blog/cluster/[slug]` routes.\n * Renders a topic cluster overview with:\n * - Cluster hero (name, topic, description)\n * - Pillar article (featured, large card)\n * - Support articles (grid, categorized by article_type or funnel_stage)\n *\n * Server component — fetches cluster data from Portal API.\n * Ships with `.sk-cluster-landing-*` scoped styles.\n */\n\nimport React from 'react'\nimport { getTopicCluster } from './server-core'\nimport type { TopicCluster, BlogPost } from './types'\n\n// ============================================================================\n// CSS\n// ============================================================================\n\nconst clusterLandingCss = `\n.sk-cluster-landing { max-width: 72rem; margin: 0 auto; padding: 2rem 1rem; }\n\n.sk-cluster-hero { margin-bottom: 3rem; text-align: center; }\n.sk-cluster-hero-label {\n display: inline-flex; align-items: center; gap: 0.375rem;\n font-size: 0.75rem; font-weight: 600; text-transform: uppercase;\n letter-spacing: 0.05em; color: #6366f1; margin-bottom: 0.75rem;\n}\n.sk-cluster-hero-title {\n font-size: 2.25rem; font-weight: 800; color: #111827;\n line-height: 1.2; margin: 0 0 0.75rem 0;\n}\n.sk-cluster-hero-desc {\n font-size: 1.125rem; color: #6b7280; max-width: 40rem;\n margin: 0 auto; line-height: 1.6;\n}\n.sk-cluster-hero-meta {\n display: flex; justify-content: center; gap: 1.5rem;\n margin-top: 1rem; font-size: 0.875rem; color: #9ca3af;\n}\n\n.sk-cluster-pillar-card {\n display: block; text-decoration: none; color: inherit;\n padding: 2rem; border-radius: 0.75rem;\n background: linear-gradient(135deg, rgba(99,102,241,0.04), rgba(99,102,241,0.01));\n border: 2px solid rgba(99,102,241,0.2);\n margin-bottom: 3rem; transition: border-color 0.2s, box-shadow 0.2s;\n}\n.sk-cluster-pillar-card:hover {\n border-color: rgba(99,102,241,0.4);\n box-shadow: 0 4px 24px rgba(99,102,241,0.08);\n}\n.sk-cluster-pillar-label {\n display: inline-flex; align-items: center; gap: 0.375rem;\n font-size: 0.6875rem; font-weight: 700; text-transform: uppercase;\n letter-spacing: 0.05em; color: #6366f1; margin-bottom: 0.75rem;\n padding: 0.25rem 0.5rem; border-radius: 9999px;\n background: rgba(99,102,241,0.08);\n}\n.sk-cluster-pillar-title {\n font-size: 1.5rem; font-weight: 700; color: #111827;\n margin: 0 0 0.5rem 0; line-height: 1.3;\n}\n.sk-cluster-pillar-excerpt {\n font-size: 1rem; color: #6b7280; line-height: 1.6;\n margin: 0 0 1rem 0;\n}\n.sk-cluster-pillar-meta {\n display: flex; gap: 1rem; font-size: 0.8125rem; color: #9ca3af;\n}\n\n.sk-cluster-supports-section { margin-bottom: 2rem; }\n.sk-cluster-supports-title {\n font-size: 1.25rem; font-weight: 700; color: #111827;\n margin: 0 0 1.25rem 0;\n}\n.sk-cluster-supports-grid {\n display: grid; gap: 1.25rem;\n grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));\n}\n.sk-cluster-support-card {\n display: block; text-decoration: none; color: inherit;\n padding: 1.25rem; border-radius: 0.5rem;\n border: 1px solid #e5e7eb; background: #fff;\n transition: border-color 0.2s, box-shadow 0.2s;\n}\n.sk-cluster-support-card:hover {\n border-color: #c7d2fe;\n box-shadow: 0 2px 12px rgba(0,0,0,0.04);\n}\n.sk-cluster-support-card-header {\n display: flex; align-items: center; gap: 0.5rem;\n margin-bottom: 0.5rem;\n}\n.sk-cluster-support-type {\n display: inline-flex; align-items: center;\n padding: 0.125rem 0.375rem; border-radius: 9999px;\n font-size: 0.6875rem; font-weight: 500;\n background: rgba(99,102,241,0.06); color: #6366f1;\n border: 1px solid rgba(99,102,241,0.12);\n text-transform: capitalize;\n}\n.sk-cluster-support-intent {\n font-size: 0.6875rem; color: #9ca3af;\n text-transform: capitalize;\n}\n.sk-cluster-support-title {\n font-size: 1rem; font-weight: 600; color: #111827;\n margin: 0 0 0.375rem 0; line-height: 1.4;\n}\n.sk-cluster-support-excerpt {\n font-size: 0.875rem; color: #6b7280; line-height: 1.5;\n margin: 0; display: -webkit-box; -webkit-line-clamp: 2;\n -webkit-box-orient: vertical; overflow: hidden;\n}\n.sk-cluster-support-meta {\n display: flex; gap: 0.75rem; margin-top: 0.75rem;\n font-size: 0.75rem; color: #9ca3af;\n}\n`\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport interface ClusterLandingPageProps {\n /** Cluster slug to fetch */\n slug: string\n /** Base path for blog URLs (default: /blog) */\n basePath?: string\n /**\n * Include each article's own category segment in its URL:\n * {basePath}/{category}/{slug}. Enable on sites whose blog routes are\n * category-segmented (e.g. upforge.io /insights/{category}/{slug}) —\n * without it, links point at {basePath}/{slug} and 404 on such sites.\n */\n categoryInPath?: boolean\n /** Disable default styles */\n unstyled?: boolean\n /** Custom class name */\n className?: string\n /** Render prop for full data access */\n children?: (props: { cluster: TopicCluster }) => React.ReactNode\n}\n\n/** Category slug of a post — handles both string and object category shapes. */\nfunction categorySlugOf(post: { category?: unknown } | null | undefined): string | null {\n const c = post?.category as { slug?: string } | string | undefined\n if (!c) return null\n if (typeof c === 'string') return c\n return c.slug || null\n}\n\nexport async function ClusterLandingPage({\n slug,\n basePath = '/blog',\n categoryInPath = false,\n unstyled = false,\n className,\n children,\n}: ClusterLandingPageProps) {\n const cluster = await getTopicCluster(slug)\n\n if (!cluster) {\n return (\n <div style={{ padding: '4rem 1rem', textAlign: 'center', color: '#6b7280' }}>\n <p>Topic cluster not found.</p>\n </div>\n )\n }\n\n // Custom render\n if (children) {\n return children({ cluster })\n }\n\n const pillar = cluster.pillar\n const supports = cluster.supports || []\n\n const articleUrl = (post: { slug: string; category?: unknown }) => {\n const cat = categoryInPath ? categorySlugOf(post) : null\n return cat ? `${basePath}/${cat}/${post.slug}` : `${basePath}/${post.slug}`\n }\n\n return (\n <>\n {!unstyled && <style dangerouslySetInnerHTML={{ __html: clusterLandingCss }} />}\n\n <div className={`${unstyled ? '' : 'sk-cluster-landing'} ${className || ''}`}>\n {/* Hero */}\n <header className={unstyled ? '' : 'sk-cluster-hero'}>\n <p className={unstyled ? '' : 'sk-cluster-hero-label'}>\n Topic Cluster\n </p>\n <h1 className={unstyled ? '' : 'sk-cluster-hero-title'}>\n {cluster.cluster_name}\n </h1>\n <p className={unstyled ? '' : 'sk-cluster-hero-desc'}>\n {cluster.core_topic}\n {cluster.geo_target ? ` in ${cluster.geo_target}` : ''}\n </p>\n <div className={unstyled ? '' : 'sk-cluster-hero-meta'}>\n <span>{cluster.article_count} articles</span>\n {cluster.geo_target && <span>{cluster.geo_target}</span>}\n </div>\n </header>\n\n {/* Pillar article (hero card) */}\n {pillar && (\n <a href={articleUrl(pillar)} className={unstyled ? '' : 'sk-cluster-pillar-card'}>\n <span className={unstyled ? '' : 'sk-cluster-pillar-label'}>\n Pillar Guide\n </span>\n <h2 className={unstyled ? '' : 'sk-cluster-pillar-title'}>\n {pillar.title}\n </h2>\n {pillar.excerpt && (\n <p className={unstyled ? '' : 'sk-cluster-pillar-excerpt'}>\n {pillar.excerpt}\n </p>\n )}\n <div className={unstyled ? '' : 'sk-cluster-pillar-meta'}>\n {pillar.reading_time_minutes && (\n <span>{pillar.reading_time_minutes} min read</span>\n )}\n {pillar.word_count && (\n <span>{pillar.word_count.toLocaleString()} words</span>\n )}\n </div>\n </a>\n )}\n\n {/* Support articles */}\n {supports.length > 0 && (\n <section className={unstyled ? '' : 'sk-cluster-supports-section'}>\n <h2 className={unstyled ? '' : 'sk-cluster-supports-title'}>\n Deep Dives\n </h2>\n <div className={unstyled ? '' : 'sk-cluster-supports-grid'}>\n {supports.map((post) => (\n <a\n key={post.id || post.slug}\n href={articleUrl(post)}\n className={unstyled ? '' : 'sk-cluster-support-card'}\n >\n <div className={unstyled ? '' : 'sk-cluster-support-card-header'}>\n {post.article_type && (\n <span className={unstyled ? '' : 'sk-cluster-support-type'}>\n {post.article_type}\n </span>\n )}\n {post.search_intent && (\n <span className={unstyled ? '' : 'sk-cluster-support-intent'}>\n {post.search_intent}\n </span>\n )}\n </div>\n <h3 className={unstyled ? '' : 'sk-cluster-support-title'}>\n {post.title}\n </h3>\n {post.excerpt && (\n <p className={unstyled ? '' : 'sk-cluster-support-excerpt'}>\n {post.excerpt}\n </p>\n )}\n <div className={unstyled ? '' : 'sk-cluster-support-meta'}>\n {post.reading_time_minutes && (\n <span>{post.reading_time_minutes} min read</span>\n )}\n {post.relationship_to_pillar && (\n <span>{post.relationship_to_pillar}</span>\n )}\n </div>\n </a>\n ))}\n </div>\n </section>\n )}\n </div>\n </>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/blog/ClusterLandingPage.tsx"],"names":[],"mappings":"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","file":"server-ui.mjs","sourcesContent":["/**\n * @sonordev/site-kit/blog - Cluster Landing Page Component\n *\n * Pre-built page component for `/blog/cluster/[slug]` routes.\n * Renders a topic cluster overview with:\n * - Cluster hero (name, topic, description)\n * - Pillar article (featured, large card)\n * - Support articles (grid, categorized by article_type or funnel_stage)\n *\n * Server component — fetches cluster data from Portal API.\n * Ships with `.sk-cluster-landing-*` scoped styles.\n */\n\nimport React from 'react'\nimport { getTopicCluster } from './server-core'\nimport type { TopicCluster, BlogPost } from './types'\n\n// ============================================================================\n// CSS\n// ============================================================================\n\nconst clusterLandingCss = `\n.sk-cluster-landing { max-width: 72rem; margin: 0 auto; padding: 2rem 1rem; }\n\n.sk-cluster-hero { margin-bottom: 3rem; text-align: center; }\n.sk-cluster-hero-label {\n display: inline-flex; align-items: center; gap: 0.375rem;\n font-size: 0.75rem; font-weight: 600; text-transform: uppercase;\n letter-spacing: 0.05em; color: #6366f1; margin-bottom: 0.75rem;\n}\n.sk-cluster-hero-title {\n font-size: 2.25rem; font-weight: 800; color: #111827;\n line-height: 1.2; margin: 0 0 0.75rem 0;\n}\n.sk-cluster-hero-desc {\n font-size: 1.125rem; color: #6b7280; max-width: 40rem;\n margin: 0 auto; line-height: 1.6;\n}\n.sk-cluster-hero-meta {\n display: flex; justify-content: center; gap: 1.5rem;\n margin-top: 1rem; font-size: 0.875rem; color: #9ca3af;\n}\n\n.sk-cluster-pillar-card {\n display: block; text-decoration: none; color: inherit;\n padding: 2rem; border-radius: 0.75rem;\n background: linear-gradient(135deg, rgba(99,102,241,0.04), rgba(99,102,241,0.01));\n border: 2px solid rgba(99,102,241,0.2);\n margin-bottom: 3rem; transition: border-color 0.2s, box-shadow 0.2s;\n}\n.sk-cluster-pillar-card:hover {\n border-color: rgba(99,102,241,0.4);\n box-shadow: 0 4px 24px rgba(99,102,241,0.08);\n}\n.sk-cluster-pillar-label {\n display: inline-flex; align-items: center; gap: 0.375rem;\n font-size: 0.6875rem; font-weight: 700; text-transform: uppercase;\n letter-spacing: 0.05em; color: #6366f1; margin-bottom: 0.75rem;\n padding: 0.25rem 0.5rem; border-radius: 9999px;\n background: rgba(99,102,241,0.08);\n}\n.sk-cluster-pillar-title {\n font-size: 1.5rem; font-weight: 700; color: #111827;\n margin: 0 0 0.5rem 0; line-height: 1.3;\n}\n.sk-cluster-pillar-excerpt {\n font-size: 1rem; color: #6b7280; line-height: 1.6;\n margin: 0 0 1rem 0;\n}\n.sk-cluster-pillar-meta {\n display: flex; gap: 1rem; font-size: 0.8125rem; color: #9ca3af;\n}\n\n.sk-cluster-supports-section { margin-bottom: 2rem; }\n.sk-cluster-supports-title {\n font-size: 1.25rem; font-weight: 700; color: #111827;\n margin: 0 0 1.25rem 0;\n}\n.sk-cluster-supports-grid {\n display: grid; gap: 1.25rem;\n grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));\n}\n.sk-cluster-support-card {\n display: block; text-decoration: none; color: inherit;\n padding: 1.25rem; border-radius: 0.5rem;\n border: 1px solid #e5e7eb; background: #fff;\n transition: border-color 0.2s, box-shadow 0.2s;\n}\n.sk-cluster-support-card:hover {\n border-color: #c7d2fe;\n box-shadow: 0 2px 12px rgba(0,0,0,0.04);\n}\n.sk-cluster-support-card-header {\n display: flex; align-items: center; gap: 0.5rem;\n margin-bottom: 0.5rem;\n}\n.sk-cluster-support-type {\n display: inline-flex; align-items: center;\n padding: 0.125rem 0.375rem; border-radius: 9999px;\n font-size: 0.6875rem; font-weight: 500;\n background: rgba(99,102,241,0.06); color: #6366f1;\n border: 1px solid rgba(99,102,241,0.12);\n text-transform: capitalize;\n}\n.sk-cluster-support-intent {\n font-size: 0.6875rem; color: #9ca3af;\n text-transform: capitalize;\n}\n.sk-cluster-support-title {\n font-size: 1rem; font-weight: 600; color: #111827;\n margin: 0 0 0.375rem 0; line-height: 1.4;\n}\n.sk-cluster-support-excerpt {\n font-size: 0.875rem; color: #6b7280; line-height: 1.5;\n margin: 0; display: -webkit-box; -webkit-line-clamp: 2;\n -webkit-box-orient: vertical; overflow: hidden;\n}\n.sk-cluster-support-meta {\n display: flex; gap: 0.75rem; margin-top: 0.75rem;\n font-size: 0.75rem; color: #9ca3af;\n}\n`\n\n// ============================================================================\n// COMPONENT\n// ============================================================================\n\nexport interface ClusterLandingPageProps {\n /** Cluster slug to fetch */\n slug: string\n /** Base path for blog URLs (default: /blog) */\n basePath?: string\n /**\n * Include each article's own category segment in its URL:\n * {basePath}/{category}/{slug}. Enable on sites whose blog routes are\n * category-segmented (e.g. upforge.io /insights/{category}/{slug}) —\n * without it, links point at {basePath}/{slug} and 404 on such sites.\n */\n categoryInPath?: boolean\n /** Disable default styles */\n unstyled?: boolean\n /** Custom class name */\n className?: string\n /** Render prop for full data access */\n children?: (props: { cluster: TopicCluster }) => React.ReactNode\n}\n\n/** Category slug of a post — handles both string and object category shapes. */\nfunction categorySlugOf(post: { category?: unknown } | null | undefined): string | null {\n const c = post?.category as { slug?: string } | string | undefined\n if (!c) return null\n if (typeof c === 'string') return c\n return c.slug || null\n}\n\nexport async function ClusterLandingPage({\n slug,\n basePath = '/blog',\n categoryInPath = false,\n unstyled = false,\n className,\n children,\n}: ClusterLandingPageProps) {\n const cluster = await getTopicCluster(slug)\n\n if (!cluster) {\n return (\n <div style={{ padding: '4rem 1rem', textAlign: 'center', color: '#6b7280' }}>\n <p>Topic cluster not found.</p>\n </div>\n )\n }\n\n // Custom render\n if (children) {\n return children({ cluster })\n }\n\n const pillar = cluster.pillar\n const supports = cluster.supports || []\n\n const articleUrl = (post: { slug: string; category?: unknown }) => {\n const cat = categoryInPath ? categorySlugOf(post) : null\n return cat ? `${basePath}/${cat}/${post.slug}` : `${basePath}/${post.slug}`\n }\n\n return (\n <>\n {!unstyled && <style dangerouslySetInnerHTML={{ __html: clusterLandingCss }} />}\n\n <div className={`${unstyled ? '' : 'sk-cluster-landing'} ${className || ''}`}>\n {/* Hero */}\n <header className={unstyled ? '' : 'sk-cluster-hero'}>\n <p className={unstyled ? '' : 'sk-cluster-hero-label'}>\n Topic Cluster\n </p>\n <h1 className={unstyled ? '' : 'sk-cluster-hero-title'}>\n {cluster.cluster_name}\n </h1>\n <p className={unstyled ? '' : 'sk-cluster-hero-desc'}>\n {cluster.core_topic}\n {cluster.geo_target ? ` in ${cluster.geo_target}` : ''}\n </p>\n <div className={unstyled ? '' : 'sk-cluster-hero-meta'}>\n <span>{cluster.article_count} articles</span>\n {cluster.geo_target && <span>{cluster.geo_target}</span>}\n </div>\n </header>\n\n {/* Pillar article (hero card) */}\n {pillar && (\n <a href={articleUrl(pillar)} className={unstyled ? '' : 'sk-cluster-pillar-card'}>\n <span className={unstyled ? '' : 'sk-cluster-pillar-label'}>\n Pillar Guide\n </span>\n <h2 className={unstyled ? '' : 'sk-cluster-pillar-title'}>\n {pillar.title}\n </h2>\n {pillar.excerpt && (\n <p className={unstyled ? '' : 'sk-cluster-pillar-excerpt'}>\n {pillar.excerpt}\n </p>\n )}\n <div className={unstyled ? '' : 'sk-cluster-pillar-meta'}>\n {(pillar.reading_time_minutes ?? pillar.reading_time) && (\n <span>{pillar.reading_time_minutes ?? pillar.reading_time} min read</span>\n )}\n {pillar.word_count && (\n <span>{pillar.word_count.toLocaleString()} words</span>\n )}\n </div>\n </a>\n )}\n\n {/* Support articles */}\n {supports.length > 0 && (\n <section className={unstyled ? '' : 'sk-cluster-supports-section'}>\n <h2 className={unstyled ? '' : 'sk-cluster-supports-title'}>\n Deep Dives\n </h2>\n <div className={unstyled ? '' : 'sk-cluster-supports-grid'}>\n {supports.map((post) => (\n <a\n key={post.id || post.slug}\n href={articleUrl(post)}\n className={unstyled ? '' : 'sk-cluster-support-card'}\n >\n <div className={unstyled ? '' : 'sk-cluster-support-card-header'}>\n {post.article_type && (\n <span className={unstyled ? '' : 'sk-cluster-support-type'}>\n {post.article_type}\n </span>\n )}\n {post.search_intent && (\n <span className={unstyled ? '' : 'sk-cluster-support-intent'}>\n {post.search_intent}\n </span>\n )}\n </div>\n <h3 className={unstyled ? '' : 'sk-cluster-support-title'}>\n {post.title}\n </h3>\n {post.excerpt && (\n <p className={unstyled ? '' : 'sk-cluster-support-excerpt'}>\n {post.excerpt}\n </p>\n )}\n <div className={unstyled ? '' : 'sk-cluster-support-meta'}>\n {(post.reading_time_minutes ?? post.reading_time) && (\n <span>{post.reading_time_minutes ?? post.reading_time} min read</span>\n )}\n {post.relationship_to_pillar && (\n <span>{post.relationship_to_pillar}</span>\n )}\n </div>\n </a>\n ))}\n </div>\n </section>\n )}\n </div>\n </>\n )\n}\n"]}
|
package/dist/blog/server.d.mts
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
import { Metadata } from 'next';
|
|
2
2
|
import { B as BlogAuthor, a as BlogPost, T as TopicCluster, C as ClusterNavigation } from '../types-8IcjVMDa.mjs';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Excerpt sanitizing for blog metadata, schema and feeds.
|
|
6
|
+
*
|
|
7
|
+
* Pure (no `server-only` chain) so it is unit-testable and safe to reuse.
|
|
8
|
+
* Source of truth for turning a stored excerpt into display-safe prose.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Turn a stored excerpt into something safe to put in a meta description,
|
|
12
|
+
* a schema `description`, or an RSS `<description>`.
|
|
13
|
+
*
|
|
14
|
+
* The AI blog pipeline stores content as JSON sections
|
|
15
|
+
* (`{"heading": "## ...", "content": "## ...\n\nIf you're asking **how**..."}`)
|
|
16
|
+
* and that value has been shipping verbatim into <meta name="description">.
|
|
17
|
+
* nkylawfirm.com had three live articles whose SERP snippet was raw JSON with
|
|
18
|
+
* markdown asterisks and literal \n. Parse the sections out, strip markdown,
|
|
19
|
+
* and cap at a sentence boundary.
|
|
20
|
+
*/
|
|
21
|
+
declare function sanitizeExcerpt(raw: string | undefined | null, maxLength?: number): string;
|
|
22
|
+
|
|
4
23
|
/**
|
|
5
24
|
* @sonordev/site-kit/blog — Author JSON-LD (pure)
|
|
6
25
|
*
|
|
@@ -359,4 +378,4 @@ declare function generateAuthorPageMetadata(author: BlogAuthor, options?: {
|
|
|
359
378
|
siteName?: string;
|
|
360
379
|
}): Metadata;
|
|
361
380
|
|
|
362
|
-
export { BlogPost as BlogPostRecord, type HowToStep, SEO_LIMITS, type SeoValidationResult, generateAllBlogSchemas, generateAtomFeed, generateAuthorPageMetadata, generateAuthorSchema, generateAuthorStaticParams, generateBlogCategoryMetadata, generateBlogIndexMetadata, generateBlogListSchema, generateBlogPostMetadata, generateBlogPostSchema, generateBlogSitemap, generateBlogStaticParams, generateBreadcrumbSchema, generateCategoryStaticParams, generateClusterArticleSchema, generateClusterBreadcrumbSchema, generateClusterItemListSchema, generateClusterLandingSchema, generateClusterPageMetadata, generateFaqSchema, generateHowToSchema, generateRssFeed, getAllAuthorSlugs, getAllBlogPosts, getAllBlogSlugs, getAuthorBySlug, getAuthorPosts, getBlogCategories, getBlogPost, getClusterNavigation, getPostsByCategory, getRelatedInsights, getTopicCluster, getTopicClusters, identifyTopicClusters, validateBlogPostSeo, validateMetaDescription, validateSeoTitle };
|
|
381
|
+
export { BlogPost as BlogPostRecord, type HowToStep, SEO_LIMITS, type SeoValidationResult, generateAllBlogSchemas, generateAtomFeed, generateAuthorPageMetadata, generateAuthorSchema, generateAuthorStaticParams, generateBlogCategoryMetadata, generateBlogIndexMetadata, generateBlogListSchema, generateBlogPostMetadata, generateBlogPostSchema, generateBlogSitemap, generateBlogStaticParams, generateBreadcrumbSchema, generateCategoryStaticParams, generateClusterArticleSchema, generateClusterBreadcrumbSchema, generateClusterItemListSchema, generateClusterLandingSchema, generateClusterPageMetadata, generateFaqSchema, generateHowToSchema, generateRssFeed, getAllAuthorSlugs, getAllBlogPosts, getAllBlogSlugs, getAuthorBySlug, getAuthorPosts, getBlogCategories, getBlogPost, getClusterNavigation, getPostsByCategory, getRelatedInsights, getTopicCluster, getTopicClusters, identifyTopicClusters, sanitizeExcerpt, validateBlogPostSeo, validateMetaDescription, validateSeoTitle };
|
package/dist/blog/server.d.ts
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
import { Metadata } from 'next';
|
|
2
2
|
import { B as BlogAuthor, a as BlogPost, T as TopicCluster, C as ClusterNavigation } from '../types-8IcjVMDa.js';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Excerpt sanitizing for blog metadata, schema and feeds.
|
|
6
|
+
*
|
|
7
|
+
* Pure (no `server-only` chain) so it is unit-testable and safe to reuse.
|
|
8
|
+
* Source of truth for turning a stored excerpt into display-safe prose.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Turn a stored excerpt into something safe to put in a meta description,
|
|
12
|
+
* a schema `description`, or an RSS `<description>`.
|
|
13
|
+
*
|
|
14
|
+
* The AI blog pipeline stores content as JSON sections
|
|
15
|
+
* (`{"heading": "## ...", "content": "## ...\n\nIf you're asking **how**..."}`)
|
|
16
|
+
* and that value has been shipping verbatim into <meta name="description">.
|
|
17
|
+
* nkylawfirm.com had three live articles whose SERP snippet was raw JSON with
|
|
18
|
+
* markdown asterisks and literal \n. Parse the sections out, strip markdown,
|
|
19
|
+
* and cap at a sentence boundary.
|
|
20
|
+
*/
|
|
21
|
+
declare function sanitizeExcerpt(raw: string | undefined | null, maxLength?: number): string;
|
|
22
|
+
|
|
4
23
|
/**
|
|
5
24
|
* @sonordev/site-kit/blog — Author JSON-LD (pure)
|
|
6
25
|
*
|
|
@@ -359,4 +378,4 @@ declare function generateAuthorPageMetadata(author: BlogAuthor, options?: {
|
|
|
359
378
|
siteName?: string;
|
|
360
379
|
}): Metadata;
|
|
361
380
|
|
|
362
|
-
export { BlogPost as BlogPostRecord, type HowToStep, SEO_LIMITS, type SeoValidationResult, generateAllBlogSchemas, generateAtomFeed, generateAuthorPageMetadata, generateAuthorSchema, generateAuthorStaticParams, generateBlogCategoryMetadata, generateBlogIndexMetadata, generateBlogListSchema, generateBlogPostMetadata, generateBlogPostSchema, generateBlogSitemap, generateBlogStaticParams, generateBreadcrumbSchema, generateCategoryStaticParams, generateClusterArticleSchema, generateClusterBreadcrumbSchema, generateClusterItemListSchema, generateClusterLandingSchema, generateClusterPageMetadata, generateFaqSchema, generateHowToSchema, generateRssFeed, getAllAuthorSlugs, getAllBlogPosts, getAllBlogSlugs, getAuthorBySlug, getAuthorPosts, getBlogCategories, getBlogPost, getClusterNavigation, getPostsByCategory, getRelatedInsights, getTopicCluster, getTopicClusters, identifyTopicClusters, validateBlogPostSeo, validateMetaDescription, validateSeoTitle };
|
|
381
|
+
export { BlogPost as BlogPostRecord, type HowToStep, SEO_LIMITS, type SeoValidationResult, generateAllBlogSchemas, generateAtomFeed, generateAuthorPageMetadata, generateAuthorSchema, generateAuthorStaticParams, generateBlogCategoryMetadata, generateBlogIndexMetadata, generateBlogListSchema, generateBlogPostMetadata, generateBlogPostSchema, generateBlogSitemap, generateBlogStaticParams, generateBreadcrumbSchema, generateCategoryStaticParams, generateClusterArticleSchema, generateClusterBreadcrumbSchema, generateClusterItemListSchema, generateClusterLandingSchema, generateClusterPageMetadata, generateFaqSchema, generateHowToSchema, generateRssFeed, getAllAuthorSlugs, getAllBlogPosts, getAllBlogSlugs, getAuthorBySlug, getAuthorPosts, getBlogCategories, getBlogPost, getClusterNavigation, getPostsByCategory, getRelatedInsights, getTopicCluster, getTopicClusters, identifyTopicClusters, sanitizeExcerpt, validateBlogPostSeo, validateMetaDescription, validateSeoTitle };
|
package/dist/blog/server.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkTMKLH6MY_js = require('../chunk-TMKLH6MY.js');
|
|
4
4
|
var chunkTPL2IHFI_js = require('../chunk-TPL2IHFI.js');
|
|
5
5
|
require('../chunk-QPIKPWAZ.js');
|
|
6
6
|
require('../chunk-ZSMWDLMK.js');
|
|
@@ -9,155 +9,159 @@ require('../chunk-ZSMWDLMK.js');
|
|
|
9
9
|
|
|
10
10
|
Object.defineProperty(exports, "SEO_LIMITS", {
|
|
11
11
|
enumerable: true,
|
|
12
|
-
get: function () { return
|
|
12
|
+
get: function () { return chunkTMKLH6MY_js.SEO_LIMITS; }
|
|
13
13
|
});
|
|
14
14
|
Object.defineProperty(exports, "generateAllBlogSchemas", {
|
|
15
15
|
enumerable: true,
|
|
16
|
-
get: function () { return
|
|
16
|
+
get: function () { return chunkTMKLH6MY_js.generateAllBlogSchemas; }
|
|
17
17
|
});
|
|
18
18
|
Object.defineProperty(exports, "generateAtomFeed", {
|
|
19
19
|
enumerable: true,
|
|
20
|
-
get: function () { return
|
|
20
|
+
get: function () { return chunkTMKLH6MY_js.generateAtomFeed; }
|
|
21
21
|
});
|
|
22
22
|
Object.defineProperty(exports, "generateAuthorPageMetadata", {
|
|
23
23
|
enumerable: true,
|
|
24
|
-
get: function () { return
|
|
24
|
+
get: function () { return chunkTMKLH6MY_js.generateAuthorPageMetadata; }
|
|
25
25
|
});
|
|
26
26
|
Object.defineProperty(exports, "generateAuthorStaticParams", {
|
|
27
27
|
enumerable: true,
|
|
28
|
-
get: function () { return
|
|
28
|
+
get: function () { return chunkTMKLH6MY_js.generateAuthorStaticParams; }
|
|
29
29
|
});
|
|
30
30
|
Object.defineProperty(exports, "generateBlogCategoryMetadata", {
|
|
31
31
|
enumerable: true,
|
|
32
|
-
get: function () { return
|
|
32
|
+
get: function () { return chunkTMKLH6MY_js.generateBlogCategoryMetadata; }
|
|
33
33
|
});
|
|
34
34
|
Object.defineProperty(exports, "generateBlogIndexMetadata", {
|
|
35
35
|
enumerable: true,
|
|
36
|
-
get: function () { return
|
|
36
|
+
get: function () { return chunkTMKLH6MY_js.generateBlogIndexMetadata; }
|
|
37
37
|
});
|
|
38
38
|
Object.defineProperty(exports, "generateBlogListSchema", {
|
|
39
39
|
enumerable: true,
|
|
40
|
-
get: function () { return
|
|
40
|
+
get: function () { return chunkTMKLH6MY_js.generateBlogListSchema; }
|
|
41
41
|
});
|
|
42
42
|
Object.defineProperty(exports, "generateBlogPostMetadata", {
|
|
43
43
|
enumerable: true,
|
|
44
|
-
get: function () { return
|
|
44
|
+
get: function () { return chunkTMKLH6MY_js.generateBlogPostMetadata; }
|
|
45
45
|
});
|
|
46
46
|
Object.defineProperty(exports, "generateBlogPostSchema", {
|
|
47
47
|
enumerable: true,
|
|
48
|
-
get: function () { return
|
|
48
|
+
get: function () { return chunkTMKLH6MY_js.generateBlogPostSchema; }
|
|
49
49
|
});
|
|
50
50
|
Object.defineProperty(exports, "generateBlogSitemap", {
|
|
51
51
|
enumerable: true,
|
|
52
|
-
get: function () { return
|
|
52
|
+
get: function () { return chunkTMKLH6MY_js.generateBlogSitemap; }
|
|
53
53
|
});
|
|
54
54
|
Object.defineProperty(exports, "generateBlogStaticParams", {
|
|
55
55
|
enumerable: true,
|
|
56
|
-
get: function () { return
|
|
56
|
+
get: function () { return chunkTMKLH6MY_js.generateBlogStaticParams; }
|
|
57
57
|
});
|
|
58
58
|
Object.defineProperty(exports, "generateBreadcrumbSchema", {
|
|
59
59
|
enumerable: true,
|
|
60
|
-
get: function () { return
|
|
60
|
+
get: function () { return chunkTMKLH6MY_js.generateBreadcrumbSchema; }
|
|
61
61
|
});
|
|
62
62
|
Object.defineProperty(exports, "generateCategoryStaticParams", {
|
|
63
63
|
enumerable: true,
|
|
64
|
-
get: function () { return
|
|
64
|
+
get: function () { return chunkTMKLH6MY_js.generateCategoryStaticParams; }
|
|
65
65
|
});
|
|
66
66
|
Object.defineProperty(exports, "generateClusterArticleSchema", {
|
|
67
67
|
enumerable: true,
|
|
68
|
-
get: function () { return
|
|
68
|
+
get: function () { return chunkTMKLH6MY_js.generateClusterArticleSchema; }
|
|
69
69
|
});
|
|
70
70
|
Object.defineProperty(exports, "generateClusterBreadcrumbSchema", {
|
|
71
71
|
enumerable: true,
|
|
72
|
-
get: function () { return
|
|
72
|
+
get: function () { return chunkTMKLH6MY_js.generateClusterBreadcrumbSchema; }
|
|
73
73
|
});
|
|
74
74
|
Object.defineProperty(exports, "generateClusterItemListSchema", {
|
|
75
75
|
enumerable: true,
|
|
76
|
-
get: function () { return
|
|
76
|
+
get: function () { return chunkTMKLH6MY_js.generateClusterItemListSchema; }
|
|
77
77
|
});
|
|
78
78
|
Object.defineProperty(exports, "generateClusterLandingSchema", {
|
|
79
79
|
enumerable: true,
|
|
80
|
-
get: function () { return
|
|
80
|
+
get: function () { return chunkTMKLH6MY_js.generateClusterLandingSchema; }
|
|
81
81
|
});
|
|
82
82
|
Object.defineProperty(exports, "generateClusterPageMetadata", {
|
|
83
83
|
enumerable: true,
|
|
84
|
-
get: function () { return
|
|
84
|
+
get: function () { return chunkTMKLH6MY_js.generateClusterPageMetadata; }
|
|
85
85
|
});
|
|
86
86
|
Object.defineProperty(exports, "generateFaqSchema", {
|
|
87
87
|
enumerable: true,
|
|
88
|
-
get: function () { return
|
|
88
|
+
get: function () { return chunkTMKLH6MY_js.generateFaqSchema; }
|
|
89
89
|
});
|
|
90
90
|
Object.defineProperty(exports, "generateHowToSchema", {
|
|
91
91
|
enumerable: true,
|
|
92
|
-
get: function () { return
|
|
92
|
+
get: function () { return chunkTMKLH6MY_js.generateHowToSchema; }
|
|
93
93
|
});
|
|
94
94
|
Object.defineProperty(exports, "generateRssFeed", {
|
|
95
95
|
enumerable: true,
|
|
96
|
-
get: function () { return
|
|
96
|
+
get: function () { return chunkTMKLH6MY_js.generateRssFeed; }
|
|
97
97
|
});
|
|
98
98
|
Object.defineProperty(exports, "getAllAuthorSlugs", {
|
|
99
99
|
enumerable: true,
|
|
100
|
-
get: function () { return
|
|
100
|
+
get: function () { return chunkTMKLH6MY_js.getAllAuthorSlugs; }
|
|
101
101
|
});
|
|
102
102
|
Object.defineProperty(exports, "getAllBlogPosts", {
|
|
103
103
|
enumerable: true,
|
|
104
|
-
get: function () { return
|
|
104
|
+
get: function () { return chunkTMKLH6MY_js.getAllBlogPosts; }
|
|
105
105
|
});
|
|
106
106
|
Object.defineProperty(exports, "getAllBlogSlugs", {
|
|
107
107
|
enumerable: true,
|
|
108
|
-
get: function () { return
|
|
108
|
+
get: function () { return chunkTMKLH6MY_js.getAllBlogSlugs; }
|
|
109
109
|
});
|
|
110
110
|
Object.defineProperty(exports, "getAuthorBySlug", {
|
|
111
111
|
enumerable: true,
|
|
112
|
-
get: function () { return
|
|
112
|
+
get: function () { return chunkTMKLH6MY_js.getAuthorBySlug; }
|
|
113
113
|
});
|
|
114
114
|
Object.defineProperty(exports, "getAuthorPosts", {
|
|
115
115
|
enumerable: true,
|
|
116
|
-
get: function () { return
|
|
116
|
+
get: function () { return chunkTMKLH6MY_js.getAuthorPosts; }
|
|
117
117
|
});
|
|
118
118
|
Object.defineProperty(exports, "getBlogCategories", {
|
|
119
119
|
enumerable: true,
|
|
120
|
-
get: function () { return
|
|
120
|
+
get: function () { return chunkTMKLH6MY_js.getBlogCategories; }
|
|
121
121
|
});
|
|
122
122
|
Object.defineProperty(exports, "getBlogPost", {
|
|
123
123
|
enumerable: true,
|
|
124
|
-
get: function () { return
|
|
124
|
+
get: function () { return chunkTMKLH6MY_js.getBlogPost; }
|
|
125
125
|
});
|
|
126
126
|
Object.defineProperty(exports, "getClusterNavigation", {
|
|
127
127
|
enumerable: true,
|
|
128
|
-
get: function () { return
|
|
128
|
+
get: function () { return chunkTMKLH6MY_js.getClusterNavigation; }
|
|
129
129
|
});
|
|
130
130
|
Object.defineProperty(exports, "getPostsByCategory", {
|
|
131
131
|
enumerable: true,
|
|
132
|
-
get: function () { return
|
|
132
|
+
get: function () { return chunkTMKLH6MY_js.getPostsByCategory; }
|
|
133
133
|
});
|
|
134
134
|
Object.defineProperty(exports, "getRelatedInsights", {
|
|
135
135
|
enumerable: true,
|
|
136
|
-
get: function () { return
|
|
136
|
+
get: function () { return chunkTMKLH6MY_js.getRelatedInsights; }
|
|
137
137
|
});
|
|
138
138
|
Object.defineProperty(exports, "getTopicCluster", {
|
|
139
139
|
enumerable: true,
|
|
140
|
-
get: function () { return
|
|
140
|
+
get: function () { return chunkTMKLH6MY_js.getTopicCluster; }
|
|
141
141
|
});
|
|
142
142
|
Object.defineProperty(exports, "getTopicClusters", {
|
|
143
143
|
enumerable: true,
|
|
144
|
-
get: function () { return
|
|
144
|
+
get: function () { return chunkTMKLH6MY_js.getTopicClusters; }
|
|
145
145
|
});
|
|
146
146
|
Object.defineProperty(exports, "identifyTopicClusters", {
|
|
147
147
|
enumerable: true,
|
|
148
|
-
get: function () { return
|
|
148
|
+
get: function () { return chunkTMKLH6MY_js.identifyTopicClusters; }
|
|
149
|
+
});
|
|
150
|
+
Object.defineProperty(exports, "sanitizeExcerpt", {
|
|
151
|
+
enumerable: true,
|
|
152
|
+
get: function () { return chunkTMKLH6MY_js.sanitizeExcerpt; }
|
|
149
153
|
});
|
|
150
154
|
Object.defineProperty(exports, "validateBlogPostSeo", {
|
|
151
155
|
enumerable: true,
|
|
152
|
-
get: function () { return
|
|
156
|
+
get: function () { return chunkTMKLH6MY_js.validateBlogPostSeo; }
|
|
153
157
|
});
|
|
154
158
|
Object.defineProperty(exports, "validateMetaDescription", {
|
|
155
159
|
enumerable: true,
|
|
156
|
-
get: function () { return
|
|
160
|
+
get: function () { return chunkTMKLH6MY_js.validateMetaDescription; }
|
|
157
161
|
});
|
|
158
162
|
Object.defineProperty(exports, "validateSeoTitle", {
|
|
159
163
|
enumerable: true,
|
|
160
|
-
get: function () { return
|
|
164
|
+
get: function () { return chunkTMKLH6MY_js.validateSeoTitle; }
|
|
161
165
|
});
|
|
162
166
|
Object.defineProperty(exports, "generateAuthorSchema", {
|
|
163
167
|
enumerable: true,
|
package/dist/blog/server.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { SEO_LIMITS, generateAllBlogSchemas, generateAtomFeed, generateAuthorPageMetadata, generateAuthorStaticParams, generateBlogCategoryMetadata, generateBlogIndexMetadata, generateBlogListSchema, generateBlogPostMetadata, generateBlogPostSchema, generateBlogSitemap, generateBlogStaticParams, generateBreadcrumbSchema, generateCategoryStaticParams, generateClusterArticleSchema, generateClusterBreadcrumbSchema, generateClusterItemListSchema, generateClusterLandingSchema, generateClusterPageMetadata, generateFaqSchema, generateHowToSchema, generateRssFeed, getAllAuthorSlugs, getAllBlogPosts, getAllBlogSlugs, getAuthorBySlug, getAuthorPosts, getBlogCategories, getBlogPost, getClusterNavigation, getPostsByCategory, getRelatedInsights, getTopicCluster, getTopicClusters, identifyTopicClusters, validateBlogPostSeo, validateMetaDescription, validateSeoTitle } from '../chunk-
|
|
1
|
+
export { SEO_LIMITS, generateAllBlogSchemas, generateAtomFeed, generateAuthorPageMetadata, generateAuthorStaticParams, generateBlogCategoryMetadata, generateBlogIndexMetadata, generateBlogListSchema, generateBlogPostMetadata, generateBlogPostSchema, generateBlogSitemap, generateBlogStaticParams, generateBreadcrumbSchema, generateCategoryStaticParams, generateClusterArticleSchema, generateClusterBreadcrumbSchema, generateClusterItemListSchema, generateClusterLandingSchema, generateClusterPageMetadata, generateFaqSchema, generateHowToSchema, generateRssFeed, getAllAuthorSlugs, getAllBlogPosts, getAllBlogSlugs, getAuthorBySlug, getAuthorPosts, getBlogCategories, getBlogPost, getClusterNavigation, getPostsByCategory, getRelatedInsights, getTopicCluster, getTopicClusters, identifyTopicClusters, sanitizeExcerpt, validateBlogPostSeo, validateMetaDescription, validateSeoTitle } from '../chunk-PA7ENTUZ.mjs';
|
|
2
2
|
export { generateAuthorSchema } from '../chunk-CGCYZJYX.mjs';
|
|
3
3
|
import '../chunk-UDBUK5ZJ.mjs';
|
|
4
4
|
import '../chunk-4XPGGLVP.mjs';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { sonorFetch } from './chunk-
|
|
2
|
+
import { sonorFetch } from './chunk-RSFSXEV2.mjs';
|
|
3
3
|
import { useState, useCallback, useEffect } from 'react';
|
|
4
4
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
5
5
|
|
|
@@ -521,5 +521,5 @@ async function clearImageSlot(config, slotId, pagePath) {
|
|
|
521
521
|
}
|
|
522
522
|
|
|
523
523
|
export { ManagedImage, assignImageToSlot, clearImageSlot, fetchManagedImage, fetchManagedImages, listImageFiles, uploadImage };
|
|
524
|
-
//# sourceMappingURL=chunk-
|
|
525
|
-
//# sourceMappingURL=chunk-
|
|
524
|
+
//# sourceMappingURL=chunk-2LQGFCEA.mjs.map
|
|
525
|
+
//# sourceMappingURL=chunk-2LQGFCEA.mjs.map
|