@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,43 +1,35 @@
1
1
  'use client';
2
- import { ScrollReveal } from './chunk-7CFFAKDM.js';
3
- import { useState, useCallback, useRef, useEffect } from 'react';
4
- import gsap from 'gsap';
5
- import { jsxs, jsx } from 'react/jsx-runtime';
2
+ "use client";
3
+ import {
4
+ resolvePortfolioImage
5
+ } from "../../chunk-QDXZ27R7.js";
6
6
 
7
+ // src/portfolio/components/sections/FeatureSpotlightSection.tsx
8
+ import { useState, useCallback } from "react";
9
+ import Image from "next/image";
10
+ import ScrollReveal from "@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal";
11
+ import { jsx, jsxs } from "react/jsx-runtime";
7
12
  function AnnotationPin({
8
13
  annotation,
9
14
  index,
10
15
  activeIndex,
11
16
  onSelect
12
17
  }) {
13
- const pinRef = useRef(null);
14
18
  const isActive = activeIndex === index;
15
- useEffect(() => {
16
- if (!pinRef.current) return;
17
- if (isActive) {
18
- gsap.to(pinRef.current, {
19
- scale: 1.2,
20
- duration: 0.3,
21
- ease: "back.out(2)"
22
- });
23
- } else {
24
- gsap.to(pinRef.current, {
25
- scale: 1,
26
- duration: 0.2,
27
- ease: "power2.out"
28
- });
29
- }
30
- }, [isActive]);
31
19
  return /* @__PURE__ */ jsxs(
32
20
  "button",
33
21
  {
34
- ref: pinRef,
35
22
  onClick: () => onSelect(isActive ? null : index),
36
- className: "absolute z-10 flex items-center justify-center w-8 h-8 rounded-full text-xs font-bold transition-colors cursor-pointer",
23
+ className: "absolute z-10 flex items-center justify-center w-8 h-8 rounded-full text-xs font-bold cursor-pointer",
37
24
  style: {
38
25
  left: `${annotation.x}%`,
39
26
  top: `${annotation.y}%`,
40
- transform: "translate(-50%, -50%)",
27
+ // Active pop: back.out-style overshoot in (.3s), power2.out-style
28
+ // settle out (.2s) — CSS applies the post-change transition value,
29
+ // so each direction keeps its own timing. background-color keeps
30
+ // the 150ms fade the old transition-colors class provided.
31
+ transition: isActive ? "transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1)" : "transform 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94), background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1)",
32
+ transform: isActive ? "translate(-50%, -50%) scale(1.2)" : "translate(-50%, -50%) scale(1)",
41
33
  background: isActive ? "var(--sk-primary, #6366f1)" : "color-mix(in srgb, var(--sk-primary, #6366f1) 80%, transparent)",
42
34
  color: "#ffffff",
43
35
  boxShadow: isActive ? "0 0 20px color-mix(in srgb, var(--sk-primary, #6366f1) 50%, transparent)" : "0 4px 12px rgba(0,0,0,0.3)",
@@ -96,24 +88,38 @@ function AnnotationPin({
96
88
  }
97
89
  function FeatureSpotlightSection({ data }) {
98
90
  const [activeAnnotation, setActiveAnnotation] = useState(null);
99
- const imageUrl = data.image?.asset?._ref || "";
91
+ const image = resolvePortfolioImage(data.image);
100
92
  const layout = data.layout || "left";
101
93
  const handleSelect = useCallback((index) => {
102
94
  setActiveAnnotation(index);
103
95
  }, []);
104
96
  const imageBlock = /* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
105
- /* @__PURE__ */ jsx(
97
+ image && (image.width && image.height ? /* @__PURE__ */ jsx(
98
+ Image,
99
+ {
100
+ src: image.url,
101
+ alt: data.title,
102
+ width: image.width,
103
+ height: image.height,
104
+ sizes: "(max-width: 1024px) 100vw, 640px",
105
+ className: "w-full h-auto rounded-xl",
106
+ style: {
107
+ border: "1px solid var(--sk-border, rgba(255,255,255,0.1))"
108
+ }
109
+ }
110
+ ) : /* @__PURE__ */ jsx(
106
111
  "img",
107
112
  {
108
- src: imageUrl,
113
+ src: image.url,
109
114
  alt: data.title,
110
115
  className: "w-full h-auto rounded-xl",
111
116
  style: {
112
117
  border: "1px solid var(--sk-border, rgba(255,255,255,0.1))"
113
118
  },
114
- loading: "lazy"
119
+ loading: "lazy",
120
+ decoding: "async"
115
121
  }
116
- ),
122
+ )),
117
123
  data.annotations.map((annotation, index) => /* @__PURE__ */ jsx(
118
124
  AnnotationPin,
119
125
  {
@@ -199,7 +205,7 @@ function FeatureSpotlightSection({ data }) {
199
205
  }
200
206
  );
201
207
  }
202
-
203
- export { FeatureSpotlightSection as default };
204
- //# sourceMappingURL=FeatureSpotlightSection-B7P3JGNL.js.map
205
- //# sourceMappingURL=FeatureSpotlightSection-B7P3JGNL.js.map
208
+ export {
209
+ FeatureSpotlightSection as default
210
+ };
211
+ //# sourceMappingURL=FeatureSpotlightSection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/portfolio/components/sections/FeatureSpotlightSection.tsx"],"sourcesContent":["'use client';\n\nimport React, { useState, useCallback } from 'react';\nimport Image from 'next/image';\nimport type { PortfolioFeatureSpotlightData, PortfolioAnnotation } from '../../../types';\nimport { resolvePortfolioImage } from '../../../shared/images';\nimport ScrollReveal from '@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal';\n\ninterface FeatureSpotlightSectionProps {\n data: PortfolioFeatureSpotlightData;\n}\n\nfunction AnnotationPin({\n annotation,\n index,\n activeIndex,\n onSelect,\n}: {\n annotation: PortfolioAnnotation;\n index: number;\n activeIndex: number | null;\n onSelect: (index: number | null) => void;\n}) {\n const isActive = activeIndex === index;\n\n return (\n <button\n onClick={() => onSelect(isActive ? null : index)}\n className=\"absolute z-10 flex items-center justify-center w-8 h-8 rounded-full text-xs font-bold cursor-pointer\"\n style={{\n left: `${annotation.x}%`,\n top: `${annotation.y}%`,\n // Active pop: back.out-style overshoot in (.3s), power2.out-style\n // settle out (.2s) — CSS applies the post-change transition value,\n // so each direction keeps its own timing. background-color keeps\n // the 150ms fade the old transition-colors class provided.\n transition: isActive\n ? 'transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1)'\n : 'transform 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94), background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1)',\n transform: isActive\n ? 'translate(-50%, -50%) scale(1.2)'\n : 'translate(-50%, -50%) scale(1)',\n background: isActive\n ? 'var(--sk-primary, #6366f1)'\n : 'color-mix(in srgb, var(--sk-primary, #6366f1) 80%, transparent)',\n color: '#ffffff',\n boxShadow: isActive\n ? '0 0 20px color-mix(in srgb, var(--sk-primary, #6366f1) 50%, transparent)'\n : '0 4px 12px rgba(0,0,0,0.3)',\n border: '2px solid rgba(255,255,255,0.3)',\n willChange: 'transform',\n }}\n aria-label={annotation.label}\n >\n {index + 1}\n\n {/* Tooltip */}\n {isActive && (\n <div\n className=\"absolute bottom-full left-1/2 mb-3 w-56 p-3 rounded-xl text-left\"\n style={{\n transform: 'translateX(-50%)',\n background: 'var(--sk-surface, rgba(255,255,255,0.05))',\n backdropFilter: 'blur(16px)',\n border: '1px solid var(--sk-border, rgba(255,255,255,0.1))',\n boxShadow: '0 8px 32px rgba(0,0,0,0.3)',\n }}\n >\n <div\n className=\"text-sm font-semibold mb-1\"\n style={{ color: 'var(--sk-text-primary, #ffffff)' }}\n >\n {annotation.label}\n </div>\n <div\n className=\"text-xs leading-relaxed\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {annotation.description}\n </div>\n {/* Arrow */}\n <div\n className=\"absolute top-full left-1/2 w-0 h-0\"\n style={{\n transform: 'translateX(-50%)',\n borderLeft: '6px solid transparent',\n borderRight: '6px solid transparent',\n borderTop: '6px solid var(--sk-border, rgba(255,255,255,0.1))',\n }}\n />\n </div>\n )}\n </button>\n );\n}\n\nexport default function FeatureSpotlightSection({ data }: FeatureSpotlightSectionProps) {\n const [activeAnnotation, setActiveAnnotation] = useState<number | null>(null);\n\n const image = resolvePortfolioImage(data.image);\n const layout = data.layout || 'left';\n\n const handleSelect = useCallback((index: number | null) => {\n setActiveAnnotation(index);\n }, []);\n\n const imageBlock = (\n <div className=\"relative w-full\">\n {image &&\n (image.width && image.height ? (\n <Image\n src={image.url}\n alt={data.title}\n width={image.width}\n height={image.height}\n sizes=\"(max-width: 1024px) 100vw, 640px\"\n className=\"w-full h-auto rounded-xl\"\n style={{\n border: '1px solid var(--sk-border, rgba(255,255,255,0.1))',\n }}\n />\n ) : (\n <img\n src={image.url}\n alt={data.title}\n className=\"w-full h-auto rounded-xl\"\n style={{\n border: '1px solid var(--sk-border, rgba(255,255,255,0.1))',\n }}\n loading=\"lazy\"\n decoding=\"async\"\n />\n ))}\n {/* Annotation pins */}\n {data.annotations.map((annotation, index) => (\n <AnnotationPin\n key={index}\n annotation={annotation}\n index={index}\n activeIndex={activeAnnotation}\n onSelect={handleSelect}\n />\n ))}\n </div>\n );\n\n const textBlock = (\n <div className=\"flex flex-col justify-center gap-4\">\n <h2\n className=\"text-3xl md:text-4xl font-bold\"\n style={{\n color: 'var(--sk-text-primary, #ffffff)',\n fontFamily: 'var(--sk-font-heading, inherit)',\n }}\n >\n {data.title}\n </h2>\n <p\n className=\"text-base md:text-lg leading-relaxed\"\n style={{ color: 'var(--sk-text-secondary, #a1a1aa)' }}\n >\n {data.description}\n </p>\n\n {/* Annotation legend */}\n {data.annotations.length > 0 && (\n <div className=\"flex flex-col gap-2 mt-4\">\n {data.annotations.map((annotation, index) => (\n <button\n key={index}\n onClick={() => handleSelect(activeAnnotation === index ? null : index)}\n className=\"flex items-start gap-3 text-left p-2 rounded-lg transition-colors cursor-pointer\"\n style={{\n background:\n activeAnnotation === index\n ? 'color-mix(in srgb, var(--sk-primary, #6366f1) 10%, transparent)'\n : 'transparent',\n }}\n >\n <span\n className=\"flex items-center justify-center w-6 h-6 rounded-full text-xs font-bold shrink-0\"\n style={{\n background: 'color-mix(in srgb, var(--sk-primary, #6366f1) 20%, transparent)',\n color: 'var(--sk-primary, #6366f1)',\n }}\n >\n {index + 1}\n </span>\n <div>\n <span\n className=\"text-sm font-medium\"\n style={{ color: 'var(--sk-text-primary, #ffffff)' }}\n >\n {annotation.label}\n </span>\n </div>\n </button>\n ))}\n </div>\n )}\n </div>\n );\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-7xl mx-auto px-6\">\n {layout === 'full' ? (\n <div className=\"flex flex-col gap-8\">\n <ScrollReveal y={30}>{textBlock}</ScrollReveal>\n <ScrollReveal y={40} delay={0.15}>\n <div className=\"relative\">{imageBlock}</div>\n </ScrollReveal>\n </div>\n ) : (\n <div\n className={`grid lg:grid-cols-2 gap-12 items-center ${\n layout === 'right' ? 'lg:[direction:rtl] lg:[&>*]:![direction:ltr]' : ''\n }`}\n >\n <ScrollReveal y={40}>{imageBlock}</ScrollReveal>\n <ScrollReveal y={40} delay={0.15}>{textBlock}</ScrollReveal>\n </div>\n )}\n </div>\n </section>\n );\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,321 @@
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/GallerySection.tsx
33
+ var GallerySection_exports = {};
34
+ __export(GallerySection_exports, {
35
+ default: () => GallerySection
36
+ });
37
+ module.exports = __toCommonJS(GallerySection_exports);
38
+ var import_react = __toESM(require("react"), 1);
39
+ var import_image = __toESM(require("next/image"), 1);
40
+
41
+ // src/shared/images.ts
42
+ var SANITY_ASSET_REF = /^image-[A-Za-z0-9]+-\d+x\d+-[a-z0-9]+$/;
43
+ var FILENAME_DIMS = /-(\d{2,5})x(\d{2,5})\.[a-z0-9]+(?:\?.*)?$/i;
44
+ var warnedAboutRefs = false;
45
+ function resolvePortfolioImage(input) {
46
+ const raw = typeof input === "string" ? input : input?.asset?._ref ?? "";
47
+ const value = (raw || "").trim();
48
+ if (!value) return null;
49
+ if (SANITY_ASSET_REF.test(value)) {
50
+ if (!warnedAboutRefs && typeof console !== "undefined") {
51
+ warnedAboutRefs = true;
52
+ console.warn(
53
+ "[@sonordev/agency-site-kit] Received a raw Sanity asset ref instead of an image URL \u2014 skipping render. The Sonor API should resolve image refs to cdn.sanity.io URLs before returning portfolio sections."
54
+ );
55
+ }
56
+ return null;
57
+ }
58
+ if (!/^https?:\/\//i.test(value) && !value.startsWith("/")) return null;
59
+ const dims = value.match(FILENAME_DIMS);
60
+ if (dims) {
61
+ const width = parseInt(dims[1], 10);
62
+ const height = parseInt(dims[2], 10);
63
+ if (width > 0 && height > 0) return { url: value, width, height };
64
+ }
65
+ return { url: value };
66
+ }
67
+
68
+ // src/portfolio/components/sections/GallerySection.tsx
69
+ var import_ScrollReveal = __toESM(require("@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal"), 1);
70
+ var import_jsx_runtime = require("react/jsx-runtime");
71
+ var typeBadgeColors = {
72
+ screenshot: {
73
+ bg: "color-mix(in srgb, #6366f1 12%, transparent)",
74
+ text: "#6366f1",
75
+ border: "color-mix(in srgb, #6366f1 20%, transparent)"
76
+ },
77
+ before: {
78
+ bg: "color-mix(in srgb, #f59e0b 12%, transparent)",
79
+ text: "#f59e0b",
80
+ border: "color-mix(in srgb, #f59e0b 20%, transparent)"
81
+ },
82
+ after: {
83
+ bg: "color-mix(in srgb, #10b981 12%, transparent)",
84
+ text: "#10b981",
85
+ border: "color-mix(in srgb, #10b981 20%, transparent)"
86
+ },
87
+ design: {
88
+ bg: "color-mix(in srgb, #ec4899 12%, transparent)",
89
+ text: "#ec4899",
90
+ border: "color-mix(in srgb, #ec4899 20%, transparent)"
91
+ }
92
+ };
93
+ function GallerySection({ data }) {
94
+ const [lightboxIndex, setLightboxIndex] = (0, import_react.useState)(null);
95
+ const dialogRef = import_react.default.useRef(null);
96
+ const restoreFocusRef = import_react.default.useRef(null);
97
+ const layout = data.layout || "grid";
98
+ const openLightbox = (0, import_react.useCallback)((index) => {
99
+ setLightboxIndex(index);
100
+ }, []);
101
+ const closeLightbox = (0, import_react.useCallback)(() => {
102
+ setLightboxIndex(null);
103
+ }, []);
104
+ const goNext = (0, import_react.useCallback)(() => {
105
+ setLightboxIndex(
106
+ (prev) => prev !== null ? (prev + 1) % data.images.length : null
107
+ );
108
+ }, [data.images.length]);
109
+ const goPrev = (0, import_react.useCallback)(() => {
110
+ setLightboxIndex(
111
+ (prev) => prev !== null ? (prev - 1 + data.images.length) % data.images.length : null
112
+ );
113
+ }, [data.images.length]);
114
+ (0, import_react.useEffect)(() => {
115
+ if (lightboxIndex === null) return;
116
+ restoreFocusRef.current = document.activeElement;
117
+ const dialog = dialogRef.current;
118
+ const focusables = () => dialog ? Array.from(
119
+ dialog.querySelectorAll('button, [href], [tabindex]:not([tabindex="-1"])')
120
+ ) : [];
121
+ focusables()[0]?.focus();
122
+ function handleKeyDown(e) {
123
+ if (e.key === "Escape") closeLightbox();
124
+ if (e.key === "ArrowRight") goNext();
125
+ if (e.key === "ArrowLeft") goPrev();
126
+ if (e.key === "Tab") {
127
+ const items = focusables();
128
+ if (items.length === 0) return;
129
+ const first = items[0];
130
+ const last = items[items.length - 1];
131
+ if (e.shiftKey && document.activeElement === first) {
132
+ e.preventDefault();
133
+ last.focus();
134
+ } else if (!e.shiftKey && document.activeElement === last) {
135
+ e.preventDefault();
136
+ first.focus();
137
+ }
138
+ }
139
+ }
140
+ document.addEventListener("keydown", handleKeyDown);
141
+ document.body.style.overflow = "hidden";
142
+ return () => {
143
+ document.removeEventListener("keydown", handleKeyDown);
144
+ document.body.style.overflow = "";
145
+ restoreFocusRef.current?.focus?.();
146
+ };
147
+ }, [lightboxIndex !== null, closeLightbox, goNext, goPrev]);
148
+ function getImage(image) {
149
+ return resolvePortfolioImage(image.image);
150
+ }
151
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
152
+ "section",
153
+ {
154
+ className: "w-full py-20 md:py-28",
155
+ style: { background: "var(--sk-bg, #0a0a0a)" },
156
+ children: [
157
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "max-w-7xl mx-auto px-6", children: [
158
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ScrollReveal.default, { y: 30, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
159
+ "h2",
160
+ {
161
+ className: "text-3xl md:text-4xl font-bold mb-12",
162
+ style: {
163
+ color: "var(--sk-text-primary, #ffffff)",
164
+ fontFamily: "var(--sk-font-heading, inherit)"
165
+ },
166
+ children: "Gallery"
167
+ }
168
+ ) }),
169
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ScrollReveal.default, { stagger: 0.08, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
170
+ "div",
171
+ {
172
+ className: layout === "masonry" ? "columns-1 md:columns-2 lg:columns-3 gap-4 space-y-4" : "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",
173
+ children: data.images.map((img, index) => {
174
+ const resolved = getImage(img);
175
+ if (!resolved) return null;
176
+ const colors = typeBadgeColors[img.type || "screenshot"] || typeBadgeColors.screenshot;
177
+ const alt = img.caption || `Gallery image ${index + 1}`;
178
+ const imgClass = "w-full h-auto object-cover transition-transform duration-500 group-hover:scale-105";
179
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
180
+ "div",
181
+ {
182
+ className: `relative group cursor-pointer overflow-hidden rounded-xl ${layout === "masonry" ? "break-inside-avoid" : ""}`,
183
+ style: {
184
+ border: "1px solid var(--sk-border, rgba(255,255,255,0.1))"
185
+ },
186
+ onClick: () => openLightbox(index),
187
+ children: [
188
+ resolved.width && resolved.height ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
189
+ import_image.default,
190
+ {
191
+ src: resolved.url,
192
+ alt,
193
+ width: resolved.width,
194
+ height: resolved.height,
195
+ sizes: "(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 33vw",
196
+ className: imgClass
197
+ }
198
+ ) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
199
+ "img",
200
+ {
201
+ src: resolved.url,
202
+ alt,
203
+ className: imgClass,
204
+ loading: "lazy",
205
+ decoding: "async"
206
+ }
207
+ ),
208
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
209
+ "div",
210
+ {
211
+ className: "absolute inset-0 flex flex-col justify-end p-4 opacity-0 group-hover:opacity-100 transition-opacity duration-300",
212
+ style: {
213
+ background: "linear-gradient(to top, rgba(0,0,0,0.7) 0%, transparent 60%)"
214
+ },
215
+ children: img.caption && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm text-white font-medium", children: img.caption })
216
+ }
217
+ ),
218
+ img.type && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
219
+ "span",
220
+ {
221
+ className: "absolute top-3 left-3 px-2.5 py-1 rounded-full text-[11px] uppercase tracking-wider font-medium",
222
+ style: {
223
+ background: colors.bg,
224
+ color: colors.text,
225
+ border: `1px solid ${colors.border}`,
226
+ backdropFilter: "blur(8px)"
227
+ },
228
+ children: img.type
229
+ }
230
+ )
231
+ ]
232
+ },
233
+ index
234
+ );
235
+ })
236
+ }
237
+ ) })
238
+ ] }),
239
+ lightboxIndex !== null && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
240
+ "div",
241
+ {
242
+ ref: dialogRef,
243
+ role: "dialog",
244
+ "aria-modal": "true",
245
+ "aria-label": data.images[lightboxIndex].caption || `Gallery image ${lightboxIndex + 1} of ${data.images.length}`,
246
+ className: "fixed inset-0 z-50 flex items-center justify-center",
247
+ style: { background: "rgba(0,0,0,0.9)" },
248
+ onClick: closeLightbox,
249
+ children: [
250
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
251
+ "button",
252
+ {
253
+ onClick: closeLightbox,
254
+ className: "absolute top-6 right-6 w-10 h-10 flex items-center justify-center rounded-full transition-colors z-10",
255
+ style: {
256
+ background: "rgba(255,255,255,0.1)",
257
+ color: "#ffffff"
258
+ },
259
+ "aria-label": "Close lightbox",
260
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M15 5L5 15M5 5l10 10", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) })
261
+ }
262
+ ),
263
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
264
+ "button",
265
+ {
266
+ onClick: (e) => {
267
+ e.stopPropagation();
268
+ goPrev();
269
+ },
270
+ className: "absolute left-4 md:left-8 w-12 h-12 flex items-center justify-center rounded-full transition-colors z-10",
271
+ style: {
272
+ background: "rgba(255,255,255,0.1)",
273
+ color: "#ffffff"
274
+ },
275
+ "aria-label": "Previous image",
276
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12.5 15l-5-5 5-5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
277
+ }
278
+ ),
279
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
280
+ "button",
281
+ {
282
+ onClick: (e) => {
283
+ e.stopPropagation();
284
+ goNext();
285
+ },
286
+ className: "absolute right-4 md:right-8 w-12 h-12 flex items-center justify-center rounded-full transition-colors z-10",
287
+ style: {
288
+ background: "rgba(255,255,255,0.1)",
289
+ color: "#ffffff"
290
+ },
291
+ "aria-label": "Next image",
292
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M7.5 5l5 5-5 5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
293
+ }
294
+ ),
295
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
296
+ "div",
297
+ {
298
+ className: "max-w-[90vw] max-h-[85vh] flex flex-col items-center gap-4",
299
+ onClick: (e) => e.stopPropagation(),
300
+ children: [
301
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
302
+ "img",
303
+ {
304
+ src: getImage(data.images[lightboxIndex])?.url,
305
+ alt: data.images[lightboxIndex].caption || "",
306
+ className: "max-w-full max-h-[80vh] object-contain rounded-lg",
307
+ decoding: "async"
308
+ }
309
+ ),
310
+ data.images[lightboxIndex].caption && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm text-white/70 text-center", children: data.images[lightboxIndex].caption })
311
+ ]
312
+ }
313
+ )
314
+ ]
315
+ }
316
+ )
317
+ ]
318
+ }
319
+ );
320
+ }
321
+ //# sourceMappingURL=GallerySection.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/portfolio/components/sections/GallerySection.tsx","../../../src/shared/images.ts"],"sourcesContent":["'use client';\n\nimport React, { useState, useCallback, useEffect } from 'react';\nimport Image from 'next/image';\nimport type { PortfolioGalleryData } from '../../../types';\nimport { resolvePortfolioImage } from '../../../shared/images';\nimport ScrollReveal from '@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal';\n\ninterface GallerySectionProps {\n data: PortfolioGalleryData;\n}\n\nconst typeBadgeColors: Record<string, { bg: string; text: string; border: string }> = {\n screenshot: {\n bg: 'color-mix(in srgb, #6366f1 12%, transparent)',\n text: '#6366f1',\n border: 'color-mix(in srgb, #6366f1 20%, transparent)',\n },\n before: {\n bg: 'color-mix(in srgb, #f59e0b 12%, transparent)',\n text: '#f59e0b',\n border: 'color-mix(in srgb, #f59e0b 20%, transparent)',\n },\n after: {\n bg: 'color-mix(in srgb, #10b981 12%, transparent)',\n text: '#10b981',\n border: 'color-mix(in srgb, #10b981 20%, transparent)',\n },\n design: {\n bg: 'color-mix(in srgb, #ec4899 12%, transparent)',\n text: '#ec4899',\n border: 'color-mix(in srgb, #ec4899 20%, transparent)',\n },\n};\n\nexport default function GallerySection({ data }: GallerySectionProps) {\n const [lightboxIndex, setLightboxIndex] = useState<number | null>(null);\n const dialogRef = React.useRef<HTMLDivElement>(null);\n const restoreFocusRef = React.useRef<HTMLElement | null>(null);\n\n const layout = data.layout || 'grid';\n\n const openLightbox = useCallback((index: number) => {\n setLightboxIndex(index);\n }, []);\n\n const closeLightbox = useCallback(() => {\n setLightboxIndex(null);\n }, []);\n\n const goNext = useCallback(() => {\n setLightboxIndex((prev) =>\n prev !== null ? (prev + 1) % data.images.length : null,\n );\n }, [data.images.length]);\n\n const goPrev = useCallback(() => {\n setLightboxIndex((prev) =>\n prev !== null ? (prev - 1 + data.images.length) % data.images.length : null,\n );\n }, [data.images.length]);\n\n // Keyboard navigation + dialog focus management\n useEffect(() => {\n if (lightboxIndex === null) return;\n\n // Move focus into the dialog; restore it to the trigger on close.\n restoreFocusRef.current = document.activeElement as HTMLElement | null;\n const dialog = dialogRef.current;\n const focusables = () =>\n dialog\n ? Array.from(\n dialog.querySelectorAll<HTMLElement>('button, [href], [tabindex]:not([tabindex=\"-1\"])'),\n )\n : [];\n focusables()[0]?.focus();\n\n function handleKeyDown(e: KeyboardEvent) {\n if (e.key === 'Escape') closeLightbox();\n if (e.key === 'ArrowRight') goNext();\n if (e.key === 'ArrowLeft') goPrev();\n if (e.key === 'Tab') {\n // Trap Tab inside the dialog\n const items = focusables();\n if (items.length === 0) return;\n const first = items[0];\n const last = items[items.length - 1];\n if (e.shiftKey && document.activeElement === first) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n\n document.addEventListener('keydown', handleKeyDown);\n document.body.style.overflow = 'hidden';\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n document.body.style.overflow = '';\n restoreFocusRef.current?.focus?.();\n };\n }, [lightboxIndex !== null, closeLightbox, goNext, goPrev]); // eslint-disable-line react-hooks/exhaustive-deps\n\n function getImage(image: typeof data.images[0]) {\n // URL (+ intrinsic dims when derivable); raw Sanity refs resolve to null.\n return resolvePortfolioImage(image.image);\n }\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-7xl mx-auto px-6\">\n <ScrollReveal y={30}>\n <h2\n className=\"text-3xl md:text-4xl font-bold mb-12\"\n style={{\n color: 'var(--sk-text-primary, #ffffff)',\n fontFamily: 'var(--sk-font-heading, inherit)',\n }}\n >\n Gallery\n </h2>\n </ScrollReveal>\n\n <ScrollReveal stagger={0.08}>\n <div\n className={\n layout === 'masonry'\n ? 'columns-1 md:columns-2 lg:columns-3 gap-4 space-y-4'\n : 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4'\n }\n >\n {data.images.map((img, index) => {\n const resolved = getImage(img);\n if (!resolved) return null;\n const colors = typeBadgeColors[img.type || 'screenshot'] || typeBadgeColors.screenshot;\n const alt = img.caption || `Gallery image ${index + 1}`;\n const imgClass =\n 'w-full h-auto object-cover transition-transform duration-500 group-hover:scale-105';\n\n return (\n <div\n key={index}\n className={`relative group cursor-pointer overflow-hidden rounded-xl ${\n layout === 'masonry' ? 'break-inside-avoid' : ''\n }`}\n style={{\n border: '1px solid var(--sk-border, rgba(255,255,255,0.1))',\n }}\n onClick={() => openLightbox(index)}\n >\n {resolved.width && resolved.height ? (\n <Image\n src={resolved.url}\n alt={alt}\n width={resolved.width}\n height={resolved.height}\n sizes=\"(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 33vw\"\n className={imgClass}\n />\n ) : (\n <img\n src={resolved.url}\n alt={alt}\n className={imgClass}\n loading=\"lazy\"\n decoding=\"async\"\n />\n )}\n\n {/* Overlay on hover */}\n <div\n className=\"absolute inset-0 flex flex-col justify-end p-4 opacity-0 group-hover:opacity-100 transition-opacity duration-300\"\n style={{\n background: 'linear-gradient(to top, rgba(0,0,0,0.7) 0%, transparent 60%)',\n }}\n >\n {img.caption && (\n <p className=\"text-sm text-white font-medium\">{img.caption}</p>\n )}\n </div>\n\n {/* Type badge */}\n {img.type && (\n <span\n className=\"absolute top-3 left-3 px-2.5 py-1 rounded-full text-[11px] uppercase tracking-wider font-medium\"\n style={{\n background: colors.bg,\n color: colors.text,\n border: `1px solid ${colors.border}`,\n backdropFilter: 'blur(8px)',\n }}\n >\n {img.type}\n </span>\n )}\n </div>\n );\n })}\n </div>\n </ScrollReveal>\n </div>\n\n {/* Lightbox modal */}\n {lightboxIndex !== null && (\n <div\n ref={dialogRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={data.images[lightboxIndex].caption || `Gallery image ${lightboxIndex + 1} of ${data.images.length}`}\n className=\"fixed inset-0 z-50 flex items-center justify-center\"\n style={{ background: 'rgba(0,0,0,0.9)' }}\n onClick={closeLightbox}\n >\n {/* Close button */}\n <button\n onClick={closeLightbox}\n className=\"absolute top-6 right-6 w-10 h-10 flex items-center justify-center rounded-full transition-colors z-10\"\n style={{\n background: 'rgba(255,255,255,0.1)',\n color: '#ffffff',\n }}\n aria-label=\"Close lightbox\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path d=\"M15 5L5 15M5 5l10 10\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n </button>\n\n {/* Prev button */}\n <button\n onClick={(e) => { e.stopPropagation(); goPrev(); }}\n className=\"absolute left-4 md:left-8 w-12 h-12 flex items-center justify-center rounded-full transition-colors z-10\"\n style={{\n background: 'rgba(255,255,255,0.1)',\n color: '#ffffff',\n }}\n aria-label=\"Previous image\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path d=\"M12.5 15l-5-5 5-5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </button>\n\n {/* Next button */}\n <button\n onClick={(e) => { e.stopPropagation(); goNext(); }}\n className=\"absolute right-4 md:right-8 w-12 h-12 flex items-center justify-center rounded-full transition-colors z-10\"\n style={{\n background: 'rgba(255,255,255,0.1)',\n color: '#ffffff',\n }}\n aria-label=\"Next image\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path d=\"M7.5 5l5 5-5 5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </button>\n\n {/* Image */}\n <div\n className=\"max-w-[90vw] max-h-[85vh] flex flex-col items-center gap-4\"\n onClick={(e) => e.stopPropagation()}\n >\n <img\n src={getImage(data.images[lightboxIndex])?.url}\n alt={data.images[lightboxIndex].caption || ''}\n className=\"max-w-full max-h-[80vh] object-contain rounded-lg\"\n decoding=\"async\"\n />\n {data.images[lightboxIndex].caption && (\n <p className=\"text-sm text-white/70 text-center\">\n {data.images[lightboxIndex].caption}\n </p>\n )}\n </div>\n </div>\n )}\n </section>\n );\n}\n","/**\n * Portfolio image resolution — single source of truth for turning the mixed\n * image shapes the API sends (plain URL strings, Supabase Storage URLs,\n * Sanity image objects) into something safe to render.\n *\n * IMPORTANT: a raw Sanity asset _ref (`image-{id}-{W}x{H}-{fmt}`) is an asset\n * ID, NOT a URL. Rendering it as `src` issues a garbage relative request\n * against the agency site's origin. Resolving refs to cdn.sanity.io URLs is\n * the API's job (it owns the Sanity project config); this helper refuses refs\n * so a broken image can never render, and warns once so the gap is visible.\n *\n * When a URL carries `-{W}x{H}.{ext}` dimensions (Sanity CDN URLs always do),\n * they're parsed out so callers can give next/image exact intrinsic sizes.\n */\n\nexport interface ResolvedPortfolioImage {\n url: string;\n width?: number;\n height?: number;\n}\n\n/** Raw Sanity asset reference — an ID, not a URL. */\nconst SANITY_ASSET_REF = /^image-[A-Za-z0-9]+-\\d+x\\d+-[a-z0-9]+$/;\n\n/** `…-1200x800.png` (optionally with a query string) → intrinsic dimensions. */\nconst FILENAME_DIMS = /-(\\d{2,5})x(\\d{2,5})\\.[a-z0-9]+(?:\\?.*)?$/i;\n\ninterface SanityImageLike {\n asset?: { _ref?: string };\n}\n\nlet warnedAboutRefs = false;\n\n/**\n * Resolve a portfolio image input into a renderable URL (+ intrinsic\n * dimensions when they can be derived). Returns null for empty values and\n * for unresolved Sanity refs — callers skip rendering in that case.\n */\nexport function resolvePortfolioImage(\n input: string | SanityImageLike | null | undefined,\n): ResolvedPortfolioImage | null {\n const raw =\n typeof input === 'string' ? input : input?.asset?._ref ?? '';\n const value = (raw || '').trim();\n if (!value) return null;\n\n if (SANITY_ASSET_REF.test(value)) {\n if (!warnedAboutRefs && typeof console !== 'undefined') {\n warnedAboutRefs = true;\n console.warn(\n '[@sonordev/agency-site-kit] Received a raw Sanity asset ref instead of an ' +\n 'image URL — skipping render. The Sonor API should resolve image refs to ' +\n 'cdn.sanity.io URLs before returning portfolio sections.',\n );\n }\n return null;\n }\n\n // Only absolute http(s) URLs or site-rooted paths are renderable.\n if (!/^https?:\\/\\//i.test(value) && !value.startsWith('/')) return null;\n\n const dims = value.match(FILENAME_DIMS);\n if (dims) {\n const width = parseInt(dims[1], 10);\n const height = parseInt(dims[2], 10);\n if (width > 0 && height > 0) return { url: value, width, height };\n }\n\n return { url: value };\n}\n"],"mappings":"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","names":["React","ScrollReveal","Image"]}
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import { d as PortfolioGalleryData } from '../../types-D0nb6KAx.cjs';
3
+
4
+ interface GallerySectionProps {
5
+ data: PortfolioGalleryData;
6
+ }
7
+ declare function GallerySection({ data }: GallerySectionProps): React.JSX.Element;
8
+
9
+ export { GallerySection as default };
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import { d as PortfolioGalleryData } from '../../types-D0nb6KAx.js';
3
+
4
+ interface GallerySectionProps {
5
+ data: PortfolioGalleryData;
6
+ }
7
+ declare function GallerySection({ data }: GallerySectionProps): React.JSX.Element;
8
+
9
+ export { GallerySection as default };