@sonordev/agency-site-kit 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-7D4H36UF.js +13 -0
- package/dist/chunk-7D4H36UF.js.map +1 -0
- package/dist/{chunk-XLK77USA.js → chunk-K2BGTDSN.js} +2 -2
- package/dist/{chunk-XLK77USA.js.map → chunk-K2BGTDSN.js.map} +1 -1
- package/dist/{chunk-UNTOEWQL.js → chunk-NLGUPJZA.js} +9 -6
- package/dist/chunk-NLGUPJZA.js.map +1 -0
- package/dist/{chunk-L7E3UHQC.cjs → chunk-QGSW43TM.cjs} +9 -6
- package/dist/chunk-QGSW43TM.cjs.map +1 -0
- package/dist/{chunk-NIZJLONK.js → chunk-RWQ675N6.js} +72 -13
- package/dist/chunk-RWQ675N6.js.map +1 -0
- package/dist/{chunk-4N7ENJ7L.cjs → chunk-UXUU7FVT.cjs} +75 -12
- package/dist/chunk-UXUU7FVT.cjs.map +1 -0
- package/dist/chunk-ZBPF7TLZ.cjs +16 -0
- package/dist/chunk-ZBPF7TLZ.cjs.map +1 -0
- package/dist/index.cjs +34 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/portfolio/client.cjs +40 -6
- package/dist/portfolio/client.cjs.map +1 -1
- package/dist/portfolio/client.d.cts +20 -1
- package/dist/portfolio/client.d.ts +20 -1
- package/dist/portfolio/client.js +37 -5
- package/dist/portfolio/client.js.map +1 -1
- package/dist/portfolio/components/PortfolioErrorFallback.cjs +1 -1
- package/dist/portfolio/components/PortfolioErrorFallback.cjs.map +1 -1
- package/dist/portfolio/components/PortfolioErrorFallback.js +1 -1
- package/dist/portfolio/index.cjs +34 -9
- package/dist/portfolio/index.d.cts +82 -5
- package/dist/portfolio/index.d.ts +82 -5
- package/dist/portfolio/index.js +3 -2
- package/dist/portfolio/sections/ChallengesSection.cjs +1 -1
- package/dist/portfolio/sections/ChallengesSection.cjs.map +1 -1
- package/dist/portfolio/sections/ChallengesSection.js +1 -1
- package/dist/portfolio/sections/ChallengesSection.js.map +1 -1
- package/dist/portfolio/sections/HeroSection.cjs +3 -3
- package/dist/portfolio/sections/HeroSection.cjs.map +1 -1
- package/dist/portfolio/sections/HeroSection.js +3 -3
- package/dist/portfolio/sections/HeroSection.js.map +1 -1
- package/dist/portfolio/sections/PerformanceSection.cjs +1 -64
- package/dist/portfolio/sections/PerformanceSection.cjs.map +1 -1
- package/dist/portfolio/sections/PerformanceSection.js +1 -64
- package/dist/portfolio/sections/PerformanceSection.js.map +1 -1
- package/dist/portfolio/sections/ResultsSection.cjs +3 -2
- package/dist/portfolio/sections/ResultsSection.cjs.map +1 -1
- package/dist/portfolio/sections/ResultsSection.d.cts +1 -1
- package/dist/portfolio/sections/ResultsSection.d.ts +1 -1
- package/dist/portfolio/sections/ResultsSection.js +2 -1
- package/dist/portfolio/sections/ResultsSection.js.map +1 -1
- package/dist/portfolio/sections/SiteArchitectureSection.cjs +1 -1
- package/dist/portfolio/sections/SiteArchitectureSection.cjs.map +1 -1
- package/dist/portfolio/sections/SiteArchitectureSection.js +1 -1
- package/dist/portfolio/sections/SiteArchitectureSection.js.map +1 -1
- package/dist/portfolio/sections/SpeedComparisonSection.cjs +1 -1
- package/dist/portfolio/sections/SpeedComparisonSection.cjs.map +1 -1
- package/dist/portfolio/sections/SpeedComparisonSection.js +1 -1
- package/dist/portfolio/sections/SpeedComparisonSection.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-4N7ENJ7L.cjs.map +0 -1
- package/dist/chunk-L7E3UHQC.cjs.map +0 -1
- package/dist/chunk-NIZJLONK.js.map +0 -1
- package/dist/chunk-UNTOEWQL.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { P as PortfolioItemFull, M as MetricsDelta } from '../types-0tVPy4pU.js';
|
|
3
|
-
export { j as MetricSource, k as MetricsSnapshot, l as PORTFOLIO_SECTION_TYPES, n as PortfolioBeforeAfterData, o as PortfolioCTAData, c as PortfolioChallengesData, r as PortfolioConversionFunnelData, d as PortfolioDetailsData, s as PortfolioFeatureSpotlightData, u as PortfolioGalleryData, e as PortfolioHeroData, w as PortfolioItem,
|
|
2
|
+
import { P as PortfolioItemFull, M as MetricsDelta, x as PortfolioKPI, A as PortfolioResultItem } from '../types-0tVPy4pU.js';
|
|
3
|
+
export { j as MetricSource, k as MetricsSnapshot, l as PORTFOLIO_SECTION_TYPES, n as PortfolioBeforeAfterData, o as PortfolioCTAData, c as PortfolioChallengesData, r as PortfolioConversionFunnelData, d as PortfolioDetailsData, s as PortfolioFeatureSpotlightData, u as PortfolioGalleryData, e as PortfolioHeroData, w as PortfolioItem, b as PortfolioListResponse, z as PortfolioMetricsTimelineData, f as PortfolioResultsData, a as PortfolioSection, C as PortfolioSectionData, D as PortfolioSectionDataMap, E as PortfolioSectionType, F as PortfolioSeoData, g as PortfolioServicesData, H as PortfolioStrategyData, J as PortfolioTeamData, h as PortfolioTechStackData, i as PortfolioTestimonialData, N as PortfolioVideoData } from '../types-0tVPy4pU.js';
|
|
4
4
|
export * from '@sonordev/agency-site-kit/portfolio/client';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -29,7 +29,7 @@ export * from '@sonordev/agency-site-kit/portfolio/client';
|
|
|
29
29
|
interface PortfolioPageProps {
|
|
30
30
|
item: PortfolioItemFull;
|
|
31
31
|
}
|
|
32
|
-
declare function PortfolioPage({ item }: PortfolioPageProps): React.JSX.Element;
|
|
32
|
+
declare function PortfolioPage({ item: rawItem }: PortfolioPageProps): React.JSX.Element;
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* PortfolioSchema — JSON-LD structured data for a case study page.
|
|
@@ -109,7 +109,13 @@ declare function PortfolioIndex({ basePath, category, page, pageSize, heading, e
|
|
|
109
109
|
*
|
|
110
110
|
* `direction` semantics come from the API: 'up' ALWAYS means "improved"
|
|
111
111
|
* (lower-is-better metrics like Avg Position/LCP are inverted server-side
|
|
112
|
-
* in metrics-baseline.service), so up renders
|
|
112
|
+
* in metrics-baseline.service), so 'up' renders green. The ARROW glyph
|
|
113
|
+
* follows the raw numbers instead — an improved bounce rate shows a green ▼,
|
|
114
|
+
* never a green ▲ next to a value that visibly went down.
|
|
115
|
+
*
|
|
116
|
+
* Deltas pass through gateMetricsDeltas (curate-proof.ts) before display:
|
|
117
|
+
* raw platform deltas carry no editorial judgment, and this strip only
|
|
118
|
+
* exists to flatter — see that module for the policy.
|
|
113
119
|
*/
|
|
114
120
|
|
|
115
121
|
interface MetricsProvenanceProps {
|
|
@@ -119,6 +125,77 @@ interface MetricsProvenanceProps {
|
|
|
119
125
|
}
|
|
120
126
|
declare function MetricsProvenance({ deltas, refreshedAt }: MetricsProvenanceProps): React.JSX.Element | null;
|
|
121
127
|
|
|
128
|
+
/**
|
|
129
|
+
* curate-proof — single source of truth for which proof points a public case
|
|
130
|
+
* study is allowed to display, and in what shape.
|
|
131
|
+
*
|
|
132
|
+
* Two classes of problem this guards against (both shipped to production on
|
|
133
|
+
* upforge.io before this existed):
|
|
134
|
+
*
|
|
135
|
+
* 1. Repetition: generated items arrive with four "100/100 Lighthouse X"
|
|
136
|
+
* KPIs in the hero, the same four restated as Results cards, AND a full
|
|
137
|
+
* Performance section with score gauges. One differentiator repeated
|
|
138
|
+
* twelve times per page stops differentiating. The Performance section is
|
|
139
|
+
* the one home for the Lighthouse breakdown; hero/results/cards collapse
|
|
140
|
+
* to at most one summary tile.
|
|
141
|
+
*
|
|
142
|
+
* 2. Self-harming live metrics: MetricsDelta rows are computed from raw
|
|
143
|
+
* analytics baselines with no editorial judgment — a bounce rate of
|
|
144
|
+
* "100 → 99.69" rendered as a green win. Marketing surfaces only show a
|
|
145
|
+
* delta when it's a genuinely flattering, meaningful story.
|
|
146
|
+
*
|
|
147
|
+
* Used by PortfolioPage (hero KPIs + results items), PortfolioCard (KPI
|
|
148
|
+
* preview), and MetricsProvenance (delta gate). Change display policy here,
|
|
149
|
+
* nowhere else.
|
|
150
|
+
*/
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Collapse per-category Lighthouse KPIs to at most one summary tile, business
|
|
154
|
+
* outcomes first. When every category is present at 100 the summary says so;
|
|
155
|
+
* otherwise the Performance category (the one buyers know) represents the set.
|
|
156
|
+
*/
|
|
157
|
+
declare function curateHeroKpis(kpis: PortfolioKPI[]): PortfolioKPI[];
|
|
158
|
+
/**
|
|
159
|
+
* Drop Results cards that restate Lighthouse scores when the case study also
|
|
160
|
+
* renders a Performance section (the score breakdown's single home).
|
|
161
|
+
*/
|
|
162
|
+
declare function curateResultItems(items: PortfolioResultItem[], hasPerformanceSection: boolean): PortfolioResultItem[];
|
|
163
|
+
/**
|
|
164
|
+
* Editorial gate for live metric deltas ("Verified from live analytics").
|
|
165
|
+
* `direction` comes from the platform with 'up' meaning IMPROVED (lower-is-
|
|
166
|
+
* better metrics are inverted server-side). A public case study only shows a
|
|
167
|
+
* delta when it's a win worth telling:
|
|
168
|
+
* - improved ('up'), never a regression or flat noise
|
|
169
|
+
* - moved by a double-digit relative margin (small drift isn't a story)
|
|
170
|
+
* - bounce-rate-style metrics must also be respectable in absolute terms —
|
|
171
|
+
* "100 → 99.69" is technically an improvement and still self-harm
|
|
172
|
+
*/
|
|
173
|
+
declare function gateMetricsDeltas(deltas: MetricsDelta[] | undefined | null): MetricsDelta[];
|
|
174
|
+
/**
|
|
175
|
+
* Apply the full display policy to a portfolio item before rendering.
|
|
176
|
+
* Pure — returns a new item; the fetched payload is never mutated.
|
|
177
|
+
*/
|
|
178
|
+
declare function curatePortfolioProof(item: PortfolioItemFull): PortfolioItemFull;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Presentation formatters shared by portfolio components and consuming apps.
|
|
182
|
+
*/
|
|
183
|
+
/**
|
|
184
|
+
* Human label for a category slug. Single source of truth — HeroSection,
|
|
185
|
+
* PortfolioCard, and app-side filter chips all render categories through
|
|
186
|
+
* this. Underscores become spaces; hyphens are PRESERVED so compound slugs
|
|
187
|
+
* keep their canonical form ("e-commerce" → "E-Commerce", never "E Commerce"),
|
|
188
|
+
* and every word start (including after a hyphen) is capitalized.
|
|
189
|
+
*/
|
|
190
|
+
declare function formatCategoryLabel(slug: string | undefined | null): string;
|
|
191
|
+
/**
|
|
192
|
+
* Normalize a service tag's casing for display: the first character of each
|
|
193
|
+
* word is uppercased, the rest left alone (so "Next.js development" becomes
|
|
194
|
+
* "Next.js Development" and "Technical SEO implementation" keeps "SEO").
|
|
195
|
+
* Fixes per-item casing drift in stored tags without touching the data.
|
|
196
|
+
*/
|
|
197
|
+
declare function formatServiceTag(tag: string | undefined | null): string;
|
|
198
|
+
|
|
122
199
|
/**
|
|
123
200
|
* Loading skeletons for portfolio routes — pure CSS pulse, server-safe,
|
|
124
201
|
* zero JS. Drop into `loading.tsx`:
|
|
@@ -135,4 +212,4 @@ declare function PortfolioIndexSkeleton({ cards }: {
|
|
|
135
212
|
/** Hero-shaped placeholder for /work/[slug] case study pages. */
|
|
136
213
|
declare function PortfolioPageSkeleton(): React.JSX.Element;
|
|
137
214
|
|
|
138
|
-
export { MetricsDelta, MetricsProvenance, PortfolioIndex, type PortfolioIndexProps, PortfolioIndexSkeleton, PortfolioItemFull, PortfolioPage, PortfolioPageSkeleton, PortfolioSchema };
|
|
215
|
+
export { MetricsDelta, MetricsProvenance, PortfolioIndex, type PortfolioIndexProps, PortfolioIndexSkeleton, PortfolioItemFull, PortfolioKPI, PortfolioPage, PortfolioPageSkeleton, PortfolioSchema, curateHeroKpis, curatePortfolioProof, curateResultItems, formatCategoryLabel, formatServiceTag, gateMetricsDeltas };
|
package/dist/portfolio/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export { PORTFOLIO_SECTION_TYPES, PortfolioIndex, PortfolioIndexSkeleton, PortfolioPage, PortfolioPageSkeleton, PortfolioSchema } from '../chunk-
|
|
2
|
-
export {
|
|
1
|
+
export { PORTFOLIO_SECTION_TYPES, PortfolioIndex, PortfolioIndexSkeleton, PortfolioPage, PortfolioPageSkeleton, PortfolioSchema } from '../chunk-NLGUPJZA.js';
|
|
2
|
+
export { formatCategoryLabel, formatServiceTag } from '../chunk-7D4H36UF.js';
|
|
3
|
+
export { MetricsProvenance, curateHeroKpis, curatePortfolioProof, curateResultItems, gateMetricsDeltas } from '../chunk-RWQ675N6.js';
|
|
3
4
|
import '../chunk-KXLROAO5.js';
|
|
4
5
|
import '../chunk-N7TVKUYQ.js';
|
|
5
6
|
import '../chunk-L4EOQVRJ.js';
|
|
@@ -55,7 +55,7 @@ function ChallengesSection({ data }) {
|
|
|
55
55
|
{
|
|
56
56
|
className: "text-lg mb-12 max-w-2xl",
|
|
57
57
|
style: { color: "var(--sk-text-secondary, #a1a1aa)" },
|
|
58
|
-
children: "
|
|
58
|
+
children: "What stood in the way, and how we cleared it."
|
|
59
59
|
}
|
|
60
60
|
)
|
|
61
61
|
] }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/portfolio/components/sections/ChallengesSection.tsx"],"names":["jsx","jsxs","ScrollReveal","GlassCard"],"mappings":"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","file":"ChallengesSection.cjs","sourcesContent":["// Server component — renders on the server; the client primitives below cross the\n// RSC boundary via package subpaths (never import them relatively here).\nimport React from 'react';\nimport type { PortfolioChallengesData } from '../../../types';\nimport ScrollReveal from '@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal';\nimport GlassCard from '@sonordev/agency-site-kit/portfolio/primitives/GlassCard';\n\ninterface ChallengesSectionProps {\n data: PortfolioChallengesData;\n}\n\n/** Icon registry lookup. Returns an inline SVG for known icon keys. */\nfunction ChallengeIcon({ name }: { name?: string }) {\n if (!name) return null;\n\n const icons: Record<string, React.ReactNode> = {\n speed: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M13 2L3 14h9l-1 8 10-12h-9l1-8z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ),\n seo: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"M21 21l-4.35-4.35\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n ),\n design: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ),\n conversion: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M22 12h-4l-3 9L9 3l-3 9H2\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ),\n mobile: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"5\" y=\"2\" width=\"14\" height=\"20\" rx=\"2\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"M12 18h.01\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n ),\n content: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n <path d=\"M14 2v6h6M16 13H8M16 17H8M10 9H8\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ),\n };\n\n return (\n <span style={{ color: 'var(--sk-primary, #6366f1)' }}>\n {icons[name] || icons.speed}\n </span>\n );\n}\n\nexport default function ChallengesSection({ data }: ChallengesSectionProps) {\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-4\"\n style={{\n color: 'var(--sk-text-primary, #ffffff)',\n fontFamily: 'var(--sk-font-heading, inherit)',\n }}\n >\n Challenges & Solutions\n </h2>\n <p\n className=\"text-lg mb-12 max-w-2xl\"\n style={{ color: 'var(--sk-text-secondary, #a1a1aa)' }}\n >\n Every great project starts with obstacles to overcome. Here is how we tackled them.\n </p>\n </ScrollReveal>\n\n <div className=\"flex flex-col gap-8\">\n {data.items.map((item, index) => {\n const isEven = index % 2 === 0;\n return (\n <ScrollReveal key={index} y={40} delay={index * 0.1}>\n <GlassCard padding=\"lg\" hover={false}>\n <div\n className={`flex flex-col lg:flex-row gap-8 ${\n isEven ? '' : 'lg:flex-row-reverse'\n }`}\n >\n {/* Challenge side */}\n <div className=\"flex-1 flex flex-col gap-3\">\n <div className=\"flex items-center gap-3\">\n {/* Number badge */}\n <span\n className=\"flex items-center justify-center w-10 h-10 rounded-full text-sm font-bold shrink-0\"\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 {String(index + 1).padStart(2, '0')}\n </span>\n <ChallengeIcon name={item.icon} />\n <h3\n className=\"text-xl font-semibold\"\n style={{ color: 'var(--sk-text-primary, #ffffff)' }}\n >\n {item.title}\n </h3>\n </div>\n <p\n className=\"text-base leading-relaxed\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {item.description}\n </p>\n </div>\n\n {/* Divider */}\n <div\n className=\"hidden lg:block w-px self-stretch\"\n style={{\n background: 'var(--sk-border, rgba(255,255,255,0.1))',\n }}\n />\n <div\n className=\"lg:hidden h-px w-full\"\n style={{\n background: 'var(--sk-border, rgba(255,255,255,0.1))',\n }}\n />\n\n {/* Solution side */}\n <div className=\"flex-1 flex flex-col gap-3\">\n <div className=\"flex items-center gap-2\">\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{ color: '#10b981' }}\n >\n <path\n d=\"M16.667 5L7.5 14.167 3.333 10\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n <span\n className=\"text-sm font-semibold uppercase tracking-wider\"\n style={{ color: '#10b981' }}\n >\n Solution\n </span>\n </div>\n <p\n className=\"text-base leading-relaxed\"\n style={{ color: 'var(--sk-text-secondary, #a1a1aa)' }}\n >\n {item.solution}\n </p>\n {item.result && (\n <div\n className=\"mt-2 px-4 py-2 rounded-lg text-sm\"\n style={{\n background: 'color-mix(in srgb, var(--sk-primary, #6366f1) 8%, transparent)',\n color: 'var(--sk-primary, #6366f1)',\n border: '1px solid color-mix(in srgb, var(--sk-primary, #6366f1) 15%, transparent)',\n }}\n >\n <span className=\"font-semibold\">Result:</span> {item.result}\n </div>\n )}\n </div>\n </div>\n </GlassCard>\n </ScrollReveal>\n );\n })}\n </div>\n </div>\n </section>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/portfolio/components/sections/ChallengesSection.tsx"],"names":["jsx","jsxs","ScrollReveal","GlassCard"],"mappings":"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","file":"ChallengesSection.cjs","sourcesContent":["// Server component — renders on the server; the client primitives below cross the\n// RSC boundary via package subpaths (never import them relatively here).\nimport React from 'react';\nimport type { PortfolioChallengesData } from '../../../types';\nimport ScrollReveal from '@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal';\nimport GlassCard from '@sonordev/agency-site-kit/portfolio/primitives/GlassCard';\n\ninterface ChallengesSectionProps {\n data: PortfolioChallengesData;\n}\n\n/** Icon registry lookup. Returns an inline SVG for known icon keys. */\nfunction ChallengeIcon({ name }: { name?: string }) {\n if (!name) return null;\n\n const icons: Record<string, React.ReactNode> = {\n speed: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M13 2L3 14h9l-1 8 10-12h-9l1-8z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ),\n seo: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"M21 21l-4.35-4.35\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n ),\n design: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ),\n conversion: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M22 12h-4l-3 9L9 3l-3 9H2\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ),\n mobile: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"5\" y=\"2\" width=\"14\" height=\"20\" rx=\"2\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"M12 18h.01\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n ),\n content: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n <path d=\"M14 2v6h6M16 13H8M16 17H8M10 9H8\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ),\n };\n\n return (\n <span style={{ color: 'var(--sk-primary, #6366f1)' }}>\n {icons[name] || icons.speed}\n </span>\n );\n}\n\nexport default function ChallengesSection({ data }: ChallengesSectionProps) {\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-4\"\n style={{\n color: 'var(--sk-text-primary, #ffffff)',\n fontFamily: 'var(--sk-font-heading, inherit)',\n }}\n >\n Challenges & Solutions\n </h2>\n <p\n className=\"text-lg mb-12 max-w-2xl\"\n style={{ color: 'var(--sk-text-secondary, #a1a1aa)' }}\n >\n What stood in the way, and how we cleared it.\n </p>\n </ScrollReveal>\n\n <div className=\"flex flex-col gap-8\">\n {data.items.map((item, index) => {\n const isEven = index % 2 === 0;\n return (\n <ScrollReveal key={index} y={40} delay={index * 0.1}>\n <GlassCard padding=\"lg\" hover={false}>\n <div\n className={`flex flex-col lg:flex-row gap-8 ${\n isEven ? '' : 'lg:flex-row-reverse'\n }`}\n >\n {/* Challenge side */}\n <div className=\"flex-1 flex flex-col gap-3\">\n <div className=\"flex items-center gap-3\">\n {/* Number badge */}\n <span\n className=\"flex items-center justify-center w-10 h-10 rounded-full text-sm font-bold shrink-0\"\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 {String(index + 1).padStart(2, '0')}\n </span>\n <ChallengeIcon name={item.icon} />\n <h3\n className=\"text-xl font-semibold\"\n style={{ color: 'var(--sk-text-primary, #ffffff)' }}\n >\n {item.title}\n </h3>\n </div>\n <p\n className=\"text-base leading-relaxed\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {item.description}\n </p>\n </div>\n\n {/* Divider */}\n <div\n className=\"hidden lg:block w-px self-stretch\"\n style={{\n background: 'var(--sk-border, rgba(255,255,255,0.1))',\n }}\n />\n <div\n className=\"lg:hidden h-px w-full\"\n style={{\n background: 'var(--sk-border, rgba(255,255,255,0.1))',\n }}\n />\n\n {/* Solution side */}\n <div className=\"flex-1 flex flex-col gap-3\">\n <div className=\"flex items-center gap-2\">\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{ color: '#10b981' }}\n >\n <path\n d=\"M16.667 5L7.5 14.167 3.333 10\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n <span\n className=\"text-sm font-semibold uppercase tracking-wider\"\n style={{ color: '#10b981' }}\n >\n Solution\n </span>\n </div>\n <p\n className=\"text-base leading-relaxed\"\n style={{ color: 'var(--sk-text-secondary, #a1a1aa)' }}\n >\n {item.solution}\n </p>\n {item.result && (\n <div\n className=\"mt-2 px-4 py-2 rounded-lg text-sm\"\n style={{\n background: 'color-mix(in srgb, var(--sk-primary, #6366f1) 8%, transparent)',\n color: 'var(--sk-primary, #6366f1)',\n border: '1px solid color-mix(in srgb, var(--sk-primary, #6366f1) 15%, transparent)',\n }}\n >\n <span className=\"font-semibold\">Result:</span> {item.result}\n </div>\n )}\n </div>\n </div>\n </GlassCard>\n </ScrollReveal>\n );\n })}\n </div>\n </div>\n </section>\n );\n}\n"]}
|
|
@@ -48,7 +48,7 @@ function ChallengesSection({ data }) {
|
|
|
48
48
|
{
|
|
49
49
|
className: "text-lg mb-12 max-w-2xl",
|
|
50
50
|
style: { color: "var(--sk-text-secondary, #a1a1aa)" },
|
|
51
|
-
children: "
|
|
51
|
+
children: "What stood in the way, and how we cleared it."
|
|
52
52
|
}
|
|
53
53
|
)
|
|
54
54
|
] }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/portfolio/components/sections/ChallengesSection.tsx"],"names":[],"mappings":";;;;;AAYA,SAAS,aAAA,CAAc,EAAE,IAAA,EAAK,EAAsB;AAClD,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAElB,EAAA,MAAM,KAAA,GAAyC;AAAA,IAC7C,KAAA,kBACE,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,IAAA,EAAK,QAAO,IAAA,EAAK,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,MAAA,EAAO,KAAA,EAAM,8BAChE,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,iCAAA,EAAkC,MAAA,EAAO,cAAA,EAAe,WAAA,EAAY,GAAA,EAAI,aAAA,EAAc,OAAA,EAAQ,cAAA,EAAe,OAAA,EAAQ,CAAA,EAC/H,CAAA;AAAA,IAEF,GAAA,kBACE,IAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,IAAA,EAAK,MAAA,EAAO,IAAA,EAAK,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,MAAA,EAAO,KAAA,EAAM,4BAAA,EAChE,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,QAAA,EAAA,EAAO,EAAA,EAAG,IAAA,EAAK,EAAA,EAAG,IAAA,EAAK,GAAE,GAAA,EAAI,MAAA,EAAO,cAAA,EAAe,WAAA,EAAY,GAAA,EAAI,CAAA;AAAA,sBACpE,GAAA,CAAC,UAAK,CAAA,EAAE,mBAAA,EAAoB,QAAO,cAAA,EAAe,WAAA,EAAY,GAAA,EAAI,aAAA,EAAc,OAAA,EAAQ;AAAA,KAAA,EAC1F,CAAA;AAAA,IAEF,MAAA,kBACE,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,IAAA,EAAK,QAAO,IAAA,EAAK,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,MAAA,EAAO,KAAA,EAAM,8BAChE,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,yDAAA,EAA0D,MAAA,EAAO,cAAA,EAAe,WAAA,EAAY,GAAA,EAAI,aAAA,EAAc,OAAA,EAAQ,cAAA,EAAe,OAAA,EAAQ,CAAA,EACvJ,CAAA;AAAA,IAEF,UAAA,kBACE,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,IAAA,EAAK,QAAO,IAAA,EAAK,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,MAAA,EAAO,KAAA,EAAM,8BAChE,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,2BAAA,EAA4B,MAAA,EAAO,cAAA,EAAe,WAAA,EAAY,GAAA,EAAI,aAAA,EAAc,OAAA,EAAQ,cAAA,EAAe,OAAA,EAAQ,CAAA,EACzH,CAAA;AAAA,IAEF,MAAA,kBACE,IAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,IAAA,EAAK,MAAA,EAAO,IAAA,EAAK,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,MAAA,EAAO,KAAA,EAAM,4BAAA,EAChE,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,GAAA,EAAI,CAAA,EAAE,KAAI,KAAA,EAAM,IAAA,EAAK,MAAA,EAAO,IAAA,EAAK,EAAA,EAAG,GAAA,EAAI,MAAA,EAAO,cAAA,EAAe,aAAY,GAAA,EAAI,CAAA;AAAA,sBACtF,GAAA,CAAC,UAAK,CAAA,EAAE,YAAA,EAAa,QAAO,cAAA,EAAe,WAAA,EAAY,GAAA,EAAI,aAAA,EAAc,OAAA,EAAQ;AAAA,KAAA,EACnF,CAAA;AAAA,IAEF,OAAA,kBACE,IAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,IAAA,EAAK,MAAA,EAAO,IAAA,EAAK,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,MAAA,EAAO,KAAA,EAAM,4BAAA,EAChE,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,uDAAA,EAAwD,MAAA,EAAO,cAAA,EAAe,aAAY,GAAA,EAAI,aAAA,EAAc,OAAA,EAAQ,cAAA,EAAe,OAAA,EAAQ,CAAA;AAAA,sBACnJ,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,kCAAA,EAAmC,MAAA,EAAO,cAAA,EAAe,WAAA,EAAY,GAAA,EAAI,aAAA,EAAc,OAAA,EAAQ,cAAA,EAAe,OAAA,EAAQ;AAAA,KAAA,EAChI;AAAA,GAEJ;AAEA,EAAA,uBACE,GAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAO,EAAE,KAAA,EAAO,4BAAA,EAA6B,EAChD,QAAA,EAAA,KAAA,CAAM,IAAI,CAAA,IAAK,KAAA,CAAM,KAAA,EACxB,CAAA;AAEJ;AAEe,SAAR,iBAAA,CAAmC,EAAE,IAAA,EAAK,EAA2B;AAC1E,EAAA,uBACE,GAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAU,uBAAA;AAAA,MACV,KAAA,EAAO,EAAE,UAAA,EAAY,uBAAA,EAAwB;AAAA,MAE7C,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,wBAAA,EACb,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,YAAA,EAAA,EAAa,GAAG,EAAA,EACf,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,IAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAU,qCAAA;AAAA,cACV,KAAA,EAAO;AAAA,gBACL,KAAA,EAAO,iCAAA;AAAA,gBACP,UAAA,EAAY;AAAA,eACd;AAAA,cACD,QAAA,EAAA;AAAA;AAAA,WAED;AAAA,0BACA,GAAA;AAAA,YAAC,GAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAU,yBAAA;AAAA,cACV,KAAA,EAAO,EAAE,KAAA,EAAO,mCAAA,EAAoC;AAAA,cACrD,QAAA,EAAA;AAAA;AAAA;AAED,SAAA,EACF,CAAA;AAAA,wBAEA,GAAA,CAAC,SAAI,SAAA,EAAU,qBAAA,EACZ,eAAK,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,EAAM,KAAA,KAAU;AAC/B,UAAA,MAAM,MAAA,GAAS,QAAQ,CAAA,KAAM,CAAA;AAC7B,UAAA,uBACE,GAAA,CAAC,YAAA,EAAA,EAAyB,CAAA,EAAG,EAAA,EAAI,KAAA,EAAO,KAAA,GAAQ,GAAA,EAC9C,QAAA,kBAAA,GAAA,CAAC,SAAA,EAAA,EAAU,OAAA,EAAQ,IAAA,EAAK,KAAA,EAAO,KAAA,EAC7B,QAAA,kBAAA,IAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAW,CAAA,gCAAA,EACT,MAAA,GAAS,EAAA,GAAK,qBAChB,CAAA,CAAA;AAAA,cAGA,QAAA,EAAA;AAAA,gCAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,4BAAA,EACb,QAAA,EAAA;AAAA,kCAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,yBAAA,EAEb,QAAA,EAAA;AAAA,oCAAA,GAAA;AAAA,sBAAC,MAAA;AAAA,sBAAA;AAAA,wBACC,SAAA,EAAU,oFAAA;AAAA,wBACV,KAAA,EAAO;AAAA,0BACL,UAAA,EAAY,iEAAA;AAAA,0BACZ,KAAA,EAAO,4BAAA;AAAA,0BACP,MAAA,EAAQ;AAAA,yBACV;AAAA,wBAEC,iBAAO,KAAA,GAAQ,CAAC,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG;AAAA;AAAA,qBACpC;AAAA,oCACA,GAAA,CAAC,aAAA,EAAA,EAAc,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,CAAA;AAAA,oCAChC,GAAA;AAAA,sBAAC,IAAA;AAAA,sBAAA;AAAA,wBACC,SAAA,EAAU,uBAAA;AAAA,wBACV,KAAA,EAAO,EAAE,KAAA,EAAO,iCAAA,EAAkC;AAAA,wBAEjD,QAAA,EAAA,IAAA,CAAK;AAAA;AAAA;AACR,mBAAA,EACF,CAAA;AAAA,kCACA,GAAA;AAAA,oBAAC,GAAA;AAAA,oBAAA;AAAA,sBACC,SAAA,EAAU,2BAAA;AAAA,sBACV,KAAA,EAAO,EAAE,KAAA,EAAO,kCAAA,EAAmC;AAAA,sBAElD,QAAA,EAAA,IAAA,CAAK;AAAA;AAAA;AACR,iBAAA,EACF,CAAA;AAAA,gCAGA,GAAA;AAAA,kBAAC,KAAA;AAAA,kBAAA;AAAA,oBACC,SAAA,EAAU,mCAAA;AAAA,oBACV,KAAA,EAAO;AAAA,sBACL,UAAA,EAAY;AAAA;AACd;AAAA,iBACF;AAAA,gCACA,GAAA;AAAA,kBAAC,KAAA;AAAA,kBAAA;AAAA,oBACC,SAAA,EAAU,uBAAA;AAAA,oBACV,KAAA,EAAO;AAAA,sBACL,UAAA,EAAY;AAAA;AACd;AAAA,iBACF;AAAA,gCAGA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,4BAAA,EACb,QAAA,EAAA;AAAA,kCAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,yBAAA,EACb,QAAA,EAAA;AAAA,oCAAA,GAAA;AAAA,sBAAC,KAAA;AAAA,sBAAA;AAAA,wBACC,KAAA,EAAM,IAAA;AAAA,wBACN,MAAA,EAAO,IAAA;AAAA,wBACP,OAAA,EAAQ,WAAA;AAAA,wBACR,IAAA,EAAK,MAAA;AAAA,wBACL,KAAA,EAAM,4BAAA;AAAA,wBACN,KAAA,EAAO,EAAE,KAAA,EAAO,SAAA,EAAU;AAAA,wBAE1B,QAAA,kBAAA,GAAA;AAAA,0BAAC,MAAA;AAAA,0BAAA;AAAA,4BACC,CAAA,EAAE,+BAAA;AAAA,4BACF,MAAA,EAAO,cAAA;AAAA,4BACP,WAAA,EAAY,GAAA;AAAA,4BACZ,aAAA,EAAc,OAAA;AAAA,4BACd,cAAA,EAAe;AAAA;AAAA;AACjB;AAAA,qBACF;AAAA,oCACA,GAAA;AAAA,sBAAC,MAAA;AAAA,sBAAA;AAAA,wBACC,SAAA,EAAU,gDAAA;AAAA,wBACV,KAAA,EAAO,EAAE,KAAA,EAAO,SAAA,EAAU;AAAA,wBAC3B,QAAA,EAAA;AAAA;AAAA;AAED,mBAAA,EACF,CAAA;AAAA,kCACA,GAAA;AAAA,oBAAC,GAAA;AAAA,oBAAA;AAAA,sBACC,SAAA,EAAU,2BAAA;AAAA,sBACV,KAAA,EAAO,EAAE,KAAA,EAAO,mCAAA,EAAoC;AAAA,sBAEnD,QAAA,EAAA,IAAA,CAAK;AAAA;AAAA,mBACR;AAAA,kBACC,KAAK,MAAA,oBACJ,IAAA;AAAA,oBAAC,KAAA;AAAA,oBAAA;AAAA,sBACC,SAAA,EAAU,mCAAA;AAAA,sBACV,KAAA,EAAO;AAAA,wBACL,UAAA,EAAY,gEAAA;AAAA,wBACZ,KAAA,EAAO,4BAAA;AAAA,wBACP,MAAA,EAAQ;AAAA,uBACV;AAAA,sBAEA,QAAA,EAAA;AAAA,wCAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,eAAA,EAAgB,QAAA,EAAA,SAAA,EAAO,CAAA;AAAA,wBAAO,GAAA;AAAA,wBAAE,IAAA,CAAK;AAAA;AAAA;AAAA;AACvD,iBAAA,EAEJ;AAAA;AAAA;AAAA,WACF,EACF,KAjGiB,KAkGnB,CAAA;AAAA,QAEJ,CAAC,CAAA,EACH;AAAA,OAAA,EACF;AAAA;AAAA,GACF;AAEJ","file":"ChallengesSection.js","sourcesContent":["// Server component — renders on the server; the client primitives below cross the\n// RSC boundary via package subpaths (never import them relatively here).\nimport React from 'react';\nimport type { PortfolioChallengesData } from '../../../types';\nimport ScrollReveal from '@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal';\nimport GlassCard from '@sonordev/agency-site-kit/portfolio/primitives/GlassCard';\n\ninterface ChallengesSectionProps {\n data: PortfolioChallengesData;\n}\n\n/** Icon registry lookup. Returns an inline SVG for known icon keys. */\nfunction ChallengeIcon({ name }: { name?: string }) {\n if (!name) return null;\n\n const icons: Record<string, React.ReactNode> = {\n speed: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M13 2L3 14h9l-1 8 10-12h-9l1-8z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ),\n seo: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"M21 21l-4.35-4.35\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n ),\n design: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ),\n conversion: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M22 12h-4l-3 9L9 3l-3 9H2\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ),\n mobile: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"5\" y=\"2\" width=\"14\" height=\"20\" rx=\"2\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"M12 18h.01\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n ),\n content: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n <path d=\"M14 2v6h6M16 13H8M16 17H8M10 9H8\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ),\n };\n\n return (\n <span style={{ color: 'var(--sk-primary, #6366f1)' }}>\n {icons[name] || icons.speed}\n </span>\n );\n}\n\nexport default function ChallengesSection({ data }: ChallengesSectionProps) {\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-4\"\n style={{\n color: 'var(--sk-text-primary, #ffffff)',\n fontFamily: 'var(--sk-font-heading, inherit)',\n }}\n >\n Challenges & Solutions\n </h2>\n <p\n className=\"text-lg mb-12 max-w-2xl\"\n style={{ color: 'var(--sk-text-secondary, #a1a1aa)' }}\n >\n Every great project starts with obstacles to overcome. Here is how we tackled them.\n </p>\n </ScrollReveal>\n\n <div className=\"flex flex-col gap-8\">\n {data.items.map((item, index) => {\n const isEven = index % 2 === 0;\n return (\n <ScrollReveal key={index} y={40} delay={index * 0.1}>\n <GlassCard padding=\"lg\" hover={false}>\n <div\n className={`flex flex-col lg:flex-row gap-8 ${\n isEven ? '' : 'lg:flex-row-reverse'\n }`}\n >\n {/* Challenge side */}\n <div className=\"flex-1 flex flex-col gap-3\">\n <div className=\"flex items-center gap-3\">\n {/* Number badge */}\n <span\n className=\"flex items-center justify-center w-10 h-10 rounded-full text-sm font-bold shrink-0\"\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 {String(index + 1).padStart(2, '0')}\n </span>\n <ChallengeIcon name={item.icon} />\n <h3\n className=\"text-xl font-semibold\"\n style={{ color: 'var(--sk-text-primary, #ffffff)' }}\n >\n {item.title}\n </h3>\n </div>\n <p\n className=\"text-base leading-relaxed\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {item.description}\n </p>\n </div>\n\n {/* Divider */}\n <div\n className=\"hidden lg:block w-px self-stretch\"\n style={{\n background: 'var(--sk-border, rgba(255,255,255,0.1))',\n }}\n />\n <div\n className=\"lg:hidden h-px w-full\"\n style={{\n background: 'var(--sk-border, rgba(255,255,255,0.1))',\n }}\n />\n\n {/* Solution side */}\n <div className=\"flex-1 flex flex-col gap-3\">\n <div className=\"flex items-center gap-2\">\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{ color: '#10b981' }}\n >\n <path\n d=\"M16.667 5L7.5 14.167 3.333 10\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n <span\n className=\"text-sm font-semibold uppercase tracking-wider\"\n style={{ color: '#10b981' }}\n >\n Solution\n </span>\n </div>\n <p\n className=\"text-base leading-relaxed\"\n style={{ color: 'var(--sk-text-secondary, #a1a1aa)' }}\n >\n {item.solution}\n </p>\n {item.result && (\n <div\n className=\"mt-2 px-4 py-2 rounded-lg text-sm\"\n style={{\n background: 'color-mix(in srgb, var(--sk-primary, #6366f1) 8%, transparent)',\n color: 'var(--sk-primary, #6366f1)',\n border: '1px solid color-mix(in srgb, var(--sk-primary, #6366f1) 15%, transparent)',\n }}\n >\n <span className=\"font-semibold\">Result:</span> {item.result}\n </div>\n )}\n </div>\n </div>\n </GlassCard>\n </ScrollReveal>\n );\n })}\n </div>\n </div>\n </section>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/portfolio/components/sections/ChallengesSection.tsx"],"names":[],"mappings":"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","file":"ChallengesSection.js","sourcesContent":["// Server component — renders on the server; the client primitives below cross the\n// RSC boundary via package subpaths (never import them relatively here).\nimport React from 'react';\nimport type { PortfolioChallengesData } from '../../../types';\nimport ScrollReveal from '@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal';\nimport GlassCard from '@sonordev/agency-site-kit/portfolio/primitives/GlassCard';\n\ninterface ChallengesSectionProps {\n data: PortfolioChallengesData;\n}\n\n/** Icon registry lookup. Returns an inline SVG for known icon keys. */\nfunction ChallengeIcon({ name }: { name?: string }) {\n if (!name) return null;\n\n const icons: Record<string, React.ReactNode> = {\n speed: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M13 2L3 14h9l-1 8 10-12h-9l1-8z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ),\n seo: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <circle cx=\"11\" cy=\"11\" r=\"8\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"M21 21l-4.35-4.35\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n ),\n design: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ),\n conversion: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M22 12h-4l-3 9L9 3l-3 9H2\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ),\n mobile: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <rect x=\"5\" y=\"2\" width=\"14\" height=\"20\" rx=\"2\" stroke=\"currentColor\" strokeWidth=\"2\" />\n <path d=\"M12 18h.01\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n ),\n content: (\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n <path d=\"M14 2v6h6M16 13H8M16 17H8M10 9H8\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ),\n };\n\n return (\n <span style={{ color: 'var(--sk-primary, #6366f1)' }}>\n {icons[name] || icons.speed}\n </span>\n );\n}\n\nexport default function ChallengesSection({ data }: ChallengesSectionProps) {\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-4\"\n style={{\n color: 'var(--sk-text-primary, #ffffff)',\n fontFamily: 'var(--sk-font-heading, inherit)',\n }}\n >\n Challenges & Solutions\n </h2>\n <p\n className=\"text-lg mb-12 max-w-2xl\"\n style={{ color: 'var(--sk-text-secondary, #a1a1aa)' }}\n >\n What stood in the way, and how we cleared it.\n </p>\n </ScrollReveal>\n\n <div className=\"flex flex-col gap-8\">\n {data.items.map((item, index) => {\n const isEven = index % 2 === 0;\n return (\n <ScrollReveal key={index} y={40} delay={index * 0.1}>\n <GlassCard padding=\"lg\" hover={false}>\n <div\n className={`flex flex-col lg:flex-row gap-8 ${\n isEven ? '' : 'lg:flex-row-reverse'\n }`}\n >\n {/* Challenge side */}\n <div className=\"flex-1 flex flex-col gap-3\">\n <div className=\"flex items-center gap-3\">\n {/* Number badge */}\n <span\n className=\"flex items-center justify-center w-10 h-10 rounded-full text-sm font-bold shrink-0\"\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 {String(index + 1).padStart(2, '0')}\n </span>\n <ChallengeIcon name={item.icon} />\n <h3\n className=\"text-xl font-semibold\"\n style={{ color: 'var(--sk-text-primary, #ffffff)' }}\n >\n {item.title}\n </h3>\n </div>\n <p\n className=\"text-base leading-relaxed\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {item.description}\n </p>\n </div>\n\n {/* Divider */}\n <div\n className=\"hidden lg:block w-px self-stretch\"\n style={{\n background: 'var(--sk-border, rgba(255,255,255,0.1))',\n }}\n />\n <div\n className=\"lg:hidden h-px w-full\"\n style={{\n background: 'var(--sk-border, rgba(255,255,255,0.1))',\n }}\n />\n\n {/* Solution side */}\n <div className=\"flex-1 flex flex-col gap-3\">\n <div className=\"flex items-center gap-2\">\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{ color: '#10b981' }}\n >\n <path\n d=\"M16.667 5L7.5 14.167 3.333 10\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n <span\n className=\"text-sm font-semibold uppercase tracking-wider\"\n style={{ color: '#10b981' }}\n >\n Solution\n </span>\n </div>\n <p\n className=\"text-base leading-relaxed\"\n style={{ color: 'var(--sk-text-secondary, #a1a1aa)' }}\n >\n {item.solution}\n </p>\n {item.result && (\n <div\n className=\"mt-2 px-4 py-2 rounded-lg text-sm\"\n style={{\n background: 'color-mix(in srgb, var(--sk-primary, #6366f1) 8%, transparent)',\n color: 'var(--sk-primary, #6366f1)',\n border: '1px solid color-mix(in srgb, var(--sk-primary, #6366f1) 15%, transparent)',\n }}\n >\n <span className=\"font-semibold\">Result:</span> {item.result}\n </div>\n )}\n </div>\n </div>\n </GlassCard>\n </ScrollReveal>\n );\n })}\n </div>\n </div>\n </section>\n );\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var chunkZBPF7TLZ_cjs = require('../../chunk-ZBPF7TLZ.cjs');
|
|
3
4
|
var ScrollReveal = require('@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal');
|
|
4
5
|
var AnimatedCounter = require('@sonordev/agency-site-kit/portfolio/primitives/AnimatedCounter');
|
|
5
6
|
var GlassCard = require('@sonordev/agency-site-kit/portfolio/primitives/GlassCard');
|
|
@@ -13,7 +14,6 @@ var AnimatedCounter__default = /*#__PURE__*/_interopDefault(AnimatedCounter);
|
|
|
13
14
|
var GlassCard__default = /*#__PURE__*/_interopDefault(GlassCard);
|
|
14
15
|
var DeviceTrifolio__default = /*#__PURE__*/_interopDefault(DeviceTrifolio);
|
|
15
16
|
|
|
16
|
-
// src/portfolio/components/sections/HeroSection.tsx
|
|
17
17
|
var HERO_PARALLAX_CSS = `
|
|
18
18
|
@supports (animation-timeline: view()) {
|
|
19
19
|
@media (prefers-reduced-motion: no-preference) {
|
|
@@ -66,7 +66,7 @@ function HeroSection({ data, screenshots, liveUrl }) {
|
|
|
66
66
|
color: "var(--sk-primary, #6366f1)",
|
|
67
67
|
border: "1px solid color-mix(in srgb, var(--sk-primary, #6366f1) 25%, transparent)"
|
|
68
68
|
},
|
|
69
|
-
children: data.category
|
|
69
|
+
children: chunkZBPF7TLZ_cjs.formatCategoryLabel(data.category)
|
|
70
70
|
}
|
|
71
71
|
),
|
|
72
72
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -107,7 +107,7 @@ function HeroSection({ data, screenshots, liveUrl }) {
|
|
|
107
107
|
color: "var(--sk-text-secondary, #a1a1aa)",
|
|
108
108
|
border: "1px solid var(--sk-border, rgba(255,255,255,0.1))"
|
|
109
109
|
},
|
|
110
|
-
children: service
|
|
110
|
+
children: chunkZBPF7TLZ_cjs.formatServiceTag(service)
|
|
111
111
|
},
|
|
112
112
|
service
|
|
113
113
|
)) }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/portfolio/components/sections/HeroSection.tsx"],"names":["jsxs","jsx","DeviceTrifolio","ScrollReveal","GlassCard","AnimatedCounter"],"mappings":"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","file":"HeroSection.cjs","sourcesContent":["// Server component — the entire hero renders on the server and ships zero\n// component JS. Client primitives (counter, reveal, trifolio) cross the RSC\n// boundary via package subpaths.\nimport React from 'react';\nimport type { PortfolioHeroData } from '../../../types';\nimport ScrollReveal from '@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal';\nimport AnimatedCounter from '@sonordev/agency-site-kit/portfolio/primitives/AnimatedCounter';\nimport GlassCard from '@sonordev/agency-site-kit/portfolio/primitives/GlassCard';\nimport DeviceTrifolio from '@sonordev/agency-site-kit/portfolio/primitives/DeviceTrifolio';\n\n// LCP rule (monorepo CLAUDE.md, Performance): above-the-fold content renders\n// fully static — no entrance animation, no post-hydration re-hide. The text\n// column below must never be wrapped in ScrollReveal/SplitHeadline: hiding\n// the H1 after hydration moves LCP to the tween's end and tanks the mobile\n// Lighthouse score. Reveal animations are for the below-fold KPI cards only.\n\n// Background parallax as a CSS scroll-driven animation — progressive\n// enhancement: browsers without animation-timeline get a static gradient.\nconst HERO_PARALLAX_CSS = `\n@supports (animation-timeline: view()) {\n @media (prefers-reduced-motion: no-preference) {\n .sk-hero-bg {\n animation: sk-hero-drift linear both;\n animation-timeline: view(block);\n animation-range: exit 0% exit 100%;\n }\n @keyframes sk-hero-drift {\n from { transform: translateY(0); }\n to { transform: translateY(30%); }\n }\n }\n}\n`;\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 shots = screenshots || data.screenshots;\n const url = liveUrl || data.liveUrl;\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 (CSS scroll-driven) */}\n <style href=\"sk-hero-parallax\" precedence=\"default\">\n {HERO_PARALLAX_CSS}\n </style>\n <div\n className=\"sk-hero-bg 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 min-w-0 px-4 sm:px-6 py-24 lg:py-32\">\n <div className=\"grid grid-cols-1 min-w-0 lg:grid-cols-2 gap-12 lg:gap-16 items-start\">\n {/* Text column — min-w-0 so grid track can shrink below content intrinsic width (mobile) */}\n <div className=\"flex min-w-0 max-w-full flex-col gap-6\">\n {/* Category badge */}\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?.replace(/[-_]/g, ' ').replace(/\\b\\w/g, (c: string) => c.toUpperCase())}\n </span>\n\n {/* Headline — static, this is usually the LCP element */}\n <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 overflowWrap: 'break-word',\n wordBreak: 'break-word',\n }}\n >\n {data.headline}\n </h1>\n\n {/* Subheadline */}\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\n {/* Description */}\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\n {/* Services tags */}\n {data.services.length > 0 && (\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 )}\n\n {/* CTA button */}\n {url && (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n data-portfolio-action=\"live-site\"\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 )}\n\n </div>\n\n {/* Right column — trifolio + KPIs */}\n <div className=\"flex min-w-0 max-w-full flex-col gap-10 lg:pt-8\">\n {/* Device trifolio — realistic device frames */}\n {(url || shots?.desktop || shots?.tablet || shots?.mobile) && (\n <div className=\"min-w-0 max-w-full\">\n <DeviceTrifolio\n screenshots={{\n desktop: shots?.desktop,\n tablet: shots?.tablet,\n mobile: shots?.mobile,\n }}\n url={url}\n />\n </div>\n )}\n\n {/* KPI cards — below trifolio in right column */}\n {data.kpis.length > 0 && (\n <ScrollReveal y={30} delay={0.6} stagger={0.1}>\n <div className=\"grid grid-cols-2 gap-3\">\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 </GlassCard>\n ))}\n </div>\n </ScrollReveal>\n )}\n </div>\n </div>\n </div>\n </section>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/portfolio/components/sections/HeroSection.tsx"],"names":["jsxs","jsx","formatCategoryLabel","DeviceTrifolio","ScrollReveal","GlassCard","AnimatedCounter"],"mappings":"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","file":"HeroSection.cjs","sourcesContent":["// Server component — the entire hero renders on the server and ships zero\n// component JS. Client primitives (counter, reveal, trifolio) cross the RSC\n// boundary via package subpaths.\nimport React from 'react';\nimport type { PortfolioHeroData } from '../../../types';\nimport { formatCategoryLabel, formatServiceTag } from '../../format';\nimport ScrollReveal from '@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal';\nimport AnimatedCounter from '@sonordev/agency-site-kit/portfolio/primitives/AnimatedCounter';\nimport GlassCard from '@sonordev/agency-site-kit/portfolio/primitives/GlassCard';\nimport DeviceTrifolio from '@sonordev/agency-site-kit/portfolio/primitives/DeviceTrifolio';\n\n// LCP rule (monorepo CLAUDE.md, Performance): above-the-fold content renders\n// fully static — no entrance animation, no post-hydration re-hide. The text\n// column below must never be wrapped in ScrollReveal/SplitHeadline: hiding\n// the H1 after hydration moves LCP to the tween's end and tanks the mobile\n// Lighthouse score. Reveal animations are for the below-fold KPI cards only.\n\n// Background parallax as a CSS scroll-driven animation — progressive\n// enhancement: browsers without animation-timeline get a static gradient.\nconst HERO_PARALLAX_CSS = `\n@supports (animation-timeline: view()) {\n @media (prefers-reduced-motion: no-preference) {\n .sk-hero-bg {\n animation: sk-hero-drift linear both;\n animation-timeline: view(block);\n animation-range: exit 0% exit 100%;\n }\n @keyframes sk-hero-drift {\n from { transform: translateY(0); }\n to { transform: translateY(30%); }\n }\n }\n}\n`;\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 shots = screenshots || data.screenshots;\n const url = liveUrl || data.liveUrl;\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 (CSS scroll-driven) */}\n <style href=\"sk-hero-parallax\" precedence=\"default\">\n {HERO_PARALLAX_CSS}\n </style>\n <div\n className=\"sk-hero-bg 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 min-w-0 px-4 sm:px-6 py-24 lg:py-32\">\n <div className=\"grid grid-cols-1 min-w-0 lg:grid-cols-2 gap-12 lg:gap-16 items-start\">\n {/* Text column — min-w-0 so grid track can shrink below content intrinsic width (mobile) */}\n <div className=\"flex min-w-0 max-w-full flex-col gap-6\">\n {/* Category badge */}\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 {formatCategoryLabel(data.category)}\n </span>\n\n {/* Headline — static, this is usually the LCP element */}\n <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 overflowWrap: 'break-word',\n wordBreak: 'break-word',\n }}\n >\n {data.headline}\n </h1>\n\n {/* Subheadline */}\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\n {/* Description */}\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\n {/* Services tags */}\n {data.services.length > 0 && (\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 {formatServiceTag(service)}\n </span>\n ))}\n </div>\n )}\n\n {/* CTA button */}\n {url && (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n data-portfolio-action=\"live-site\"\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 )}\n\n </div>\n\n {/* Right column — trifolio + KPIs */}\n <div className=\"flex min-w-0 max-w-full flex-col gap-10 lg:pt-8\">\n {/* Device trifolio — realistic device frames */}\n {(url || shots?.desktop || shots?.tablet || shots?.mobile) && (\n <div className=\"min-w-0 max-w-full\">\n <DeviceTrifolio\n screenshots={{\n desktop: shots?.desktop,\n tablet: shots?.tablet,\n mobile: shots?.mobile,\n }}\n url={url}\n />\n </div>\n )}\n\n {/* KPI cards — below trifolio in right column */}\n {data.kpis.length > 0 && (\n <ScrollReveal y={30} delay={0.6} stagger={0.1}>\n <div className=\"grid grid-cols-2 gap-3\">\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 </GlassCard>\n ))}\n </div>\n </ScrollReveal>\n )}\n </div>\n </div>\n </div>\n </section>\n );\n}\n"]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import { formatCategoryLabel, formatServiceTag } from '../../chunk-7D4H36UF.js';
|
|
1
2
|
import ScrollReveal from '@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal';
|
|
2
3
|
import AnimatedCounter from '@sonordev/agency-site-kit/portfolio/primitives/AnimatedCounter';
|
|
3
4
|
import GlassCard from '@sonordev/agency-site-kit/portfolio/primitives/GlassCard';
|
|
4
5
|
import DeviceTrifolio from '@sonordev/agency-site-kit/portfolio/primitives/DeviceTrifolio';
|
|
5
6
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
7
|
|
|
7
|
-
// src/portfolio/components/sections/HeroSection.tsx
|
|
8
8
|
var HERO_PARALLAX_CSS = `
|
|
9
9
|
@supports (animation-timeline: view()) {
|
|
10
10
|
@media (prefers-reduced-motion: no-preference) {
|
|
@@ -57,7 +57,7 @@ function HeroSection({ data, screenshots, liveUrl }) {
|
|
|
57
57
|
color: "var(--sk-primary, #6366f1)",
|
|
58
58
|
border: "1px solid color-mix(in srgb, var(--sk-primary, #6366f1) 25%, transparent)"
|
|
59
59
|
},
|
|
60
|
-
children: data.category
|
|
60
|
+
children: formatCategoryLabel(data.category)
|
|
61
61
|
}
|
|
62
62
|
),
|
|
63
63
|
/* @__PURE__ */ jsx(
|
|
@@ -98,7 +98,7 @@ function HeroSection({ data, screenshots, liveUrl }) {
|
|
|
98
98
|
color: "var(--sk-text-secondary, #a1a1aa)",
|
|
99
99
|
border: "1px solid var(--sk-border, rgba(255,255,255,0.1))"
|
|
100
100
|
},
|
|
101
|
-
children: service
|
|
101
|
+
children: formatServiceTag(service)
|
|
102
102
|
},
|
|
103
103
|
service
|
|
104
104
|
)) }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/portfolio/components/sections/HeroSection.tsx"],"names":[],"mappings":"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","file":"HeroSection.js","sourcesContent":["// Server component — the entire hero renders on the server and ships zero\n// component JS. Client primitives (counter, reveal, trifolio) cross the RSC\n// boundary via package subpaths.\nimport React from 'react';\nimport type { PortfolioHeroData } from '../../../types';\nimport ScrollReveal from '@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal';\nimport AnimatedCounter from '@sonordev/agency-site-kit/portfolio/primitives/AnimatedCounter';\nimport GlassCard from '@sonordev/agency-site-kit/portfolio/primitives/GlassCard';\nimport DeviceTrifolio from '@sonordev/agency-site-kit/portfolio/primitives/DeviceTrifolio';\n\n// LCP rule (monorepo CLAUDE.md, Performance): above-the-fold content renders\n// fully static — no entrance animation, no post-hydration re-hide. The text\n// column below must never be wrapped in ScrollReveal/SplitHeadline: hiding\n// the H1 after hydration moves LCP to the tween's end and tanks the mobile\n// Lighthouse score. Reveal animations are for the below-fold KPI cards only.\n\n// Background parallax as a CSS scroll-driven animation — progressive\n// enhancement: browsers without animation-timeline get a static gradient.\nconst HERO_PARALLAX_CSS = `\n@supports (animation-timeline: view()) {\n @media (prefers-reduced-motion: no-preference) {\n .sk-hero-bg {\n animation: sk-hero-drift linear both;\n animation-timeline: view(block);\n animation-range: exit 0% exit 100%;\n }\n @keyframes sk-hero-drift {\n from { transform: translateY(0); }\n to { transform: translateY(30%); }\n }\n }\n}\n`;\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 shots = screenshots || data.screenshots;\n const url = liveUrl || data.liveUrl;\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 (CSS scroll-driven) */}\n <style href=\"sk-hero-parallax\" precedence=\"default\">\n {HERO_PARALLAX_CSS}\n </style>\n <div\n className=\"sk-hero-bg 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 min-w-0 px-4 sm:px-6 py-24 lg:py-32\">\n <div className=\"grid grid-cols-1 min-w-0 lg:grid-cols-2 gap-12 lg:gap-16 items-start\">\n {/* Text column — min-w-0 so grid track can shrink below content intrinsic width (mobile) */}\n <div className=\"flex min-w-0 max-w-full flex-col gap-6\">\n {/* Category badge */}\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?.replace(/[-_]/g, ' ').replace(/\\b\\w/g, (c: string) => c.toUpperCase())}\n </span>\n\n {/* Headline — static, this is usually the LCP element */}\n <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 overflowWrap: 'break-word',\n wordBreak: 'break-word',\n }}\n >\n {data.headline}\n </h1>\n\n {/* Subheadline */}\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\n {/* Description */}\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\n {/* Services tags */}\n {data.services.length > 0 && (\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 )}\n\n {/* CTA button */}\n {url && (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n data-portfolio-action=\"live-site\"\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 )}\n\n </div>\n\n {/* Right column — trifolio + KPIs */}\n <div className=\"flex min-w-0 max-w-full flex-col gap-10 lg:pt-8\">\n {/* Device trifolio — realistic device frames */}\n {(url || shots?.desktop || shots?.tablet || shots?.mobile) && (\n <div className=\"min-w-0 max-w-full\">\n <DeviceTrifolio\n screenshots={{\n desktop: shots?.desktop,\n tablet: shots?.tablet,\n mobile: shots?.mobile,\n }}\n url={url}\n />\n </div>\n )}\n\n {/* KPI cards — below trifolio in right column */}\n {data.kpis.length > 0 && (\n <ScrollReveal y={30} delay={0.6} stagger={0.1}>\n <div className=\"grid grid-cols-2 gap-3\">\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 </GlassCard>\n ))}\n </div>\n </ScrollReveal>\n )}\n </div>\n </div>\n </div>\n </section>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/portfolio/components/sections/HeroSection.tsx"],"names":[],"mappings":";;;;;;;AAmBA,IAAM,iBAAA,GAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAsBX,SAAR,WAAA,CAA6B,EAAE,IAAA,EAAM,WAAA,EAAa,SAAQ,EAAqB;AACpF,EAAA,MAAM,KAAA,GAAQ,eAAe,IAAA,CAAK,WAAA;AAClC,EAAA,MAAM,GAAA,GAAM,WAAW,IAAA,CAAK,OAAA;AAE5B,EAAA,uBACE,IAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAU,iCAAA;AAAA,MACV,KAAA,EAAO;AAAA,QACL,SAAA,EAAW,MAAA;AAAA,QACX,OAAA,EAAS,MAAA;AAAA,QACT,aAAA,EAAe,QAAA;AAAA,QACf,cAAA,EAAgB,QAAA;AAAA,QAChB,UAAA,EAAY;AAAA,OACd;AAAA,MAGA,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,OAAA,EAAA,EAAM,IAAA,EAAK,kBAAA,EAAmB,UAAA,EAAW,WACvC,QAAA,EAAA,iBAAA,EACH,CAAA;AAAA,wBACA,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,iDAAA;AAAA,YACV,KAAA,EAAO;AAAA,cACL,UAAA,EAAY,CAAA,wHAAA,CAAA;AAAA,cACZ,UAAA,EAAY;AAAA;AACd;AAAA,SACF;AAAA,4BAEC,KAAA,EAAA,EAAI,SAAA,EAAU,8EACb,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,sEAAA,EAEb,QAAA,EAAA;AAAA,0BAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,wCAAA,EAEb,QAAA,EAAA;AAAA,4BAAA,GAAA;AAAA,cAAC,MAAA;AAAA,cAAA;AAAA,gBACC,SAAA,EAAU,kFAAA;AAAA,gBACV,KAAA,EAAO;AAAA,kBACL,UAAA,EAAY,iEAAA;AAAA,kBACZ,KAAA,EAAO,4BAAA;AAAA,kBACP,MAAA,EAAQ;AAAA,iBACV;AAAA,gBAEC,QAAA,EAAA,mBAAA,CAAoB,KAAK,QAAQ;AAAA;AAAA,aACpC;AAAA,4BAGA,GAAA;AAAA,cAAC,IAAA;AAAA,cAAA;AAAA,gBACC,SAAA,EAAU,0DAAA;AAAA,gBACV,KAAA,EAAO;AAAA,kBACL,KAAA,EAAO,iCAAA;AAAA,kBACP,UAAA,EAAY,iCAAA;AAAA,kBACZ,YAAA,EAAc,YAAA;AAAA,kBACd,SAAA,EAAW;AAAA,iBACb;AAAA,gBAEC,QAAA,EAAA,IAAA,CAAK;AAAA;AAAA,aACR;AAAA,4BAGA,GAAA;AAAA,cAAC,GAAA;AAAA,cAAA;AAAA,gBACC,SAAA,EAAU,iCAAA;AAAA,gBACV,KAAA,EAAO,EAAE,KAAA,EAAO,mCAAA,EAAoC;AAAA,gBAEnD,QAAA,EAAA,IAAA,CAAK;AAAA;AAAA,aACR;AAAA,4BAGA,GAAA;AAAA,cAAC,GAAA;AAAA,cAAA;AAAA,gBACC,SAAA,EAAU,sCAAA;AAAA,gBACV,KAAA,EAAO,EAAE,KAAA,EAAO,kCAAA,EAAmC;AAAA,gBAElD,QAAA,EAAA,IAAA,CAAK;AAAA;AAAA,aACR;AAAA,YAGC,IAAA,CAAK,QAAA,CAAS,MAAA,GAAS,CAAA,oBACtB,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sBAAA,EACZ,QAAA,EAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,CAAC,OAAA,qBAClB,GAAA;AAAA,cAAC,MAAA;AAAA,cAAA;AAAA,gBAEC,SAAA,EAAU,4CAAA;AAAA,gBACV,KAAA,EAAO;AAAA,kBACL,UAAA,EAAY,2CAAA;AAAA,kBACZ,KAAA,EAAO,mCAAA;AAAA,kBACP,MAAA,EAAQ;AAAA,iBACV;AAAA,gBAEC,2BAAiB,OAAO;AAAA,eAAA;AAAA,cARpB;AAAA,aAUR,CAAA,EACH,CAAA;AAAA,YAID,GAAA,oBACC,IAAA;AAAA,cAAC,GAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAM,GAAA;AAAA,gBACN,MAAA,EAAO,QAAA;AAAA,gBACP,GAAA,EAAI,qBAAA;AAAA,gBACJ,uBAAA,EAAsB,WAAA;AAAA,gBACtB,SAAA,EAAU,0HAAA;AAAA,gBACV,KAAA,EAAO;AAAA,kBACL,UAAA,EAAY,4BAAA;AAAA,kBACZ,KAAA,EAAO;AAAA,iBACT;AAAA,gBACD,QAAA,EAAA;AAAA,kBAAA,gBAAA;AAAA,kCAEC,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,IAAA,EAAK,MAAA,EAAO,MAAK,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,MAAA,EAAO,KAAA,EAAM,4BAAA,EAChE,8BAAC,MAAA,EAAA,EAAK,CAAA,EAAE,oBAAA,EAAqB,MAAA,EAAO,cAAA,EAAe,WAAA,EAAY,KAAI,aAAA,EAAc,OAAA,EAAQ,cAAA,EAAe,OAAA,EAAQ,CAAA,EAClH;AAAA;AAAA;AAAA;AACF,WAAA,EAGJ,CAAA;AAAA,0BAGA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,iDAAA,EAEX,QAAA,EAAA;AAAA,YAAA,CAAA,GAAA,IAAO,KAAA,EAAO,WAAW,KAAA,EAAO,MAAA,IAAU,OAAO,MAAA,qBACjD,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,oBAAA,EACb,QAAA,kBAAA,GAAA;AAAA,cAAC,cAAA;AAAA,cAAA;AAAA,gBACC,WAAA,EAAa;AAAA,kBACX,SAAS,KAAA,EAAO,OAAA;AAAA,kBAChB,QAAQ,KAAA,EAAO,MAAA;AAAA,kBACf,QAAQ,KAAA,EAAO;AAAA,iBACjB;AAAA,gBACA;AAAA;AAAA,aACF,EACF,CAAA;AAAA,YAID,IAAA,CAAK,IAAA,CAAK,MAAA,GAAS,CAAA,oBAClB,GAAA,CAAC,YAAA,EAAA,EAAa,CAAA,EAAG,EAAA,EAAI,KAAA,EAAO,GAAA,EAAK,OAAA,EAAS,GAAA,EACxC,QAAA,kBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,wBAAA,EACZ,QAAA,EAAA,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,EAAK,CAAA,qBACnB,IAAA,CAAC,SAAA,EAAA,EAAkB,OAAA,EAAQ,IAAA,EAAK,KAAA,EAAO,KAAA,EAAO,WAAU,aAAA,EACtD,QAAA,EAAA;AAAA,8BAAA,GAAA;AAAA,gBAAC,KAAA;AAAA,gBAAA;AAAA,kBACC,SAAA,EAAU,gCAAA;AAAA,kBACV,KAAA,EAAO,EAAE,KAAA,EAAO,4BAAA,EAA6B;AAAA,kBAE7C,QAAA,kBAAA,GAAA;AAAA,oBAAC,eAAA;AAAA,oBAAA;AAAA,sBACC,OAAO,GAAA,CAAI,KAAA;AAAA,sBACX,QAAQ,GAAA,CAAI,MAAA;AAAA,sBACZ,QAAQ,GAAA,CAAI,MAAA;AAAA,sBACZ,QAAA,EAAU;AAAA;AAAA;AACZ;AAAA,eACF;AAAA,8BACA,GAAA;AAAA,gBAAC,KAAA;AAAA,gBAAA;AAAA,kBACC,SAAA,EAAU,0BAAA;AAAA,kBACV,KAAA,EAAO,EAAE,KAAA,EAAO,mCAAA,EAAoC;AAAA,kBAEnD,QAAA,EAAA,GAAA,CAAI;AAAA;AAAA;AACP,aAAA,EAAA,EAjBc,CAkBhB,CACD,CAAA,EACH,CAAA,EACF;AAAA,WAAA,EAEJ;AAAA,SAAA,EACF,CAAA,EACF;AAAA;AAAA;AAAA,GACF;AAEJ","file":"HeroSection.js","sourcesContent":["// Server component — the entire hero renders on the server and ships zero\n// component JS. Client primitives (counter, reveal, trifolio) cross the RSC\n// boundary via package subpaths.\nimport React from 'react';\nimport type { PortfolioHeroData } from '../../../types';\nimport { formatCategoryLabel, formatServiceTag } from '../../format';\nimport ScrollReveal from '@sonordev/agency-site-kit/portfolio/primitives/ScrollReveal';\nimport AnimatedCounter from '@sonordev/agency-site-kit/portfolio/primitives/AnimatedCounter';\nimport GlassCard from '@sonordev/agency-site-kit/portfolio/primitives/GlassCard';\nimport DeviceTrifolio from '@sonordev/agency-site-kit/portfolio/primitives/DeviceTrifolio';\n\n// LCP rule (monorepo CLAUDE.md, Performance): above-the-fold content renders\n// fully static — no entrance animation, no post-hydration re-hide. The text\n// column below must never be wrapped in ScrollReveal/SplitHeadline: hiding\n// the H1 after hydration moves LCP to the tween's end and tanks the mobile\n// Lighthouse score. Reveal animations are for the below-fold KPI cards only.\n\n// Background parallax as a CSS scroll-driven animation — progressive\n// enhancement: browsers without animation-timeline get a static gradient.\nconst HERO_PARALLAX_CSS = `\n@supports (animation-timeline: view()) {\n @media (prefers-reduced-motion: no-preference) {\n .sk-hero-bg {\n animation: sk-hero-drift linear both;\n animation-timeline: view(block);\n animation-range: exit 0% exit 100%;\n }\n @keyframes sk-hero-drift {\n from { transform: translateY(0); }\n to { transform: translateY(30%); }\n }\n }\n}\n`;\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 shots = screenshots || data.screenshots;\n const url = liveUrl || data.liveUrl;\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 (CSS scroll-driven) */}\n <style href=\"sk-hero-parallax\" precedence=\"default\">\n {HERO_PARALLAX_CSS}\n </style>\n <div\n className=\"sk-hero-bg 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 min-w-0 px-4 sm:px-6 py-24 lg:py-32\">\n <div className=\"grid grid-cols-1 min-w-0 lg:grid-cols-2 gap-12 lg:gap-16 items-start\">\n {/* Text column — min-w-0 so grid track can shrink below content intrinsic width (mobile) */}\n <div className=\"flex min-w-0 max-w-full flex-col gap-6\">\n {/* Category badge */}\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 {formatCategoryLabel(data.category)}\n </span>\n\n {/* Headline — static, this is usually the LCP element */}\n <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 overflowWrap: 'break-word',\n wordBreak: 'break-word',\n }}\n >\n {data.headline}\n </h1>\n\n {/* Subheadline */}\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\n {/* Description */}\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\n {/* Services tags */}\n {data.services.length > 0 && (\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 {formatServiceTag(service)}\n </span>\n ))}\n </div>\n )}\n\n {/* CTA button */}\n {url && (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n data-portfolio-action=\"live-site\"\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 )}\n\n </div>\n\n {/* Right column — trifolio + KPIs */}\n <div className=\"flex min-w-0 max-w-full flex-col gap-10 lg:pt-8\">\n {/* Device trifolio — realistic device frames */}\n {(url || shots?.desktop || shots?.tablet || shots?.mobile) && (\n <div className=\"min-w-0 max-w-full\">\n <DeviceTrifolio\n screenshots={{\n desktop: shots?.desktop,\n tablet: shots?.tablet,\n mobile: shots?.mobile,\n }}\n url={url}\n />\n </div>\n )}\n\n {/* KPI cards — below trifolio in right column */}\n {data.kpis.length > 0 && (\n <ScrollReveal y={30} delay={0.6} stagger={0.1}>\n <div className=\"grid grid-cols-2 gap-3\">\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 </GlassCard>\n ))}\n </div>\n </ScrollReveal>\n )}\n </div>\n </div>\n </div>\n </section>\n );\n}\n"]}
|
|
@@ -169,24 +169,6 @@ function ScoreGauge({
|
|
|
169
169
|
)
|
|
170
170
|
] });
|
|
171
171
|
}
|
|
172
|
-
var SCORE_EXPLANATIONS = {
|
|
173
|
-
performance: {
|
|
174
|
-
why: "Faster sites convert more visitors into customers. A 1-second delay in load time reduces conversions by up to 7%. Google uses page speed as a direct ranking factor.",
|
|
175
|
-
competitors: "Wix and GoDaddy sites typically score 30\u201350 due to bloated JavaScript bundles and shared hosting. Template builders prioritize ease-of-use over speed."
|
|
176
|
-
},
|
|
177
|
-
seo: {
|
|
178
|
-
why: "Technical SEO determines whether search engines can properly crawl, index, and rank your pages. Higher scores mean more organic visibility and free traffic.",
|
|
179
|
-
competitors: "DIY builders often miss critical SEO fundamentals\u2014proper meta tags, structured data, canonical URLs, and server-side rendering that search engines need."
|
|
180
|
-
},
|
|
181
|
-
accessibility: {
|
|
182
|
-
why: "Accessible sites reach more customers, including the 1 in 4 adults with disabilities. It also reduces legal risk and improves usability for everyone.",
|
|
183
|
-
competitors: "Template platforms generate markup that frequently fails WCAG standards\u2014missing alt text, poor contrast ratios, and keyboard navigation issues."
|
|
184
|
-
},
|
|
185
|
-
bestPractices: {
|
|
186
|
-
why: "Best practices cover security (HTTPS, safe APIs), modern code standards, and browser compatibility. They protect your business and your visitors.",
|
|
187
|
-
competitors: "Older platforms rely on outdated libraries, insecure dependencies, and legacy patterns that create vulnerabilities and degrade user trust."
|
|
188
|
-
}
|
|
189
|
-
};
|
|
190
172
|
function PerformanceSection({ data }) {
|
|
191
173
|
const hasBeforeAfter = data.before && data.after;
|
|
192
174
|
const scores = data.after || data.before;
|
|
@@ -214,7 +196,7 @@ function PerformanceSection({ data }) {
|
|
|
214
196
|
{
|
|
215
197
|
className: "text-lg mb-12 max-w-2xl",
|
|
216
198
|
style: { color: "var(--sk-text-secondary, #a1a1aa)" },
|
|
217
|
-
children: hasBeforeAfter ? "Real Lighthouse scores
|
|
199
|
+
children: hasBeforeAfter ? "Real Lighthouse scores, before and after our rebuild." : "Real performance metrics measured by Google Lighthouse."
|
|
218
200
|
}
|
|
219
201
|
)
|
|
220
202
|
] }),
|
|
@@ -233,51 +215,6 @@ function PerformanceSection({ data }) {
|
|
|
233
215
|
cat.key
|
|
234
216
|
);
|
|
235
217
|
}) }) }),
|
|
236
|
-
scores && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ScrollReveal.default, { y: 30, delay: 0.2, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid md:grid-cols-2 gap-4 mb-12", children: CATEGORIES.map((cat) => {
|
|
237
|
-
const currentScore = scores[cat.key];
|
|
238
|
-
if (currentScore === void 0) return null;
|
|
239
|
-
const explanation = SCORE_EXPLANATIONS[cat.key];
|
|
240
|
-
if (!explanation) return null;
|
|
241
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_GlassCard.default, { padding: "md", hover: false, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-start gap-3", children: [
|
|
242
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
243
|
-
"div",
|
|
244
|
-
{
|
|
245
|
-
className: "w-10 h-10 rounded-lg flex items-center justify-center shrink-0 text-sm font-bold",
|
|
246
|
-
style: {
|
|
247
|
-
background: `color-mix(in srgb, ${getScoreColor(currentScore)} 15%, transparent)`,
|
|
248
|
-
color: getScoreColor(currentScore)
|
|
249
|
-
},
|
|
250
|
-
children: currentScore
|
|
251
|
-
}
|
|
252
|
-
),
|
|
253
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
254
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
255
|
-
"h4",
|
|
256
|
-
{
|
|
257
|
-
className: "text-sm font-semibold mb-1",
|
|
258
|
-
style: { color: "var(--sk-text-primary, #ffffff)" },
|
|
259
|
-
children: cat.label
|
|
260
|
-
}
|
|
261
|
-
),
|
|
262
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
263
|
-
"p",
|
|
264
|
-
{
|
|
265
|
-
className: "text-xs leading-relaxed mb-2",
|
|
266
|
-
style: { color: "var(--sk-text-secondary, #a1a1aa)" },
|
|
267
|
-
children: explanation.why
|
|
268
|
-
}
|
|
269
|
-
),
|
|
270
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
271
|
-
"p",
|
|
272
|
-
{
|
|
273
|
-
className: "text-xs leading-relaxed",
|
|
274
|
-
style: { color: "var(--sk-text-tertiary, #71717a)" },
|
|
275
|
-
children: explanation.competitors
|
|
276
|
-
}
|
|
277
|
-
)
|
|
278
|
-
] })
|
|
279
|
-
] }) }, cat.key);
|
|
280
|
-
}) }) }),
|
|
281
218
|
hasBeforeAfter && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ScrollReveal.default, { y: 30, delay: 0.3, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "grid md:grid-cols-2 gap-4", children: [
|
|
282
219
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_GlassCard.default, { padding: "lg", hover: false, children: [
|
|
283
220
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|