@sonordev/agency-site-kit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/dist/BeforeAfterSection-6QUJOBO2.js +176 -0
  2. package/dist/BeforeAfterSection-6QUJOBO2.js.map +1 -0
  3. package/dist/BeforeAfterSection-DVAWWE4K.cjs +181 -0
  4. package/dist/BeforeAfterSection-DVAWWE4K.cjs.map +1 -0
  5. package/dist/CTASection-4JKLXEUF.cjs +111 -0
  6. package/dist/CTASection-4JKLXEUF.cjs.map +1 -0
  7. package/dist/CTASection-BJA72XIL.js +106 -0
  8. package/dist/CTASection-BJA72XIL.js.map +1 -0
  9. package/dist/ChallengesSection-GEQGVSJN.js +180 -0
  10. package/dist/ChallengesSection-GEQGVSJN.js.map +1 -0
  11. package/dist/ChallengesSection-IZ3DHECS.cjs +182 -0
  12. package/dist/ChallengesSection-IZ3DHECS.cjs.map +1 -0
  13. package/dist/ConversionFunnelSection-AUUSJ5HQ.cjs +209 -0
  14. package/dist/ConversionFunnelSection-AUUSJ5HQ.cjs.map +1 -0
  15. package/dist/ConversionFunnelSection-D3GE4NKE.js +203 -0
  16. package/dist/ConversionFunnelSection-D3GE4NKE.js.map +1 -0
  17. package/dist/DetailsSection-FB763FS7.js +135 -0
  18. package/dist/DetailsSection-FB763FS7.js.map +1 -0
  19. package/dist/DetailsSection-OACJFGH7.cjs +137 -0
  20. package/dist/DetailsSection-OACJFGH7.cjs.map +1 -0
  21. package/dist/FeatureSpotlightSection-B7P3JGNL.js +205 -0
  22. package/dist/FeatureSpotlightSection-B7P3JGNL.js.map +1 -0
  23. package/dist/FeatureSpotlightSection-WRHXS7TU.cjs +210 -0
  24. package/dist/FeatureSpotlightSection-WRHXS7TU.cjs.map +1 -0
  25. package/dist/GallerySection-VMKORC47.js +218 -0
  26. package/dist/GallerySection-VMKORC47.js.map +1 -0
  27. package/dist/GallerySection-WJ4PQDBI.cjs +219 -0
  28. package/dist/GallerySection-WJ4PQDBI.cjs.map +1 -0
  29. package/dist/MetricsTimelineSection-4L6DUHJ5.cjs +258 -0
  30. package/dist/MetricsTimelineSection-4L6DUHJ5.cjs.map +1 -0
  31. package/dist/MetricsTimelineSection-6BT5GNFV.js +253 -0
  32. package/dist/MetricsTimelineSection-6BT5GNFV.js.map +1 -0
  33. package/dist/ResultsSection-DFUJ5U6M.js +93 -0
  34. package/dist/ResultsSection-DFUJ5U6M.js.map +1 -0
  35. package/dist/ResultsSection-XLGMMQKY.cjs +95 -0
  36. package/dist/ResultsSection-XLGMMQKY.cjs.map +1 -0
  37. package/dist/ServicesSection-D5V3Q4GR.js +118 -0
  38. package/dist/ServicesSection-D5V3Q4GR.js.map +1 -0
  39. package/dist/ServicesSection-WJMGK2MF.cjs +120 -0
  40. package/dist/ServicesSection-WJMGK2MF.cjs.map +1 -0
  41. package/dist/StrategySection-3ED3QW4R.cjs +180 -0
  42. package/dist/StrategySection-3ED3QW4R.cjs.map +1 -0
  43. package/dist/StrategySection-VUWMIYYP.js +175 -0
  44. package/dist/StrategySection-VUWMIYYP.js.map +1 -0
  45. package/dist/TeamSection-DZVSNZE6.cjs +112 -0
  46. package/dist/TeamSection-DZVSNZE6.cjs.map +1 -0
  47. package/dist/TeamSection-HGKFW6PQ.js +107 -0
  48. package/dist/TeamSection-HGKFW6PQ.js.map +1 -0
  49. package/dist/TechStackSection-OCUYG4XT.js +90 -0
  50. package/dist/TechStackSection-OCUYG4XT.js.map +1 -0
  51. package/dist/TechStackSection-VKJK4KQB.cjs +91 -0
  52. package/dist/TechStackSection-VKJK4KQB.cjs.map +1 -0
  53. package/dist/TestimonialSection-6RGSMXQB.js +122 -0
  54. package/dist/TestimonialSection-6RGSMXQB.js.map +1 -0
  55. package/dist/TestimonialSection-XPTFUQIN.cjs +124 -0
  56. package/dist/TestimonialSection-XPTFUQIN.cjs.map +1 -0
  57. package/dist/VideoSection-4A2HC6K6.js +117 -0
  58. package/dist/VideoSection-4A2HC6K6.js.map +1 -0
  59. package/dist/VideoSection-G3DFS7UH.cjs +118 -0
  60. package/dist/VideoSection-G3DFS7UH.cjs.map +1 -0
  61. package/dist/chunk-2VNNFAG6.js +415 -0
  62. package/dist/chunk-2VNNFAG6.js.map +1 -0
  63. package/dist/chunk-2Y4O3LWM.js +53 -0
  64. package/dist/chunk-2Y4O3LWM.js.map +1 -0
  65. package/dist/chunk-5FKOLIV6.cjs +221 -0
  66. package/dist/chunk-5FKOLIV6.cjs.map +1 -0
  67. package/dist/chunk-7CFFAKDM.js +74 -0
  68. package/dist/chunk-7CFFAKDM.js.map +1 -0
  69. package/dist/chunk-A4I4IK7V.js +69 -0
  70. package/dist/chunk-A4I4IK7V.js.map +1 -0
  71. package/dist/chunk-IKBK7HYX.cjs +79 -0
  72. package/dist/chunk-IKBK7HYX.cjs.map +1 -0
  73. package/dist/chunk-KEOHORIH.cjs +79 -0
  74. package/dist/chunk-KEOHORIH.cjs.map +1 -0
  75. package/dist/chunk-NAS4K5UR.cjs +139 -0
  76. package/dist/chunk-NAS4K5UR.cjs.map +1 -0
  77. package/dist/chunk-QBLWP25X.cjs +73 -0
  78. package/dist/chunk-QBLWP25X.cjs.map +1 -0
  79. package/dist/chunk-QIC6JFFD.js +210 -0
  80. package/dist/chunk-QIC6JFFD.js.map +1 -0
  81. package/dist/chunk-TAPNXT7X.cjs +422 -0
  82. package/dist/chunk-TAPNXT7X.cjs.map +1 -0
  83. package/dist/chunk-XCKXHK44.js +15 -0
  84. package/dist/chunk-XCKXHK44.js.map +1 -0
  85. package/dist/chunk-XMC4DN6G.js +131 -0
  86. package/dist/chunk-XMC4DN6G.js.map +1 -0
  87. package/dist/chunk-XONXEFJY.cjs +58 -0
  88. package/dist/chunk-XONXEFJY.cjs.map +1 -0
  89. package/dist/chunk-XQNJED46.cjs +19 -0
  90. package/dist/chunk-XQNJED46.cjs.map +1 -0
  91. package/dist/chunk-YB4B3OMC.js +74 -0
  92. package/dist/chunk-YB4B3OMC.js.map +1 -0
  93. package/dist/index.cjs +271 -0
  94. package/dist/index.cjs.map +1 -0
  95. package/dist/index.d.cts +137 -0
  96. package/dist/index.d.ts +137 -0
  97. package/dist/index.js +197 -0
  98. package/dist/index.js.map +1 -0
  99. package/dist/layout/index.cjs +13 -0
  100. package/dist/layout/index.cjs.map +1 -0
  101. package/dist/layout/index.d.cts +54 -0
  102. package/dist/layout/index.d.ts +54 -0
  103. package/dist/layout/index.js +4 -0
  104. package/dist/layout/index.js.map +1 -0
  105. package/dist/portfolio/client.cjs +18 -0
  106. package/dist/portfolio/client.cjs.map +1 -0
  107. package/dist/portfolio/client.d.cts +97 -0
  108. package/dist/portfolio/client.d.ts +97 -0
  109. package/dist/portfolio/client.js +6 -0
  110. package/dist/portfolio/client.js.map +1 -0
  111. package/dist/portfolio/index.cjs +41 -0
  112. package/dist/portfolio/index.cjs.map +1 -0
  113. package/dist/portfolio/index.d.cts +12 -0
  114. package/dist/portfolio/index.d.ts +12 -0
  115. package/dist/portfolio/index.js +8 -0
  116. package/dist/portfolio/index.js.map +1 -0
  117. package/dist/portfolio/sections.cjs +20 -0
  118. package/dist/portfolio/sections.cjs.map +1 -0
  119. package/dist/portfolio/sections.d.cts +42 -0
  120. package/dist/portfolio/sections.d.ts +42 -0
  121. package/dist/portfolio/sections.js +4 -0
  122. package/dist/portfolio/sections.js.map +1 -0
  123. package/dist/portfolio/server.cjs +141 -0
  124. package/dist/portfolio/server.cjs.map +1 -0
  125. package/dist/portfolio/server.d.cts +68 -0
  126. package/dist/portfolio/server.d.ts +68 -0
  127. package/dist/portfolio/server.js +134 -0
  128. package/dist/portfolio/server.js.map +1 -0
  129. package/dist/types-BMUhBhWx.d.cts +346 -0
  130. package/dist/types-BMUhBhWx.d.ts +346 -0
  131. package/package.json +71 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/portfolio/components/sections/FeatureSpotlightSection.tsx"],"names":["useRef","useEffect","gsap","jsxs","jsx","useState","useCallback","ScrollReveal"],"mappings":"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","file":"FeatureSpotlightSection-WRHXS7TU.cjs","sourcesContent":["'use client';\n\nimport React, { useRef, useEffect, useState, useCallback } from 'react';\nimport gsap from 'gsap';\nimport type { PortfolioFeatureSpotlightData, PortfolioAnnotation } from '../../../types';\nimport ScrollReveal from '../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 pinRef = useRef<HTMLButtonElement>(null);\n const isActive = activeIndex === index;\n\n useEffect(() => {\n if (!pinRef.current) return;\n\n if (isActive) {\n gsap.to(pinRef.current, {\n scale: 1.2,\n duration: 0.3,\n ease: 'back.out(2)',\n });\n } else {\n gsap.to(pinRef.current, {\n scale: 1,\n duration: 0.2,\n ease: 'power2.out',\n });\n }\n }, [isActive]);\n\n return (\n <button\n ref={pinRef}\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 transition-colors cursor-pointer\"\n style={{\n left: `${annotation.x}%`,\n top: `${annotation.y}%`,\n transform: 'translate(-50%, -50%)',\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 imageUrl = data.image?.asset?._ref || '';\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 <img\n src={imageUrl}\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 />\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"]}
