@sonordev/agency-site-kit 0.1.0 → 0.1.2
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.
- package/dist/{BeforeAfterSection-6QUJOBO2.js → BeforeAfterSection-6BHFLY4Y.js} +6 -6
- package/dist/BeforeAfterSection-6BHFLY4Y.js.map +1 -0
- package/dist/{BeforeAfterSection-DVAWWE4K.cjs → BeforeAfterSection-JTORBR3A.cjs} +6 -6
- package/dist/BeforeAfterSection-JTORBR3A.cjs.map +1 -0
- package/dist/DesignSystemSection-2R5BRBGO.js +172 -0
- package/dist/DesignSystemSection-2R5BRBGO.js.map +1 -0
- package/dist/DesignSystemSection-KXIQXITF.cjs +174 -0
- package/dist/DesignSystemSection-KXIQXITF.cjs.map +1 -0
- package/dist/{DetailsSection-FB763FS7.js → DetailsSection-A6PZQUQL.js} +14 -5
- package/dist/DetailsSection-A6PZQUQL.js.map +1 -0
- package/dist/{DetailsSection-OACJFGH7.cjs → DetailsSection-TTUZAPZZ.cjs} +14 -5
- package/dist/DetailsSection-TTUZAPZZ.cjs.map +1 -0
- package/dist/PerformanceSection-24TVVFZA.cjs +356 -0
- package/dist/PerformanceSection-24TVVFZA.cjs.map +1 -0
- package/dist/PerformanceSection-MGCEIXDX.js +351 -0
- package/dist/PerformanceSection-MGCEIXDX.js.map +1 -0
- package/dist/SiteArchitectureSection-EE6VQSXM.cjs +349 -0
- package/dist/SiteArchitectureSection-EE6VQSXM.cjs.map +1 -0
- package/dist/SiteArchitectureSection-PBBRTARV.js +344 -0
- package/dist/SiteArchitectureSection-PBBRTARV.js.map +1 -0
- package/dist/SpeedComparisonSection-EZKFQVGW.cjs +174 -0
- package/dist/SpeedComparisonSection-EZKFQVGW.cjs.map +1 -0
- package/dist/SpeedComparisonSection-Y3K7OFZQ.js +172 -0
- package/dist/SpeedComparisonSection-Y3K7OFZQ.js.map +1 -0
- package/dist/{StrategySection-3ED3QW4R.cjs → StrategySection-CJ7Y6OFQ.cjs} +18 -24
- package/dist/StrategySection-CJ7Y6OFQ.cjs.map +1 -0
- package/dist/{StrategySection-VUWMIYYP.js → StrategySection-DI5RSCJU.js} +18 -24
- package/dist/StrategySection-DI5RSCJU.js.map +1 -0
- package/dist/TechStackSection-2AQ7RGY3.js +93 -0
- package/dist/TechStackSection-2AQ7RGY3.js.map +1 -0
- package/dist/TechStackSection-VTNNZR5V.cjs +95 -0
- package/dist/TechStackSection-VTNNZR5V.cjs.map +1 -0
- package/dist/{chunk-XMC4DN6G.js → chunk-APG2QSMB.js} +8 -8
- package/dist/chunk-APG2QSMB.js.map +1 -0
- package/dist/chunk-JTI3F3QY.cjs +619 -0
- package/dist/chunk-JTI3F3QY.cjs.map +1 -0
- package/dist/{chunk-NAS4K5UR.cjs → chunk-OA5ZM4OA.cjs} +8 -8
- package/dist/chunk-OA5ZM4OA.cjs.map +1 -0
- package/dist/{chunk-QIC6JFFD.js → chunk-OMOF4VR5.js} +14 -14
- package/dist/chunk-OMOF4VR5.js.map +1 -0
- package/dist/chunk-RLVW7WEK.js +612 -0
- package/dist/chunk-RLVW7WEK.js.map +1 -0
- package/dist/{chunk-5FKOLIV6.cjs → chunk-XM2QD3AK.cjs} +14 -14
- package/dist/chunk-XM2QD3AK.cjs.map +1 -0
- package/dist/index.cjs +13 -13
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/layout/index.cjs +2 -2
- package/dist/layout/index.d.cts +1 -1
- package/dist/layout/index.d.ts +1 -1
- package/dist/layout/index.js +1 -1
- package/dist/portfolio/client.cjs +3 -3
- package/dist/portfolio/client.d.cts +7 -3
- package/dist/portfolio/client.d.ts +7 -3
- package/dist/portfolio/client.js +1 -1
- package/dist/portfolio/index.cjs +6 -6
- package/dist/portfolio/index.d.cts +2 -2
- package/dist/portfolio/index.d.ts +2 -2
- package/dist/portfolio/index.js +2 -2
- package/dist/portfolio/sections.d.cts +1 -1
- package/dist/portfolio/sections.d.ts +1 -1
- package/dist/portfolio/server.cjs +1 -0
- package/dist/portfolio/server.cjs.map +1 -1
- package/dist/portfolio/server.d.cts +1 -1
- package/dist/portfolio/server.d.ts +1 -1
- package/dist/portfolio/server.js +1 -0
- package/dist/portfolio/server.js.map +1 -1
- package/dist/{types-BMUhBhWx.d.cts → types-DL4t_Cfa.d.cts} +3 -1
- package/dist/{types-BMUhBhWx.d.ts → types-DL4t_Cfa.d.ts} +3 -1
- package/package.json +1 -1
- package/dist/BeforeAfterSection-6QUJOBO2.js.map +0 -1
- package/dist/BeforeAfterSection-DVAWWE4K.cjs.map +0 -1
- package/dist/DetailsSection-FB763FS7.js.map +0 -1
- package/dist/DetailsSection-OACJFGH7.cjs.map +0 -1
- package/dist/StrategySection-3ED3QW4R.cjs.map +0 -1
- package/dist/StrategySection-VUWMIYYP.js.map +0 -1
- package/dist/TechStackSection-OCUYG4XT.js +0 -90
- package/dist/TechStackSection-OCUYG4XT.js.map +0 -1
- package/dist/TechStackSection-VKJK4KQB.cjs +0 -91
- package/dist/TechStackSection-VKJK4KQB.cjs.map +0 -1
- package/dist/chunk-2VNNFAG6.js +0 -415
- package/dist/chunk-2VNNFAG6.js.map +0 -1
- package/dist/chunk-5FKOLIV6.cjs.map +0 -1
- package/dist/chunk-NAS4K5UR.cjs.map +0 -1
- package/dist/chunk-QIC6JFFD.js.map +0 -1
- package/dist/chunk-TAPNXT7X.cjs +0 -422
- package/dist/chunk-TAPNXT7X.cjs.map +0 -1
- package/dist/chunk-XMC4DN6G.js.map +0 -1
package/dist/chunk-TAPNXT7X.cjs
DELETED
|
@@ -1,422 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var chunkXONXEFJY_cjs = require('./chunk-XONXEFJY.cjs');
|
|
4
|
-
var chunkKEOHORIH_cjs = require('./chunk-KEOHORIH.cjs');
|
|
5
|
-
var chunkIKBK7HYX_cjs = require('./chunk-IKBK7HYX.cjs');
|
|
6
|
-
var dynamic = require('next/dynamic');
|
|
7
|
-
var react = require('react');
|
|
8
|
-
var gsap = require('gsap');
|
|
9
|
-
var ScrollTrigger = require('gsap/ScrollTrigger');
|
|
10
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
11
|
-
|
|
12
|
-
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
|
-
|
|
14
|
-
var dynamic__default = /*#__PURE__*/_interopDefault(dynamic);
|
|
15
|
-
var gsap__default = /*#__PURE__*/_interopDefault(gsap);
|
|
16
|
-
|
|
17
|
-
function SplitHeadline({
|
|
18
|
-
children,
|
|
19
|
-
tag: Tag = "h2",
|
|
20
|
-
className,
|
|
21
|
-
style,
|
|
22
|
-
delay = 0,
|
|
23
|
-
duration = 0.8,
|
|
24
|
-
staggerAmount = 0.02
|
|
25
|
-
}) {
|
|
26
|
-
const ref = react.useRef(null);
|
|
27
|
-
const splitContent = react.useMemo(() => {
|
|
28
|
-
const words = children.split(" ");
|
|
29
|
-
return words.map((word, wi) => /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "inline-block", whiteSpace: "nowrap" }, children: [
|
|
30
|
-
word.split("").map((char, ci) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
31
|
-
"span",
|
|
32
|
-
{
|
|
33
|
-
className: "split-char",
|
|
34
|
-
style: { display: "inline-block" },
|
|
35
|
-
children: char
|
|
36
|
-
},
|
|
37
|
-
ci
|
|
38
|
-
)),
|
|
39
|
-
wi < words.length - 1 && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { display: "inline-block" }, children: "\xA0" })
|
|
40
|
-
] }, wi));
|
|
41
|
-
}, [children]);
|
|
42
|
-
react.useEffect(() => {
|
|
43
|
-
gsap__default.default.registerPlugin(ScrollTrigger.ScrollTrigger);
|
|
44
|
-
const el = ref.current;
|
|
45
|
-
if (!el) return;
|
|
46
|
-
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
47
|
-
if (prefersReducedMotion) {
|
|
48
|
-
gsap__default.default.set(el.querySelectorAll(".split-char"), { opacity: 1, y: 0 });
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
const chars = el.querySelectorAll(".split-char");
|
|
52
|
-
const ctx = gsap__default.default.context(() => {
|
|
53
|
-
gsap__default.default.fromTo(
|
|
54
|
-
chars,
|
|
55
|
-
{
|
|
56
|
-
opacity: 0,
|
|
57
|
-
y: 20
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
opacity: 1,
|
|
61
|
-
y: 0,
|
|
62
|
-
duration,
|
|
63
|
-
delay,
|
|
64
|
-
stagger: staggerAmount,
|
|
65
|
-
ease: "power2.out",
|
|
66
|
-
scrollTrigger: {
|
|
67
|
-
trigger: el,
|
|
68
|
-
start: "top 85%",
|
|
69
|
-
toggleActions: "play none none none"
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
);
|
|
73
|
-
}, el);
|
|
74
|
-
return () => ctx.revert();
|
|
75
|
-
}, [delay, duration, staggerAmount]);
|
|
76
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
77
|
-
Tag,
|
|
78
|
-
{
|
|
79
|
-
ref,
|
|
80
|
-
className,
|
|
81
|
-
style: { overflow: "hidden", ...style },
|
|
82
|
-
children: splitContent
|
|
83
|
-
}
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
function HeroSection({ data, screenshots, liveUrl }) {
|
|
87
|
-
const bgRef = react.useRef(null);
|
|
88
|
-
const deviceRef = react.useRef(null);
|
|
89
|
-
const shots = screenshots || data.screenshots;
|
|
90
|
-
const url = liveUrl || data.liveUrl;
|
|
91
|
-
react.useEffect(() => {
|
|
92
|
-
gsap__default.default.registerPlugin(ScrollTrigger.ScrollTrigger);
|
|
93
|
-
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
94
|
-
if (prefersReducedMotion) return;
|
|
95
|
-
const ctx = gsap__default.default.context(() => {
|
|
96
|
-
if (bgRef.current) {
|
|
97
|
-
gsap__default.default.to(bgRef.current, {
|
|
98
|
-
yPercent: 30,
|
|
99
|
-
ease: "none",
|
|
100
|
-
scrollTrigger: {
|
|
101
|
-
trigger: bgRef.current.parentElement,
|
|
102
|
-
start: "top top",
|
|
103
|
-
end: "bottom top",
|
|
104
|
-
scrub: true
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
if (deviceRef.current) {
|
|
109
|
-
const devices = deviceRef.current.children;
|
|
110
|
-
gsap__default.default.fromTo(
|
|
111
|
-
devices,
|
|
112
|
-
{ y: 60, opacity: 0, scale: 0.95 },
|
|
113
|
-
{
|
|
114
|
-
y: 0,
|
|
115
|
-
opacity: 1,
|
|
116
|
-
scale: 1,
|
|
117
|
-
duration: 1,
|
|
118
|
-
stagger: 0.15,
|
|
119
|
-
ease: "power3.out",
|
|
120
|
-
delay: 0.6
|
|
121
|
-
}
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
return () => ctx.revert();
|
|
126
|
-
}, []);
|
|
127
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
128
|
-
"section",
|
|
129
|
-
{
|
|
130
|
-
className: "relative overflow-hidden w-full",
|
|
131
|
-
style: {
|
|
132
|
-
minHeight: "90vh",
|
|
133
|
-
display: "flex",
|
|
134
|
-
flexDirection: "column",
|
|
135
|
-
justifyContent: "center",
|
|
136
|
-
background: "var(--sk-bg, #0a0a0a)"
|
|
137
|
-
},
|
|
138
|
-
children: [
|
|
139
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
140
|
-
"div",
|
|
141
|
-
{
|
|
142
|
-
ref: bgRef,
|
|
143
|
-
className: "absolute inset-0 pointer-events-none",
|
|
144
|
-
style: {
|
|
145
|
-
background: `radial-gradient(ellipse at 50% 20%, color-mix(in srgb, var(--sk-primary, #6366f1) 15%, transparent) 0%, transparent 70%)`,
|
|
146
|
-
willChange: "transform"
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
),
|
|
150
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative z-10 max-w-7xl mx-auto w-full px-6 py-24 lg:py-32", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid lg:grid-cols-2 gap-12 lg:gap-16 items-center", children: [
|
|
151
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-6", children: [
|
|
152
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunkIKBK7HYX_cjs.ScrollReveal, { y: 20, duration: 0.6, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
153
|
-
"span",
|
|
154
|
-
{
|
|
155
|
-
className: "inline-flex items-center self-start px-4 py-1.5 rounded-full text-sm font-medium",
|
|
156
|
-
style: {
|
|
157
|
-
background: "color-mix(in srgb, var(--sk-primary, #6366f1) 15%, transparent)",
|
|
158
|
-
color: "var(--sk-primary, #6366f1)",
|
|
159
|
-
border: "1px solid color-mix(in srgb, var(--sk-primary, #6366f1) 25%, transparent)"
|
|
160
|
-
},
|
|
161
|
-
children: data.category
|
|
162
|
-
}
|
|
163
|
-
) }),
|
|
164
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
165
|
-
SplitHeadline,
|
|
166
|
-
{
|
|
167
|
-
tag: "h1",
|
|
168
|
-
className: "text-4xl md:text-5xl lg:text-6xl font-bold leading-tight",
|
|
169
|
-
style: {
|
|
170
|
-
color: "var(--sk-text-primary, #ffffff)",
|
|
171
|
-
fontFamily: "var(--sk-font-heading, inherit)"
|
|
172
|
-
},
|
|
173
|
-
children: data.headline
|
|
174
|
-
}
|
|
175
|
-
),
|
|
176
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunkIKBK7HYX_cjs.ScrollReveal, { y: 20, delay: 0.2, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
177
|
-
"p",
|
|
178
|
-
{
|
|
179
|
-
className: "text-xl md:text-2xl font-medium",
|
|
180
|
-
style: { color: "var(--sk-text-secondary, #a1a1aa)" },
|
|
181
|
-
children: data.subheadline
|
|
182
|
-
}
|
|
183
|
-
) }),
|
|
184
|
-
/* @__PURE__ */ jsxRuntime.jsx(chunkIKBK7HYX_cjs.ScrollReveal, { y: 20, delay: 0.3, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
185
|
-
"p",
|
|
186
|
-
{
|
|
187
|
-
className: "text-base md:text-lg leading-relaxed",
|
|
188
|
-
style: { color: "var(--sk-text-tertiary, #71717a)" },
|
|
189
|
-
children: data.description
|
|
190
|
-
}
|
|
191
|
-
) }),
|
|
192
|
-
data.services.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(chunkIKBK7HYX_cjs.ScrollReveal, { y: 20, delay: 0.4, stagger: 0.05, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: data.services.map((service) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
193
|
-
"span",
|
|
194
|
-
{
|
|
195
|
-
className: "px-3 py-1 rounded-full text-xs font-medium",
|
|
196
|
-
style: {
|
|
197
|
-
background: "var(--sk-surface, rgba(255,255,255,0.05))",
|
|
198
|
-
color: "var(--sk-text-secondary, #a1a1aa)",
|
|
199
|
-
border: "1px solid var(--sk-border, rgba(255,255,255,0.1))"
|
|
200
|
-
},
|
|
201
|
-
children: service
|
|
202
|
-
},
|
|
203
|
-
service
|
|
204
|
-
)) }) }),
|
|
205
|
-
url && /* @__PURE__ */ jsxRuntime.jsx(chunkIKBK7HYX_cjs.ScrollReveal, { y: 20, delay: 0.5, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
206
|
-
"a",
|
|
207
|
-
{
|
|
208
|
-
href: url,
|
|
209
|
-
target: "_blank",
|
|
210
|
-
rel: "noopener noreferrer",
|
|
211
|
-
className: "inline-flex items-center gap-2 self-start px-6 py-3 rounded-xl text-sm font-semibold transition-opacity hover:opacity-90",
|
|
212
|
-
style: {
|
|
213
|
-
background: "var(--sk-primary, #6366f1)",
|
|
214
|
-
color: "#ffffff"
|
|
215
|
-
},
|
|
216
|
-
children: [
|
|
217
|
-
"View Live Site",
|
|
218
|
-
/* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 3h7v7M13 3L3 13", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
|
|
219
|
-
]
|
|
220
|
-
}
|
|
221
|
-
) }),
|
|
222
|
-
data.kpis.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(chunkIKBK7HYX_cjs.ScrollReveal, { y: 30, delay: 0.6, stagger: 0.1, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 md:grid-cols-3 gap-4 mt-4", children: data.kpis.map((kpi, i) => /* @__PURE__ */ jsxRuntime.jsxs(chunkKEOHORIH_cjs.GlassCard, { padding: "sm", hover: false, className: "text-center", children: [
|
|
223
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
224
|
-
"div",
|
|
225
|
-
{
|
|
226
|
-
className: "text-2xl md:text-3xl font-bold",
|
|
227
|
-
style: { color: "var(--sk-primary, #6366f1)" },
|
|
228
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
229
|
-
chunkXONXEFJY_cjs.AnimatedCounter,
|
|
230
|
-
{
|
|
231
|
-
value: kpi.value,
|
|
232
|
-
suffix: kpi.suffix,
|
|
233
|
-
prefix: kpi.prefix,
|
|
234
|
-
duration: 2.5
|
|
235
|
-
}
|
|
236
|
-
)
|
|
237
|
-
}
|
|
238
|
-
),
|
|
239
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
240
|
-
"div",
|
|
241
|
-
{
|
|
242
|
-
className: "text-xs mt-1 font-medium",
|
|
243
|
-
style: { color: "var(--sk-text-secondary, #a1a1aa)" },
|
|
244
|
-
children: kpi.label
|
|
245
|
-
}
|
|
246
|
-
),
|
|
247
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
248
|
-
"span",
|
|
249
|
-
{
|
|
250
|
-
className: "inline-block mt-1.5 px-2 py-0.5 rounded text-[10px] uppercase tracking-wider font-medium",
|
|
251
|
-
style: {
|
|
252
|
-
background: kpi.source === "measured" ? "color-mix(in srgb, #10b981 15%, transparent)" : "color-mix(in srgb, #f59e0b 15%, transparent)",
|
|
253
|
-
color: kpi.source === "measured" ? "#10b981" : "#f59e0b"
|
|
254
|
-
},
|
|
255
|
-
children: kpi.source
|
|
256
|
-
}
|
|
257
|
-
)
|
|
258
|
-
] }, i)) }) })
|
|
259
|
-
] }),
|
|
260
|
-
(shots?.desktop || shots?.tablet || shots?.mobile) && /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: deviceRef, className: "relative flex items-end justify-center gap-3 lg:gap-4 min-h-[400px]", children: [
|
|
261
|
-
shots.desktop && /* @__PURE__ */ jsxRuntime.jsx(
|
|
262
|
-
"div",
|
|
263
|
-
{
|
|
264
|
-
className: "relative w-full max-w-[480px] rounded-lg overflow-hidden shadow-2xl",
|
|
265
|
-
style: {
|
|
266
|
-
border: "2px solid var(--sk-border, rgba(255,255,255,0.1))",
|
|
267
|
-
aspectRatio: "16/10"
|
|
268
|
-
},
|
|
269
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
270
|
-
"img",
|
|
271
|
-
{
|
|
272
|
-
src: shots.desktop,
|
|
273
|
-
alt: "Desktop screenshot",
|
|
274
|
-
className: "w-full h-full object-cover object-top",
|
|
275
|
-
loading: "eager"
|
|
276
|
-
}
|
|
277
|
-
)
|
|
278
|
-
}
|
|
279
|
-
),
|
|
280
|
-
shots.tablet && /* @__PURE__ */ jsxRuntime.jsx(
|
|
281
|
-
"div",
|
|
282
|
-
{
|
|
283
|
-
className: "absolute bottom-0 right-0 w-[45%] max-w-[220px] rounded-lg overflow-hidden shadow-2xl z-10",
|
|
284
|
-
style: {
|
|
285
|
-
border: "2px solid var(--sk-border, rgba(255,255,255,0.1))",
|
|
286
|
-
aspectRatio: "3/4",
|
|
287
|
-
transform: "translateX(10%) translateY(5%)"
|
|
288
|
-
},
|
|
289
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
290
|
-
"img",
|
|
291
|
-
{
|
|
292
|
-
src: shots.tablet,
|
|
293
|
-
alt: "Tablet screenshot",
|
|
294
|
-
className: "w-full h-full object-cover object-top",
|
|
295
|
-
loading: "eager"
|
|
296
|
-
}
|
|
297
|
-
)
|
|
298
|
-
}
|
|
299
|
-
),
|
|
300
|
-
shots.mobile && /* @__PURE__ */ jsxRuntime.jsx(
|
|
301
|
-
"div",
|
|
302
|
-
{
|
|
303
|
-
className: "absolute bottom-0 right-[15%] w-[25%] max-w-[120px] rounded-xl overflow-hidden shadow-2xl z-20",
|
|
304
|
-
style: {
|
|
305
|
-
border: "2px solid var(--sk-border, rgba(255,255,255,0.1))",
|
|
306
|
-
aspectRatio: "9/19",
|
|
307
|
-
transform: "translateY(10%)"
|
|
308
|
-
},
|
|
309
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
310
|
-
"img",
|
|
311
|
-
{
|
|
312
|
-
src: shots.mobile,
|
|
313
|
-
alt: "Mobile screenshot",
|
|
314
|
-
className: "w-full h-full object-cover object-top",
|
|
315
|
-
loading: "eager"
|
|
316
|
-
}
|
|
317
|
-
)
|
|
318
|
-
}
|
|
319
|
-
)
|
|
320
|
-
] })
|
|
321
|
-
] }) })
|
|
322
|
-
]
|
|
323
|
-
}
|
|
324
|
-
);
|
|
325
|
-
}
|
|
326
|
-
var ChallengesSection = dynamic__default.default(() => import('./ChallengesSection-IZ3DHECS.cjs'), { ssr: true });
|
|
327
|
-
var StrategySection = dynamic__default.default(() => import('./StrategySection-3ED3QW4R.cjs'), { ssr: true });
|
|
328
|
-
var ResultsSection = dynamic__default.default(() => import('./ResultsSection-XLGMMQKY.cjs'), { ssr: true });
|
|
329
|
-
var TechStackSection = dynamic__default.default(() => import('./TechStackSection-VKJK4KQB.cjs'), { ssr: true });
|
|
330
|
-
var ServicesSection = dynamic__default.default(() => import('./ServicesSection-WJMGK2MF.cjs'), { ssr: true });
|
|
331
|
-
var TestimonialSection = dynamic__default.default(() => import('./TestimonialSection-XPTFUQIN.cjs'), { ssr: true });
|
|
332
|
-
var GallerySection = dynamic__default.default(() => import('./GallerySection-WJ4PQDBI.cjs'), { ssr: true });
|
|
333
|
-
var VideoSection = dynamic__default.default(() => import('./VideoSection-G3DFS7UH.cjs'), { ssr: true });
|
|
334
|
-
var TeamSection = dynamic__default.default(() => import('./TeamSection-DZVSNZE6.cjs'), { ssr: true });
|
|
335
|
-
var FeatureSpotlightSection = dynamic__default.default(() => import('./FeatureSpotlightSection-WRHXS7TU.cjs'), { ssr: true });
|
|
336
|
-
var BeforeAfterSection = dynamic__default.default(() => import('./BeforeAfterSection-DVAWWE4K.cjs'), { ssr: true });
|
|
337
|
-
var MetricsTimelineSection = dynamic__default.default(() => import('./MetricsTimelineSection-4L6DUHJ5.cjs'), { ssr: true });
|
|
338
|
-
var ConversionFunnelSection = dynamic__default.default(() => import('./ConversionFunnelSection-AUUSJ5HQ.cjs'), { ssr: true });
|
|
339
|
-
var DetailsSection = dynamic__default.default(() => import('./DetailsSection-OACJFGH7.cjs'), { ssr: true });
|
|
340
|
-
var CTASection = dynamic__default.default(() => import('./CTASection-4JKLXEUF.cjs'), { ssr: true });
|
|
341
|
-
function renderSection(section, item, index) {
|
|
342
|
-
const key = `${section.sectionType}-${index}`;
|
|
343
|
-
switch (section.sectionType) {
|
|
344
|
-
case "portfolioHero":
|
|
345
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
346
|
-
HeroSection,
|
|
347
|
-
{
|
|
348
|
-
data: section.data,
|
|
349
|
-
screenshots: item.hero_screenshots ?? void 0,
|
|
350
|
-
liveUrl: item.live_url ?? void 0
|
|
351
|
-
},
|
|
352
|
-
key
|
|
353
|
-
);
|
|
354
|
-
case "portfolioChallenges":
|
|
355
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ChallengesSection, { data: section.data }, key);
|
|
356
|
-
case "portfolioStrategy":
|
|
357
|
-
return /* @__PURE__ */ jsxRuntime.jsx(StrategySection, { data: section.data }, key);
|
|
358
|
-
case "portfolioResults":
|
|
359
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ResultsSection, { data: section.data }, key);
|
|
360
|
-
case "portfolioTechStack":
|
|
361
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TechStackSection, { data: section.data }, key);
|
|
362
|
-
case "portfolioServices":
|
|
363
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ServicesSection, { data: section.data }, key);
|
|
364
|
-
case "portfolioTestimonial":
|
|
365
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TestimonialSection, { data: section.data }, key);
|
|
366
|
-
case "portfolioGallery":
|
|
367
|
-
return /* @__PURE__ */ jsxRuntime.jsx(GallerySection, { data: section.data }, key);
|
|
368
|
-
case "portfolioVideo":
|
|
369
|
-
return /* @__PURE__ */ jsxRuntime.jsx(VideoSection, { data: section.data }, key);
|
|
370
|
-
case "portfolioTeam":
|
|
371
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TeamSection, { data: section.data }, key);
|
|
372
|
-
case "portfolioFeatureSpotlight":
|
|
373
|
-
return /* @__PURE__ */ jsxRuntime.jsx(FeatureSpotlightSection, { data: section.data }, key);
|
|
374
|
-
case "portfolioBeforeAfter":
|
|
375
|
-
return /* @__PURE__ */ jsxRuntime.jsx(BeforeAfterSection, { data: section.data }, key);
|
|
376
|
-
case "portfolioMetricsTimeline":
|
|
377
|
-
return /* @__PURE__ */ jsxRuntime.jsx(MetricsTimelineSection, { data: section.data }, key);
|
|
378
|
-
case "portfolioConversionFunnel":
|
|
379
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ConversionFunnelSection, { data: section.data }, key);
|
|
380
|
-
case "portfolioDetails":
|
|
381
|
-
return /* @__PURE__ */ jsxRuntime.jsx(DetailsSection, { data: section.data }, key);
|
|
382
|
-
case "portfolioCTA":
|
|
383
|
-
return /* @__PURE__ */ jsxRuntime.jsx(CTASection, { data: section.data }, key);
|
|
384
|
-
case "portfolioSeo":
|
|
385
|
-
return null;
|
|
386
|
-
default:
|
|
387
|
-
return null;
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
function PortfolioPage({ item }) {
|
|
391
|
-
return /* @__PURE__ */ jsxRuntime.jsx("article", { className: "w-full flex flex-col", children: item.sections.map((section, index) => {
|
|
392
|
-
const rendered = renderSection(section, item, index);
|
|
393
|
-
if (!rendered) return null;
|
|
394
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full", children: rendered }, `wrapper-${section.sectionType}-${index}`);
|
|
395
|
-
}) });
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
// src/types.ts
|
|
399
|
-
var PORTFOLIO_SECTION_TYPES = [
|
|
400
|
-
"portfolioHero",
|
|
401
|
-
"portfolioChallenges",
|
|
402
|
-
"portfolioStrategy",
|
|
403
|
-
"portfolioResults",
|
|
404
|
-
"portfolioTechStack",
|
|
405
|
-
"portfolioServices",
|
|
406
|
-
"portfolioTestimonial",
|
|
407
|
-
"portfolioGallery",
|
|
408
|
-
"portfolioVideo",
|
|
409
|
-
"portfolioTeam",
|
|
410
|
-
"portfolioFeatureSpotlight",
|
|
411
|
-
"portfolioBeforeAfter",
|
|
412
|
-
"portfolioMetricsTimeline",
|
|
413
|
-
"portfolioConversionFunnel",
|
|
414
|
-
"portfolioDetails",
|
|
415
|
-
"portfolioSeo",
|
|
416
|
-
"portfolioCTA"
|
|
417
|
-
];
|
|
418
|
-
|
|
419
|
-
exports.PORTFOLIO_SECTION_TYPES = PORTFOLIO_SECTION_TYPES;
|
|
420
|
-
exports.PortfolioPage = PortfolioPage;
|
|
421
|
-
//# sourceMappingURL=chunk-TAPNXT7X.cjs.map
|
|
422
|
-
//# sourceMappingURL=chunk-TAPNXT7X.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/portfolio/components/primitives/SplitHeadline.tsx","../src/portfolio/components/sections/HeroSection.tsx","../src/portfolio/components/PortfolioPage.tsx","../src/types.ts"],"names":["useRef","useMemo","jsxs","jsx","useEffect","gsap","ScrollTrigger","ScrollReveal","GlassCard","AnimatedCounter","dynamic"],"mappings":"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","file":"chunk-TAPNXT7X.cjs","sourcesContent":["'use client';\n\nimport React, { useRef, useEffect, useMemo } from 'react';\nimport gsap from 'gsap';\nimport { ScrollTrigger } from 'gsap/ScrollTrigger';\n\ninterface SplitHeadlineProps {\n children: string;\n tag?: 'h1' | 'h2' | 'h3' | 'h4' | 'p';\n className?: string;\n style?: React.CSSProperties;\n delay?: number;\n duration?: number;\n staggerAmount?: number;\n}\n\nexport default function SplitHeadline({\n children,\n tag: Tag = 'h2',\n className,\n style,\n delay = 0,\n duration = 0.8,\n staggerAmount = 0.02,\n}: SplitHeadlineProps) {\n const ref = useRef<HTMLElement>(null);\n\n // Split text into words and characters, preserving spaces\n const splitContent = useMemo(() => {\n const words = children.split(' ');\n return words.map((word, wi) => (\n <span key={wi} style={{ display: 'inline-block', whiteSpace: 'nowrap' }}>\n {word.split('').map((char, ci) => (\n <span\n key={ci}\n className=\"split-char\"\n style={{ display: 'inline-block' }}\n >\n {char}\n </span>\n ))}\n {wi < words.length - 1 && (\n <span style={{ display: 'inline-block' }}> </span>\n )}\n </span>\n ));\n }, [children]);\n\n useEffect(() => {\n gsap.registerPlugin(ScrollTrigger);\n\n const el = ref.current;\n if (!el) return;\n\n // Respect prefers-reduced-motion\n const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n if (prefersReducedMotion) {\n gsap.set(el.querySelectorAll('.split-char'), { opacity: 1, y: 0 });\n return;\n }\n\n const chars = el.querySelectorAll('.split-char');\n\n const ctx = gsap.context(() => {\n gsap.fromTo(\n chars,\n {\n opacity: 0,\n y: 20,\n },\n {\n opacity: 1,\n y: 0,\n duration,\n delay,\n stagger: staggerAmount,\n ease: 'power2.out',\n scrollTrigger: {\n trigger: el,\n start: 'top 85%',\n toggleActions: 'play none none none',\n },\n },\n );\n }, el);\n\n return () => ctx.revert();\n }, [delay, duration, staggerAmount]);\n\n return (\n <Tag\n ref={ref as React.RefObject<any>}\n className={className}\n style={{ overflow: 'hidden', ...style }}\n >\n {splitContent}\n </Tag>\n );\n}\n","'use client';\n\nimport React, { useRef, useEffect } from 'react';\nimport gsap from 'gsap';\nimport { ScrollTrigger } from 'gsap/ScrollTrigger';\nimport type { PortfolioHeroData } from '../../../types';\nimport ScrollReveal from '../primitives/ScrollReveal';\nimport AnimatedCounter from '../primitives/AnimatedCounter';\nimport SplitHeadline from '../primitives/SplitHeadline';\nimport GlassCard from '../primitives/GlassCard';\n\ninterface HeroSectionProps {\n data: PortfolioHeroData;\n screenshots?: { desktop?: string; tablet?: string; mobile?: string };\n liveUrl?: string;\n}\n\nexport default function HeroSection({ data, screenshots, liveUrl }: HeroSectionProps) {\n const bgRef = useRef<HTMLDivElement>(null);\n const deviceRef = useRef<HTMLDivElement>(null);\n\n const shots = screenshots || data.screenshots;\n const url = liveUrl || data.liveUrl;\n\n useEffect(() => {\n gsap.registerPlugin(ScrollTrigger);\n\n const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n if (prefersReducedMotion) return;\n\n const ctx = gsap.context(() => {\n // Background parallax — bg moves at 0.3x scroll speed\n if (bgRef.current) {\n gsap.to(bgRef.current, {\n yPercent: 30,\n ease: 'none',\n scrollTrigger: {\n trigger: bgRef.current.parentElement,\n start: 'top top',\n end: 'bottom top',\n scrub: true,\n },\n });\n }\n\n // Device trifolio entrance\n if (deviceRef.current) {\n const devices = deviceRef.current.children;\n gsap.fromTo(\n devices,\n { y: 60, opacity: 0, scale: 0.95 },\n {\n y: 0,\n opacity: 1,\n scale: 1,\n duration: 1,\n stagger: 0.15,\n ease: 'power3.out',\n delay: 0.6,\n },\n );\n }\n });\n\n return () => ctx.revert();\n }, []);\n\n return (\n <section\n className=\"relative overflow-hidden w-full\"\n style={{\n minHeight: '90vh',\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n background: 'var(--sk-bg, #0a0a0a)',\n }}\n >\n {/* Parallax background layer */}\n <div\n ref={bgRef}\n className=\"absolute inset-0 pointer-events-none\"\n style={{\n background: `radial-gradient(ellipse at 50% 20%, color-mix(in srgb, var(--sk-primary, #6366f1) 15%, transparent) 0%, transparent 70%)`,\n willChange: 'transform',\n }}\n />\n\n <div className=\"relative z-10 max-w-7xl mx-auto w-full px-6 py-24 lg:py-32\">\n <div className=\"grid lg:grid-cols-2 gap-12 lg:gap-16 items-center\">\n {/* Text column */}\n <div className=\"flex flex-col gap-6\">\n {/* Category badge */}\n <ScrollReveal y={20} duration={0.6}>\n <span\n className=\"inline-flex items-center self-start px-4 py-1.5 rounded-full text-sm font-medium\"\n style={{\n background: 'color-mix(in srgb, var(--sk-primary, #6366f1) 15%, transparent)',\n color: 'var(--sk-primary, #6366f1)',\n border: '1px solid color-mix(in srgb, var(--sk-primary, #6366f1) 25%, transparent)',\n }}\n >\n {data.category}\n </span>\n </ScrollReveal>\n\n {/* Headline */}\n <SplitHeadline\n tag=\"h1\"\n className=\"text-4xl md:text-5xl lg:text-6xl font-bold leading-tight\"\n style={{\n color: 'var(--sk-text-primary, #ffffff)',\n fontFamily: 'var(--sk-font-heading, inherit)',\n }}\n >\n {data.headline}\n </SplitHeadline>\n\n {/* Subheadline */}\n <ScrollReveal y={20} delay={0.2}>\n <p\n className=\"text-xl md:text-2xl font-medium\"\n style={{ color: 'var(--sk-text-secondary, #a1a1aa)' }}\n >\n {data.subheadline}\n </p>\n </ScrollReveal>\n\n {/* Description */}\n <ScrollReveal y={20} delay={0.3}>\n <p\n className=\"text-base md:text-lg leading-relaxed\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {data.description}\n </p>\n </ScrollReveal>\n\n {/* Services tags */}\n {data.services.length > 0 && (\n <ScrollReveal y={20} delay={0.4} stagger={0.05}>\n <div className=\"flex flex-wrap gap-2\">\n {data.services.map((service) => (\n <span\n key={service}\n className=\"px-3 py-1 rounded-full text-xs font-medium\"\n style={{\n background: 'var(--sk-surface, rgba(255,255,255,0.05))',\n color: 'var(--sk-text-secondary, #a1a1aa)',\n border: '1px solid var(--sk-border, rgba(255,255,255,0.1))',\n }}\n >\n {service}\n </span>\n ))}\n </div>\n </ScrollReveal>\n )}\n\n {/* CTA button */}\n {url && (\n <ScrollReveal y={20} delay={0.5}>\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"inline-flex items-center gap-2 self-start px-6 py-3 rounded-xl text-sm font-semibold transition-opacity hover:opacity-90\"\n style={{\n background: 'var(--sk-primary, #6366f1)',\n color: '#ffffff',\n }}\n >\n View Live Site\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M6 3h7v7M13 3L3 13\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </a>\n </ScrollReveal>\n )}\n\n {/* KPI counter row */}\n {data.kpis.length > 0 && (\n <ScrollReveal y={30} delay={0.6} stagger={0.1}>\n <div className=\"grid grid-cols-2 md:grid-cols-3 gap-4 mt-4\">\n {data.kpis.map((kpi, i) => (\n <GlassCard key={i} padding=\"sm\" hover={false} className=\"text-center\">\n <div\n className=\"text-2xl md:text-3xl font-bold\"\n style={{ color: 'var(--sk-primary, #6366f1)' }}\n >\n <AnimatedCounter\n value={kpi.value}\n suffix={kpi.suffix}\n prefix={kpi.prefix}\n duration={2.5}\n />\n </div>\n <div\n className=\"text-xs mt-1 font-medium\"\n style={{ color: 'var(--sk-text-secondary, #a1a1aa)' }}\n >\n {kpi.label}\n </div>\n {/* Source badge */}\n <span\n className=\"inline-block mt-1.5 px-2 py-0.5 rounded text-[10px] uppercase tracking-wider font-medium\"\n style={{\n background:\n kpi.source === 'measured'\n ? 'color-mix(in srgb, #10b981 15%, transparent)'\n : 'color-mix(in srgb, #f59e0b 15%, transparent)',\n color: kpi.source === 'measured' ? '#10b981' : '#f59e0b',\n }}\n >\n {kpi.source}\n </span>\n </GlassCard>\n ))}\n </div>\n </ScrollReveal>\n )}\n </div>\n\n {/* Device trifolio column */}\n {(shots?.desktop || shots?.tablet || shots?.mobile) && (\n <div ref={deviceRef} className=\"relative flex items-end justify-center gap-3 lg:gap-4 min-h-[400px]\">\n {/* Desktop */}\n {shots.desktop && (\n <div\n className=\"relative w-full max-w-[480px] rounded-lg overflow-hidden shadow-2xl\"\n style={{\n border: '2px solid var(--sk-border, rgba(255,255,255,0.1))',\n aspectRatio: '16/10',\n }}\n >\n <img\n src={shots.desktop}\n alt=\"Desktop screenshot\"\n className=\"w-full h-full object-cover object-top\"\n loading=\"eager\"\n />\n </div>\n )}\n {/* Tablet */}\n {shots.tablet && (\n <div\n className=\"absolute bottom-0 right-0 w-[45%] max-w-[220px] rounded-lg overflow-hidden shadow-2xl z-10\"\n style={{\n border: '2px solid var(--sk-border, rgba(255,255,255,0.1))',\n aspectRatio: '3/4',\n transform: 'translateX(10%) translateY(5%)',\n }}\n >\n <img\n src={shots.tablet}\n alt=\"Tablet screenshot\"\n className=\"w-full h-full object-cover object-top\"\n loading=\"eager\"\n />\n </div>\n )}\n {/* Mobile */}\n {shots.mobile && (\n <div\n className=\"absolute bottom-0 right-[15%] w-[25%] max-w-[120px] rounded-xl overflow-hidden shadow-2xl z-20\"\n style={{\n border: '2px solid var(--sk-border, rgba(255,255,255,0.1))',\n aspectRatio: '9/19',\n transform: 'translateY(10%)',\n }}\n >\n <img\n src={shots.mobile}\n alt=\"Mobile screenshot\"\n className=\"w-full h-full object-cover object-top\"\n loading=\"eager\"\n />\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n </section>\n );\n}\n","/**\n * PortfolioPage — Server component that renders a full portfolio case study.\n *\n * Maps each section in item.sections to the correct renderer component.\n * All sections below the hero are loaded lazily via next/dynamic.\n *\n * NOTE: This file is intentionally NOT a client component — it is designed\n * to be used as an RSC in a Next.js app directory page.\n */\n\nimport React from 'react';\nimport dynamic from 'next/dynamic';\nimport type {\n PortfolioItemFull,\n PortfolioSection,\n PortfolioHeroData,\n PortfolioChallengesData,\n PortfolioStrategyData,\n PortfolioResultsData,\n PortfolioTechStackData,\n PortfolioServicesData,\n PortfolioTestimonialData,\n PortfolioGalleryData,\n PortfolioVideoData,\n PortfolioTeamData,\n PortfolioFeatureSpotlightData,\n PortfolioBeforeAfterData,\n PortfolioMetricsTimelineData,\n PortfolioConversionFunnelData,\n PortfolioDetailsData,\n PortfolioCTAData,\n} from '../../types';\n\n// Hero is loaded eagerly (above the fold)\nimport HeroSection from './sections/HeroSection';\n\n// All other sections are loaded lazily\nconst ChallengesSection = dynamic(() => import('./sections/ChallengesSection'), { ssr: true });\nconst StrategySection = dynamic(() => import('./sections/StrategySection'), { ssr: true });\nconst ResultsSection = dynamic(() => import('./sections/ResultsSection'), { ssr: true });\nconst TechStackSection = dynamic(() => import('./sections/TechStackSection'), { ssr: true });\nconst ServicesSection = dynamic(() => import('./sections/ServicesSection'), { ssr: true });\nconst TestimonialSection = dynamic(() => import('./sections/TestimonialSection'), { ssr: true });\nconst GallerySection = dynamic(() => import('./sections/GallerySection'), { ssr: true });\nconst VideoSection = dynamic(() => import('./sections/VideoSection'), { ssr: true });\nconst TeamSection = dynamic(() => import('./sections/TeamSection'), { ssr: true });\nconst FeatureSpotlightSection = dynamic(() => import('./sections/FeatureSpotlightSection'), { ssr: true });\nconst BeforeAfterSection = dynamic(() => import('./sections/BeforeAfterSection'), { ssr: true });\nconst MetricsTimelineSection = dynamic(() => import('./sections/MetricsTimelineSection'), { ssr: true });\nconst ConversionFunnelSection = dynamic(() => import('./sections/ConversionFunnelSection'), { ssr: true });\nconst DetailsSection = dynamic(() => import('./sections/DetailsSection'), { ssr: true });\nconst CTASection = dynamic(() => import('./sections/CTASection'), { ssr: true });\n\ninterface PortfolioPageProps {\n item: PortfolioItemFull;\n}\n\nfunction renderSection(section: PortfolioSection, item: PortfolioItemFull, index: number) {\n const key = `${section.sectionType}-${index}`;\n\n switch (section.sectionType) {\n case 'portfolioHero':\n return (\n <HeroSection\n key={key}\n data={section.data as PortfolioHeroData}\n screenshots={item.hero_screenshots ?? undefined}\n liveUrl={item.live_url ?? undefined}\n />\n );\n case 'portfolioChallenges':\n return <ChallengesSection key={key} data={section.data as PortfolioChallengesData} />;\n case 'portfolioStrategy':\n return <StrategySection key={key} data={section.data as PortfolioStrategyData} />;\n case 'portfolioResults':\n return <ResultsSection key={key} data={section.data as PortfolioResultsData} />;\n case 'portfolioTechStack':\n return <TechStackSection key={key} data={section.data as PortfolioTechStackData} />;\n case 'portfolioServices':\n return <ServicesSection key={key} data={section.data as PortfolioServicesData} />;\n case 'portfolioTestimonial':\n return <TestimonialSection key={key} data={section.data as PortfolioTestimonialData} />;\n case 'portfolioGallery':\n return <GallerySection key={key} data={section.data as PortfolioGalleryData} />;\n case 'portfolioVideo':\n return <VideoSection key={key} data={section.data as PortfolioVideoData} />;\n case 'portfolioTeam':\n return <TeamSection key={key} data={section.data as PortfolioTeamData} />;\n case 'portfolioFeatureSpotlight':\n return <FeatureSpotlightSection key={key} data={section.data as PortfolioFeatureSpotlightData} />;\n case 'portfolioBeforeAfter':\n return <BeforeAfterSection key={key} data={section.data as PortfolioBeforeAfterData} />;\n case 'portfolioMetricsTimeline':\n return <MetricsTimelineSection key={key} data={section.data as PortfolioMetricsTimelineData} />;\n case 'portfolioConversionFunnel':\n return <ConversionFunnelSection key={key} data={section.data as PortfolioConversionFunnelData} />;\n case 'portfolioDetails':\n return <DetailsSection key={key} data={section.data as PortfolioDetailsData} />;\n case 'portfolioCTA':\n return <CTASection key={key} data={section.data as PortfolioCTAData} />;\n case 'portfolioSeo':\n // SEO section is metadata-only; nothing to render visually.\n return null;\n default:\n return null;\n }\n}\n\nexport default function PortfolioPage({ item }: PortfolioPageProps) {\n return (\n <article className=\"w-full flex flex-col\">\n {item.sections.map((section, index) => {\n const rendered = renderSection(section, item, index);\n if (!rendered) return null;\n return (\n <div key={`wrapper-${section.sectionType}-${index}`} className=\"w-full\">\n {rendered}\n </div>\n );\n })}\n </article>\n );\n}\n","/**\n * @sonordev/agency-site-kit — Type definitions\n *\n * These types mirror the Portal API's cms/types.ts definitions for portfolio\n * content. Keep them in sync when modifying the API response shapes.\n */\n\n// ---------------------------------------------------------------------------\n// Brand Configuration\n// ---------------------------------------------------------------------------\n\nexport interface BrandConfig {\n /** Primary brand color (hex) */\n primary: string;\n /** Secondary/accent color (hex) */\n secondary: string;\n /** Background color (hex) */\n background: string;\n /** Elevated background — cards, modals (hex) */\n backgroundElevated: string;\n /** Surface color — interactive containers (hex) */\n surface: string;\n /** Surface hover state (hex) */\n surfaceHover: string;\n /** Surface border color (hex) */\n surfaceBorder: string;\n /** Primary text color (hex) */\n textPrimary: string;\n /** Secondary text color (hex) */\n textSecondary: string;\n /** Tertiary/muted text color (hex) */\n textTertiary: string;\n /** Heading font family */\n fontHeading: string;\n /** Body font family */\n fontBody: string;\n /** Logo URL (absolute or relative) */\n logoUrl?: string;\n /** Logo alt text */\n logoAlt?: string;\n /** Dark mode overrides — partial, merged with base values */\n darkMode?: Partial<Omit<BrandConfig, 'fontHeading' | 'fontBody' | 'logoUrl' | 'logoAlt' | 'darkMode'>>;\n /** Border radius tokens */\n radius?: {\n sm: string;\n md: string;\n lg: string;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Sanity Image Reference\n// ---------------------------------------------------------------------------\n\nexport interface SanityImageRef {\n _type: 'image';\n asset: { _type: 'reference'; _ref: string };\n hotspot?: { x: number; y: number; height: number; width: number };\n crop?: { top: number; bottom: number; left: number; right: number };\n alt?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Metrics\n// ---------------------------------------------------------------------------\n\nexport type MetricSource = 'measured' | 'estimated';\n\nexport interface PortfolioKPI {\n label: string;\n value: number;\n suffix: string;\n prefix?: string;\n description: string;\n source: MetricSource;\n}\n\nexport interface MetricsDelta {\n metric: string;\n baseline: number;\n current: number;\n delta: number;\n deltaPercent: number;\n direction: 'up' | 'down' | 'flat';\n timespan: string;\n}\n\nexport interface MetricsSnapshot {\n seo: {\n clicks_28d?: number;\n impressions_28d?: number;\n avg_position?: number;\n ctr?: number;\n };\n cwv: {\n lcp_ms?: number;\n inp_ms?: number;\n cls?: number;\n performance_score?: number;\n };\n analytics: {\n sessions_28d?: number;\n page_views_28d?: number;\n conversion_rate?: number;\n bounce_rate?: number;\n };\n pages: {\n total_indexed?: number;\n total_crawled?: number;\n total_pages?: number;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Portfolio Section Data Types\n// ---------------------------------------------------------------------------\n\nexport interface PortfolioHeroData {\n headline: string;\n subheadline: string;\n description: string;\n category: string;\n services: string[];\n liveUrl?: string;\n screenshots: {\n desktop?: string;\n tablet?: string;\n mobile?: string;\n };\n kpis: PortfolioKPI[];\n}\n\nexport interface PortfolioChallengeItem {\n title: string;\n description: string;\n solution: string;\n result?: string;\n icon?: string;\n}\n\nexport interface PortfolioChallengesData {\n items: PortfolioChallengeItem[];\n}\n\nexport interface PortfolioStrategyPhase {\n number: number;\n title: string;\n description: string;\n deliverables?: string[];\n icon?: string;\n timeline?: string;\n}\n\nexport interface PortfolioStrategyData {\n phases: PortfolioStrategyPhase[];\n}\n\nexport interface PortfolioResultItem {\n title: string;\n description: string;\n metric?: {\n value: number;\n suffix: string;\n prefix?: string;\n };\n source: MetricSource;\n icon?: string;\n}\n\nexport interface PortfolioResultsData {\n items: PortfolioResultItem[];\n}\n\nexport interface PortfolioTechItem {\n name: string;\n category: string;\n icon?: string;\n description?: string;\n}\n\nexport interface PortfolioTechStackData {\n technologies: PortfolioTechItem[];\n}\n\nexport interface PortfolioServiceItem {\n title: string;\n description: string;\n features: string[];\n icon?: string;\n}\n\nexport interface PortfolioServicesData {\n items: PortfolioServiceItem[];\n}\n\nexport interface PortfolioTestimonialData {\n quote: string;\n author: string;\n title: string;\n company: string;\n avatar?: SanityImageRef;\n rating?: number;\n}\n\nexport interface PortfolioGalleryImage {\n image: SanityImageRef;\n caption?: string;\n type?: 'screenshot' | 'before' | 'after' | 'design';\n}\n\nexport interface PortfolioGalleryData {\n images: PortfolioGalleryImage[];\n layout?: 'grid' | 'masonry';\n}\n\nexport interface PortfolioVideoData {\n url?: string;\n embedUrl?: string;\n thumbnail: SanityImageRef;\n title: string;\n duration?: string;\n platform?: 'youtube' | 'vimeo' | 'custom';\n}\n\nexport interface PortfolioTeamMember {\n name: string;\n role: string;\n avatar?: SanityImageRef;\n}\n\nexport interface PortfolioTeamData {\n members: PortfolioTeamMember[];\n}\n\nexport interface PortfolioAnnotation {\n x: number;\n y: number;\n label: string;\n description: string;\n icon?: string;\n}\n\nexport interface PortfolioFeatureSpotlightData {\n image: SanityImageRef;\n title: string;\n description: string;\n layout: 'left' | 'right' | 'full';\n annotations: PortfolioAnnotation[];\n}\n\nexport interface PortfolioBeforeAfterData {\n before: SanityImageRef;\n after: SanityImageRef;\n title?: string;\n description?: string;\n defaultPosition?: number;\n}\n\nexport interface PortfolioMetricsDataPoint {\n month: string;\n label: string;\n metrics: {\n traffic?: number;\n conversions?: number;\n revenue?: number;\n rankings?: number;\n };\n}\n\nexport interface PortfolioMetricsTimelineData {\n dataPoints: PortfolioMetricsDataPoint[];\n baselineDate: string;\n title?: string;\n description?: string;\n}\n\nexport interface PortfolioFunnelStage {\n label: string;\n value: number;\n icon?: string;\n color?: string;\n}\n\nexport interface PortfolioConversionFunnelData {\n stages: PortfolioFunnelStage[];\n title?: string;\n description?: string;\n}\n\nexport interface PortfolioDetailsData {\n industry: string;\n location?: string;\n website?: string;\n timeline?: string;\n launchDate?: string;\n budgetRange?: string;\n}\n\nexport interface PortfolioSeoData {\n metaTitle: string;\n metaDescription: string;\n keywords: string[];\n ogImage?: SanityImageRef;\n}\n\nexport interface PortfolioCTAData {\n headline: string;\n description: string;\n buttonText: string;\n buttonUrl: string;\n style?: 'primary' | 'glass';\n}\n\n// ---------------------------------------------------------------------------\n// Portfolio Sections\n// ---------------------------------------------------------------------------\n\nexport const PORTFOLIO_SECTION_TYPES = [\n 'portfolioHero',\n 'portfolioChallenges',\n 'portfolioStrategy',\n 'portfolioResults',\n 'portfolioTechStack',\n 'portfolioServices',\n 'portfolioTestimonial',\n 'portfolioGallery',\n 'portfolioVideo',\n 'portfolioTeam',\n 'portfolioFeatureSpotlight',\n 'portfolioBeforeAfter',\n 'portfolioMetricsTimeline',\n 'portfolioConversionFunnel',\n 'portfolioDetails',\n 'portfolioSeo',\n 'portfolioCTA',\n] as const;\n\nexport type PortfolioSectionType = (typeof PORTFOLIO_SECTION_TYPES)[number];\n\nexport type PortfolioSectionData =\n | PortfolioHeroData\n | PortfolioChallengesData\n | PortfolioStrategyData\n | PortfolioResultsData\n | PortfolioTechStackData\n | PortfolioServicesData\n | PortfolioTestimonialData\n | PortfolioGalleryData\n | PortfolioVideoData\n | PortfolioTeamData\n | PortfolioFeatureSpotlightData\n | PortfolioBeforeAfterData\n | PortfolioMetricsTimelineData\n | PortfolioConversionFunnelData\n | PortfolioDetailsData\n | PortfolioSeoData\n | PortfolioCTAData;\n\nexport interface PortfolioSectionDataMap {\n portfolioHero: PortfolioHeroData;\n portfolioChallenges: PortfolioChallengesData;\n portfolioStrategy: PortfolioStrategyData;\n portfolioResults: PortfolioResultsData;\n portfolioTechStack: PortfolioTechStackData;\n portfolioServices: PortfolioServicesData;\n portfolioTestimonial: PortfolioTestimonialData;\n portfolioGallery: PortfolioGalleryData;\n portfolioVideo: PortfolioVideoData;\n portfolioTeam: PortfolioTeamData;\n portfolioFeatureSpotlight: PortfolioFeatureSpotlightData;\n portfolioBeforeAfter: PortfolioBeforeAfterData;\n portfolioMetricsTimeline: PortfolioMetricsTimelineData;\n portfolioConversionFunnel: PortfolioConversionFunnelData;\n portfolioDetails: PortfolioDetailsData;\n portfolioSeo: PortfolioSeoData;\n portfolioCTA: PortfolioCTAData;\n}\n\nexport interface PortfolioSection<T extends PortfolioSectionType = PortfolioSectionType> {\n sectionType: T;\n displayName: string;\n data: T extends keyof PortfolioSectionDataMap ? PortfolioSectionDataMap[T] : PortfolioSectionData;\n}\n\n// ---------------------------------------------------------------------------\n// Portfolio Item (mirrors public API response)\n// ---------------------------------------------------------------------------\n\nexport interface PortfolioItem {\n id: string;\n slug: string;\n title: string;\n subtitle: string;\n category: string;\n services: string[];\n description: string;\n hero_image: string;\n hero_image_alt: string;\n live_url: string | null;\n kpis: PortfolioKPI[];\n details: PortfolioDetailsData | null;\n seo: PortfolioSeoData | null;\n featured: boolean;\n order?: number;\n published_at: string | null;\n hero_screenshots: {\n desktop?: string;\n tablet?: string;\n mobile?: string;\n } | null;\n baseline_metrics: MetricsSnapshot | null;\n current_metrics: MetricsSnapshot | null;\n metrics_last_refreshed_at: string | null;\n}\n\nexport interface PortfolioItemFull extends PortfolioItem {\n sections: PortfolioSection[];\n metricsDelta: MetricsDelta[];\n}\n\n// ---------------------------------------------------------------------------\n// API Responses\n// ---------------------------------------------------------------------------\n\nexport interface PortfolioListResponse {\n items: PortfolioItem[];\n total: number;\n limit: number;\n offset: number;\n}\n\nexport interface PortfolioConfigResponse {\n brand: BrandConfig;\n orgName: string;\n orgSlug: string;\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/portfolio/components/PortfolioCard.tsx","../src/portfolio/components/PortfolioGrid.tsx"],"names":["jsx"],"mappings":"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","file":"chunk-XMC4DN6G.js","sourcesContent":["'use client';\n\nimport React from 'react';\nimport Image from 'next/image';\nimport Link from 'next/link';\nimport type { PortfolioItem } from '../../types';\nimport GlassCard from './primitives/GlassCard';\n\ninterface PortfolioCardProps {\n item: PortfolioItem;\n className?: string;\n}\n\nexport default function PortfolioCard({ item, className = '' }: PortfolioCardProps) {\n // Use hero_screenshots desktop as thumbnail, fall back to hero_image\n const thumbnailSrc = item.hero_screenshots?.desktop || item.hero_image;\n const kpis = Array.isArray(item.kpis) ? item.kpis : [];\n const services = Array.isArray(item.services) ? item.services : [];\n const kpiPreview = kpis.slice(0, 3);\n const servicePreview = services.slice(0, 3);\n\n return (\n <Link href={`/portfolio/${item.slug}`} className={`block group ${className}`}>\n <GlassCard padding=\"sm\" hover>\n <div className=\"flex flex-col gap-4\">\n {/* Thumbnail */}\n {thumbnailSrc && (\n <div\n className=\"relative w-full overflow-hidden rounded-xl\"\n style={{ aspectRatio: '16/10' }}\n >\n <Image\n src={thumbnailSrc}\n alt={item.hero_image_alt || item.title}\n fill\n sizes=\"(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 33vw\"\n className=\"object-cover object-top transition-transform duration-500 group-hover:scale-105\"\n />\n {/* Category badge */}\n <span\n className=\"absolute top-3 left-3 px-3 py-1 rounded-full text-[11px] uppercase tracking-wider font-semibold\"\n style={{\n background: 'color-mix(in srgb, var(--sk-primary, #6366f1) 80%, transparent)',\n color: '#ffffff',\n backdropFilter: 'blur(8px)',\n }}\n >\n {item.category}\n </span>\n </div>\n )}\n\n {/* Text content */}\n <div className=\"flex flex-col gap-2 px-2 pb-2\">\n <h3\n className=\"text-lg font-semibold line-clamp-1\"\n style={{ color: 'var(--sk-text-primary, #ffffff)' }}\n >\n {item.title}\n </h3>\n\n {item.subtitle && (\n <p\n className=\"text-sm line-clamp-2\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {item.subtitle}\n </p>\n )}\n\n {/* KPI preview */}\n {kpiPreview.length > 0 && (\n <div className=\"flex items-center gap-4 mt-1\">\n {kpiPreview.map((kpi, i) => (\n <div key={i} className=\"flex flex-col\">\n <span\n className=\"text-base font-bold\"\n style={{ color: 'var(--sk-primary, #6366f1)' }}\n >\n {kpi.prefix || ''}\n {kpi.value.toLocaleString()}\n {kpi.suffix}\n </span>\n <span\n className=\"text-[10px] uppercase tracking-wider font-medium\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {kpi.label}\n </span>\n </div>\n ))}\n </div>\n )}\n\n {/* Services tags */}\n {servicePreview.length > 0 && (\n <div className=\"flex flex-wrap gap-1.5 mt-2\">\n {servicePreview.map((service) => (\n <span\n key={service}\n className=\"px-2.5 py-0.5 rounded-full text-[11px] font-medium\"\n style={{\n background: 'var(--sk-surface, rgba(255,255,255,0.05))',\n color: 'var(--sk-text-secondary, #a1a1aa)',\n border: '1px solid var(--sk-border, rgba(255,255,255,0.1))',\n }}\n >\n {service}\n </span>\n ))}\n {services.length > 3 && (\n <span\n className=\"px-2.5 py-0.5 rounded-full text-[11px] font-medium\"\n style={{\n background: 'var(--sk-surface, rgba(255,255,255,0.05))',\n color: 'var(--sk-text-tertiary, #71717a)',\n }}\n >\n +{item.services.length - 3}\n </span>\n )}\n </div>\n )}\n </div>\n </div>\n </GlassCard>\n </Link>\n );\n}\n","'use client';\n\nimport React from 'react';\nimport type { PortfolioItem } from '../../types';\nimport ScrollReveal from './primitives/ScrollReveal';\nimport PortfolioCard from './PortfolioCard';\n\ninterface PortfolioGridProps {\n items: PortfolioItem[];\n className?: string;\n}\n\nexport default function PortfolioGrid({ items, className = '' }: PortfolioGridProps) {\n return (\n <ScrollReveal stagger={0.1}>\n <div\n className={`grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 ${className}`}\n style={{\n gap: 'var(--sk-grid-gap, 24px)',\n }}\n >\n {items.map((item) => (\n <PortfolioCard key={item.id} item={item} />\n ))}\n </div>\n </ScrollReveal>\n );\n}\n"]}
|