@burdenoff/website-sdk 2026.529.4 → 2026.610.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -114,6 +114,43 @@ interface BlogPostPageProps {
114
114
  declare function BlogListPage(props: BlogListPageProps): react_jsx_runtime.JSX.Element;
115
115
  declare function BlogPostPage(props: BlogPostPageProps): react_jsx_runtime.JSX.Element;
116
116
 
117
+ interface CaseStudiesListPageProps {
118
+ productName?: string;
119
+ heroTitle?: string;
120
+ heroSubtitle?: string;
121
+ caseStudyBasePath?: string;
122
+ className?: string;
123
+ seoTitle?: string;
124
+ seoDescription?: string;
125
+ seoKeywords?: string;
126
+ }
127
+ interface CaseStudyPageProps {
128
+ productName?: string;
129
+ caseStudiesListUrl?: string;
130
+ /** Back-link label. Default: "Back to Case Studies". */
131
+ backLabel?: string;
132
+ className?: string;
133
+ }
134
+ declare function CaseStudiesListPage(props: CaseStudiesListPageProps): react_jsx_runtime.JSX.Element;
135
+ declare function CaseStudyPage(props: CaseStudyPageProps): react_jsx_runtime.JSX.Element;
136
+
137
+ interface ChangelogPageProps {
138
+ productName?: string;
139
+ heroEyebrow?: string;
140
+ heroTitle?: string;
141
+ heroSubtitle?: string;
142
+ /** Optional bottom CTA. Rendered only when ctaHref + ctaLabel are provided. */
143
+ ctaTitle?: string;
144
+ ctaSubtitle?: string;
145
+ ctaHref?: string;
146
+ ctaLabel?: string;
147
+ className?: string;
148
+ seoTitle?: string;
149
+ seoDescription?: string;
150
+ seoKeywords?: string;
151
+ }
152
+ declare function ChangelogPage(props: ChangelogPageProps): react_jsx_runtime.JSX.Element;
153
+
117
154
  type PressKitAssetCategory = "LOGO" | "BANNER" | "SCREENSHOT" | "BROCHURE" | "DOCUMENT" | "PRESS_RELEASE" | "BRAND_GUIDE";
118
155
  interface PressKitAsset {
119
156
  id: string;
@@ -184,4 +221,4 @@ interface ContractsPageProps {
184
221
  }
185
222
  declare function ContractsPage(props: ContractsPageProps): react_jsx_runtime.JSX.Element;
186
223
 
187
- export { BlogListPage, type BlogListPageProps, BlogPostPage, type BlogPostPageProps, type ContentPageData, type ContentPageListData, type ContentPageListItem, ContentRenderer, type ContractAsset, ContractsPage, type ContractsPageProps, type PressKitAsset, type PressKitAssetCategory, PressKitPage, type PressKitPageProps, type UseContentPageOptions, useContentPage, useContentPages };
224
+ export { BlogListPage, type BlogListPageProps, BlogPostPage, type BlogPostPageProps, CaseStudiesListPage, type CaseStudiesListPageProps, CaseStudyPage, type CaseStudyPageProps, ChangelogPage, type ChangelogPageProps, type ContentPageData, type ContentPageListData, type ContentPageListItem, ContentRenderer, type ContractAsset, ContractsPage, type ContractsPageProps, type PressKitAsset, type PressKitAssetCategory, PressKitPage, type PressKitPageProps, type UseContentPageOptions, useContentPage, useContentPages };
@@ -114,6 +114,43 @@ interface BlogPostPageProps {
114
114
  declare function BlogListPage(props: BlogListPageProps): react_jsx_runtime.JSX.Element;
115
115
  declare function BlogPostPage(props: BlogPostPageProps): react_jsx_runtime.JSX.Element;
116
116
 
117
+ interface CaseStudiesListPageProps {
118
+ productName?: string;
119
+ heroTitle?: string;
120
+ heroSubtitle?: string;
121
+ caseStudyBasePath?: string;
122
+ className?: string;
123
+ seoTitle?: string;
124
+ seoDescription?: string;
125
+ seoKeywords?: string;
126
+ }
127
+ interface CaseStudyPageProps {
128
+ productName?: string;
129
+ caseStudiesListUrl?: string;
130
+ /** Back-link label. Default: "Back to Case Studies". */
131
+ backLabel?: string;
132
+ className?: string;
133
+ }
134
+ declare function CaseStudiesListPage(props: CaseStudiesListPageProps): react_jsx_runtime.JSX.Element;
135
+ declare function CaseStudyPage(props: CaseStudyPageProps): react_jsx_runtime.JSX.Element;
136
+
137
+ interface ChangelogPageProps {
138
+ productName?: string;
139
+ heroEyebrow?: string;
140
+ heroTitle?: string;
141
+ heroSubtitle?: string;
142
+ /** Optional bottom CTA. Rendered only when ctaHref + ctaLabel are provided. */
143
+ ctaTitle?: string;
144
+ ctaSubtitle?: string;
145
+ ctaHref?: string;
146
+ ctaLabel?: string;
147
+ className?: string;
148
+ seoTitle?: string;
149
+ seoDescription?: string;
150
+ seoKeywords?: string;
151
+ }
152
+ declare function ChangelogPage(props: ChangelogPageProps): react_jsx_runtime.JSX.Element;
153
+
117
154
  type PressKitAssetCategory = "LOGO" | "BANNER" | "SCREENSHOT" | "BROCHURE" | "DOCUMENT" | "PRESS_RELEASE" | "BRAND_GUIDE";
118
155
  interface PressKitAsset {
119
156
  id: string;
@@ -184,4 +221,4 @@ interface ContractsPageProps {
184
221
  }
185
222
  declare function ContractsPage(props: ContractsPageProps): react_jsx_runtime.JSX.Element;
186
223
 
187
- export { BlogListPage, type BlogListPageProps, BlogPostPage, type BlogPostPageProps, type ContentPageData, type ContentPageListData, type ContentPageListItem, ContentRenderer, type ContractAsset, ContractsPage, type ContractsPageProps, type PressKitAsset, type PressKitAssetCategory, PressKitPage, type PressKitPageProps, type UseContentPageOptions, useContentPage, useContentPages };
224
+ export { BlogListPage, type BlogListPageProps, BlogPostPage, type BlogPostPageProps, CaseStudiesListPage, type CaseStudiesListPageProps, CaseStudyPage, type CaseStudyPageProps, ChangelogPage, type ChangelogPageProps, type ContentPageData, type ContentPageListData, type ContentPageListItem, ContentRenderer, type ContractAsset, ContractsPage, type ContractsPageProps, type PressKitAsset, type PressKitAssetCategory, PressKitPage, type PressKitPageProps, type UseContentPageOptions, useContentPage, useContentPages };
@@ -774,6 +774,566 @@ function BlogPostPage(props) {
774
774
  ] })
775
775
  ] });
