@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
@@ -0,0 +1,336 @@
1
+ 'use client';
2
+ "use strict";
3
+ "use client";
4
+ var __create = Object.create;
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
+ var __getOwnPropNames = Object.getOwnPropertyNames;
8
+ var __getProtoOf = Object.getPrototypeOf;
9
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
10
+ var __export = (target, all) => {
11
+ for (var name in all)
12
+ __defProp(target, name, { get: all[name], enumerable: true });
13
+ };
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") {
16
+ for (let key of __getOwnPropNames(from))
17
+ if (!__hasOwnProp.call(to, key) && key !== except)
18
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
+ // If the importer is in node compatibility mode or this is not an ESM
24
+ // file that has been converted to a CommonJS file using a Babel-
25
+ // compatible transform (i.e. "__esModule" has not been set), then set
26
+ // "default" to the CommonJS "module.exports" for node compatibility.
27
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
28
+ mod
29
+ ));
30
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
31
+
32
+ // src/portfolio/components/sections/PerformanceSection.tsx
33
+ var PerformanceSection_exports = {};
34
+ __export(PerformanceSection_exports, {
35
+ default: () => PerformanceSection
36
+ });
37
+ module.exports = __toCommonJS(PerformanceSection_exports);
38
+ var import_react = require("react");
39
+ var import_ScrollReveal = __toESM(require("@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal"), 1);
40
+ var import_GlassCard = __toESM(require("@sonordev/agency-site-kit/portfolio/primitives/GlassCard"), 1);
41
+ var import_jsx_runtime = require("react/jsx-runtime");
42
+ var CATEGORIES = [
43
+ { key: "performance", label: "Performance", color: "#10b981" },
44
+ { key: "seo", label: "SEO", color: "#6366f1" },
45
+ { key: "accessibility", label: "Accessibility", color: "#f59e0b" },
46
+ { key: "bestPractices", label: "Best Practices", color: "#3b82f6" }
47
+ ];
48
+ function getScoreColor(score) {
49
+ if (score >= 90) return "#10b981";
50
+ if (score >= 50) return "#f59e0b";
51
+ return "#ef4444";
52
+ }
53
+ var EASE = "cubic-bezier(0.25, 0.46, 0.45, 0.94)";
54
+ var RADIUS = 44;
55
+ var CIRCUMFERENCE = 2 * Math.PI * RADIUS;
56
+ function ScoreGauge({
57
+ score,
58
+ label,
59
+ previousScore,
60
+ delay = 0
61
+ }) {
62
+ const circleRef = (0, import_react.useRef)(null);
63
+ const [displayScore, setDisplayScore] = (0, import_react.useState)(score);
64
+ (0, import_react.useEffect)(() => {
65
+ const circle = circleRef.current;
66
+ if (!circle) return;
67
+ if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
68
+ setDisplayScore(score);
69
+ return;
70
+ }
71
+ const rect = circle.getBoundingClientRect();
72
+ if (rect.top < window.innerHeight && rect.bottom > 0) {
73
+ setDisplayScore(score);
74
+ return;
75
+ }
76
+ const finalOffset = CIRCUMFERENCE - score / 100 * CIRCUMFERENCE;
77
+ circle.style.strokeDashoffset = String(CIRCUMFERENCE);
78
+ setDisplayScore(0);
79
+ let raf = 0;
80
+ const easeOut = (t) => 1 - Math.pow(1 - t, 2);
81
+ const io = new IntersectionObserver(
82
+ ([entry]) => {
83
+ if (!entry.isIntersecting) return;
84
+ io.disconnect();
85
+ circle.style.transition = `stroke-dashoffset 1.5s ${EASE} ${delay}s`;
86
+ circle.style.strokeDashoffset = String(finalOffset);
87
+ const start = performance.now();
88
+ const tick = (now) => {
89
+ const p = Math.min(1, Math.max(0, (now - start - delay * 1e3) / 1500));
90
+ setDisplayScore(Math.round(easeOut(p) * score));
91
+ if (p < 1) raf = requestAnimationFrame(tick);
92
+ };
93
+ raf = requestAnimationFrame(tick);
94
+ },
95
+ { rootMargin: "0px 0px -15% 0px" }
96
+ // ≈ the old 'top 85%' trigger
97
+ );
98
+ io.observe(circle);
99
+ return () => {
100
+ io.disconnect();
101
+ cancelAnimationFrame(raf);
102
+ circle.style.transition = "";
103
+ circle.style.strokeDashoffset = "";
104
+ };
105
+ }, [score, delay]);
106
+ const color = getScoreColor(score);
107
+ const improvement = previousScore ? score - previousScore : void 0;
108
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col items-center gap-3", children: [
109
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative w-28 h-28", children: [
110
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { className: "w-full h-full -rotate-90", viewBox: "0 0 100 100", children: [
111
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
112
+ "circle",
113
+ {
114
+ cx: "50",
115
+ cy: "50",
116
+ r: "44",
117
+ fill: "none",
118
+ stroke: "var(--sk-surface, rgba(255,255,255,0.05))",
119
+ strokeWidth: "6"
120
+ }
121
+ ),
122
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
123
+ "circle",
124
+ {
125
+ ref: circleRef,
126
+ cx: "50",
127
+ cy: "50",
128
+ r: RADIUS,
129
+ fill: "none",
130
+ stroke: color,
131
+ strokeWidth: "6",
132
+ strokeLinecap: "round",
133
+ strokeDasharray: CIRCUMFERENCE,
134
+ strokeDashoffset: CIRCUMFERENCE - score / 100 * CIRCUMFERENCE
135
+ }
136
+ )
137
+ ] }),
138
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
139
+ "span",
140
+ {
141
+ className: "text-2xl font-bold",
142
+ style: { color },
143
+ children: displayScore
144
+ }
145
+ ) })
146
+ ] }),
147
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
148
+ "span",
149
+ {
150
+ className: "text-sm font-medium text-center",
151
+ style: { color: "var(--sk-text-primary, #ffffff)" },
152
+ children: label
153
+ }
154
+ ),
155
+ improvement !== void 0 && improvement > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
156
+ "span",
157
+ {
158
+ className: "text-xs font-semibold px-2 py-0.5 rounded-full",
159
+ style: {
160
+ background: "color-mix(in srgb, #10b981 15%, transparent)",
161
+ color: "#10b981"
162
+ },
163
+ children: [
164
+ "+",
165
+ improvement,
166
+ " pts"
167
+ ]
168
+ }
169
+ )
170
+ ] });
171
+ }
172
+ function PerformanceSection({ data }) {
173
+ const hasBeforeAfter = data.before && data.after;
174
+ const scores = data.after || data.before;
175
+ if (!scores && !data.cwv) return null;
176
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
177
+ "section",
178
+ {
179
+ className: "w-full py-20 md:py-28",
180
+ style: { background: "var(--sk-bg, #0a0a0a)" },
181
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "max-w-5xl mx-auto px-6", children: [
182
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ScrollReveal.default, { y: 30, children: [
183
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
184
+ "h2",
185
+ {
186
+ className: "text-3xl md:text-4xl font-bold mb-4",
187
+ style: {
188
+ color: "var(--sk-text-primary, #ffffff)",
189
+ fontFamily: "var(--sk-font-heading, inherit)"
190
+ },
191
+ children: "Performance"
192
+ }
193
+ ),
194
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
195
+ "p",
196
+ {
197
+ className: "text-lg mb-12 max-w-2xl",
198
+ style: { color: "var(--sk-text-secondary, #a1a1aa)" },
199
+ children: hasBeforeAfter ? "Real Lighthouse scores, before and after our rebuild." : "Real performance metrics measured by Google Lighthouse."
200
+ }
201
+ )
202
+ ] }),
203
+ scores && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ScrollReveal.default, { y: 30, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-8 mb-8", children: CATEGORIES.map((cat, i) => {
204
+ const currentScore = scores[cat.key];
205
+ const previousScore = hasBeforeAfter ? data.before?.[cat.key] : void 0;
206
+ if (currentScore === void 0) return null;
207
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
208
+ ScoreGauge,
209
+ {
210
+ score: currentScore,
211
+ label: cat.label,
212
+ previousScore,
213
+ delay: i * 0.15
214
+ },
215
+ cat.key
216
+ );
217
+ }) }) }),
218
+ hasBeforeAfter && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ScrollReveal.default, { y: 30, delay: 0.3, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "grid md:grid-cols-2 gap-4", children: [
219
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_GlassCard.default, { padding: "lg", hover: false, children: [
220
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
221
+ "h3",
222
+ {
223
+ className: "text-sm font-semibold uppercase tracking-wider mb-4",
224
+ style: { color: "#ef4444" },
225
+ children: "Before (Original Site)"
226
+ }
227
+ ),
228
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid grid-cols-2 gap-3", children: CATEGORIES.map((cat) => {
229
+ const val = data.before?.[cat.key];
230
+ if (val === void 0) return null;
231
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "text-center", children: [
232
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-2xl font-bold", style: { color: getScoreColor(val) }, children: val }),
233
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
234
+ "span",
235
+ {
236
+ className: "block text-[11px] mt-1",
237
+ style: { color: "var(--sk-text-tertiary, #71717a)" },
238
+ children: cat.label
239
+ }
240
+ )
241
+ ] }, cat.key);
242
+ }) })
243
+ ] }),
244
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_GlassCard.default, { padding: "lg", hover: false, children: [
245
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
246
+ "h3",
247
+ {
248
+ className: "text-sm font-semibold uppercase tracking-wider mb-4",
249
+ style: { color: "#10b981" },
250
+ children: "After (Next.js Rebuild)"
251
+ }
252
+ ),
253
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid grid-cols-2 gap-3", children: CATEGORIES.map((cat) => {
254
+ const val = data.after?.[cat.key];
255
+ if (val === void 0) return null;
256
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "text-center", children: [
257
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-2xl font-bold", style: { color: getScoreColor(val) }, children: val }),
258
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
259
+ "span",
260
+ {
261
+ className: "block text-[11px] mt-1",
262
+ style: { color: "var(--sk-text-tertiary, #71717a)" },
263
+ children: cat.label
264
+ }
265
+ )
266
+ ] }, cat.key);
267
+ }) })
268
+ ] })
269
+ ] }) }),
270
+ data.cwv && (data.cwv.lcp != null || data.cwv.cls != null || data.cwv.inp != null) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ScrollReveal.default, { y: 30, delay: 0.4, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "grid grid-cols-3 gap-4 mt-8", children: [
271
+ data.cwv.lcp != null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_GlassCard.default, { padding: "md", hover: false, className: "text-center", children: [
272
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
273
+ "span",
274
+ {
275
+ className: "text-2xl font-bold",
276
+ style: { color: data.cwv.lcp < 2500 ? "#10b981" : data.cwv.lcp < 4e3 ? "#f59e0b" : "#ef4444" },
277
+ children: [
278
+ (data.cwv.lcp / 1e3).toFixed(1),
279
+ "s"
280
+ ]
281
+ }
282
+ ),
283
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
284
+ "span",
285
+ {
286
+ className: "block text-xs mt-1",
287
+ style: { color: "var(--sk-text-tertiary, #71717a)" },
288
+ children: "LCP"
289
+ }
290
+ )
291
+ ] }),
292
+ data.cwv.cls != null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_GlassCard.default, { padding: "md", hover: false, className: "text-center", children: [
293
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
294
+ "span",
295
+ {
296
+ className: "text-2xl font-bold",
297
+ style: { color: data.cwv.cls < 0.1 ? "#10b981" : data.cwv.cls < 0.25 ? "#f59e0b" : "#ef4444" },
298
+ children: data.cwv.cls.toFixed(3)
299
+ }
300
+ ),
301
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
302
+ "span",
303
+ {
304
+ className: "block text-xs mt-1",
305
+ style: { color: "var(--sk-text-tertiary, #71717a)" },
306
+ children: "CLS"
307
+ }
308
+ )
309
+ ] }),
310
+ data.cwv.inp != null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_GlassCard.default, { padding: "md", hover: false, className: "text-center", children: [
311
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
312
+ "span",
313
+ {
314
+ className: "text-2xl font-bold",
315
+ style: { color: data.cwv.inp < 200 ? "#10b981" : data.cwv.inp < 500 ? "#f59e0b" : "#ef4444" },
316
+ children: [
317
+ data.cwv.inp,
318
+ "ms"
319
+ ]
320
+ }
321
+ ),
322
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
323
+ "span",
324
+ {
325
+ className: "block text-xs mt-1",
326
+ style: { color: "var(--sk-text-tertiary, #71717a)" },
327
+ children: "INP"
328
+ }
329
+ )
330
+ ] })
331
+ ] }) })
332
+ ] })
333
+ }
334
+ );
335
+ }
336
+ //# sourceMappingURL=PerformanceSection.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/portfolio/components/sections/PerformanceSection.tsx"],"sourcesContent":["'use client';\n\nimport React, { useRef, useEffect, useState } from 'react';\nimport ScrollReveal from '@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal';\nimport GlassCard from '@sonordev/agency-site-kit/portfolio/primitives/GlassCard';\n\ninterface LighthouseScores {\n performance?: number;\n seo?: number;\n accessibility?: number;\n bestPractices?: number;\n}\n\ninterface PerformanceSectionProps {\n data: {\n before?: LighthouseScores;\n after?: LighthouseScores;\n cwv?: {\n lcp?: number;\n cls?: number;\n inp?: number;\n };\n };\n}\n\nconst CATEGORIES = [\n { key: 'performance', label: 'Performance', color: '#10b981' },\n { key: 'seo', label: 'SEO', color: '#6366f1' },\n { key: 'accessibility', label: 'Accessibility', color: '#f59e0b' },\n { key: 'bestPractices', label: 'Best Practices', color: '#3b82f6' },\n] as const;\n\nfunction getScoreColor(score: number): string {\n if (score >= 90) return '#10b981'; // green\n if (score >= 50) return '#f59e0b'; // amber\n return '#ef4444'; // red\n}\n\nconst EASE = 'cubic-bezier(0.25, 0.46, 0.45, 0.94)'; // ≈ power2.out\nconst RADIUS = 44;\nconst CIRCUMFERENCE = 2 * Math.PI * RADIUS;\n\nfunction ScoreGauge({\n score,\n label,\n previousScore,\n delay = 0,\n}: {\n score: number;\n label: string;\n previousScore?: number;\n delay?: number;\n}) {\n const circleRef = useRef<SVGCircleElement>(null);\n // SSR renders the real final score + arc (crawlers and no-JS users see the\n // true number); the count-up only runs for gauges below the viewport.\n const [displayScore, setDisplayScore] = useState(score);\n\n useEffect(() => {\n const circle = circleRef.current;\n if (!circle) return;\n\n if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {\n setDisplayScore(score);\n return;\n }\n\n // Never re-hide a gauge already in the viewport at hydration.\n const rect = circle.getBoundingClientRect();\n if (rect.top < window.innerHeight && rect.bottom > 0) {\n setDisplayScore(score);\n return;\n }\n\n // Hidden state: arc fully retracted, score zeroed.\n const finalOffset = CIRCUMFERENCE - (score / 100) * CIRCUMFERENCE;\n circle.style.strokeDashoffset = String(CIRCUMFERENCE);\n setDisplayScore(0);\n\n let raf = 0;\n const easeOut = (t: number) => 1 - Math.pow(1 - t, 2); // ≈ power2.out\n\n const io = new IntersectionObserver(\n ([entry]) => {\n if (!entry.isIntersecting) return;\n io.disconnect();\n // Draw the arc in, and count the score up in sync with the draw.\n circle.style.transition = `stroke-dashoffset 1.5s ${EASE} ${delay}s`;\n circle.style.strokeDashoffset = String(finalOffset);\n const start = performance.now();\n const tick = (now: number) => {\n const p = Math.min(1, Math.max(0, (now - start - delay * 1000) / 1500));\n setDisplayScore(Math.round(easeOut(p) * score));\n if (p < 1) raf = requestAnimationFrame(tick);\n };\n raf = requestAnimationFrame(tick);\n },\n { rootMargin: '0px 0px -15% 0px' }, // ≈ the old 'top 85%' trigger\n );\n io.observe(circle);\n\n return () => {\n io.disconnect();\n cancelAnimationFrame(raf);\n circle.style.transition = '';\n circle.style.strokeDashoffset = '';\n };\n }, [score, delay]);\n\n const color = getScoreColor(score);\n const improvement = previousScore ? score - previousScore : undefined;\n\n return (\n <div className=\"flex flex-col items-center gap-3\">\n <div className=\"relative w-28 h-28\">\n <svg className=\"w-full h-full -rotate-90\" viewBox=\"0 0 100 100\">\n {/* Background circle */}\n <circle\n cx=\"50\"\n cy=\"50\"\n r=\"44\"\n fill=\"none\"\n stroke=\"var(--sk-surface, rgba(255,255,255,0.05))\"\n strokeWidth=\"6\"\n />\n {/* Score arc — rendered at its final sweep; the effect retracts and\n redraws it only when the gauge scrolls in */}\n <circle\n ref={circleRef}\n cx=\"50\"\n cy=\"50\"\n r={RADIUS}\n fill=\"none\"\n stroke={color}\n strokeWidth=\"6\"\n strokeLinecap=\"round\"\n strokeDasharray={CIRCUMFERENCE}\n strokeDashoffset={CIRCUMFERENCE - (score / 100) * CIRCUMFERENCE}\n />\n </svg>\n {/* Score text */}\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <span\n className=\"text-2xl font-bold\"\n style={{ color }}\n >\n {displayScore}\n </span>\n </div>\n </div>\n <span\n className=\"text-sm font-medium text-center\"\n style={{ color: 'var(--sk-text-primary, #ffffff)' }}\n >\n {label}\n </span>\n {improvement !== undefined && improvement > 0 && (\n <span\n className=\"text-xs font-semibold px-2 py-0.5 rounded-full\"\n style={{\n background: 'color-mix(in srgb, #10b981 15%, transparent)',\n color: '#10b981',\n }}\n >\n +{improvement} pts\n </span>\n )}\n </div>\n );\n}\n\nexport default function PerformanceSection({ data }: PerformanceSectionProps) {\n const hasBeforeAfter = data.before && data.after;\n const scores = data.after || data.before;\n if (!scores && !data.cwv) return null;\n\n return (\n <section\n className=\"w-full py-20 md:py-28\"\n style={{ background: 'var(--sk-bg, #0a0a0a)' }}\n >\n <div className=\"max-w-5xl mx-auto px-6\">\n <ScrollReveal y={30}>\n <h2\n className=\"text-3xl md:text-4xl font-bold mb-4\"\n style={{\n color: 'var(--sk-text-primary, #ffffff)',\n fontFamily: 'var(--sk-font-heading, inherit)',\n }}\n >\n Performance\n </h2>\n <p\n className=\"text-lg mb-12 max-w-2xl\"\n style={{ color: 'var(--sk-text-secondary, #a1a1aa)' }}\n >\n {hasBeforeAfter\n ? 'Real Lighthouse scores, before and after our rebuild.'\n : 'Real performance metrics measured by Google Lighthouse.'}\n </p>\n </ScrollReveal>\n\n {/* Score gauges */}\n {scores && (\n <ScrollReveal y={30}>\n <div className=\"grid grid-cols-2 md:grid-cols-4 gap-8 mb-8\">\n {CATEGORIES.map((cat, i) => {\n const currentScore = (scores as any)[cat.key];\n const previousScore = hasBeforeAfter ? (data.before as any)?.[cat.key] : undefined;\n if (currentScore === undefined) return null;\n return (\n <ScoreGauge\n key={cat.key}\n score={currentScore}\n label={cat.label}\n previousScore={previousScore}\n delay={i * 0.15}\n />\n );\n })}\n </div>\n </ScrollReveal>\n )}\n\n {/* Before/After comparison cards */}\n {hasBeforeAfter && (\n <ScrollReveal y={30} delay={0.3}>\n <div className=\"grid md:grid-cols-2 gap-4\">\n <GlassCard padding=\"lg\" hover={false}>\n <h3\n className=\"text-sm font-semibold uppercase tracking-wider mb-4\"\n style={{ color: '#ef4444' }}\n >\n Before (Original Site)\n </h3>\n <div className=\"grid grid-cols-2 gap-3\">\n {CATEGORIES.map((cat) => {\n const val = (data.before as any)?.[cat.key];\n if (val === undefined) return null;\n return (\n <div key={cat.key} className=\"text-center\">\n <span className=\"text-2xl font-bold\" style={{ color: getScoreColor(val) }}>\n {val}\n </span>\n <span\n className=\"block text-[11px] mt-1\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {cat.label}\n </span>\n </div>\n );\n })}\n </div>\n </GlassCard>\n <GlassCard padding=\"lg\" hover={false}>\n <h3\n className=\"text-sm font-semibold uppercase tracking-wider mb-4\"\n style={{ color: '#10b981' }}\n >\n After (Next.js Rebuild)\n </h3>\n <div className=\"grid grid-cols-2 gap-3\">\n {CATEGORIES.map((cat) => {\n const val = (data.after as any)?.[cat.key];\n if (val === undefined) return null;\n return (\n <div key={cat.key} className=\"text-center\">\n <span className=\"text-2xl font-bold\" style={{ color: getScoreColor(val) }}>\n {val}\n </span>\n <span\n className=\"block text-[11px] mt-1\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {cat.label}\n </span>\n </div>\n );\n })}\n </div>\n </GlassCard>\n </div>\n </ScrollReveal>\n )}\n\n {/* Core Web Vitals */}\n {data.cwv && (data.cwv.lcp != null || data.cwv.cls != null || data.cwv.inp != null) && (\n <ScrollReveal y={30} delay={0.4}>\n <div className=\"grid grid-cols-3 gap-4 mt-8\">\n {data.cwv.lcp != null && (\n <GlassCard padding=\"md\" hover={false} className=\"text-center\">\n <span\n className=\"text-2xl font-bold\"\n style={{ color: data.cwv.lcp < 2500 ? '#10b981' : data.cwv.lcp < 4000 ? '#f59e0b' : '#ef4444' }}\n >\n {(data.cwv.lcp / 1000).toFixed(1)}s\n </span>\n <span\n className=\"block text-xs mt-1\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n LCP\n </span>\n </GlassCard>\n )}\n {data.cwv.cls != null && (\n <GlassCard padding=\"md\" hover={false} className=\"text-center\">\n <span\n className=\"text-2xl font-bold\"\n style={{ color: data.cwv.cls < 0.1 ? '#10b981' : data.cwv.cls < 0.25 ? '#f59e0b' : '#ef4444' }}\n >\n {data.cwv.cls.toFixed(3)}\n </span>\n <span\n className=\"block text-xs mt-1\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n CLS\n </span>\n </GlassCard>\n )}\n {data.cwv.inp != null && (\n <GlassCard padding=\"md\" hover={false} className=\"text-center\">\n <span\n className=\"text-2xl font-bold\"\n style={{ color: data.cwv.inp < 200 ? '#10b981' : data.cwv.inp < 500 ? '#f59e0b' : '#ef4444' }}\n >\n {data.cwv.inp}ms\n </span>\n <span\n className=\"block text-xs mt-1\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n INP\n </span>\n </GlassCard>\n )}\n </div>\n </ScrollReveal>\n )}\n </div>\n </section>\n );\n}\n"],"mappings":"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","names":["ScrollReveal","GlassCard"]}
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+
3
+ interface LighthouseScores {
4
+ performance?: number;
5
+ seo?: number;
6
+ accessibility?: number;
7
+ bestPractices?: number;
8
+ }
9
+ interface PerformanceSectionProps {
10
+ data: {
11
+ before?: LighthouseScores;
12
+ after?: LighthouseScores;
13
+ cwv?: {
14
+ lcp?: number;
15
+ cls?: number;
16
+ inp?: number;
17
+ };
18
+ };
19
+ }
20
+ declare function PerformanceSection({ data }: PerformanceSectionProps): React.JSX.Element | null;
21
+
22
+ export { PerformanceSection as default };
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+
3
+ interface LighthouseScores {
4
+ performance?: number;
5
+ seo?: number;
6
+ accessibility?: number;
7
+ bestPractices?: number;
8
+ }
9
+ interface PerformanceSectionProps {
10
+ data: {
11
+ before?: LighthouseScores;
12
+ after?: LighthouseScores;
13
+ cwv?: {
14
+ lcp?: number;
15
+ cls?: number;
16
+ inp?: number;
17
+ };
18
+ };
19
+ }
20
+ declare function PerformanceSection({ data }: PerformanceSectionProps): React.JSX.Element | null;
21
+
22
+ export { PerformanceSection as default };
@@ -1,11 +1,11 @@
1
1
  'use client';
