@burdenoff/website-sdk 2026.703.2 → 2026.709.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.
Files changed (37) hide show
  1. package/dist/components/electron-download.d.mts +32 -0
  2. package/dist/components/electron-download.d.ts +32 -0
  3. package/dist/components/electron-download.js +131 -0
  4. package/dist/components/electron-download.js.map +1 -0
  5. package/dist/components/electron-download.mjs +108 -0
  6. package/dist/components/electron-download.mjs.map +1 -0
  7. package/dist/components/launch-countdown.d.mts +15 -0
  8. package/dist/components/launch-countdown.d.ts +15 -0
  9. package/dist/components/launch-countdown.js +89 -0
  10. package/dist/components/launch-countdown.js.map +1 -0
  11. package/dist/components/launch-countdown.mjs +87 -0
  12. package/dist/components/launch-countdown.mjs.map +1 -0
  13. package/dist/components/problems-solved.d.mts +37 -0
  14. package/dist/components/problems-solved.d.ts +37 -0
  15. package/dist/components/problems-solved.js +157 -0
  16. package/dist/components/problems-solved.js.map +1 -0
  17. package/dist/components/problems-solved.mjs +135 -0
  18. package/dist/components/problems-solved.mjs.map +1 -0
  19. package/dist/components/website-switcher.d.mts +27 -0
  20. package/dist/components/website-switcher.d.ts +27 -0
  21. package/dist/components/website-switcher.js +168 -0
  22. package/dist/components/website-switcher.js.map +1 -0
  23. package/dist/components/website-switcher.mjs +146 -0
  24. package/dist/components/website-switcher.mjs.map +1 -0
  25. package/dist/content/index.d.mts +24 -1
  26. package/dist/content/index.d.ts +24 -1
  27. package/dist/content/index.js +459 -149
  28. package/dist/content/index.js.map +1 -1
  29. package/dist/content/index.mjs +378 -87
  30. package/dist/content/index.mjs.map +1 -1
  31. package/dist/index.d.mts +15 -2
  32. package/dist/index.d.ts +15 -2
  33. package/dist/index.js +817 -86
  34. package/dist/index.js.map +1 -1
  35. package/dist/index.mjs +812 -88
  36. package/dist/index.mjs.map +1 -1
  37. package/package.json +3 -1