@@ -0,0 +1,218 @@
1
+ 'use client';
2
+ import { ScrollReveal } from './chunk-7CFFAKDM.js';
3
+ import { useState, useCallback, useEffect } from 'react';
4
+ import { jsxs, jsx } from 'react/jsx-runtime';
5
+
6
+ var typeBadgeColors = {
7
+ screenshot: {
8
+ bg: "color-mix(in srgb, #6366f1 12%, transparent)",
9
+ text: "#6366f1",
10
+ border: "color-mix(in srgb, #6366f1 20%, transparent)"
11
+ },
12
+ before: {
13
+ bg: "color-mix(in srgb, #f59e0b 12%, transparent)",
14
+ text: "#f59e0b",
15
+ border: "color-mix(in srgb, #f59e0b 20%, transparent)"
16
+ },
17
+ after: {
18
+ bg: "color-mix(in srgb, #10b981 12%, transparent)",
19
+ text: "#10b981",
20
+ border: "color-mix(in srgb, #10b981 20%, transparent)"
21
+ },
22
+ design: {
23
+ bg: "color-mix(in srgb, #ec4899 12%, transparent)",
24
+ text: "#ec4899",
25
+ border: "color-mix(in srgb, #ec4899 20%, transparent)"
26
+ }
27
+ };
28
+ function GallerySection({ data }) {
29
+ const [lightboxIndex, setLightboxIndex] = useState(null);
30
+ const layout = data.layout || "grid";
31
+ const openLightbox = useCallback((index) => {
32
+ setLightboxIndex(index);
33
+ }, []);
34
+ const closeLightbox = useCallback(() => {
35
+ setLightboxIndex(null);
36
+ }, []);
37
+ const goNext = useCallback(() => {
38
+ setLightboxIndex(
39
+ (prev) => prev !== null ? (prev + 1) % data.images.length : null
40
+ );
41
+ }, [data.images.length]);
42
+ const goPrev = useCallback(() => {
43
+ setLightboxIndex(
44
+ (prev) => prev !== null ? (prev - 1 + data.images.length) % data.images.length : null
45
+ );
46
+ }, [data.images.length]);
47
+ useEffect(() => {
48
+ if (lightboxIndex === null) return;
49
+ function handleKeyDown(e) {
50
+ if (e.key === "Escape") closeLightbox();
51
+ if (e.key === "ArrowRight") goNext();
52
+ if (e.key === "ArrowLeft") goPrev();
53
+ }
54
+ document.addEventListener("keydown", handleKeyDown);
55
+ document.body.style.overflow = "hidden";
56
+ return () => {
57
+ document.removeEventListener("keydown", handleKeyDown);
58
+ document.body.style.overflow = "";
59
+ };
60
+ }, [lightboxIndex, closeLightbox, goNext, goPrev]);
61
+ function getImageUrl(image) {
62
+ return image.image.asset._ref || "";
63
+ }
64
+ return /* @__PURE__ */ jsxs(
65
+ "section",
66
+ {
67
+ className: "w-full py-20 md:py-28",
68
+ style: { background: "var(--sk-bg, #0a0a0a)" },
69
+ children: [
70
+ /* @__PURE__ */ jsxs("div", { className: "max-w-7xl mx-auto px-6", children: [
71
+ /* @__PURE__ */ jsx(ScrollReveal, { y: 30, children: /* @__PURE__ */ jsx(
72
+ "h2",
73
+ {
74
+ className: "text-3xl md:text-4xl font-bold mb-12",
75
+ style: {
76
+ color: "var(--sk-text-primary, #ffffff)",
77
+ fontFamily: "var(--sk-font-heading, inherit)"
78
+ },
79
+ children: "Gallery"
80
+ }
81
+ ) }),
82
+ /* @__PURE__ */ jsx(ScrollReveal, { stagger: 0.08, children: /* @__PURE__ */ jsx(
83
+ "div",
84
+ {
85
+ 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",
86
+ children: data.images.map((img, index) => {
87
+ const url = getImageUrl(img);
88
+ const colors = typeBadgeColors[img.type || "screenshot"] || typeBadgeColors.screenshot;
89
+ return /* @__PURE__ */ jsxs(
90
+ "div",
91
+ {
92
+ className: `relative group cursor-pointer overflow-hidden rounded-xl ${layout === "masonry" ? "break-inside-avoid" : ""}`,
93
+ style: {
94
+ border: "1px solid var(--sk-border, rgba(255,255,255,0.1))"
95
+ },
96
+ onClick: () => openLightbox(index),
97
+ children: [
98
+ /* @__PURE__ */ jsx(
99
+ "img",
100
+ {
101
+ src: url,
102
+ alt: img.caption || `Gallery image ${index + 1}`,
103
+ className: "w-full h-auto object-cover transition-transform duration-500 group-hover:scale-105",
104
+ loading: "lazy"
105
+ }
106
+ ),
107
+ /* @__PURE__ */ jsx(
108
+ "div",
109
+ {
110
+ className: "absolute inset-0 flex flex-col justify-end p-4 opacity-0 group-hover:opacity-100 transition-opacity duration-300",
111
+ style: {
112
+ background: "linear-gradient(to top, rgba(0,0,0,0.7) 0%, transparent 60%)"
113
+ },
114
+ children: img.caption && /* @__PURE__ */ jsx("p", { className: "text-sm text-white font-medium", children: img.caption })
115
+ }
116
+ ),
117
+ img.type && /* @__PURE__ */ jsx(
118
+ "span",
119
+ {
120
+ className: "absolute top-3 left-3 px-2.5 py-1 rounded-full text-[11px] uppercase tracking-wider font-medium",
121
+ style: {
122
+ background: colors.bg,
123
+ color: colors.text,
124
+ border: `1px solid ${colors.border}`,
125
+ backdropFilter: "blur(8px)"
126
+ },
127
+ children: img.type
128
+ }
129
+ )
130
+ ]
131
+ },
132
+ index
133
+ );
134
+ })
135
+ }
136
+ ) })
137
+ ] }),
138
+ lightboxIndex !== null && /* @__PURE__ */ jsxs(
139
+ "div",
140
+ {
141
+ className: "fixed inset-0 z-50 flex items-center justify-center",
142
+ style: { background: "rgba(0,0,0,0.9)" },
143
+ onClick: closeLightbox,
144
+ children: [
145
+ /* @__PURE__ */ jsx(
146
+ "button",
147
+ {
148
+ onClick: closeLightbox,
149
+ className: "absolute top-6 right-6 w-10 h-10 flex items-center justify-center rounded-full transition-colors z-10",
150
+ style: {
151
+ background: "rgba(255,255,255,0.1)",
152
+ color: "#ffffff"
153
+ },
154
+ "aria-label": "Close lightbox",
155
+ children: /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M15 5L5 15M5 5l10 10", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) })
156
+ }
157
+ ),
158
+ /* @__PURE__ */ jsx(
159
+ "button",
160
+ {
161
+ onClick: (e) => {
162
+ e.stopPropagation();
163
+ goPrev();
164
+ },
165
+ className: "absolute left-4 md:left-8 w-12 h-12 flex items-center justify-center rounded-full transition-colors z-10",
166
+ style: {
167
+ background: "rgba(255,255,255,0.1)",
168
+ color: "#ffffff"
169
+ },
170
+ "aria-label": "Previous image",
171
+ children: /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M12.5 15l-5-5 5-5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
172
+ }
173
+ ),
174
+ /* @__PURE__ */ jsx(
175
+ "button",
176
+ {
177
+ onClick: (e) => {
178
+ e.stopPropagation();
179
+ goNext();
180
+ },
181
+ className: "absolute right-4 md:right-8 w-12 h-12 flex items-center justify-center rounded-full transition-colors z-10",
182
+ style: {
183
+ background: "rgba(255,255,255,0.1)",
184
+ color: "#ffffff"
185
+ },
186
+ "aria-label": "Next image",
187
+ children: /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M7.5 5l5 5-5 5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
188
+ }
189
+ ),
190
+ /* @__PURE__ */ jsxs(
191
+ "div",
192
+ {
193
+ className: "max-w-[90vw] max-h-[85vh] flex flex-col items-center gap-4",
194
+ onClick: (e) => e.stopPropagation(),
195
+ children: [
196
+ /* @__PURE__ */ jsx(
197
+ "img",
198
+ {
199
+ src: getImageUrl(data.images[lightboxIndex]),
200
+ alt: data.images[lightboxIndex].caption || "",
201
+ className: "max-w-full max-h-[80vh] object-contain rounded-lg"
202
+ }
203
+ ),
204
+ data.images[lightboxIndex].caption && /* @__PURE__ */ jsx("p", { className: "text-sm text-white/70 text-center", children: data.images[lightboxIndex].caption })
205
+ ]
206
+ }
207
+ )
208
+ ]
209
+ }
210
+ )
211
+ ]
212
+ }
213
+ );
214
+ }
215
+
216
+ export { GallerySection as default };
217
+ //# sourceMappingURL=GallerySection-VMKORC47.js.map
218
+ //# sourceMappingURL=GallerySection-VMKORC47.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/portfolio/components/sections/GallerySection.tsx"],"names":[],"mappings":"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","file":"GallerySection-VMKORC47.js","sourcesContent":["'use client';\n\nimport React, { useState, useCallback, useEffect } from 'react';\nimport type { PortfolioGalleryData } from '../../../types';\nimport ScrollReveal from '../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\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\n useEffect(() => {\n if (lightboxIndex === null) return;\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 }\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 };\n }, [lightboxIndex, closeLightbox, goNext, goPrev]);\n\n function getImageUrl(image: typeof data.images[0]) {\n // Extract URL from SanityImageRef asset _ref or fall back\n return image.image.asset._ref || '';\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 url = getImageUrl(img);\n const colors = typeBadgeColors[img.type || 'screenshot'] || typeBadgeColors.screenshot;\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 <img\n src={url}\n alt={img.caption || `Gallery image ${index + 1}`}\n className=\"w-full h-auto object-cover transition-transform duration-500 group-hover:scale-105\"\n loading=\"lazy\"\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 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={getImageUrl(data.images[lightboxIndex])}\n alt={data.images[lightboxIndex].caption || ''}\n className=\"max-w-full max-h-[80vh] object-contain rounded-lg\"\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"]}
@@ -0,0 +1,219 @@
1
+ 'use strict';
2
+
3
+ var chunkIKBK7HYX_cjs = require('./chunk-IKBK7HYX.cjs');
4
+ var react = require('react');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ var typeBadgeColors = {
8
+ screenshot: {
9
+ bg: "color-mix(in srgb, #6366f1 12%, transparent)",
10
+ text: "#6366f1",
11
+ border: "color-mix(in srgb, #6366f1 20%, transparent)"
12
+ },
13
+ before: {
14
+ bg: "color-mix(in srgb, #f59e0b 12%, transparent)",
15
+ text: "#f59e0b",
16
+ border: "color-mix(in srgb, #f59e0b 20%, transparent)"
17
+ },
18
+ after: {
19
+ bg: "color-mix(in srgb, #10b981 12%, transparent)",
20
+ text: "#10b981",
21
+ border: "color-mix(in srgb, #10b981 20%, transparent)"
22
+ },
23
+ design: {
24
+ bg: "color-mix(in srgb, #ec4899 12%, transparent)",
25
+ text: "#ec4899",
26
+ border: "color-mix(in srgb, #ec4899 20%, transparent)"
27
+ }
28
+ };
29
+ function GallerySection({ data }) {
30
+ const [lightboxIndex, setLightboxIndex] = react.useState(null);
31
+ const layout = data.layout || "grid";
32
+ const openLightbox = react.useCallback((index) => {
33
+ setLightboxIndex(index);
34
+ }, []);
35
+ const closeLightbox = react.useCallback(() => {
36
+ setLightboxIndex(null);
37
+ }, []);
38
+ const goNext = react.useCallback(() => {
39
+ setLightboxIndex(
40
+ (prev) => prev !== null ? (prev + 1) % data.images.length : null
41
+ );
42
+ }, [data.images.length]);
43
+ const goPrev = react.useCallback(() => {
44
+ setLightboxIndex(
45
+ (prev) => prev !== null ? (prev - 1 + data.images.length) % data.images.length : null
46
+ );
47
+ }, [data.images.length]);
48
+ react.useEffect(() => {
49
+ if (lightboxIndex === null) return;
50
+ function handleKeyDown(e) {
51
+ if (e.key === "Escape") closeLightbox();
52
+ if (e.key === "ArrowRight") goNext();
53
+ if (e.key === "ArrowLeft") goPrev();
54
+ }
55
+ document.addEventListener("keydown", handleKeyDown);
56
+ document.body.style.overflow = "hidden";
57
+ return () => {
58
+ document.removeEventListener("keydown", handleKeyDown);
59
+ document.body.style.overflow = "";
60
+ };
61
+ }, [lightboxIndex, closeLightbox, goNext, goPrev]);
62
+ function getImageUrl(image) {
63
+ return image.image.asset._ref || "";
64
+ }
65
+ return /* @__PURE__ */ jsxRuntime.jsxs(
66
+ "section",
67
+ {
68
+ className: "w-full py-20 md:py-28",
69
+ style: { background: "var(--sk-bg, #0a0a0a)" },
70
+ children: [
71
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-7xl mx-auto px-6", children: [
72
+ /* @__PURE__ */ jsxRuntime.jsx(chunkIKBK7HYX_cjs.ScrollReveal, { y: 30, children: /* @__PURE__ */ jsxRuntime.jsx(
73
+ "h2",
74
+ {
75
+ className: "text-3xl md:text-4xl font-bold mb-12",
76
+ style: {
77
+ color: "var(--sk-text-primary, #ffffff)",
78
+ fontFamily: "var(--sk-font-heading, inherit)"
79
+ },
80
+ children: "Gallery"
81
+ }
82
+ ) }),
83
+ /* @__PURE__ */ jsxRuntime.jsx(chunkIKBK7HYX_cjs.ScrollReveal, { stagger: 0.08, children: /* @__PURE__ */ jsxRuntime.jsx(
84
+ "div",
85
+ {
86
+ 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",
87
+ children: data.images.map((img, index) => {
88
+ const url = getImageUrl(img);
89
+ const colors = typeBadgeColors[img.type || "screenshot"] || typeBadgeColors.screenshot;
90
+ return /* @__PURE__ */ jsxRuntime.jsxs(
91
+ "div",
92
+ {
93
+ className: `relative group cursor-pointer overflow-hidden rounded-xl ${layout === "masonry" ? "break-inside-avoid" : ""}`,
94
+ style: {
95
+ border: "1px solid var(--sk-border, rgba(255,255,255,0.1))"
96
+ },
97
+ onClick: () => openLightbox(index),
98
+ children: [
99
+ /* @__PURE__ */ jsxRuntime.jsx(
100
+ "img",
101
+ {
102
+ src: url,
103
+ alt: img.caption || `Gallery image ${index + 1}`,
104
+ className: "w-full h-auto object-cover transition-transform duration-500 group-hover:scale-105",
105
+ loading: "lazy"
106
+ }
107
+ ),
108
+ /* @__PURE__ */ jsxRuntime.jsx(
109
+ "div",
110
+ {
111
+ className: "absolute inset-0 flex flex-col justify-end p-4 opacity-0 group-hover:opacity-100 transition-opacity duration-300",
112
+ style: {
113
+ background: "linear-gradient(to top, rgba(0,0,0,0.7) 0%, transparent 60%)"
114
+ },
115
+ children: img.caption && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-white font-medium", children: img.caption })
116
+ }
117
+ ),
118
+ img.type && /* @__PURE__ */ jsxRuntime.jsx(
119
+ "span",
120
+ {
121
+ className: "absolute top-3 left-3 px-2.5 py-1 rounded-full text-[11px] uppercase tracking-wider font-medium",
122
+ style: {
123
+ background: colors.bg,
124
+ color: colors.text,
125
+ border: `1px solid ${colors.border}`,
126
+ backdropFilter: "blur(8px)"
127
+ },
128
+ children: img.type
129
+ }
130
+ )
131
+ ]
132
+ },
133
+ index
134
+ );
135
+ })
136
+ }
137
+ ) })
138
+ ] }),
139
+ lightboxIndex !== null && /* @__PURE__ */ jsxRuntime.jsxs(
140
+ "div",
141
+ {
142
+ className: "fixed inset-0 z-50 flex items-center justify-center",
143
+ style: { background: "rgba(0,0,0,0.9)" },
144
+ onClick: closeLightbox,
145
+ children: [
146
+ /* @__PURE__ */ jsxRuntime.jsx(
147
+ "button",
148
+ {
149
+ onClick: closeLightbox,
150
+ className: "absolute top-6 right-6 w-10 h-10 flex items-center justify-center rounded-full transition-colors z-10",
151
+ style: {
152
+ background: "rgba(255,255,255,0.1)",
153
+ color: "#ffffff"
154
+ },
155
+ "aria-label": "Close lightbox",
156
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M15 5L5 15M5 5l10 10", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) })
157
+ }
158
+ ),
159
+ /* @__PURE__ */ jsxRuntime.jsx(
160
+ "button",
161
+ {
162
+ onClick: (e) => {
163
+ e.stopPropagation();
164
+ goPrev();
165
+ },
166
+ className: "absolute left-4 md:left-8 w-12 h-12 flex items-center justify-center rounded-full transition-colors z-10",
167
+ style: {
168
+ background: "rgba(255,255,255,0.1)",
169
+ color: "#ffffff"
170
+ },
171
+ "aria-label": "Previous image",
172
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12.5 15l-5-5 5-5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
173
+ }
174
+ ),
175
+ /* @__PURE__ */ jsxRuntime.jsx(
176
+ "button",
177
+ {
178
+ onClick: (e) => {
179
+ e.stopPropagation();
180
+ goNext();
181
+ },
182
+ className: "absolute right-4 md:right-8 w-12 h-12 flex items-center justify-center rounded-full transition-colors z-10",
183
+ style: {
184
+ background: "rgba(255,255,255,0.1)",
185
+ color: "#ffffff"
186
+ },
187
+ "aria-label": "Next image",
188
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7.5 5l5 5-5 5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
189
+ }
190
+ ),
191
+ /* @__PURE__ */ jsxRuntime.jsxs(
192
+ "div",
193
+ {
194
+ className: "max-w-[90vw] max-h-[85vh] flex flex-col items-center gap-4",
195
+ onClick: (e) => e.stopPropagation(),
196
+ children: [
197
+ /* @__PURE__ */ jsxRuntime.jsx(
198
+ "img",
199
+ {
200
+ src: getImageUrl(data.images[lightboxIndex]),
201
+ alt: data.images[lightboxIndex].caption || "",
202
+ className: "max-w-full max-h-[80vh] object-contain rounded-lg"
203
+ }
204
+ ),
205
+ data.images[lightboxIndex].caption && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-white/70 text-center", children: data.images[lightboxIndex].caption })
206
+ ]
207
+ }
208
+ )
209
+ ]
210
+ }
211
+ )
212
+ ]
213
+ }
214
+ );
215
+ }
216
+
217
+ module.exports = GallerySection;
218
+ //# sourceMappingURL=GallerySection-WJ4PQDBI.cjs.map
219
+ //# sourceMappingURL=GallerySection-WJ4PQDBI.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/portfolio/components/sections/GallerySection.tsx"],"names":["useState","useCallback","useEffect","jsxs","jsx","ScrollReveal"],"mappings":"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","file":"GallerySection-WJ4PQDBI.cjs","sourcesContent":["'use client';\n\nimport React, { useState, useCallback, useEffect } from 'react';\nimport type { PortfolioGalleryData } from '../../../types';\nimport ScrollReveal from '../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\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\n useEffect(() => {\n if (lightboxIndex === null) return;\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 }\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 };\n }, [lightboxIndex, closeLightbox, goNext, goPrev]);\n\n function getImageUrl(image: typeof data.images[0]) {\n // Extract URL from SanityImageRef asset _ref or fall back\n return image.image.asset._ref || '';\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 url = getImageUrl(img);\n const colors = typeBadgeColors[img.type || 'screenshot'] || typeBadgeColors.screenshot;\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 <img\n src={url}\n alt={img.caption || `Gallery image ${index + 1}`}\n className=\"w-full h-auto object-cover transition-transform duration-500 group-hover:scale-105\"\n loading=\"lazy\"\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 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={getImageUrl(data.images[lightboxIndex])}\n alt={data.images[lightboxIndex].caption || ''}\n className=\"max-w-full max-h-[80vh] object-contain rounded-lg\"\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"]}