@sonordev/site-kit 1.2.7

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.
Files changed (300) hide show
  1. package/README.md +376 -0
  2. package/dist/SetupWizard-Cki06kB0.d.mts +12 -0
  3. package/dist/SetupWizard-Cki06kB0.d.ts +12 -0
  4. package/dist/analytics/index.d.mts +93 -0
  5. package/dist/analytics/index.d.ts +93 -0
  6. package/dist/analytics/index.js +89 -0
  7. package/dist/analytics/index.js.map +1 -0
  8. package/dist/analytics/index.mjs +71 -0
  9. package/dist/analytics/index.mjs.map +1 -0
  10. package/dist/api-CWtoFJCO.d.mts +137 -0
  11. package/dist/api-CWtoFJCO.d.ts +137 -0
  12. package/dist/blog/index.d.mts +305 -0
  13. package/dist/blog/index.d.ts +305 -0
  14. package/dist/blog/index.js +1578 -0
  15. package/dist/blog/index.js.map +1 -0
  16. package/dist/blog/index.mjs +1562 -0
  17. package/dist/blog/index.mjs.map +1 -0
  18. package/dist/blog/server.d.mts +229 -0
  19. package/dist/blog/server.d.ts +229 -0
  20. package/dist/blog/server.js +692 -0
  21. package/dist/blog/server.js.map +1 -0
  22. package/dist/blog/server.mjs +666 -0
  23. package/dist/blog/server.mjs.map +1 -0
  24. package/dist/chunk-24277A3Q.mjs +968 -0
  25. package/dist/chunk-24277A3Q.mjs.map +1 -0
  26. package/dist/chunk-373TK6TZ.js +321 -0
  27. package/dist/chunk-373TK6TZ.js.map +1 -0
  28. package/dist/chunk-3MYZS6PD.js +30 -0
  29. package/dist/chunk-3MYZS6PD.js.map +1 -0
  30. package/dist/chunk-43GBM4SX.js +283 -0
  31. package/dist/chunk-43GBM4SX.js.map +1 -0
  32. package/dist/chunk-4XPGGLVP.mjs +53 -0
  33. package/dist/chunk-4XPGGLVP.mjs.map +1 -0
  34. package/dist/chunk-622GAQP5.js +2008 -0
  35. package/dist/chunk-622GAQP5.js.map +1 -0
  36. package/dist/chunk-6BIPAKL4.mjs +28 -0
  37. package/dist/chunk-6BIPAKL4.mjs.map +1 -0
  38. package/dist/chunk-6ZCISNAB.mjs +343 -0
  39. package/dist/chunk-6ZCISNAB.mjs.map +1 -0
  40. package/dist/chunk-72MQFHYJ.js +1429 -0
  41. package/dist/chunk-72MQFHYJ.js.map +1 -0
  42. package/dist/chunk-7557OTHW.js +62 -0
  43. package/dist/chunk-7557OTHW.js.map +1 -0
  44. package/dist/chunk-7FUV73JZ.js +981 -0
  45. package/dist/chunk-7FUV73JZ.js.map +1 -0
  46. package/dist/chunk-7RF6PVHA.mjs +324 -0
  47. package/dist/chunk-7RF6PVHA.mjs.map +1 -0
  48. package/dist/chunk-7RYCHO6D.mjs +134 -0
  49. package/dist/chunk-7RYCHO6D.mjs.map +1 -0
  50. package/dist/chunk-7UKPRW25.mjs +1999 -0
  51. package/dist/chunk-7UKPRW25.mjs.map +1 -0
  52. package/dist/chunk-7URAOG2M.js +14864 -0
  53. package/dist/chunk-7URAOG2M.js.map +1 -0
  54. package/dist/chunk-AFAO3TGS.mjs +810 -0
  55. package/dist/chunk-AFAO3TGS.mjs.map +1 -0
  56. package/dist/chunk-BYLIU6XG.js +343 -0
  57. package/dist/chunk-BYLIU6XG.js.map +1 -0
  58. package/dist/chunk-D63MUKZ6.mjs +4423 -0
  59. package/dist/chunk-D63MUKZ6.mjs.map +1 -0
  60. package/dist/chunk-DDKW2FNA.js +390 -0
  61. package/dist/chunk-DDKW2FNA.js.map +1 -0
  62. package/dist/chunk-DQYMKR27.mjs +341 -0
  63. package/dist/chunk-DQYMKR27.mjs.map +1 -0
  64. package/dist/chunk-DW5UJKHH.js +221 -0
  65. package/dist/chunk-DW5UJKHH.js.map +1 -0
  66. package/dist/chunk-EEZCR6E6.js +50 -0
  67. package/dist/chunk-EEZCR6E6.js.map +1 -0
  68. package/dist/chunk-GCJXQ4AG.mjs +59 -0
  69. package/dist/chunk-GCJXQ4AG.mjs.map +1 -0
  70. package/dist/chunk-JGNQK2G6.mjs +14845 -0
  71. package/dist/chunk-JGNQK2G6.mjs.map +1 -0
  72. package/dist/chunk-JTLOJLWQ.mjs +563 -0
  73. package/dist/chunk-JTLOJLWQ.mjs.map +1 -0
  74. package/dist/chunk-K23A4G76.mjs +202 -0
  75. package/dist/chunk-K23A4G76.mjs.map +1 -0
  76. package/dist/chunk-KKU3K7RG.js +336 -0
  77. package/dist/chunk-KKU3K7RG.js.map +1 -0
  78. package/dist/chunk-KUGMH4ZF.js +571 -0
  79. package/dist/chunk-KUGMH4ZF.js.map +1 -0
  80. package/dist/chunk-LBVWVP72.js +110 -0
  81. package/dist/chunk-LBVWVP72.js.map +1 -0
  82. package/dist/chunk-LIVWLY2P.js +138 -0
  83. package/dist/chunk-LIVWLY2P.js.map +1 -0
  84. package/dist/chunk-M2T6R7BA.mjs +1003 -0
  85. package/dist/chunk-M2T6R7BA.mjs.map +1 -0
  86. package/dist/chunk-MV3QN7PW.mjs +47 -0
  87. package/dist/chunk-MV3QN7PW.mjs.map +1 -0
  88. package/dist/chunk-OB7E654K.js +72 -0
  89. package/dist/chunk-OB7E654K.js.map +1 -0
  90. package/dist/chunk-OIIKTGRL.mjs +380 -0
  91. package/dist/chunk-OIIKTGRL.mjs.map +1 -0
  92. package/dist/chunk-P3UWIUJS.mjs +1427 -0
  93. package/dist/chunk-P3UWIUJS.mjs.map +1 -0
  94. package/dist/chunk-PKN27UMH.mjs +136 -0
  95. package/dist/chunk-PKN27UMH.mjs.map +1 -0
  96. package/dist/chunk-QXV4667R.mjs +105 -0
  97. package/dist/chunk-QXV4667R.mjs.map +1 -0
  98. package/dist/chunk-S7FRYNSU.mjs +315 -0
  99. package/dist/chunk-S7FRYNSU.mjs.map +1 -0
  100. package/dist/chunk-TFLQX7K7.mjs +68 -0
  101. package/dist/chunk-TFLQX7K7.mjs.map +1 -0
  102. package/dist/chunk-UWE5PCYJ.mjs +279 -0
  103. package/dist/chunk-UWE5PCYJ.mjs.map +1 -0
  104. package/dist/chunk-UYFDNX2F.js +4469 -0
  105. package/dist/chunk-UYFDNX2F.js.map +1 -0
  106. package/dist/chunk-W4PALSGM.js +350 -0
  107. package/dist/chunk-W4PALSGM.js.map +1 -0
  108. package/dist/chunk-WECQ6KOB.js +1008 -0
  109. package/dist/chunk-WECQ6KOB.js.map +1 -0
  110. package/dist/chunk-XQQWI6WB.js +814 -0
  111. package/dist/chunk-XQQWI6WB.js.map +1 -0
  112. package/dist/chunk-XZJOZJB6.js +140 -0
  113. package/dist/chunk-XZJOZJB6.js.map +1 -0
  114. package/dist/chunk-ZSMWDLMK.js +63 -0
  115. package/dist/chunk-ZSMWDLMK.js.map +1 -0
  116. package/dist/cli/index.js +37243 -0
  117. package/dist/cli/index.js.map +1 -0
  118. package/dist/cli/index.mjs +37209 -0
  119. package/dist/cli/index.mjs.map +1 -0
  120. package/dist/commerce/index.d.mts +170 -0
  121. package/dist/commerce/index.d.ts +170 -0
  122. package/dist/commerce/index.js +174 -0
  123. package/dist/commerce/index.js.map +1 -0
  124. package/dist/commerce/index.mjs +5 -0
  125. package/dist/commerce/index.mjs.map +1 -0
  126. package/dist/commerce/server.d.mts +107 -0
  127. package/dist/commerce/server.d.ts +107 -0
  128. package/dist/commerce/server.js +187 -0
  129. package/dist/commerce/server.js.map +1 -0
  130. package/dist/commerce/server.mjs +177 -0
  131. package/dist/commerce/server.mjs.map +1 -0
  132. package/dist/config/index.d.mts +43 -0
  133. package/dist/config/index.d.ts +43 -0
  134. package/dist/config/index.js +66 -0
  135. package/dist/config/index.js.map +1 -0
  136. package/dist/config/index.mjs +64 -0
  137. package/dist/config/index.mjs.map +1 -0
  138. package/dist/engage/index.d.mts +33 -0
  139. package/dist/engage/index.d.ts +33 -0
  140. package/dist/engage/index.js +22 -0
  141. package/dist/engage/index.js.map +1 -0
  142. package/dist/engage/index.mjs +5 -0
  143. package/dist/engage/index.mjs.map +1 -0
  144. package/dist/forms/index.d.mts +437 -0
  145. package/dist/forms/index.d.ts +437 -0
  146. package/dist/forms/index.js +1168 -0
  147. package/dist/forms/index.js.map +1 -0
  148. package/dist/forms/index.mjs +1142 -0
  149. package/dist/forms/index.mjs.map +1 -0
  150. package/dist/generators-2XKQMPKH.mjs +4 -0
  151. package/dist/generators-2XKQMPKH.mjs.map +1 -0
  152. package/dist/generators-DTMO36DV.js +33 -0
  153. package/dist/generators-DTMO36DV.js.map +1 -0
  154. package/dist/images/index.d.mts +4 -0
  155. package/dist/images/index.d.ts +4 -0
  156. package/dist/images/index.js +46 -0
  157. package/dist/images/index.js.map +1 -0
  158. package/dist/images/index.mjs +5 -0
  159. package/dist/images/index.mjs.map +1 -0
  160. package/dist/images/server.d.mts +69 -0
  161. package/dist/images/server.d.ts +69 -0
  162. package/dist/images/server.js +21 -0
  163. package/dist/images/server.js.map +1 -0
  164. package/dist/images/server.mjs +4 -0
  165. package/dist/images/server.mjs.map +1 -0
  166. package/dist/index.d.mts +846 -0
  167. package/dist/index.d.ts +846 -0
  168. package/dist/index.js +2623 -0
  169. package/dist/index.js.map +1 -0
  170. package/dist/index.mjs +2416 -0
  171. package/dist/index.mjs.map +1 -0
  172. package/dist/layout/index.d.mts +53 -0
  173. package/dist/layout/index.d.ts +53 -0
  174. package/dist/layout/index.js +187 -0
  175. package/dist/layout/index.js.map +1 -0
  176. package/dist/layout/index.mjs +185 -0
  177. package/dist/layout/index.mjs.map +1 -0
  178. package/dist/llms/index.d.mts +448 -0
  179. package/dist/llms/index.d.ts +448 -0
  180. package/dist/llms/index.js +581 -0
  181. package/dist/llms/index.js.map +1 -0
  182. package/dist/llms/index.mjs +529 -0
  183. package/dist/llms/index.mjs.map +1 -0
  184. package/dist/manifest/index.d.mts +62 -0
  185. package/dist/manifest/index.d.ts +62 -0
  186. package/dist/manifest/index.js +85 -0
  187. package/dist/manifest/index.js.map +1 -0
  188. package/dist/manifest/index.mjs +83 -0
  189. package/dist/manifest/index.mjs.map +1 -0
  190. package/dist/middleware/index.d.mts +63 -0
  191. package/dist/middleware/index.d.ts +63 -0
  192. package/dist/middleware/index.js +54 -0
  193. package/dist/middleware/index.js.map +1 -0
  194. package/dist/middleware/index.mjs +51 -0
  195. package/dist/middleware/index.mjs.map +1 -0
  196. package/dist/migrator-2MQHOFDQ.mjs +4 -0
  197. package/dist/migrator-2MQHOFDQ.mjs.map +1 -0
  198. package/dist/migrator-THJCF6MZ.js +37 -0
  199. package/dist/migrator-THJCF6MZ.js.map +1 -0
  200. package/dist/redirects/index.d.mts +78 -0
  201. package/dist/redirects/index.d.ts +78 -0
  202. package/dist/redirects/index.js +26 -0
  203. package/dist/redirects/index.js.map +1 -0
  204. package/dist/redirects/index.mjs +5 -0
  205. package/dist/redirects/index.mjs.map +1 -0
  206. package/dist/reputation/index.d.mts +57 -0
  207. package/dist/reputation/index.d.ts +57 -0
  208. package/dist/reputation/index.js +21 -0
  209. package/dist/reputation/index.js.map +1 -0
  210. package/dist/reputation/index.mjs +4 -0
  211. package/dist/reputation/index.mjs.map +1 -0
  212. package/dist/robots/index.d.mts +38 -0
  213. package/dist/robots/index.d.ts +38 -0
  214. package/dist/robots/index.js +52 -0
  215. package/dist/robots/index.js.map +1 -0
  216. package/dist/robots/index.mjs +50 -0
  217. package/dist/robots/index.mjs.map +1 -0
  218. package/dist/routing-B5XS-6_W.d.mts +118 -0
  219. package/dist/routing-DZYzyDHw.d.ts +118 -0
  220. package/dist/scanner-GAF5PO5F.js +53 -0
  221. package/dist/scanner-GAF5PO5F.js.map +1 -0
  222. package/dist/scanner-LKJKW7IT.mjs +4 -0
  223. package/dist/scanner-LKJKW7IT.mjs.map +1 -0
  224. package/dist/securityHeaders-nwZ6nP4g.d.mts +24 -0
  225. package/dist/securityHeaders-nwZ6nP4g.d.ts +24 -0
  226. package/dist/seo/index.d.mts +600 -0
  227. package/dist/seo/index.d.ts +600 -0
  228. package/dist/seo/index.js +883 -0
  229. package/dist/seo/index.js.map +1 -0
  230. package/dist/seo/index.mjs +773 -0
  231. package/dist/seo/index.mjs.map +1 -0
  232. package/dist/seo/register-sitemap-cli.js +151 -0
  233. package/dist/seo/register-sitemap-cli.js.map +1 -0
  234. package/dist/seo/register-sitemap-cli.mjs +144 -0
  235. package/dist/seo/register-sitemap-cli.mjs.map +1 -0
  236. package/dist/seo/server.d.mts +107 -0
  237. package/dist/seo/server.d.ts +107 -0
  238. package/dist/seo/server.js +207 -0
  239. package/dist/seo/server.js.map +1 -0
  240. package/dist/seo/server.mjs +186 -0
  241. package/dist/seo/server.mjs.map +1 -0
  242. package/dist/server-api-EWXKOQZA.mjs +4 -0
  243. package/dist/server-api-EWXKOQZA.mjs.map +1 -0
  244. package/dist/server-api-GJPNRYUP.js +81 -0
  245. package/dist/server-api-GJPNRYUP.js.map +1 -0
  246. package/dist/setup/client.d.mts +60 -0
  247. package/dist/setup/client.d.ts +60 -0
  248. package/dist/setup/client.js +31 -0
  249. package/dist/setup/client.js.map +1 -0
  250. package/dist/setup/client.mjs +6 -0
  251. package/dist/setup/client.mjs.map +1 -0
  252. package/dist/setup/index.d.mts +5 -0
  253. package/dist/setup/index.d.ts +5 -0
  254. package/dist/setup/index.js +35 -0
  255. package/dist/setup/index.js.map +1 -0
  256. package/dist/setup/index.mjs +6 -0
  257. package/dist/setup/index.mjs.map +1 -0
  258. package/dist/setup/server.d.mts +14 -0
  259. package/dist/setup/server.d.ts +14 -0
  260. package/dist/setup/server.js +13 -0
  261. package/dist/setup/server.js.map +1 -0
  262. package/dist/setup/server.mjs +4 -0
  263. package/dist/setup/server.mjs.map +1 -0
  264. package/dist/site-config/index.d.mts +24 -0
  265. package/dist/site-config/index.d.ts +24 -0
  266. package/dist/site-config/index.js +17 -0
  267. package/dist/site-config/index.js.map +1 -0
  268. package/dist/site-config/index.mjs +4 -0
  269. package/dist/site-config/index.mjs.map +1 -0
  270. package/dist/sitemap/index.d.mts +96 -0
  271. package/dist/sitemap/index.d.ts +96 -0
  272. package/dist/sitemap/index.js +288 -0
  273. package/dist/sitemap/index.js.map +1 -0
  274. package/dist/sitemap/index.mjs +285 -0
  275. package/dist/sitemap/index.mjs.map +1 -0
  276. package/dist/socket-loader-J26QHHOB.js +16 -0
  277. package/dist/socket-loader-J26QHHOB.js.map +1 -0
  278. package/dist/socket-loader-R7S2YJ2J.mjs +14 -0
  279. package/dist/socket-loader-R7S2YJ2J.mjs.map +1 -0
  280. package/dist/types-0dmq3k20.d.mts +168 -0
  281. package/dist/types-0dmq3k20.d.ts +168 -0
  282. package/dist/types-Blb2QNkV.d.mts +263 -0
  283. package/dist/types-Blb2QNkV.d.ts +263 -0
  284. package/dist/types-BnCwwUX3.d.mts +250 -0
  285. package/dist/types-BnCwwUX3.d.ts +250 -0
  286. package/dist/types-CGlnp43R.d.mts +312 -0
  287. package/dist/types-CGlnp43R.d.ts +312 -0
  288. package/dist/types-D08004rU.d.mts +179 -0
  289. package/dist/types-D08004rU.d.ts +179 -0
  290. package/dist/types-DNSYU7qI.d.mts +127 -0
  291. package/dist/types-DNSYU7qI.d.ts +127 -0
  292. package/dist/types-KZP_VWZp.d.mts +266 -0
  293. package/dist/types-KZP_VWZp.d.ts +266 -0
  294. package/dist/useEventModal-BVTx69XE.d.mts +274 -0
  295. package/dist/useEventModal-Dx1dItTJ.d.ts +274 -0
  296. package/dist/web-vitals-444RLW3B.js +252 -0
  297. package/dist/web-vitals-444RLW3B.js.map +1 -0
  298. package/dist/web-vitals-KPICZIEF.mjs +241 -0
  299. package/dist/web-vitals-KPICZIEF.mjs.map +1 -0
  300. package/package.json +192 -0