@@ -0,0 +1,146 @@
1
+ import * as React from 'react';
2
+ import { useState, useMemo } from 'react';
3
+ import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
4
+ import { Globe, ChevronDown, Search } from 'lucide-react';
5
+ import { clsx } from 'clsx';
6
+ import { twMerge } from 'tailwind-merge';
7
+ import { jsx, jsxs } from 'react/jsx-runtime';
8
+
9
+ function cn(...inputs) {
10
+ return twMerge(clsx(inputs));
11
+ }
12
+ var Input = React.forwardRef(
13
+ ({ className, type, ...props }, ref) => {
14
+ return /* @__PURE__ */ jsx(
15
+ "input",
16
+ {
17
+ type,
18
+ className: cn(
19
+ "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
20
+ className
21
+ ),
22
+ ref,
23
+ ...props
24
+ }
25
+ );
26
+ }
27
+ );
28
+ Input.displayName = "Input";
29
+ function normalizeSearch(value) {
30
+ return value.toLowerCase().trim();
31
+ }
32
+ function filterProducts(products, query) {
33
+ const normalized = normalizeSearch(query);
34
+ if (!normalized) return products;
35
+ return products.filter((p) => normalizeSearch(p.name).includes(normalized));
36
+ }
37
+ function WebsiteSwitcher({
38
+ products,
39
+ triggerLabel = "Explore products",
40
+ searchPlaceholder = "Find a product\u2026",
41
+ emptyText = "No products match your search.",
42
+ className
43
+ }) {
44
+ const [open, setOpen] = useState(false);
45
+ const [query, setQuery] = useState("");
46
+ const filtered = useMemo(
47
+ () => filterProducts(products, query),
48
+ [products, query]
49
+ );
50
+ return /* @__PURE__ */ jsxs(DropdownMenu.Root, { open, onOpenChange: setOpen, children: [
51
+ /* @__PURE__ */ jsxs(
52
+ DropdownMenu.Trigger,
53
+ {
54
+ className: cn(
55
+ "inline-flex items-center gap-1.5 text-sm font-medium transition-colors",
56
+ "text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring rounded-md",
57
+ className
58
+ ),
59
+ "aria-label": triggerLabel,
60
+ children: [
61
+ /* @__PURE__ */ jsx(Globe, { className: "h-4 w-4", "aria-hidden": "true" }),
62
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: triggerLabel }),
63
+ /* @__PURE__ */ jsx(
64
+ ChevronDown,
65
+ {
66
+ className: cn(
67
+ "h-3.5 w-3.5 transition-transform duration-200",
68
+ open && "rotate-180"
69
+ ),
70
+ "aria-hidden": "true"
71
+ }
72
+ )
73
+ ]
74
+ }
75
+ ),
76
+ /* @__PURE__ */ jsx(DropdownMenu.Portal, { children: /* @__PURE__ */ jsxs(
77
+ DropdownMenu.Content,
78
+ {
79
+ className: "z-50 min-w-[16rem] max-w-[20rem] rounded-lg border border-border/60 bg-popover p-2 shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2",
80
+ sideOffset: 8,
81
+ align: "end",
82
+ avoidCollisions: true,
83
+ children: [
84
+ /* @__PURE__ */ jsxs("div", { className: "px-2 pb-2 pt-1", children: [
85
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground mb-2", children: "Burdenoff ecosystem" }),
86
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
87
+ /* @__PURE__ */ jsx(
88
+ Search,
89
+ {
90
+ className: "absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-muted-foreground",
91
+ "aria-hidden": "true"
92
+ }
93
+ ),
94
+ /* @__PURE__ */ jsx(
95
+ Input,
96
+ {
97
+ type: "search",
98
+ value: query,
99
+ onChange: (e) => setQuery(e.target.value),
100
+ placeholder: searchPlaceholder,
101
+ className: "h-8 pl-8 text-sm",
102
+ "aria-label": searchPlaceholder,
103
+ onKeyDown: (e) => {
104
+ if (e.key === "Escape") {
105
+ setQuery("");
106
+ }
107
+ }
108
+ }
109
+ )
110
+ ] })
111
+ ] }),
112
+ /* @__PURE__ */ jsx(DropdownMenu.Separator, { className: "my-1 h-px bg-border/60" }),
113
+ /* @__PURE__ */ jsx("div", { className: "max-h-[min(60vh,24rem)] overflow-y-auto py-1", children: filtered.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: emptyText }) : filtered.map((product) => /* @__PURE__ */ jsx(DropdownMenu.Item, { asChild: true, children: /* @__PURE__ */ jsxs(
114
+ "a",
115
+ {
116
+ href: product.websiteUrl,
117
+ target: "_blank",
118
+ rel: "noopener noreferrer",
119
+ className: cn(
120
+ "flex items-center gap-3 rounded-md px-2 py-2 text-sm outline-none",
121
+ "text-foreground hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground"
122
+ ),
123
+ children: [
124
+ product.logoUrl ? /* @__PURE__ */ jsx(
125
+ "img",
126
+ {
127
+ src: product.logoUrl,
128
+ alt: "",
129
+ "aria-hidden": "true",
130
+ className: "h-5 w-5 shrink-0 rounded object-contain"
131
+ }
132
+ ) : /* @__PURE__ */ jsx("span", { className: "flex h-5 w-5 shrink-0 items-center justify-center rounded bg-primary/10 text-[10px] font-bold text-primary", children: product.name.charAt(0) }),
133
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: product.name })
134
+ ]
135
+ }
136
+ ) }, product.slug)) }),
137
+ /* @__PURE__ */ jsx(DropdownMenu.Arrow, { className: "fill-popover" })
138
+ ]
139
+ }
140
+ ) })
141
+ ] });
142
+ }
143
+
144
+ export { WebsiteSwitcher };
145
+ //# sourceMappingURL=website-switcher.mjs.map
146
+ //# sourceMappingURL=website-switcher.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/cn.ts","../../src/ui/input.tsx","../../src/components/website-switcher.tsx"],"names":["jsx"],"mappings":"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","file":"website-switcher.mjs","sourcesContent":["/**\n * Utility function to merge Tailwind CSS classes\n * Combines clsx and tailwind-merge for optimal class handling\n */\n\nimport { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merge multiple class names intelligently\n * - Handles conditional classes via clsx\n * - Deduplicates and resolves Tailwind conflicts via tailwind-merge\n *\n * @example\n * ```ts\n * cn('px-4 py-2', 'bg-blue-500', { 'text-white': isActive })\n * // => 'px-4 py-2 bg-blue-500 text-white' (if isActive is true)\n * ```\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","import * as React from \"react\";\n\nimport { cn } from \"../utils/cn\";\n\nconst Input = React.forwardRef<HTMLInputElement, React.ComponentProps<\"input\">>(\n ({ className, type, ...props }, ref) => {\n return (\n <input\n type={type}\n className={cn(\n \"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\",\n className,\n )}\n ref={ref}\n {...props}\n />\n );\n },\n);\nInput.displayName = \"Input\";\n\nexport { Input };\n","\"use client\";\n\n/**\n * WebsiteSwitcher Component\n *\n * A dropdown menu for navigating between Burdenoff ecosystem product websites.\n * Includes a search filter and renders each product with its logo and name.\n *\n * @example\n * ```tsx\n * import { WebsiteSwitcher } from '@burdenoff/website-sdk'\n *\n * <WebsiteSwitcher\n * products={[\n * { slug: 'vibecontrols', name: 'VibeControls', logoUrl: '/vibe.svg', websiteUrl: 'https://vibecontrols.com' },\n * { slug: 'fluidgrids', name: 'FluidGrids', logoUrl: '/fg.svg', websiteUrl: 'https://fluidgrids.com' },\n * ]}\n * />\n * ```\n */\n\nimport { useMemo, useState } from \"react\";\n\nimport * as DropdownMenu from \"@radix-ui/react-dropdown-menu\";\nimport { ChevronDown, Globe, Search } from \"lucide-react\";\n\nimport { Input } from \"../ui/input\";\nimport { cn } from \"../utils/cn\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface WebsiteSwitcherProduct {\n /** Stable identifier for the product. */\n slug: string;\n /** Human-readable product name. */\n name: string;\n /** URL to the product logo (absolute or relative). */\n logoUrl?: string | null;\n /** Product marketing site URL. */\n websiteUrl: string;\n}\n\nexport interface WebsiteSwitcherProps {\n /** All Burdenoff ecosystem products to display. */\n products: WebsiteSwitcherProduct[];\n /** Accessible label for the trigger. */\n triggerLabel?: string;\n /** Placeholder text for the search input. */\n searchPlaceholder?: string;\n /** Empty-state text when filtering returns no results. */\n emptyText?: string;\n /** Optional additional CSS class for the trigger. */\n className?: string;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction normalizeSearch(value: string): string {\n return value.toLowerCase().trim();\n}\n\nfunction filterProducts(\n products: WebsiteSwitcherProduct[],\n query: string,\n): WebsiteSwitcherProduct[] {\n const normalized = normalizeSearch(query);\n if (!normalized) return products;\n return products.filter((p) => normalizeSearch(p.name).includes(normalized));\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport function WebsiteSwitcher({\n products,\n triggerLabel = \"Explore products\",\n searchPlaceholder = \"Find a product…\",\n emptyText = \"No products match your search.\",\n className,\n}: WebsiteSwitcherProps) {\n const [open, setOpen] = useState(false);\n const [query, setQuery] = useState(\"\");\n\n const filtered = useMemo(\n () => filterProducts(products, query),\n [products, query],\n );\n\n return (\n <DropdownMenu.Root open={open} onOpenChange={setOpen}>\n <DropdownMenu.Trigger\n className={cn(\n \"inline-flex items-center gap-1.5 text-sm font-medium transition-colors\",\n \"text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring rounded-md\",\n className,\n )}\n aria-label={triggerLabel}\n >\n <Globe className=\"h-4 w-4\" aria-hidden=\"true\" />\n <span className=\"hidden sm:inline\">{triggerLabel}</span>\n <ChevronDown\n className={cn(\n \"h-3.5 w-3.5 transition-transform duration-200\",\n open && \"rotate-180\",\n )}\n aria-hidden=\"true\"\n />\n </DropdownMenu.Trigger>\n\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n className=\"z-50 min-w-[16rem] max-w-[20rem] rounded-lg border border-border/60 bg-popover p-2 shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2\"\n sideOffset={8}\n align=\"end\"\n avoidCollisions\n >\n <div className=\"px-2 pb-2 pt-1\">\n <p className=\"text-xs font-medium text-muted-foreground mb-2\">\n Burdenoff ecosystem\n </p>\n <div className=\"relative\">\n <Search\n className=\"absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-muted-foreground\"\n aria-hidden=\"true\"\n />\n <Input\n type=\"search\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder={searchPlaceholder}\n className=\"h-8 pl-8 text-sm\"\n aria-label={searchPlaceholder}\n onKeyDown={(e) => {\n if (e.key === \"Escape\") {\n setQuery(\"\");\n }\n }}\n />\n </div>\n </div>\n\n <DropdownMenu.Separator className=\"my-1 h-px bg-border/60\" />\n\n <div className=\"max-h-[min(60vh,24rem)] overflow-y-auto py-1\">\n {filtered.length === 0 ? (\n <div className=\"px-3 py-4 text-center text-sm text-muted-foreground\">\n {emptyText}\n </div>\n ) : (\n filtered.map((product) => (\n <DropdownMenu.Item key={product.slug} asChild>\n <a\n href={product.websiteUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={cn(\n \"flex items-center gap-3 rounded-md px-2 py-2 text-sm outline-none\",\n \"text-foreground hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground\",\n )}\n >\n {product.logoUrl ? (\n <img\n src={product.logoUrl}\n alt=\"\"\n aria-hidden=\"true\"\n className=\"h-5 w-5 shrink-0 rounded object-contain\"\n />\n ) : (\n <span className=\"flex h-5 w-5 shrink-0 items-center justify-center rounded bg-primary/10 text-[10px] font-bold text-primary\">\n {product.name.charAt(0)}\n </span>\n )}\n <span className=\"truncate\">{product.name}</span>\n </a>\n </DropdownMenu.Item>\n ))\n )}\n </div>\n\n <DropdownMenu.Arrow className=\"fill-popover\" />\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n );\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
2
3
 
