@burdenoff/website-sdk 2026.516.13 → 2026.516.15

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/index.mjs CHANGED
@@ -2758,6 +2758,15 @@ var PUBLIC_CONTENT_PAGES_QUERY = `
2758
2758
  title
2759
2759
  slug
2760
2760
  lastUpdated
2761
+ tags
2762
+ excerpt
2763
+ thumbnail
2764
+ author
2765
+ publishedAt
2766
+ readingTime
2767
+ featured
2768
+ category
2769
+ seoDescription
2761
2770
  }
2762
2771
  total
2763
2772
  hasMore
@@ -2855,7 +2864,347 @@ function ContentRenderer({
2855
2864
  }
2856
2865
  return /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsx("pre", { style: { whiteSpace: "pre-wrap", fontFamily: "inherit" }, children: content }) });
2857
2866
  }
2867
+ var BLOG_POSTS_QUERY = `
2868
+ query BlogPosts($productId: String!, $limit: Int, $offset: Int) {
2869
+ publicContentPages(productId: $productId, limit: $limit, offset: $offset) {
2870
+ items {
2871
+ id
2872
+ title
2873
+ slug
2874
+ lastUpdated
2875
+ tags
2876
+ excerpt
2877
+ thumbnail
2878
+ author
2879
+ publishedAt
2880
+ readingTime
2881
+ featured
2882
+ category
2883
+ seoDescription
2884
+ }
2885
+ total
2886
+ hasMore
2887
+ }
2888
+ }
2889
+ `;
2890
+ var BLOG_POST_QUERY = `
2891
+ query BlogPost($slug: String!, $productId: String) {
2892
+ publicContentPage(slug: $slug, productId: $productId) {
2893
+ id
2894
+ title
2895
+ slug
2896
+ content
2897
+ contentFormat
2898
+ seoTitle
2899
+ seoDescription
2900
+ seoKeywords
2901
+ lastUpdated
2902
+ tags
2903
+ excerpt
2904
+ thumbnail
2905
+ author
2906
+ publishedAt
2907
+ readingTime
2908
+ category
2909
+ }
2910
+ }
2911
+ `;
2912
+ function BlogCard({
2913
+ post,
2914
+ basePath = "/blog"
2915
+ }) {
2916
+ const date = post.publishedAt || post.lastUpdated;
2917
+ const formattedDate = date ? new Date(date).toLocaleDateString("en-US", {
2918
+ year: "numeric",
2919
+ month: "long",
2920
+ day: "numeric"
2921
+ }) : "";
2922
+ return /* @__PURE__ */ jsxs(
2923
+ "a",
2924
+ {
2925
+ href: `${basePath}/${post.slug}`,
2926
+ className: "group block bg-card border rounded-xl overflow-hidden hover:shadow-lg hover:border-primary/30 transition-all duration-300",
2927
+ children: [
2928
+ post.thumbnail ? /* @__PURE__ */ jsx("div", { className: "aspect-[16/9] overflow-hidden", children: /* @__PURE__ */ jsx(
2929
+ "img",
2930
+ {
2931
+ src: post.thumbnail,
2932
+ alt: post.title,
2933
+ className: "w-full h-full object-cover group-hover:scale-105 transition-transform duration-300",
2934
+ loading: "lazy"
2935
+ }
2936
+ ) }) : /* @__PURE__ */ jsx("div", { className: "aspect-[16/9] bg-muted/50 flex items-center justify-center", children: /* @__PURE__ */ jsx(
2937
+ "svg",
2938
+ {
2939
+ className: "w-12 h-12 text-muted-foreground/20",
2940
+ fill: "none",
2941
+ viewBox: "0 0 24 24",
2942
+ stroke: "currentColor",
2943
+ children: /* @__PURE__ */ jsx(
2944
+ "path",
2945
+ {
2946
+ strokeLinecap: "round",
2947
+ strokeLinejoin: "round",
2948
+ strokeWidth: 1.5,
2949
+ 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"
2950
+ }
2951
+ )
2952
+ }
2953
+ ) }),
2954
+ /* @__PURE__ */ jsxs("div", { className: "p-5 sm:p-6", children: [
2955
+ post.category && /* @__PURE__ */ 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 }),
2956
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold text-foreground mb-2 group-hover:text-primary transition-colors line-clamp-2", children: post.title }),
2957
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mb-4 line-clamp-3", children: post.excerpt || post.seoDescription || "" }),
2958
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-xs text-muted-foreground", children: [
2959
+ post.author && /* @__PURE__ */ jsx("span", { className: "font-medium", children: post.author }),
2960
+ post.author && formattedDate && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/40", children: "\xB7" }),
2961
+ formattedDate && /* @__PURE__ */ jsx("span", { children: formattedDate }),
2962
+ post.readingTime && /* @__PURE__ */ jsxs(Fragment, { children: [
2963
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/40", children: "\xB7" }),
2964
+ /* @__PURE__ */ jsxs("span", { children: [
2965
+ post.readingTime,
2966
+ " min read"
2967
+ ] })
2968
+ ] })
2969
+ ] })
2970
+ ] })
2971
+ ]
2972
+ }
2973
+ );
2974
+ }
2975
+ function BlogListPage(props) {
2976
+ const {
2977
+ productName,
2978
+ heroTitle = "Blog",
2979
+ heroSubtitle = "Latest updates, engineering insights, and product news",
2980
+ blogPostBasePath = "/blog",
2981
+ className = "",
2982
+ seoTitle,
2983
+ seoDescription,
2984
+ seoKeywords
2985
+ } = props;
2986
+ const client = useWebSDK();
2987
+ const config = useWebSDKConfig();
2988
+ const { product } = useProduct();
2989
+ const resolvedProductId = product?.id || config.productId;
2990
+ const [posts, setPosts] = useState([]);
2991
+ const [total, setTotal] = useState(0);
2992
+ const [loading, setLoading] = useState(true);
2993
+ const [error, setError] = useState(null);
2994
+ const [offset, setOffset] = useState(0);
2995
+ const limit = 12;
2996
+ const fetchPosts = useCallback(async () => {
2997
+ if (!resolvedProductId) return;
2998
+ setLoading(true);
2999
+ try {
3000
+ const result = await client.query(BLOG_POSTS_QUERY, {
3001
+ productId: resolvedProductId,
3002
+ limit,
3003
+ offset
3004
+ });
3005
+ if (result.errors?.length) {
3006
+ setError(result.errors[0]?.message ?? "Failed to load posts");
3007
+ return;
3008
+ }
3009
+ const blogPosts = (result.data?.publicContentPages?.items || []).filter(
3010
+ (p) => p.tags?.includes("blog")
3011
+ );
3012
+ setPosts(blogPosts);
3013
+ setTotal(result.data?.publicContentPages?.total || 0);
3014
+ setError(null);
3015
+ } catch {
3016
+ setError("Failed to load blog posts");
3017
+ } finally {
3018
+ setLoading(false);
3019
+ }
3020
+ }, [client, resolvedProductId, offset]);
3021
+ useEffect(() => {
3022
+ fetchPosts();
3023
+ }, [fetchPosts]);
3024
+ const featuredPosts = posts.filter((p) => p.featured);
3025
+ const regularPosts = posts.filter((p) => !p.featured);
3026
+ return /* @__PURE__ */ jsxs("div", { className: `w-full ${className}`, children: [
3027
+ seoTitle && /* @__PURE__ */ jsx(
3028
+ PageHead,
3029
+ {
3030
+ title: seoTitle,
3031
+ description: seoDescription || heroSubtitle,
3032
+ productName,
3033
+ keywords: seoKeywords
3034
+ }
3035
+ ),
3036
+ /* @__PURE__ */ jsx("section", { className: "py-16 sm:py-20 md:py-24", children: /* @__PURE__ */ jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsxs("div", { className: "text-center max-w-3xl mx-auto", children: [
3037
+ /* @__PURE__ */ jsx("h1", { className: "text-3xl sm:text-4xl md:text-5xl font-bold tracking-tight text-foreground", children: heroTitle }),
3038
+ /* @__PURE__ */ jsx("p", { className: "mt-4 text-lg text-muted-foreground", children: heroSubtitle })
3039
+ ] }) }) }),
3040
+ /* @__PURE__ */ jsx("section", { className: "pb-16 sm:pb-20", children: /* @__PURE__ */ jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: loading ? /* @__PURE__ */ jsx("div", { className: "grid md:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8", children: [1, 2, 3].map((i) => /* @__PURE__ */ jsxs(
3041
+ "div",
3042
+ {
3043
+ className: "bg-card border rounded-xl overflow-hidden animate-pulse",
3044
+ children: [
3045
+ /* @__PURE__ */ jsx("div", { className: "aspect-[16/9] bg-muted" }),
3046
+ /* @__PURE__ */ jsxs("div", { className: "p-6 space-y-3", children: [
3047
+ /* @__PURE__ */ jsx("div", { className: "h-4 bg-muted rounded w-1/4" }),
3048
+ /* @__PURE__ */ jsx("div", { className: "h-6 bg-muted rounded w-3/4" }),
3049
+ /* @__PURE__ */ jsx("div", { className: "h-4 bg-muted rounded" }),
3050
+ /* @__PURE__ */ jsx("div", { className: "h-4 bg-muted rounded w-1/2" })
3051
+ ] })
3052
+ ]
3053
+ },
3054
+ i
3055
+ )) }) : error ? /* @__PURE__ */ jsx("div", { className: "text-center py-12", children: /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: error }) }) : posts.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-center py-12", children: /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "No blog posts yet. Check back soon!" }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3056
+ featuredPosts.length > 0 && /* @__PURE__ */ jsx("div", { className: "grid md:grid-cols-2 gap-6 sm:gap-8 mb-8", children: featuredPosts.map((post) => /* @__PURE__ */ jsx(
3057
+ BlogCard,
3058
+ {
3059
+ post,
3060
+ basePath: blogPostBasePath
3061
+ },
3062
+ post.id
3063
+ )) }),
3064
+ /* @__PURE__ */ jsx("div", { className: "grid md:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8", children: regularPosts.map((post) => /* @__PURE__ */ jsx(
3065
+ BlogCard,
3066
+ {
3067
+ post,
3068
+ basePath: blogPostBasePath
3069
+ },
3070
+ post.id
3071
+ )) }),
3072
+ total > limit && /* @__PURE__ */ jsxs("div", { className: "flex justify-center gap-4 mt-12", children: [
3073
+ /* @__PURE__ */ jsx(
3074
+ "button",
3075
+ {
3076
+ onClick: () => setOffset(Math.max(0, offset - limit)),
3077
+ disabled: offset === 0,
3078
+ className: "px-5 py-2.5 text-sm font-medium border rounded-lg disabled:opacity-40 hover:bg-muted transition-colors",
3079
+ children: "Previous"
3080
+ }
3081
+ ),
3082
+ /* @__PURE__ */ jsx(
3083
+ "button",
3084
+ {
3085
+ onClick: () => setOffset(offset + limit),
3086
+ disabled: offset + limit >= total,
3087
+ className: "px-5 py-2.5 text-sm font-medium border rounded-lg disabled:opacity-40 hover:bg-muted transition-colors",
3088
+ children: "Next"
3089
+ }
3090
+ )
3091
+ ] })
3092
+ ] }) }) })
3093
+ ] });
3094
+ }
3095
+ function BlogPostPage(props) {
3096
+ const { productName, blogListUrl = "/blog", className = "" } = props;
3097
+ const client = useWebSDK();
3098
+ const config = useWebSDKConfig();
3099
+ const { product } = useProduct();
3100
+ const resolvedProductId = product?.id || config.productId;
3101
+ const [post, setPost] = useState(null);
3102
+ const [loading, setLoading] = useState(true);
3103
+ const [error, setError] = useState(null);
3104
+ const slug = typeof window !== "undefined" ? window.location.pathname.split("/").pop() || "" : "";
3105
+ useEffect(() => {
3106
+ if (!slug || !resolvedProductId) return;
3107
+ async function fetchPost() {
3108
+ setLoading(true);
3109
+ try {
3110
+ const result = await client.query(BLOG_POST_QUERY, {
3111
+ slug,
3112
+ productId: resolvedProductId
3113
+ });
3114
+ if (result.errors?.length) {
3115
+ setError(result.errors[0]?.message ?? "Failed to load post");
3116
+ return;
3117
+ }
3118
+ setPost(result.data?.publicContentPage ?? null);
3119
+ setError(null);
3120
+ } catch {
3121
+ setError("Failed to load blog post");
3122
+ } finally {
3123
+ setLoading(false);
3124
+ }
3125
+ }
3126
+ fetchPost();
3127
+ }, [client, slug, resolvedProductId]);
3128
+ if (loading) {
3129
+ return /* @__PURE__ */ jsx("div", { className: `w-full ${className}`, children: /* @__PURE__ */ jsx("div", { className: "max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-24", children: /* @__PURE__ */ jsxs("div", { className: "animate-pulse space-y-6", children: [
3130
+ /* @__PURE__ */ jsx("div", { className: "h-8 bg-muted rounded w-2/3" }),
3131
+ /* @__PURE__ */ jsx("div", { className: "h-4 bg-muted rounded w-1/3" }),
3132
+ /* @__PURE__ */ jsx("div", { className: "aspect-[16/9] bg-muted rounded-xl" }),
3133
+ /* @__PURE__ */ jsx("div", { className: "space-y-3", children: [1, 2, 3, 4, 5].map((i) => /* @__PURE__ */ jsx("div", { className: "h-4 bg-muted rounded" }, i)) })
3134
+ ] }) }) });
3135
+ }
3136
+ if (error || !post) {
3137
+ return /* @__PURE__ */ jsx("div", { className: `w-full ${className}`, children: /* @__PURE__ */ jsxs("div", { className: "max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-24 text-center", children: [
3138
+ /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold mb-4", children: "Post not found" }),
3139
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground mb-6", children: error || "This blog post doesn't exist or has been removed." }),
3140
+ /* @__PURE__ */ jsx(
3141
+ "a",
3142
+ {
3143
+ href: blogListUrl,
3144
+ className: "text-primary hover:underline font-medium",
3145
+ children: "\u2190 Back to Blog"
3146
+ }
3147
+ )
3148
+ ] }) });
3149
+ }
3150
+ const date = post.publishedAt || post.lastUpdated;
3151
+ const formattedDate = date ? new Date(date).toLocaleDateString("en-US", {
3152
+ year: "numeric",
3153
+ month: "long",
3154
+ day: "numeric"
3155
+ }) : "";
3156
+ return /* @__PURE__ */ jsxs("div", { className: `w-full ${className}`, children: [
3157
+ /* @__PURE__ */ jsx(
3158
+ PageHead,
3159
+ {
3160
+ title: post.seoTitle || post.title,
3161
+ description: post.seoDescription || post.excerpt || "",
3162
+ productName,
3163
+ keywords: post.seoKeywords || ""
3164
+ }
3165
+ ),
3166
+ /* @__PURE__ */ jsxs("article", { className: "max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-16 sm:py-20", children: [
3167
+ /* @__PURE__ */ jsx(
3168
+ "a",
3169
+ {
3170
+ href: blogListUrl,
3171
+ className: "inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground mb-8 transition-colors",
3172
+ children: "\u2190 Back to Blog"
3173
+ }
3174
+ ),
3175
+ post.category && /* @__PURE__ */ 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 }),
3176
+ /* @__PURE__ */ jsx("h1", { className: "text-3xl sm:text-4xl md:text-5xl font-bold tracking-tight text-foreground mb-4", children: post.title }),
3177
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 text-sm text-muted-foreground mb-8", children: [
3178
+ post.author && /* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: post.author }),
3179
+ post.author && formattedDate && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/40", children: "\xB7" }),
3180
+ formattedDate && /* @__PURE__ */ jsx("span", { children: formattedDate }),
3181
+ post.readingTime && /* @__PURE__ */ jsxs(Fragment, { children: [
3182
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/40", children: "\xB7" }),
3183
+ /* @__PURE__ */ jsxs("span", { children: [
3184
+ post.readingTime,
3185
+ " min read"
3186
+ ] })
3187
+ ] })
3188
+ ] }),
3189
+ post.thumbnail && /* @__PURE__ */ jsx("div", { className: "aspect-[16/9] rounded-xl overflow-hidden mb-10", children: /* @__PURE__ */ jsx(
3190
+ "img",
3191
+ {
3192
+ src: post.thumbnail,
3193
+ alt: post.title,
3194
+ className: "w-full h-full object-cover"
3195
+ }
3196
+ ) }),
3197
+ /* @__PURE__ */ jsx("div", { className: "prose prose-gray dark:prose-invert max-w-none", children: /* @__PURE__ */ jsx(
3198
+ ContentRenderer,
3199
+ {
3200
+ content: post.content,
3201
+ format: post.contentFormat
3202
+ }
3203
+ ) })
3204
+ ] })
3205
+ ] });
3206
+ }
2858
3207
 
2859
- export { Button, ContactPage, ContentRenderer, Input, Label, NewsletterForm, NewsletterPage, PageHead, PricingPage, PricingSection, ProductProvider, RybbitAnalytics, Textarea, UnsubscribePage, WaitlistForm, WaitlistPage, WebSDKClient, WebSDKProvider, buttonVariants, cn, useContentPage, useContentPages, useProduct, useProductConfig, useWebSDK, useWebSDKConfig };
3208
+ export { BlogListPage, BlogPostPage, Button, ContactPage, ContentRenderer, Input, Label, NewsletterForm, NewsletterPage, PageHead, PricingPage, PricingSection, ProductProvider, RybbitAnalytics, Textarea, UnsubscribePage, WaitlistForm, WaitlistPage, WebSDKClient, WebSDKProvider, buttonVariants, cn, useContentPage, useContentPages, useProduct, useProductConfig, useWebSDK, useWebSDKConfig };
2860
3209
  //# sourceMappingURL=index.mjs.map
2861
3210
  //# sourceMappingURL=index.mjs.map