@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.
- package/dist/BeforeAfterSection-6QUJOBO2.js +176 -0
- package/dist/BeforeAfterSection-6QUJOBO2.js.map +1 -0
- package/dist/BeforeAfterSection-DVAWWE4K.cjs +181 -0
- package/dist/BeforeAfterSection-DVAWWE4K.cjs.map +1 -0
- package/dist/CTASection-4JKLXEUF.cjs +111 -0
- package/dist/CTASection-4JKLXEUF.cjs.map +1 -0
- package/dist/CTASection-BJA72XIL.js +106 -0
- package/dist/CTASection-BJA72XIL.js.map +1 -0
- package/dist/ChallengesSection-GEQGVSJN.js +180 -0
- package/dist/ChallengesSection-GEQGVSJN.js.map +1 -0
- package/dist/ChallengesSection-IZ3DHECS.cjs +182 -0
- package/dist/ChallengesSection-IZ3DHECS.cjs.map +1 -0
- package/dist/ConversionFunnelSection-AUUSJ5HQ.cjs +209 -0
- package/dist/ConversionFunnelSection-AUUSJ5HQ.cjs.map +1 -0
- package/dist/ConversionFunnelSection-D3GE4NKE.js +203 -0
- package/dist/ConversionFunnelSection-D3GE4NKE.js.map +1 -0
- package/dist/DetailsSection-FB763FS7.js +135 -0
- package/dist/DetailsSection-FB763FS7.js.map +1 -0
- package/dist/DetailsSection-OACJFGH7.cjs +137 -0
- package/dist/DetailsSection-OACJFGH7.cjs.map +1 -0
- package/dist/FeatureSpotlightSection-B7P3JGNL.js +205 -0
- package/dist/FeatureSpotlightSection-B7P3JGNL.js.map +1 -0
- package/dist/FeatureSpotlightSection-WRHXS7TU.cjs +210 -0
- package/dist/FeatureSpotlightSection-WRHXS7TU.cjs.map +1 -0
- package/dist/GallerySection-VMKORC47.js +218 -0
- package/dist/GallerySection-VMKORC47.js.map +1 -0
- package/dist/GallerySection-WJ4PQDBI.cjs +219 -0
- package/dist/GallerySection-WJ4PQDBI.cjs.map +1 -0
- package/dist/MetricsTimelineSection-4L6DUHJ5.cjs +258 -0
- package/dist/MetricsTimelineSection-4L6DUHJ5.cjs.map +1 -0
- package/dist/MetricsTimelineSection-6BT5GNFV.js +253 -0
- package/dist/MetricsTimelineSection-6BT5GNFV.js.map +1 -0
- package/dist/ResultsSection-DFUJ5U6M.js +93 -0
- package/dist/ResultsSection-DFUJ5U6M.js.map +1 -0
- package/dist/ResultsSection-XLGMMQKY.cjs +95 -0
- package/dist/ResultsSection-XLGMMQKY.cjs.map +1 -0
- package/dist/ServicesSection-D5V3Q4GR.js +118 -0
- package/dist/ServicesSection-D5V3Q4GR.js.map +1 -0
- package/dist/ServicesSection-WJMGK2MF.cjs +120 -0
- package/dist/ServicesSection-WJMGK2MF.cjs.map +1 -0
- package/dist/StrategySection-3ED3QW4R.cjs +180 -0
- package/dist/StrategySection-3ED3QW4R.cjs.map +1 -0
- package/dist/StrategySection-VUWMIYYP.js +175 -0
- package/dist/StrategySection-VUWMIYYP.js.map +1 -0
- package/dist/TeamSection-DZVSNZE6.cjs +112 -0
- package/dist/TeamSection-DZVSNZE6.cjs.map +1 -0
- package/dist/TeamSection-HGKFW6PQ.js +107 -0
- package/dist/TeamSection-HGKFW6PQ.js.map +1 -0
- package/dist/TechStackSection-OCUYG4XT.js +90 -0
- package/dist/TechStackSection-OCUYG4XT.js.map +1 -0
- package/dist/TechStackSection-VKJK4KQB.cjs +91 -0
- package/dist/TechStackSection-VKJK4KQB.cjs.map +1 -0
- package/dist/TestimonialSection-6RGSMXQB.js +122 -0
- package/dist/TestimonialSection-6RGSMXQB.js.map +1 -0
- package/dist/TestimonialSection-XPTFUQIN.cjs +124 -0
- package/dist/TestimonialSection-XPTFUQIN.cjs.map +1 -0
- package/dist/VideoSection-4A2HC6K6.js +117 -0
- package/dist/VideoSection-4A2HC6K6.js.map +1 -0
- package/dist/VideoSection-G3DFS7UH.cjs +118 -0
- package/dist/VideoSection-G3DFS7UH.cjs.map +1 -0
- package/dist/chunk-2VNNFAG6.js +415 -0
- package/dist/chunk-2VNNFAG6.js.map +1 -0
- package/dist/chunk-2Y4O3LWM.js +53 -0
- package/dist/chunk-2Y4O3LWM.js.map +1 -0
- package/dist/chunk-5FKOLIV6.cjs +221 -0
- package/dist/chunk-5FKOLIV6.cjs.map +1 -0
- package/dist/chunk-7CFFAKDM.js +74 -0
- package/dist/chunk-7CFFAKDM.js.map +1 -0
- package/dist/chunk-A4I4IK7V.js +69 -0
- package/dist/chunk-A4I4IK7V.js.map +1 -0
- package/dist/chunk-IKBK7HYX.cjs +79 -0
- package/dist/chunk-IKBK7HYX.cjs.map +1 -0
- package/dist/chunk-KEOHORIH.cjs +79 -0
- package/dist/chunk-KEOHORIH.cjs.map +1 -0
- package/dist/chunk-NAS4K5UR.cjs +139 -0
- package/dist/chunk-NAS4K5UR.cjs.map +1 -0
- package/dist/chunk-QBLWP25X.cjs +73 -0
- package/dist/chunk-QBLWP25X.cjs.map +1 -0
- package/dist/chunk-QIC6JFFD.js +210 -0
- package/dist/chunk-QIC6JFFD.js.map +1 -0
- package/dist/chunk-TAPNXT7X.cjs +422 -0
- package/dist/chunk-TAPNXT7X.cjs.map +1 -0
- package/dist/chunk-XCKXHK44.js +15 -0
- package/dist/chunk-XCKXHK44.js.map +1 -0
- package/dist/chunk-XMC4DN6G.js +131 -0
- package/dist/chunk-XMC4DN6G.js.map +1 -0
- package/dist/chunk-XONXEFJY.cjs +58 -0
- package/dist/chunk-XONXEFJY.cjs.map +1 -0
- package/dist/chunk-XQNJED46.cjs +19 -0
- package/dist/chunk-XQNJED46.cjs.map +1 -0
- package/dist/chunk-YB4B3OMC.js +74 -0
- package/dist/chunk-YB4B3OMC.js.map +1 -0
- package/dist/index.cjs +271 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +137 -0
- package/dist/index.d.ts +137 -0
- package/dist/index.js +197 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/index.cjs +13 -0
- package/dist/layout/index.cjs.map +1 -0
- package/dist/layout/index.d.cts +54 -0
- package/dist/layout/index.d.ts +54 -0
- package/dist/layout/index.js +4 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/portfolio/client.cjs +18 -0
- package/dist/portfolio/client.cjs.map +1 -0
- package/dist/portfolio/client.d.cts +97 -0
- package/dist/portfolio/client.d.ts +97 -0
- package/dist/portfolio/client.js +6 -0
- package/dist/portfolio/client.js.map +1 -0
- package/dist/portfolio/index.cjs +41 -0
- package/dist/portfolio/index.cjs.map +1 -0
- package/dist/portfolio/index.d.cts +12 -0
- package/dist/portfolio/index.d.ts +12 -0
- package/dist/portfolio/index.js +8 -0
- package/dist/portfolio/index.js.map +1 -0
- package/dist/portfolio/sections.cjs +20 -0
- package/dist/portfolio/sections.cjs.map +1 -0
- package/dist/portfolio/sections.d.cts +42 -0
- package/dist/portfolio/sections.d.ts +42 -0
- package/dist/portfolio/sections.js +4 -0
- package/dist/portfolio/sections.js.map +1 -0
- package/dist/portfolio/server.cjs +141 -0
- package/dist/portfolio/server.cjs.map +1 -0
- package/dist/portfolio/server.d.cts +68 -0
- package/dist/portfolio/server.d.ts +68 -0
- package/dist/portfolio/server.js +134 -0
- package/dist/portfolio/server.js.map +1 -0
- package/dist/types-BMUhBhWx.d.cts +346 -0
- package/dist/types-BMUhBhWx.d.ts +346 -0
- package/package.json +71 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { u as PortfolioItem, P as PortfolioItemFull, A as PortfolioSection } from '../types-BMUhBhWx.cjs';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
interface PortfolioGridProps$1 {
|
|
5
|
+
items: PortfolioItem[];
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
declare function PortfolioGrid({ items, className }: PortfolioGridProps$1): react_jsx_runtime.JSX.Element;
|
|
9
|
+
|
|
10
|
+
interface PortfolioCardProps$1 {
|
|
11
|
+
item: PortfolioItem;
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
declare function PortfolioCard({ item, className }: PortfolioCardProps$1): react_jsx_runtime.JSX.Element;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @sonordev/agency-site-kit/portfolio/client — Client-only portfolio components
|
|
18
|
+
*
|
|
19
|
+
* Components in this barrel require browser APIs (DOM, events, IntersectionObserver,
|
|
20
|
+
* animations). The 'use client' directive at the top marks the client boundary.
|
|
21
|
+
*
|
|
22
|
+
* Client components will be added here as they are implemented:
|
|
23
|
+
*
|
|
24
|
+
* - PortfolioPageClient — full case study page with scroll-driven sections
|
|
25
|
+
* - PortfolioFilter — category/service filter bar with animated transitions
|
|
26
|
+
* - PortfolioGrid — animated grid layout with filtering
|
|
27
|
+
* - PortfolioCard — interactive card with hover effects and KPI preview
|
|
28
|
+
* - PortfolioLightbox — fullscreen image viewer for gallery sections
|
|
29
|
+
* - PortfolioBeforeAfterSlider — drag/touch comparison slider
|
|
30
|
+
* - PortfolioMetricsChart — animated chart for metrics timeline
|
|
31
|
+
* - PortfolioFunnelViz — conversion funnel visualization
|
|
32
|
+
*
|
|
33
|
+
* For now, export the type interfaces so consuming code can reference them.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
interface PortfolioPageClientProps {
|
|
37
|
+
item: PortfolioItemFull;
|
|
38
|
+
/** Back link URL (defaults to /portfolio) */
|
|
39
|
+
backUrl?: string;
|
|
40
|
+
/** Custom class name for the page wrapper */
|
|
41
|
+
className?: string;
|
|
42
|
+
}
|
|
43
|
+
interface PortfolioFilterProps {
|
|
44
|
+
/** All available categories extracted from items */
|
|
45
|
+
categories: string[];
|
|
46
|
+
/** All available services extracted from items */
|
|
47
|
+
services: string[];
|
|
48
|
+
/** Currently selected category (null = all) */
|
|
49
|
+
activeCategory: string | null;
|
|
50
|
+
/** Currently selected services */
|
|
51
|
+
activeServices: string[];
|
|
52
|
+
/** Callback when category changes */
|
|
53
|
+
onCategoryChange: (category: string | null) => void;
|
|
54
|
+
/** Callback when services selection changes */
|
|
55
|
+
onServicesChange: (services: string[]) => void;
|
|
56
|
+
/** Custom class name */
|
|
57
|
+
className?: string;
|
|
58
|
+
}
|
|
59
|
+
interface PortfolioGridProps {
|
|
60
|
+
/** Portfolio items to display */
|
|
61
|
+
items: PortfolioItem[];
|
|
62
|
+
/** Number of columns at each breakpoint */
|
|
63
|
+
columns?: {
|
|
64
|
+
sm?: number;
|
|
65
|
+
md?: number;
|
|
66
|
+
lg?: number;
|
|
67
|
+
xl?: number;
|
|
68
|
+
};
|
|
69
|
+
/** Animation style for grid items */
|
|
70
|
+
animation?: 'fade' | 'slide' | 'scale' | 'none';
|
|
71
|
+
/** Custom class name */
|
|
72
|
+
className?: string;
|
|
73
|
+
}
|
|
74
|
+
interface PortfolioCardProps {
|
|
75
|
+
/** Portfolio item data */
|
|
76
|
+
item: PortfolioItem;
|
|
77
|
+
/** Card size variant */
|
|
78
|
+
variant?: 'default' | 'featured' | 'compact';
|
|
79
|
+
/** Whether to show KPI preview on hover */
|
|
80
|
+
showKpis?: boolean;
|
|
81
|
+
/** Click handler (if not using Link) */
|
|
82
|
+
onClick?: (item: PortfolioItem) => void;
|
|
83
|
+
/** Link href for the card */
|
|
84
|
+
href?: string;
|
|
85
|
+
/** Custom class name */
|
|
86
|
+
className?: string;
|
|
87
|
+
}
|
|
88
|
+
interface PortfolioSectionRendererProps {
|
|
89
|
+
/** The section to render */
|
|
90
|
+
section: PortfolioSection;
|
|
91
|
+
/** Index within the page (for animation staggering) */
|
|
92
|
+
index?: number;
|
|
93
|
+
/** Custom class name */
|
|
94
|
+
className?: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export { PortfolioCard, type PortfolioCardProps, type PortfolioFilterProps, PortfolioGrid, type PortfolioGridProps, PortfolioItem, PortfolioItemFull, type PortfolioPageClientProps, PortfolioSection, type PortfolioSectionRendererProps };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { u as PortfolioItem, P as PortfolioItemFull, A as PortfolioSection } from '../types-BMUhBhWx.js';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
interface PortfolioGridProps$1 {
|
|
5
|
+
items: PortfolioItem[];
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
declare function PortfolioGrid({ items, className }: PortfolioGridProps$1): react_jsx_runtime.JSX.Element;
|
|
9
|
+
|
|
10
|
+
interface PortfolioCardProps$1 {
|
|
11
|
+
item: PortfolioItem;
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
declare function PortfolioCard({ item, className }: PortfolioCardProps$1): react_jsx_runtime.JSX.Element;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @sonordev/agency-site-kit/portfolio/client — Client-only portfolio components
|
|
18
|
+
*
|
|
19
|
+
* Components in this barrel require browser APIs (DOM, events, IntersectionObserver,
|
|
20
|
+
* animations). The 'use client' directive at the top marks the client boundary.
|
|
21
|
+
*
|
|
22
|
+
* Client components will be added here as they are implemented:
|
|
23
|
+
*
|
|
24
|
+
* - PortfolioPageClient — full case study page with scroll-driven sections
|
|
25
|
+
* - PortfolioFilter — category/service filter bar with animated transitions
|
|
26
|
+
* - PortfolioGrid — animated grid layout with filtering
|
|
27
|
+
* - PortfolioCard — interactive card with hover effects and KPI preview
|
|
28
|
+
* - PortfolioLightbox — fullscreen image viewer for gallery sections
|
|
29
|
+
* - PortfolioBeforeAfterSlider — drag/touch comparison slider
|
|
30
|
+
* - PortfolioMetricsChart — animated chart for metrics timeline
|
|
31
|
+
* - PortfolioFunnelViz — conversion funnel visualization
|
|
32
|
+
*
|
|
33
|
+
* For now, export the type interfaces so consuming code can reference them.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
interface PortfolioPageClientProps {
|
|
37
|
+
item: PortfolioItemFull;
|
|
38
|
+
/** Back link URL (defaults to /portfolio) */
|
|
39
|
+
backUrl?: string;
|
|
40
|
+
/** Custom class name for the page wrapper */
|
|
41
|
+
className?: string;
|
|
42
|
+
}
|
|
43
|
+
interface PortfolioFilterProps {
|
|
44
|
+
/** All available categories extracted from items */
|
|
45
|
+
categories: string[];
|
|
46
|
+
/** All available services extracted from items */
|
|
47
|
+
services: string[];
|
|
48
|
+
/** Currently selected category (null = all) */
|
|
49
|
+
activeCategory: string | null;
|
|
50
|
+
/** Currently selected services */
|
|
51
|
+
activeServices: string[];
|
|
52
|
+
/** Callback when category changes */
|
|
53
|
+
onCategoryChange: (category: string | null) => void;
|
|
54
|
+
/** Callback when services selection changes */
|
|
55
|
+
onServicesChange: (services: string[]) => void;
|
|
56
|
+
/** Custom class name */
|
|
57
|
+
className?: string;
|
|
58
|
+
}
|
|
59
|
+
interface PortfolioGridProps {
|
|
60
|
+
/** Portfolio items to display */
|
|
61
|
+
items: PortfolioItem[];
|
|
62
|
+
/** Number of columns at each breakpoint */
|
|
63
|
+
columns?: {
|
|
64
|
+
sm?: number;
|
|
65
|
+
md?: number;
|
|
66
|
+
lg?: number;
|
|
67
|
+
xl?: number;
|
|
68
|
+
};
|
|
69
|
+
/** Animation style for grid items */
|
|
70
|
+
animation?: 'fade' | 'slide' | 'scale' | 'none';
|
|
71
|
+
/** Custom class name */
|
|
72
|
+
className?: string;
|
|
73
|
+
}
|
|
74
|
+
interface PortfolioCardProps {
|
|
75
|
+
/** Portfolio item data */
|
|
76
|
+
item: PortfolioItem;
|
|
77
|
+
/** Card size variant */
|
|
78
|
+
variant?: 'default' | 'featured' | 'compact';
|
|
79
|
+
/** Whether to show KPI preview on hover */
|
|
80
|
+
showKpis?: boolean;
|
|
81
|
+
/** Click handler (if not using Link) */
|
|
82
|
+
onClick?: (item: PortfolioItem) => void;
|
|
83
|
+
/** Link href for the card */
|
|
84
|
+
href?: string;
|
|
85
|
+
/** Custom class name */
|
|
86
|
+
className?: string;
|
|
87
|
+
}
|
|
88
|
+
interface PortfolioSectionRendererProps {
|
|
89
|
+
/** The section to render */
|
|
90
|
+
section: PortfolioSection;
|
|
91
|
+
/** Index within the page (for animation staggering) */
|
|
92
|
+
index?: number;
|
|
93
|
+
/** Custom class name */
|
|
94
|
+
className?: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export { PortfolioCard, type PortfolioCardProps, type PortfolioFilterProps, PortfolioGrid, type PortfolioGridProps, PortfolioItem, PortfolioItemFull, type PortfolioPageClientProps, PortfolioSection, type PortfolioSectionRendererProps };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"client.js"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkTAPNXT7X_cjs = require('../chunk-TAPNXT7X.cjs');
|
|
4
|
+
require('../chunk-XONXEFJY.cjs');
|
|
5
|
+
var chunkXQNJED46_cjs = require('../chunk-XQNJED46.cjs');
|
|
6
|
+
var chunkNAS4K5UR_cjs = require('../chunk-NAS4K5UR.cjs');
|
|
7
|
+
require('../chunk-KEOHORIH.cjs');
|
|
8
|
+
require('../chunk-IKBK7HYX.cjs');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
Object.defineProperty(exports, "PORTFOLIO_SECTION_TYPES", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () { return chunkTAPNXT7X_cjs.PORTFOLIO_SECTION_TYPES; }
|
|
15
|
+
});
|
|
16
|
+
Object.defineProperty(exports, "PortfolioPage", {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function () { return chunkTAPNXT7X_cjs.PortfolioPage; }
|
|
19
|
+
});
|
|
20
|
+
Object.defineProperty(exports, "getRegisteredSectionTypes", {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
get: function () { return chunkXQNJED46_cjs.getRegisteredSectionTypes; }
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(exports, "getSectionRenderer", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
get: function () { return chunkXQNJED46_cjs.getSectionRenderer; }
|
|
27
|
+
});
|
|
28
|
+
Object.defineProperty(exports, "registerSectionRenderer", {
|
|
29
|
+
enumerable: true,
|
|
30
|
+
get: function () { return chunkXQNJED46_cjs.registerSectionRenderer; }
|
|
31
|
+
});
|
|
32
|
+
Object.defineProperty(exports, "PortfolioCard", {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
get: function () { return chunkNAS4K5UR_cjs.PortfolioCard; }
|
|
35
|
+
});
|
|
36
|
+
Object.defineProperty(exports, "PortfolioGrid", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
get: function () { return chunkNAS4K5UR_cjs.PortfolioGrid; }
|
|
39
|
+
});
|
|
40
|
+
//# sourceMappingURL=index.cjs.map
|
|
41
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.cjs"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { P as PortfolioItemFull } from '../types-BMUhBhWx.cjs';
|
|
3
|
+
export { M as MetricSource, e as MetricsDelta, f as MetricsSnapshot, g as PORTFOLIO_SECTION_TYPES, i as PortfolioBeforeAfterData, j as PortfolioCTAData, l as PortfolioChallengesData, n as PortfolioConversionFunnelData, o as PortfolioDetailsData, p as PortfolioFeatureSpotlightData, r as PortfolioGalleryData, t as PortfolioHeroData, u as PortfolioItem, v as PortfolioKPI, a as PortfolioListResponse, x as PortfolioMetricsTimelineData, z as PortfolioResultsData, A as PortfolioSection, d as PortfolioSectionData, c as PortfolioSectionDataMap, b as PortfolioSectionType, C as PortfolioSeoData, E as PortfolioServicesData, F as PortfolioStrategyData, H as PortfolioTeamData, K as PortfolioTechStackData, L as PortfolioTestimonialData, N as PortfolioVideoData } from '../types-BMUhBhWx.cjs';
|
|
4
|
+
export { PortfolioCard, PortfolioCardProps, PortfolioFilterProps, PortfolioGrid, PortfolioGridProps, PortfolioPageClientProps, PortfolioSectionRendererProps } from './client.cjs';
|
|
5
|
+
export { PortfolioSectionRenderer, PortfolioSectionRenderer as SectionRenderer, getRegisteredSectionTypes, getSectionRenderer, registerSectionRenderer } from './sections.cjs';
|
|
6
|
+
|
|
7
|
+
interface PortfolioPageProps {
|
|
8
|
+
item: PortfolioItemFull;
|
|
9
|
+
}
|
|
10
|
+
declare function PortfolioPage({ item }: PortfolioPageProps): react_jsx_runtime.JSX.Element;
|
|
11
|
+
|
|
12
|
+
export { PortfolioItemFull, PortfolioPage };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { P as PortfolioItemFull } from '../types-BMUhBhWx.js';
|
|
3
|
+
export { M as MetricSource, e as MetricsDelta, f as MetricsSnapshot, g as PORTFOLIO_SECTION_TYPES, i as PortfolioBeforeAfterData, j as PortfolioCTAData, l as PortfolioChallengesData, n as PortfolioConversionFunnelData, o as PortfolioDetailsData, p as PortfolioFeatureSpotlightData, r as PortfolioGalleryData, t as PortfolioHeroData, u as PortfolioItem, v as PortfolioKPI, a as PortfolioListResponse, x as PortfolioMetricsTimelineData, z as PortfolioResultsData, A as PortfolioSection, d as PortfolioSectionData, c as PortfolioSectionDataMap, b as PortfolioSectionType, C as PortfolioSeoData, E as PortfolioServicesData, F as PortfolioStrategyData, H as PortfolioTeamData, K as PortfolioTechStackData, L as PortfolioTestimonialData, N as PortfolioVideoData } from '../types-BMUhBhWx.js';
|
|
4
|
+
export { PortfolioCard, PortfolioCardProps, PortfolioFilterProps, PortfolioGrid, PortfolioGridProps, PortfolioPageClientProps, PortfolioSectionRendererProps } from './client.js';
|
|
5
|
+
export { PortfolioSectionRenderer, PortfolioSectionRenderer as SectionRenderer, getRegisteredSectionTypes, getSectionRenderer, registerSectionRenderer } from './sections.js';
|
|
6
|
+
|
|
7
|
+
interface PortfolioPageProps {
|
|
8
|
+
item: PortfolioItemFull;
|
|
9
|
+
}
|
|
10
|
+
declare function PortfolioPage({ item }: PortfolioPageProps): react_jsx_runtime.JSX.Element;
|
|
11
|
+
|
|
12
|
+
export { PortfolioItemFull, PortfolioPage };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { PORTFOLIO_SECTION_TYPES, PortfolioPage } from '../chunk-2VNNFAG6.js';
|
|
2
|
+
import '../chunk-2Y4O3LWM.js';
|
|
3
|
+
export { getRegisteredSectionTypes, getSectionRenderer, registerSectionRenderer } from '../chunk-XCKXHK44.js';
|
|
4
|
+
export { PortfolioCard, PortfolioGrid } from '../chunk-XMC4DN6G.js';
|
|
5
|
+
import '../chunk-YB4B3OMC.js';
|
|
6
|
+
import '../chunk-7CFFAKDM.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkXQNJED46_cjs = require('../chunk-XQNJED46.cjs');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Object.defineProperty(exports, "getRegisteredSectionTypes", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: function () { return chunkXQNJED46_cjs.getRegisteredSectionTypes; }
|
|
10
|
+
});
|
|
11
|
+
Object.defineProperty(exports, "getSectionRenderer", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function () { return chunkXQNJED46_cjs.getSectionRenderer; }
|
|
14
|
+
});
|
|
15
|
+
Object.defineProperty(exports, "registerSectionRenderer", {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return chunkXQNJED46_cjs.registerSectionRenderer; }
|
|
18
|
+
});
|
|
19
|
+
//# sourceMappingURL=sections.cjs.map
|
|
20
|
+
//# sourceMappingURL=sections.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"sections.cjs"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { b as PortfolioSectionType, c as PortfolioSectionDataMap, d as PortfolioSectionData } from '../types-BMUhBhWx.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @sonordev/agency-site-kit/portfolio/sections — Section component barrel
|
|
5
|
+
*
|
|
6
|
+
* All portfolio section components are client components (they use
|
|
7
|
+
* animations, interactivity, and browser APIs). This barrel marks the
|
|
8
|
+
* client boundary and re-exports each section renderer.
|
|
9
|
+
*
|
|
10
|
+
* Section components will be added here as they are implemented.
|
|
11
|
+
* Each section component follows the pattern:
|
|
12
|
+
*
|
|
13
|
+
* interface Props { data: Portfolio[SectionName]Data; className?: string; }
|
|
14
|
+
* export function Portfolio[SectionName]Section({ data, className }: Props) { ... }
|
|
15
|
+
*
|
|
16
|
+
* For now, export the section type map and a placeholder renderer registry
|
|
17
|
+
* so that consuming code can be written against the final API.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Section renderer function signature.
|
|
22
|
+
* Each section component conforms to this interface.
|
|
23
|
+
*/
|
|
24
|
+
type SectionRenderer<T extends PortfolioSectionType = PortfolioSectionType> = (props: {
|
|
25
|
+
data: T extends keyof PortfolioSectionDataMap ? PortfolioSectionDataMap[T] : PortfolioSectionData;
|
|
26
|
+
className?: string;
|
|
27
|
+
}) => React.ReactElement | null;
|
|
28
|
+
/**
|
|
29
|
+
* Register a section renderer for a given section type.
|
|
30
|
+
*/
|
|
31
|
+
declare function registerSectionRenderer<T extends PortfolioSectionType>(sectionType: T, renderer: SectionRenderer<T>): void;
|
|
32
|
+
/**
|
|
33
|
+
* Look up a registered section renderer by type.
|
|
34
|
+
* Returns null if no renderer is registered for the given type.
|
|
35
|
+
*/
|
|
36
|
+
declare function getSectionRenderer(sectionType: PortfolioSectionType): SectionRenderer | null;
|
|
37
|
+
/**
|
|
38
|
+
* Returns all registered section types.
|
|
39
|
+
*/
|
|
40
|
+
declare function getRegisteredSectionTypes(): PortfolioSectionType[];
|
|
41
|
+
|
|
42
|
+
export { type SectionRenderer as PortfolioSectionRenderer, type SectionRenderer, getRegisteredSectionTypes, getSectionRenderer, registerSectionRenderer };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { b as PortfolioSectionType, c as PortfolioSectionDataMap, d as PortfolioSectionData } from '../types-BMUhBhWx.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @sonordev/agency-site-kit/portfolio/sections — Section component barrel
|
|
5
|
+
*
|
|
6
|
+
* All portfolio section components are client components (they use
|
|
7
|
+
* animations, interactivity, and browser APIs). This barrel marks the
|
|
8
|
+
* client boundary and re-exports each section renderer.
|
|
9
|
+
*
|
|
10
|
+
* Section components will be added here as they are implemented.
|
|
11
|
+
* Each section component follows the pattern:
|
|
12
|
+
*
|
|
13
|
+
* interface Props { data: Portfolio[SectionName]Data; className?: string; }
|
|
14
|
+
* export function Portfolio[SectionName]Section({ data, className }: Props) { ... }
|
|
15
|
+
*
|
|
16
|
+
* For now, export the section type map and a placeholder renderer registry
|
|
17
|
+
* so that consuming code can be written against the final API.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Section renderer function signature.
|
|
22
|
+
* Each section component conforms to this interface.
|
|
23
|
+
*/
|
|
24
|
+
type SectionRenderer<T extends PortfolioSectionType = PortfolioSectionType> = (props: {
|
|
25
|
+
data: T extends keyof PortfolioSectionDataMap ? PortfolioSectionDataMap[T] : PortfolioSectionData;
|
|
26
|
+
className?: string;
|
|
27
|
+
}) => React.ReactElement | null;
|
|
28
|
+
/**
|
|
29
|
+
* Register a section renderer for a given section type.
|
|
30
|
+
*/
|
|
31
|
+
declare function registerSectionRenderer<T extends PortfolioSectionType>(sectionType: T, renderer: SectionRenderer<T>): void;
|
|
32
|
+
/**
|
|
33
|
+
* Look up a registered section renderer by type.
|
|
34
|
+
* Returns null if no renderer is registered for the given type.
|
|
35
|
+
*/
|
|
36
|
+
declare function getSectionRenderer(sectionType: PortfolioSectionType): SectionRenderer | null;
|
|
37
|
+
/**
|
|
38
|
+
* Returns all registered section types.
|
|
39
|
+
*/
|
|
40
|
+
declare function getRegisteredSectionTypes(): PortfolioSectionType[];
|
|
41
|
+
|
|
42
|
+
export { type SectionRenderer as PortfolioSectionRenderer, type SectionRenderer, getRegisteredSectionTypes, getSectionRenderer, registerSectionRenderer };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"sections.js"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkQBLWP25X_cjs = require('../chunk-QBLWP25X.cjs');
|
|
4
|
+
|
|
5
|
+
// src/portfolio/server.ts
|
|
6
|
+
var LOG_PREFIX = "[@sonordev/agency-site-kit/portfolio]";
|
|
7
|
+
function buildQuery(params) {
|
|
8
|
+
const entries = Object.entries(params).filter(
|
|
9
|
+
(entry) => entry[1] != null
|
|
10
|
+
);
|
|
11
|
+
if (entries.length === 0) return "";
|
|
12
|
+
const qs = new URLSearchParams(
|
|
13
|
+
entries.map(([k, v]) => [k, String(v)])
|
|
14
|
+
).toString();
|
|
15
|
+
return `?${qs}`;
|
|
16
|
+
}
|
|
17
|
+
async function getPortfolioItems(options) {
|
|
18
|
+
const fallback = { items: [], total: 0, limit: 0, offset: 0 };
|
|
19
|
+
const query = buildQuery({
|
|
20
|
+
category: options?.category,
|
|
21
|
+
featured: options?.featured,
|
|
22
|
+
limit: options?.limit,
|
|
23
|
+
offset: options?.offset
|
|
24
|
+
});
|
|
25
|
+
const data = await chunkQBLWP25X_cjs.apiGet(
|
|
26
|
+
`/api/public/portfolio/items${query}`
|
|
27
|
+
);
|
|
28
|
+
if (!data) {
|
|
29
|
+
console.warn(`${LOG_PREFIX} Failed to fetch portfolio items.`);
|
|
30
|
+
return fallback;
|
|
31
|
+
}
|
|
32
|
+
return data;
|
|
33
|
+
}
|
|
34
|
+
async function getPortfolioItem(slug) {
|
|
35
|
+
if (!slug) {
|
|
36
|
+
console.warn(`${LOG_PREFIX} getPortfolioItem called with empty slug.`);
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
const data = await chunkQBLWP25X_cjs.apiGet(
|
|
40
|
+
`/api/public/portfolio/items/${encodeURIComponent(slug)}`
|
|
41
|
+
);
|
|
42
|
+
if (!data || !data.found || !data.item) {
|
|
43
|
+
console.warn(`${LOG_PREFIX} Portfolio item not found for slug: "${slug}".`);
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
const { item } = data;
|
|
47
|
+
return {
|
|
48
|
+
id: item.id,
|
|
49
|
+
slug: item.slug,
|
|
50
|
+
title: item.title,
|
|
51
|
+
subtitle: item.subtitle,
|
|
52
|
+
category: item.category,
|
|
53
|
+
services: item.services,
|
|
54
|
+
description: item.description,
|
|
55
|
+
hero_image: item.hero_image,
|
|
56
|
+
hero_image_alt: item.hero_image_alt,
|
|
57
|
+
live_url: item.live_url,
|
|
58
|
+
kpis: item.kpis,
|
|
59
|
+
details: item.details,
|
|
60
|
+
seo: item.seo,
|
|
61
|
+
featured: item.featured,
|
|
62
|
+
order: item.order,
|
|
63
|
+
published_at: item.published_at,
|
|
64
|
+
hero_screenshots: item.hero_screenshots,
|
|
65
|
+
baseline_metrics: item.baseline_metrics,
|
|
66
|
+
current_metrics: item.current_metrics,
|
|
67
|
+
metrics_last_refreshed_at: item.metrics_last_refreshed_at,
|
|
68
|
+
sections: item.sections ?? [],
|
|
69
|
+
metricsDelta: item.metricsDelta ?? []
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
async function getPortfolioCategories() {
|
|
73
|
+
const data = await chunkQBLWP25X_cjs.apiGet("/api/public/portfolio/categories");
|
|
74
|
+
if (!data) {
|
|
75
|
+
console.warn(`${LOG_PREFIX} Failed to fetch portfolio categories.`);
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
return data;
|
|
79
|
+
}
|
|
80
|
+
async function getPortfolioBrandConfig() {
|
|
81
|
+
const fallback = {
|
|
82
|
+
primary: "#6366f1",
|
|
83
|
+
secondary: "#8b5cf6",
|
|
84
|
+
background: "#0a0a0f",
|
|
85
|
+
backgroundElevated: "#12121a",
|
|
86
|
+
surface: "#1a1a2e",
|
|
87
|
+
surfaceHover: "#22223a",
|
|
88
|
+
surfaceBorder: "#2a2a3e",
|
|
89
|
+
textPrimary: "#f0f0f5",
|
|
90
|
+
textSecondary: "#a0a0b5",
|
|
91
|
+
textTertiary: "#6b6b80",
|
|
92
|
+
fontHeading: "Inter, system-ui, sans-serif",
|
|
93
|
+
fontBody: "Inter, system-ui, sans-serif"
|
|
94
|
+
};
|
|
95
|
+
const data = await chunkQBLWP25X_cjs.apiGet(
|
|
96
|
+
"/api/public/portfolio/config"
|
|
97
|
+
);
|
|
98
|
+
if (!data || !data.brand) {
|
|
99
|
+
console.warn(`${LOG_PREFIX} Failed to fetch brand config, using defaults.`);
|
|
100
|
+
return fallback;
|
|
101
|
+
}
|
|
102
|
+
return data.brand;
|
|
103
|
+
}
|
|
104
|
+
async function generatePortfolioMetadata(slug) {
|
|
105
|
+
const item = await getPortfolioItem(slug);
|
|
106
|
+
if (!item) {
|
|
107
|
+
return {};
|
|
108
|
+
}
|
|
109
|
+
const seo = item.seo;
|
|
110
|
+
const title = seo?.metaTitle || item.title;
|
|
111
|
+
const description = seo?.metaDescription || item.description;
|
|
112
|
+
const keywords = seo?.keywords ?? [];
|
|
113
|
+
const ogImages = [];
|
|
114
|
+
if (item.hero_image) {
|
|
115
|
+
ogImages.push(item.hero_image);
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
title,
|
|
119
|
+
description,
|
|
120
|
+
keywords: keywords.length > 0 ? keywords : void 0,
|
|
121
|
+
openGraph: {
|
|
122
|
+
title,
|
|
123
|
+
description,
|
|
124
|
+
images: ogImages.length > 0 ? ogImages : void 0,
|
|
125
|
+
type: "article"
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
async function generatePortfolioStaticParams() {
|
|
130
|
+
const data = await getPortfolioItems({ limit: 500, offset: 0 });
|
|
131
|
+
return data.items.map((item) => ({ slug: item.slug }));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
exports.generatePortfolioMetadata = generatePortfolioMetadata;
|
|
135
|
+
exports.generatePortfolioStaticParams = generatePortfolioStaticParams;
|
|
136
|
+
exports.getPortfolioBrandConfig = getPortfolioBrandConfig;
|
|
137
|
+
exports.getPortfolioCategories = getPortfolioCategories;
|
|
138
|
+
exports.getPortfolioItem = getPortfolioItem;
|
|
139
|
+
exports.getPortfolioItems = getPortfolioItems;
|
|
140
|
+
//# sourceMappingURL=server.cjs.map
|
|
141
|
+
//# sourceMappingURL=server.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/portfolio/server.ts"],"names":["apiGet"],"mappings":"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","file":"server.cjs","sourcesContent":["/**\n * @sonordev/agency-site-kit — Portfolio server-side data fetching\n *\n * RSC (React Server Component) data layer for portfolio pages.\n * All functions are async and designed for use in Next.js App Router\n * server components, generateMetadata(), and generateStaticParams().\n *\n * This file is server-only — no 'use client' directive.\n */\n\nimport { apiGet } from '../shared/api';\nimport type {\n BrandConfig,\n MetricsDelta,\n PortfolioConfigResponse,\n PortfolioItemFull,\n PortfolioListResponse,\n PortfolioSeoData,\n PortfolioSection,\n} from '../types';\n\nconst LOG_PREFIX = '[@sonordev/agency-site-kit/portfolio]';\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Builds a query string from an object, omitting undefined/null values.\n */\nfunction buildQuery(params: Record<string, string | number | boolean | undefined | null>): string {\n const entries = Object.entries(params).filter(\n (entry): entry is [string, string | number | boolean] => entry[1] != null,\n );\n if (entries.length === 0) return '';\n const qs = new URLSearchParams(\n entries.map(([k, v]) => [k, String(v)]),\n ).toString();\n return `?${qs}`;\n}\n\n// ---------------------------------------------------------------------------\n// Public API — List items\n// ---------------------------------------------------------------------------\n\n/**\n * Fetches published portfolio items from the public API.\n * Cached via Next.js ISR (revalidate: 3600).\n */\nexport async function getPortfolioItems(options?: {\n category?: string;\n featured?: boolean;\n limit?: number;\n offset?: number;\n}): Promise<PortfolioListResponse> {\n const fallback: PortfolioListResponse = { items: [], total: 0, limit: 0, offset: 0 };\n\n const query = buildQuery({\n category: options?.category,\n featured: options?.featured,\n limit: options?.limit,\n offset: options?.offset,\n });\n\n const data = await apiGet<PortfolioListResponse>(\n `/api/public/portfolio/items${query}`,\n );\n\n if (!data) {\n console.warn(`${LOG_PREFIX} Failed to fetch portfolio items.`);\n return fallback;\n }\n\n return data;\n}\n\n// ---------------------------------------------------------------------------\n// Public API — Single item\n// ---------------------------------------------------------------------------\n\n/** Shape returned by the single-item API endpoint. */\ninterface PortfolioItemApiResponse {\n found: boolean;\n item: {\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: PortfolioItemFull['kpis'];\n details: PortfolioItemFull['details'];\n seo: PortfolioItemFull['seo'];\n featured: boolean;\n order?: number;\n published_at: string | null;\n hero_screenshots: PortfolioItemFull['hero_screenshots'];\n baseline_metrics: PortfolioItemFull['baseline_metrics'];\n current_metrics: PortfolioItemFull['current_metrics'];\n metrics_last_refreshed_at: string | null;\n sections: PortfolioSection[];\n metricsDelta: MetricsDelta[];\n };\n}\n\n/**\n * Fetches a single portfolio item by slug, including full Sanity sections\n * and live metrics delta. This is the main data function for portfolio detail pages.\n *\n * Returns null when the item is not found or the API call fails.\n */\nexport async function getPortfolioItem(slug: string): Promise<PortfolioItemFull | null> {\n if (!slug) {\n console.warn(`${LOG_PREFIX} getPortfolioItem called with empty slug.`);\n return null;\n }\n\n const data = await apiGet<PortfolioItemApiResponse>(\n `/api/public/portfolio/items/${encodeURIComponent(slug)}`,\n );\n\n if (!data || !data.found || !data.item) {\n console.warn(`${LOG_PREFIX} Portfolio item not found for slug: \"${slug}\".`);\n return null;\n }\n\n // Map the API response to the PortfolioItemFull type\n const { item } = data;\n return {\n id: item.id,\n slug: item.slug,\n title: item.title,\n subtitle: item.subtitle,\n category: item.category,\n services: item.services,\n description: item.description,\n hero_image: item.hero_image,\n hero_image_alt: item.hero_image_alt,\n live_url: item.live_url,\n kpis: item.kpis,\n details: item.details,\n seo: item.seo,\n featured: item.featured,\n order: item.order,\n published_at: item.published_at,\n hero_screenshots: item.hero_screenshots,\n baseline_metrics: item.baseline_metrics,\n current_metrics: item.current_metrics,\n metrics_last_refreshed_at: item.metrics_last_refreshed_at,\n sections: item.sections ?? [],\n metricsDelta: item.metricsDelta ?? [],\n };\n}\n\n// ---------------------------------------------------------------------------\n// Public API — Categories\n// ---------------------------------------------------------------------------\n\n/**\n * Fetches available portfolio categories.\n * Returns an empty array on failure.\n */\nexport async function getPortfolioCategories(): Promise<string[]> {\n const data = await apiGet<string[]>('/api/public/portfolio/categories');\n\n if (!data) {\n console.warn(`${LOG_PREFIX} Failed to fetch portfolio categories.`);\n return [];\n }\n\n return data;\n}\n\n// ---------------------------------------------------------------------------\n// Public API — Brand config\n// ---------------------------------------------------------------------------\n\n/**\n * Fetches brand configuration for the agency (colors, fonts, logo).\n * Returns sensible defaults when the API call fails.\n */\nexport async function getPortfolioBrandConfig(): Promise<BrandConfig> {\n const fallback: BrandConfig = {\n primary: '#6366f1',\n secondary: '#8b5cf6',\n background: '#0a0a0f',\n backgroundElevated: '#12121a',\n surface: '#1a1a2e',\n surfaceHover: '#22223a',\n surfaceBorder: '#2a2a3e',\n textPrimary: '#f0f0f5',\n textSecondary: '#a0a0b5',\n textTertiary: '#6b6b80',\n fontHeading: 'Inter, system-ui, sans-serif',\n fontBody: 'Inter, system-ui, sans-serif',\n };\n\n const data = await apiGet<PortfolioConfigResponse>(\n '/api/public/portfolio/config',\n );\n\n if (!data || !data.brand) {\n console.warn(`${LOG_PREFIX} Failed to fetch brand config, using defaults.`);\n return fallback;\n }\n\n return data.brand;\n}\n\n// ---------------------------------------------------------------------------\n// Next.js Metadata helper\n// ---------------------------------------------------------------------------\n\n/**\n * Generates Next.js Metadata for a portfolio item page.\n * For use in generateMetadata() in the App Router.\n *\n * Returns an empty object when the item cannot be found, which is safe\n * to spread into the metadata return value.\n */\nexport async function generatePortfolioMetadata(slug: string): Promise<{\n title?: string;\n description?: string;\n keywords?: string[];\n openGraph?: {\n title?: string;\n description?: string;\n images?: string[];\n type?: string;\n };\n}> {\n const item = await getPortfolioItem(slug);\n\n if (!item) {\n return {};\n }\n\n // Prefer dedicated SEO data if available, fall back to item fields\n const seo: PortfolioSeoData | null = item.seo;\n const title = seo?.metaTitle || item.title;\n const description = seo?.metaDescription || item.description;\n const keywords = seo?.keywords ?? [];\n\n // Collect OG images: prefer SEO og image, then hero image\n const ogImages: string[] = [];\n if (item.hero_image) {\n ogImages.push(item.hero_image);\n }\n\n return {\n title,\n description,\n keywords: keywords.length > 0 ? keywords : undefined,\n openGraph: {\n title,\n description,\n images: ogImages.length > 0 ? ogImages : undefined,\n type: 'article',\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Next.js Static Params helper\n// ---------------------------------------------------------------------------\n\n/**\n * Generates static params for portfolio pages.\n * For use in generateStaticParams() in the App Router.\n *\n * Fetches all published portfolio items and returns their slugs.\n */\nexport async function generatePortfolioStaticParams(): Promise<Array<{ slug: string }>> {\n // Fetch a large batch to cover all published items\n const data = await getPortfolioItems({ limit: 500, offset: 0 });\n\n return data.items.map((item) => ({ slug: item.slug }));\n}\n"]}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { B as BrandConfig, P as PortfolioItemFull, a as PortfolioListResponse } from '../types-BMUhBhWx.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @sonordev/agency-site-kit — Portfolio server-side data fetching
|
|
5
|
+
*
|
|
6
|
+
* RSC (React Server Component) data layer for portfolio pages.
|
|
7
|
+
* All functions are async and designed for use in Next.js App Router
|
|
8
|
+
* server components, generateMetadata(), and generateStaticParams().
|
|
9
|
+
*
|
|
10
|
+
* This file is server-only — no 'use client' directive.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Fetches published portfolio items from the public API.
|
|
15
|
+
* Cached via Next.js ISR (revalidate: 3600).
|
|
16
|
+
*/
|
|
17
|
+
declare function getPortfolioItems(options?: {
|
|
18
|
+
category?: string;
|
|
19
|
+
featured?: boolean;
|
|
20
|
+
limit?: number;
|
|
21
|
+
offset?: number;
|
|
22
|
+
}): Promise<PortfolioListResponse>;
|
|
23
|
+
/**
|
|
24
|
+
* Fetches a single portfolio item by slug, including full Sanity sections
|
|
25
|
+
* and live metrics delta. This is the main data function for portfolio detail pages.
|
|
26
|
+
*
|
|
27
|
+
* Returns null when the item is not found or the API call fails.
|
|
28
|
+
*/
|
|
29
|
+
declare function getPortfolioItem(slug: string): Promise<PortfolioItemFull | null>;
|
|
30
|
+
/**
|
|
31
|
+
* Fetches available portfolio categories.
|
|
32
|
+
* Returns an empty array on failure.
|
|
33
|
+
*/
|
|
34
|
+
declare function getPortfolioCategories(): Promise<string[]>;
|
|
35
|
+
/**
|
|
36
|
+
* Fetches brand configuration for the agency (colors, fonts, logo).
|
|
37
|
+
* Returns sensible defaults when the API call fails.
|
|
38
|
+
*/
|
|
39
|
+
declare function getPortfolioBrandConfig(): Promise<BrandConfig>;
|
|
40
|
+
/**
|
|
41
|
+
* Generates Next.js Metadata for a portfolio item page.
|
|
42
|
+
* For use in generateMetadata() in the App Router.
|
|
43
|
+
*
|
|
44
|
+
* Returns an empty object when the item cannot be found, which is safe
|
|
45
|
+
* to spread into the metadata return value.
|
|
46
|
+
*/
|
|
47
|
+
declare function generatePortfolioMetadata(slug: string): Promise<{
|
|
48
|
+
title?: string;
|
|
49
|
+
description?: string;
|
|
50
|
+
keywords?: string[];
|
|
51
|
+
openGraph?: {
|
|
52
|
+
title?: string;
|
|
53
|
+
description?: string;
|
|
54
|
+
images?: string[];
|
|
55
|
+
type?: string;
|
|
56
|
+
};
|
|
57
|
+
}>;
|
|
58
|
+
/**
|
|
59
|
+
* Generates static params for portfolio pages.
|
|
60
|
+
* For use in generateStaticParams() in the App Router.
|
|
61
|
+
*
|
|
62
|
+
* Fetches all published portfolio items and returns their slugs.
|
|
63
|
+
*/
|
|
64
|
+
declare function generatePortfolioStaticParams(): Promise<Array<{
|
|
65
|
+
slug: string;
|
|
66
|
+
}>>;
|
|
67
|
+
|
|
68
|
+
export { generatePortfolioMetadata, generatePortfolioStaticParams, getPortfolioBrandConfig, getPortfolioCategories, getPortfolioItem, getPortfolioItems };
|