3
4
  interface ContentPageData {
4
5
  id: string;
@@ -134,6 +135,20 @@ interface CaseStudyPageProps {
134
135
  declare function CaseStudiesListPage(props: CaseStudiesListPageProps): react_jsx_runtime.JSX.Element;
135
136
  declare function CaseStudyPage(props: CaseStudyPageProps): react_jsx_runtime.JSX.Element;
136
137
 
138
+ interface ChangelogEntry {
139
+ /** Release date as an ISO string. */
140
+ date: string;
141
+ /** Version identifier, e.g. "1.2.0". */
142
+ version: string;
143
+ /** Entry headline. */
144
+ title: string;
145
+ /** Category used for filtering, e.g. "feature", "fix", "improvement". */
146
+ category: string;
147
+ /** Entry body — plain text, markdown, or a React node. */
148
+ content: ReactNode | string;
149
+ /** Optional tags for search and filtering. */
150
+ tags?: string[];
151
+ }
137
152
  interface ChangelogPageProps {
138
153
  productName?: string;
139
154
  heroEyebrow?: string;
@@ -148,6 +163,14 @@ interface ChangelogPageProps {
148
163
  seoTitle?: string;
149
164
  seoDescription?: string;
150
165
  seoKeywords?: string;
166
+ /**
167
+ * Optional prop-driven entries. When provided, the component skips the CMS
168
+ * fetch and renders these entries with search, category filters, and
169
+ * pagination.
170
+ */
171
+ entries?: ChangelogEntry[];
172
+ /** Number of entries per page in prop-driven mode. Defaults to 10. */
173
+ pageSize?: number;
151
174
  }
152
175
  declare function ChangelogPage(props: ChangelogPageProps): react_jsx_runtime.JSX.Element;
153
176
 
@@ -221,4 +244,4 @@ interface ContractsPageProps {
221
244
  }
222
245
  declare function ContractsPage(props: ContractsPageProps): react_jsx_runtime.JSX.Element;
223
246
 
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 };
247
+ export { BlogListPage, type BlogListPageProps, BlogPostPage, type BlogPostPageProps, CaseStudiesListPage, type CaseStudiesListPageProps, CaseStudyPage, type CaseStudyPageProps, type ChangelogEntry, 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 };
@@ -1,4 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
2
3
 
3
4
  interface ContentPageData {
4
5
  id: string;
@@ -134,6 +135,20 @@ interface CaseStudyPageProps {
134
135
  declare function CaseStudiesListPage(props: CaseStudiesListPageProps): react_jsx_runtime.JSX.Element;
135
136
  declare function CaseStudyPage(props: CaseStudyPageProps): react_jsx_runtime.JSX.Element;
136
137
 
138
+ interface ChangelogEntry {
139
+ /** Release date as an ISO string. */
140
+ date: string;
141
+ /** Version identifier, e.g. "1.2.0". */
142
+ version: string;
143
+ /** Entry headline. */
144
+ title: string;
145
+ /** Category used for filtering, e.g. "feature", "fix", "improvement". */
146
+ category: string;
147
+ /** Entry body — plain text, markdown, or a React node. */
148
+ content: ReactNode | string;
149
+ /** Optional tags for search and filtering. */
150
+ tags?: string[];
151
+ }
137
152
  interface ChangelogPageProps {
138
153
  productName?: string;
139
154
  heroEyebrow?: string;
@@ -148,6 +163,14 @@ interface ChangelogPageProps {
148
163
  seoTitle?: string;
149
164
  seoDescription?: string;
150
165
  seoKeywords?: string;
166
+ /**
167
+ * Optional prop-driven entries. When provided, the component skips the CMS
168
+ * fetch and renders these entries with search, category filters, and
169
+ * pagination.
170
+ */
171
+ entries?: ChangelogEntry[];
172
+ /** Number of entries per page in prop-driven mode. Defaults to 10. */
173
+ pageSize?: number;
151
174
  }
152
175
  declare function ChangelogPage(props: ChangelogPageProps): react_jsx_runtime.JSX.Element;
153
176
 
@@ -221,4 +244,4 @@ interface ContractsPageProps {
221
244
  }
222
245
  declare function ContractsPage(props: ContractsPageProps): react_jsx_runtime.JSX.Element;
223
246
 
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 };
247
+ export { BlogListPage, type BlogListPageProps, BlogPostPage, type BlogPostPageProps, CaseStudiesListPage, type CaseStudiesListPageProps, CaseStudyPage, type CaseStudyPageProps, type ChangelogEntry, 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 };