@sonordev/agency-site-kit 0.3.1 → 0.4.1

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 (374) hide show
  1. package/README.md +302 -0
  2. package/bin/setup.mjs +79 -0
  3. package/dist/{chunk-RXBK2EOE.js → chunk-4IES23GV.js} +3 -3
  4. package/dist/{chunk-RXBK2EOE.js.map → chunk-4IES23GV.js.map} +1 -1
  5. package/dist/{chunk-WNR4KNG4.cjs → chunk-5MEZU3OG.cjs} +4 -4
  6. package/dist/{chunk-WNR4KNG4.cjs.map → chunk-5MEZU3OG.cjs.map} +1 -1
  7. package/dist/chunk-7D4H36UF.js +13 -0
  8. package/dist/chunk-7D4H36UF.js.map +1 -0
  9. package/dist/chunk-7ZHRMWJU.cjs +306 -0
  10. package/dist/chunk-7ZHRMWJU.cjs.map +1 -0
  11. package/dist/chunk-CVT7I5BQ.js +71 -0
  12. package/dist/chunk-CVT7I5BQ.js.map +1 -0
  13. package/dist/chunk-HQGAX2LI.cjs +8 -0
  14. package/dist/chunk-HQGAX2LI.cjs.map +1 -0
  15. package/dist/chunk-K2BGTDSN.js +45 -0
  16. package/dist/chunk-K2BGTDSN.js.map +1 -0
  17. package/dist/chunk-KXLROAO5.js +291 -0
  18. package/dist/chunk-KXLROAO5.js.map +1 -0
  19. package/dist/chunk-L4EOQVRJ.js +6 -0
  20. package/dist/chunk-L4EOQVRJ.js.map +1 -0
  21. package/dist/chunk-NI4FVCLS.cjs +32 -0
  22. package/dist/chunk-NI4FVCLS.cjs.map +1 -0
  23. package/dist/chunk-NLGUPJZA.js +507 -0
  24. package/dist/chunk-NLGUPJZA.js.map +1 -0
  25. package/dist/chunk-QDXZ27R7.js +33 -0
  26. package/dist/chunk-QDXZ27R7.js.map +1 -0
  27. package/dist/chunk-QGSW43TM.cjs +538 -0
  28. package/dist/chunk-QGSW43TM.cjs.map +1 -0
  29. package/dist/{chunk-TVFXN6W6.js → chunk-QL6KVIFR.js} +8 -4
  30. package/dist/chunk-QL6KVIFR.js.map +1 -0
  31. package/dist/chunk-RWQ675N6.js +165 -0
  32. package/dist/chunk-RWQ675N6.js.map +1 -0
  33. package/dist/chunk-UXUU7FVT.cjs +171 -0
  34. package/dist/chunk-UXUU7FVT.cjs.map +1 -0
  35. package/dist/chunk-XJ434N7I.js +30 -0
  36. package/dist/chunk-XJ434N7I.js.map +1 -0
  37. package/dist/{chunk-EE75WRCM.cjs → chunk-XOWSXZYW.cjs} +8 -4
  38. package/dist/chunk-XOWSXZYW.cjs.map +1 -0
  39. package/dist/chunk-ZBPF7TLZ.cjs +16 -0
  40. package/dist/chunk-ZBPF7TLZ.cjs.map +1 -0
  41. package/dist/chunk-ZINKVJQU.js +67 -0
  42. package/dist/chunk-ZINKVJQU.js.map +1 -0
  43. package/dist/index.cjs +53 -30
  44. package/dist/index.cjs.map +1 -1
  45. package/dist/index.d.cts +17 -9
  46. package/dist/index.d.ts +17 -9
  47. package/dist/index.js +8 -9
  48. package/dist/index.js.map +1 -1
  49. package/dist/layout/index.cjs +3 -3
  50. package/dist/layout/index.d.cts +1 -1
  51. package/dist/layout/index.d.ts +1 -1
  52. package/dist/layout/index.js +2 -2
  53. package/dist/portfolio/client.cjs +376 -12
  54. package/dist/portfolio/client.cjs.map +1 -1
  55. package/dist/portfolio/client.d.cts +27 -85
  56. package/dist/portfolio/client.d.ts +27 -85
  57. package/dist/portfolio/client.js +182 -4
  58. package/dist/portfolio/client.js.map +1 -1
  59. package/dist/portfolio/components/PortfolioAnalytics.cjs +87 -0
  60. package/dist/portfolio/components/PortfolioAnalytics.cjs.map +1 -0
  61. package/dist/portfolio/components/PortfolioAnalytics.d.cts +5 -0
  62. package/dist/portfolio/components/PortfolioAnalytics.d.ts +5 -0
  63. package/dist/portfolio/components/PortfolioAnalytics.js +9 -0
  64. package/dist/portfolio/components/PortfolioAnalytics.js.map +1 -0
  65. package/dist/portfolio/components/PortfolioErrorFallback.cjs +65 -0
  66. package/dist/portfolio/components/PortfolioErrorFallback.cjs.map +1 -0
  67. package/dist/portfolio/components/PortfolioErrorFallback.d.cts +22 -0
  68. package/dist/portfolio/components/PortfolioErrorFallback.d.ts +22 -0
  69. package/dist/portfolio/components/PortfolioErrorFallback.js +9 -0
  70. package/dist/portfolio/components/PortfolioErrorFallback.js.map +1 -0
  71. package/dist/portfolio/components/PortfolioLeadCTA.cjs +91 -0
  72. package/dist/portfolio/components/PortfolioLeadCTA.cjs.map +1 -0
  73. package/dist/portfolio/components/PortfolioLeadCTA.d.cts +34 -0
  74. package/dist/portfolio/components/PortfolioLeadCTA.d.ts +34 -0
  75. package/dist/portfolio/components/PortfolioLeadCTA.js +9 -0
  76. package/dist/portfolio/components/PortfolioLeadCTA.js.map +1 -0
  77. package/dist/portfolio/index.cjs +43 -19
  78. package/dist/portfolio/index.d.cts +210 -7
  79. package/dist/portfolio/index.d.ts +210 -7
  80. package/dist/portfolio/index.js +7 -7
  81. package/dist/portfolio/primitives/AnimatedCounter.cjs +88 -0
  82. package/dist/portfolio/primitives/AnimatedCounter.cjs.map +1 -0
  83. package/dist/portfolio/primitives/AnimatedCounter.d.cts +22 -0
  84. package/dist/portfolio/primitives/AnimatedCounter.d.ts +22 -0
  85. package/dist/portfolio/primitives/AnimatedCounter.js +68 -0
  86. package/dist/portfolio/primitives/AnimatedCounter.js.map +1 -0
  87. package/dist/portfolio/primitives/AnnotatedImage.cjs +320 -0
  88. package/dist/portfolio/primitives/AnnotatedImage.cjs.map +1 -0
  89. package/dist/portfolio/primitives/AnnotatedImage.d.cts +18 -0
  90. package/dist/portfolio/primitives/AnnotatedImage.d.ts +18 -0
  91. package/dist/portfolio/primitives/AnnotatedImage.js +264 -0
  92. package/dist/portfolio/primitives/AnnotatedImage.js.map +1 -0
  93. package/dist/portfolio/primitives/BeforeAfterSlider.cjs +348 -0
  94. package/dist/portfolio/primitives/BeforeAfterSlider.cjs.map +1 -0
  95. package/dist/portfolio/primitives/BeforeAfterSlider.d.cts +13 -0
  96. package/dist/portfolio/primitives/BeforeAfterSlider.d.ts +13 -0
  97. package/dist/portfolio/primitives/BeforeAfterSlider.js +292 -0
  98. package/dist/portfolio/primitives/BeforeAfterSlider.js.map +1 -0
  99. package/dist/portfolio/primitives/DeviceTrifolio.cjs +298 -0
  100. package/dist/portfolio/primitives/DeviceTrifolio.cjs.map +1 -0
  101. package/dist/portfolio/primitives/DeviceTrifolio.d.cts +14 -0
  102. package/dist/portfolio/primitives/DeviceTrifolio.d.ts +14 -0
  103. package/dist/portfolio/primitives/DeviceTrifolio.js +242 -0
  104. package/dist/portfolio/primitives/DeviceTrifolio.js.map +1 -0
  105. package/dist/portfolio/primitives/FrequencyBarSkeleton.cjs +88 -0
  106. package/dist/portfolio/primitives/FrequencyBarSkeleton.cjs.map +1 -0
  107. package/dist/portfolio/primitives/FrequencyBarSkeleton.d.cts +10 -0
  108. package/dist/portfolio/primitives/FrequencyBarSkeleton.d.ts +10 -0
  109. package/dist/portfolio/primitives/FrequencyBarSkeleton.js +68 -0
  110. package/dist/portfolio/primitives/FrequencyBarSkeleton.js.map +1 -0
  111. package/dist/portfolio/primitives/GlassCard.cjs +45 -0
  112. package/dist/portfolio/primitives/GlassCard.cjs.map +1 -0
  113. package/dist/portfolio/primitives/GlassCard.d.cts +11 -0
  114. package/dist/portfolio/primitives/GlassCard.d.ts +11 -0
  115. package/dist/portfolio/primitives/GlassCard.js +43 -0
  116. package/dist/portfolio/primitives/GlassCard.js.map +1 -0
  117. package/dist/portfolio/primitives/MetricBadge.cjs +74 -0
  118. package/dist/portfolio/primitives/MetricBadge.cjs.map +1 -0
  119. package/dist/portfolio/primitives/MetricBadge.d.cts +9 -0
  120. package/dist/portfolio/primitives/MetricBadge.d.ts +9 -0
  121. package/dist/portfolio/primitives/MetricBadge.js +54 -0
  122. package/dist/portfolio/primitives/MetricBadge.js.map +1 -0
  123. package/dist/portfolio/primitives/SVGChart.cjs +316 -0
  124. package/dist/portfolio/primitives/SVGChart.cjs.map +1 -0
  125. package/dist/portfolio/primitives/SVGChart.d.cts +18 -0
  126. package/dist/portfolio/primitives/SVGChart.d.ts +18 -0
  127. package/dist/portfolio/primitives/SVGChart.js +296 -0
  128. package/dist/portfolio/primitives/SVGChart.js.map +1 -0
  129. package/dist/portfolio/primitives/ScrollReveal.cjs +97 -0
  130. package/dist/portfolio/primitives/ScrollReveal.cjs.map +1 -0
  131. package/dist/portfolio/primitives/ScrollReveal.d.cts +27 -0
  132. package/dist/portfolio/primitives/ScrollReveal.d.ts +27 -0
  133. package/dist/portfolio/primitives/ScrollReveal.js +77 -0
  134. package/dist/portfolio/primitives/ScrollReveal.js.map +1 -0
  135. package/dist/portfolio/primitives/SplitHeadline.cjs +107 -0
  136. package/dist/portfolio/primitives/SplitHeadline.cjs.map +1 -0
  137. package/dist/portfolio/primitives/SplitHeadline.d.cts +24 -0
  138. package/dist/portfolio/primitives/SplitHeadline.d.ts +24 -0
  139. package/dist/portfolio/primitives/SplitHeadline.js +87 -0
  140. package/dist/portfolio/primitives/SplitHeadline.js.map +1 -0
  141. package/dist/portfolio/sections/BeforeAfterSection.cjs +271 -0
  142. package/dist/portfolio/sections/BeforeAfterSection.cjs.map +1 -0
  143. package/dist/portfolio/sections/BeforeAfterSection.d.cts +9 -0
  144. package/dist/portfolio/sections/BeforeAfterSection.d.ts +9 -0
  145. package/dist/{BeforeAfterSection-6BHFLY4Y.js → portfolio/sections/BeforeAfterSection.js} +66 -27
  146. package/dist/portfolio/sections/BeforeAfterSection.js.map +1 -0
  147. package/dist/portfolio/sections/CTASection.cjs +123 -0
  148. package/dist/portfolio/sections/CTASection.cjs.map +1 -0
  149. package/dist/portfolio/sections/CTASection.d.cts +9 -0
  150. package/dist/portfolio/sections/CTASection.d.ts +9 -0
  151. package/dist/portfolio/sections/CTASection.js +93 -0
  152. package/dist/portfolio/sections/CTASection.js.map +1 -0
  153. package/dist/{ChallengesSection-IZ3DHECS.cjs → portfolio/sections/ChallengesSection.cjs} +13 -7
  154. package/dist/portfolio/sections/ChallengesSection.cjs.map +1 -0
  155. package/dist/portfolio/sections/ChallengesSection.d.cts +9 -0
  156. package/dist/portfolio/sections/ChallengesSection.d.ts +9 -0
  157. package/dist/{ChallengesSection-GEQGVSJN.js → portfolio/sections/ChallengesSection.js} +6 -5
  158. package/dist/portfolio/sections/ChallengesSection.js.map +1 -0
  159. package/dist/portfolio/sections/ConversionFunnelSection.cjs +263 -0
  160. package/dist/portfolio/sections/ConversionFunnelSection.cjs.map +1 -0
  161. package/dist/portfolio/sections/ConversionFunnelSection.d.cts +9 -0
  162. package/dist/portfolio/sections/ConversionFunnelSection.d.ts +9 -0
  163. package/dist/{ConversionFunnelSection-D3GE4NKE.js → portfolio/sections/ConversionFunnelSection.js} +60 -56
  164. package/dist/portfolio/sections/ConversionFunnelSection.js.map +1 -0
  165. package/dist/{DesignSystemSection-KXIQXITF.cjs → portfolio/sections/DesignSystemSection.cjs} +13 -7
  166. package/dist/portfolio/sections/DesignSystemSection.cjs.map +1 -0
  167. package/dist/portfolio/sections/DesignSystemSection.d.cts +32 -0
  168. package/dist/portfolio/sections/DesignSystemSection.d.ts +32 -0
  169. package/dist/{DesignSystemSection-2R5BRBGO.js → portfolio/sections/DesignSystemSection.js} +5 -4
  170. package/dist/portfolio/sections/DesignSystemSection.js.map +1 -0
  171. package/dist/{DetailsSection-TTUZAPZZ.cjs → portfolio/sections/DetailsSection.cjs} +12 -6
  172. package/dist/portfolio/sections/DetailsSection.cjs.map +1 -0
  173. package/dist/portfolio/sections/DetailsSection.d.cts +9 -0
  174. package/dist/portfolio/sections/DetailsSection.d.ts +9 -0
  175. package/dist/{DetailsSection-A6PZQUQL.js → portfolio/sections/DetailsSection.js} +5 -4
  176. package/dist/portfolio/sections/DetailsSection.js.map +1 -0
  177. package/dist/portfolio/sections/FeatureSpotlightSection.cjs +267 -0
  178. package/dist/portfolio/sections/FeatureSpotlightSection.cjs.map +1 -0
  179. package/dist/portfolio/sections/FeatureSpotlightSection.d.cts +9 -0
  180. package/dist/portfolio/sections/FeatureSpotlightSection.d.ts +9 -0
  181. package/dist/{FeatureSpotlightSection-B7P3JGNL.js → portfolio/sections/FeatureSpotlightSection.js} +39 -33
  182. package/dist/portfolio/sections/FeatureSpotlightSection.js.map +1 -0
  183. package/dist/portfolio/sections/GallerySection.cjs +321 -0
  184. package/dist/portfolio/sections/GallerySection.cjs.map +1 -0
  185. package/dist/portfolio/sections/GallerySection.d.cts +9 -0
  186. package/dist/portfolio/sections/GallerySection.d.ts +9 -0
  187. package/dist/{GallerySection-VMKORC47.js → portfolio/sections/GallerySection.js} +65 -18
  188. package/dist/portfolio/sections/GallerySection.js.map +1 -0
  189. package/dist/portfolio/sections/HeroSection.cjs +180 -0
  190. package/dist/portfolio/sections/HeroSection.cjs.map +1 -0
  191. package/dist/portfolio/sections/HeroSection.d.cts +15 -0
  192. package/dist/portfolio/sections/HeroSection.d.ts +15 -0
  193. package/dist/portfolio/sections/HeroSection.js +171 -0
  194. package/dist/portfolio/sections/HeroSection.js.map +1 -0
  195. package/dist/{MetricsTimelineSection-4L6DUHJ5.cjs → portfolio/sections/MetricsTimelineSection.cjs} +102 -61
  196. package/dist/portfolio/sections/MetricsTimelineSection.cjs.map +1 -0
  197. package/dist/portfolio/sections/MetricsTimelineSection.d.cts +9 -0
  198. package/dist/portfolio/sections/MetricsTimelineSection.d.ts +9 -0
  199. package/dist/{MetricsTimelineSection-6BT5GNFV.js → portfolio/sections/MetricsTimelineSection.js} +45 -29
  200. package/dist/portfolio/sections/MetricsTimelineSection.js.map +1 -0
  201. package/dist/portfolio/sections/PerformanceSection.cjs +336 -0
  202. package/dist/portfolio/sections/PerformanceSection.cjs.map +1 -0
  203. package/dist/portfolio/sections/PerformanceSection.d.cts +22 -0
  204. package/dist/portfolio/sections/PerformanceSection.d.ts +22 -0
  205. package/dist/{PerformanceSection-MGCEIXDX.js → portfolio/sections/PerformanceSection.js} +59 -104
  206. package/dist/portfolio/sections/PerformanceSection.js.map +1 -0
  207. package/dist/{ResultsSection-XLGMMQKY.cjs → portfolio/sections/ResultsSection.cjs} +23 -10
  208. package/dist/portfolio/sections/ResultsSection.cjs.map +1 -0
  209. package/dist/portfolio/sections/ResultsSection.d.cts +13 -0
  210. package/dist/portfolio/sections/ResultsSection.d.ts +13 -0
  211. package/dist/{ResultsSection-DFUJ5U6M.js → portfolio/sections/ResultsSection.js} +14 -7
  212. package/dist/portfolio/sections/ResultsSection.js.map +1 -0
  213. package/dist/portfolio/sections/ServicesSection.cjs +129 -0
  214. package/dist/portfolio/sections/ServicesSection.cjs.map +1 -0
  215. package/dist/portfolio/sections/ServicesSection.d.cts +9 -0
  216. package/dist/portfolio/sections/ServicesSection.d.ts +9 -0
  217. package/dist/portfolio/sections/ServicesSection.js +122 -0
  218. package/dist/portfolio/sections/ServicesSection.js.map +1 -0
  219. package/dist/{SiteArchitectureSection-J7BPBERH.cjs → portfolio/sections/SiteArchitectureSection.cjs} +117 -93
  220. package/dist/portfolio/sections/SiteArchitectureSection.cjs.map +1 -0
  221. package/dist/portfolio/sections/SiteArchitectureSection.d.cts +21 -0
  222. package/dist/portfolio/sections/SiteArchitectureSection.d.ts +21 -0
  223. package/dist/{SiteArchitectureSection-TE22OAWV.js → portfolio/sections/SiteArchitectureSection.js} +47 -48
  224. package/dist/portfolio/sections/SiteArchitectureSection.js.map +1 -0
  225. package/dist/{SpeedComparisonSection-EZKFQVGW.cjs → portfolio/sections/SpeedComparisonSection.cjs} +13 -7
  226. package/dist/portfolio/sections/SpeedComparisonSection.cjs.map +1 -0
  227. package/dist/portfolio/sections/SpeedComparisonSection.d.cts +20 -0
  228. package/dist/portfolio/sections/SpeedComparisonSection.d.ts +20 -0
  229. package/dist/{SpeedComparisonSection-Y3K7OFZQ.js → portfolio/sections/SpeedComparisonSection.js} +6 -5
  230. package/dist/portfolio/sections/SpeedComparisonSection.js.map +1 -0
  231. package/dist/portfolio/sections/StrategySection.cjs +233 -0
  232. package/dist/portfolio/sections/StrategySection.cjs.map +1 -0
  233. package/dist/portfolio/sections/StrategySection.d.cts +9 -0
  234. package/dist/portfolio/sections/StrategySection.d.ts +9 -0
  235. package/dist/{StrategySection-DI5RSCJU.js → portfolio/sections/StrategySection.js} +60 -26
  236. package/dist/portfolio/sections/StrategySection.js.map +1 -0
  237. package/dist/portfolio/sections/TeamSection.cjs +162 -0
  238. package/dist/portfolio/sections/TeamSection.cjs.map +1 -0
  239. package/dist/portfolio/sections/TeamSection.d.cts +9 -0
  240. package/dist/portfolio/sections/TeamSection.d.ts +9 -0
  241. package/dist/portfolio/sections/TeamSection.js +106 -0
  242. package/dist/portfolio/sections/TeamSection.js.map +1 -0
  243. package/dist/portfolio/sections/TechStackSection.cjs +106 -0
  244. package/dist/portfolio/sections/TechStackSection.cjs.map +1 -0
  245. package/dist/portfolio/sections/TechStackSection.d.cts +9 -0
  246. package/dist/portfolio/sections/TechStackSection.d.ts +9 -0
  247. package/dist/portfolio/sections/TechStackSection.js +99 -0
  248. package/dist/portfolio/sections/TechStackSection.js.map +1 -0
  249. package/dist/{TestimonialSection-XPTFUQIN.cjs → portfolio/sections/TestimonialSection.cjs} +47 -28
  250. package/dist/portfolio/sections/TestimonialSection.cjs.map +1 -0
  251. package/dist/portfolio/sections/TestimonialSection.d.cts +9 -0
  252. package/dist/portfolio/sections/TestimonialSection.d.ts +9 -0
  253. package/dist/{TestimonialSection-6RGSMXQB.js → portfolio/sections/TestimonialSection.js} +40 -27
  254. package/dist/portfolio/sections/TestimonialSection.js.map +1 -0
  255. package/dist/portfolio/sections/VideoSection.cjs +181 -0
  256. package/dist/portfolio/sections/VideoSection.cjs.map +1 -0
  257. package/dist/portfolio/sections/VideoSection.d.cts +9 -0
  258. package/dist/portfolio/sections/VideoSection.d.ts +9 -0
  259. package/dist/{VideoSection-4A2HC6K6.js → portfolio/sections/VideoSection.js} +21 -13
  260. package/dist/portfolio/sections/VideoSection.js.map +1 -0
  261. package/dist/portfolio/server.cjs +56 -144
  262. package/dist/portfolio/server.cjs.map +1 -1
  263. package/dist/portfolio/server.d.cts +157 -7
  264. package/dist/portfolio/server.d.ts +157 -7
  265. package/dist/portfolio/server.js +3 -142
  266. package/dist/portfolio/server.js.map +1 -1
  267. package/dist/preview.cjs +56 -0
  268. package/dist/preview.cjs.map +1 -0
  269. package/dist/preview.d.cts +31 -0
  270. package/dist/preview.d.ts +31 -0
  271. package/dist/preview.js +54 -0
  272. package/dist/preview.js.map +1 -0
  273. package/dist/{types-DL4t_Cfa.d.ts → types-0tVPy4pU.d.cts} +7 -1
  274. package/dist/{types-DL4t_Cfa.d.cts → types-0tVPy4pU.d.ts} +7 -1
  275. package/dist/types-D0nb6KAx.d.cts +299 -0
  276. package/dist/types-D0nb6KAx.d.ts +299 -0
  277. package/package.json +38 -14
  278. package/templates/api-portfolio-preview.ts +6 -0
  279. package/templates/api-revalidate.ts +5 -0
  280. package/templates/work-category-page.tsx +40 -0
  281. package/templates/work-error.tsx +3 -0
  282. package/templates/work-loading.tsx +1 -0
  283. package/templates/work-page.tsx +37 -0
  284. package/templates/work-slug-loading.tsx +1 -0
  285. package/templates/work-slug-page.tsx +41 -0
  286. package/dist/BeforeAfterSection-6BHFLY4Y.js.map +0 -1
  287. package/dist/BeforeAfterSection-JTORBR3A.cjs +0 -181
  288. package/dist/BeforeAfterSection-JTORBR3A.cjs.map +0 -1
  289. package/dist/CTASection-4JKLXEUF.cjs +0 -111
  290. package/dist/CTASection-4JKLXEUF.cjs.map +0 -1
  291. package/dist/CTASection-BJA72XIL.js +0 -106
  292. package/dist/CTASection-BJA72XIL.js.map +0 -1
  293. package/dist/ChallengesSection-GEQGVSJN.js.map +0 -1
  294. package/dist/ChallengesSection-IZ3DHECS.cjs.map +0 -1
  295. package/dist/ConversionFunnelSection-AUUSJ5HQ.cjs +0 -209
  296. package/dist/ConversionFunnelSection-AUUSJ5HQ.cjs.map +0 -1
  297. package/dist/ConversionFunnelSection-D3GE4NKE.js.map +0 -1
  298. package/dist/DesignSystemSection-2R5BRBGO.js.map +0 -1
  299. package/dist/DesignSystemSection-KXIQXITF.cjs.map +0 -1
  300. package/dist/DetailsSection-A6PZQUQL.js.map +0 -1
  301. package/dist/DetailsSection-TTUZAPZZ.cjs.map +0 -1
  302. package/dist/FeatureSpotlightSection-B7P3JGNL.js.map +0 -1
  303. package/dist/FeatureSpotlightSection-WRHXS7TU.cjs +0 -210
  304. package/dist/FeatureSpotlightSection-WRHXS7TU.cjs.map +0 -1
  305. package/dist/GallerySection-VMKORC47.js.map +0 -1
  306. package/dist/GallerySection-WJ4PQDBI.cjs +0 -219
  307. package/dist/GallerySection-WJ4PQDBI.cjs.map +0 -1
  308. package/dist/MetricsTimelineSection-4L6DUHJ5.cjs.map +0 -1
  309. package/dist/MetricsTimelineSection-6BT5GNFV.js.map +0 -1
  310. package/dist/PerformanceSection-24TVVFZA.cjs +0 -356
  311. package/dist/PerformanceSection-24TVVFZA.cjs.map +0 -1
  312. package/dist/PerformanceSection-MGCEIXDX.js.map +0 -1
  313. package/dist/ResultsSection-DFUJ5U6M.js.map +0 -1
  314. package/dist/ResultsSection-XLGMMQKY.cjs.map +0 -1
  315. package/dist/ServicesSection-D5V3Q4GR.js +0 -118
  316. package/dist/ServicesSection-D5V3Q4GR.js.map +0 -1
  317. package/dist/ServicesSection-WJMGK2MF.cjs +0 -120
  318. package/dist/ServicesSection-WJMGK2MF.cjs.map +0 -1
  319. package/dist/SiteArchitectureSection-J7BPBERH.cjs.map +0 -1
  320. package/dist/SiteArchitectureSection-TE22OAWV.js.map +0 -1
  321. package/dist/SpeedComparisonSection-EZKFQVGW.cjs.map +0 -1
  322. package/dist/SpeedComparisonSection-Y3K7OFZQ.js.map +0 -1
  323. package/dist/StrategySection-CJ7Y6OFQ.cjs +0 -174
  324. package/dist/StrategySection-CJ7Y6OFQ.cjs.map +0 -1
  325. package/dist/StrategySection-DI5RSCJU.js.map +0 -1
  326. package/dist/TeamSection-DZVSNZE6.cjs +0 -112
  327. package/dist/TeamSection-DZVSNZE6.cjs.map +0 -1
  328. package/dist/TeamSection-HGKFW6PQ.js +0 -107
  329. package/dist/TeamSection-HGKFW6PQ.js.map +0 -1
  330. package/dist/TechStackSection-2AQ7RGY3.js +0 -93
  331. package/dist/TechStackSection-2AQ7RGY3.js.map +0 -1
  332. package/dist/TechStackSection-VTNNZR5V.cjs +0 -95
  333. package/dist/TechStackSection-VTNNZR5V.cjs.map +0 -1
  334. package/dist/TestimonialSection-6RGSMXQB.js.map +0 -1
  335. package/dist/TestimonialSection-XPTFUQIN.cjs.map +0 -1
  336. package/dist/VideoSection-4A2HC6K6.js.map +0 -1
  337. package/dist/VideoSection-G3DFS7UH.cjs +0 -118
  338. package/dist/VideoSection-G3DFS7UH.cjs.map +0 -1
  339. package/dist/chunk-2Y4O3LWM.js +0 -53
  340. package/dist/chunk-2Y4O3LWM.js.map +0 -1
  341. package/dist/chunk-633UMQQH.cjs +0 -31
  342. package/dist/chunk-633UMQQH.cjs.map +0 -1
  343. package/dist/chunk-7CFFAKDM.js +0 -74
  344. package/dist/chunk-7CFFAKDM.js.map +0 -1
  345. package/dist/chunk-APG2QSMB.js +0 -131
  346. package/dist/chunk-APG2QSMB.js.map +0 -1
  347. package/dist/chunk-AVCH4LMG.cjs +0 -620
  348. package/dist/chunk-AVCH4LMG.cjs.map +0 -1
  349. package/dist/chunk-AYBUHRFS.js +0 -613
  350. package/dist/chunk-AYBUHRFS.js.map +0 -1
  351. package/dist/chunk-EE75WRCM.cjs.map +0 -1
  352. package/dist/chunk-IKBK7HYX.cjs +0 -79
  353. package/dist/chunk-IKBK7HYX.cjs.map +0 -1
  354. package/dist/chunk-KEOHORIH.cjs +0 -79
  355. package/dist/chunk-KEOHORIH.cjs.map +0 -1
  356. package/dist/chunk-OA5ZM4OA.cjs +0 -139
  357. package/dist/chunk-OA5ZM4OA.cjs.map +0 -1
  358. package/dist/chunk-TVFXN6W6.js.map +0 -1
  359. package/dist/chunk-VVTK4OL6.js +0 -28
  360. package/dist/chunk-VVTK4OL6.js.map +0 -1
  361. package/dist/chunk-XCKXHK44.js +0 -15
  362. package/dist/chunk-XCKXHK44.js.map +0 -1
  363. package/dist/chunk-XONXEFJY.cjs +0 -58
  364. package/dist/chunk-XONXEFJY.cjs.map +0 -1
  365. package/dist/chunk-XQNJED46.cjs +0 -19
  366. package/dist/chunk-XQNJED46.cjs.map +0 -1
  367. package/dist/chunk-YB4B3OMC.js +0 -74
  368. package/dist/chunk-YB4B3OMC.js.map +0 -1
  369. package/dist/portfolio/sections.cjs +0 -20
  370. package/dist/portfolio/sections.cjs.map +0 -1
  371. package/dist/portfolio/sections.d.cts +0 -42
  372. package/dist/portfolio/sections.d.ts +0 -42
  373. package/dist/portfolio/sections.js +0 -4
  374. package/dist/portfolio/sections.js.map +0 -1