@@ -0,0 +1,1578 @@
1
+ 'use strict';
2
+
3
+ require('../chunk-ZSMWDLMK.js');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var React = require('react');
6
+
7
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
+
9
+ var React__default = /*#__PURE__*/_interopDefault(React);
10
+
11
+ async function fetchBlogPost(apiUrl, apiKey, slug) {
12
+ try {
13
+ const response = await fetch(`${apiUrl}/public/blog/posts/${slug}`, {
14
+ headers: { "x-api-key": apiKey },
15
+ next: { revalidate: 60 }
16
+ });
17
+ if (!response.ok) {
18
+ if (response.status === 404) return null;
19
+ console.error("[Blog] Failed to fetch post:", response.statusText);
20
+ return null;
21
+ }
22
+ const data = await response.json();
23
+ return data.post;
24
+ } catch (error) {
25
+ console.error("[Blog] Error fetching post:", error);
26
+ return null;
27
+ }
28
+ }
29
+ async function fetchRelatedPosts(apiUrl, apiKey, postId, limit = 3) {
30
+ try {
31
+ const response = await fetch(`${apiUrl}/public/blog/related`, {
32
+ method: "POST",
33
+ headers: {
34
+ "Content-Type": "application/json",
35
+ "x-api-key": apiKey
36
+ },
37
+ body: JSON.stringify({ current_post_id: postId, limit }),
38
+ next: { revalidate: 300 }
39
+ });
40
+ if (!response.ok) return [];
41
+ const data = await response.json();
42
+ return data.posts || [];
43
+ } catch (error) {
44
+ console.error("[Blog] Error fetching related posts:", error);
45
+ return [];
46
+ }
47
+ }
48
+ function generateTableOfContents(html) {
49
+ const headingRegex = /<h([2-4])[^>]*(?:id="([^"]*)")?[^>]*>(.*?)<\/h[2-4]>/gi;
50
+ const items = [];
51
+ let match;
52
+ while ((match = headingRegex.exec(html)) !== null) {
53
+ const level = parseInt(match[1]);
54
+ const existingId = match[2];
55
+ const text = match[3].replace(/<[^>]*>/g, "");
56
+ const id = existingId || slugify(text);
57
+ items.push({ id, text, level });
58
+ }
59
+ return items;
60
+ }
61
+ function slugify(text) {
62
+ return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
63
+ }
64
+ async function BlogPost({
65
+ apiUrl = process.env.NEXT_PUBLIC_UPTRADE_API_URL || "https://api.uptrademedia.com",
66
+ apiKey = process.env.NEXT_PUBLIC_UPTRADE_API_KEY || "",
67
+ slug,
68
+ showToc = true,
69
+ showRelated = true,
70
+ relatedCount = 3,
71
+ showAuthor = true,
72
+ basePath = "/blog",
73
+ className,
74
+ styles = {},
75
+ unstyled = false,
76
+ children
77
+ }) {
78
+ const inlineStyle = (defaultStyle, classKey) => unstyled || styles[classKey] ? void 0 : defaultStyle;
79
+ if (!apiKey) {
80
+ console.warn("[Blog] No API key configured");
81
+ return null;
82
+ }
83
+ const post = await fetchBlogPost(apiUrl, apiKey, slug);
84
+ if (!post) {
85
+ return /* @__PURE__ */ jsxRuntime.jsxs(
86
+ "div",
87
+ {
88
+ className: `${styles.notFound || ""} ${className || ""}`.trim() || void 0,
89
+ style: inlineStyle({ textAlign: "center", padding: 60 }, "notFound"),
90
+ children: [
91
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { style: inlineStyle({ fontSize: 24, marginBottom: 16 }, "notFound"), children: "Post Not Found" }),
92
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: inlineStyle({ color: "#6b7280" }, "notFound"), children: "The blog post you're looking for doesn't exist or has been removed." }),
93
+ /* @__PURE__ */ jsxRuntime.jsx(
94
+ "a",
95
+ {
96
+ href: basePath,
97
+ style: inlineStyle({
98
+ display: "inline-block",
99
+ marginTop: 24,
100
+ padding: "12px 24px",
101
+ backgroundColor: "#3b82f6",
102
+ color: "#fff",
103
+ borderRadius: 8,
104
+ textDecoration: "none"
105
+ }, "notFound"),
106
+ children: "\u2190 Back to Blog"
107
+ }
108
+ )
109
+ ]
110
+ }
111
+ );
112
+ }
113
+ const content = post.content_html || post.content || "";
114
+ const tableOfContents = showToc ? generateTableOfContents(content) : [];
115
+ const relatedPosts = showRelated ? await fetchRelatedPosts(apiUrl, apiKey, post.id, relatedCount) : [];
116
+ if (children) {
117
+ return children({ post, tableOfContents, relatedPosts });
118
+ }
119
+ const date = post.published_at ? new Date(post.published_at).toLocaleDateString("en-US", {
120
+ month: "long",
121
+ day: "numeric",
122
+ year: "numeric"
123
+ }) : null;
124
+ return /* @__PURE__ */ jsxRuntime.jsxs("article", { className: `${styles.article || ""} ${className || ""}`.trim() || void 0, children: [
125
+ /* @__PURE__ */ jsxRuntime.jsxs(
126
+ "header",
127
+ {
128
+ className: styles.header,
129
+ style: inlineStyle({ marginBottom: 32 }, "header"),
130
+ children: [
131
+ /* @__PURE__ */ jsxRuntime.jsxs(
132
+ "nav",
133
+ {
134
+ className: styles.breadcrumb,
135
+ style: inlineStyle({ marginBottom: 16, fontSize: 14, color: "#6b7280" }, "breadcrumb"),
136
+ children: [
137
+ /* @__PURE__ */ jsxRuntime.jsx(
138
+ "a",
139
+ {
140
+ href: basePath,
141
+ className: styles.breadcrumbLink,
142
+ style: inlineStyle({ color: "#3b82f6", textDecoration: "none" }, "breadcrumbLink"),
143
+ children: "Blog"
144
+ }
145
+ ),
146
+ post.category && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
147
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: inlineStyle({ margin: "0 8px" }, "breadcrumb"), children: "/" }),
148
+ /* @__PURE__ */ jsxRuntime.jsx(
149
+ "a",
150
+ {
151
+ href: `${basePath}?category=${post.category}`,
152
+ className: styles.breadcrumbLink,
153
+ style: inlineStyle({ color: "#3b82f6", textDecoration: "none" }, "breadcrumbLink"),
154
+ children: typeof post.category === "string" ? post.category : post.category?.name || "Uncategorized"
155
+ }
156
+ )
157
+ ] })
158
+ ]
159
+ }
160
+ ),
161
+ /* @__PURE__ */ jsxRuntime.jsx(
162
+ "h1",
163
+ {
164
+ className: styles.title,
165
+ style: inlineStyle({ fontSize: 36, fontWeight: 700, lineHeight: 1.2, marginBottom: 16 }, "title"),
166
+ children: post.title
167
+ }
168
+ ),
169
+ post.subtitle && /* @__PURE__ */ jsxRuntime.jsx(
170
+ "p",
171
+ {
172
+ className: styles.subtitle,
173
+ style: inlineStyle({ fontSize: 20, color: "#6b7280", marginBottom: 16 }, "subtitle"),
174
+ children: post.subtitle
175
+ }
176
+ ),
177
+ /* @__PURE__ */ jsxRuntime.jsxs(
178
+ "div",
179
+ {
180
+ className: styles.meta,
181
+ style: inlineStyle({ display: "flex", alignItems: "center", gap: 16, flexWrap: "wrap" }, "meta"),
182
+ children: [
183
+ post.author && /* @__PURE__ */ jsxRuntime.jsxs(
184
+ "span",
185
+ {
186
+ className: styles.metaItem,
187
+ style: inlineStyle({ fontSize: 14, color: "#374151" }, "metaItem"),
188
+ children: [
189
+ "By ",
190
+ typeof post.author === "string" ? post.author : post.author.name
191
+ ]
192
+ }
193
+ ),
194
+ date && /* @__PURE__ */ jsxRuntime.jsx(
195
+ "span",
196
+ {
197
+ className: styles.metaItem,
198
+ style: inlineStyle({ fontSize: 14, color: "#6b7280" }, "metaItem"),
199
+ children: date
200
+ }
201
+ ),
202
+ post.reading_time_minutes && /* @__PURE__ */ jsxRuntime.jsxs(
203
+ "span",
204
+ {
205
+ className: styles.metaItem,
206
+ style: inlineStyle({ fontSize: 14, color: "#9ca3af" }, "metaItem"),
207
+ children: [
208
+ post.reading_time_minutes,
209
+ " min read"
210
+ ]
211
+ }
212
+ )
213
+ ]
214
+ }
215
+ )
216
+ ]
217
+ }
218
+ ),
219
+ post.featured_image && /* @__PURE__ */ jsxRuntime.jsx(
220
+ "figure",
221
+ {
222
+ className: styles.featuredImageWrapper,
223
+ style: inlineStyle({ margin: "0 0 32px" }, "featuredImageWrapper"),
224
+ children: /* @__PURE__ */ jsxRuntime.jsx(
225
+ "img",
226
+ {
227
+ src: post.featured_image,
228
+ alt: post.featured_image_alt || post.title,
229
+ className: styles.featuredImage,
230
+ style: inlineStyle({
231
+ width: "100%",
232
+ maxHeight: 500,
233
+ objectFit: "cover",
234
+ borderRadius: 12
235
+ }, "featuredImage")
236
+ }
237
+ )
238
+ }
239
+ ),
240
+ /* @__PURE__ */ jsxRuntime.jsxs(
241
+ "div",
242
+ {
243
+ className: styles.contentLayout,
244
+ style: inlineStyle({
245
+ display: showToc && tableOfContents.length > 0 ? "grid" : "block",
246
+ gridTemplateColumns: showToc && tableOfContents.length > 0 ? "1fr 250px" : void 0,
247
+ gap: 48
248
+ }, "contentLayout"),
249
+ children: [
250
+ /* @__PURE__ */ jsxRuntime.jsx(
251
+ "div",
252
+ {
253
+ className: `blog-content ${styles.content || ""}`.trim(),
254
+ style: inlineStyle({
255
+ fontSize: 17,
256
+ lineHeight: 1.8,
257
+ color: "#374151"
258
+ }, "content"),
259
+ dangerouslySetInnerHTML: { __html: content }
260
+ }
261
+ ),
262
+ showToc && tableOfContents.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
263
+ "aside",
264
+ {
265
+ className: styles.tocSidebar,
266
+ style: inlineStyle({
267
+ position: "sticky",
268
+ top: 100,
269
+ alignSelf: "start",
270
+ padding: 20,
271
+ backgroundColor: "#f9fafb",
272
+ borderRadius: 12
273
+ }, "tocSidebar"),
274
+ children: [
275
+ /* @__PURE__ */ jsxRuntime.jsx(
276
+ "h4",
277
+ {
278
+ className: styles.tocTitle,
279
+ style: inlineStyle({
280
+ margin: "0 0 12px",
281
+ fontSize: 12,
282
+ fontWeight: 600,
283
+ textTransform: "uppercase",
284
+ letterSpacing: "0.05em",
285
+ color: "#6b7280"
286
+ }, "tocTitle"),
287
+ children: "On This Page"
288
+ }
289
+ ),
290
+ /* @__PURE__ */ jsxRuntime.jsx(
291
+ "ul",
292
+ {
293
+ className: styles.tocList,
294
+ style: inlineStyle({ listStyle: "none", margin: 0, padding: 0 }, "tocList"),
295
+ children: tableOfContents.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
296
+ "li",
297
+ {
298
+ className: styles.tocItem,
299
+ style: inlineStyle({
300
+ paddingLeft: (item.level - 2) * 12,
301
+ marginBottom: 8
302
+ }, "tocItem"),
303
+ children: /* @__PURE__ */ jsxRuntime.jsx(
304
+ "a",
305
+ {
306
+ href: `#${item.id}`,
307
+ className: styles.tocLink,
308
+ style: inlineStyle({
309
+ fontSize: 14,
310
+ color: "#6b7280",
311
+ textDecoration: "none"
312
+ }, "tocLink"),
313
+ children: item.text
314
+ }
315
+ )
316
+ },
317
+ item.id
318
+ ))
319
+ }
320
+ )
321
+ ]
322
+ }
323
+ )
324
+ ]
325
+ }
326
+ ),
327
+ post.tags && post.tags.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
328
+ "div",
329
+ {
330
+ className: styles.tags,
331
+ style: inlineStyle({ marginTop: 32, display: "flex", gap: 8, flexWrap: "wrap" }, "tags"),
332
+ children: post.tags.map((tag, index) => {
333
+ const tagName = typeof tag === "string" ? tag : tag?.name || "";
334
+ return /* @__PURE__ */ jsxRuntime.jsxs(
335
+ "a",
336
+ {
337
+ href: `${basePath}?tag=${tagName}`,
338
+ className: styles.tag,
339
+ style: inlineStyle({
340
+ padding: "4px 12px",
341
+ backgroundColor: "#f3f4f6",
342
+ borderRadius: 9999,
343
+ fontSize: 13,
344
+ color: "#374151",
345
+ textDecoration: "none"
346
+ }, "tag"),
347
+ children: [
348
+ "#",
349
+ tagName
350
+ ]
351
+ },
352
+ `${tagName}-${index}`
353
+ );
354
+ })
355
+ }
356
+ ),
357
+ (post.faq_items ?? post.faqItems) && Array.isArray(post.faq_items ?? post.faqItems) && (post.faq_items ?? post.faqItems).length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
358
+ "section",
359
+ {
360
+ className: styles.faqSection,
361
+ style: inlineStyle({ marginTop: 48 }, "faqSection"),
362
+ children: [
363
+ /* @__PURE__ */ jsxRuntime.jsx(
364
+ "h2",
365
+ {
366
+ className: styles.faqTitle,
367
+ style: inlineStyle({ fontSize: 24, fontWeight: 600, marginBottom: 24 }, "faqTitle"),
368
+ children: "Frequently Asked Questions"
369
+ }
370
+ ),
371
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: inlineStyle({ display: "flex", flexDirection: "column", gap: 16 }, "faqSection"), children: (post.faq_items ?? post.faqItems).map((faq, index) => /* @__PURE__ */ jsxRuntime.jsxs(
372
+ "details",
373
+ {
374
+ className: styles.faqItem,
375
+ style: inlineStyle({
376
+ padding: 16,
377
+ backgroundColor: "#f9fafb",
378
+ borderRadius: 8
379
+ }, "faqItem"),
380
+ children: [
381
+ /* @__PURE__ */ jsxRuntime.jsx(
382
+ "summary",
383
+ {
384
+ className: styles.faqQuestion,
385
+ style: inlineStyle({
386
+ fontWeight: 500,
387
+ cursor: "pointer",
388
+ listStyle: "none"
389
+ }, "faqQuestion"),
390
+ children: faq.question
391
+ }
392
+ ),
393
+ /* @__PURE__ */ jsxRuntime.jsx(
394
+ "p",
395
+ {
396
+ className: styles.faqAnswer,
397
+ style: inlineStyle({ marginTop: 12, color: "#6b7280" }, "faqAnswer"),
398
+ children: faq.answer
399
+ }
400
+ )
401
+ ]
402
+ },
403
+ index
404
+ )) })
405
+ ]
406
+ }
407
+ ),
408
+ showAuthor && post.author && typeof post.author === "object" && /* @__PURE__ */ jsxRuntime.jsx(AuthorSection, { author: normalizeAuthorForDisplay(post.author), className: styles.authorCard, unstyled }),
409
+ showRelated && relatedPosts.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
410
+ "section",
411
+ {
412
+ className: styles.relatedSection,
413
+ style: inlineStyle({ marginTop: 48 }, "relatedSection"),
414
+ children: [
415
+ /* @__PURE__ */ jsxRuntime.jsx(
416
+ "h2",
417
+ {
418
+ className: styles.relatedTitle,
419
+ style: inlineStyle({ fontSize: 24, fontWeight: 600, marginBottom: 24 }, "relatedTitle"),
420
+ children: "Related Posts"
421
+ }
422
+ ),
423
+ /* @__PURE__ */ jsxRuntime.jsx(
424
+ "div",
425
+ {
426
+ className: styles.relatedGrid,
427
+ style: inlineStyle({
428
+ display: "grid",
429
+ gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))",
430
+ gap: 24
431
+ }, "relatedGrid"),
432
+ children: relatedPosts.map((relatedPost) => /* @__PURE__ */ jsxRuntime.jsxs(
433
+ "article",
434
+ {
435
+ className: styles.relatedCard,
436
+ style: inlineStyle({
437
+ backgroundColor: "#fff",
438
+ borderRadius: 12,
439
+ overflow: "hidden",
440
+ boxShadow: "0 1px 3px rgba(0,0,0,0.1)"
441
+ }, "relatedCard"),
442
+ children: [
443
+ relatedPost.featured_image && /* @__PURE__ */ jsxRuntime.jsx("a", { href: `${basePath}/${relatedPost.slug}`, children: /* @__PURE__ */ jsxRuntime.jsx(
444
+ "img",
445
+ {
446
+ src: relatedPost.featured_image,
447
+ alt: relatedPost.title,
448
+ style: inlineStyle({ width: "100%", height: 150, objectFit: "cover" }, "relatedCard")
449
+ }
450
+ ) }),
451
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: inlineStyle({ padding: 16 }, "relatedCard"), children: [
452
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { style: inlineStyle({ fontSize: 16, fontWeight: 600, marginBottom: 8 }, "relatedCard"), children: /* @__PURE__ */ jsxRuntime.jsx(
453
+ "a",
454
+ {
455
+ href: `${basePath}/${relatedPost.slug}`,
456
+ style: inlineStyle({ color: "inherit", textDecoration: "none" }, "relatedCard"),
457
+ children: relatedPost.title
458
+ }
459
+ ) }),
460
+ relatedPost.excerpt && /* @__PURE__ */ jsxRuntime.jsxs("p", { style: inlineStyle({ fontSize: 14, color: "#6b7280", margin: 0 }, "relatedCard"), children: [
461
+ relatedPost.excerpt.slice(0, 100),
462
+ "..."
463
+ ] })
464
+ ] })
465
+ ]
466
+ },
467
+ relatedPost.id
468
+ ))
469
+ }
470
+ )
471
+ ]
472
+ }
473
+ )
474
+ ] });
475
+ }
476
+ function normalizeAuthorForDisplay(author) {
477
+ const a = author;
478
+ const avatarUrl = a.avatar_url ?? a.image ?? a.image_url;
479
+ const socialLinks = a.social_links;
480
+ const socialProfiles = a.socialProfiles;
481
+ return {
482
+ id: a.id ?? "author",
483
+ project_id: a.project_id ?? "",
484
+ name: a.name ?? "Author",
485
+ slug: a.slug ?? "author",
486
+ bio: a.bio ?? void 0,
487
+ avatar_url: avatarUrl ?? void 0,
488
+ email: a.email ?? void 0,
489
+ website: a.website ?? a.url ?? void 0,
490
+ social_links: socialLinks ?? void 0,
491
+ is_active: a.is_active ?? true,
492
+ ...socialProfiles?.length ? { sameAs: socialProfiles } : {},
493
+ ...a.title ? { title: a.title } : {}
494
+ };
495
+ }
496
+ function AuthorSection({
497
+ author,
498
+ className,
499
+ unstyled = false
500
+ }) {
501
+ return /* @__PURE__ */ jsxRuntime.jsxs(
502
+ "section",
503
+ {
504
+ className,
505
+ style: unstyled || className ? void 0 : {
506
+ marginTop: 48,
507
+ padding: 24,
508
+ backgroundColor: "#f9fafb",
509
+ borderRadius: 12,
510
+ display: "flex",
511
+ gap: 20,
512
+ alignItems: "flex-start"
513
+ },
514
+ children: [
515
+ author.avatar_url && /* @__PURE__ */ jsxRuntime.jsx(
516
+ "img",
517
+ {
518
+ src: author.avatar_url,
519
+ alt: author.name,
520
+ style: unstyled || className ? void 0 : {
521
+ width: 80,
522
+ height: 80,
523
+ borderRadius: "50%",
524
+ objectFit: "cover"
525
+ }
526
+ }
527
+ ),
528
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
529
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { style: unstyled || className ? void 0 : { margin: "0 0 4px", fontSize: 18, fontWeight: 600 }, children: author.name }),
530
+ "title" in author && author.title && /* @__PURE__ */ jsxRuntime.jsx("p", { style: unstyled || className ? void 0 : { margin: "0 0 4px", fontSize: 14, color: "#6b7280" }, children: author.title }),
531
+ author.bio && /* @__PURE__ */ jsxRuntime.jsx("p", { style: unstyled || className ? void 0 : { margin: "0 0 12px", color: "#6b7280", fontSize: 14 }, children: author.bio }),
532
+ author.social_links && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: unstyled || className ? void 0 : { display: "flex", gap: 16 }, children: [
533
+ author.social_links.twitter && /* @__PURE__ */ jsxRuntime.jsx(
534
+ "a",
535
+ {
536
+ href: `https://twitter.com/${author.social_links.twitter}`,
537
+ target: "_blank",
538
+ rel: "noopener noreferrer",
539
+ style: unstyled || className ? void 0 : { color: "#3b82f6", fontSize: 14 },
540
+ children: "Twitter"
541
+ }
542
+ ),
543
+ author.social_links.linkedin && /* @__PURE__ */ jsxRuntime.jsx(
544
+ "a",
545
+ {
546
+ href: author.social_links.linkedin,
547
+ target: "_blank",
548
+ rel: "noopener noreferrer",
549
+ style: unstyled || className ? void 0 : { color: "#3b82f6", fontSize: 14 },
550
+ children: "LinkedIn"
551
+ }
552
+ )
553
+ ] }),
554
+ "sameAs" in author && author.sameAs && author.sameAs.length > 0 && !author.social_links && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", gap: 16, flexWrap: "wrap" }, children: author.sameAs.map((url, i) => /* @__PURE__ */ jsxRuntime.jsx(
555
+ "a",
556
+ {
557
+ href: url,
558
+ target: "_blank",
559
+ rel: "noopener noreferrer",
560
+ style: { color: "#3b82f6", fontSize: 14 },
561
+ children: "Profile"
562
+ },
563
+ i
564
+ )) })
565
+ ] })
566
+ ]
567
+ }
568
+ );
569
+ }
570
+ async function fetchBlogList(params) {
571
+ const {
572
+ apiUrl,
573
+ apiKey,
574
+ category,
575
+ tag,
576
+ author,
577
+ featured,
578
+ search,
579
+ page = 1,
580
+ perPage = 12,
581
+ orderBy = "published_at",
582
+ order = "desc"
583
+ } = params;
584
+ const queryParams = new URLSearchParams();
585
+ if (category) queryParams.set("category", category);
586
+ if (tag) queryParams.set("tag", tag);
587
+ if (author) queryParams.set("author", author);
588
+ if (featured) queryParams.set("featured", "true");
589
+ if (search) queryParams.set("search", search);
590
+ queryParams.set("page", String(page));
591
+ queryParams.set("per_page", String(perPage));
592
+ queryParams.set("order_by", orderBy);
593
+ queryParams.set("order", order);
594
+ try {
595
+ const response = await fetch(`${apiUrl}/public/blog/posts?${queryParams}`, {
596
+ headers: {
597
+ "x-api-key": apiKey
598
+ },
599
+ next: { revalidate: 60 }
600
+ // Revalidate every 60 seconds
601
+ });
602
+ if (!response.ok) {
603
+ console.error("[Blog] Failed to fetch posts:", response.statusText);
604
+ return {
605
+ posts: [],
606
+ pagination: {
607
+ page: 1,
608
+ perPage: 12,
609
+ total: 0,
610
+ totalPages: 0,
611
+ hasNext: false,
612
+ hasPrev: false
613
+ }
614
+ };
615
+ }
616
+ const data = await response.json();
617
+ return {
618
+ posts: data.posts || [],
619
+ pagination: {
620
+ page: data.pagination?.page || 1,
621
+ perPage: data.pagination?.per_page || 12,
622
+ total: data.pagination?.total || 0,
623
+ totalPages: data.pagination?.total_pages || 0,
624
+ hasNext: data.pagination?.has_next || false,
625
+ hasPrev: data.pagination?.has_prev || false
626
+ }
627
+ };
628
+ } catch (error) {
629
+ console.error("[Blog] Error fetching posts:", error);
630
+ return {
631
+ posts: [],
632
+ pagination: {
633
+ page: 1,
634
+ perPage: 12,
635
+ total: 0,
636
+ totalPages: 0,
637
+ hasNext: false,
638
+ hasPrev: false
639
+ }
640
+ };
641
+ }
642
+ }
643
+ async function fetchCategories(apiUrl, apiKey) {
644
+ try {
645
+ const response = await fetch(`${apiUrl}/public/blog/categories`, {
646
+ headers: { "x-api-key": apiKey },
647
+ next: { revalidate: 300 }
648
+ // Cache for 5 minutes
649
+ });
650
+ if (!response.ok) return [];
651
+ const data = await response.json();
652
+ return data.categories || [];
653
+ } catch (error) {
654
+ console.error("[Blog] Error fetching categories:", error);
655
+ return [];
656
+ }
657
+ }
658
+ async function BlogList({
659
+ apiUrl = process.env.NEXT_PUBLIC_UPTRADE_API_URL || "https://api.uptrademedia.com",
660
+ apiKey = process.env.NEXT_PUBLIC_UPTRADE_API_KEY || "",
661
+ category,
662
+ tag,
663
+ author,
664
+ featured,
665
+ search,
666
+ page = 1,
667
+ perPage = 12,
668
+ orderBy = "published_at",
669
+ order = "desc",
670
+ showCategoryFilter = false,
671
+ showPagination = true,
672
+ className,
673
+ basePath = "/blog",
674
+ styles = {},
675
+ unstyled = false,
676
+ renderPost,
677
+ children
678
+ }) {
679
+ if (!apiKey) {
680
+ console.warn("[Blog] No API key configured");
681
+ return null;
682
+ }
683
+ const inlineStyle = (defaultStyle, classKey) => unstyled || styles[classKey] ? void 0 : defaultStyle;
684
+ const [blogData, categories] = await Promise.all([
685
+ fetchBlogList({
686
+ apiUrl,
687
+ apiKey,
688
+ category,
689
+ tag,
690
+ author,
691
+ featured,
692
+ search,
693
+ page,
694
+ perPage,
695
+ orderBy,
696
+ order
697
+ }),
698
+ showCategoryFilter ? fetchCategories(apiUrl, apiKey) : Promise.resolve([])
699
+ ]);
700
+ if (children) {
701
+ return children({ posts: blogData.posts, pagination: blogData.pagination, categories });
702
+ }
703
+ const { posts, pagination } = blogData;
704
+ if (posts.length === 0) {
705
+ return /* @__PURE__ */ jsxRuntime.jsx(
706
+ "div",
707
+ {
708
+ className: `${styles.container || ""} ${styles.emptyState || ""} ${className || ""}`.trim() || void 0,
709
+ style: inlineStyle({ textAlign: "center", padding: 40 }, "emptyState"),
710
+ children: /* @__PURE__ */ jsxRuntime.jsx("p", { style: inlineStyle({ color: "#6b7280" }, "emptyState"), children: "No posts found." })
711
+ }
712
+ );
713
+ }
714
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${styles.container || ""} ${className || ""}`.trim() || void 0, children: [
715
+ showCategoryFilter && categories.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
716
+ "nav",
717
+ {
718
+ className: styles.categoryNav,
719
+ style: inlineStyle({ marginBottom: 24, display: "flex", gap: 8, flexWrap: "wrap" }, "categoryNav"),
720
+ children: [
721
+ /* @__PURE__ */ jsxRuntime.jsx(
722
+ "a",
723
+ {
724
+ href: basePath,
725
+ className: `${styles.categoryLink || ""} ${!category ? styles.categoryLinkActive || "" : styles.categoryLinkInactive || ""}`.trim() || void 0,
726
+ style: inlineStyle({
727
+ padding: "6px 12px",
728
+ borderRadius: 9999,
729
+ fontSize: 14,
730
+ textDecoration: "none",
731
+ backgroundColor: !category ? "#3b82f6" : "#f3f4f6",
732
+ color: !category ? "#fff" : "#374151"
733
+ }, "categoryLink"),
734
+ children: "All"
735
+ }
736
+ ),
737
+ categories.map((cat) => /* @__PURE__ */ jsxRuntime.jsxs(
738
+ "a",
739
+ {
740
+ href: `${basePath}?category=${cat.slug}`,
741
+ className: `${styles.categoryLink || ""} ${category === cat.slug ? styles.categoryLinkActive || "" : styles.categoryLinkInactive || ""}`.trim() || void 0,
742
+ style: inlineStyle({
743
+ padding: "6px 12px",
744
+ borderRadius: 9999,
745
+ fontSize: 14,
746
+ textDecoration: "none",
747
+ backgroundColor: category === cat.slug ? "#3b82f6" : "#f3f4f6",
748
+ color: category === cat.slug ? "#fff" : "#374151"
749
+ }, "categoryLink"),
750
+ children: [
751
+ cat.name,
752
+ " (",
753
+ cat.post_count,
754
+ ")"
755
+ ]
756
+ },
757
+ cat.slug
758
+ ))
759
+ ]
760
+ }
761
+ ),
762
+ /* @__PURE__ */ jsxRuntime.jsx(
763
+ "div",
764
+ {
765
+ className: styles.grid,
766
+ style: inlineStyle({
767
+ display: "grid",
768
+ gridTemplateColumns: "repeat(auto-fill, minmax(320px, 1fr))",
769
+ gap: 24
770
+ }, "grid"),
771
+ children: posts.map(
772
+ (post) => renderPost ? /* @__PURE__ */ jsxRuntime.jsx(React__default.default.Fragment, { children: renderPost(post) }, post.id) : /* @__PURE__ */ jsxRuntime.jsx(BlogPostCard, { post, basePath, styles, unstyled }, post.id)
773
+ )
774
+ }
775
+ ),
776
+ showPagination && pagination.totalPages > 1 && /* @__PURE__ */ jsxRuntime.jsxs(
777
+ "nav",
778
+ {
779
+ className: styles.pagination,
780
+ style: inlineStyle({
781
+ marginTop: 40,
782
+ display: "flex",
783
+ justifyContent: "center",
784
+ gap: 8
785
+ }, "pagination"),
786
+ children: [
787
+ pagination.hasPrev && /* @__PURE__ */ jsxRuntime.jsx(
788
+ "a",
789
+ {
790
+ href: buildPaginationUrl(basePath, page - 1, category),
791
+ className: styles.paginationLink,
792
+ style: inlineStyle(paginationLinkStyle, "paginationLink"),
793
+ children: "\u2190 Previous"
794
+ }
795
+ ),
796
+ /* @__PURE__ */ jsxRuntime.jsxs(
797
+ "span",
798
+ {
799
+ className: styles.paginationInfo,
800
+ style: inlineStyle({ padding: "8px 16px", color: "#6b7280" }, "paginationInfo"),
801
+ children: [
802
+ "Page ",
803
+ pagination.page,
804
+ " of ",
805
+ pagination.totalPages
806
+ ]
807
+ }
808
+ ),
809
+ pagination.hasNext && /* @__PURE__ */ jsxRuntime.jsx(
810
+ "a",
811
+ {
812
+ href: buildPaginationUrl(basePath, page + 1, category),
813
+ className: styles.paginationLink,
814
+ style: inlineStyle(paginationLinkStyle, "paginationLink"),
815
+ children: "Next \u2192"
816
+ }
817
+ )
818
+ ]
819
+ }
820
+ )
821
+ ] });
822
+ }
823
+ function BlogPostCard({ post, basePath, styles = {}, unstyled = false }) {
824
+ const date = post.published_at ? new Date(post.published_at).toLocaleDateString("en-US", {
825
+ month: "long",
826
+ day: "numeric",
827
+ year: "numeric"
828
+ }) : null;
829
+ const inlineStyle = (defaultStyle, classKey) => unstyled || styles[classKey] ? void 0 : defaultStyle;
830
+ return /* @__PURE__ */ jsxRuntime.jsxs(
831
+ "article",
832
+ {
833
+ className: styles.card,
834
+ style: inlineStyle({
835
+ backgroundColor: "#fff",
836
+ borderRadius: 12,
837
+ overflow: "hidden",
838
+ boxShadow: "0 1px 3px rgba(0,0,0,0.1)",
839
+ transition: "box-shadow 0.2s, transform 0.2s"
840
+ }, "card"),
841
+ children: [
842
+ post.featured_image && /* @__PURE__ */ jsxRuntime.jsx("a", { href: `${basePath}/${post.slug}`, className: styles.cardImageWrapper, children: /* @__PURE__ */ jsxRuntime.jsx(
843
+ "img",
844
+ {
845
+ src: post.featured_image,
846
+ alt: post.featured_image_alt || post.title,
847
+ className: styles.cardImage,
848
+ style: inlineStyle({
849
+ width: "100%",
850
+ height: 200,
851
+ objectFit: "cover"
852
+ }, "cardImage")
853
+ }
854
+ ) }),
855
+ /* @__PURE__ */ jsxRuntime.jsxs(
856
+ "div",
857
+ {
858
+ className: styles.cardBody,
859
+ style: inlineStyle({ padding: 20 }, "cardBody"),
860
+ children: [
861
+ /* @__PURE__ */ jsxRuntime.jsxs(
862
+ "div",
863
+ {
864
+ className: styles.cardMeta,
865
+ style: inlineStyle({ display: "flex", alignItems: "center", gap: 12, marginBottom: 12 }, "cardMeta"),
866
+ children: [
867
+ post.category && /* @__PURE__ */ jsxRuntime.jsx(
868
+ "span",
869
+ {
870
+ className: styles.cardCategory,
871
+ style: inlineStyle({
872
+ padding: "2px 8px",
873
+ borderRadius: 4,
874
+ fontSize: 12,
875
+ fontWeight: 500,
876
+ backgroundColor: "#eff6ff",
877
+ color: "#3b82f6",
878
+ textTransform: "uppercase"
879
+ }, "cardCategory"),
880
+ children: typeof post.category === "string" ? post.category : post.category?.name || "Uncategorized"
881
+ }
882
+ ),
883
+ date && /* @__PURE__ */ jsxRuntime.jsx(
884
+ "span",
885
+ {
886
+ className: styles.cardDate,
887
+ style: inlineStyle({ fontSize: 13, color: "#6b7280" }, "cardDate"),
888
+ children: date
889
+ }
890
+ )
891
+ ]
892
+ }
893
+ ),
894
+ /* @__PURE__ */ jsxRuntime.jsx(
895
+ "h3",
896
+ {
897
+ className: styles.cardTitle,
898
+ style: inlineStyle({ margin: "0 0 8px", fontSize: 18, fontWeight: 600, lineHeight: 1.4 }, "cardTitle"),
899
+ children: /* @__PURE__ */ jsxRuntime.jsx(
900
+ "a",
901
+ {
902
+ href: `${basePath}/${post.slug}`,
903
+ className: styles.cardTitleLink,
904
+ style: inlineStyle({ color: "inherit", textDecoration: "none" }, "cardTitleLink"),
905
+ children: post.title
906
+ }
907
+ )
908
+ }
909
+ ),
910
+ post.excerpt && /* @__PURE__ */ jsxRuntime.jsx(
911
+ "p",
912
+ {
913
+ className: styles.cardExcerpt,
914
+ style: inlineStyle({
915
+ margin: "0 0 16px",
916
+ fontSize: 14,
917
+ color: "#6b7280",
918
+ lineHeight: 1.6,
919
+ display: "-webkit-box",
920
+ WebkitLineClamp: 3,
921
+ WebkitBoxOrient: "vertical",
922
+ overflow: "hidden"
923
+ }, "cardExcerpt"),
924
+ children: post.excerpt
925
+ }
926
+ ),
927
+ /* @__PURE__ */ jsxRuntime.jsxs(
928
+ "div",
929
+ {
930
+ className: styles.cardFooter,
931
+ style: inlineStyle({ display: "flex", justifyContent: "space-between", alignItems: "center" }, "cardFooter"),
932
+ children: [
933
+ post.author && /* @__PURE__ */ jsxRuntime.jsxs(
934
+ "span",
935
+ {
936
+ className: styles.cardAuthor,
937
+ style: inlineStyle({ fontSize: 13, color: "#6b7280" }, "cardAuthor"),
938
+ children: [
939
+ "By ",
940
+ typeof post.author === "string" ? post.author : post.author.name
941
+ ]
942
+ }
943
+ ),
944
+ post.reading_time_minutes && /* @__PURE__ */ jsxRuntime.jsxs(
945
+ "span",
946
+ {
947
+ className: styles.cardReadingTime,
948
+ style: inlineStyle({ fontSize: 13, color: "#9ca3af" }, "cardReadingTime"),
949
+ children: [
950
+ post.reading_time_minutes,
951
+ " min read"
952
+ ]
953
+ }
954
+ )
955
+ ]
956
+ }
957
+ )
958
+ ]
959
+ }
960
+ )
961
+ ]
962
+ }
963
+ );
964
+ }
965
+ function buildPaginationUrl(basePath, page, category) {
966
+ const params = new URLSearchParams();
967
+ params.set("page", String(page));
968
+ if (category) params.set("category", category);
969
+ return `${basePath}?${params}`;
970
+ }
971
+ var paginationLinkStyle = {
972
+ padding: "8px 16px",
973
+ borderRadius: 8,
974
+ backgroundColor: "#3b82f6",
975
+ color: "#fff",
976
+ textDecoration: "none",
977
+ fontSize: 14,
978
+ fontWeight: 500
979
+ };
980
+ async function fetchRecentPosts(apiUrl, apiKey, limit = 5) {
981
+ try {
982
+ const response = await fetch(`${apiUrl}/public/blog/recent?limit=${limit}`, {
983
+ headers: { "x-api-key": apiKey },
984
+ next: { revalidate: 300 }
985
+ });
986
+ if (!response.ok) return [];
987
+ const data = await response.json();
988
+ return data.posts || [];
989
+ } catch (error) {
990
+ console.error("[Blog] Error fetching recent posts:", error);
991
+ return [];
992
+ }
993
+ }
994
+ async function fetchCategories2(apiUrl, apiKey) {
995
+ try {
996
+ const response = await fetch(`${apiUrl}/public/blog/categories`, {
997
+ headers: { "x-api-key": apiKey },
998
+ next: { revalidate: 300 }
999
+ });
1000
+ if (!response.ok) return [];
1001
+ const data = await response.json();
1002
+ return data.categories || [];
1003
+ } catch (error) {
1004
+ console.error("[Blog] Error fetching categories:", error);
1005
+ return [];
1006
+ }
1007
+ }
1008
+ async function fetchTags(apiUrl, apiKey) {
1009
+ try {
1010
+ const response = await fetch(`${apiUrl}/public/blog/tags`, {
1011
+ headers: { "x-api-key": apiKey },
1012
+ next: { revalidate: 300 }
1013
+ });
1014
+ if (!response.ok) return [];
1015
+ const data = await response.json();
1016
+ return data.tags || [];
1017
+ } catch (error) {
1018
+ console.error("[Blog] Error fetching tags:", error);
1019
+ return [];
1020
+ }
1021
+ }
1022
+ async function BlogSidebar({
1023
+ apiUrl = process.env.NEXT_PUBLIC_UPTRADE_API_URL || "https://api.uptrademedia.com",
1024
+ apiKey = process.env.NEXT_PUBLIC_UPTRADE_API_KEY || "",
1025
+ showCategories = true,
1026
+ showRecentPosts = true,
1027
+ recentPostsCount = 5,
1028
+ showTags = true,
1029
+ showSearch = true,
1030
+ basePath = "/blog",
1031
+ className,
1032
+ currentCategory,
1033
+ children
1034
+ }) {
1035
+ if (!apiKey) {
1036
+ console.warn("[Blog] No API key configured for sidebar");
1037
+ return null;
1038
+ }
1039
+ const [categories, recentPosts, tags] = await Promise.all([
1040
+ showCategories ? fetchCategories2(apiUrl, apiKey) : Promise.resolve([]),
1041
+ showRecentPosts ? fetchRecentPosts(apiUrl, apiKey, recentPostsCount) : Promise.resolve([]),
1042
+ showTags ? fetchTags(apiUrl, apiKey) : Promise.resolve([])
1043
+ ]);
1044
+ return /* @__PURE__ */ jsxRuntime.jsxs("aside", { className, style: { display: "flex", flexDirection: "column", gap: 32 }, children: [
1045
+ showSearch && /* @__PURE__ */ jsxRuntime.jsx(SearchWidget, { basePath }),
1046
+ showCategories && categories.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
1047
+ CategoriesWidget,
1048
+ {
1049
+ categories,
1050
+ basePath,
1051
+ currentCategory
1052
+ }
1053
+ ),
1054
+ showRecentPosts && recentPosts.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(RecentPostsWidget, { posts: recentPosts, basePath }),
1055
+ showTags && tags.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(TagsWidget, { tags, basePath }),
1056
+ children
1057
+ ] });
1058
+ }
1059
+ function SearchWidget({ basePath }) {
1060
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: widgetStyle, children: [
1061
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { style: widgetTitleStyle, children: "Search" }),
1062
+ /* @__PURE__ */ jsxRuntime.jsx("form", { action: basePath, method: "get", children: /* @__PURE__ */ jsxRuntime.jsx(
1063
+ "input",
1064
+ {
1065
+ type: "search",
1066
+ name: "search",
1067
+ placeholder: "Search posts...",
1068
+ style: {
1069
+ width: "100%",
1070
+ padding: "10px 12px",
1071
+ border: "1px solid #e5e7eb",
1072
+ borderRadius: 8,
1073
+ fontSize: 14
1074
+ }
1075
+ }
1076
+ ) })
1077
+ ] });
1078
+ }
1079
+ function CategoriesWidget({
1080
+ categories,
1081
+ basePath,
1082
+ currentCategory
1083
+ }) {
1084
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: widgetStyle, children: [
1085
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { style: widgetTitleStyle, children: "Categories" }),
1086
+ /* @__PURE__ */ jsxRuntime.jsxs("ul", { style: { listStyle: "none", margin: 0, padding: 0 }, children: [
1087
+ /* @__PURE__ */ jsxRuntime.jsx("li", { style: { marginBottom: 8 }, children: /* @__PURE__ */ jsxRuntime.jsx(
1088
+ "a",
1089
+ {
1090
+ href: basePath,
1091
+ style: {
1092
+ ...categoryLinkStyle,
1093
+ fontWeight: !currentCategory ? 600 : 400,
1094
+ color: !currentCategory ? "#3b82f6" : "#374151"
1095
+ },
1096
+ children: "All Posts"
1097
+ }
1098
+ ) }),
1099
+ categories.map((cat) => /* @__PURE__ */ jsxRuntime.jsx("li", { style: { marginBottom: 8 }, children: /* @__PURE__ */ jsxRuntime.jsxs(
1100
+ "a",
1101
+ {
1102
+ href: `${basePath}?category=${cat.slug}`,
1103
+ style: {
1104
+ ...categoryLinkStyle,
1105
+ fontWeight: currentCategory === cat.slug ? 600 : 400,
1106
+ color: currentCategory === cat.slug ? "#3b82f6" : "#374151"
1107
+ },
1108
+ children: [
1109
+ cat.name,
1110
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { color: "#9ca3af", marginLeft: 8 }, children: [
1111
+ "(",
1112
+ cat.post_count,
1113
+ ")"
1114
+ ] })
1115
+ ]
1116
+ }
1117
+ ) }, cat.slug))
1118
+ ] })
1119
+ ] });
1120
+ }
1121
+ function RecentPostsWidget({
1122
+ posts,
1123
+ basePath
1124
+ }) {
1125
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: widgetStyle, children: [
1126
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { style: widgetTitleStyle, children: "Recent Posts" }),
1127
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0 }, children: posts.map((post) => {
1128
+ const date = post.published_at ? new Date(post.published_at).toLocaleDateString("en-US", {
1129
+ month: "short",
1130
+ day: "numeric"
1131
+ }) : null;
1132
+ return /* @__PURE__ */ jsxRuntime.jsx(
1133
+ "li",
1134
+ {
1135
+ style: {
1136
+ marginBottom: 16,
1137
+ paddingBottom: 16,
1138
+ borderBottom: "1px solid #e5e7eb"
1139
+ },
1140
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 12 }, children: [
1141
+ post.featured_image && /* @__PURE__ */ jsxRuntime.jsx("a", { href: `${basePath}/${post.slug}`, children: /* @__PURE__ */ jsxRuntime.jsx(
1142
+ "img",
1143
+ {
1144
+ src: post.featured_image,
1145
+ alt: "",
1146
+ style: {
1147
+ width: 64,
1148
+ height: 48,
1149
+ objectFit: "cover",
1150
+ borderRadius: 6,
1151
+ flexShrink: 0
1152
+ }
1153
+ }
1154
+ ) }),
1155
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
1156
+ /* @__PURE__ */ jsxRuntime.jsx(
1157
+ "a",
1158
+ {
1159
+ href: `${basePath}/${post.slug}`,
1160
+ style: {
1161
+ fontSize: 14,
1162
+ fontWeight: 500,
1163
+ color: "#374151",
1164
+ textDecoration: "none",
1165
+ display: "-webkit-box",
1166
+ WebkitLineClamp: 2,
1167
+ WebkitBoxOrient: "vertical",
1168
+ overflow: "hidden"
1169
+ },
1170
+ children: post.title
1171
+ }
1172
+ ),
1173
+ date && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12, color: "#9ca3af", display: "block", marginTop: 4 }, children: date })
1174
+ ] })
1175
+ ] })
1176
+ },
1177
+ post.id
1178
+ );
1179
+ }) })
1180
+ ] });
1181
+ }
1182
+ function TagsWidget({
1183
+ tags,
1184
+ basePath
1185
+ }) {
1186
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: widgetStyle, children: [
1187
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { style: widgetTitleStyle, children: "Popular Tags" }),
1188
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 8 }, children: tags.slice(0, 15).map((tag) => /* @__PURE__ */ jsxRuntime.jsx(
1189
+ "a",
1190
+ {
1191
+ href: `${basePath}?tag=${tag.slug}`,
1192
+ style: {
1193
+ padding: "4px 10px",
1194
+ backgroundColor: "#f3f4f6",
1195
+ borderRadius: 9999,
1196
+ fontSize: 12,
1197
+ color: "#374151",
1198
+ textDecoration: "none",
1199
+ transition: "background-color 0.2s"
1200
+ },
1201
+ children: tag.name
1202
+ },
1203
+ tag.slug
1204
+ )) })
1205
+ ] });
1206
+ }
1207
+ function NewsletterWidget({
1208
+ title = "Subscribe to Our Newsletter",
1209
+ description = "Get the latest posts delivered straight to your inbox.",
1210
+ buttonText = "Subscribe"
1211
+ }) {
1212
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...widgetStyle, backgroundColor: "#eff6ff" }, children: [
1213
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { style: { ...widgetTitleStyle, color: "#1e40af" }, children: title }),
1214
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: 14, color: "#6b7280", marginBottom: 16 }, children: description }),
1215
+ /* @__PURE__ */ jsxRuntime.jsxs(
1216
+ "form",
1217
+ {
1218
+ onSubmit: (e) => {
1219
+ e.preventDefault();
1220
+ },
1221
+ style: { display: "flex", gap: 8 },
1222
+ children: [
1223
+ /* @__PURE__ */ jsxRuntime.jsx(
1224
+ "input",
1225
+ {
1226
+ type: "email",
1227
+ name: "email",
1228
+ placeholder: "Enter your email",
1229
+ required: true,
1230
+ style: {
1231
+ flex: 1,
1232
+ padding: "10px 12px",
1233
+ border: "1px solid #bfdbfe",
1234
+ borderRadius: 8,
1235
+ fontSize: 14
1236
+ }
1237
+ }
1238
+ ),
1239
+ /* @__PURE__ */ jsxRuntime.jsx(
1240
+ "button",
1241
+ {
1242
+ type: "submit",
1243
+ style: {
1244
+ padding: "10px 16px",
1245
+ backgroundColor: "#3b82f6",
1246
+ color: "#fff",
1247
+ border: "none",
1248
+ borderRadius: 8,
1249
+ fontSize: 14,
1250
+ fontWeight: 500,
1251
+ cursor: "pointer"
1252
+ },
1253
+ children: buttonText
1254
+ }
1255
+ )
1256
+ ]
1257
+ }
1258
+ )
1259
+ ] });
1260
+ }
1261
+ var widgetStyle = {
1262
+ padding: 20,
1263
+ backgroundColor: "#f9fafb",
1264
+ borderRadius: 12
1265
+ };
1266
+ var widgetTitleStyle = {
1267
+ margin: "0 0 16px",
1268
+ fontSize: 16,
1269
+ fontWeight: 600,
1270
+ color: "#111827"
1271
+ };
1272
+ var categoryLinkStyle = {
1273
+ display: "flex",
1274
+ alignItems: "center",
1275
+ fontSize: 14,
1276
+ textDecoration: "none"
1277
+ };
1278
+ async function BlogLayout({
1279
+ apiUrl = process.env.NEXT_PUBLIC_UPTRADE_API_URL || "https://api.uptrademedia.com",
1280
+ apiKey = process.env.NEXT_PUBLIC_UPTRADE_API_KEY || "",
1281
+ layout = "sidebar-right",
1282
+ showSidebar = true,
1283
+ sidebarProps = {},
1284
+ hero,
1285
+ maxWidth = 1280,
1286
+ basePath = "/blog",
1287
+ className,
1288
+ currentCategory,
1289
+ children
1290
+ }) {
1291
+ const hasSidebar = showSidebar && layout !== "full-width";
1292
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
1293
+ hero && /* @__PURE__ */ jsxRuntime.jsx(
1294
+ "section",
1295
+ {
1296
+ style: {
1297
+ padding: "60px 20px",
1298
+ backgroundColor: hero.backgroundColor || "#1e3a5f",
1299
+ backgroundImage: hero.backgroundImage ? `url(${hero.backgroundImage})` : void 0,
1300
+ backgroundSize: "cover",
1301
+ backgroundPosition: "center",
1302
+ color: "#fff",
1303
+ textAlign: "center"
1304
+ },
1305
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { maxWidth, margin: "0 auto" }, children: [
1306
+ hero.title && /* @__PURE__ */ jsxRuntime.jsx(
1307
+ "h1",
1308
+ {
1309
+ style: {
1310
+ fontSize: "clamp(32px, 5vw, 48px)",
1311
+ fontWeight: 700,
1312
+ marginBottom: 16
1313
+ },
1314
+ children: hero.title
1315
+ }
1316
+ ),
1317
+ hero.subtitle && /* @__PURE__ */ jsxRuntime.jsx(
1318
+ "p",
1319
+ {
1320
+ style: {
1321
+ fontSize: "clamp(16px, 2vw, 20px)",
1322
+ opacity: 0.9,
1323
+ maxWidth: 600,
1324
+ margin: "0 auto"
1325
+ },
1326
+ children: hero.subtitle
1327
+ }
1328
+ )
1329
+ ] })
1330
+ }
1331
+ ),
1332
+ /* @__PURE__ */ jsxRuntime.jsx(
1333
+ "div",
1334
+ {
1335
+ style: {
1336
+ maxWidth,
1337
+ margin: "0 auto",
1338
+ padding: "40px 20px"
1339
+ },
1340
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
1341
+ "div",
1342
+ {
1343
+ style: {
1344
+ display: hasSidebar ? "grid" : "block",
1345
+ gridTemplateColumns: hasSidebar ? layout === "sidebar-left" ? "300px 1fr" : "1fr 300px" : void 0,
1346
+ gap: 48
1347
+ },
1348
+ children: [
1349
+ hasSidebar && layout === "sidebar-left" && /* @__PURE__ */ jsxRuntime.jsx(
1350
+ BlogSidebar,
1351
+ {
1352
+ apiUrl,
1353
+ apiKey,
1354
+ basePath,
1355
+ currentCategory,
1356
+ ...sidebarProps
1357
+ }
1358
+ ),
1359
+ /* @__PURE__ */ jsxRuntime.jsx("main", { style: { minWidth: 0 }, children }),
1360
+ hasSidebar && layout === "sidebar-right" && /* @__PURE__ */ jsxRuntime.jsx(
1361
+ BlogSidebar,
1362
+ {
1363
+ apiUrl,
1364
+ apiKey,
1365
+ basePath,
1366
+ currentCategory,
1367
+ ...sidebarProps
1368
+ }
1369
+ )
1370
+ ]
1371
+ }
1372
+ )
1373
+ }
1374
+ )
1375
+ ] });
1376
+ }
1377
+ async function BlogPage({ listComponent, ...layoutProps }) {
1378
+ return /* @__PURE__ */ jsxRuntime.jsx(BlogLayout, { ...layoutProps, children: listComponent });
1379
+ }
1380
+ async function BlogPostPage({ postComponent, ...layoutProps }) {
1381
+ return /* @__PURE__ */ jsxRuntime.jsx(BlogLayout, { ...layoutProps, showSidebar: false, layout: "full-width", children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { maxWidth: 800, margin: "0 auto" }, children: postComponent }) });
1382
+ }
1383
+ async function CategoryPage({
1384
+ category,
1385
+ categoryName,
1386
+ listComponent,
1387
+ hero,
1388
+ ...layoutProps
1389
+ }) {
1390
+ const categoryHero = hero || {
1391
+ title: categoryName || category,
1392
+ subtitle: `Browse all posts in ${categoryName || category}`,
1393
+ backgroundColor: "#1e3a5f"
1394
+ };
1395
+ return /* @__PURE__ */ jsxRuntime.jsx(BlogLayout, { ...layoutProps, hero: categoryHero, currentCategory: category, children: listComponent });
1396
+ }
1397
+ function AuthorCard({ author, showBio = true, showSocial = true, className }) {
1398
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { display: "flex", gap: 16, alignItems: "flex-start" }, children: [
1399
+ author.avatar_url && /* @__PURE__ */ jsxRuntime.jsx(
1400
+ "img",
1401
+ {
1402
+ src: author.avatar_url,
1403
+ alt: author.name,
1404
+ style: {
1405
+ width: 64,
1406
+ height: 64,
1407
+ borderRadius: "50%",
1408
+ objectFit: "cover"
1409
+ }
1410
+ }
1411
+ ),
1412
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1413
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { style: { margin: 0 }, children: author.name }),
1414
+ showBio && author.bio && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "4px 0", color: "#6b7280", fontSize: 14 }, children: author.bio }),
1415
+ showSocial && author.social_links && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 12, marginTop: 8 }, children: [
1416
+ author.social_links.twitter && /* @__PURE__ */ jsxRuntime.jsx("a", { href: `https://twitter.com/${author.social_links.twitter}`, target: "_blank", rel: "noopener noreferrer", children: "Twitter" }),
1417
+ author.social_links.linkedin && /* @__PURE__ */ jsxRuntime.jsx("a", { href: author.social_links.linkedin, target: "_blank", rel: "noopener noreferrer", children: "LinkedIn" }),
1418
+ author.social_links.github && /* @__PURE__ */ jsxRuntime.jsx("a", { href: `https://github.com/${author.social_links.github}`, target: "_blank", rel: "noopener noreferrer", children: "GitHub" })
1419
+ ] })
1420
+ ] })
1421
+ ] });
1422
+ }
1423
+ async function fetchRelatedPosts2(apiUrl, apiKey, currentPostId, limit) {
1424
+ try {
1425
+ const response = await fetch(`${apiUrl}/api/public/blog/related`, {
1426
+ method: "POST",
1427
+ headers: {
1428
+ "Content-Type": "application/json",
1429
+ "x-api-key": apiKey
1430
+ },
1431
+ body: JSON.stringify({
1432
+ currentPostId,
1433
+ limit
1434
+ })
1435
+ });
1436
+ if (!response.ok) {
1437
+ console.error("Failed to fetch related posts:", response.statusText);
1438
+ return [];
1439
+ }
1440
+ const data = await response.json();
1441
+ return data.posts || [];
1442
+ } catch (error) {
1443
+ console.error("Failed to fetch related posts:", error);
1444
+ return [];
1445
+ }
1446
+ }
1447
+ async function RelatedPosts({
1448
+ apiUrl = process.env.NEXT_PUBLIC_UPTRADE_API_URL || "https://api.uptrademedia.com",
1449
+ apiKey = process.env.NEXT_PUBLIC_UPTRADE_API_KEY || "",
1450
+ currentPostId,
1451
+ limit = 3,
1452
+ className,
1453
+ renderItem
1454
+ }) {
1455
+ if (!apiKey) {
1456
+ console.warn("[Blog] No API key configured for RelatedPosts");
1457
+ return null;
1458
+ }
1459
+ const posts = await fetchRelatedPosts2(apiUrl, apiKey, currentPostId, limit);
1460
+ if (posts.length === 0) return null;
1461
+ return /* @__PURE__ */ jsxRuntime.jsxs("section", { className, children: [
1462
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { style: { marginBottom: 16 }, children: "Related Posts" }),
1463
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "grid", gap: 16 }, children: posts.map(
1464
+ (post) => renderItem ? renderItem(post) : /* @__PURE__ */ jsxRuntime.jsxs("article", { style: { borderBottom: "1px solid #e5e7eb", paddingBottom: 16 }, children: [
1465
+ post.featured_image && /* @__PURE__ */ jsxRuntime.jsx(
1466
+ "img",
1467
+ {
1468
+ src: post.featured_image,
1469
+ alt: post.title,
1470
+ style: {
1471
+ width: "100%",
1472
+ height: 120,
1473
+ objectFit: "cover",
1474
+ borderRadius: 8,
1475
+ marginBottom: 8
1476
+ }
1477
+ }
1478
+ ),
1479
+ /* @__PURE__ */ jsxRuntime.jsx("a", { href: `/blog/${post.slug}`, style: { textDecoration: "none" }, children: /* @__PURE__ */ jsxRuntime.jsx("h4", { style: { margin: 0, color: "inherit" }, children: post.title }) }),
1480
+ post.excerpt && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { margin: "4px 0 0", fontSize: 14, color: "#6b7280" }, children: post.excerpt })
1481
+ ] }, post.id)
1482
+ ) })
1483
+ ] });
1484
+ }
1485
+ function parseHeadings(content) {
1486
+ const headingRegex = /<h([2-4])[^>]*id="([^"]*)"[^>]*>(.*?)<\/h[2-4]>/gi;
1487
+ const items = [];
1488
+ let match;
1489
+ while ((match = headingRegex.exec(content)) !== null) {
1490
+ items.push({
1491
+ level: parseInt(match[1]),
1492
+ id: match[2],
1493
+ text: match[3].replace(/<[^>]*>/g, "")
1494
+ // Strip any nested HTML
1495
+ });
1496
+ }
1497
+ return items;
1498
+ }
1499
+ function TableOfContents({
1500
+ content,
1501
+ className,
1502
+ maxDepth = 3
1503
+ }) {
1504
+ const [activeId, setActiveId] = React.useState("");
1505
+ const items = parseHeadings(content).filter((item) => item.level <= maxDepth);
1506
+ React.useEffect(() => {
1507
+ if (typeof window === "undefined") return;
1508
+ const observer = new IntersectionObserver(
1509
+ (entries) => {
1510
+ entries.forEach((entry) => {
1511
+ if (entry.isIntersecting) {
1512
+ setActiveId(entry.target.id);
1513
+ }
1514
+ });
1515
+ },
1516
+ {
1517
+ rootMargin: "-20% 0% -35% 0%",
1518
+ threshold: 0
1519
+ }
1520
+ );
1521
+ items.forEach((item) => {
1522
+ const element = document.getElementById(item.id);
1523
+ if (element) {
1524
+ observer.observe(element);
1525
+ }
1526
+ });
1527
+ return () => observer.disconnect();
1528
+ }, [items]);
1529
+ if (items.length === 0) return null;
1530
+ const handleClick = (id) => {
1531
+ const element = document.getElementById(id);
1532
+ if (element) {
1533
+ element.scrollIntoView({ behavior: "smooth" });
1534
+ }
1535
+ };
1536
+ return /* @__PURE__ */ jsxRuntime.jsxs("nav", { className, "aria-label": "Table of contents", children: [
1537
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { style: { margin: "0 0 12px", fontSize: 14, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.05em" }, children: "On This Page" }),
1538
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0 }, children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
1539
+ "li",
1540
+ {
1541
+ style: {
1542
+ paddingLeft: (item.level - 2) * 12,
1543
+ marginBottom: 8
1544
+ },
1545
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1546
+ "button",
1547
+ {
1548
+ onClick: () => handleClick(item.id),
1549
+ style: {
1550
+ all: "unset",
1551
+ cursor: "pointer",
1552
+ fontSize: 14,
1553
+ color: activeId === item.id ? "#2563eb" : "#6b7280",
1554
+ fontWeight: activeId === item.id ? 500 : 400,
1555
+ transition: "color 0.2s"
1556
+ },
1557
+ children: item.text
1558
+ }
1559
+ )
1560
+ },
1561
+ item.id
1562
+ )) })
1563
+ ] });
1564
+ }
1565
+
1566
+ exports.AuthorCard = AuthorCard;
1567
+ exports.BlogLayout = BlogLayout;
1568
+ exports.BlogList = BlogList;
1569
+ exports.BlogPage = BlogPage;
1570
+ exports.BlogPost = BlogPost;
1571
+ exports.BlogPostPage = BlogPostPage;
1572
+ exports.BlogSidebar = BlogSidebar;
1573
+ exports.CategoryPage = CategoryPage;
1574
+ exports.NewsletterWidget = NewsletterWidget;
1575
+ exports.RelatedPosts = RelatedPosts;
1576
+ exports.TableOfContents = TableOfContents;
1577
+ //# sourceMappingURL=index.js.map
1578
+ //# sourceMappingURL=index.js.map