@sonordev/agency-site-kit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/dist/BeforeAfterSection-6QUJOBO2.js +176 -0
  2. package/dist/BeforeAfterSection-6QUJOBO2.js.map +1 -0
  3. package/dist/BeforeAfterSection-DVAWWE4K.cjs +181 -0
  4. package/dist/BeforeAfterSection-DVAWWE4K.cjs.map +1 -0
  5. package/dist/CTASection-4JKLXEUF.cjs +111 -0
  6. package/dist/CTASection-4JKLXEUF.cjs.map +1 -0
  7. package/dist/CTASection-BJA72XIL.js +106 -0
  8. package/dist/CTASection-BJA72XIL.js.map +1 -0
  9. package/dist/ChallengesSection-GEQGVSJN.js +180 -0
  10. package/dist/ChallengesSection-GEQGVSJN.js.map +1 -0
  11. package/dist/ChallengesSection-IZ3DHECS.cjs +182 -0
  12. package/dist/ChallengesSection-IZ3DHECS.cjs.map +1 -0
  13. package/dist/ConversionFunnelSection-AUUSJ5HQ.cjs +209 -0
  14. package/dist/ConversionFunnelSection-AUUSJ5HQ.cjs.map +1 -0
  15. package/dist/ConversionFunnelSection-D3GE4NKE.js +203 -0
  16. package/dist/ConversionFunnelSection-D3GE4NKE.js.map +1 -0
  17. package/dist/DetailsSection-FB763FS7.js +135 -0
  18. package/dist/DetailsSection-FB763FS7.js.map +1 -0
  19. package/dist/DetailsSection-OACJFGH7.cjs +137 -0
  20. package/dist/DetailsSection-OACJFGH7.cjs.map +1 -0
  21. package/dist/FeatureSpotlightSection-B7P3JGNL.js +205 -0
  22. package/dist/FeatureSpotlightSection-B7P3JGNL.js.map +1 -0
  23. package/dist/FeatureSpotlightSection-WRHXS7TU.cjs +210 -0
  24. package/dist/FeatureSpotlightSection-WRHXS7TU.cjs.map +1 -0
  25. package/dist/GallerySection-VMKORC47.js +218 -0
  26. package/dist/GallerySection-VMKORC47.js.map +1 -0
  27. package/dist/GallerySection-WJ4PQDBI.cjs +219 -0
  28. package/dist/GallerySection-WJ4PQDBI.cjs.map +1 -0
  29. package/dist/MetricsTimelineSection-4L6DUHJ5.cjs +258 -0
  30. package/dist/MetricsTimelineSection-4L6DUHJ5.cjs.map +1 -0
  31. package/dist/MetricsTimelineSection-6BT5GNFV.js +253 -0
  32. package/dist/MetricsTimelineSection-6BT5GNFV.js.map +1 -0
  33. package/dist/ResultsSection-DFUJ5U6M.js +93 -0
  34. package/dist/ResultsSection-DFUJ5U6M.js.map +1 -0
  35. package/dist/ResultsSection-XLGMMQKY.cjs +95 -0
  36. package/dist/ResultsSection-XLGMMQKY.cjs.map +1 -0
  37. package/dist/ServicesSection-D5V3Q4GR.js +118 -0
  38. package/dist/ServicesSection-D5V3Q4GR.js.map +1 -0
  39. package/dist/ServicesSection-WJMGK2MF.cjs +120 -0
  40. package/dist/ServicesSection-WJMGK2MF.cjs.map +1 -0
  41. package/dist/StrategySection-3ED3QW4R.cjs +180 -0
  42. package/dist/StrategySection-3ED3QW4R.cjs.map +1 -0
  43. package/dist/StrategySection-VUWMIYYP.js +175 -0
  44. package/dist/StrategySection-VUWMIYYP.js.map +1 -0
  45. package/dist/TeamSection-DZVSNZE6.cjs +112 -0
  46. package/dist/TeamSection-DZVSNZE6.cjs.map +1 -0
  47. package/dist/TeamSection-HGKFW6PQ.js +107 -0
  48. package/dist/TeamSection-HGKFW6PQ.js.map +1 -0
  49. package/dist/TechStackSection-OCUYG4XT.js +90 -0
  50. package/dist/TechStackSection-OCUYG4XT.js.map +1 -0
  51. package/dist/TechStackSection-VKJK4KQB.cjs +91 -0
  52. package/dist/TechStackSection-VKJK4KQB.cjs.map +1 -0
  53. package/dist/TestimonialSection-6RGSMXQB.js +122 -0
  54. package/dist/TestimonialSection-6RGSMXQB.js.map +1 -0
  55. package/dist/TestimonialSection-XPTFUQIN.cjs +124 -0
  56. package/dist/TestimonialSection-XPTFUQIN.cjs.map +1 -0
  57. package/dist/VideoSection-4A2HC6K6.js +117 -0
  58. package/dist/VideoSection-4A2HC6K6.js.map +1 -0
  59. package/dist/VideoSection-G3DFS7UH.cjs +118 -0
  60. package/dist/VideoSection-G3DFS7UH.cjs.map +1 -0
  61. package/dist/chunk-2VNNFAG6.js +415 -0
  62. package/dist/chunk-2VNNFAG6.js.map +1 -0
  63. package/dist/chunk-2Y4O3LWM.js +53 -0
  64. package/dist/chunk-2Y4O3LWM.js.map +1 -0
  65. package/dist/chunk-5FKOLIV6.cjs +221 -0
  66. package/dist/chunk-5FKOLIV6.cjs.map +1 -0
  67. package/dist/chunk-7CFFAKDM.js +74 -0
  68. package/dist/chunk-7CFFAKDM.js.map +1 -0
  69. package/dist/chunk-A4I4IK7V.js +69 -0
  70. package/dist/chunk-A4I4IK7V.js.map +1 -0
  71. package/dist/chunk-IKBK7HYX.cjs +79 -0
  72. package/dist/chunk-IKBK7HYX.cjs.map +1 -0
  73. package/dist/chunk-KEOHORIH.cjs +79 -0
  74. package/dist/chunk-KEOHORIH.cjs.map +1 -0
  75. package/dist/chunk-NAS4K5UR.cjs +139 -0
  76. package/dist/chunk-NAS4K5UR.cjs.map +1 -0
  77. package/dist/chunk-QBLWP25X.cjs +73 -0
  78. package/dist/chunk-QBLWP25X.cjs.map +1 -0
  79. package/dist/chunk-QIC6JFFD.js +210 -0
  80. package/dist/chunk-QIC6JFFD.js.map +1 -0
  81. package/dist/chunk-TAPNXT7X.cjs +422 -0
  82. package/dist/chunk-TAPNXT7X.cjs.map +1 -0
  83. package/dist/chunk-XCKXHK44.js +15 -0
  84. package/dist/chunk-XCKXHK44.js.map +1 -0
  85. package/dist/chunk-XMC4DN6G.js +131 -0
  86. package/dist/chunk-XMC4DN6G.js.map +1 -0
  87. package/dist/chunk-XONXEFJY.cjs +58 -0
  88. package/dist/chunk-XONXEFJY.cjs.map +1 -0
  89. package/dist/chunk-XQNJED46.cjs +19 -0
  90. package/dist/chunk-XQNJED46.cjs.map +1 -0
  91. package/dist/chunk-YB4B3OMC.js +74 -0
  92. package/dist/chunk-YB4B3OMC.js.map +1 -0
  93. package/dist/index.cjs +271 -0
  94. package/dist/index.cjs.map +1 -0
  95. package/dist/index.d.cts +137 -0
  96. package/dist/index.d.ts +137 -0
  97. package/dist/index.js +197 -0
  98. package/dist/index.js.map +1 -0
  99. package/dist/layout/index.cjs +13 -0
  100. package/dist/layout/index.cjs.map +1 -0
  101. package/dist/layout/index.d.cts +54 -0
  102. package/dist/layout/index.d.ts +54 -0
  103. package/dist/layout/index.js +4 -0
  104. package/dist/layout/index.js.map +1 -0
  105. package/dist/portfolio/client.cjs +18 -0
  106. package/dist/portfolio/client.cjs.map +1 -0
  107. package/dist/portfolio/client.d.cts +97 -0
  108. package/dist/portfolio/client.d.ts +97 -0
  109. package/dist/portfolio/client.js +6 -0
  110. package/dist/portfolio/client.js.map +1 -0
  111. package/dist/portfolio/index.cjs +41 -0
  112. package/dist/portfolio/index.cjs.map +1 -0
  113. package/dist/portfolio/index.d.cts +12 -0
  114. package/dist/portfolio/index.d.ts +12 -0
  115. package/dist/portfolio/index.js +8 -0
  116. package/dist/portfolio/index.js.map +1 -0
  117. package/dist/portfolio/sections.cjs +20 -0
  118. package/dist/portfolio/sections.cjs.map +1 -0
  119. package/dist/portfolio/sections.d.cts +42 -0
  120. package/dist/portfolio/sections.d.ts +42 -0
  121. package/dist/portfolio/sections.js +4 -0
  122. package/dist/portfolio/sections.js.map +1 -0
  123. package/dist/portfolio/server.cjs +141 -0
  124. package/dist/portfolio/server.cjs.map +1 -0
  125. package/dist/portfolio/server.d.cts +68 -0
  126. package/dist/portfolio/server.d.ts +68 -0
  127. package/dist/portfolio/server.js +134 -0
  128. package/dist/portfolio/server.js.map +1 -0
  129. package/dist/types-BMUhBhWx.d.cts +346 -0
  130. package/dist/types-BMUhBhWx.d.ts +346 -0
  131. package/package.json +71 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared/brand.ts","../src/layout/AgencySiteKitLayout.tsx"],"names":[],"mappings":"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","file":"chunk-QIC6JFFD.js","sourcesContent":["/**\n * @sonordev/agency-site-kit — Brand customization system\n *\n * Generates CSS custom properties from a BrandConfig object.\n * Supports light/dark mode with automatic fallbacks.\n */\n\nimport type { BrandConfig } from '../types';\n\n// ---------------------------------------------------------------------------\n// Hex to RGB helper\n// ---------------------------------------------------------------------------\n\n/**\n * Converts a hex color string to an \"R, G, B\" string for use in rgb()/rgba().\n * Supports 3-digit (#abc) and 6-digit (#aabbcc) hex values.\n * Returns null for invalid inputs.\n */\nexport function hexToRgb(hex: string): string | null {\n if (!hex || typeof hex !== 'string') return null;\n\n const cleaned = hex.replace(/^#/, '');\n\n let r: number;\n let g: number;\n let b: number;\n\n if (cleaned.length === 3) {\n r = parseInt(cleaned[0] + cleaned[0], 16);\n g = parseInt(cleaned[1] + cleaned[1], 16);\n b = parseInt(cleaned[2] + cleaned[2], 16);\n } else if (cleaned.length === 6) {\n r = parseInt(cleaned.substring(0, 2), 16);\n g = parseInt(cleaned.substring(2, 4), 16);\n b = parseInt(cleaned.substring(4, 6), 16);\n } else {\n return null;\n }\n\n if (isNaN(r) || isNaN(g) || isNaN(b)) return null;\n\n return `${r}, ${g}, ${b}`;\n}\n\n// ---------------------------------------------------------------------------\n// Default theme values\n// ---------------------------------------------------------------------------\n\nexport const DEFAULT_BRAND_CONFIG: BrandConfig = {\n primary: '#6366f1',\n secondary: '#8b5cf6',\n background: '#ffffff',\n backgroundElevated: '#f8fafc',\n surface: '#f1f5f9',\n surfaceHover: '#e2e8f0',\n surfaceBorder: '#e2e8f0',\n textPrimary: '#0f172a',\n textSecondary: '#475569',\n textTertiary: '#94a3b8',\n fontHeading: \"'Inter', system-ui, -apple-system, sans-serif\",\n fontBody: \"'Inter', system-ui, -apple-system, sans-serif\",\n radius: {\n sm: '0.375rem',\n md: '0.5rem',\n lg: '0.75rem',\n },\n};\n\nexport const DEFAULT_DARK_MODE: Partial<BrandConfig> = {\n background: '#0f172a',\n backgroundElevated: '#1e293b',\n surface: '#1e293b',\n surfaceHover: '#334155',\n surfaceBorder: '#334155',\n textPrimary: '#f8fafc',\n textSecondary: '#cbd5e1',\n textTertiary: '#64748b',\n};\n\n// ---------------------------------------------------------------------------\n// CSS variable generation\n// ---------------------------------------------------------------------------\n\nfunction buildVariables(config: BrandConfig): string {\n const primaryRgb = hexToRgb(config.primary) || '99, 102, 241';\n const secondaryRgb = hexToRgb(config.secondary) || '139, 92, 246';\n\n const radius = config.radius || DEFAULT_BRAND_CONFIG.radius!;\n\n return [\n // Primary tokens (--sk-*)\n `--sk-primary: ${config.primary};`,\n `--sk-primary-rgb: ${primaryRgb};`,\n `--sk-secondary: ${config.secondary};`,\n `--sk-secondary-rgb: ${secondaryRgb};`,\n `--sk-bg: ${config.background};`,\n `--sk-bg-elevated: ${config.backgroundElevated};`,\n `--sk-surface: ${config.surface};`,\n `--sk-surface-hover: ${config.surfaceHover};`,\n `--sk-border: ${config.surfaceBorder};`,\n `--sk-text-primary: ${config.textPrimary};`,\n `--sk-text-secondary: ${config.textSecondary};`,\n `--sk-text-tertiary: ${config.textTertiary};`,\n `--sk-radius-sm: ${radius.sm};`,\n `--sk-radius: ${radius.md};`,\n `--sk-radius-lg: ${radius.lg};`,\n `--sk-font-heading: ${config.fontHeading};`,\n `--sk-font: ${config.fontBody};`,\n ].join('\\n ');\n}\n\nfunction buildDarkVariables(base: BrandConfig): string {\n const dark = {\n ...DEFAULT_DARK_MODE,\n ...base.darkMode,\n // Primary/secondary carry over unless explicitly overridden\n primary: base.darkMode?.primary || base.primary,\n secondary: base.darkMode?.secondary || base.secondary,\n };\n\n const primaryRgb = hexToRgb(dark.primary!) || hexToRgb(base.primary) || '99, 102, 241';\n const secondaryRgb = hexToRgb(dark.secondary!) || hexToRgb(base.secondary) || '139, 92, 246';\n\n return [\n // Primary tokens (--sk-*)\n `--sk-primary: ${dark.primary};`,\n `--sk-primary-rgb: ${primaryRgb};`,\n `--sk-secondary: ${dark.secondary};`,\n `--sk-secondary-rgb: ${secondaryRgb};`,\n `--sk-bg: ${dark.background || DEFAULT_DARK_MODE.background};`,\n `--sk-bg-elevated: ${dark.backgroundElevated || DEFAULT_DARK_MODE.backgroundElevated};`,\n `--sk-surface: ${dark.surface || DEFAULT_DARK_MODE.surface};`,\n `--sk-surface-hover: ${dark.surfaceHover || DEFAULT_DARK_MODE.surfaceHover};`,\n `--sk-border: ${dark.surfaceBorder || DEFAULT_DARK_MODE.surfaceBorder};`,\n `--sk-text-primary: ${dark.textPrimary || DEFAULT_DARK_MODE.textPrimary};`,\n `--sk-text-secondary: ${dark.textSecondary || DEFAULT_DARK_MODE.textSecondary};`,\n `--sk-text-tertiary: ${dark.textTertiary || DEFAULT_DARK_MODE.textTertiary};`,\n ].join('\\n ');\n}\n\n/**\n * Generates a complete CSS string with all --sk-* custom properties.\n *\n * Produces:\n * - `:root` / `[data-theme=\"light\"]` block with light mode values\n * - `[data-theme=\"dark\"]` block with dark mode values\n * - `@media (prefers-color-scheme: dark)` fallback for auto detection\n *\n * Usage: inject the returned string into a `<style>` tag.\n */\nexport function generateBrandCSS(config: BrandConfig): string {\n const merged: BrandConfig = {\n ...DEFAULT_BRAND_CONFIG,\n ...config,\n radius: {\n ...DEFAULT_BRAND_CONFIG.radius!,\n ...config.radius,\n },\n };\n\n const lightVars = buildVariables(merged);\n const darkVars = buildDarkVariables(merged);\n\n return `\n:root, [data-theme=\"light\"] {\n ${lightVars}\n}\n\n[data-theme=\"dark\"] {\n ${darkVars}\n}\n\n@media (prefers-color-scheme: dark) {\n :root:not([data-theme=\"light\"]) {\n ${darkVars}\n }\n}\n`.trim();\n}\n\n/**\n * Merges a partial brand config with defaults, returning a complete BrandConfig.\n */\nexport function mergeBrandConfig(partial: Partial<BrandConfig>): BrandConfig {\n return {\n ...DEFAULT_BRAND_CONFIG,\n ...partial,\n radius: {\n ...DEFAULT_BRAND_CONFIG.radius!,\n ...partial.radius,\n },\n };\n}\n","/**\n * @sonordev/agency-site-kit — AgencySiteKitLayout\n *\n * Server component that wraps children with brand CSS variables.\n * Fetches the brand configuration from the Portal API and injects\n * a <style> tag with all --sk-* custom properties (plus --agency-* aliases for backwards compatibility).\n *\n * Usage in app/layout.tsx:\n *\n * ```tsx\n * import { AgencySiteKitLayout } from '@sonordev/agency-site-kit';\n *\n * export default function RootLayout({ children }) {\n * return (\n * <html lang=\"en\">\n * <body>\n * <AgencySiteKitLayout>\n * {children}\n * </AgencySiteKitLayout>\n * </body>\n * </html>\n * );\n * }\n * ```\n */\n\nimport React from 'react';\nimport { apiGet } from '../shared/api';\nimport { generateBrandCSS, mergeBrandConfig } from '../shared/brand';\nimport type { BrandConfig, PortfolioConfigResponse } from '../types';\n\nfunction portalApiOrigin(apiUrl: string): string {\n try {\n return new URL(apiUrl.replace(/\\/$/, '')).origin\n } catch {\n return 'https://api.sonor.io'\n }\n}\n\nexport interface AgencySiteKitLayoutProps {\n children: React.ReactNode;\n /** Override the API key (defaults to process.env.SONOR_API_KEY) */\n apiKey?: string;\n /** Override the API URL (defaults to process.env.SONOR_API_URL or https://api.sonor.io) */\n apiUrl?: string;\n /** Override brand config instead of fetching from API */\n brandConfig?: Partial<BrandConfig>;\n /** Force a specific theme: \"light\" | \"dark\". Omit for system preference. */\n theme?: 'light' | 'dark';\n /** Additional class name for the wrapper div */\n className?: string;\n}\n\n/**\n * Fetches brand configuration from the Portal API.\n * Returns a merged BrandConfig with defaults applied.\n * Falls back to defaults if the API call fails.\n */\nasync function fetchBrandConfig(\n apiKey?: string,\n apiUrl?: string,\n): Promise<BrandConfig> {\n const response = await apiGet<PortfolioConfigResponse>(\n '/api/public/portfolio/config',\n 3600,\n apiKey,\n apiUrl,\n );\n\n if (response?.brand) {\n return mergeBrandConfig(response.brand);\n }\n\n return mergeBrandConfig({});\n}\n\n/**\n * AgencySiteKitLayout — Server component wrapper\n *\n * Fetches the agency's brand configuration and injects CSS custom properties\n * so all child components can use --sk-* variables for theming.\n *\n * This is an async server component (RSC). It makes one API call at render\n * time, cached via Next.js ISR (default 1 hour revalidation).\n */\nexport async function AgencySiteKitLayout({\n children,\n apiKey,\n apiUrl,\n brandConfig: brandConfigOverride,\n theme,\n className,\n}: AgencySiteKitLayoutProps): Promise<React.ReactElement> {\n // Use override brand config if provided, otherwise fetch from API\n const brandConfig = brandConfigOverride\n ? mergeBrandConfig(brandConfigOverride)\n : await fetchBrandConfig(apiKey, apiUrl);\n\n const cssString = generateBrandCSS(brandConfig);\n\n const resolvedApiUrl =\n apiUrl ??\n process.env.SONOR_API_URL ??\n process.env.UPTRADE_API_URL ??\n 'https://api.sonor.io';\n const preconnectHref = portalApiOrigin(resolvedApiUrl);\n\n return React.createElement(\n React.Fragment,\n null,\n React.createElement('link', {\n rel: 'preconnect',\n href: preconnectHref,\n crossOrigin: 'anonymous',\n }),\n React.createElement('link', {\n rel: 'dns-prefetch',\n href: preconnectHref,\n }),\n React.createElement('style', {\n dangerouslySetInnerHTML: { __html: cssString },\n 'data-agency-site-kit': 'brand',\n }),\n React.createElement(\n 'div',\n {\n 'data-theme': theme || undefined,\n 'data-agency-site-kit': 'root',\n className,\n style: {\n fontFamily: 'var(--sk-font)',\n color: 'var(--sk-text-primary)',\n backgroundColor: 'var(--sk-bg)',\n },\n },\n children,\n ),\n );\n}\n"]}