2
- import { GlassCard } from './chunk-YB4B3OMC.js';
3
- import { ScrollReveal } from './chunk-7CFFAKDM.js';
4
- import { useRef, useState, useEffect } from 'react';
5
- import gsap from 'gsap';
6
- import { ScrollTrigger } from 'gsap/ScrollTrigger';
7
- import { jsx, jsxs } from 'react/jsx-runtime';
2
+ "use client";
8
3
 
4
+ // src/portfolio/components/sections/PerformanceSection.tsx
5
+ import { useRef, useEffect, useState } from "react";
6
+ import ScrollReveal from "@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal";
7
+ import GlassCard from "@sonordev/agency-site-kit/portfolio/primitives/GlassCard";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
9
  var CATEGORIES = [
10
10
  { key: "performance", label: "Performance", color: "#10b981" },
11
11
  { key: "seo", label: "SEO", color: "#6366f1" },
@@ -17,6 +17,9 @@ function getScoreColor(score) {
17
17
  if (score >= 50) return "#f59e0b";
18
18
  return "#ef4444";
19
19
  }
20
+ var EASE = "cubic-bezier(0.25, 0.46, 0.45, 0.94)";
21
+ var RADIUS = 44;
22
+ var CIRCUMFERENCE = 2 * Math.PI * RADIUS;
20
23
  function ScoreGauge({
21
24
  score,
22
25
  label,
@@ -24,35 +27,48 @@ function ScoreGauge({
24
27
  delay = 0
25
28
  }) {
26
29
  const circleRef = useRef(null);
27
- const [displayScore, setDisplayScore] = useState(0);
30
+ const [displayScore, setDisplayScore] = useState(score);
28
31
  useEffect(() => {
29
- gsap.registerPlugin(ScrollTrigger);
30
- if (!circleRef.current) return;
31
- const radius = 44;
32
- const circumference = 2 * Math.PI * radius;
33
- const offset = circumference - score / 100 * circumference;
34
- gsap.set(circleRef.current, {
35
- strokeDasharray: circumference,
36
- strokeDashoffset: circumference
37
- });
38
- const ctx = gsap.context(() => {
39
- gsap.to(circleRef.current, {
40
- strokeDashoffset: offset,
41
- duration: 1.5,
42
- ease: "power2.out",
43
- delay,
44
- scrollTrigger: {
45
- trigger: circleRef.current,
46
- start: "top 85%",
47
- toggleActions: "play none none none"
48
- },
49
- onUpdate: function() {
50
- const progress = 1 - (this.targets()[0].style.strokeDashoffset ? parseFloat(this.targets()[0].style.strokeDashoffset) / circumference : 0);
51
- setDisplayScore(Math.round(progress * score));
52
- }
53
- });
54
- });
55
- return () => ctx.revert();
32
+ const circle = circleRef.current;
33
+ if (!circle) return;
34
+ if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
35
+ setDisplayScore(score);
36
+ return;
37
+ }
38
+ const rect = circle.getBoundingClientRect();
39
+ if (rect.top < window.innerHeight && rect.bottom > 0) {
40
+ setDisplayScore(score);
41
+ return;
42
+ }
43
+ const finalOffset = CIRCUMFERENCE - score / 100 * CIRCUMFERENCE;
44
+ circle.style.strokeDashoffset = String(CIRCUMFERENCE);
45
+ setDisplayScore(0);
46
+ let raf = 0;
47
+ const easeOut = (t) => 1 - Math.pow(1 - t, 2);
48
+ const io = new IntersectionObserver(
49
+ ([entry]) => {
50
+ if (!entry.isIntersecting) return;
51
+ io.disconnect();
52
+ circle.style.transition = `stroke-dashoffset 1.5s ${EASE} ${delay}s`;
53
+ circle.style.strokeDashoffset = String(finalOffset);
54
+ const start = performance.now();
55
+ const tick = (now) => {
56
+ const p = Math.min(1, Math.max(0, (now - start - delay * 1e3) / 1500));
57
+ setDisplayScore(Math.round(easeOut(p) * score));
58
+ if (p < 1) raf = requestAnimationFrame(tick);
59
+ };
60
+ raf = requestAnimationFrame(tick);
61
+ },
62
+ { rootMargin: "0px 0px -15% 0px" }
63
+ // ≈ the old 'top 85%' trigger
64
+ );
65
+ io.observe(circle);
66
+ return () => {
67
+ io.disconnect();
68
+ cancelAnimationFrame(raf);
69
+ circle.style.transition = "";
70
+ circle.style.strokeDashoffset = "";
71
+ };
56
72
  }, [score, delay]);
57
73
  const color = getScoreColor(score);
58
74
  const improvement = previousScore ? score - previousScore : void 0;
@@ -76,11 +92,13 @@ function ScoreGauge({
76
92
  ref: circleRef,
77
93
  cx: "50",
78
94
  cy: "50",
79
- r: "44",
95
+ r: RADIUS,
80
96
  fill: "none",
81
97
  stroke: color,
82
98
  strokeWidth: "6",
83
- strokeLinecap: "round"
99
+ strokeLinecap: "round",
100
+ strokeDasharray: CIRCUMFERENCE,
101
+ strokeDashoffset: CIRCUMFERENCE - score / 100 * CIRCUMFERENCE
84
102
  }
85
103
  )
86
104
  ] }),
