@burdenoff/website-sdk 2026.709.2 → 2026.710.1
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/components/launch-countdown.js +1 -1
- package/dist/components/launch-countdown.js.map +1 -1
- package/dist/components/launch-countdown.mjs +1 -1
- package/dist/components/launch-countdown.mjs.map +1 -1
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1295 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1288 -2
- package/dist/index.mjs.map +1 -1
- package/dist/store/index.d.mts +157 -0
- package/dist/store/index.d.ts +157 -0
- package/dist/store/index.js +1503 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/index.mjs +1494 -0
- package/dist/store/index.mjs.map +1 -0
- package/package.json +6 -1
package/dist/index.js
CHANGED
|
@@ -4093,7 +4093,7 @@ function LaunchCountdown({
|
|
|
4093
4093
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4094
4094
|
"div",
|
|
4095
4095
|
{
|
|
4096
|
-
className: cn("
|
|
4096
|
+
className: cn("flex flex-col items-center gap-3", className),
|
|
4097
4097
|
role: "timer",
|
|
4098
4098
|
"aria-label": launchLabel ?? (hasLaunched ? launchedMessage : `Countdown to launch`),
|
|
4099
4099
|
children: [
|
|
@@ -6224,6 +6224,1292 @@ function ContractsPage(props) {
|
|
|
6224
6224
|
}) }) })
|
|
6225
6225
|
] });
|
|
6226
6226
|
}
|
|
6227
|
+
function formatPrice2(price, currency, pricingModel) {
|
|
6228
|
+
if (pricingModel === "FREE" || !price || price === 0) return "Free";
|
|
6229
|
+
const curr = currency || "USD";
|
|
6230
|
+
try {
|
|
6231
|
+
return new Intl.NumberFormat("en-US", {
|
|
6232
|
+
style: "currency",
|
|
6233
|
+
currency: curr
|
|
6234
|
+
}).format(price);
|
|
6235
|
+
} catch {
|
|
6236
|
+
return `${curr} ${price.toFixed(2)}`;
|
|
6237
|
+
}
|
|
6238
|
+
}
|
|
6239
|
+
function formatDownloads(n) {
|
|
6240
|
+
if (!n) return "0";
|
|
6241
|
+
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
6242
|
+
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
|
|
6243
|
+
return n.toString();
|
|
6244
|
+
}
|
|
6245
|
+
function StarRating({ rating }) {
|
|
6246
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center gap-0.5", children: [1, 2, 3, 4, 5].map((star) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
6247
|
+
"svg",
|
|
6248
|
+
{
|
|
6249
|
+
viewBox: "0 0 12 12",
|
|
6250
|
+
className: `w-3 h-3 ${star <= Math.round(rating) ? "text-amber-400 fill-current" : "text-muted-foreground/30 fill-current"}`,
|
|
6251
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 1l1.545 3.09L11 4.59l-2.5 2.41.59 3.41L6 8.79l-3.09 1.61L3.5 7 1 4.59l3.455-.5L6 1z" })
|
|
6252
|
+
},
|
|
6253
|
+
star
|
|
6254
|
+
)) });
|
|
6255
|
+
}
|
|
6256
|
+
function TypeBadge({ type }) {
|
|
6257
|
+
const labels = {
|
|
6258
|
+
APP: "App",
|
|
6259
|
+
NODE: "Node",
|
|
6260
|
+
WORKFLOW: "Workflow",
|
|
6261
|
+
TEMPLATE: "Template",
|
|
6262
|
+
INTEGRATION: "Integration",
|
|
6263
|
+
EXTENSION: "Extension",
|
|
6264
|
+
THEME: "Theme"
|
|
6265
|
+
};
|
|
6266
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block text-xs px-2 py-0.5 rounded-full bg-primary/10 text-primary font-medium", children: labels[type] ?? type });
|
|
6267
|
+
}
|
|
6268
|
+
function ProductCard({ product, onClick, href }) {
|
|
6269
|
+
const priceLabel = formatPrice2(product.price, product.currency, product.pricingModel);
|
|
6270
|
+
const inner = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group bg-card border border-border rounded-xl p-4 flex flex-col gap-3 transition-all duration-200 hover:shadow-md hover:border-primary/30 cursor-pointer h-full", children: [
|
|
6271
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2", children: [
|
|
6272
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-12 h-12 rounded-lg bg-muted flex-shrink-0 overflow-hidden", children: product.icon ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
6273
|
+
"img",
|
|
6274
|
+
{
|
|
6275
|
+
src: product.icon,
|
|
6276
|
+
alt: "",
|
|
6277
|
+
"aria-hidden": "true",
|
|
6278
|
+
className: "w-full h-full object-cover"
|
|
6279
|
+
}
|
|
6280
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full flex items-center justify-center bg-gradient-to-br from-primary/15 to-primary/5", children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 32 32", className: "w-8 h-8", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [
|
|
6281
|
+
/* @__PURE__ */ jsxRuntime.jsx("polygon", { points: "16,4 28,10 16,16 4,10", className: "fill-primary/30", stroke: "currentColor", strokeWidth: "0.6", strokeOpacity: "0.35" }),
|
|
6282
|
+
/* @__PURE__ */ jsxRuntime.jsx("polygon", { points: "4,10 16,16 16,28 4,22", className: "fill-primary/15", stroke: "currentColor", strokeWidth: "0.6", strokeOpacity: "0.35" }),
|
|
6283
|
+
/* @__PURE__ */ jsxRuntime.jsx("polygon", { points: "28,10 16,16 16,28 28,22", className: "fill-primary/20", stroke: "currentColor", strokeWidth: "0.6", strokeOpacity: "0.35" })
|
|
6284
|
+
] }) }) }),
|
|
6285
|
+
/* @__PURE__ */ jsxRuntime.jsx(TypeBadge, { type: product.type })
|
|
6286
|
+
] }),
|
|
6287
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
6288
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold text-foreground text-sm leading-snug line-clamp-1 group-hover:text-primary transition-colors", children: product.name }),
|
|
6289
|
+
product.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground text-xs mt-1 line-clamp-2 leading-relaxed", children: product.description })
|
|
6290
|
+
] }),
|
|
6291
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
6292
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1.5", children: product.rating != null && product.rating > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6293
|
+
/* @__PURE__ */ jsxRuntime.jsx(StarRating, { rating: product.rating }),
|
|
6294
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: product.rating.toFixed(1) })
|
|
6295
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "No reviews yet" }) }),
|
|
6296
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6297
|
+
"span",
|
|
6298
|
+
{
|
|
6299
|
+
className: `text-xs font-semibold ${priceLabel === "Free" ? "text-emerald-500" : "text-foreground"}`,
|
|
6300
|
+
children: priceLabel
|
|
6301
|
+
}
|
|
6302
|
+
)
|
|
6303
|
+
] })
|
|
6304
|
+
] });
|
|
6305
|
+
if (href) {
|
|
6306
|
+
return /* @__PURE__ */ jsxRuntime.jsx("a", { href, onClick, className: "block h-full no-underline", children: inner });
|
|
6307
|
+
}
|
|
6308
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
6309
|
+
"button",
|
|
6310
|
+
{
|
|
6311
|
+
type: "button",
|
|
6312
|
+
onClick,
|
|
6313
|
+
className: "block w-full text-left h-full",
|
|
6314
|
+
children: inner
|
|
6315
|
+
}
|
|
6316
|
+
);
|
|
6317
|
+
}
|
|
6318
|
+
|
|
6319
|
+
// src/store/queries.ts
|
|
6320
|
+
var STORE_PRODUCT_FIELDS = `
|
|
6321
|
+
fragment StoreProductFields on StoreProduct {
|
|
6322
|
+
id name slug type subType nature status pricingModel
|
|
6323
|
+
price currency description icon bannerUrl screenshots
|
|
6324
|
+
category tags featured downloads viewCount rating reviewCount
|
|
6325
|
+
publisherId authorName license compatibleProducts
|
|
6326
|
+
}
|
|
6327
|
+
`;
|
|
6328
|
+
var HOME_GROUPED_PRODUCTS_QUERY = `
|
|
6329
|
+
${STORE_PRODUCT_FIELDS}
|
|
6330
|
+
query HomeGroupedProducts($compatibleWith: String) {
|
|
6331
|
+
homeGroupedProducts(compatibleWith: $compatibleWith) {
|
|
6332
|
+
featured { ...StoreProductFields }
|
|
6333
|
+
mostDownloaded { ...StoreProductFields }
|
|
6334
|
+
recentlyAdded { ...StoreProductFields }
|
|
6335
|
+
freeItems { ...StoreProductFields }
|
|
6336
|
+
}
|
|
6337
|
+
}
|
|
6338
|
+
`;
|
|
6339
|
+
var BROWSE_STORE_QUERY = `
|
|
6340
|
+
${STORE_PRODUCT_FIELDS}
|
|
6341
|
+
query BrowseStore($input: BrowseStoreInput!) {
|
|
6342
|
+
browseStore(input: $input) {
|
|
6343
|
+
products { ...StoreProductFields }
|
|
6344
|
+
totalCount
|
|
6345
|
+
hasMore
|
|
6346
|
+
nextCursor
|
|
6347
|
+
facets {
|
|
6348
|
+
types { value count }
|
|
6349
|
+
categories { value count }
|
|
6350
|
+
pricingModels { value count }
|
|
6351
|
+
priceRange { min max }
|
|
6352
|
+
}
|
|
6353
|
+
}
|
|
6354
|
+
}
|
|
6355
|
+
`;
|
|
6356
|
+
var STORE_PRODUCT_DETAILS_QUERY = `
|
|
6357
|
+
${STORE_PRODUCT_FIELDS}
|
|
6358
|
+
query StoreProductDetails($input: StoreProductDetailsInput!) {
|
|
6359
|
+
storeProductDetails(input: $input) {
|
|
6360
|
+
product { ...StoreProductFields longDescription videoUrls minPlatformVersion }
|
|
6361
|
+
publisher { id name email websiteUrl logoUrl bio isVerified tier }
|
|
6362
|
+
reviews { id rating title comment verifiedPurchase helpful createdAt }
|
|
6363
|
+
reviewsCount
|
|
6364
|
+
relatedProducts { ...StoreProductFields }
|
|
6365
|
+
ratingDistribution { fiveStars fourStars threeStars twoStars oneStar }
|
|
6366
|
+
}
|
|
6367
|
+
}
|
|
6368
|
+
`;
|
|
6369
|
+
var CATEGORIES_QUERY = `
|
|
6370
|
+
query Categories {
|
|
6371
|
+
categories {
|
|
6372
|
+
id name slug description icon parentId
|
|
6373
|
+
}
|
|
6374
|
+
}
|
|
6375
|
+
`;
|
|
6376
|
+
function dedupAcross(lists) {
|
|
6377
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6378
|
+
return lists.map((list) => {
|
|
6379
|
+
const out = [];
|
|
6380
|
+
for (const p of list) {
|
|
6381
|
+
if (!seen.has(p.id)) {
|
|
6382
|
+
seen.add(p.id);
|
|
6383
|
+
out.push(p);
|
|
6384
|
+
}
|
|
6385
|
+
}
|
|
6386
|
+
return out;
|
|
6387
|
+
});
|
|
6388
|
+
}
|
|
6389
|
+
function FeaturedHeroCard({
|
|
6390
|
+
product,
|
|
6391
|
+
onNavigate
|
|
6392
|
+
}) {
|
|
6393
|
+
const priceLabel = formatPrice2(product.price, product.currency, product.pricingModel);
|
|
6394
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6395
|
+
"button",
|
|
6396
|
+
{
|
|
6397
|
+
type: "button",
|
|
6398
|
+
onClick: () => onNavigate(`/store/${product.slug}`),
|
|
6399
|
+
className: "group w-full text-left h-full rounded-2xl border border-border bg-card overflow-hidden hover:border-primary/40 transition-all duration-300 hover:shadow-xl hover:shadow-primary/10 flex flex-col",
|
|
6400
|
+
children: [
|
|
6401
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative h-44 sm:h-52 bg-gradient-to-br from-primary/20 via-primary/8 to-background overflow-hidden flex-shrink-0", children: [
|
|
6402
|
+
product.bannerUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: product.bannerUrl, alt: "", "aria-hidden": "true", className: "w-full h-full object-cover" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6403
|
+
/* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "absolute inset-0 w-full h-full opacity-[0.07]", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [
|
|
6404
|
+
/* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsx("pattern", { id: "fg-hero-grid", width: "36", height: "36", patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 36 0 L 0 0 0 36", fill: "none", stroke: "currentColor", strokeWidth: "1" }) }) }),
|
|
6405
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { width: "100%", height: "100%", fill: "url(#fg-hero-grid)" })
|
|
6406
|
+
] }),
|
|
6407
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 64 64", className: "w-20 h-20 opacity-25", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
|
|
6408
|
+
/* @__PURE__ */ jsxRuntime.jsx("polygon", { points: "32,8 56,20 32,32 8,20", className: "fill-primary/40", stroke: "currentColor", strokeWidth: "1", strokeOpacity: "0.5" }),
|
|
6409
|
+
/* @__PURE__ */ jsxRuntime.jsx("polygon", { points: "8,20 32,32 32,56 8,44", className: "fill-primary/20", stroke: "currentColor", strokeWidth: "1", strokeOpacity: "0.5" }),
|
|
6410
|
+
/* @__PURE__ */ jsxRuntime.jsx("polygon", { points: "56,20 32,32 32,56 56,44", className: "fill-primary/30", stroke: "currentColor", strokeWidth: "1", strokeOpacity: "0.5" })
|
|
6411
|
+
] }) })
|
|
6412
|
+
] }),
|
|
6413
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute top-3 left-3 text-xs font-semibold px-2.5 py-1 rounded-full bg-primary text-primary-foreground shadow-sm", children: "Featured" }),
|
|
6414
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-4 left-4 w-14 h-14 rounded-xl shadow-lg overflow-hidden border-2 border-background", children: product.icon ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: product.icon, alt: "", "aria-hidden": "true", className: "w-full h-full object-cover" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full bg-gradient-to-br from-primary/25 to-primary/10 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 32 32", className: "w-8 h-8", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [
|
|
6415
|
+
/* @__PURE__ */ jsxRuntime.jsx("polygon", { points: "16,4 28,10 16,16 4,10", className: "fill-primary/40", stroke: "currentColor", strokeWidth: "0.6", strokeOpacity: "0.4" }),
|
|
6416
|
+
/* @__PURE__ */ jsxRuntime.jsx("polygon", { points: "4,10 16,16 16,28 4,22", className: "fill-primary/20", stroke: "currentColor", strokeWidth: "0.6", strokeOpacity: "0.4" }),
|
|
6417
|
+
/* @__PURE__ */ jsxRuntime.jsx("polygon", { points: "28,10 16,16 16,28 28,22", className: "fill-primary/30", stroke: "currentColor", strokeWidth: "0.6", strokeOpacity: "0.4" })
|
|
6418
|
+
] }) }) })
|
|
6419
|
+
] }),
|
|
6420
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-5 flex flex-col flex-1", children: [
|
|
6421
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-3 mb-2", children: [
|
|
6422
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-base font-bold text-foreground group-hover:text-primary transition-colors line-clamp-1", children: product.name }),
|
|
6423
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `text-sm font-bold flex-shrink-0 ${priceLabel === "Free" ? "text-emerald-500" : "text-foreground"}`, children: priceLabel })
|
|
6424
|
+
] }),
|
|
6425
|
+
product.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground line-clamp-2 leading-relaxed flex-1", children: product.description }),
|
|
6426
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 flex items-center gap-2", children: [
|
|
6427
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs px-2 py-0.5 rounded-full bg-primary/10 text-primary font-medium", children: product.type }),
|
|
6428
|
+
product.authorName && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground truncate", children: [
|
|
6429
|
+
"by ",
|
|
6430
|
+
product.authorName
|
|
6431
|
+
] })
|
|
6432
|
+
] })
|
|
6433
|
+
] })
|
|
6434
|
+
]
|
|
6435
|
+
}
|
|
6436
|
+
);
|
|
6437
|
+
}
|
|
6438
|
+
function ScrollRow({
|
|
6439
|
+
products,
|
|
6440
|
+
onProductClick
|
|
6441
|
+
}) {
|
|
6442
|
+
const ref = React.useRef(null);
|
|
6443
|
+
function scroll(dir) {
|
|
6444
|
+
ref.current?.scrollBy({ left: dir === "r" ? 272 : -272, behavior: "smooth" });
|
|
6445
|
+
}
|
|
6446
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative group/row", children: [
|
|
6447
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6448
|
+
"button",
|
|
6449
|
+
{
|
|
6450
|
+
type: "button",
|
|
6451
|
+
onClick: () => scroll("l"),
|
|
6452
|
+
"aria-label": "Scroll left",
|
|
6453
|
+
className: "absolute left-0 top-1/2 -translate-y-1/2 -translate-x-4 z-10 w-8 h-8 rounded-full bg-background border border-border shadow-md items-center justify-center text-muted-foreground hover:text-primary hover:border-primary/40 transition-all hidden sm:flex opacity-0 group-hover/row:opacity-100",
|
|
6454
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", className: "w-4 h-4", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 3L6 8l4 5" }) })
|
|
6455
|
+
}
|
|
6456
|
+
),
|
|
6457
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6458
|
+
"div",
|
|
6459
|
+
{
|
|
6460
|
+
ref,
|
|
6461
|
+
className: "flex gap-3 overflow-x-auto pb-1 snap-x snap-mandatory",
|
|
6462
|
+
style: { scrollbarWidth: "none", msOverflowStyle: "none" },
|
|
6463
|
+
children: products.map((product) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 w-56 snap-start", children: /* @__PURE__ */ jsxRuntime.jsx(ProductCard, { product, onClick: () => onProductClick(product) }) }, product.id))
|
|
6464
|
+
}
|
|
6465
|
+
),
|
|
6466
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6467
|
+
"button",
|
|
6468
|
+
{
|
|
6469
|
+
type: "button",
|
|
6470
|
+
onClick: () => scroll("r"),
|
|
6471
|
+
"aria-label": "Scroll right",
|
|
6472
|
+
className: "absolute right-0 top-1/2 -translate-y-1/2 translate-x-4 z-10 w-8 h-8 rounded-full bg-background border border-border shadow-md items-center justify-center text-muted-foreground hover:text-primary hover:border-primary/40 transition-all hidden sm:flex opacity-0 group-hover/row:opacity-100",
|
|
6473
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", className: "w-4 h-4", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 3l4 5-4 5" }) })
|
|
6474
|
+
}
|
|
6475
|
+
)
|
|
6476
|
+
] });
|
|
6477
|
+
}
|
|
6478
|
+
function SectionHead({
|
|
6479
|
+
title,
|
|
6480
|
+
hint,
|
|
6481
|
+
browseHref,
|
|
6482
|
+
onNavigate
|
|
6483
|
+
}) {
|
|
6484
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-end justify-between mb-5 gap-4", children: [
|
|
6485
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
6486
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl font-bold text-foreground", children: title }),
|
|
6487
|
+
hint && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground mt-0.5", children: hint })
|
|
6488
|
+
] }),
|
|
6489
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6490
|
+
"button",
|
|
6491
|
+
{
|
|
6492
|
+
type: "button",
|
|
6493
|
+
onClick: () => onNavigate(browseHref),
|
|
6494
|
+
className: "text-sm text-primary hover:underline font-medium flex-shrink-0 underline-offset-2",
|
|
6495
|
+
children: "See all \u2192"
|
|
6496
|
+
}
|
|
6497
|
+
)
|
|
6498
|
+
] });
|
|
6499
|
+
}
|
|
6500
|
+
var TYPE_FILTERS = [
|
|
6501
|
+
{ type: "NODE", label: "Nodes" },
|
|
6502
|
+
{ type: "WORKFLOW", label: "Workflows" },
|
|
6503
|
+
{ type: "TEMPLATE", label: "Templates" },
|
|
6504
|
+
{ type: "INTEGRATION", label: "Integrations" },
|
|
6505
|
+
{ type: "APP", label: "Apps" },
|
|
6506
|
+
{ type: "EXTENSION", label: "Extensions" }
|
|
6507
|
+
];
|
|
6508
|
+
function TypeFilters({
|
|
6509
|
+
browsePath,
|
|
6510
|
+
onNavigate
|
|
6511
|
+
}) {
|
|
6512
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2 justify-center", children: TYPE_FILTERS.map((f) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
6513
|
+
"button",
|
|
6514
|
+
{
|
|
6515
|
+
type: "button",
|
|
6516
|
+
onClick: () => onNavigate(`${browsePath}?type=${f.type}`),
|
|
6517
|
+
className: "px-4 py-1.5 rounded-full border border-border bg-background text-sm text-foreground hover:border-primary/50 hover:bg-primary/5 hover:text-primary transition-all duration-200",
|
|
6518
|
+
children: f.label
|
|
6519
|
+
},
|
|
6520
|
+
f.type
|
|
6521
|
+
)) });
|
|
6522
|
+
}
|
|
6523
|
+
function HeroCardSkeleton() {
|
|
6524
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-2xl border border-border bg-card overflow-hidden animate-pulse h-full", children: [
|
|
6525
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-44 sm:h-52 bg-muted" }),
|
|
6526
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-5 space-y-3", children: [
|
|
6527
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-5 bg-muted rounded w-1/2" }),
|
|
6528
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-muted rounded w-3/4" }),
|
|
6529
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-muted rounded w-5/6" }),
|
|
6530
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-5 bg-muted rounded w-16 mt-2" })
|
|
6531
|
+
] })
|
|
6532
|
+
] });
|
|
6533
|
+
}
|
|
6534
|
+
function GridCardSkeleton() {
|
|
6535
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-border bg-card p-4 h-36 animate-pulse", children: [
|
|
6536
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3 mb-3", children: [
|
|
6537
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-12 h-12 rounded-lg bg-muted flex-shrink-0" }),
|
|
6538
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-2 pt-1", children: [
|
|
6539
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-muted rounded w-3/4" }),
|
|
6540
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-muted rounded w-1/2" })
|
|
6541
|
+
] })
|
|
6542
|
+
] }),
|
|
6543
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-muted rounded w-full mb-2" }),
|
|
6544
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-muted rounded w-5/6" })
|
|
6545
|
+
] });
|
|
6546
|
+
}
|
|
6547
|
+
function ScrollCardSkeleton() {
|
|
6548
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-shrink-0 w-56 rounded-xl border border-border bg-card p-4 h-36 animate-pulse", children: [
|
|
6549
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3 mb-3", children: [
|
|
6550
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-12 h-12 rounded-lg bg-muted flex-shrink-0" }),
|
|
6551
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-2 pt-1", children: [
|
|
6552
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-muted rounded w-3/4" }),
|
|
6553
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-muted rounded w-1/2" })
|
|
6554
|
+
] })
|
|
6555
|
+
] }),
|
|
6556
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-muted rounded w-full mb-2" }),
|
|
6557
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 bg-muted rounded w-5/6" })
|
|
6558
|
+
] });
|
|
6559
|
+
}
|
|
6560
|
+
function StoreHomePage({
|
|
6561
|
+
compatibleWith,
|
|
6562
|
+
appLoginUrl,
|
|
6563
|
+
onNavigate,
|
|
6564
|
+
productName,
|
|
6565
|
+
heroTitle,
|
|
6566
|
+
heroSubtitle,
|
|
6567
|
+
browsePath = "/store/browse",
|
|
6568
|
+
seoTitle,
|
|
6569
|
+
seoDescription,
|
|
6570
|
+
seoKeywords
|
|
6571
|
+
}) {
|
|
6572
|
+
const client = useWebSDK();
|
|
6573
|
+
const [grouped, setGrouped] = React.useState(null);
|
|
6574
|
+
const [loading, setLoading] = React.useState(true);
|
|
6575
|
+
const [error, setError] = React.useState(null);
|
|
6576
|
+
React.useEffect(() => {
|
|
6577
|
+
let cancelled = false;
|
|
6578
|
+
async function load() {
|
|
6579
|
+
setLoading(true);
|
|
6580
|
+
try {
|
|
6581
|
+
const res = await client.query(
|
|
6582
|
+
HOME_GROUPED_PRODUCTS_QUERY,
|
|
6583
|
+
{ compatibleWith: compatibleWith ?? null }
|
|
6584
|
+
);
|
|
6585
|
+
if (cancelled) return;
|
|
6586
|
+
if (res.errors?.length) throw new Error(res.errors[0].message);
|
|
6587
|
+
if (!res.data?.homeGroupedProducts) throw new Error("No data");
|
|
6588
|
+
setGrouped(res.data.homeGroupedProducts);
|
|
6589
|
+
setError(null);
|
|
6590
|
+
} catch {
|
|
6591
|
+
if (!cancelled) setError("Failed to load store. Please try again.");
|
|
6592
|
+
} finally {
|
|
6593
|
+
if (!cancelled) setLoading(false);
|
|
6594
|
+
}
|
|
6595
|
+
}
|
|
6596
|
+
load();
|
|
6597
|
+
return () => {
|
|
6598
|
+
cancelled = true;
|
|
6599
|
+
};
|
|
6600
|
+
}, [client, compatibleWith]);
|
|
6601
|
+
function navigate(path) {
|
|
6602
|
+
if (onNavigate) {
|
|
6603
|
+
onNavigate(path);
|
|
6604
|
+
return;
|
|
6605
|
+
}
|
|
6606
|
+
window.location.href = path;
|
|
6607
|
+
}
|
|
6608
|
+
function handleProductClick(product) {
|
|
6609
|
+
navigate(`/store/${product.slug}`);
|
|
6610
|
+
}
|
|
6611
|
+
const deduped = grouped ? dedupAcross([grouped.featured, grouped.mostDownloaded, grouped.freeItems]) : [[], [], []];
|
|
6612
|
+
const featuredItems = deduped[0] ?? [];
|
|
6613
|
+
const popularItems = deduped[1] ?? [];
|
|
6614
|
+
const freeItems = deduped[2] ?? [];
|
|
6615
|
+
const resolvedTitle = heroTitle ?? `${productName ? `${productName} ` : ""}Store`;
|
|
6616
|
+
const resolvedSubtitle = heroSubtitle ?? "Discover workflows, nodes, integrations, and templates built by the community.";
|
|
6617
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full", children: [
|
|
6618
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6619
|
+
PageHead,
|
|
6620
|
+
{
|
|
6621
|
+
title: seoTitle ?? `Store${productName ? ` \u2013 ${productName}` : ""}`,
|
|
6622
|
+
description: seoDescription ?? resolvedSubtitle,
|
|
6623
|
+
keywords: seoKeywords,
|
|
6624
|
+
productName
|
|
6625
|
+
}
|
|
6626
|
+
),
|
|
6627
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "relative overflow-hidden pt-14 pb-12 sm:pt-20 sm:pb-16", children: [
|
|
6628
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 bg-gradient-to-b from-background via-primary/[0.06] to-background pointer-events-none", "aria-hidden": "true" }),
|
|
6629
|
+
/* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "absolute inset-0 w-full h-full opacity-[0.035] pointer-events-none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [
|
|
6630
|
+
/* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsx("pattern", { id: "store-home-grid", width: "40", height: "40", patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 40 0 L 0 0 0 40", fill: "none", stroke: "currentColor", strokeWidth: "1" }) }) }),
|
|
6631
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { width: "100%", height: "100%", fill: "url(#store-home-grid)" })
|
|
6632
|
+
] }),
|
|
6633
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -top-16 left-1/3 w-80 h-80 rounded-full bg-primary/10 blur-3xl pointer-events-none", "aria-hidden": "true" }),
|
|
6634
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-8 right-1/4 w-56 h-56 rounded-full bg-primary/8 blur-2xl pointer-events-none", "aria-hidden": "true" }),
|
|
6635
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center", children: [
|
|
6636
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-2 px-3 py-1 rounded-full border border-primary/30 bg-primary/10 text-xs font-semibold text-primary mb-5", children: [
|
|
6637
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-primary flex-shrink-0", "aria-hidden": "true" }),
|
|
6638
|
+
"Community Marketplace"
|
|
6639
|
+
] }),
|
|
6640
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-4xl sm:text-5xl md:text-6xl font-extrabold tracking-tight text-foreground mb-4 leading-[1.08]", children: resolvedTitle }),
|
|
6641
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-lg text-muted-foreground max-w-2xl mx-auto mb-8 leading-relaxed", children: resolvedSubtitle }),
|
|
6642
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
6643
|
+
"form",
|
|
6644
|
+
{
|
|
6645
|
+
className: "max-w-xl mx-auto flex gap-2 mb-7",
|
|
6646
|
+
onSubmit: (e) => {
|
|
6647
|
+
e.preventDefault();
|
|
6648
|
+
const q = new FormData(e.currentTarget).get("q");
|
|
6649
|
+
navigate(q.trim() ? `${browsePath}?q=${encodeURIComponent(q.trim())}` : browsePath);
|
|
6650
|
+
},
|
|
6651
|
+
children: [
|
|
6652
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6653
|
+
"input",
|
|
6654
|
+
{
|
|
6655
|
+
name: "q",
|
|
6656
|
+
type: "search",
|
|
6657
|
+
placeholder: "Search nodes, workflows, templates\u2026",
|
|
6658
|
+
className: "flex-1 h-12 rounded-xl border border-border bg-background px-4 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/40 shadow-sm"
|
|
6659
|
+
}
|
|
6660
|
+
),
|
|
6661
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6662
|
+
"button",
|
|
6663
|
+
{
|
|
6664
|
+
type: "submit",
|
|
6665
|
+
className: "h-12 px-6 rounded-xl bg-primary text-primary-foreground text-sm font-semibold hover:opacity-90 transition-opacity shadow-sm",
|
|
6666
|
+
children: "Search"
|
|
6667
|
+
}
|
|
6668
|
+
)
|
|
6669
|
+
]
|
|
6670
|
+
}
|
|
6671
|
+
),
|
|
6672
|
+
/* @__PURE__ */ jsxRuntime.jsx(TypeFilters, { browsePath, onNavigate: navigate })
|
|
6673
|
+
] })
|
|
6674
|
+
] }),
|
|
6675
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pb-20 space-y-14 pt-4", children: [
|
|
6676
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { children: [
|
|
6677
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6678
|
+
SectionHead,
|
|
6679
|
+
{
|
|
6680
|
+
title: "Featured",
|
|
6681
|
+
hint: "Hand-picked highlights from the community",
|
|
6682
|
+
browseHref: `${browsePath}?featured=true`,
|
|
6683
|
+
onNavigate: navigate
|
|
6684
|
+
}
|
|
6685
|
+
),
|
|
6686
|
+
loading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-[1fr_2fr] gap-4 items-start", children: [
|
|
6687
|
+
/* @__PURE__ */ jsxRuntime.jsx(HeroCardSkeleton, {}),
|
|
6688
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: [...Array(4)].map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(GridCardSkeleton, {}, i)) })
|
|
6689
|
+
] }) : error ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-16 text-center", children: [
|
|
6690
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground mb-4", children: error }),
|
|
6691
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => window.location.reload(), className: "text-sm text-primary hover:underline", children: "Retry" })
|
|
6692
|
+
] }) : featuredItems.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-[1fr_2fr] gap-4 items-start", children: [
|
|
6693
|
+
/* @__PURE__ */ jsxRuntime.jsx(FeaturedHeroCard, { product: featuredItems[0], onNavigate: navigate }),
|
|
6694
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: featuredItems.slice(1, 5).map((product) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
6695
|
+
ProductCard,
|
|
6696
|
+
{
|
|
6697
|
+
product,
|
|
6698
|
+
onClick: () => handleProductClick(product)
|
|
6699
|
+
},
|
|
6700
|
+
product.id
|
|
6701
|
+
)) })
|
|
6702
|
+
] }) : null
|
|
6703
|
+
] }),
|
|
6704
|
+
(loading || popularItems.length > 0) && /* @__PURE__ */ jsxRuntime.jsxs("section", { children: [
|
|
6705
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6706
|
+
SectionHead,
|
|
6707
|
+
{
|
|
6708
|
+
title: "Most Popular",
|
|
6709
|
+
hint: "Top downloads across the community",
|
|
6710
|
+
browseHref: `${browsePath}?sortBy=DOWNLOADS`,
|
|
6711
|
+
onNavigate: navigate
|
|
6712
|
+
}
|
|
6713
|
+
),
|
|
6714
|
+
loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-3 overflow-hidden", children: [...Array(5)].map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(ScrollCardSkeleton, {}, i)) }) : /* @__PURE__ */ jsxRuntime.jsx(ScrollRow, { products: popularItems, onProductClick: handleProductClick })
|
|
6715
|
+
] }),
|
|
6716
|
+
(loading || freeItems.length > 0) && /* @__PURE__ */ jsxRuntime.jsxs("section", { children: [
|
|
6717
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6718
|
+
SectionHead,
|
|
6719
|
+
{
|
|
6720
|
+
title: "Free to Use",
|
|
6721
|
+
hint: "Zero cost, full power \u2014 community-contributed freebies",
|
|
6722
|
+
browseHref: `${browsePath}?pricingModel=FREE`,
|
|
6723
|
+
onNavigate: navigate
|
|
6724
|
+
}
|
|
6725
|
+
),
|
|
6726
|
+
loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4", children: [...Array(6)].map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(GridCardSkeleton, {}, i)) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4", children: freeItems.slice(0, 6).map((product) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
6727
|
+
ProductCard,
|
|
6728
|
+
{
|
|
6729
|
+
product,
|
|
6730
|
+
onClick: () => handleProductClick(product)
|
|
6731
|
+
},
|
|
6732
|
+
product.id
|
|
6733
|
+
)) })
|
|
6734
|
+
] })
|
|
6735
|
+
] }),
|
|
6736
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "relative overflow-hidden border-t border-border", children: [
|
|
6737
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 bg-gradient-to-br from-primary/8 via-background to-primary/5 pointer-events-none", "aria-hidden": "true" }),
|
|
6738
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-80 h-40 rounded-full bg-primary/12 blur-3xl pointer-events-none", "aria-hidden": "true" }),
|
|
6739
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative max-w-2xl mx-auto px-4 py-16 text-center", children: [
|
|
6740
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "inline-flex items-center gap-2 px-3 py-1 rounded-full border border-primary/30 bg-primary/10 text-xs font-semibold text-primary mb-5", children: [
|
|
6741
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-primary flex-shrink-0", "aria-hidden": "true" }),
|
|
6742
|
+
"Become a publisher"
|
|
6743
|
+
] }),
|
|
6744
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl sm:text-3xl font-bold text-foreground mb-3", children: "Built something useful?" }),
|
|
6745
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-muted-foreground mb-8 max-w-lg mx-auto leading-relaxed", children: [
|
|
6746
|
+
"Share your workflows, nodes, and integrations with ",
|
|
6747
|
+
productName ?? "the",
|
|
6748
|
+
" community. Earn from your work or contribute for free."
|
|
6749
|
+
] }),
|
|
6750
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col sm:flex-row gap-3 justify-center", children: [
|
|
6751
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6752
|
+
"a",
|
|
6753
|
+
{
|
|
6754
|
+
href: appLoginUrl,
|
|
6755
|
+
target: "_blank",
|
|
6756
|
+
rel: "noopener noreferrer",
|
|
6757
|
+
className: "inline-flex items-center justify-center h-11 px-7 rounded-lg bg-primary text-primary-foreground text-sm font-semibold hover:opacity-90 transition-opacity",
|
|
6758
|
+
children: "Submit to Store"
|
|
6759
|
+
}
|
|
6760
|
+
),
|
|
6761
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6762
|
+
"button",
|
|
6763
|
+
{
|
|
6764
|
+
type: "button",
|
|
6765
|
+
onClick: () => navigate(browsePath),
|
|
6766
|
+
className: "inline-flex items-center justify-center h-11 px-7 rounded-lg border border-border bg-background text-sm font-medium text-foreground hover:border-primary/40 hover:bg-primary/5 transition-all",
|
|
6767
|
+
children: "Browse the store"
|
|
6768
|
+
}
|
|
6769
|
+
)
|
|
6770
|
+
] })
|
|
6771
|
+
] })
|
|
6772
|
+
] })
|
|
6773
|
+
] });
|
|
6774
|
+
}
|
|
6775
|
+
var SORT_OPTIONS = [
|
|
6776
|
+
{ value: "RELEVANCE", label: "Relevance" },
|
|
6777
|
+
{ value: "NEWEST", label: "Newest" },
|
|
6778
|
+
{ value: "DOWNLOADS", label: "Most Downloaded" },
|
|
6779
|
+
{ value: "RATING", label: "Top Rated" },
|
|
6780
|
+
{ value: "PRICE_LOW", label: "Price: Low to High" },
|
|
6781
|
+
{ value: "PRICE_HIGH", label: "Price: High to Low" },
|
|
6782
|
+
{ value: "NAME_ASC", label: "Name A\u2013Z" }
|
|
6783
|
+
];
|
|
6784
|
+
var TYPE_OPTIONS = [
|
|
6785
|
+
{ value: "", label: "All types" },
|
|
6786
|
+
{ value: "APP", label: "Apps" },
|
|
6787
|
+
{ value: "NODE", label: "Nodes" },
|
|
6788
|
+
{ value: "WORKFLOW", label: "Workflows" },
|
|
6789
|
+
{ value: "TEMPLATE", label: "Templates" },
|
|
6790
|
+
{ value: "INTEGRATION", label: "Integrations" },
|
|
6791
|
+
{ value: "EXTENSION", label: "Extensions" },
|
|
6792
|
+
{ value: "THEME", label: "Themes" }
|
|
6793
|
+
];
|
|
6794
|
+
var PRICING_OPTIONS = [
|
|
6795
|
+
{ value: "", label: "All pricing" },
|
|
6796
|
+
{ value: "FREE", label: "Free" },
|
|
6797
|
+
{ value: "ONE_TIME", label: "Paid (one-time)" },
|
|
6798
|
+
{ value: "SUBSCRIPTION", label: "Subscription" }
|
|
6799
|
+
];
|
|
6800
|
+
function parseUrlParams() {
|
|
6801
|
+
if (typeof window === "undefined")
|
|
6802
|
+
return { q: "", type: "", pricingModel: "", category: "", sortBy: "RELEVANCE", featured: false };
|
|
6803
|
+
const p = new URLSearchParams(window.location.search);
|
|
6804
|
+
return {
|
|
6805
|
+
q: p.get("q") ?? "",
|
|
6806
|
+
type: p.get("type") ?? "",
|
|
6807
|
+
pricingModel: p.get("pricingModel") ?? "",
|
|
6808
|
+
category: p.get("category") ?? "",
|
|
6809
|
+
sortBy: p.get("sortBy") ?? (p.get("q") ? "RELEVANCE" : "NEWEST"),
|
|
6810
|
+
featured: p.get("featured") === "true"
|
|
6811
|
+
};
|
|
6812
|
+
}
|
|
6813
|
+
function FacetList({
|
|
6814
|
+
title,
|
|
6815
|
+
facets,
|
|
6816
|
+
selected,
|
|
6817
|
+
onSelect
|
|
6818
|
+
}) {
|
|
6819
|
+
if (facets.length === 0) return null;
|
|
6820
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
6821
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-2", children: title }),
|
|
6822
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-1", children: facets.map((f) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6823
|
+
"button",
|
|
6824
|
+
{
|
|
6825
|
+
type: "button",
|
|
6826
|
+
onClick: () => onSelect(selected === f.value ? "" : f.value),
|
|
6827
|
+
className: `w-full text-left text-sm px-2 py-1 rounded flex items-center justify-between gap-2 transition-colors ${selected === f.value ? "bg-primary/10 text-primary font-medium" : "text-muted-foreground hover:text-foreground hover:bg-muted/50"}`,
|
|
6828
|
+
children: [
|
|
6829
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: f.value }),
|
|
6830
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs opacity-60 flex-shrink-0", children: f.count })
|
|
6831
|
+
]
|
|
6832
|
+
}
|
|
6833
|
+
) }, f.value)) })
|
|
6834
|
+
] });
|
|
6835
|
+
}
|
|
6836
|
+
function StoreBrowsePage({
|
|
6837
|
+
compatibleWith,
|
|
6838
|
+
onNavigate,
|
|
6839
|
+
productName,
|
|
6840
|
+
seoTitle,
|
|
6841
|
+
seoDescription
|
|
6842
|
+
}) {
|
|
6843
|
+
const client = useWebSDK();
|
|
6844
|
+
const initial = parseUrlParams();
|
|
6845
|
+
const [search, setSearch] = React.useState(initial.q);
|
|
6846
|
+
const [inputValue, setInputValue] = React.useState(initial.q);
|
|
6847
|
+
const [type, setType] = React.useState(initial.type);
|
|
6848
|
+
const [pricingModel, setPricingModel] = React.useState(initial.pricingModel);
|
|
6849
|
+
const [category, setCategory] = React.useState(initial.category);
|
|
6850
|
+
const [sortBy, setSortBy] = React.useState(initial.sortBy);
|
|
6851
|
+
const [featured, setFeatured] = React.useState(initial.featured);
|
|
6852
|
+
const [offset, setOffset] = React.useState(0);
|
|
6853
|
+
const [result, setResult] = React.useState(null);
|
|
6854
|
+
const [allProducts, setAllProducts] = React.useState([]);
|
|
6855
|
+
const [categories, setCategories] = React.useState([]);
|
|
6856
|
+
const [loading, setLoading] = React.useState(true);
|
|
6857
|
+
const [loadingMore, setLoadingMore] = React.useState(false);
|
|
6858
|
+
const [filtersOpen, setFiltersOpen] = React.useState(false);
|
|
6859
|
+
const searchRef = React.useRef(null);
|
|
6860
|
+
const PAGE_SIZE = 24;
|
|
6861
|
+
React.useEffect(() => {
|
|
6862
|
+
client.query(CATEGORIES_QUERY, {}).then((r) => {
|
|
6863
|
+
if (r.data?.categories) setCategories(r.data.categories);
|
|
6864
|
+
}).catch(() => {
|
|
6865
|
+
});
|
|
6866
|
+
}, [client]);
|
|
6867
|
+
React.useEffect(() => {
|
|
6868
|
+
let cancelled = false;
|
|
6869
|
+
setOffset(0);
|
|
6870
|
+
setLoading(true);
|
|
6871
|
+
setAllProducts([]);
|
|
6872
|
+
client.query(BROWSE_STORE_QUERY, {
|
|
6873
|
+
input: {
|
|
6874
|
+
filter: {
|
|
6875
|
+
search: search || void 0,
|
|
6876
|
+
type: type || void 0,
|
|
6877
|
+
pricingModel: pricingModel || void 0,
|
|
6878
|
+
category: category || void 0,
|
|
6879
|
+
compatibleWith: compatibleWith ?? void 0,
|
|
6880
|
+
featured: featured || void 0
|
|
6881
|
+
},
|
|
6882
|
+
sortBy,
|
|
6883
|
+
pagination: { limit: PAGE_SIZE, offset: 0 }
|
|
6884
|
+
}
|
|
6885
|
+
}).then((r) => {
|
|
6886
|
+
if (cancelled) return;
|
|
6887
|
+
if (r.data?.browseStore) {
|
|
6888
|
+
setResult(r.data.browseStore);
|
|
6889
|
+
setAllProducts(r.data.browseStore.products);
|
|
6890
|
+
}
|
|
6891
|
+
}).catch(() => {
|
|
6892
|
+
}).finally(() => {
|
|
6893
|
+
if (!cancelled) setLoading(false);
|
|
6894
|
+
});
|
|
6895
|
+
return () => {
|
|
6896
|
+
cancelled = true;
|
|
6897
|
+
};
|
|
6898
|
+
}, [client, search, type, pricingModel, category, sortBy, compatibleWith, featured]);
|
|
6899
|
+
function loadMore() {
|
|
6900
|
+
const nextOffset = offset + PAGE_SIZE;
|
|
6901
|
+
setLoadingMore(true);
|
|
6902
|
+
client.query(BROWSE_STORE_QUERY, {
|
|
6903
|
+
input: {
|
|
6904
|
+
filter: {
|
|
6905
|
+
search: search || void 0,
|
|
6906
|
+
type: type || void 0,
|
|
6907
|
+
pricingModel: pricingModel || void 0,
|
|
6908
|
+
category: category || void 0,
|
|
6909
|
+
compatibleWith: compatibleWith ?? void 0,
|
|
6910
|
+
featured: featured || void 0
|
|
6911
|
+
},
|
|
6912
|
+
sortBy,
|
|
6913
|
+
pagination: { limit: PAGE_SIZE, offset: nextOffset }
|
|
6914
|
+
}
|
|
6915
|
+
}).then((r) => {
|
|
6916
|
+
if (r.data?.browseStore) {
|
|
6917
|
+
setResult(r.data.browseStore);
|
|
6918
|
+
setAllProducts((prev) => [...prev, ...r.data.browseStore.products]);
|
|
6919
|
+
setOffset(nextOffset);
|
|
6920
|
+
}
|
|
6921
|
+
}).catch(() => {
|
|
6922
|
+
}).finally(() => setLoadingMore(false));
|
|
6923
|
+
}
|
|
6924
|
+
function navigate(path) {
|
|
6925
|
+
if (onNavigate) {
|
|
6926
|
+
onNavigate(path);
|
|
6927
|
+
return;
|
|
6928
|
+
}
|
|
6929
|
+
window.location.href = path;
|
|
6930
|
+
}
|
|
6931
|
+
function handleSearchSubmit(e) {
|
|
6932
|
+
e.preventDefault();
|
|
6933
|
+
setSearch(inputValue);
|
|
6934
|
+
setSortBy(inputValue ? "RELEVANCE" : "NEWEST");
|
|
6935
|
+
}
|
|
6936
|
+
function resetFilters() {
|
|
6937
|
+
setSearch("");
|
|
6938
|
+
setInputValue("");
|
|
6939
|
+
setType("");
|
|
6940
|
+
setPricingModel("");
|
|
6941
|
+
setCategory("");
|
|
6942
|
+
setSortBy("NEWEST");
|
|
6943
|
+
setFeatured(false);
|
|
6944
|
+
searchRef.current?.focus();
|
|
6945
|
+
}
|
|
6946
|
+
const hasActiveFilters = !!(search || type || pricingModel || category || featured);
|
|
6947
|
+
const facetTypes = result?.facets?.types ?? [];
|
|
6948
|
+
const facetCategories = result?.facets?.categories ?? [];
|
|
6949
|
+
const sidebarContent = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
|
|
6950
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
6951
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-2", children: "Type" }),
|
|
6952
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: TYPE_OPTIONS.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
6953
|
+
"button",
|
|
6954
|
+
{
|
|
6955
|
+
type: "button",
|
|
6956
|
+
onClick: () => setType(opt.value),
|
|
6957
|
+
className: `w-full text-left text-sm px-2 py-1.5 rounded transition-colors ${type === opt.value ? "bg-primary/10 text-primary font-medium" : "text-muted-foreground hover:text-foreground hover:bg-muted/50"}`,
|
|
6958
|
+
children: opt.label
|
|
6959
|
+
},
|
|
6960
|
+
opt.value
|
|
6961
|
+
)) })
|
|
6962
|
+
] }),
|
|
6963
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
6964
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-2", children: "Pricing" }),
|
|
6965
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: PRICING_OPTIONS.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
6966
|
+
"button",
|
|
6967
|
+
{
|
|
6968
|
+
type: "button",
|
|
6969
|
+
onClick: () => setPricingModel(opt.value),
|
|
6970
|
+
className: `w-full text-left text-sm px-2 py-1.5 rounded transition-colors ${pricingModel === opt.value ? "bg-primary/10 text-primary font-medium" : "text-muted-foreground hover:text-foreground hover:bg-muted/50"}`,
|
|
6971
|
+
children: opt.label
|
|
6972
|
+
},
|
|
6973
|
+
opt.value
|
|
6974
|
+
)) })
|
|
6975
|
+
] }),
|
|
6976
|
+
(facetCategories.length > 0 || categories.length > 0) && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
6977
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-2", children: "Category" }),
|
|
6978
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
6979
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6980
|
+
"button",
|
|
6981
|
+
{
|
|
6982
|
+
type: "button",
|
|
6983
|
+
onClick: () => setCategory(""),
|
|
6984
|
+
className: `w-full text-left text-sm px-2 py-1.5 rounded transition-colors ${!category ? "bg-primary/10 text-primary font-medium" : "text-muted-foreground hover:text-foreground hover:bg-muted/50"}`,
|
|
6985
|
+
children: "All categories"
|
|
6986
|
+
}
|
|
6987
|
+
),
|
|
6988
|
+
(facetCategories.length > 0 ? facetCategories : categories.slice(0, 12).map((c) => ({ value: c.slug, count: 0 }))).map((f) => {
|
|
6989
|
+
const cat = categories.find((c) => c.slug === f.value);
|
|
6990
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6991
|
+
"button",
|
|
6992
|
+
{
|
|
6993
|
+
type: "button",
|
|
6994
|
+
onClick: () => setCategory(category === f.value ? "" : f.value),
|
|
6995
|
+
className: `w-full text-left text-sm px-2 py-1.5 rounded flex items-center justify-between gap-2 transition-colors ${category === f.value ? "bg-primary/10 text-primary font-medium" : "text-muted-foreground hover:text-foreground hover:bg-muted/50"}`,
|
|
6996
|
+
children: [
|
|
6997
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: cat?.name ?? f.value }),
|
|
6998
|
+
f.count > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs opacity-60 flex-shrink-0", children: f.count })
|
|
6999
|
+
]
|
|
7000
|
+
},
|
|
7001
|
+
f.value
|
|
7002
|
+
);
|
|
7003
|
+
})
|
|
7004
|
+
] })
|
|
7005
|
+
] }),
|
|
7006
|
+
facetTypes.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7007
|
+
FacetList,
|
|
7008
|
+
{
|
|
7009
|
+
title: "Available types",
|
|
7010
|
+
facets: facetTypes,
|
|
7011
|
+
selected: type,
|
|
7012
|
+
onSelect: setType
|
|
7013
|
+
}
|
|
7014
|
+
),
|
|
7015
|
+
hasActiveFilters && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7016
|
+
"button",
|
|
7017
|
+
{
|
|
7018
|
+
type: "button",
|
|
7019
|
+
onClick: resetFilters,
|
|
7020
|
+
className: "text-sm text-muted-foreground hover:text-foreground underline",
|
|
7021
|
+
children: "Clear all filters"
|
|
7022
|
+
}
|
|
7023
|
+
)
|
|
7024
|
+
] });
|
|
7025
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full", children: [
|
|
7026
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7027
|
+
PageHead,
|
|
7028
|
+
{
|
|
7029
|
+
title: seoTitle ?? `Browse Store${productName ? ` \u2013 ${productName}` : ""}`,
|
|
7030
|
+
description: seoDescription ?? "Browse all apps, workflows, nodes, and templates.",
|
|
7031
|
+
productName
|
|
7032
|
+
}
|
|
7033
|
+
),
|
|
7034
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8", children: [
|
|
7035
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col sm:flex-row gap-3 mb-6", children: [
|
|
7036
|
+
/* @__PURE__ */ jsxRuntime.jsxs("form", { className: "flex-1 flex gap-2", onSubmit: handleSearchSubmit, children: [
|
|
7037
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7038
|
+
"input",
|
|
7039
|
+
{
|
|
7040
|
+
ref: searchRef,
|
|
7041
|
+
type: "search",
|
|
7042
|
+
value: inputValue,
|
|
7043
|
+
onChange: (e) => setInputValue(e.target.value),
|
|
7044
|
+
placeholder: "Search\u2026",
|
|
7045
|
+
className: "flex-1 h-10 rounded-lg border border-border bg-background px-4 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/50"
|
|
7046
|
+
}
|
|
7047
|
+
),
|
|
7048
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7049
|
+
"button",
|
|
7050
|
+
{
|
|
7051
|
+
type: "submit",
|
|
7052
|
+
className: "h-10 px-5 rounded-lg bg-primary text-primary-foreground text-sm font-medium hover:opacity-90 transition-opacity",
|
|
7053
|
+
children: "Search"
|
|
7054
|
+
}
|
|
7055
|
+
)
|
|
7056
|
+
] }),
|
|
7057
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
|
|
7058
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7059
|
+
"select",
|
|
7060
|
+
{
|
|
7061
|
+
value: sortBy,
|
|
7062
|
+
onChange: (e) => setSortBy(e.target.value),
|
|
7063
|
+
className: "h-10 rounded-lg border border-border bg-background px-3 text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-primary/50",
|
|
7064
|
+
children: SORT_OPTIONS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
|
|
7065
|
+
}
|
|
7066
|
+
),
|
|
7067
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
7068
|
+
"button",
|
|
7069
|
+
{
|
|
7070
|
+
type: "button",
|
|
7071
|
+
onClick: () => setFiltersOpen(!filtersOpen),
|
|
7072
|
+
className: "lg:hidden h-10 px-4 rounded-lg border border-border bg-background text-sm text-foreground hover:bg-muted/50 transition-colors",
|
|
7073
|
+
children: [
|
|
7074
|
+
"Filters ",
|
|
7075
|
+
hasActiveFilters && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-primary", children: "\u2022" })
|
|
7076
|
+
]
|
|
7077
|
+
}
|
|
7078
|
+
)
|
|
7079
|
+
] })
|
|
7080
|
+
] }),
|
|
7081
|
+
filtersOpen && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "lg:hidden mb-6 p-4 border border-border rounded-xl bg-card", children: sidebarContent }),
|
|
7082
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-8", children: [
|
|
7083
|
+
/* @__PURE__ */ jsxRuntime.jsx("aside", { className: "hidden lg:block w-52 flex-shrink-0", children: sidebarContent }),
|
|
7084
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
7085
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-4 flex-wrap", children: [
|
|
7086
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: loading ? "Loading\u2026" : `${result?.totalCount ?? 0} results` }),
|
|
7087
|
+
hasActiveFilters && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-1.5", children: [
|
|
7088
|
+
search && /* @__PURE__ */ jsxRuntime.jsx(Chip, { label: `"${search}"`, onRemove: () => {
|
|
7089
|
+
setSearch("");
|
|
7090
|
+
setInputValue("");
|
|
7091
|
+
} }),
|
|
7092
|
+
type && /* @__PURE__ */ jsxRuntime.jsx(Chip, { label: type, onRemove: () => setType("") }),
|
|
7093
|
+
pricingModel && /* @__PURE__ */ jsxRuntime.jsx(Chip, { label: pricingModel, onRemove: () => setPricingModel("") }),
|
|
7094
|
+
category && /* @__PURE__ */ jsxRuntime.jsx(Chip, { label: category, onRemove: () => setCategory("") }),
|
|
7095
|
+
featured && /* @__PURE__ */ jsxRuntime.jsx(Chip, { label: "Featured", onRemove: () => setFeatured(false) })
|
|
7096
|
+
] })
|
|
7097
|
+
] }),
|
|
7098
|
+
loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-4", children: [...Array(12)].map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
7099
|
+
"div",
|
|
7100
|
+
{
|
|
7101
|
+
className: "bg-card border border-border rounded-xl p-4 h-36 animate-pulse"
|
|
7102
|
+
},
|
|
7103
|
+
i
|
|
7104
|
+
)) }) : allProducts.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-20 text-center", children: [
|
|
7105
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-muted-foreground mb-4", children: [
|
|
7106
|
+
"No results found",
|
|
7107
|
+
search ? ` for "${search}"` : "",
|
|
7108
|
+
"."
|
|
7109
|
+
] }),
|
|
7110
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7111
|
+
"button",
|
|
7112
|
+
{
|
|
7113
|
+
type: "button",
|
|
7114
|
+
onClick: resetFilters,
|
|
7115
|
+
className: "text-sm text-primary hover:underline",
|
|
7116
|
+
children: "Clear filters"
|
|
7117
|
+
}
|
|
7118
|
+
)
|
|
7119
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
7120
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-4", children: allProducts.map((product) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
7121
|
+
ProductCard,
|
|
7122
|
+
{
|
|
7123
|
+
product,
|
|
7124
|
+
onClick: () => navigate(`/store/${product.slug}`)
|
|
7125
|
+
},
|
|
7126
|
+
product.id
|
|
7127
|
+
)) }),
|
|
7128
|
+
result?.hasMore && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-8 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7129
|
+
"button",
|
|
7130
|
+
{
|
|
7131
|
+
type: "button",
|
|
7132
|
+
onClick: loadMore,
|
|
7133
|
+
disabled: loadingMore,
|
|
7134
|
+
className: "h-10 px-8 rounded-lg border border-border text-sm font-medium text-foreground hover:bg-muted/50 transition-colors disabled:opacity-50",
|
|
7135
|
+
children: loadingMore ? "Loading\u2026" : "Load more"
|
|
7136
|
+
}
|
|
7137
|
+
) })
|
|
7138
|
+
] })
|
|
7139
|
+
] })
|
|
7140
|
+
] })
|
|
7141
|
+
] })
|
|
7142
|
+
] });
|
|
7143
|
+
}
|
|
7144
|
+
function Chip({ label, onRemove }) {
|
|
7145
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 text-xs bg-primary/10 text-primary rounded-full px-2.5 py-0.5 font-medium", children: [
|
|
7146
|
+
label,
|
|
7147
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: onRemove, "aria-label": `Remove ${label}`, className: "hover:opacity-70", children: "\xD7" })
|
|
7148
|
+
] });
|
|
7149
|
+
}
|
|
7150
|
+
var ANIM_STYLES = `
|
|
7151
|
+
@keyframes sdFadeUp {
|
|
7152
|
+
from { opacity: 0; transform: translateY(16px); }
|
|
7153
|
+
to { opacity: 1; transform: translateY(0); }
|
|
7154
|
+
}
|
|
7155
|
+
@keyframes sdFadeIn {
|
|
7156
|
+
from { opacity: 0; }
|
|
7157
|
+
to { opacity: 1; }
|
|
7158
|
+
}
|
|
7159
|
+
@keyframes sdScaleIn {
|
|
7160
|
+
from { opacity: 0; transform: scale(0.94); }
|
|
7161
|
+
to { opacity: 1; transform: scale(1); }
|
|
7162
|
+
}
|
|
7163
|
+
@keyframes sdGlowPulse {
|
|
7164
|
+
0%, 100% { opacity: 0.35; }
|
|
7165
|
+
50% { opacity: 0.65; }
|
|
7166
|
+
}
|
|
7167
|
+
@media (prefers-reduced-motion: reduce) {
|
|
7168
|
+
.sd-fu, .sd-fi, .sd-si { animation: none !important; opacity: 1 !important; transform: none !important; }
|
|
7169
|
+
.sd-gp { animation: none !important; }
|
|
7170
|
+
}
|
|
7171
|
+
.sd-fu { animation: sdFadeUp 0.55s cubic-bezier(0.16,1,0.3,1) both; }
|
|
7172
|
+
.sd-fi { animation: sdFadeIn 0.45s ease-out both; }
|
|
7173
|
+
.sd-si { animation: sdScaleIn 0.45s cubic-bezier(0.16,1,0.3,1) both; }
|
|
7174
|
+
.sd-gp { animation: sdGlowPulse 3s ease-in-out infinite; }
|
|
7175
|
+
.sd-d1 { animation-delay: 60ms; }
|
|
7176
|
+
.sd-d2 { animation-delay: 120ms; }
|
|
7177
|
+
.sd-d3 { animation-delay: 180ms; }
|
|
7178
|
+
.sd-d4 { animation-delay: 240ms; }
|
|
7179
|
+
.sd-d5 { animation-delay: 320ms; }
|
|
7180
|
+
.sd-d6 { animation-delay: 400ms; }
|
|
7181
|
+
`;
|
|
7182
|
+
function RatingBar({ label, count, total }) {
|
|
7183
|
+
const pct = total > 0 ? Math.round(count / total * 100) : 0;
|
|
7184
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
7185
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-12 text-right shrink-0", children: label }),
|
|
7186
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 h-1.5 bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7187
|
+
"div",
|
|
7188
|
+
{
|
|
7189
|
+
className: "h-full bg-amber-400 rounded-full transition-all duration-700",
|
|
7190
|
+
style: { width: `${pct}%` }
|
|
7191
|
+
}
|
|
7192
|
+
) }),
|
|
7193
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-6 shrink-0", children: count })
|
|
7194
|
+
] });
|
|
7195
|
+
}
|
|
7196
|
+
function IconBlock({ src }) {
|
|
7197
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-shrink-0", children: [
|
|
7198
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sd-gp absolute -inset-1.5 rounded-2xl bg-primary/30 blur-md pointer-events-none", "aria-hidden": "true" }),
|
|
7199
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sd-si relative w-20 h-20 rounded-2xl overflow-hidden shadow-lg ring-1 ring-border", children: src ? /* @__PURE__ */ jsxRuntime.jsx("img", { src, alt: "", "aria-hidden": true, className: "w-full h-full object-cover" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-full bg-gradient-to-br from-primary/25 to-primary/8 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 40 40", className: "w-10 h-10", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [
|
|
7200
|
+
/* @__PURE__ */ jsxRuntime.jsx("polygon", { points: "20,4 34,11 20,18 6,11", className: "fill-primary/40", stroke: "currentColor", strokeWidth: "0.6", strokeOpacity: "0.4" }),
|
|
7201
|
+
/* @__PURE__ */ jsxRuntime.jsx("polygon", { points: "6,11 20,18 20,34 6,27", className: "fill-primary/20", stroke: "currentColor", strokeWidth: "0.6", strokeOpacity: "0.4" }),
|
|
7202
|
+
/* @__PURE__ */ jsxRuntime.jsx("polygon", { points: "34,11 20,18 20,34 34,27", className: "fill-primary/30", stroke: "currentColor", strokeWidth: "0.6", strokeOpacity: "0.4" })
|
|
7203
|
+
] }) }) })
|
|
7204
|
+
] });
|
|
7205
|
+
}
|
|
7206
|
+
function StoreProductDetailPage({
|
|
7207
|
+
slug,
|
|
7208
|
+
id,
|
|
7209
|
+
appLoginUrl,
|
|
7210
|
+
onNavigate,
|
|
7211
|
+
productName
|
|
7212
|
+
}) {
|
|
7213
|
+
const client = useWebSDK();
|
|
7214
|
+
const [details, setDetails] = React.useState(null);
|
|
7215
|
+
const [loading, setLoading] = React.useState(true);
|
|
7216
|
+
const [error, setError] = React.useState(null);
|
|
7217
|
+
const [activeScreenshot, setActiveScreenshot] = React.useState(0);
|
|
7218
|
+
const [screenshotKey, setScreenshotKey] = React.useState(0);
|
|
7219
|
+
React.useEffect(() => {
|
|
7220
|
+
if (!slug && !id) {
|
|
7221
|
+
setError("Product not found.");
|
|
7222
|
+
setLoading(false);
|
|
7223
|
+
return;
|
|
7224
|
+
}
|
|
7225
|
+
let cancelled = false;
|
|
7226
|
+
setLoading(true);
|
|
7227
|
+
client.query(STORE_PRODUCT_DETAILS_QUERY, {
|
|
7228
|
+
input: { slug: slug ?? void 0, id: id ?? void 0 }
|
|
7229
|
+
}).then((r) => {
|
|
7230
|
+
if (cancelled) return;
|
|
7231
|
+
if (r.errors?.length) throw new Error(r.errors[0].message);
|
|
7232
|
+
if (!r.data?.storeProductDetails) throw new Error("Not found");
|
|
7233
|
+
setDetails(r.data.storeProductDetails);
|
|
7234
|
+
}).catch(() => {
|
|
7235
|
+
if (!cancelled) setError("Product not found or unavailable.");
|
|
7236
|
+
}).finally(() => {
|
|
7237
|
+
if (!cancelled) setLoading(false);
|
|
7238
|
+
});
|
|
7239
|
+
return () => {
|
|
7240
|
+
cancelled = true;
|
|
7241
|
+
};
|
|
7242
|
+
}, [client, slug, id]);
|
|
7243
|
+
function navigate(path) {
|
|
7244
|
+
if (onNavigate) {
|
|
7245
|
+
onNavigate(path);
|
|
7246
|
+
return;
|
|
7247
|
+
}
|
|
7248
|
+
window.location.href = path;
|
|
7249
|
+
}
|
|
7250
|
+
function switchScreenshot(i) {
|
|
7251
|
+
setActiveScreenshot(i);
|
|
7252
|
+
setScreenshotKey((k) => k + 1);
|
|
7253
|
+
}
|
|
7254
|
+
if (loading) {
|
|
7255
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12 animate-pulse", children: [
|
|
7256
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 bg-muted rounded w-40 mb-8" }),
|
|
7257
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-6 mb-8", children: [
|
|
7258
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-20 h-20 rounded-2xl bg-muted flex-shrink-0" }),
|
|
7259
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-3 pt-1", children: [
|
|
7260
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-6 bg-muted rounded w-1/3" }),
|
|
7261
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 bg-muted rounded w-1/2" }),
|
|
7262
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 bg-muted rounded w-1/4" })
|
|
7263
|
+
] })
|
|
7264
|
+
] }),
|
|
7265
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-56 bg-muted rounded-xl mb-8" }),
|
|
7266
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: [...Array(5)].map((_, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-4 bg-muted rounded" }, i)) })
|
|
7267
|
+
] });
|
|
7268
|
+
}
|
|
7269
|
+
if (error || !details) {
|
|
7270
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20 text-center", children: [
|
|
7271
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground mb-4", children: error ?? "Product not found." }),
|
|
7272
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => navigate("/store"), className: "text-sm text-primary hover:underline", children: "Back to Store" })
|
|
7273
|
+
] });
|
|
7274
|
+
}
|
|
7275
|
+
const { product, publisher, reviews, reviewsCount, relatedProducts, ratingDistribution } = details;
|
|
7276
|
+
const priceLabel = formatPrice2(product.price, product.currency, product.pricingModel);
|
|
7277
|
+
const screenshots = product.screenshots ?? [];
|
|
7278
|
+
const totalRatings = ratingDistribution ? ratingDistribution.fiveStars + ratingDistribution.fourStars + ratingDistribution.threeStars + ratingDistribution.twoStars + ratingDistribution.oneStar : 0;
|
|
7279
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full", children: [
|
|
7280
|
+
/* @__PURE__ */ jsxRuntime.jsx("style", { dangerouslySetInnerHTML: { __html: ANIM_STYLES } }),
|
|
7281
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7282
|
+
PageHead,
|
|
7283
|
+
{
|
|
7284
|
+
title: `${product.name}${productName ? ` \u2013 ${productName} Store` : " \u2013 Store"}`,
|
|
7285
|
+
description: product.description ?? void 0,
|
|
7286
|
+
productName
|
|
7287
|
+
}
|
|
7288
|
+
),
|
|
7289
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative overflow-hidden", children: [
|
|
7290
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 bg-gradient-to-b from-primary/[0.07] via-background to-background pointer-events-none", "aria-hidden": "true" }),
|
|
7291
|
+
/* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "absolute inset-0 w-full h-full opacity-[0.04] pointer-events-none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [
|
|
7292
|
+
/* @__PURE__ */ jsxRuntime.jsx("defs", { children: /* @__PURE__ */ jsxRuntime.jsx("pattern", { id: "sd-grid", width: "40", height: "40", patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 40 0 L 0 0 0 40", fill: "none", stroke: "currentColor", strokeWidth: "1" }) }) }),
|
|
7293
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { width: "100%", height: "100%", fill: "url(#sd-grid)" })
|
|
7294
|
+
] }),
|
|
7295
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -top-12 -left-12 w-72 h-72 rounded-full bg-primary/10 blur-3xl pointer-events-none", "aria-hidden": "true" }),
|
|
7296
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pt-6 pb-8", children: [
|
|
7297
|
+
/* @__PURE__ */ jsxRuntime.jsxs("nav", { className: "sd-fi text-sm text-muted-foreground mb-6 flex items-center gap-1.5 flex-wrap", children: [
|
|
7298
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => navigate("/store"), className: "hover:text-primary transition-colors", children: "Store" }),
|
|
7299
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u203A" }),
|
|
7300
|
+
product.category && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
7301
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7302
|
+
"button",
|
|
7303
|
+
{
|
|
7304
|
+
type: "button",
|
|
7305
|
+
onClick: () => navigate(`/store/browse?category=${product.category}`),
|
|
7306
|
+
className: "hover:text-primary transition-colors",
|
|
7307
|
+
children: product.category
|
|
7308
|
+
}
|
|
7309
|
+
),
|
|
7310
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u203A" })
|
|
7311
|
+
] }),
|
|
7312
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground font-medium", children: product.name })
|
|
7313
|
+
] }),
|
|
7314
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-5 items-start", children: [
|
|
7315
|
+
/* @__PURE__ */ jsxRuntime.jsx(IconBlock, { src: product.icon, name: product.name }),
|
|
7316
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
7317
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sd-fu flex items-start gap-2 flex-wrap mb-1", children: [
|
|
7318
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl sm:text-3xl font-bold text-foreground leading-tight", children: product.name }),
|
|
7319
|
+
/* @__PURE__ */ jsxRuntime.jsx(TypeBadge, { type: product.type })
|
|
7320
|
+
] }),
|
|
7321
|
+
product.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "sd-fu sd-d1 text-muted-foreground text-sm mb-2 leading-relaxed", children: product.description }),
|
|
7322
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sd-fu sd-d2 flex items-center gap-3 text-sm text-muted-foreground flex-wrap", children: [
|
|
7323
|
+
product.rating != null && product.rating > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1", children: [
|
|
7324
|
+
/* @__PURE__ */ jsxRuntime.jsx(StarRating, { rating: product.rating }),
|
|
7325
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground", children: product.rating.toFixed(1) }),
|
|
7326
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
7327
|
+
"(",
|
|
7328
|
+
reviewsCount ?? 0,
|
|
7329
|
+
")"
|
|
7330
|
+
] })
|
|
7331
|
+
] }),
|
|
7332
|
+
product.downloads != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
7333
|
+
formatDownloads(product.downloads),
|
|
7334
|
+
" downloads"
|
|
7335
|
+
] }),
|
|
7336
|
+
product.authorName && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
7337
|
+
"by ",
|
|
7338
|
+
product.authorName
|
|
7339
|
+
] }),
|
|
7340
|
+
product.license && /* @__PURE__ */ jsxRuntime.jsx("span", { children: product.license })
|
|
7341
|
+
] })
|
|
7342
|
+
] })
|
|
7343
|
+
] })
|
|
7344
|
+
] })
|
|
7345
|
+
] }),
|
|
7346
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid lg:grid-cols-[1fr_300px] gap-8", children: [
|
|
7347
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
7348
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sd-fu sd-d3 lg:hidden mb-6 p-4 rounded-xl border border-border bg-card flex items-center gap-4", children: [
|
|
7349
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
7350
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-2xl font-bold text-foreground", children: priceLabel }),
|
|
7351
|
+
product.pricingModel === "SUBSCRIPTION" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground", children: "per month" })
|
|
7352
|
+
] }),
|
|
7353
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7354
|
+
"a",
|
|
7355
|
+
{
|
|
7356
|
+
href: appLoginUrl,
|
|
7357
|
+
target: "_blank",
|
|
7358
|
+
rel: "noopener noreferrer",
|
|
7359
|
+
className: "flex-1 h-11 rounded-lg bg-primary text-primary-foreground text-sm font-semibold flex items-center justify-center hover:opacity-90 transition-opacity",
|
|
7360
|
+
children: priceLabel === "Free" ? "Install Free" : `Get for ${priceLabel}`
|
|
7361
|
+
}
|
|
7362
|
+
)
|
|
7363
|
+
] }),
|
|
7364
|
+
screenshots.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sd-fu sd-d3 mb-8", children: [
|
|
7365
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-xl overflow-hidden bg-muted aspect-video mb-3 shadow-md", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7366
|
+
"img",
|
|
7367
|
+
{
|
|
7368
|
+
src: screenshots[activeScreenshot],
|
|
7369
|
+
alt: `Screenshot ${activeScreenshot + 1}`,
|
|
7370
|
+
className: "sd-fi w-full h-full object-cover"
|
|
7371
|
+
},
|
|
7372
|
+
screenshotKey
|
|
7373
|
+
) }),
|
|
7374
|
+
screenshots.length > 1 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-2 overflow-x-auto pb-1", children: screenshots.map((src, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
7375
|
+
"button",
|
|
7376
|
+
{
|
|
7377
|
+
type: "button",
|
|
7378
|
+
onClick: () => switchScreenshot(i),
|
|
7379
|
+
className: `w-20 h-14 rounded-lg overflow-hidden flex-shrink-0 border-2 transition-all duration-200 ${i === activeScreenshot ? "border-primary shadow-sm shadow-primary/20" : "border-transparent opacity-50 hover:opacity-80"}`,
|
|
7380
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("img", { src, alt: `Thumbnail ${i + 1}`, className: "w-full h-full object-cover" })
|
|
7381
|
+
},
|
|
7382
|
+
i
|
|
7383
|
+
)) })
|
|
7384
|
+
] }),
|
|
7385
|
+
product.longDescription && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sd-fu sd-d4 mb-8", children: [
|
|
7386
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-bold text-foreground mb-3", children: "About" }),
|
|
7387
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "prose prose-sm max-w-none text-muted-foreground leading-relaxed whitespace-pre-line", children: product.longDescription })
|
|
7388
|
+
] }),
|
|
7389
|
+
publisher && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sd-fu sd-d5 mb-8 p-4 rounded-xl border border-border bg-card hover:border-primary/30 transition-colors duration-300", children: [
|
|
7390
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-sm font-semibold text-foreground mb-3", children: "Publisher" }),
|
|
7391
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
7392
|
+
publisher.logoUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: publisher.logoUrl, alt: publisher.name, className: "w-10 h-10 rounded-full object-cover" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center text-primary text-sm font-bold", children: publisher.name.charAt(0).toUpperCase() }),
|
|
7393
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
7394
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
7395
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground text-sm", children: publisher.name }),
|
|
7396
|
+
publisher.isVerified && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-primary font-medium", children: "\u2713 Verified" })
|
|
7397
|
+
] }),
|
|
7398
|
+
publisher.bio && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mt-0.5 line-clamp-2", children: publisher.bio })
|
|
7399
|
+
] })
|
|
7400
|
+
] })
|
|
7401
|
+
] }),
|
|
7402
|
+
(reviews?.length ?? 0) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sd-fu sd-d5 mb-8", children: [
|
|
7403
|
+
/* @__PURE__ */ jsxRuntime.jsxs("h2", { className: "text-lg font-bold text-foreground mb-4", children: [
|
|
7404
|
+
"Reviews (",
|
|
7405
|
+
reviewsCount ?? reviews.length,
|
|
7406
|
+
")"
|
|
7407
|
+
] }),
|
|
7408
|
+
ratingDistribution && totalRatings > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sd-si flex gap-6 mb-5 p-4 rounded-xl border border-border bg-card", children: [
|
|
7409
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center", children: [
|
|
7410
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-4xl font-bold text-foreground tabular-nums", children: product.rating?.toFixed(1) ?? "\u2014" }),
|
|
7411
|
+
product.rating != null && /* @__PURE__ */ jsxRuntime.jsx(StarRating, { rating: product.rating }),
|
|
7412
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground mt-1", children: [
|
|
7413
|
+
totalRatings,
|
|
7414
|
+
" ratings"
|
|
7415
|
+
] })
|
|
7416
|
+
] }),
|
|
7417
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-1.5 pt-1", children: [
|
|
7418
|
+
/* @__PURE__ */ jsxRuntime.jsx(RatingBar, { label: "5 \u2605", count: ratingDistribution.fiveStars, total: totalRatings }),
|
|
7419
|
+
/* @__PURE__ */ jsxRuntime.jsx(RatingBar, { label: "4 \u2605", count: ratingDistribution.fourStars, total: totalRatings }),
|
|
7420
|
+
/* @__PURE__ */ jsxRuntime.jsx(RatingBar, { label: "3 \u2605", count: ratingDistribution.threeStars, total: totalRatings }),
|
|
7421
|
+
/* @__PURE__ */ jsxRuntime.jsx(RatingBar, { label: "2 \u2605", count: ratingDistribution.twoStars, total: totalRatings }),
|
|
7422
|
+
/* @__PURE__ */ jsxRuntime.jsx(RatingBar, { label: "1 \u2605", count: ratingDistribution.oneStar, total: totalRatings })
|
|
7423
|
+
] })
|
|
7424
|
+
] }),
|
|
7425
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: reviews.slice(0, 5).map((review, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7426
|
+
"div",
|
|
7427
|
+
{
|
|
7428
|
+
className: "sd-fu p-4 rounded-xl border border-border bg-card hover:border-primary/20 transition-colors duration-200",
|
|
7429
|
+
style: { animationDelay: `${(idx + 5) * 60}ms` },
|
|
7430
|
+
children: [
|
|
7431
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 mb-2", children: [
|
|
7432
|
+
/* @__PURE__ */ jsxRuntime.jsx(StarRating, { rating: review.rating }),
|
|
7433
|
+
review.verifiedPurchase && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-emerald-500 font-medium", children: "Verified" })
|
|
7434
|
+
] }),
|
|
7435
|
+
review.title && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-sm text-foreground mb-1", children: review.title }),
|
|
7436
|
+
review.comment && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground leading-relaxed", children: review.comment }),
|
|
7437
|
+
review.createdAt && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mt-2", children: new Date(review.createdAt).toLocaleDateString("en-US", {
|
|
7438
|
+
year: "numeric",
|
|
7439
|
+
month: "short",
|
|
7440
|
+
day: "numeric"
|
|
7441
|
+
}) })
|
|
7442
|
+
]
|
|
7443
|
+
},
|
|
7444
|
+
review.id
|
|
7445
|
+
)) })
|
|
7446
|
+
] }),
|
|
7447
|
+
(relatedProducts?.length ?? 0) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sd-fu sd-d6", children: [
|
|
7448
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-bold text-foreground mb-4", children: "Related" }),
|
|
7449
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4", children: relatedProducts.slice(0, 6).map((p) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
7450
|
+
ProductCard,
|
|
7451
|
+
{
|
|
7452
|
+
product: p,
|
|
7453
|
+
onClick: () => navigate(`/store/${p.slug}`)
|
|
7454
|
+
},
|
|
7455
|
+
p.id
|
|
7456
|
+
)) })
|
|
7457
|
+
] })
|
|
7458
|
+
] }),
|
|
7459
|
+
/* @__PURE__ */ jsxRuntime.jsx("aside", { className: "lg:sticky lg:top-24 self-start", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sd-fu sd-d4 bg-card border border-border rounded-xl p-5 space-y-4 hover:border-primary/30 transition-colors duration-300 hover:shadow-lg hover:shadow-primary/5", children: [
|
|
7460
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
7461
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `text-3xl font-extrabold ${priceLabel === "Free" ? "text-emerald-500" : "text-foreground"}`, children: priceLabel }),
|
|
7462
|
+
product.pricingModel === "SUBSCRIPTION" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground", children: "per month" })
|
|
7463
|
+
] }),
|
|
7464
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7465
|
+
"a",
|
|
7466
|
+
{
|
|
7467
|
+
href: appLoginUrl,
|
|
7468
|
+
target: "_blank",
|
|
7469
|
+
rel: "noopener noreferrer",
|
|
7470
|
+
className: "flex items-center justify-center w-full h-11 rounded-lg bg-primary text-primary-foreground text-sm font-semibold hover:opacity-90 active:scale-[0.98] transition-all duration-150",
|
|
7471
|
+
children: priceLabel === "Free" ? "Install Free" : `Get for ${priceLabel}`
|
|
7472
|
+
}
|
|
7473
|
+
),
|
|
7474
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground text-center", children: "Login required to install" }),
|
|
7475
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-border pt-4 space-y-2 text-xs text-muted-foreground", children: [
|
|
7476
|
+
product.type && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
|
|
7477
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Type" }),
|
|
7478
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground font-medium", children: product.type })
|
|
7479
|
+
] }),
|
|
7480
|
+
product.category && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
|
|
7481
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Category" }),
|
|
7482
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground font-medium", children: product.category })
|
|
7483
|
+
] }),
|
|
7484
|
+
product.license && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
|
|
7485
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "License" }),
|
|
7486
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground font-medium", children: product.license })
|
|
7487
|
+
] }),
|
|
7488
|
+
product.minPlatformVersion && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
|
|
7489
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Requires" }),
|
|
7490
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-foreground font-medium", children: [
|
|
7491
|
+
"v",
|
|
7492
|
+
product.minPlatformVersion,
|
|
7493
|
+
"+"
|
|
7494
|
+
] })
|
|
7495
|
+
] }),
|
|
7496
|
+
product.downloads != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between", children: [
|
|
7497
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Downloads" }),
|
|
7498
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground font-medium", children: formatDownloads(product.downloads) })
|
|
7499
|
+
] })
|
|
7500
|
+
] }),
|
|
7501
|
+
(product.tags?.length ?? 0) > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1.5 pt-1", children: product.tags.map((tag) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
7502
|
+
"span",
|
|
7503
|
+
{
|
|
7504
|
+
className: "text-xs px-2 py-0.5 rounded-full bg-primary/10 text-primary font-medium",
|
|
7505
|
+
children: tag
|
|
7506
|
+
},
|
|
7507
|
+
tag
|
|
7508
|
+
)) })
|
|
7509
|
+
] }) })
|
|
7510
|
+
] }) })
|
|
7511
|
+
] });
|
|
7512
|
+
}
|
|
6227
7513
|
|
|
6228
7514
|
// src/data/products.ts
|
|
6229
7515
|
var ECOSYSTEM_PRODUCTS = [
|
|
@@ -6423,12 +7709,18 @@ exports.PressKitPage = PressKitPage;
|
|
|
6423
7709
|
exports.PricingPage = PricingPage;
|
|
6424
7710
|
exports.PricingSection = PricingSection;
|
|
6425
7711
|
exports.ProblemsSolvedSection = ProblemsSolvedSection;
|
|
7712
|
+
exports.ProductCard = ProductCard;
|
|
6426
7713
|
exports.ProductProvider = ProductProvider;
|
|
6427
7714
|
exports.ResourceLinks = ResourceLinks;
|
|
6428
7715
|
exports.RybbitAnalytics = RybbitAnalytics;
|
|
6429
7716
|
exports.Select = Select;
|
|
6430
7717
|
exports.SocialLinks = SocialLinks;
|
|
7718
|
+
exports.StarRating = StarRating;
|
|
7719
|
+
exports.StoreBrowsePage = StoreBrowsePage;
|
|
7720
|
+
exports.StoreHomePage = StoreHomePage;
|
|
7721
|
+
exports.StoreProductDetailPage = StoreProductDetailPage;
|
|
6431
7722
|
exports.Textarea = Textarea;
|
|
7723
|
+
exports.TypeBadge = TypeBadge;
|
|
6432
7724
|
exports.UnsubscribePage = UnsubscribePage;
|
|
6433
7725
|
exports.WaitlistForm = WaitlistForm;
|
|
6434
7726
|
exports.WaitlistPage = WaitlistPage;
|
|
@@ -6438,6 +7730,8 @@ exports.WebsiteSwitcher = WebsiteSwitcher;
|
|
|
6438
7730
|
exports.buttonVariants = buttonVariants;
|
|
6439
7731
|
exports.cn = cn;
|
|
6440
7732
|
exports.detectElectronPlatform = detectElectronPlatform;
|
|
7733
|
+
exports.formatDownloads = formatDownloads;
|
|
7734
|
+
exports.formatPrice = formatPrice2;
|
|
6441
7735
|
exports.useContentPage = useContentPage;
|
|
6442
7736
|
exports.useContentPages = useContentPages;
|
|
6443
7737
|
exports.useProduct = useProduct;
|