776
776
  }
777
+ var CASE_STUDY_TAG = "case-study";
778
+ var CASE_STUDIES_QUERY = `
779
+ query CaseStudies($productId: String!, $limit: Int, $offset: Int) {
780
+ publicContentPages(productId: $productId, limit: $limit, offset: $offset) {
781
+ items {
782
+ id
783
+ title
784
+ slug
785
+ lastUpdated
786
+ tags
787
+ seoDescription
788
+ excerpt
789
+ thumbnail
790
+ author
791
+ publishedAt
792
+ readingTime
793
+ featured
794
+ category
795
+ }
796
+ total
797
+ hasMore
798
+ }
799
+ }
800
+ `;
801
+ var CASE_STUDY_QUERY = `
802
+ query CaseStudy($slug: String!, $productId: String) {
803
+ publicContentPage(slug: $slug, productId: $productId) {
804
+ id
805
+ title
806
+ slug
807
+ content
808
+ contentFormat
809
+ seoTitle
810
+ seoDescription
811
+ seoKeywords
812
+ lastUpdated
813
+ tags
814
+ excerpt
815
+ thumbnail
816
+ author
817
+ publishedAt
818
+ readingTime
819
+ featured
820
+ category
821
+ }
822
+ }
823
+ `;
824
+ function CaseStudyCard({
825
+ post,
826
+ basePath = "/case-studies"
827
+ }) {
828
+ const date = post.publishedAt || post.lastUpdated;
829
+ const formattedDate = date ? new Date(date).toLocaleDateString("en-US", {
830
+ year: "numeric",
831
+ month: "long",
832
+ day: "numeric"
833
+ }) : "";
834
+ const [imgError, setImgError] = react.useState(false);
835
+ return /* @__PURE__ */ jsxRuntime.jsxs(
836
+ "a",
837
+ {
838
+ href: `${basePath}/${post.slug}`,
839
+ className: "group block bg-card border rounded-xl overflow-hidden hover:shadow-lg hover:border-primary/30 transition-all duration-300",
840
+ children: [
841
+ post.thumbnail && !imgError ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aspect-[16/9] overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
842
+ "img",
843
+ {
844
+ src: post.thumbnail,
845
+ alt: post.title,
846
+ className: "w-full h-full object-cover group-hover:scale-105 transition-transform duration-300",
847
+ loading: "lazy",
848
+ onError: () => setImgError(true)
849
+ }
850
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aspect-[16/9] bg-muted/50 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
851
+ "svg",
852
+ {
853
+ className: "w-12 h-12 text-muted-foreground/20",
854
+ fill: "none",
855
+ viewBox: "0 0 24 24",
856
+ stroke: "currentColor",
857
+ children: /* @__PURE__ */ jsxRuntime.jsx(
858
+ "path",
859
+ {
860
+ strokeLinecap: "round",
861
+ strokeLinejoin: "round",
862
+ strokeWidth: 1.5,
863
+ d: "M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"
864
+ }
865
+ )
866
+ }
867
+ ) }),
868
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-5 sm:p-6", children: [
869
+ post.category && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block text-xs font-medium text-primary bg-primary/10 px-2.5 py-1 rounded-full mb-3", children: post.category }),
870
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-foreground mb-2 group-hover:text-primary transition-colors line-clamp-2", children: post.title }),
871
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground mb-4 line-clamp-3", children: post.excerpt || post.seoDescription || "" }),
872
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-xs text-muted-foreground", children: [
873
+ post.author && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: post.author }),
874
+ post.author && formattedDate && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/40", children: "\xB7" }),
875
+ formattedDate && /* @__PURE__ */ jsxRuntime.jsx("span", { children: formattedDate }),
876
+ post.readingTime && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
877
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/40", children: "\xB7" }),
878
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
879
+ post.readingTime,
880
+ " min read"
881
+ ] })
882
+ ] })
883
+ ] })
884
+ ] })
885
+ ]
886
+ }
887
+ );
888
+ }
889
+ function CaseStudiesListPage(props) {
890
+ const {
891
+ productName,
892
+ heroTitle = "Case Studies",
893
+ heroSubtitle = "Real-world stories of teams building with our platform",
894
+ caseStudyBasePath = "/case-studies",
895
+ className = "",
896
+ seoTitle,
897
+ seoDescription,
898
+ seoKeywords
899
+ } = props;
900
+ const client = useWebSDK();
901
+ const config = useWebSDKConfig();
902
+ const { product } = useProduct();
903
+ const resolvedProductId = product?.id || config.productId;
904
+ const [posts, setPosts] = react.useState([]);
905
+ const [total, setTotal] = react.useState(0);
906
+ const [loading, setLoading] = react.useState(true);
907
+ const [error, setError] = react.useState(null);
908
+ const [offset, setOffset] = react.useState(0);
909
+ const limit = 12;
910
+ const fetchPosts = react.useCallback(async () => {
911
+ if (!resolvedProductId) return;
912
+ setLoading(true);
913
+ try {
914
+ const result = await client.query(CASE_STUDIES_QUERY, {
915
+ productId: resolvedProductId,
916
+ limit,
917
+ offset
918
+ });
919
+ if (result.errors?.length) {
920
+ setError(result.errors[0]?.message ?? "Failed to load case studies");
921
+ return;
922
+ }
923
+ const caseStudies = (result.data?.publicContentPages?.items || []).filter(
924
+ (p) => p.tags?.includes(CASE_STUDY_TAG)
925
+ );
926
+ setPosts(caseStudies);
927
+ setTotal(result.data?.publicContentPages?.total || 0);
928
+ setError(null);
929
+ } catch {
930
+ setError("Failed to load case studies");
931
+ } finally {
932
+ setLoading(false);
933
+ }
934
+ }, [client, resolvedProductId, offset]);
935
+ react.useEffect(() => {
936
+ fetchPosts();
937
+ }, [fetchPosts]);
938
+ const featuredPosts = posts.filter((p) => p.featured);
939
+ const regularPosts = posts.filter((p) => !p.featured);
940
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `w-full ${className}`, children: [
941
+ seoTitle && /* @__PURE__ */ jsxRuntime.jsx(
942
+ PageHead,
943
+ {
944
+ title: seoTitle,
945
+ description: seoDescription || heroSubtitle,
946
+ productName,
947
+ keywords: seoKeywords
948
+ }
949
+ ),
950
+ /* @__PURE__ */ jsxRuntime.jsx("section", { className: "py-16 sm:py-20 md:py-24", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center max-w-3xl mx-auto", children: [
951
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl sm:text-4xl md:text-5xl font-bold tracking-tight text-foreground", children: heroTitle }),
952
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-4 text-lg text-muted-foreground", children: heroSubtitle })
953
+ ] }) }) }),
954
+ /* @__PURE__ */ jsxRuntime.jsx("section", { className: "pb-16 sm:pb-20", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid md:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8", children: [1, 2, 3].map((i) => /* @__PURE__ */ jsxRuntime.jsxs(
955
+ "div",
956
+ {
957
+ className: "bg-card border rounded-xl overflow-hidden animate-pulse",
958
+ children: [
959
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aspect-[16/9] bg-muted" }),
960
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6 space-y-3", children: [
961
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 bg-muted rounded w-1/4" }),
962
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-6 bg-muted rounded w-3/4" }),
963
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 bg-muted rounded" }),
964
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 bg-muted rounded w-1/2" })
965
+ ] })
966
+ ]
967
+ },
968
+ i
969
+ )) }) : error ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-12", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: error }) }) : posts.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-12", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: "No case studies yet. Check back soon!" }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
970
+ featuredPosts.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid md:grid-cols-2 gap-6 sm:gap-8 mb-8", children: featuredPosts.map((post) => /* @__PURE__ */ jsxRuntime.jsx(
971
+ CaseStudyCard,
972
+ {
973
+ post,
974
+ basePath: caseStudyBasePath
975
+ },
976
+ post.id
977
+ )) }),
978
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid md:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8", children: regularPosts.map((post) => /* @__PURE__ */ jsxRuntime.jsx(
979
+ CaseStudyCard,
980
+ {
981
+ post,
982
+ basePath: caseStudyBasePath
983
+ },
984
+ post.id
985
+ )) }),
986
+ total > limit && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-center gap-4 mt-12", children: [
987
+ /* @__PURE__ */ jsxRuntime.jsx(
988
+ "button",
989
+ {
990
+ onClick: () => setOffset(Math.max(0, offset - limit)),
991
+ disabled: offset === 0,
992
+ className: "px-5 py-2.5 text-sm font-medium border rounded-lg disabled:opacity-40 hover:bg-muted transition-colors",
993
+ children: "Previous"
994
+ }
995
+ ),
996
+ /* @__PURE__ */ jsxRuntime.jsx(
997
+ "button",
998
+ {
999
+ onClick: () => setOffset(offset + limit),
1000
+ disabled: offset + limit >= total,
1001
+ className: "px-5 py-2.5 text-sm font-medium border rounded-lg disabled:opacity-40 hover:bg-muted transition-colors",
1002
+ children: "Next"
1003
+ }
1004
+ )
1005
+ ] })
1006
+ ] }) }) })
1007
+ ] });
1008
+ }
1009
+ function CaseStudyPage(props) {
1010
+ const {
1011
+ productName,
1012
+ caseStudiesListUrl = "/case-studies",
1013
+ backLabel = "Back to Case Studies",
1014
+ className = ""
1015
+ } = props;
1016
+ const client = useWebSDK();
1017
+ const config = useWebSDKConfig();
1018
+ const { product } = useProduct();
1019
+ const resolvedProductId = product?.id || config.productId;
1020
+ const [post, setPost] = react.useState(null);
1021
+ const [loading, setLoading] = react.useState(true);
1022
+ const [error, setError] = react.useState(null);
1023
+ const slug = typeof window !== "undefined" ? window.location.pathname.split("/").pop() || "" : "";
1024
+ react.useEffect(() => {
1025
+ if (!slug || !resolvedProductId) return;
1026
+ async function fetchPost() {
1027
+ setLoading(true);
1028
+ try {
1029
+ const result = await client.query(CASE_STUDY_QUERY, {
1030
+ slug,
1031
+ productId: resolvedProductId
1032
+ });
1033
+ if (result.errors?.length) {
1034
+ setError(result.errors[0]?.message ?? "Failed to load case study");
1035
+ return;
1036
+ }
1037
+ setPost(result.data?.publicContentPage ?? null);
1038
+ setError(null);
1039
+ } catch {
1040
+ setError("Failed to load case study");
1041
+ } finally {
1042
+ setLoading(false);
1043
+ }
1044
+ }
1045
+ fetchPost();
1046
+ }, [client, slug, resolvedProductId]);
1047
+ if (loading) {
1048
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-full ${className}`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-24", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "animate-pulse space-y-6", children: [
1049
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-8 bg-muted rounded w-2/3" }),
1050
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 bg-muted rounded w-1/3" }),
1051
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aspect-[16/9] bg-muted rounded-xl" }),
1052
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: [1, 2, 3, 4, 5].map((i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 bg-muted rounded" }, i)) })
1053
+ ] }) }) });
1054
+ }
1055
+ if (error || !post) {
1056
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-full ${className}`, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-24 text-center", children: [
1057
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl font-bold mb-4", children: "Case study not found" }),
1058
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground mb-6", children: error || "This case study doesn't exist or has been removed." }),
1059
+ /* @__PURE__ */ jsxRuntime.jsxs(
1060
+ "a",
1061
+ {
1062
+ href: caseStudiesListUrl,
1063
+ className: "text-primary hover:underline font-medium",
1064
+ children: [
1065
+ "\u2190 ",
1066
+ backLabel
1067
+ ]
1068
+ }
1069
+ )
1070
+ ] }) });
1071
+ }
1072
+ const date = post.publishedAt || post.lastUpdated;
1073
+ const formattedDate = date ? new Date(date).toLocaleDateString("en-US", {
1074
+ year: "numeric",
1075
+ month: "long",
1076
+ day: "numeric"
1077
+ }) : "";
1078
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `w-full ${className}`, children: [
1079
+ /* @__PURE__ */ jsxRuntime.jsx(
1080
+ PageHead,
1081
+ {
1082
+ title: post.seoTitle || post.title,
1083
+ description: post.seoDescription || post.excerpt || "",
1084
+ productName,
1085
+ keywords: post.seoKeywords || ""
1086
+ }
1087
+ ),
1088
+ /* @__PURE__ */ jsxRuntime.jsxs("article", { className: "max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-16 sm:py-20", children: [
1089
+ /* @__PURE__ */ jsxRuntime.jsxs(
1090
+ "a",
1091
+ {
1092
+ href: caseStudiesListUrl,
1093
+ className: "inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground mb-8 transition-colors",
1094
+ children: [
1095
+ "\u2190 ",
1096
+ backLabel
1097
+ ]
1098
+ }
1099
+ ),
1100
+ post.category && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block text-xs font-medium text-primary bg-primary/10 px-2.5 py-1 rounded-full mb-4", children: post.category }),
1101
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl sm:text-4xl md:text-5xl font-bold tracking-tight text-foreground mb-4", children: post.title }),
1102
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-sm text-muted-foreground mb-8", children: [
1103
+ post.author && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-foreground", children: post.author }),
1104
+ post.author && formattedDate && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/40", children: "\xB7" }),
1105
+ formattedDate && /* @__PURE__ */ jsxRuntime.jsx("span", { children: formattedDate }),
1106
+ post.readingTime && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1107
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground/40", children: "\xB7" }),
1108
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
1109
+ post.readingTime,
1110
+ " min read"
1111
+ ] })
1112
+ ] })
1113
+ ] }),
1114
+ post.thumbnail && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "aspect-[16/9] rounded-xl overflow-hidden mb-10", children: /* @__PURE__ */ jsxRuntime.jsx(
1115
+ "img",
1116
+ {
1117
+ src: post.thumbnail,
1118
+ alt: post.title,
1119
+ className: "w-full h-full object-cover"
1120
+ }
1121
+ ) }),
1122
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "prose prose-gray dark:prose-invert max-w-none", children: /* @__PURE__ */ jsxRuntime.jsx(ContentRenderer, { content: post.content, format: post.contentFormat }) })
1123
+ ] })
1124
+ ] });
1125
+ }
1126
+ var CHANGELOG_TAG = "changelog";
1127
+ var CHANGELOG_LIST_QUERY = `
1128
+ query ChangelogList($productId: String!, $limit: Int, $offset: Int) {
1129
+ publicContentPages(productId: $productId, limit: $limit, offset: $offset) {
1130
+ items {
1131
+ id
1132
+ title
1133
+ slug
1134
+ lastUpdated
1135
+ tags
1136
+ excerpt
1137
+ seoDescription
1138
+ thumbnail
1139
+ author
1140
+ publishedAt
1141
+ readingTime
1142
+ featured
1143
+ category
1144
+ }
1145
+ total
1146
+ hasMore
1147
+ }
1148
+ }
1149
+ `;
1150
+ var CHANGELOG_ENTRY_QUERY = `
1151
+ query ChangelogEntry($slug: String!, $productId: String) {
1152
+ publicContentPage(slug: $slug, productId: $productId) {
1153
+ content
1154
+ contentFormat
1155
+ }
1156
+ }
1157
+ `;
1158
+ function formatDate(value) {
1159
+ if (!value) return "";
1160
+ return new Date(value).toLocaleDateString("en-US", {
1161
+ year: "numeric",
1162
+ month: "long",
1163
+ day: "numeric"
1164
+ });
1165
+ }
1166
+ function sortByDateDesc(a, b) {
1167
+ const da = new Date(a.publishedAt || a.lastUpdated || 0).getTime();
1168
+ const db = new Date(b.publishedAt || b.lastUpdated || 0).getTime();
1169
+ return db - da;
1170
+ }
1171
+ function ChangelogPage(props) {
1172
+ const {
1173
+ productName,
1174
+ heroEyebrow = "What's new",
1175
+ heroTitle = "Changelog",
1176
+ heroSubtitle = "Platform updates, improvements, and announcements \u2014 newest first.",
1177
+ ctaTitle,
1178
+ ctaSubtitle,
1179
+ ctaHref,
1180
+ ctaLabel,
1181
+ className = "",
1182
+ seoTitle,
1183
+ seoDescription,
1184
+ seoKeywords
1185
+ } = props;
1186
+ const client = useWebSDK();
1187
+ const config = useWebSDKConfig();
1188
+ const { product } = useProduct();
1189
+ const resolvedProductId = product?.id || config.productId;
1190
+ const [entries, setEntries] = react.useState([]);
1191
+ const [loading, setLoading] = react.useState(true);
1192
+ const [error, setError] = react.useState(null);
1193
+ const fetchEntries = react.useCallback(async () => {
1194
+ if (!resolvedProductId) return;
1195
+ setLoading(true);
1196
+ try {
1197
+ const listResult = await client.query(CHANGELOG_LIST_QUERY, {
1198
+ productId: resolvedProductId,
1199
+ limit: 50,
1200
+ offset: 0
1201
+ });
1202
+ if (listResult.errors?.length) {
1203
+ setError(listResult.errors[0]?.message ?? "Failed to load changelog");
1204
+ return;
1205
+ }
1206
+ const changelogItems = (listResult.data?.publicContentPages?.items || []).filter((p) => p.tags?.includes(CHANGELOG_TAG)).sort(sortByDateDesc);
1207
+ const resolved = await Promise.all(
1208
+ changelogItems.map(async (item) => {
1209
+ try {
1210
+ const detail = await client.query(CHANGELOG_ENTRY_QUERY, {
1211
+ slug: item.slug,
1212
+ productId: resolvedProductId
1213
+ });
1214
+ const page = detail.data?.publicContentPage;
1215
+ return {
1216
+ ...item,
1217
+ content: page?.content,
1218
+ contentFormat: page?.contentFormat
1219
+ };
1220
+ } catch {
1221
+ return { ...item };
1222
+ }
1223
+ })
1224
+ );
1225
+ setEntries(resolved);
1226
+ setError(null);
1227
+ } catch {
1228
+ setError("Failed to load changelog");
1229
+ } finally {
1230
+ setLoading(false);
1231
+ }
1232
+ }, [client, resolvedProductId]);
1233
+ react.useEffect(() => {
1234
+ fetchEntries();
1235
+ }, [fetchEntries]);
1236
+ const showCta = Boolean(ctaHref && ctaLabel);
1237
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `w-full ${className}`, children: [
1238
+ seoTitle && /* @__PURE__ */ jsxRuntime.jsx(
1239
+ PageHead,
1240
+ {
1241
+ title: seoTitle,
1242
+ description: seoDescription || heroSubtitle,
1243
+ productName,
1244
+ keywords: seoKeywords
1245
+ }
1246
+ ),
1247
+ /* @__PURE__ */ jsxRuntime.jsx("section", { className: "py-16 md:py-20 px-4 sm:px-6 lg:px-8 text-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-3xl mx-auto", children: [
1248
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-primary/10 border border-primary/20 text-xs font-medium text-primary mb-6", children: [
1249
+ /* @__PURE__ */ jsxRuntime.jsx(
1250
+ "svg",
1251
+ {
1252
+ className: "h-3.5 w-3.5",
1253
+ fill: "none",
1254
+ viewBox: "0 0 24 24",
1255
+ stroke: "currentColor",
1256
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1257
+ "path",
1258
+ {
1259
+ strokeLinecap: "round",
1260
+ strokeLinejoin: "round",
1261
+ strokeWidth: 2,
1262
+ d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
1263
+ }
1264
+ )
1265
+ }
1266
+ ),
1267
+ heroEyebrow
1268
+ ] }),
1269
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-4xl sm:text-5xl font-bold text-foreground mb-4", children: heroTitle }),
1270
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-lg text-muted-foreground", children: heroSubtitle })
1271
+ ] }) }),
1272
+ /* @__PURE__ */ jsxRuntime.jsx("section", { className: "px-4 sm:px-6 lg:px-8 pb-20", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-3xl mx-auto space-y-12", children: loading ? [1, 2, 3].map((i) => /* @__PURE__ */ jsxRuntime.jsx(
1273
+ "div",
1274
+ {
1275
+ className: "rounded-2xl border border-border/40 bg-card overflow-hidden animate-pulse",
1276
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6 sm:p-8 space-y-4", children: [
1277
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-muted rounded w-1/3" }),
1278
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-6 bg-muted rounded w-2/3" }),
1279
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 bg-muted rounded" }),
1280
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 bg-muted rounded w-5/6" })
1281
+ ] })
1282
+ },
1283
+ i
1284
+ )) : error ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-12", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: error }) }) : entries.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-12", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: "No changelog entries yet. Check back soon!" }) }) : entries.map((entry) => /* @__PURE__ */ jsxRuntime.jsxs(
1285
+ "article",
1286
+ {
1287
+ id: entry.slug,
1288
+ className: "rounded-2xl border border-border/40 bg-card overflow-hidden scroll-mt-24",
1289
+ children: [
1290
+ entry.thumbnail && /* @__PURE__ */ jsxRuntime.jsx(
1291
+ "img",
1292
+ {
1293
+ src: entry.thumbnail,
1294
+ alt: "",
1295
+ width: 1024,
1296
+ height: 576,
1297
+ loading: "lazy",
1298
+ decoding: "async",
1299
+ className: "w-full aspect-video object-cover border-b border-border/40"
1300
+ }
1301
+ ),
1302
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6 sm:p-8", children: [
1303
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground mb-2", children: [
1304
+ entry.publishedAt && /* @__PURE__ */ jsxRuntime.jsx("time", { dateTime: entry.publishedAt, children: formatDate(entry.publishedAt || entry.lastUpdated) }),
1305
+ entry.author && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1306
+ " \xB7 ",
1307
+ entry.author
1308
+ ] })
1309
+ ] }),
1310
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl sm:text-2xl font-bold text-foreground mb-4", children: entry.title }),
1311
+ entry.content ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "prose prose-sm prose-gray dark:prose-invert max-w-none", children: /* @__PURE__ */ jsxRuntime.jsx(
1312
+ ContentRenderer,
1313
+ {
1314
+ content: entry.content,
1315
+ format: entry.contentFormat
1316
+ }
1317
+ ) }) : entry.excerpt && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground leading-relaxed", children: entry.excerpt })
1318
+ ] })
1319
+ ]
1320
+ },
1321
+ entry.id
1322
+ )) }) }),
1323
+ showCta && /* @__PURE__ */ jsxRuntime.jsx("section", { className: "py-14 px-4 sm:px-6 lg:px-8 bg-primary/5 border-t border-border/40", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-2xl mx-auto text-center", children: [
1324
+ ctaTitle && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl font-bold text-foreground mb-3", children: ctaTitle }),
1325
+ ctaSubtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground mb-7", children: ctaSubtitle }),
1326
+ /* @__PURE__ */ jsxRuntime.jsx(
1327
+ "a",
1328
+ {
1329
+ href: ctaHref,
1330
+ className: "inline-flex items-center justify-center rounded-lg bg-primary px-6 py-3 text-sm font-medium text-primary-foreground hover:opacity-90 transition-opacity",
1331
+ children: ctaLabel
1332
+ }
1333
+ )
1334
+ ] }) })
1335
+ ] });
1336
+ }
777
1337
 
778
1338
  // src/content/utils.ts
779
1339
  function formatBytes(bytes) {
@@ -1576,6 +2136,9 @@ function ContractsPage(props) {
1576
2136
 
1577
2137
  exports.BlogListPage = BlogListPage;
1578
2138
  exports.BlogPostPage = BlogPostPage;
2139
+ exports.CaseStudiesListPage = CaseStudiesListPage;
2140
+ exports.CaseStudyPage = CaseStudyPage;
2141
+ exports.ChangelogPage = ChangelogPage;
1579
2142
  exports.ContentRenderer = ContentRenderer;
1580
2143
  exports.ContractsPage = ContractsPage;
1581
2144
  exports.PressKitPage = PressKitPage;