@@ -118,24 +136,6 @@ function ScoreGauge({
118
136
  )
119
137
  ] });
120
138
  }
121
- var SCORE_EXPLANATIONS = {
122
- performance: {
123
- why: "Faster sites convert more visitors into customers. A 1-second delay in load time reduces conversions by up to 7%. Google uses page speed as a direct ranking factor.",
124
- competitors: "Wix and GoDaddy sites typically score 30\u201350 due to bloated JavaScript bundles and shared hosting. Template builders prioritize ease-of-use over speed."
125
- },
126
- seo: {
127
- why: "Technical SEO determines whether search engines can properly crawl, index, and rank your pages. Higher scores mean more organic visibility and free traffic.",
128
- competitors: "DIY builders often miss critical SEO fundamentals\u2014proper meta tags, structured data, canonical URLs, and server-side rendering that search engines need."
129
- },
130
- accessibility: {
131
- why: "Accessible sites reach more customers, including the 1 in 4 adults with disabilities. It also reduces legal risk and improves usability for everyone.",
132
- competitors: "Template platforms generate markup that frequently fails WCAG standards\u2014missing alt text, poor contrast ratios, and keyboard navigation issues."
133
- },
134
- bestPractices: {
135
- why: "Best practices cover security (HTTPS, safe APIs), modern code standards, and browser compatibility. They protect your business and your visitors.",
136
- competitors: "Older platforms rely on outdated libraries, insecure dependencies, and legacy patterns that create vulnerabilities and degrade user trust."
137
- }
138
- };
139
139
  function PerformanceSection({ data }) {
140
140
  const hasBeforeAfter = data.before && data.after;
141
141
  const scores = data.after || data.before;
@@ -163,7 +163,7 @@ function PerformanceSection({ data }) {
163
163
  {
164
164
  className: "text-lg mb-12 max-w-2xl",
165
165
  style: { color: "var(--sk-text-secondary, #a1a1aa)" },
166
- children: hasBeforeAfter ? "Real Lighthouse scores \u2014 before and after our rebuild." : "Real performance metrics measured by Google Lighthouse."
166
+ children: hasBeforeAfter ? "Real Lighthouse scores, before and after our rebuild." : "Real performance metrics measured by Google Lighthouse."
167
167
  }
168
168
  )
169
169
  ] }),
