@sonordev/agency-site-kit 0.1.3 → 0.3.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.
- package/dist/{SiteArchitectureSection-EE6VQSXM.cjs → SiteArchitectureSection-J7BPBERH.cjs} +2 -2
- package/dist/SiteArchitectureSection-J7BPBERH.cjs.map +1 -0
- package/dist/{SiteArchitectureSection-PBBRTARV.js → SiteArchitectureSection-TE22OAWV.js} +2 -2
- package/dist/SiteArchitectureSection-TE22OAWV.js.map +1 -0
- package/dist/cache-CE_ujDK4.d.cts +15 -0
- package/dist/cache-CE_ujDK4.d.ts +15 -0
- package/dist/{chunk-RLVW7WEK.js → chunk-2UNKXWQM.js} +22 -4
- package/dist/chunk-2UNKXWQM.js.map +1 -0
- package/dist/chunk-EE75WRCM.cjs +56 -0
- package/dist/chunk-EE75WRCM.cjs.map +1 -0
- package/dist/chunk-FCKDJ4MJ.cjs +8 -0
- package/dist/chunk-FCKDJ4MJ.cjs.map +1 -0
- package/dist/{chunk-JTI3F3QY.cjs → chunk-FDFVLYAM.cjs} +22 -4
- package/dist/chunk-FDFVLYAM.cjs.map +1 -0
- package/dist/chunk-N7TVKUYQ.js +6 -0
- package/dist/chunk-N7TVKUYQ.js.map +1 -0
- package/dist/{chunk-OMOF4VR5.js → chunk-RXBK2EOE.js} +13 -13
- package/dist/chunk-RXBK2EOE.js.map +1 -0
- package/dist/chunk-TVFXN6W6.js +52 -0
- package/dist/chunk-TVFXN6W6.js.map +1 -0
- package/dist/{chunk-XM2QD3AK.cjs → chunk-WNR4KNG4.cjs} +14 -14
- package/dist/chunk-WNR4KNG4.cjs.map +1 -0
- package/dist/index.cjs +14 -14
- package/dist/index.d.cts +34 -13
- package/dist/index.d.ts +34 -13
- package/dist/index.js +3 -3
- package/dist/layout/index.cjs +3 -3
- package/dist/layout/index.d.cts +6 -1
- package/dist/layout/index.d.ts +6 -1
- package/dist/layout/index.js +2 -2
- package/dist/portfolio/index.cjs +3 -3
- package/dist/portfolio/index.js +1 -1
- package/dist/portfolio/server.cjs +13 -5
- package/dist/portfolio/server.cjs.map +1 -1
- package/dist/portfolio/server.d.cts +1 -0
- package/dist/portfolio/server.d.ts +1 -0
- package/dist/portfolio/server.js +10 -5
- package/dist/portfolio/server.js.map +1 -1
- package/dist/revalidate.cjs +98 -0
- package/dist/revalidate.cjs.map +1 -0
- package/dist/revalidate.d.cts +53 -0
- package/dist/revalidate.d.ts +53 -0
- package/dist/revalidate.js +93 -0
- package/dist/revalidate.js.map +1 -0
- package/package.json +9 -1
- package/dist/SiteArchitectureSection-EE6VQSXM.cjs.map +0 -1
- package/dist/SiteArchitectureSection-PBBRTARV.js.map +0 -1
- package/dist/chunk-A4I4IK7V.js +0 -69
- package/dist/chunk-A4I4IK7V.js.map +0 -1
- package/dist/chunk-JTI3F3QY.cjs.map +0 -1
- package/dist/chunk-OMOF4VR5.js.map +0 -1
- package/dist/chunk-QBLWP25X.cjs +0 -73
- package/dist/chunk-QBLWP25X.cjs.map +0 -1
- package/dist/chunk-RLVW7WEK.js.map +0 -1
- package/dist/chunk-XM2QD3AK.cjs.map +0 -1
|
@@ -345,5 +345,5 @@ function SiteArchitectureSection({ data }) {
|
|
|
345
345
|
}
|
|
346
346
|
|
|
347
347
|
module.exports = SiteArchitectureSection;
|
|
348
|
-
//# sourceMappingURL=SiteArchitectureSection-
|
|
349
|
-
//# sourceMappingURL=SiteArchitectureSection-
|
|
348
|
+
//# sourceMappingURL=SiteArchitectureSection-J7BPBERH.cjs.map
|
|
349
|
+
//# sourceMappingURL=SiteArchitectureSection-J7BPBERH.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/portfolio/components/sections/SiteArchitectureSection.tsx"],"names":["useRef","useState","useEffect","gsap","ScrollTrigger","jsx","jsxs","ScrollReveal","Fragment"],"mappings":"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","file":"SiteArchitectureSection-J7BPBERH.cjs","sourcesContent":["'use client';\n\nimport React, { useRef, useEffect, useState } from 'react';\nimport gsap from 'gsap';\nimport { ScrollTrigger } from 'gsap/ScrollTrigger';\nimport ScrollReveal from '../primitives/ScrollReveal';\nimport GlassCard from '../primitives/GlassCard';\n\ninterface PageGroup {\n label: string;\n count: number;\n // path is optional: PortfolioPage strips raw client-site paths before they\n // reach this client component so they never enter the RSC flight payload\n // (Googlebot crawls path-like strings against the host site → 404 floods).\n pages: Array<{ path?: string; title: string }>;\n}\n\nexport interface SiteArchitectureData {\n totalPages: number;\n totalWords: number;\n groups: PageGroup[];\n}\n\ninterface SiteArchitectureSectionProps {\n data: SiteArchitectureData;\n}\n\n/** Generates a pleasing color from the brand palette for each branch */\nfunction getBranchColor(index: number): string {\n const hues = [\n 'var(--sk-primary, #6366f1)',\n '#10b981',\n '#f59e0b',\n '#8b5cf6',\n '#ec4899',\n '#06b6d4',\n '#f97316',\n '#14b8a6',\n ];\n return hues[index % hues.length];\n}\n\nexport default function SiteArchitectureSection({ data }: SiteArchitectureSectionProps) {\n const { totalPages, totalWords, groups } = data;\n const treeRef = useRef<HTMLDivElement>(null);\n const svgRef = useRef<SVGSVGElement>(null);\n const [expandedGroup, setExpandedGroup] = useState<number | null>(null);\n\n // Animate connection lines on scroll\n useEffect(() => {\n gsap.registerPlugin(ScrollTrigger);\n\n const ctx = gsap.context(() => {\n // Animate each branch node in\n gsap.utils.toArray<HTMLElement>('.arch-node').forEach((node, i) => {\n gsap.fromTo(\n node,\n { opacity: 0, scale: 0.8, y: 20 },\n {\n opacity: 1,\n scale: 1,\n y: 0,\n duration: 0.5,\n delay: i * 0.08,\n ease: 'back.out(1.4)',\n scrollTrigger: {\n trigger: treeRef.current,\n start: 'top 70%',\n toggleActions: 'play none none none',\n },\n },\n );\n });\n\n // Animate SVG connection lines drawing in\n gsap.utils.toArray<SVGPathElement>('.arch-line').forEach((line, i) => {\n const length = line.getTotalLength();\n gsap.set(line, { strokeDasharray: length, strokeDashoffset: length });\n gsap.to(line, {\n strokeDashoffset: 0,\n duration: 0.6,\n delay: i * 0.1,\n ease: 'power2.out',\n scrollTrigger: {\n trigger: treeRef.current,\n start: 'top 70%',\n toggleActions: 'play none none none',\n },\n });\n });\n });\n\n return () => ctx.revert();\n }, [groups.length]);\n\n const hasWords = totalWords > 0;\n const subtitle = hasWords\n ? `${totalPages} pages structured across ${groups.length} content ${groups.length === 1 ? 'category' : 'categories'} with ${totalWords.toLocaleString()} words of content.`\n : `${totalPages} pages structured across ${groups.length} content ${groups.length === 1 ? 'category' : 'categories'}.`;\n\n return (\n <section\n className=\"w-full py-20 md:py-28\"\n style={{ background: 'var(--sk-bg, #0a0a0a)' }}\n >\n <div className=\"max-w-6xl 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 Site Architecture\n </h2>\n <p\n className=\"text-lg mb-16 max-w-3xl\"\n style={{ color: 'var(--sk-text-secondary, #a1a1aa)' }}\n >\n {subtitle}\n </p>\n </ScrollReveal>\n\n {/* Visual Tree */}\n <div ref={treeRef} className=\"relative\">\n {/* Root node — the domain */}\n <div className=\"flex justify-center mb-8\">\n <div\n className=\"arch-node relative px-6 py-3 rounded-xl text-center\"\n style={{\n background: 'color-mix(in srgb, var(--sk-primary, #6366f1) 15%, var(--sk-bg, #0a0a0a))',\n border: '2px solid var(--sk-primary, #6366f1)',\n boxShadow: '0 0 30px color-mix(in srgb, var(--sk-primary, #6366f1) 20%, transparent)',\n }}\n >\n <span\n className=\"text-sm font-bold tracking-wide\"\n style={{ color: 'var(--sk-primary, #6366f1)' }}\n >\n /\n </span>\n <span\n className=\"block text-xs mt-0.5\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {totalPages} pages\n </span>\n </div>\n </div>\n\n {/* Branch nodes — each page group */}\n <div className=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4\">\n {groups.map((group, gi) => {\n const color = getBranchColor(gi);\n const isExpanded = expandedGroup === gi;\n const hasChildren = group.pages.length > 0;\n\n return (\n <div\n key={gi}\n className=\"arch-node flex flex-col\"\n >\n {/* Branch connector line (vertical from root) */}\n <div\n className=\"w-px h-6 mx-auto mb-2\"\n style={{\n background: `linear-gradient(to bottom, color-mix(in srgb, ${color} 40%, transparent), ${color})`,\n }}\n />\n\n {/* Branch node */}\n <button\n onClick={() => hasChildren && setExpandedGroup(isExpanded ? null : gi)}\n className=\"relative rounded-xl p-4 text-left transition-all duration-300 cursor-pointer group\"\n style={{\n background: `color-mix(in srgb, ${color} 8%, var(--sk-bg, #0a0a0a))`,\n border: `1.5px solid color-mix(in srgb, ${color} ${isExpanded ? '40' : '20'}%, transparent)`,\n boxShadow: isExpanded\n ? `0 0 20px color-mix(in srgb, ${color} 15%, transparent)`\n : 'none',\n }}\n >\n {/* Count badge */}\n <div\n className=\"absolute -top-2.5 -right-2 px-2 py-0.5 rounded-full text-xs font-bold\"\n style={{\n background: color,\n color: '#000',\n boxShadow: `0 0 10px color-mix(in srgb, ${color} 40%, transparent)`,\n }}\n >\n {group.count}\n </div>\n\n <div className=\"flex items-center gap-2\">\n {/* Branch icon — folder-like indicator */}\n <div\n className=\"w-2 h-2 rounded-full shrink-0\"\n style={{ background: color }}\n />\n <span\n className=\"text-sm font-semibold truncate\"\n style={{ color: 'var(--sk-text-primary, #ffffff)' }}\n >\n {group.label}\n </span>\n </div>\n\n {/* Expand indicator */}\n {hasChildren && (\n <span\n className=\"text-[10px] mt-1 block transition-colors\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {isExpanded ? 'click to collapse' : `${group.count} ${group.count === 1 ? 'page' : 'pages'} — click to expand`}\n </span>\n )}\n </button>\n\n {/* Expanded page list */}\n {isExpanded && hasChildren && (\n <div\n className=\"mt-2 rounded-lg overflow-hidden\"\n style={{\n background: `color-mix(in srgb, ${color} 5%, var(--sk-bg, #0a0a0a))`,\n border: `1px solid color-mix(in srgb, ${color} 15%, transparent)`,\n }}\n >\n {group.pages.map((page, pi) => (\n <div\n key={pi}\n className=\"flex items-center gap-2 px-3 py-1.5\"\n style={{\n borderBottom:\n pi < group.pages.length - 1\n ? `1px solid color-mix(in srgb, ${color} 8%, transparent)`\n : 'none',\n }}\n >\n <div\n className=\"w-1 h-1 rounded-full shrink-0\"\n style={{ background: color, opacity: 0.5 }}\n />\n <span\n className=\"text-xs truncate\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n title={page.title || page.path}\n >\n {page.title || page.path}\n </span>\n </div>\n ))}\n {group.count > group.pages.length && (\n <div\n className=\"px-3 py-1.5 text-xs italic\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)', opacity: 0.6 }}\n >\n +{group.count - group.pages.length} more pages\n </div>\n )}\n </div>\n )}\n </div>\n );\n })}\n </div>\n </div>\n\n {/* Bottom stats bar */}\n <ScrollReveal y={20} delay={0.4}>\n <div\n className=\"mt-12 flex items-center justify-center gap-8 md:gap-12 py-4 px-6 rounded-xl mx-auto max-w-2xl\"\n style={{\n background: 'color-mix(in srgb, var(--sk-primary, #6366f1) 5%, var(--sk-bg, #0a0a0a))',\n border: '1px solid color-mix(in srgb, var(--sk-primary, #6366f1) 15%, transparent)',\n }}\n >\n <div className=\"text-center\">\n <span\n className=\"text-2xl font-bold block\"\n style={{ color: 'var(--sk-primary, #6366f1)' }}\n >\n {totalPages}\n </span>\n <span\n className=\"text-[10px] uppercase tracking-wider block mt-0.5\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n Pages\n </span>\n </div>\n <div\n className=\"w-px h-8\"\n style={{ background: 'color-mix(in srgb, var(--sk-text-tertiary, #71717a) 20%, transparent)' }}\n />\n <div className=\"text-center\">\n <span\n className=\"text-2xl font-bold block\"\n style={{ color: 'var(--sk-primary, #6366f1)' }}\n >\n {groups.length}\n </span>\n <span\n className=\"text-[10px] uppercase tracking-wider block mt-0.5\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n Categories\n </span>\n </div>\n {hasWords && (\n <>\n <div\n className=\"w-px h-8\"\n style={{ background: 'color-mix(in srgb, var(--sk-text-tertiary, #71717a) 20%, transparent)' }}\n />\n <div className=\"text-center\">\n <span\n className=\"text-2xl font-bold block\"\n style={{ color: 'var(--sk-primary, #6366f1)' }}\n >\n {totalWords > 1000 ? `${(totalWords / 1000).toFixed(0)}k` : totalWords}\n </span>\n <span\n className=\"text-[10px] uppercase tracking-wider block mt-0.5\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n Words\n </span>\n </div>\n </>\n )}\n </div>\n </ScrollReveal>\n </div>\n </section>\n );\n}\n"]}
|
|
@@ -340,5 +340,5 @@ function SiteArchitectureSection({ data }) {
|
|
|
340
340
|
}
|
|
341
341
|
|
|
342
342
|
export { SiteArchitectureSection as default };
|
|
343
|
-
//# sourceMappingURL=SiteArchitectureSection-
|
|
344
|
-
//# sourceMappingURL=SiteArchitectureSection-
|
|
343
|
+
//# sourceMappingURL=SiteArchitectureSection-TE22OAWV.js.map
|
|
344
|
+
//# sourceMappingURL=SiteArchitectureSection-TE22OAWV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/portfolio/components/sections/SiteArchitectureSection.tsx"],"names":[],"mappings":"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","file":"SiteArchitectureSection-TE22OAWV.js","sourcesContent":["'use client';\n\nimport React, { useRef, useEffect, useState } from 'react';\nimport gsap from 'gsap';\nimport { ScrollTrigger } from 'gsap/ScrollTrigger';\nimport ScrollReveal from '../primitives/ScrollReveal';\nimport GlassCard from '../primitives/GlassCard';\n\ninterface PageGroup {\n label: string;\n count: number;\n // path is optional: PortfolioPage strips raw client-site paths before they\n // reach this client component so they never enter the RSC flight payload\n // (Googlebot crawls path-like strings against the host site → 404 floods).\n pages: Array<{ path?: string; title: string }>;\n}\n\nexport interface SiteArchitectureData {\n totalPages: number;\n totalWords: number;\n groups: PageGroup[];\n}\n\ninterface SiteArchitectureSectionProps {\n data: SiteArchitectureData;\n}\n\n/** Generates a pleasing color from the brand palette for each branch */\nfunction getBranchColor(index: number): string {\n const hues = [\n 'var(--sk-primary, #6366f1)',\n '#10b981',\n '#f59e0b',\n '#8b5cf6',\n '#ec4899',\n '#06b6d4',\n '#f97316',\n '#14b8a6',\n ];\n return hues[index % hues.length];\n}\n\nexport default function SiteArchitectureSection({ data }: SiteArchitectureSectionProps) {\n const { totalPages, totalWords, groups } = data;\n const treeRef = useRef<HTMLDivElement>(null);\n const svgRef = useRef<SVGSVGElement>(null);\n const [expandedGroup, setExpandedGroup] = useState<number | null>(null);\n\n // Animate connection lines on scroll\n useEffect(() => {\n gsap.registerPlugin(ScrollTrigger);\n\n const ctx = gsap.context(() => {\n // Animate each branch node in\n gsap.utils.toArray<HTMLElement>('.arch-node').forEach((node, i) => {\n gsap.fromTo(\n node,\n { opacity: 0, scale: 0.8, y: 20 },\n {\n opacity: 1,\n scale: 1,\n y: 0,\n duration: 0.5,\n delay: i * 0.08,\n ease: 'back.out(1.4)',\n scrollTrigger: {\n trigger: treeRef.current,\n start: 'top 70%',\n toggleActions: 'play none none none',\n },\n },\n );\n });\n\n // Animate SVG connection lines drawing in\n gsap.utils.toArray<SVGPathElement>('.arch-line').forEach((line, i) => {\n const length = line.getTotalLength();\n gsap.set(line, { strokeDasharray: length, strokeDashoffset: length });\n gsap.to(line, {\n strokeDashoffset: 0,\n duration: 0.6,\n delay: i * 0.1,\n ease: 'power2.out',\n scrollTrigger: {\n trigger: treeRef.current,\n start: 'top 70%',\n toggleActions: 'play none none none',\n },\n });\n });\n });\n\n return () => ctx.revert();\n }, [groups.length]);\n\n const hasWords = totalWords > 0;\n const subtitle = hasWords\n ? `${totalPages} pages structured across ${groups.length} content ${groups.length === 1 ? 'category' : 'categories'} with ${totalWords.toLocaleString()} words of content.`\n : `${totalPages} pages structured across ${groups.length} content ${groups.length === 1 ? 'category' : 'categories'}.`;\n\n return (\n <section\n className=\"w-full py-20 md:py-28\"\n style={{ background: 'var(--sk-bg, #0a0a0a)' }}\n >\n <div className=\"max-w-6xl 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 Site Architecture\n </h2>\n <p\n className=\"text-lg mb-16 max-w-3xl\"\n style={{ color: 'var(--sk-text-secondary, #a1a1aa)' }}\n >\n {subtitle}\n </p>\n </ScrollReveal>\n\n {/* Visual Tree */}\n <div ref={treeRef} className=\"relative\">\n {/* Root node — the domain */}\n <div className=\"flex justify-center mb-8\">\n <div\n className=\"arch-node relative px-6 py-3 rounded-xl text-center\"\n style={{\n background: 'color-mix(in srgb, var(--sk-primary, #6366f1) 15%, var(--sk-bg, #0a0a0a))',\n border: '2px solid var(--sk-primary, #6366f1)',\n boxShadow: '0 0 30px color-mix(in srgb, var(--sk-primary, #6366f1) 20%, transparent)',\n }}\n >\n <span\n className=\"text-sm font-bold tracking-wide\"\n style={{ color: 'var(--sk-primary, #6366f1)' }}\n >\n /\n </span>\n <span\n className=\"block text-xs mt-0.5\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {totalPages} pages\n </span>\n </div>\n </div>\n\n {/* Branch nodes — each page group */}\n <div className=\"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4\">\n {groups.map((group, gi) => {\n const color = getBranchColor(gi);\n const isExpanded = expandedGroup === gi;\n const hasChildren = group.pages.length > 0;\n\n return (\n <div\n key={gi}\n className=\"arch-node flex flex-col\"\n >\n {/* Branch connector line (vertical from root) */}\n <div\n className=\"w-px h-6 mx-auto mb-2\"\n style={{\n background: `linear-gradient(to bottom, color-mix(in srgb, ${color} 40%, transparent), ${color})`,\n }}\n />\n\n {/* Branch node */}\n <button\n onClick={() => hasChildren && setExpandedGroup(isExpanded ? null : gi)}\n className=\"relative rounded-xl p-4 text-left transition-all duration-300 cursor-pointer group\"\n style={{\n background: `color-mix(in srgb, ${color} 8%, var(--sk-bg, #0a0a0a))`,\n border: `1.5px solid color-mix(in srgb, ${color} ${isExpanded ? '40' : '20'}%, transparent)`,\n boxShadow: isExpanded\n ? `0 0 20px color-mix(in srgb, ${color} 15%, transparent)`\n : 'none',\n }}\n >\n {/* Count badge */}\n <div\n className=\"absolute -top-2.5 -right-2 px-2 py-0.5 rounded-full text-xs font-bold\"\n style={{\n background: color,\n color: '#000',\n boxShadow: `0 0 10px color-mix(in srgb, ${color} 40%, transparent)`,\n }}\n >\n {group.count}\n </div>\n\n <div className=\"flex items-center gap-2\">\n {/* Branch icon — folder-like indicator */}\n <div\n className=\"w-2 h-2 rounded-full shrink-0\"\n style={{ background: color }}\n />\n <span\n className=\"text-sm font-semibold truncate\"\n style={{ color: 'var(--sk-text-primary, #ffffff)' }}\n >\n {group.label}\n </span>\n </div>\n\n {/* Expand indicator */}\n {hasChildren && (\n <span\n className=\"text-[10px] mt-1 block transition-colors\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n {isExpanded ? 'click to collapse' : `${group.count} ${group.count === 1 ? 'page' : 'pages'} — click to expand`}\n </span>\n )}\n </button>\n\n {/* Expanded page list */}\n {isExpanded && hasChildren && (\n <div\n className=\"mt-2 rounded-lg overflow-hidden\"\n style={{\n background: `color-mix(in srgb, ${color} 5%, var(--sk-bg, #0a0a0a))`,\n border: `1px solid color-mix(in srgb, ${color} 15%, transparent)`,\n }}\n >\n {group.pages.map((page, pi) => (\n <div\n key={pi}\n className=\"flex items-center gap-2 px-3 py-1.5\"\n style={{\n borderBottom:\n pi < group.pages.length - 1\n ? `1px solid color-mix(in srgb, ${color} 8%, transparent)`\n : 'none',\n }}\n >\n <div\n className=\"w-1 h-1 rounded-full shrink-0\"\n style={{ background: color, opacity: 0.5 }}\n />\n <span\n className=\"text-xs truncate\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n title={page.title || page.path}\n >\n {page.title || page.path}\n </span>\n </div>\n ))}\n {group.count > group.pages.length && (\n <div\n className=\"px-3 py-1.5 text-xs italic\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)', opacity: 0.6 }}\n >\n +{group.count - group.pages.length} more pages\n </div>\n )}\n </div>\n )}\n </div>\n );\n })}\n </div>\n </div>\n\n {/* Bottom stats bar */}\n <ScrollReveal y={20} delay={0.4}>\n <div\n className=\"mt-12 flex items-center justify-center gap-8 md:gap-12 py-4 px-6 rounded-xl mx-auto max-w-2xl\"\n style={{\n background: 'color-mix(in srgb, var(--sk-primary, #6366f1) 5%, var(--sk-bg, #0a0a0a))',\n border: '1px solid color-mix(in srgb, var(--sk-primary, #6366f1) 15%, transparent)',\n }}\n >\n <div className=\"text-center\">\n <span\n className=\"text-2xl font-bold block\"\n style={{ color: 'var(--sk-primary, #6366f1)' }}\n >\n {totalPages}\n </span>\n <span\n className=\"text-[10px] uppercase tracking-wider block mt-0.5\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n Pages\n </span>\n </div>\n <div\n className=\"w-px h-8\"\n style={{ background: 'color-mix(in srgb, var(--sk-text-tertiary, #71717a) 20%, transparent)' }}\n />\n <div className=\"text-center\">\n <span\n className=\"text-2xl font-bold block\"\n style={{ color: 'var(--sk-primary, #6366f1)' }}\n >\n {groups.length}\n </span>\n <span\n className=\"text-[10px] uppercase tracking-wider block mt-0.5\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n Categories\n </span>\n </div>\n {hasWords && (\n <>\n <div\n className=\"w-px h-8\"\n style={{ background: 'color-mix(in srgb, var(--sk-text-tertiary, #71717a) 20%, transparent)' }}\n />\n <div className=\"text-center\">\n <span\n className=\"text-2xl font-bold block\"\n style={{ color: 'var(--sk-primary, #6366f1)' }}\n >\n {totalWords > 1000 ? `${(totalWords / 1000).toFixed(0)}k` : totalWords}\n </span>\n <span\n className=\"text-[10px] uppercase tracking-wider block mt-0.5\"\n style={{ color: 'var(--sk-text-tertiary, #71717a)' }}\n >\n Words\n </span>\n </div>\n </>\n )}\n </div>\n </ScrollReveal>\n </div>\n </section>\n );\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sonordev/agency-site-kit — Cache tag contract
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for the Next.js cache tag attached to every
|
|
5
|
+
* portfolio fetch. The Sonor Portal sends this tag in its revalidation
|
|
6
|
+
* webhook payload when portfolio content changes, so one revalidateTag()
|
|
7
|
+
* busts the list, detail, categories, brand-config, and sitemap data caches
|
|
8
|
+
* in a single call.
|
|
9
|
+
*
|
|
10
|
+
* The Portal side mirrors this value in portfolio.service.ts
|
|
11
|
+
* (sonor-api-nestjs) — keep them in sync.
|
|
12
|
+
*/
|
|
13
|
+
declare const PORTFOLIO_CACHE_TAG = "portfolio";
|
|
14
|
+
|
|
15
|
+
export { PORTFOLIO_CACHE_TAG as P };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @sonordev/agency-site-kit — Cache tag contract
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for the Next.js cache tag attached to every
|
|
5
|
+
* portfolio fetch. The Sonor Portal sends this tag in its revalidation
|
|
6
|
+
* webhook payload when portfolio content changes, so one revalidateTag()
|
|
7
|
+
* busts the list, detail, categories, brand-config, and sitemap data caches
|
|
8
|
+
* in a single call.
|
|
9
|
+
*
|
|
10
|
+
* The Portal side mirrors this value in portfolio.service.ts
|
|
11
|
+
* (sonor-api-nestjs) — keep them in sync.
|
|
12
|
+
*/
|
|
13
|
+
declare const PORTFOLIO_CACHE_TAG = "portfolio";
|
|
14
|
+
|
|
15
|
+
export { PORTFOLIO_CACHE_TAG as P };
|
|
@@ -490,11 +490,29 @@ var BeforeAfterSection = dynamic(() => import('./BeforeAfterSection-6BHFLY4Y.js'
|
|
|
490
490
|
var MetricsTimelineSection = dynamic(() => import('./MetricsTimelineSection-6BT5GNFV.js'), { ssr: true });
|
|
491
491
|
var ConversionFunnelSection = dynamic(() => import('./ConversionFunnelSection-D3GE4NKE.js'), { ssr: true });
|
|
492
492
|
var PerformanceSection = dynamic(() => import('./PerformanceSection-MGCEIXDX.js'), { ssr: true });
|
|
493
|
-
var SiteArchitectureSection = dynamic(() => import('./SiteArchitectureSection-
|
|
493
|
+
var SiteArchitectureSection = dynamic(() => import('./SiteArchitectureSection-TE22OAWV.js'), { ssr: true });
|
|
494
494
|
var SpeedComparisonSection = dynamic(() => import('./SpeedComparisonSection-Y3K7OFZQ.js'), { ssr: true });
|
|
495
495
|
var DesignSystemSection = dynamic(() => import('./DesignSystemSection-2R5BRBGO.js'), { ssr: true });
|
|
496
496
|
var DetailsSection = dynamic(() => import('./DetailsSection-A6PZQUQL.js'), { ssr: true });
|
|
497
497
|
var CTASection = dynamic(() => import('./CTASection-BJA72XIL.js'), { ssr: true });
|
|
498
|
+
function humanizeArchPageEntry(page) {
|
|
499
|
+
const title = (page?.title || "").trim();
|
|
500
|
+
if (title && !title.startsWith("/")) return { title };
|
|
501
|
+
const source = title || (page?.path || "").trim();
|
|
502
|
+
const lastSegment = source.split(/[?#]/)[0].split("/").filter(Boolean).pop() || "";
|
|
503
|
+
const label = lastSegment.replace(/\.(html?|php|aspx?)$/i, "").replace(/[-_]+/g, " ").trim().replace(/\b\w/g, (c) => c.toUpperCase());
|
|
504
|
+
return { title: label || "Home" };
|
|
505
|
+
}
|
|
506
|
+
function sanitizeSiteArchitectureData(data) {
|
|
507
|
+
if (!data || !Array.isArray(data.groups)) return data;
|
|
508
|
+
return {
|
|
509
|
+
...data,
|
|
510
|
+
groups: data.groups.map((group) => ({
|
|
511
|
+
...group,
|
|
512
|
+
pages: Array.isArray(group.pages) ? group.pages.map(humanizeArchPageEntry) : []
|
|
513
|
+
}))
|
|
514
|
+
};
|
|
515
|
+
}
|
|
498
516
|
function renderSection(section, item, index) {
|
|
499
517
|
const key = `${section.sectionType}-${index}`;
|
|
500
518
|
switch (section.sectionType) {
|
|
@@ -539,7 +557,7 @@ function renderSection(section, item, index) {
|
|
|
539
557
|
case "portfolioSpeedComparison":
|
|
540
558
|
return /* @__PURE__ */ jsx(SpeedComparisonSection, { data: section.data }, key);
|
|
541
559
|
case "portfolioSiteArchitecture":
|
|
542
|
-
return /* @__PURE__ */ jsx(SiteArchitectureSection, { data: section.data }, key);
|
|
560
|
+
return /* @__PURE__ */ jsx(SiteArchitectureSection, { data: sanitizeSiteArchitectureData(section.data) }, key);
|
|
543
561
|
case "portfolioDesignSystem":
|
|
544
562
|
return /* @__PURE__ */ jsx(DesignSystemSection, { data: section.data }, key);
|
|
545
563
|
case "portfolioDetails":
|
|
@@ -608,5 +626,5 @@ var PORTFOLIO_SECTION_TYPES = [
|
|
|
608
626
|
];
|
|
609
627
|
|
|
610
628
|
export { PORTFOLIO_SECTION_TYPES, PortfolioPage };
|
|
611
|
-
//# sourceMappingURL=chunk-
|
|
612
|
-
//# sourceMappingURL=chunk-
|
|
629
|
+
//# sourceMappingURL=chunk-2UNKXWQM.js.map
|
|
630
|
+
//# sourceMappingURL=chunk-2UNKXWQM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/portfolio/components/primitives/SplitHeadline.tsx","../src/portfolio/components/primitives/DeviceTrifolio.tsx","../src/portfolio/components/sections/HeroSection.tsx","../src/portfolio/components/PortfolioPage.tsx","../src/types.ts"],"names":["gsap","useRef","useEffect","jsxs","jsx","ScrollTrigger"],"mappings":"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","file":"chunk-2UNKXWQM.js","sourcesContent":["'use client';\n\nimport React, { useRef, useEffect, useMemo } from 'react';\nimport gsap from 'gsap';\nimport { ScrollTrigger } from 'gsap/ScrollTrigger';\n\ninterface SplitHeadlineProps {\n children: string;\n tag?: 'h1' | 'h2' | 'h3' | 'h4' | 'p';\n className?: string;\n style?: React.CSSProperties;\n delay?: number;\n duration?: number;\n staggerAmount?: number;\n}\n\nexport default function SplitHeadline({\n children,\n tag: Tag = 'h2',\n className,\n style,\n delay = 0,\n duration = 0.8,\n staggerAmount = 0.02,\n}: SplitHeadlineProps) {\n const ref = useRef<HTMLElement>(null);\n\n // Split text into words and characters, preserving spaces\n const splitContent = useMemo(() => {\n const words = children.split(' ');\n return words.map((word, wi) => (\n <span key={wi} style={{ display: 'inline-block', whiteSpace: 'nowrap' }}>\n {word.split('').map((char, ci) => (\n <span\n key={ci}\n className=\"split-char\"\n style={{ display: 'inline-block' }}\n >\n {char}\n </span>\n ))}\n {wi < words.length - 1 && (\n <span style={{ display: 'inline-block' }}> </span>\n )}\n </span>\n ));\n }, [children]);\n\n useEffect(() => {\n gsap.registerPlugin(ScrollTrigger);\n\n const el = ref.current;\n if (!el) return;\n\n // Respect prefers-reduced-motion\n const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n if (prefersReducedMotion) {\n gsap.set(el.querySelectorAll('.split-char'), { opacity: 1, y: 0 });\n return;\n }\n\n const chars = el.querySelectorAll('.split-char');\n\n const ctx = gsap.context(() => {\n gsap.fromTo(\n chars,\n {\n opacity: 0,\n y: 20,\n },\n {\n opacity: 1,\n y: 0,\n duration,\n delay,\n stagger: staggerAmount,\n ease: 'power2.out',\n scrollTrigger: {\n trigger: el,\n start: 'top 85%',\n toggleActions: 'play none none none',\n },\n },\n );\n }, el);\n\n return () => ctx.revert();\n }, [delay, duration, staggerAmount]);\n\n return (\n <Tag\n ref={ref as React.RefObject<any>}\n className={className}\n style={{\n overflowX: 'clip',\n overflowY: 'hidden',\n overflowWrap: 'break-word',\n wordBreak: 'break-word',\n ...style,\n }}\n >\n {splitContent}\n </Tag>\n );\n}\n","'use client';\n\nimport React, { useRef, useEffect, useState, useCallback } from 'react';\nimport gsap from 'gsap';\nimport { ScrollTrigger } from 'gsap/ScrollTrigger';\n\ninterface DeviceTrifolioProps {\n url?: string;\n screenshots?: {\n desktop?: string;\n tablet?: string;\n mobile?: string;\n };\n className?: string;\n disableAnimation?: boolean;\n}\n\n// ─── Hooks ───────────────────────────────────────────────────────────────────\n\nfunction useScaledIframe(viewportWidth: number) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [scale, setScale] = useState(1);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n const updateScale = () => {\n const containerWidth = container.offsetWidth;\n setScale(containerWidth / viewportWidth);\n };\n\n updateScale();\n const resizeObserver = new ResizeObserver(updateScale);\n resizeObserver.observe(container);\n return () => resizeObserver.disconnect();\n }, [viewportWidth]);\n\n return { containerRef, scale };\n}\n\nfunction useScrollSafeIframe() {\n const [isLoaded, setIsLoaded] = useState(false);\n const [iframeFailed, setIframeFailed] = useState(false);\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const loadTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const handleLoad = useCallback(() => {\n const iframe = iframeRef.current;\n if (!iframe) return;\n\n // Wait for iframe to paint, then verify it rendered real content\n loadTimerRef.current = setTimeout(() => {\n let isCrossOrigin = false;\n\n try {\n // Try accessing contentDocument — cross-origin sites throw here\n const doc = iframe.contentDocument;\n if (!doc || !doc.body) {\n setIframeFailed(true);\n return;\n }\n\n // Same-origin access succeeded. This means either:\n // 1. A same-origin site loaded (e.g., our own site in dev)\n // 2. Browser rendered its own error page (X-Frame-Options block, connection refused, etc.)\n //\n // Browser error pages are same-origin and have short/generic content.\n // Real sites have <title>, many DOM nodes, scripts, styles, etc.\n const title = doc.title || '';\n const bodyText = doc.body?.innerText?.trim() || '';\n const numElements = doc.querySelectorAll('*').length;\n\n // Heuristic: real sites have a meaningful title AND many DOM elements\n // Browser error pages have very few elements and generic/empty titles\n if (numElements > 20 && title.length > 0 && bodyText.length > 50) {\n setIsLoaded(true);\n } else {\n setIframeFailed(true);\n }\n } catch {\n isCrossOrigin = true;\n }\n\n if (isCrossOrigin) {\n // Cross-origin: the real remote site loaded (can't be a browser error page\n // since those are always same-origin). This is the success case.\n setIsLoaded(true);\n }\n }, 2000);\n }, []);\n\n const handleError = useCallback(() => {\n setIframeFailed(true);\n if (loadTimerRef.current) clearTimeout(loadTimerRef.current);\n }, []);\n\n // Cleanup timer on unmount\n useEffect(() => {\n return () => {\n if (loadTimerRef.current) clearTimeout(loadTimerRef.current);\n };\n }, []);\n\n const wrapperStyle: React.CSSProperties = {\n position: 'absolute',\n left: 0,\n top: 0,\n zIndex: 1,\n overflow: 'hidden',\n width: '100%',\n height: '100%',\n };\n\n const iframeStyle: React.CSSProperties = {};\n\n return { iframeRef, handleLoad, handleError, wrapperStyle, iframeStyle, isLoaded, iframeFailed };\n}\n\n// ─── Device Frames ───────────────────────────────────────────────────────────\n\n/**\n * Hook that detects if an iframe successfully loaded real content.\n * Cross-origin = success (real site loaded). Same-origin with minimal DOM = blocked/error.\n */\nfunction useIframeLoadDetection() {\n const [loaded, setLoaded] = useState(false);\n const iframeRef = useRef<HTMLIFrameElement>(null);\n\n const onLoad = useCallback(() => {\n const iframe = iframeRef.current;\n if (!iframe) return;\n\n // Delay check to let the iframe paint\n setTimeout(() => {\n try {\n // If we can access contentDocument, it's same-origin.\n // Real sites are cross-origin and throw here → catch block → success.\n const doc = iframe.contentDocument;\n if (!doc?.body) { return; } // blocked\n const numElements = doc.querySelectorAll('*').length;\n // Browser error pages have very few elements. Real same-origin sites have many.\n if (numElements > 20) setLoaded(true);\n } catch {\n // Cross-origin error = the real remote site loaded successfully\n setLoaded(true);\n }\n }, 1500);\n }, []);\n\n return { iframeRef, loaded, onLoad };\n}\n\nfunction MacBookFrame({ url, screenshot }: { url: string; screenshot?: string }) {\n const viewportWidth = 1440;\n const viewportHeight = 900;\n const { containerRef, scale } = useScaledIframe(viewportWidth);\n const { iframeRef, loaded: iframeLoaded, onLoad: onIframeLoad } = useIframeLoadDetection();\n\n return (\n <div className=\"w-full\">\n <div\n className=\"relative rounded-t-[10px] p-[4px] pb-0\"\n style={{\n background: 'linear-gradient(135deg, #e8e8ed 0%, #d1d1d6 100%)',\n boxShadow: '0 -4px 30px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.9)',\n }}\n >\n <div\n className=\"relative rounded-t-[7px] px-[8px] pt-[8px] pb-0\"\n style={{ background: '#0a0a0a' }}\n >\n <div\n className=\"absolute top-0 left-1/2 -translate-x-1/2 w-[70px] h-[18px] flex items-center justify-center z-10\"\n style={{ background: '#0a0a0a', borderRadius: '0 0 10px 10px' }}\n >\n <div className=\"w-[5px] h-[5px] rounded-full\" style={{ background: '#2a3a2a', boxShadow: '0 0 0 1px #1a1a1a' }} />\n </div>\n\n <div ref={containerRef} className=\"relative overflow-hidden rounded-t-[3px]\" style={{ aspectRatio: `${viewportWidth}/${viewportHeight}`, background: '#0a0a0a' }}>\n {screenshot && <img src={screenshot} alt=\"Desktop preview\" style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'top center', display: 'block', position: 'absolute' as const, inset: 0, zIndex: 2, opacity: iframeLoaded ? 0 : 1, transition: 'opacity 0.8s ease', pointerEvents: 'none' as const }} />}\n {url && <iframe src={url} title=\"Desktop\" loading=\"eager\" scrolling=\"no\" tabIndex={-1} sandbox=\"allow-scripts allow-same-origin\" ref={iframeRef} onLoad={onIframeLoad} className=\"border-0 pointer-events-none\" style={{ position: 'absolute', top: 0, left: 0, width: `${viewportWidth}px`, height: `${viewportHeight}px`, transformOrigin: 'top left', transform: `scale(${scale})` }} />}\n </div>\n </div>\n </div>\n\n {/* Black chin */}\n <div className=\"h-[8px]\" style={{ background: '#0a0a0a', boxShadow: '0 1px 4px rgba(0,0,0,0.3)' }} />\n\n {/* Silver base */}\n <div\n className=\"relative h-[12px] rounded-b-[10px]\"\n style={{\n background: 'linear-gradient(to bottom, #e0e0e5, #c8c8cd 20%, #b0b0b5 80%, #a0a0a5)',\n boxShadow: '0 4px 15px rgba(0,0,0,0.3)',\n }}\n >\n <div\n className=\"absolute top-0 left-1/2 -translate-x-1/2 w-[25%] h-[4px] rounded-b-[4px]\"\n style={{ background: 'linear-gradient(to bottom, #909095, #a8a8ad)' }}\n />\n </div>\n </div>\n );\n}\n\nfunction IPadFrame({ url, screenshot }: { url: string; screenshot?: string }) {\n const viewportWidth = 768;\n const viewportHeight = 1024;\n const { containerRef, scale } = useScaledIframe(viewportWidth);\n const { iframeRef, loaded: iframeLoaded, onLoad: onIframeLoad } = useIframeLoadDetection();\n\n return (\n <div className=\"relative p-[1.5%]\" style={{ background: 'linear-gradient(135deg, #e8e8ed 0%, #d1d1d6 100%)', borderRadius: '8% / 6%', boxShadow: '0 30px 60px -15px rgba(0,0,0,0.4), 0 0 0 1px rgba(255,255,255,0.9) inset, inset 0 1px 0 rgba(255,255,255,0.8)' }}>\n <div className=\"relative p-[2%]\" style={{ background: '#0a0a0a', borderRadius: '6% / 4.5%' }}>\n <div className=\"absolute top-[1.2%] left-1/2 -translate-x-1/2 w-[1.8%] aspect-square rounded-full z-10\" style={{ background: '#1a1a1f' }} />\n <div ref={containerRef} className=\"relative overflow-hidden\" style={{ borderRadius: '2%', aspectRatio: `${viewportWidth}/${viewportHeight}`, background: '#0a0a0a' }}>\n {screenshot && <img src={screenshot} alt=\"Tablet preview\" style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'top center', display: 'block', position: 'absolute' as const, inset: 0, zIndex: 2, opacity: iframeLoaded ? 0 : 1, transition: 'opacity 0.8s ease', pointerEvents: 'none' as const }} />}\n {url && <iframe src={url} title=\"Tablet\" loading=\"eager\" scrolling=\"no\" tabIndex={-1} sandbox=\"allow-scripts allow-same-origin\" ref={iframeRef} onLoad={onIframeLoad} className=\"border-0 pointer-events-none\" style={{ position: 'absolute', top: 0, left: 0, width: `${viewportWidth}px`, height: `${viewportHeight}px`, transformOrigin: 'top left', transform: `scale(${scale})` }} />}\n </div>\n </div>\n </div>\n );\n}\n\nfunction IPhoneFrame({ url, screenshot }: { url: string; screenshot?: string }) {\n const viewportWidth = 393;\n const viewportHeight = 852;\n const { containerRef, scale } = useScaledIframe(viewportWidth);\n const { iframeRef, loaded: iframeLoaded, onLoad: onIframeLoad } = useIframeLoadDetection();\n\n return (\n <div\n className=\"relative p-[2.5%]\"\n style={{\n background: 'linear-gradient(135deg, #e8e8ed 0%, #d1d1d6 100%)',\n borderRadius: '18% / 8%',\n boxShadow:\n '0 30px 60px -15px rgba(0,0,0,0.4), 0 0 0 1px rgba(255,255,255,0.9) inset, inset 0 1px 0 rgba(255,255,255,0.8)',\n }}\n >\n {/* Side buttons */}\n <div className=\"absolute left-0 top-[18%] w-[1%] h-[6%] rounded-l-sm\" style={{ background: '#c8c8cd' }} />\n <div className=\"absolute left-0 top-[26%] w-[1%] h-[10%] rounded-l-sm\" style={{ background: '#c8c8cd' }} />\n <div className=\"absolute left-0 top-[38%] w-[1%] h-[10%] rounded-l-sm\" style={{ background: '#c8c8cd' }} />\n <div className=\"absolute right-0 top-[22%] w-[1%] h-[12%] rounded-r-sm\" style={{ background: '#c8c8cd' }} />\n\n {/* Black bezel */}\n <div\n className=\"relative p-[3%]\"\n style={{ background: '#0a0a0a', borderRadius: '14% / 6%' }}\n >\n {/* Dynamic Island */}\n <div\n className=\"absolute top-[2.5%] left-1/2 -translate-x-1/2 w-[28%] h-[3.5%] rounded-full z-10\"\n style={{ background: '#1a1a1a' }}\n />\n\n <div ref={containerRef} className=\"relative overflow-hidden\" style={{ borderRadius: '8% / 4%', aspectRatio: `${viewportWidth}/${viewportHeight}`, background: '#0a0a0a' }}>\n {screenshot && <img src={screenshot} alt=\"Mobile preview\" style={{ width: '100%', height: '100%', objectFit: 'cover', objectPosition: 'top center', display: 'block', position: 'absolute' as const, inset: 0, zIndex: 2, opacity: iframeLoaded ? 0 : 1, transition: 'opacity 0.8s ease', pointerEvents: 'none' as const }} />}\n {url && <iframe src={url} title=\"Mobile\" loading=\"eager\" scrolling=\"no\" tabIndex={-1} sandbox=\"allow-scripts allow-same-origin\" ref={iframeRef} onLoad={onIframeLoad} className=\"border-0 pointer-events-none\" style={{ position: 'absolute', top: 0, left: 0, width: `${viewportWidth}px`, height: `${viewportHeight}px`, transformOrigin: 'top left', transform: `scale(${scale})` }} />}\n </div>\n\n {/* Home indicator */}\n <div\n className=\"absolute bottom-[2%] left-1/2 -translate-x-1/2 w-[34%] h-[1%] rounded-full\"\n style={{ background: 'rgba(255,255,255,0.25)' }}\n />\n </div>\n </div>\n );\n}\n\n// ─── Main Component ──────────────────────────────────────────────────────────\n\nexport default function DeviceTrifolio({\n url,\n screenshots,\n className = '',\n disableAnimation = false,\n}: DeviceTrifolioProps) {\n const trifolioRef = useRef<HTMLDivElement>(null);\n\n // Pass URL directly — iframes render immediately\n const frameUrl = url || '';\n\n // GSAP ScrollTrigger animation for device entrance\n useEffect(() => {\n gsap.registerPlugin(ScrollTrigger);\n\n const container = trifolioRef.current;\n if (!container || disableAnimation) return;\n\n const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n if (prefersReducedMotion) return;\n\n const macbook = container.querySelector<HTMLElement>('[data-device=\"macbook\"]');\n const ipad = container.querySelector<HTMLElement>('[data-device=\"ipad\"]');\n const iphone = container.querySelector<HTMLElement>('[data-device=\"iphone\"]');\n\n if (!macbook || !ipad || !iphone) return;\n\n const ctx = gsap.context(() => {\n gsap.set(container, { opacity: 0 });\n gsap.set(macbook, { opacity: 0, y: 40 });\n gsap.set(ipad, { opacity: 0, x: -60, y: 30 });\n gsap.set(iphone, { opacity: 0, x: 60, y: 30 });\n\n const tl = gsap.timeline({\n scrollTrigger: {\n trigger: container,\n start: 'top bottom',\n toggleActions: 'play none none none',\n },\n });\n\n tl.to(container, { opacity: 1, duration: 0.3 })\n .to(macbook, { opacity: 1, y: 0, duration: 0.7, ease: 'power2.out' }, 0.1)\n .to(ipad, { opacity: 1, x: 0, y: 0, duration: 0.6, ease: 'power2.out' }, 0.25)\n .to(iphone, { opacity: 1, x: 0, y: 0, duration: 0.6, ease: 'power2.out' }, 0.4);\n }, container);\n\n return () => ctx.revert();\n }, [disableAnimation]);\n\n return (\n <div\n ref={trifolioRef}\n data-screenshot-target=\"device-trifolio\"\n className={`relative w-full min-w-0 max-w-full overflow-x-clip ${className}`}\n style={{ aspectRatio: '11/5', minHeight: '200px' }}\n >\n {/* MacBook Pro - Center Back */}\n <div\n data-device=\"macbook\"\n className=\"absolute left-1/2 -translate-x-1/2 bottom-0 w-[65%] z-10\"\n >\n <MacBookFrame url={frameUrl} screenshot={screenshots?.desktop} />\n </div>\n\n {/* iPad - Front Left */}\n <div\n data-device=\"ipad\"\n className=\"absolute left-[8%] bottom-0 w-[28%] z-20\"\n >\n <IPadFrame url={frameUrl} screenshot={screenshots?.tablet} />\n </div>\n\n {/* iPhone - Front Right */}\n <div\n data-device=\"iphone\"\n className=\"absolute right-[10%] bottom-0 w-[14%] z-30\"\n >\n <IPhoneFrame url={frameUrl} screenshot={screenshots?.mobile} />\n </div>\n </div>\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';\nimport DeviceTrifolio from '../primitives/DeviceTrifolio';\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\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 handles its own entrance animation via DeviceTrifolio component\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 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 <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?.replace(/[-_]/g, ' ').replace(/\\b\\w/g, (c: string) => c.toUpperCase())}\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 </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 ref={deviceRef} 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","/**\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 PerformanceSection = dynamic(() => import('./sections/PerformanceSection'), { ssr: true });\nconst SiteArchitectureSection = dynamic(() => import('./sections/SiteArchitectureSection'), { ssr: true });\nconst SpeedComparisonSection = dynamic(() => import('./sections/SpeedComparisonSection'), { ssr: true });\nconst DesignSystemSection = dynamic(() => import('./sections/DesignSystemSection'), { 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\n/**\n * Site-architecture entries arrive from generation with raw client-site paths\n * (often title === path, e.g. \"/wheels/amp-tires\"). Raw paths must never reach\n * the RSC flight payload: Googlebot extracts URL-like strings from it and\n * crawls them against the AGENCY site's origin, flooding Search Console with\n * 404s (seen on upforge.io, June 2026). Sanitization therefore happens HERE,\n * at the server→client props boundary — doing it inside the client component\n * would be too late, the props are already serialized into the page.\n */\nfunction humanizeArchPageEntry(page: { path?: string; title?: string }): { title: string } {\n const title = (page?.title || '').trim();\n if (title && !title.startsWith('/')) return { title };\n const source = title || (page?.path || '').trim();\n const lastSegment = source.split(/[?#]/)[0].split('/').filter(Boolean).pop() || '';\n const label = lastSegment\n .replace(/\\.(html?|php|aspx?)$/i, '')\n .replace(/[-_]+/g, ' ')\n .trim()\n .replace(/\\b\\w/g, (c) => c.toUpperCase());\n return { title: label || 'Home' };\n}\n\nfunction sanitizeSiteArchitectureData(data: any): any {\n if (!data || !Array.isArray(data.groups)) return data;\n return {\n ...data,\n groups: data.groups.map((group: any) => ({\n ...group,\n pages: Array.isArray(group.pages) ? group.pages.map(humanizeArchPageEntry) : [],\n })),\n };\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 'portfolioPerformance':\n return <PerformanceSection key={key} data={section.data as any} />;\n case 'portfolioSpeedComparison':\n return <SpeedComparisonSection key={key} data={section.data as any} />;\n case 'portfolioSiteArchitecture':\n return <SiteArchitectureSection key={key} data={sanitizeSiteArchitectureData(section.data) as any} />;\n case 'portfolioDesignSystem':\n return <DesignSystemSection key={key} data={section.data as any} />;\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\n// Canonical display order — ensures consistent rendering regardless of API order\nconst SECTION_ORDER: Record<string, number> = {\n portfolioHero: 0,\n portfolioChallenges: 1,\n portfolioStrategy: 2,\n portfolioResults: 3,\n portfolioPerformance: 4,\n portfolioSpeedComparison: 5,\n portfolioSiteArchitecture: 6,\n portfolioTechStack: 7,\n portfolioDesignSystem: 8,\n portfolioServices: 9,\n portfolioBeforeAfter: 10,\n portfolioTestimonial: 11,\n portfolioMetricsTimeline: 12,\n portfolioConversionFunnel: 13,\n portfolioDetails: 11,\n portfolioSeo: 12,\n portfolioCta: 13,\n};\n\nexport default function PortfolioPage({ item }: PortfolioPageProps) {\n const sortedSections = [...item.sections].sort(\n (a, b) => (SECTION_ORDER[a.sectionType] ?? 99) - (SECTION_ORDER[b.sectionType] ?? 99)\n );\n\n return (\n <article className=\"flex w-full min-w-0 max-w-full flex-col overflow-x-clip\">\n {sortedSections.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 'portfolioPerformance',\n 'portfolioSpeedComparison',\n 'portfolioSiteArchitecture',\n 'portfolioDesignSystem',\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 /** Sonor project ID (present for items generated from a managed project) */\n project_id: 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,56 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var server = require('@sonordev/site-kit/server');
|
|
4
|
+
|
|
5
|
+
// src/shared/api.ts
|
|
6
|
+
var DEFAULT_REVALIDATE = 3600;
|
|
7
|
+
var LOG_PREFIX = "[@sonordev/agency-site-kit]";
|
|
8
|
+
function getApiConfig() {
|
|
9
|
+
const config = server.resolveServerApiConfig();
|
|
10
|
+
if (!config) {
|
|
11
|
+
console.warn(
|
|
12
|
+
`${LOG_PREFIX} Missing SONOR_API_KEY environment variable. Portfolio data will not be fetched.`
|
|
13
|
+
);
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
return config;
|
|
17
|
+
}
|
|
18
|
+
async function apiFetch(path, options = {}) {
|
|
19
|
+
const {
|
|
20
|
+
revalidate = DEFAULT_REVALIDATE,
|
|
21
|
+
tags,
|
|
22
|
+
headers,
|
|
23
|
+
apiKey,
|
|
24
|
+
apiUrl,
|
|
25
|
+
method,
|
|
26
|
+
body,
|
|
27
|
+
...init
|
|
28
|
+
} = options;
|
|
29
|
+
return server.serverApiFetch(path, {
|
|
30
|
+
method,
|
|
31
|
+
body: body ?? void 0,
|
|
32
|
+
headers,
|
|
33
|
+
revalidate,
|
|
34
|
+
tags,
|
|
35
|
+
apiKey,
|
|
36
|
+
apiUrl,
|
|
37
|
+
retry: false,
|
|
38
|
+
requireKey: false,
|
|
39
|
+
logPrefix: LOG_PREFIX,
|
|
40
|
+
init
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async function apiGet(path, revalidate, apiKey, apiUrl) {
|
|
44
|
+
return apiFetch(path, {
|
|
45
|
+
method: "GET",
|
|
46
|
+
revalidate,
|
|
47
|
+
apiKey,
|
|
48
|
+
apiUrl
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
exports.apiFetch = apiFetch;
|
|
53
|
+
exports.apiGet = apiGet;
|
|
54
|
+
exports.getApiConfig = getApiConfig;
|
|
55
|
+
//# sourceMappingURL=chunk-EE75WRCM.cjs.map
|
|
56
|
+
//# sourceMappingURL=chunk-EE75WRCM.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/api.ts"],"names":["resolveServerApiConfig","serverApiFetch"],"mappings":";;;;;AAyBA,IAAM,kBAAA,GAAqB,IAAA;AAC3B,IAAM,UAAA,GAAa,6BAAA;AASZ,SAAS,YAAA,GAAiC;AAC/C,EAAA,MAAM,SAASA,6BAAA,EAAuB;AAEtC,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,OAAA,CAAQ,IAAA;AAAA,MACN,GAAG,UAAU,CAAA,gFAAA;AAAA,KAEf;AACA,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,MAAA;AACT;AAgCA,eAAsB,QAAA,CACpB,IAAA,EACA,OAAA,GAA2B,EAAC,EACT;AACnB,EAAA,MAAM;AAAA,IACJ,UAAA,GAAa,kBAAA;AAAA,IACb,IAAA;AAAA,IACA,OAAA;AAAA,IACA,MAAA;AAAA,IACA,MAAA;AAAA,IACA,MAAA;AAAA,IACA,IAAA;AAAA,IACA,GAAG;AAAA,GACL,GAAI,OAAA;AAEJ,EAAA,OAAOC,sBAAkB,IAAA,EAAM;AAAA,IAC7B,MAAA;AAAA,IACA,MAAM,IAAA,IAAQ,MAAA;AAAA,IACd,OAAA;AAAA,IACA,UAAA;AAAA,IACA,IAAA;AAAA,IACA,MAAA;AAAA,IACA,MAAA;AAAA,IACA,KAAA,EAAO,KAAA;AAAA,IACP,UAAA,EAAY,KAAA;AAAA,IACZ,SAAA,EAAW,UAAA;AAAA,IACX;AAAA,GACD,CAAA;AACH;AAUA,eAAsB,MAAA,CACpB,IAAA,EACA,UAAA,EACA,MAAA,EACA,MAAA,EACmB;AACnB,EAAA,OAAO,SAAY,IAAA,EAAM;AAAA,IACvB,MAAA,EAAQ,KAAA;AAAA,IACR,UAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACD,CAAA;AACH","file":"chunk-EE75WRCM.cjs","sourcesContent":["/**\n * @sonordev/agency-site-kit — API fetch utilities\n *\n * Server-side only. Thin adapters over core `@sonordev/site-kit`'s shared server\n * fetcher (`@sonordev/site-kit/server`) — the single source of truth for the\n * Sonor server data plane. This package no longer ships its own `apiFetch` copy;\n * it reuses core's so the two can never drift (monorepo CLAUDE.md,\n * \"Consolidate Duplicated Logic\").\n *\n * Config resolution (SONOR_API_KEY → `x-api-key`, SONOR_API_URL, the legacy\n * UPTRADE_API_KEY fallback) and the `https://api.sonor.io` base all live in core.\n *\n * NOTE: importing this module pulls core's `server-only` guard, so it (and any\n * barrel that re-exports it, including the package root and AgencySiteKitLayout)\n * is server-only. Client components must import from\n * `@sonordev/agency-site-kit/portfolio/client`.\n */\n\nimport {\n resolveServerApiConfig,\n serverApiFetch,\n type ServerApiConfig,\n} from '@sonordev/site-kit/server';\n\n/** Portfolio fetches default to a 1h ISR window (overridable per call). */\nconst DEFAULT_REVALIDATE = 3600;\nconst LOG_PREFIX = '[@sonordev/agency-site-kit]';\n\ntype ApiConfig = ServerApiConfig;\n\n/**\n * Reads API configuration from overrides → environment (delegates to core's\n * `resolveServerApiConfig`). Returns null and warns when no API key is found, so\n * portfolio data degrades gracefully instead of throwing.\n */\nexport function getApiConfig(): ApiConfig | null {\n const config = resolveServerApiConfig();\n\n if (!config) {\n console.warn(\n `${LOG_PREFIX} Missing SONOR_API_KEY environment variable. ` +\n 'Portfolio data will not be fetched.',\n );\n return null;\n }\n\n return config;\n}\n\ninterface ApiFetchOptions extends Omit<RequestInit, 'headers'> {\n /** ISR revalidation interval in seconds. Defaults to 3600. Set to 0 for no caching. */\n revalidate?: number;\n /**\n * Next.js cache tags for on-demand invalidation. Portfolio fetches use\n * PORTFOLIO_CACHE_TAG so the Portal can bust list + detail + sitemap data\n * with a single revalidateTag call (see ./revalidate).\n */\n tags?: string[];\n /** Additional headers to merge with defaults */\n headers?: Record<string, string>;\n /** Override API key (e.g. passed from layout props) */\n apiKey?: string;\n /** Override API URL */\n apiUrl?: string;\n}\n\n/**\n * Fetch wrapper for the public portfolio API — delegates to core's\n * `serverApiFetch`.\n *\n * - Injects `x-api-key` automatically\n * - Parses JSON responses\n * - Uses Next.js ISR caching via `next.revalidate` (+ optional cache `tags`)\n * - Returns null on failure (or a missing key) instead of throwing\n *\n * Single-attempt by design — portfolio pages degrade gracefully rather than\n * hard-failing. (Core's fetcher supports retry/backoff; this preserves\n * agency-site-kit's original behavior.)\n */\nexport async function apiFetch<T>(\n path: string,\n options: ApiFetchOptions = {},\n): Promise<T | null> {\n const {\n revalidate = DEFAULT_REVALIDATE,\n tags,\n headers,\n apiKey,\n apiUrl,\n method,\n body,\n ...init\n } = options;\n\n return serverApiFetch<T>(path, {\n method,\n body: body ?? undefined,\n headers,\n revalidate,\n tags,\n apiKey,\n apiUrl,\n retry: false,\n requireKey: false,\n logPrefix: LOG_PREFIX,\n init: init as RequestInit,\n });\n}\n\n/**\n * GET shorthand for apiFetch.\n *\n * @param path API path (e.g. \"/api/public/portfolio/items\")\n * @param revalidate ISR revalidation in seconds (default 3600)\n * @param apiKey Optional override API key\n * @param apiUrl Optional override API URL\n */\nexport async function apiGet<T>(\n path: string,\n revalidate?: number,\n apiKey?: string,\n apiUrl?: string,\n): Promise<T | null> {\n return apiFetch<T>(path, {\n method: 'GET',\n revalidate,\n apiKey,\n apiUrl,\n });\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/cache.ts"],"names":[],"mappings":";;;AAYO,IAAM,mBAAA,GAAsB","file":"chunk-FCKDJ4MJ.cjs","sourcesContent":["/**\n * @sonordev/agency-site-kit — Cache tag contract\n *\n * Single source of truth for the Next.js cache tag attached to every\n * portfolio fetch. The Sonor Portal sends this tag in its revalidation\n * webhook payload when portfolio content changes, so one revalidateTag()\n * busts the list, detail, categories, brand-config, and sitemap data caches\n * in a single call.\n *\n * The Portal side mirrors this value in portfolio.service.ts\n * (sonor-api-nestjs) — keep them in sync.\n */\nexport const PORTFOLIO_CACHE_TAG = 'portfolio';\n"]}
|
|
@@ -496,11 +496,29 @@ var BeforeAfterSection = dynamic__default.default(() => import('./BeforeAfterSec
|
|
|
496
496
|
var MetricsTimelineSection = dynamic__default.default(() => import('./MetricsTimelineSection-4L6DUHJ5.cjs'), { ssr: true });
|
|
497
497
|
var ConversionFunnelSection = dynamic__default.default(() => import('./ConversionFunnelSection-AUUSJ5HQ.cjs'), { ssr: true });
|
|
498
498
|
var PerformanceSection = dynamic__default.default(() => import('./PerformanceSection-24TVVFZA.cjs'), { ssr: true });
|
|
499
|
-
var SiteArchitectureSection = dynamic__default.default(() => import('./SiteArchitectureSection-
|
|
499
|
+
var SiteArchitectureSection = dynamic__default.default(() => import('./SiteArchitectureSection-J7BPBERH.cjs'), { ssr: true });
|
|
500
500
|
var SpeedComparisonSection = dynamic__default.default(() => import('./SpeedComparisonSection-EZKFQVGW.cjs'), { ssr: true });
|
|
501
501
|
var DesignSystemSection = dynamic__default.default(() => import('./DesignSystemSection-KXIQXITF.cjs'), { ssr: true });
|
|
502
502
|
var DetailsSection = dynamic__default.default(() => import('./DetailsSection-TTUZAPZZ.cjs'), { ssr: true });
|
|
503
503
|
var CTASection = dynamic__default.default(() => import('./CTASection-4JKLXEUF.cjs'), { ssr: true });
|
|
504
|
+
function humanizeArchPageEntry(page) {
|
|
505
|
+
const title = (page?.title || "").trim();
|
|
506
|
+
if (title && !title.startsWith("/")) return { title };
|
|
507
|
+
const source = title || (page?.path || "").trim();
|
|
508
|
+
const lastSegment = source.split(/[?#]/)[0].split("/").filter(Boolean).pop() || "";
|
|
509
|
+
const label = lastSegment.replace(/\.(html?|php|aspx?)$/i, "").replace(/[-_]+/g, " ").trim().replace(/\b\w/g, (c) => c.toUpperCase());
|
|
510
|
+
return { title: label || "Home" };
|
|
511
|
+
}
|
|
512
|
+
function sanitizeSiteArchitectureData(data) {
|
|
513
|
+
if (!data || !Array.isArray(data.groups)) return data;
|
|
514
|
+
return {
|
|
515
|
+
...data,
|
|
516
|
+
groups: data.groups.map((group) => ({
|
|
517
|
+
...group,
|
|
518
|
+
pages: Array.isArray(group.pages) ? group.pages.map(humanizeArchPageEntry) : []
|
|
519
|
+
}))
|
|
520
|
+
};
|
|
521
|
+
}
|
|
504
522
|
function renderSection(section, item, index) {
|
|
505
523
|
const key = `${section.sectionType}-${index}`;
|
|
506
524
|
switch (section.sectionType) {
|
|
@@ -545,7 +563,7 @@ function renderSection(section, item, index) {
|
|
|
545
563
|
case "portfolioSpeedComparison":
|
|
546
564
|
return /* @__PURE__ */ jsxRuntime.jsx(SpeedComparisonSection, { data: section.data }, key);
|
|
547
565
|
case "portfolioSiteArchitecture":
|
|
548
|
-
return /* @__PURE__ */ jsxRuntime.jsx(SiteArchitectureSection, { data: section.data }, key);
|
|
566
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SiteArchitectureSection, { data: sanitizeSiteArchitectureData(section.data) }, key);
|
|
549
567
|
case "portfolioDesignSystem":
|
|
550
568
|
return /* @__PURE__ */ jsxRuntime.jsx(DesignSystemSection, { data: section.data }, key);
|
|
551
569
|
case "portfolioDetails":
|
|
@@ -615,5 +633,5 @@ var PORTFOLIO_SECTION_TYPES = [
|
|
|
615
633
|
|
|
616
634
|
exports.PORTFOLIO_SECTION_TYPES = PORTFOLIO_SECTION_TYPES;
|
|
617
635
|
exports.PortfolioPage = PortfolioPage;
|
|
618
|
-
//# sourceMappingURL=chunk-
|
|
619
|
-
//# sourceMappingURL=chunk-
|
|
636
|
+
//# sourceMappingURL=chunk-FDFVLYAM.cjs.map
|
|
637
|
+
//# sourceMappingURL=chunk-FDFVLYAM.cjs.map
|