@@ -1,101 +1,43 @@
1
- import { u as PortfolioItem, P as PortfolioItemFull, A as PortfolioSection } from '../types-DL4t_Cfa.js';
2
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import { i as PortfolioItem } from '../types-D0nb6KAx.js';
2
+ export { j as PortfolioItemFull, k as PortfolioSection } from '../types-D0nb6KAx.js';
3
+ import React from 'react';
4
+ export { default as PortfolioErrorFallback, PortfolioErrorFallbackProps } from './components/PortfolioErrorFallback.js';
5
+ export { default as PortfolioLeadCTA, PortfolioLeadCTAProps } from './components/PortfolioLeadCTA.js';
6
+ export { default as PortfolioAnalytics } from './components/PortfolioAnalytics.js';
3
7
 
4
- interface PortfolioGridProps$1 {
8
+ interface PortfolioGridProps {
5
9
  items: PortfolioItem[];
6
10
  className?: string;
7
11
  /** Base path for portfolio detail links (default: '/work') */
8
12
  basePath?: string;
9
13
  }
10
- declare function PortfolioGrid({ items, className, basePath }: PortfolioGridProps$1): react_jsx_runtime.JSX.Element;
14
+ declare function PortfolioGrid({ items, className, basePath }: PortfolioGridProps): React.JSX.Element;
11
15
 
12
- interface PortfolioCardProps$1 {
16
+ interface PortfolioCardProps {
13
17
  item: PortfolioItem;
14
18
  className?: string;
15
19
  /** Base path for portfolio detail links (default: '/work') */
16
20
  basePath?: string;
17
21
  }
18
- declare function PortfolioCard({ item, className, basePath }: PortfolioCardProps$1): react_jsx_runtime.JSX.Element;
22
+ declare function PortfolioCard({ item, className, basePath }: PortfolioCardProps): React.JSX.Element;
19
23
 
20
24
  /**
21
- * @sonordev/agency-site-kit/portfolio/client Client-only portfolio components
22
- *
23
- * Components in this barrel require browser APIs (DOM, events, IntersectionObserver,
24
- * animations). The 'use client' directive at the top marks the client boundary.
25
- *
26
- * Client components will be added here as they are implemented:
27
- *
28
- * - PortfolioPageClient — full case study page with scroll-driven sections
29
- * - PortfolioFilter — category/service filter bar with animated transitions
30
- * - PortfolioGrid — animated grid layout with filtering
31
- * - PortfolioCard — interactive card with hover effects and KPI preview
32
- * - PortfolioLightbox — fullscreen image viewer for gallery sections
33
- * - PortfolioBeforeAfterSlider — drag/touch comparison slider
34
- * - PortfolioMetricsChart — animated chart for metrics timeline
35
- * - PortfolioFunnelViz — conversion funnel visualization
36
- *
37
- * For now, export the type interfaces so consuming code can reference them.
25
+ * Presentation formatters shared by portfolio components and consuming apps.
38
26
  */
27
+ /**
28
+ * Human label for a category slug. Single source of truth — HeroSection,
29
+ * PortfolioCard, and app-side filter chips all render categories through
30
+ * this. Underscores become spaces; hyphens are PRESERVED so compound slugs
31
+ * keep their canonical form ("e-commerce" → "E-Commerce", never "E Commerce"),
32
+ * and every word start (including after a hyphen) is capitalized.
33
+ */
34
+ declare function formatCategoryLabel(slug: string | undefined | null): string;
35
+ /**
36
+ * Normalize a service tag's casing for display: the first character of each
37
+ * word is uppercased, the rest left alone (so "Next.js development" becomes
38
+ * "Next.js Development" and "Technical SEO implementation" keeps "SEO").
39
+ * Fixes per-item casing drift in stored tags without touching the data.
40
+ */
41
+ declare function formatServiceTag(tag: string | undefined | null): string;
39
42
 
40
- interface PortfolioPageClientProps {
41
- item: PortfolioItemFull;
42
- /** Back link URL (defaults to /portfolio) */
43
- backUrl?: string;
44
- /** Custom class name for the page wrapper */
45
- className?: string;
46
- }
47
- interface PortfolioFilterProps {
48
- /** All available categories extracted from items */
49
- categories: string[];
50
- /** All available services extracted from items */
51
- services: string[];
52
- /** Currently selected category (null = all) */
53
- activeCategory: string | null;
54
- /** Currently selected services */
55
- activeServices: string[];
56
- /** Callback when category changes */
57
- onCategoryChange: (category: string | null) => void;
58
- /** Callback when services selection changes */
59
- onServicesChange: (services: string[]) => void;
60
- /** Custom class name */
61
- className?: string;
62
- }
63
- interface PortfolioGridProps {
64
- /** Portfolio items to display */
65
- items: PortfolioItem[];
66
- /** Number of columns at each breakpoint */
67
- columns?: {
68
- sm?: number;
69
- md?: number;
70
- lg?: number;
71
- xl?: number;
72
- };
73
- /** Animation style for grid items */
74
- animation?: 'fade' | 'slide' | 'scale' | 'none';
75
- /** Custom class name */
76
- className?: string;
77
- }
78
- interface PortfolioCardProps {
79
- /** Portfolio item data */
80
- item: PortfolioItem;
81
- /** Card size variant */
82
- variant?: 'default' | 'featured' | 'compact';
83
- /** Whether to show KPI preview on hover */
84
- showKpis?: boolean;
85
- /** Click handler (if not using Link) */
86
- onClick?: (item: PortfolioItem) => void;
87
- /** Link href for the card */
88
- href?: string;
89
- /** Custom class name */
90
- className?: string;
91
- }
92
- interface PortfolioSectionRendererProps {
93
- /** The section to render */
94
- section: PortfolioSection;
95
- /** Index within the page (for animation staggering) */
96
- index?: number;
97
- /** Custom class name */
98
- className?: string;
99
- }
100
-
101
- export { PortfolioCard, type PortfolioCardProps, type PortfolioFilterProps, PortfolioGrid, type PortfolioGridProps, PortfolioItem, PortfolioItemFull, type PortfolioPageClientProps, PortfolioSection, type PortfolioSectionRendererProps };
43
+ export { PortfolioCard, PortfolioGrid, PortfolioItem, formatCategoryLabel, formatServiceTag };
@@ -1,6 +1,184 @@
1
1
  'use client';
2
- export { PortfolioCard, PortfolioGrid } from '../chunk-APG2QSMB.js';
3
- import '../chunk-YB4B3OMC.js';
4
- import '../chunk-7CFFAKDM.js';
5
- //# sourceMappingURL=client.js.map
2
+ "use client";
3
+ import {
4
+ PortfolioAnalytics
5
+ } from "../chunk-ZINKVJQU.js";
6
+ import {
7
+ PortfolioErrorFallback
8
+ } from "../chunk-K2BGTDSN.js";
9
+ import {
10
+ PortfolioLeadCTA
11
+ } from "../chunk-CVT7I5BQ.js";
12
+
13
+ // src/portfolio/components/PortfolioGrid.tsx
14
+ import ScrollReveal from "@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal";
15
+
16
+ // src/portfolio/components/PortfolioCard.tsx
17
+ import Image from "next/image";
18
+ import Link from "next/link";
19
+ import GlassCard from "@sonordev/agency-site-kit/portfolio/primitives/GlassCard";
20
+
21
+ // src/portfolio/curate-proof.ts
22
+ var LIGHTHOUSE_RE = /lighthouse/i;
23
+ function isLighthouseKpi(kpi) {
24
+ return LIGHTHOUSE_RE.test(kpi.label);
25
+ }
26
+ function curateHeroKpis(kpis) {
27
+ const business = kpis.filter((k) => !isLighthouseKpi(k));
28
+ const lighthouse = kpis.filter(isLighthouseKpi);
29
+ if (lighthouse.length <= 1) return kpis;
30
+ const allPerfect = lighthouse.length >= 4 && lighthouse.every((k) => k.value === 100);
31
+ const summary = allPerfect ? {
32
+ ...lighthouse[0],
33
+ label: "Lighthouse, all 4 categories",
34
+ description: "Perfect scores across performance, SEO, accessibility, and best practices."
35
+ } : lighthouse.find((k) => /performance/i.test(k.label)) ?? lighthouse[0];
36
+ return [...business, summary];
37
+ }
38
+
39
+ // src/portfolio/format.ts
40
+ function formatCategoryLabel(slug) {
41
+ if (!slug) return "";
42
+ return slug.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
43
+ }
44
+ function formatServiceTag(tag) {
45
+ if (!tag) return "";
46
+ return tag.replace(/(^|[\s/])([a-z])/g, (_m, sep, ch) => sep + ch.toUpperCase());
47
+ }
48
+
49
+ // src/portfolio/components/PortfolioCard.tsx
50
+ import { jsx, jsxs } from "react/jsx-runtime";
51
+ function PortfolioCard({ item, className = "", basePath = "/work" }) {
52
+ const thumbnailSrc = item.hero_screenshots?.desktop || item.hero_image || (item.project_id ? `/portfolio-previews/${item.slug}.png` : void 0);
53
+ const kpis = Array.isArray(item.kpis) ? item.kpis : [];
54
+ const services = Array.isArray(item.services) ? item.services : [];
55
+ const kpiPreview = curateHeroKpis(kpis).slice(0, 3);
56
+ const servicePreview = services.slice(0, 3);
57
+ return /* @__PURE__ */ jsx(Link, { href: `${basePath}/${item.slug}`, className: `block group ${className}`, children: /* @__PURE__ */ jsx(GlassCard, { padding: "sm", hover: true, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
58
+ thumbnailSrc && /* @__PURE__ */ jsxs(
59
+ "div",
60
+ {
61
+ className: "relative w-full overflow-hidden rounded-xl",
62
+ style: { aspectRatio: "16/10" },
63
+ children: [
64
+ /* @__PURE__ */ jsx(
65
+ Image,
66
+ {
67
+ src: thumbnailSrc,
68
+ alt: item.hero_image_alt || item.title,
69
+ fill: true,
70
+ sizes: "(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 33vw",
71
+ className: "object-cover object-top transition-transform duration-500 group-hover:scale-105"
72
+ }
73
+ ),
74
+ /* @__PURE__ */ jsx(
75
+ "span",
76
+ {
77
+ className: "absolute top-3 left-3 px-3 py-1 rounded-full text-[11px] uppercase tracking-wider font-semibold",
78
+ style: {
79
+ background: "color-mix(in srgb, var(--sk-primary, #6366f1) 80%, transparent)",
80
+ color: "#ffffff",
81
+ backdropFilter: "blur(8px)"
82
+ },
83
+ children: formatCategoryLabel(item.category)
84
+ }
85
+ )
86
+ ]
87
+ }
88
+ ),
89
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 px-2 pb-2", children: [
90
+ /* @__PURE__ */ jsx(
91
+ "h3",
92
+ {
93
+ className: "text-lg font-semibold line-clamp-1",
94
+ style: { color: "var(--sk-text-primary, #ffffff)" },
95
+ children: item.title
96
+ }
97
+ ),
98
+ item.subtitle && /* @__PURE__ */ jsx(
99
+ "p",
100
+ {
101
+ className: "text-sm line-clamp-2",
102
+ style: { color: "var(--sk-text-tertiary, #71717a)" },
103
+ children: item.subtitle
104
+ }
105
+ ),
106
+ kpiPreview.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-4 mt-1", children: kpiPreview.map((kpi, i) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
107
+ /* @__PURE__ */ jsxs(
108
+ "span",
109
+ {
110
+ className: "text-base font-bold",
111
+ style: { color: "var(--sk-primary, #6366f1)" },
112
+ children: [
113
+ kpi.prefix || "",
114
+ kpi.value.toLocaleString(),
115
+ kpi.suffix
116
+ ]
117
+ }
118
+ ),
119
+ /* @__PURE__ */ jsx(
120
+ "span",
121
+ {
122
+ className: "text-[10px] uppercase tracking-wider font-medium",
123
+ style: { color: "var(--sk-text-tertiary, #71717a)" },
124
+ children: kpi.label
125
+ }
126
+ )
127
+ ] }, i)) }),
128
+ servicePreview.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1.5 mt-2", children: [
129
+ servicePreview.map((service) => /* @__PURE__ */ jsx(
130
+ "span",
131
+ {
132
+ className: "px-2.5 py-0.5 rounded-full text-[11px] font-medium",
133
+ style: {
134
+ background: "var(--sk-surface, rgba(255,255,255,0.05))",
135
+ color: "var(--sk-text-secondary, #a1a1aa)",
136
+ border: "1px solid var(--sk-border, rgba(255,255,255,0.1))"
137
+ },
138
+ children: formatServiceTag(service)
139
+ },
140
+ service
141
+ )),
142
+ services.length > 3 && /* @__PURE__ */ jsxs(
143
+ "span",
144
+ {
145
+ className: "px-2.5 py-0.5 rounded-full text-[11px] font-medium",
146
+ style: {
147
+ background: "var(--sk-surface, rgba(255,255,255,0.05))",
148
+ color: "var(--sk-text-tertiary, #71717a)"
149
+ },
150
+ children: [
151
+ "+",
152
+ item.services.length - 3
153
+ ]
154
+ }
155
+ )
156
+ ] })
157
+ ] })
158
+ ] }) }) });
159
+ }
160
+
161
+ // src/portfolio/components/PortfolioGrid.tsx
162
+ import { jsx as jsx2 } from "react/jsx-runtime";
163
+ function PortfolioGrid({ items, className = "", basePath = "/work" }) {
164
+ return /* @__PURE__ */ jsx2(ScrollReveal, { stagger: 0.1, children: /* @__PURE__ */ jsx2(
165
+ "div",
166
+ {
167
+ className: `grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 ${className}`,
168
+ style: {
169
+ gap: "var(--sk-grid-gap, 24px)"
170
+ },
171
+ children: items.map((item) => /* @__PURE__ */ jsx2(PortfolioCard, { item, basePath }, item.id))
172
+ }
173
+ ) });
174
+ }
175
+ export {
176
+ PortfolioAnalytics,
177
+ PortfolioCard,
178
+ PortfolioErrorFallback,
179
+ PortfolioGrid,
180
+ PortfolioLeadCTA,
181
+ formatCategoryLabel,
182
+ formatServiceTag
183
+ };
6
184
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"client.js"}
1
+ {"version":3,"sources":["../../src/portfolio/components/PortfolioGrid.tsx","../../src/portfolio/components/PortfolioCard.tsx","../../src/portfolio/curate-proof.ts","../../src/portfolio/format.ts"],"sourcesContent":["// Shared component — no directive on purpose: hook-free, so it renders\n// server-side (zero JS) from PortfolioIndex and stays usable from client\n// code via the /portfolio/client barrel.\nimport React from 'react';\nimport type { PortfolioItem } from '../../types';\nimport ScrollReveal from '@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal';\nimport PortfolioCard from './PortfolioCard';\n\ninterface PortfolioGridProps {\n items: PortfolioItem[];\n className?: string;\n /** Base path for portfolio detail links (default: '/work') */\n basePath?: string;\n}\n\nexport default function PortfolioGrid({ items, className = '', basePath = '/work' }: PortfolioGridProps) {\n return (\n <ScrollReveal stagger={0.1}>\n <div\n className={`grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 ${className}`}\n style={{\n gap: 'var(--sk-grid-gap, 24px)',\n }}\n >\n {items.map((item) => (\n <PortfolioCard key={item.id} item={item} basePath={basePath} />\n ))}\n </div>\n </ScrollReveal>\n );\n}\n","// Shared component — no directive on purpose: hook-free, so it renders\n// server-side (zero JS) from PortfolioIndex and stays usable from client\n// code via the /portfolio/client barrel.\nimport React from 'react';\nimport Image from 'next/image';\nimport Link from 'next/link';\nimport type { PortfolioItem } from '../../types';\nimport GlassCard from '@sonordev/agency-site-kit/portfolio/primitives/GlassCard';\nimport { curateHeroKpis } from '../curate-proof';\nimport { formatCategoryLabel, formatServiceTag } from '../format';\n\ninterface PortfolioCardProps {\n item: PortfolioItem;\n className?: string;\n /** Base path for portfolio detail links (default: '/work') */\n basePath?: string;\n}\n\nexport default function PortfolioCard({ item, className = '', basePath = '/work' }: PortfolioCardProps) {\n // Use hero_screenshots desktop → hero_image → trifolio screenshot convention\n const thumbnailSrc =\n item.hero_screenshots?.desktop ||\n item.hero_image ||\n (item.project_id ? `/portfolio-previews/${item.slug}.png` : undefined);\n const kpis = Array.isArray(item.kpis) ? item.kpis : [];\n const services = Array.isArray(item.services) ? item.services : [];\n // Collapse per-category Lighthouse KPIs so a card never reads\n // \"100/100 · 100/100 · 100/100\" — business outcomes lead the preview.\n const kpiPreview = curateHeroKpis(kpis).slice(0, 3);\n const servicePreview = services.slice(0, 3);\n\n return (\n <Link href={`${basePath}/${item.slug}`} className={`block group ${className}`}>\n <GlassCard padding=\"sm\" hover>\n <div className=\"flex flex-col gap-4\">\n {/* Thumbnail */}\n {thumbnailSrc && (\n <div\n className=\"relative w-full overflow-hidden rounded-xl\"\n style={{ aspectRatio: '16/10' }}\n >\n <Image\n src={thumbnailSrc}\n alt={item.hero_image_alt || item.title}\n fill\n sizes=\"(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 33vw\"\n className=\"object-cover object-top transition-transform duration-500 group-hover:scale-105\"\n />\n {/* Category badge */}\n <span\n className=\"absolute top-3 left-3 px-3 py-1 rounded-full text-[11px] uppercase tracking-wider font-semibold\"\n style={{\n background: 'color-mix(in srgb, var(--sk-primary, #6366f1) 80%, transparent)',\n color: '#ffffff',\n backdropFilter: 'blur(8px)',\n }}\n >\n {formatCategoryLabel(item.category)}\n </span>\n </div>\n )}\n\n {/* Text content */}\n <div className=\"flex flex-col gap-2 px-2 pb-2\">\n <h3\n className=\"text-lg font-semibold line-clamp-1\"\n style={{ color: 'var(--sk-text-primary, #ffffff)' }}\n >\n {item.title}\n </h3>\n\n {item.subtitle && (\n <p\n className=\"text-sm line-clamp-2\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {item.subtitle}\n </p>\n )}\n\n {/* KPI preview */}\n {kpiPreview.length > 0 && (\n <div className=\"flex items-center gap-4 mt-1\">\n {kpiPreview.map((kpi, i) => (\n <div key={i} className=\"flex flex-col\">\n <span\n className=\"text-base font-bold\"\n style={{ color: 'var(--sk-primary, #6366f1)' }}\n >\n {kpi.prefix || ''}\n {kpi.value.toLocaleString()}\n {kpi.suffix}\n </span>\n <span\n className=\"text-[10px] uppercase tracking-wider font-medium\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {kpi.label}\n </span>\n </div>\n ))}\n </div>\n )}\n\n {/* Services tags */}\n {servicePreview.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5 mt-2\">\n {servicePreview.map((service) => (\n <span\n key={service}\n className=\"px-2.5 py-0.5 rounded-full text-[11px] font-medium\"\n style={{\n background: 'var(--sk-surface, rgba(255,255,255,0.05))',\n color: 'var(--sk-text-secondary, #a1a1aa)',\n border: '1px solid var(--sk-border, rgba(255,255,255,0.1))',\n }}\n >\n {formatServiceTag(service)}\n </span>\n ))}\n {services.length > 3 && (\n <span\n className=\"px-2.5 py-0.5 rounded-full text-[11px] font-medium\"\n style={{\n background: 'var(--sk-surface, rgba(255,255,255,0.05))',\n color: 'var(--sk-text-tertiary, #71717a)',\n }}\n >\n +{item.services.length - 3}\n </span>\n )}\n </div>\n )}\n </div>\n </div>\n </GlassCard>\n </Link>\n );\n}\n","/**\n * curate-proof — single source of truth for which proof points a public case\n * study is allowed to display, and in what shape.\n *\n * Two classes of problem this guards against (both shipped to production on\n * upforge.io before this existed):\n *\n * 1. Repetition: generated items arrive with four \"100/100 Lighthouse X\"\n * KPIs in the hero, the same four restated as Results cards, AND a full\n * Performance section with score gauges. One differentiator repeated\n * twelve times per page stops differentiating. The Performance section is\n * the one home for the Lighthouse breakdown; hero/results/cards collapse\n * to at most one summary tile.\n *\n * 2. Self-harming live metrics: MetricsDelta rows are computed from raw\n * analytics baselines with no editorial judgment — a bounce rate of\n * \"100 → 99.69\" rendered as a green win. Marketing surfaces only show a\n * delta when it's a genuinely flattering, meaningful story.\n *\n * Used by PortfolioPage (hero KPIs + results items), PortfolioCard (KPI\n * preview), and MetricsProvenance (delta gate). Change display policy here,\n * nowhere else.\n */\n\nimport type {\n MetricsDelta,\n PortfolioHeroData,\n PortfolioItemFull,\n PortfolioKPI,\n PortfolioResultItem,\n PortfolioResultsData,\n} from '../types';\n\nconst LIGHTHOUSE_RE = /lighthouse/i;\n\n/** True when a KPI tile is a per-category Lighthouse score. */\nexport function isLighthouseKpi(kpi: PortfolioKPI): boolean {\n return LIGHTHOUSE_RE.test(kpi.label);\n}\n\n/**\n * True when a Results card merely restates a Lighthouse category score\n * (e.g. \"Perfect performance score … measured Lighthouse score of 100/100\").\n * Business outcomes (\"Complete 14-page rebuild\", \"682% session growth\")\n * never match: the title must be about a score AND the card must reference\n * Lighthouse or carry a x/100 metric.\n */\nexport function isLighthouseRestatement(item: PortfolioResultItem): boolean {\n if (!/score/i.test(item.title)) return false;\n if (LIGHTHOUSE_RE.test(`${item.title} ${item.description}`)) return true;\n return item.metric?.suffix === '/100';\n}\n\n/**\n * Collapse per-category Lighthouse KPIs to at most one summary tile, business\n * outcomes first. When every category is present at 100 the summary says so;\n * otherwise the Performance category (the one buyers know) represents the set.\n */\nexport function curateHeroKpis(kpis: PortfolioKPI[]): PortfolioKPI[] {\n const business = kpis.filter((k) => !isLighthouseKpi(k));\n const lighthouse = kpis.filter(isLighthouseKpi);\n if (lighthouse.length <= 1) return kpis;\n\n const allPerfect = lighthouse.length >= 4 && lighthouse.every((k) => k.value === 100);\n const summary: PortfolioKPI = allPerfect\n ? {\n ...lighthouse[0],\n label: 'Lighthouse, all 4 categories',\n description: 'Perfect scores across performance, SEO, accessibility, and best practices.',\n }\n : (lighthouse.find((k) => /performance/i.test(k.label)) ?? lighthouse[0]);\n\n return [...business, summary];\n}\n\n/**\n * Drop Results cards that restate Lighthouse scores when the case study also\n * renders a Performance section (the score breakdown's single home).\n */\nexport function curateResultItems(\n items: PortfolioResultItem[],\n hasPerformanceSection: boolean,\n): PortfolioResultItem[] {\n if (!hasPerformanceSection) return items;\n const curated = items.filter((item) => !isLighthouseRestatement(item));\n // Never curate a Results section into emptiness — if every card was a\n // Lighthouse restatement, keep the strongest single card instead.\n return curated.length > 0 ? curated : items.slice(0, 1);\n}\n\n/**\n * Editorial gate for live metric deltas (\"Verified from live analytics\").\n * `direction` comes from the platform with 'up' meaning IMPROVED (lower-is-\n * better metrics are inverted server-side). A public case study only shows a\n * delta when it's a win worth telling:\n * - improved ('up'), never a regression or flat noise\n * - moved by a double-digit relative margin (small drift isn't a story)\n * - bounce-rate-style metrics must also be respectable in absolute terms —\n * \"100 → 99.69\" is technically an improvement and still self-harm\n */\nexport function gateMetricsDeltas(deltas: MetricsDelta[] | undefined | null): MetricsDelta[] {\n if (!deltas?.length) return [];\n return deltas.filter((d) => {\n if (d.direction !== 'up') return false;\n if (Math.abs(d.deltaPercent) < 10) return false;\n if (/bounce/i.test(d.metric) && d.current > 70) return false;\n return true;\n });\n}\n\n/**\n * Apply the full display policy to a portfolio item before rendering.\n * Pure — returns a new item; the fetched payload is never mutated.\n */\nexport function curatePortfolioProof(item: PortfolioItemFull): PortfolioItemFull {\n const hasPerformanceSection = item.sections.some(\n (s) => s.sectionType === 'portfolioPerformance',\n );\n\n return {\n ...item,\n sections: item.sections.map((section) => {\n if (section.sectionType === 'portfolioHero') {\n const data = section.data as PortfolioHeroData;\n return { ...section, data: { ...data, kpis: curateHeroKpis(data.kpis ?? []) } };\n }\n if (section.sectionType === 'portfolioResults') {\n const data = section.data as PortfolioResultsData;\n return {\n ...section,\n data: { ...data, items: curateResultItems(data.items ?? [], hasPerformanceSection) },\n };\n }\n return section;\n }),\n };\n}\n","/**\n * Presentation formatters shared by portfolio components and consuming apps.\n */\n\n/**\n * Human label for a category slug. Single source of truth — HeroSection,\n * PortfolioCard, and app-side filter chips all render categories through\n * this. Underscores become spaces; hyphens are PRESERVED so compound slugs\n * keep their canonical form (\"e-commerce\" → \"E-Commerce\", never \"E Commerce\"),\n * and every word start (including after a hyphen) is capitalized.\n */\nexport function formatCategoryLabel(slug: string | undefined | null): string {\n if (!slug) return '';\n return slug.replace(/_/g, ' ').replace(/\\b\\w/g, (c: string) => c.toUpperCase());\n}\n\n/**\n * Normalize a service tag's casing for display: the first character of each\n * word is uppercased, the rest left alone (so \"Next.js development\" becomes\n * \"Next.js Development\" and \"Technical SEO implementation\" keeps \"SEO\").\n * Fixes per-item casing drift in stored tags without touching the data.\n */\nexport function formatServiceTag(tag: string | undefined | null): string {\n if (!tag) return '';\n return tag.replace(/(^|[\\s/])([a-z])/g, (_m, sep: string, ch: string) => sep + ch.toUpperCase());\n}\n"],"mappings":"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","names":["jsx"]}
@@ -0,0 +1,87 @@
1
+ 'use client';
2
+ "use strict";
3
+ "use client";
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+
22
+ // src/portfolio/components/PortfolioAnalytics.tsx
23
+ var PortfolioAnalytics_exports = {};
24
+ __export(PortfolioAnalytics_exports, {
25
+ default: () => PortfolioAnalytics
26
+ });
27
+ module.exports = __toCommonJS(PortfolioAnalytics_exports);
28
+ var import_react = require("react");
29
+ var import_client = require("@sonordev/site-kit/client");
30
+ function PortfolioAnalytics({ slug }) {
31
+ (0, import_react.useEffect)(() => {
32
+ let cleanup = () => {
33
+ };
34
+ const setup = () => {
35
+ const seen = /* @__PURE__ */ new Set();
36
+ const io = new IntersectionObserver(
37
+ (entries) => {
38
+ for (const entry of entries) {
39
+ if (!entry.isIntersecting) continue;
40
+ const type = entry.target.dataset.portfolioSection;
41
+ if (!type || seen.has(type)) continue;
42
+ seen.add(type);
43
+ (0, import_client.trackEvent)({
44
+ name: "portfolio_section_view",
45
+ category: "portfolio",
46
+ label: type,
47
+ properties: { case_study: slug, section: type }
48
+ });
49
+ }
50
+ },
51
+ { threshold: 0.4 }
52
+ );
53
+ document.querySelectorAll("[data-portfolio-section]").forEach((el) => io.observe(el));
54
+ const onClick = (event) => {
55
+ const link = event.target.closest(
56
+ "a[data-portfolio-action]"
57
+ );
58
+ if (!link) return;
59
+ const action = link.dataset.portfolioAction;
60
+ (0, import_client.trackEvent)({
61
+ name: action === "live-site" ? "portfolio_live_site_click" : "portfolio_cta_click",
62
+ category: "portfolio",
63
+ label: slug,
64
+ properties: { case_study: slug, href: link.href }
65
+ });
66
+ };
67
+ document.addEventListener("click", onClick, { passive: true });
68
+ cleanup = () => {
69
+ io.disconnect();
70
+ document.removeEventListener("click", onClick);
71
+ };
72
+ };
73
+ let idleId;
74
+ if ("requestIdleCallback" in window) {
75
+ idleId = window.requestIdleCallback(setup, { timeout: 3e3 });
76
+ } else {
77
+ idleId = setTimeout(setup, 1500);
78
+ }
79
+ return () => {
80
+ if ("requestIdleCallback" in window) window.cancelIdleCallback(idleId);
81
+ else clearTimeout(idleId);
82
+ cleanup();
83
+ };
84
+ }, [slug]);
85
+ return null;
86
+ }
87
+ //# sourceMappingURL=PortfolioAnalytics.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/portfolio/components/PortfolioAnalytics.tsx"],"sourcesContent":["'use client';\n\n/**\n * PortfolioAnalytics — childless engagement-tracking island.\n *\n * Mounted by PortfolioPage as a SIBLING of the content (never a wrapper —\n * house perf doctrine), deferred to idle so it stays out of the hydration\n * path. Observes the server-rendered `data-portfolio-section` markers and\n * emits events through site-kit's standalone dispatch (which queues until\n * the site's AnalyticsProvider mounts and no-ops if it never does):\n *\n * portfolio_section_view once per section type per page view\n * portfolio_live_site_click clicks on [data-portfolio-action=\"live-site\"]\n * portfolio_cta_click clicks on [data-portfolio-action=\"cta\"]\n *\n * This is the raw material for \"your QCR case study converts best\" insights.\n */\n\nimport { useEffect } from 'react';\nimport { trackEvent } from '@sonordev/site-kit/client';\n\nexport default function PortfolioAnalytics({ slug }: { slug: string }) {\n useEffect(() => {\n let cleanup = () => {};\n\n const setup = () => {\n const seen = new Set<string>();\n const io = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (!entry.isIntersecting) continue;\n const type = (entry.target as HTMLElement).dataset.portfolioSection;\n if (!type || seen.has(type)) continue;\n seen.add(type);\n trackEvent({\n name: 'portfolio_section_view',\n category: 'portfolio',\n label: type,\n properties: { case_study: slug, section: type },\n });\n }\n },\n { threshold: 0.4 },\n );\n document\n .querySelectorAll<HTMLElement>('[data-portfolio-section]')\n .forEach((el) => io.observe(el));\n\n const onClick = (event: MouseEvent) => {\n const link = (event.target as HTMLElement).closest<HTMLAnchorElement>(\n 'a[data-portfolio-action]',\n );\n if (!link) return;\n const action = link.dataset.portfolioAction;\n trackEvent({\n name: action === 'live-site' ? 'portfolio_live_site_click' : 'portfolio_cta_click',\n category: 'portfolio',\n label: slug,\n properties: { case_study: slug, href: link.href },\n });\n };\n document.addEventListener('click', onClick, { passive: true });\n\n cleanup = () => {\n io.disconnect();\n document.removeEventListener('click', onClick);\n };\n };\n\n // Idle-defer: engagement tracking must never compete with hydration.\n let idleId: number | ReturnType<typeof setTimeout>;\n if ('requestIdleCallback' in window) {\n idleId = window.requestIdleCallback(setup, { timeout: 3000 });\n } else {\n idleId = setTimeout(setup, 1500);\n }\n\n return () => {\n if ('requestIdleCallback' in window) window.cancelIdleCallback(idleId as number);\n else clearTimeout(idleId as ReturnType<typeof setTimeout>);\n cleanup();\n };\n }, [slug]);\n\n return null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBA,mBAA0B;AAC1B,oBAA2B;AAEZ,SAAR,mBAAoC,EAAE,KAAK,GAAqB;AACrE,8BAAU,MAAM;AACd,QAAI,UAAU,MAAM;AAAA,IAAC;AAErB,UAAM,QAAQ,MAAM;AAClB,YAAM,OAAO,oBAAI,IAAY;AAC7B,YAAM,KAAK,IAAI;AAAA,QACb,CAAC,YAAY;AACX,qBAAW,SAAS,SAAS;AAC3B,gBAAI,CAAC,MAAM,eAAgB;AAC3B,kBAAM,OAAQ,MAAM,OAAuB,QAAQ;AACnD,gBAAI,CAAC,QAAQ,KAAK,IAAI,IAAI,EAAG;AAC7B,iBAAK,IAAI,IAAI;AACb,0CAAW;AAAA,cACT,MAAM;AAAA,cACN,UAAU;AAAA,cACV,OAAO;AAAA,cACP,YAAY,EAAE,YAAY,MAAM,SAAS,KAAK;AAAA,YAChD,CAAC;AAAA,UACH;AAAA,QACF;AAAA,QACA,EAAE,WAAW,IAAI;AAAA,MACnB;AACA,eACG,iBAA8B,0BAA0B,EACxD,QAAQ,CAAC,OAAO,GAAG,QAAQ,EAAE,CAAC;AAEjC,YAAM,UAAU,CAAC,UAAsB;AACrC,cAAM,OAAQ,MAAM,OAAuB;AAAA,UACzC;AAAA,QACF;AACA,YAAI,CAAC,KAAM;AACX,cAAM,SAAS,KAAK,QAAQ;AAC5B,sCAAW;AAAA,UACT,MAAM,WAAW,cAAc,8BAA8B;AAAA,UAC7D,UAAU;AAAA,UACV,OAAO;AAAA,UACP,YAAY,EAAE,YAAY,MAAM,MAAM,KAAK,KAAK;AAAA,QAClD,CAAC;AAAA,MACH;AACA,eAAS,iBAAiB,SAAS,SAAS,EAAE,SAAS,KAAK,CAAC;AAE7D,gBAAU,MAAM;AACd,WAAG,WAAW;AACd,iBAAS,oBAAoB,SAAS,OAAO;AAAA,MAC/C;AAAA,IACF;AAGA,QAAI;AACJ,QAAI,yBAAyB,QAAQ;AACnC,eAAS,OAAO,oBAAoB,OAAO,EAAE,SAAS,IAAK,CAAC;AAAA,IAC9D,OAAO;AACL,eAAS,WAAW,OAAO,IAAI;AAAA,IACjC;AAEA,WAAO,MAAM;AACX,UAAI,yBAAyB,OAAQ,QAAO,mBAAmB,MAAgB;AAAA,UAC1E,cAAa,MAAuC;AACzD,cAAQ;AAAA,IACV;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAET,SAAO;AACT;","names":[]}
@@ -0,0 +1,5 @@
1
+ declare function PortfolioAnalytics({ slug }: {
2
+ slug: string;
3
+ }): null;
4
+
5
+ export { PortfolioAnalytics as default };
@@ -0,0 +1,5 @@
1
+ declare function PortfolioAnalytics({ slug }: {
2
+ slug: string;
3
+ }): null;
4
+
5
+ export { PortfolioAnalytics as default };
@@ -0,0 +1,9 @@
1
+ 'use client';
2
+ "use client";
3
+ import {
4
+ PortfolioAnalytics
5
+ } from "../../chunk-ZINKVJQU.js";
6
+ export {
7
+ PortfolioAnalytics as default
8
+ };
9
+ //# sourceMappingURL=PortfolioAnalytics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,65 @@
1
+ 'use client';
2
+ "use strict";
3
+ "use client";
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+
22
+ // src/portfolio/components/PortfolioErrorFallback.tsx
23
+ var PortfolioErrorFallback_exports = {};
24
+ __export(PortfolioErrorFallback_exports, {
25
+ default: () => PortfolioErrorFallback
26
+ });
27
+ module.exports = __toCommonJS(PortfolioErrorFallback_exports);
28
+ var import_jsx_runtime = require("react/jsx-runtime");
29
+ function PortfolioErrorFallback({ error, reset }) {
30
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", { className: "w-full py-24", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
31
+ "div",
32
+ {
33
+ className: "max-w-xl mx-auto px-8 py-12 rounded-2xl text-center flex flex-col items-center gap-4",
34
+ style: {
35
+ background: "var(--sk-surface, rgba(255,255,255,0.05))",
36
+ border: "1px solid var(--sk-border, rgba(255,255,255,0.1))"
37
+ },
38
+ children: [
39
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
40
+ "h2",
41
+ {
42
+ className: "text-xl font-semibold",
43
+ style: { color: "var(--sk-text-primary, #ffffff)" },
44
+ children: "Our work is taking a moment to load"
45
+ }
46
+ ),
47
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm", style: { color: "var(--sk-text-secondary, #a1a1aa)" }, children: "The portfolio couldn't be fetched just now. It's us, not you. Try again in a few seconds." }),
48
+ error?.digest && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "text-xs", style: { color: "var(--sk-text-tertiary, #71717a)" }, children: [
49
+ "Reference: ",
50
+ error.digest
51
+ ] }),
52
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
53
+ "button",
54
+ {
55
+ onClick: reset,
56
+ className: "mt-2 px-6 py-2.5 rounded-xl text-sm font-semibold transition-opacity hover:opacity-90",
57
+ style: { background: "var(--sk-primary, #6366f1)", color: "#ffffff" },
58
+ children: "Try again"
59
+ }
60
+ )
61
+ ]
62
+ }
63
+ ) });
64
+ }
65
+ //# sourceMappingURL=PortfolioErrorFallback.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/portfolio/components/PortfolioErrorFallback.tsx"],"sourcesContent":["'use client';\n\n/**\n * Error boundary UI for portfolio routes — pairs with the PortfolioApiError\n * contract (infrastructure failures throw; Next renders the route's\n * error.tsx). Drop into `error.tsx`:\n *\n * ```tsx\n * 'use client';\n * export { PortfolioErrorFallback as default } from '@sonordev/agency-site-kit/portfolio/client';\n * ```\n */\n\nimport React from 'react';\n\nexport interface PortfolioErrorFallbackProps {\n error: Error & { digest?: string };\n reset: () => void;\n}\n\nexport default function PortfolioErrorFallback({ error, reset }: PortfolioErrorFallbackProps) {\n return (\n <section className=\"w-full py-24\">\n <div\n className=\"max-w-xl mx-auto px-8 py-12 rounded-2xl text-center flex flex-col items-center gap-4\"\n style={{\n background: 'var(--sk-surface, rgba(255,255,255,0.05))',\n border: '1px solid var(--sk-border, rgba(255,255,255,0.1))',\n }}\n >\n <h2\n className=\"text-xl font-semibold\"\n style={{ color: 'var(--sk-text-primary, #ffffff)' }}\n >\n Our work is taking a moment to load\n </h2>\n <p className=\"text-sm\" style={{ color: 'var(--sk-text-secondary, #a1a1aa)' }}>\n The portfolio couldn&apos;t be fetched just now. It&apos;s us, not you. Try again in a\n few seconds.\n </p>\n {error?.digest && (\n <p className=\"text-xs\" style={{ color: 'var(--sk-text-tertiary, #71717a)' }}>\n Reference: {error.digest}\n </p>\n )}\n <button\n onClick={reset}\n className=\"mt-2 px-6 py-2.5 rounded-xl text-sm font-semibold transition-opacity hover:opacity-90\"\n style={{ background: 'var(--sk-primary, #6366f1)', color: '#ffffff' }}\n >\n Try again\n </button>\n </div>\n </section>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA8BQ;AAVO,SAAR,uBAAwC,EAAE,OAAO,MAAM,GAAgC;AAC5F,SACE,4CAAC,aAAQ,WAAU,gBACjB;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,OAAO;AAAA,QACL,YAAY;AAAA,QACZ,QAAQ;AAAA,MACV;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,OAAO,kCAAkC;AAAA,YACnD;AAAA;AAAA,QAED;AAAA,QACA,4CAAC,OAAE,WAAU,WAAU,OAAO,EAAE,OAAO,oCAAoC,GAAG,uGAG9E;AAAA,QACC,OAAO,UACN,6CAAC,OAAE,WAAU,WAAU,OAAO,EAAE,OAAO,mCAAmC,GAAG;AAAA;AAAA,UAC/D,MAAM;AAAA,WACpB;AAAA,QAEF;AAAA,UAAC;AAAA;AAAA,YACC,SAAS;AAAA,YACT,WAAU;AAAA,YACV,OAAO,EAAE,YAAY,8BAA8B,OAAO,UAAU;AAAA,YACrE;AAAA;AAAA,QAED;AAAA;AAAA;AAAA,EACF,GACF;AAEJ;","names":[]}
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+
3
+ /**
4
+ * Error boundary UI for portfolio routes — pairs with the PortfolioApiError
5
+ * contract (infrastructure failures throw; Next renders the route's
6
+ * error.tsx). Drop into `error.tsx`:
7
+ *
8
+ * ```tsx
9
+ * 'use client';
10
+ * export { PortfolioErrorFallback as default } from '@sonordev/agency-site-kit/portfolio/client';
11
+ * ```
12
+ */
13
+
14
+ interface PortfolioErrorFallbackProps {
15
+ error: Error & {
16
+ digest?: string;
17
+ };
18
+ reset: () => void;
19
+ }
20
+ declare function PortfolioErrorFallback({ error, reset }: PortfolioErrorFallbackProps): React.JSX.Element;
21
+
22
+ export { type PortfolioErrorFallbackProps, PortfolioErrorFallback as default };
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+
3
+ /**
4
+ * Error boundary UI for portfolio routes — pairs with the PortfolioApiError
5
+ * contract (infrastructure failures throw; Next renders the route's
6
+ * error.tsx). Drop into `error.tsx`:
7
+ *
8
+ * ```tsx
9
+ * 'use client';
10
+ * export { PortfolioErrorFallback as default } from '@sonordev/agency-site-kit/portfolio/client';
11
+ * ```
12
+ */
13
+
14
+ interface PortfolioErrorFallbackProps {
15
+ error: Error & {
16
+ digest?: string;
17
+ };
18
+ reset: () => void;
19
+ }
20
+ declare function PortfolioErrorFallback({ error, reset }: PortfolioErrorFallbackProps): React.JSX.Element;
21
+
22
+ export { type PortfolioErrorFallbackProps, PortfolioErrorFallback as default };
@@ -0,0 +1,9 @@
1
+ 'use client';
2
+ "use client";
3
+ import {
4
+ PortfolioErrorFallback
5
+ } from "../../chunk-K2BGTDSN.js";
6
+ export {
7
+ PortfolioErrorFallback as default
8
+ };
9
+ //# sourceMappingURL=PortfolioErrorFallback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}