@@ -182,51 +182,6 @@ function PerformanceSection({ data }) {
182
182
  cat.key
183
183
  );
184
184
  }) }) }),
185
- scores && /* @__PURE__ */ jsx(ScrollReveal, { y: 30, delay: 0.2, children: /* @__PURE__ */ jsx("div", { className: "grid md:grid-cols-2 gap-4 mb-12", children: CATEGORIES.map((cat) => {
186
- const currentScore = scores[cat.key];
187
- if (currentScore === void 0) return null;
188
- const explanation = SCORE_EXPLANATIONS[cat.key];
189
- if (!explanation) return null;
190
- return /* @__PURE__ */ jsx(GlassCard, { padding: "md", hover: false, children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
191
- /* @__PURE__ */ jsx(
192
- "div",
193
- {
194
- className: "w-10 h-10 rounded-lg flex items-center justify-center shrink-0 text-sm font-bold",
195
- style: {
196
- background: `color-mix(in srgb, ${getScoreColor(currentScore)} 15%, transparent)`,
197
- color: getScoreColor(currentScore)
198
- },
199
- children: currentScore
200
- }
201
- ),
202
- /* @__PURE__ */ jsxs("div", { children: [
203
- /* @__PURE__ */ jsx(
204
- "h4",
205
- {
206
- className: "text-sm font-semibold mb-1",
207
- style: { color: "var(--sk-text-primary, #ffffff)" },
208
- children: cat.label
209
- }
210
- ),
211
- /* @__PURE__ */ jsx(
212
- "p",
213
- {
214
- className: "text-xs leading-relaxed mb-2",
215
- style: { color: "var(--sk-text-secondary, #a1a1aa)" },
216
- children: explanation.why
217
- }
218
- ),
219
- /* @__PURE__ */ jsx(
220
- "p",
221
- {
222
- className: "text-xs leading-relaxed",
223
- style: { color: "var(--sk-text-tertiary, #71717a)" },
224
- children: explanation.competitors
225
- }
226
- )
227
- ] })
228
- ] }) }, cat.key);
229
- }) }) }),
230
185
  hasBeforeAfter && /* @__PURE__ */ jsx(ScrollReveal, { y: 30, delay: 0.3, children: /* @__PURE__ */ jsxs("div", { className: "grid md:grid-cols-2 gap-4", children: [
231
186
  /* @__PURE__ */ jsxs(GlassCard, { padding: "lg", hover: false, children: [
232
187
  /* @__PURE__ */ jsx(
@@ -345,7 +300,7 @@ function PerformanceSection({ data }) {
345
300
  }
346
301
  );
347
302
  }
348
-
349
- export { PerformanceSection as default };
350
- //# sourceMappingURL=PerformanceSection-MGCEIXDX.js.map
351
- //# sourceMappingURL=PerformanceSection-MGCEIXDX.js.map
303
+ export {
304
+ PerformanceSection as default
305
+ };
306
+ //# sourceMappingURL=PerformanceSection.js.map