@@ -0,0 +1,422 @@
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
@@ -0,0 +1 @@
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' }}>&nbsp;</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"]}
@@ -0,0 +1,15 @@
1
+ // src/portfolio/sections.ts
2
+ var sectionRenderers = {};
3
+ function registerSectionRenderer(sectionType, renderer) {
4
+ sectionRenderers[sectionType] = renderer;
5
+ }
6
+ function getSectionRenderer(sectionType) {
7
+ return sectionRenderers[sectionType] ?? null;
8
+ }
9
+ function getRegisteredSectionTypes() {
10
+ return Object.keys(sectionRenderers);
11
+ }
12
+
13
+ export { getRegisteredSectionTypes, getSectionRenderer, registerSectionRenderer };
14
+ //# sourceMappingURL=chunk-XCKXHK44.js.map
15
+ //# sourceMappingURL=chunk-XCKXHK44.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/portfolio/sections.ts"],"names":[],"mappings":";AAuCA,IAAM,mBAA2E,EAAC;AAK3E,SAAS,uBAAA,CACd,aACA,QAAA,EACM;AACN,EAAA,gBAAA,CAAiB,WAAW,CAAA,GAAI,QAAA;AAClC;AAMO,SAAS,mBACd,WAAA,EACwB;AACxB,EAAA,OAAO,gBAAA,CAAiB,WAAW,CAAA,IAAK,IAAA;AAC1C;AAKO,SAAS,yBAAA,GAAoD;AAClE,EAAA,OAAO,MAAA,CAAO,KAAK,gBAAgB,CAAA;AACrC","file":"chunk-XCKXHK44.js","sourcesContent":["'use client';\n\n/**\n * @sonordev/agency-site-kit/portfolio/sections — Section component barrel\n *\n * All portfolio section components are client components (they use\n * animations, interactivity, and browser APIs). This barrel marks the\n * client boundary and re-exports each section renderer.\n *\n * Section components will be added here as they are implemented.\n * Each section component follows the pattern:\n *\n * interface Props { data: Portfolio[SectionName]Data; className?: string; }\n * export function Portfolio[SectionName]Section({ data, className }: Props) { ... }\n *\n * For now, export the section type map and a placeholder renderer registry\n * so that consuming code can be written against the final API.\n */\n\nimport type {\n PortfolioSectionType,\n PortfolioSectionData,\n PortfolioSectionDataMap,\n} from '../types';\n\n/**\n * Section renderer function signature.\n * Each section component conforms to this interface.\n */\nexport type SectionRenderer<T extends PortfolioSectionType = PortfolioSectionType> = (props: {\n data: T extends keyof PortfolioSectionDataMap ? PortfolioSectionDataMap[T] : PortfolioSectionData;\n className?: string;\n}) => React.ReactElement | null;\n\n/**\n * Registry of section renderers, keyed by section type.\n * Components register themselves here as they are implemented.\n * Consuming code can look up a renderer by section type string.\n */\nconst sectionRenderers: Partial<Record<PortfolioSectionType, SectionRenderer>> = {};\n\n/**\n * Register a section renderer for a given section type.\n */\nexport function registerSectionRenderer<T extends PortfolioSectionType>(\n sectionType: T,\n renderer: SectionRenderer<T>,\n): void {\n sectionRenderers[sectionType] = renderer as SectionRenderer;\n}\n\n/**\n * Look up a registered section renderer by type.\n * Returns null if no renderer is registered for the given type.\n */\nexport function getSectionRenderer(\n sectionType: PortfolioSectionType,\n): SectionRenderer | null {\n return sectionRenderers[sectionType] ?? null;\n}\n\n/**\n * Returns all registered section types.\n */\nexport function getRegisteredSectionTypes(): PortfolioSectionType[] {\n return Object.keys(sectionRenderers) as PortfolioSectionType[];\n}\n\n// Re-export section data types for convenience\nexport type {\n SectionRenderer as PortfolioSectionRenderer,\n};\n"]}