@fluid-app/portal-sdk 0.1.206 → 0.1.207
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/{FluidProvider-kEtG78-R.mjs → FluidProvider-5TV1VHtq.mjs} +2 -2
- package/dist/{FluidProvider-kEtG78-R.mjs.map → FluidProvider-5TV1VHtq.mjs.map} +1 -1
- package/dist/{FluidProvider-DgZSqdB4.cjs → FluidProvider-DP-sbNiR.cjs} +2 -2
- package/dist/{FluidProvider-DgZSqdB4.cjs.map → FluidProvider-DP-sbNiR.cjs.map} +1 -1
- package/dist/{MessagingScreen-B5F4cJL9.mjs → MessagingScreen-BSksI6Nw.mjs} +2 -2
- package/dist/{MessagingScreen-B5F4cJL9.mjs.map → MessagingScreen-BSksI6Nw.mjs.map} +1 -1
- package/dist/{MessagingScreen-BZNsf1M6.cjs → MessagingScreen-CXAzx8Ra.cjs} +2 -2
- package/dist/{MessagingScreen-Rr8rNnDM.cjs → MessagingScreen-D2G4zfez.cjs} +2 -2
- package/dist/{MessagingScreen-Rr8rNnDM.cjs.map → MessagingScreen-D2G4zfez.cjs.map} +1 -1
- package/dist/{OrdersScreen-Vcd072vf.cjs → OrdersScreen-CGvcgmLz.cjs} +1 -1
- package/dist/{OrdersScreen-CpU_Y_qI.cjs → OrdersScreen-Cx7xpzDk.cjs} +2 -2
- package/dist/{OrdersScreen-CpU_Y_qI.cjs.map → OrdersScreen-Cx7xpzDk.cjs.map} +1 -1
- package/dist/{OrdersScreen-jvCpiDDt.mjs → OrdersScreen-D4pe5mLs.mjs} +2 -2
- package/dist/{OrdersScreen-jvCpiDDt.mjs.map → OrdersScreen-D4pe5mLs.mjs.map} +1 -1
- package/dist/{PortalContentApiProvider-DqAbDYgq.cjs → PortalContentApiProvider-C5WzWC3k.cjs} +671 -765
- package/dist/PortalContentApiProvider-C5WzWC3k.cjs.map +1 -0
- package/dist/{PortalContentApiProvider-DxCHKK04.mjs → PortalContentApiProvider-CAa1jYwz.mjs} +671 -765
- package/dist/PortalContentApiProvider-CAa1jYwz.mjs.map +1 -0
- package/dist/{PortalProductsApiProvider-DaQUq6vq.cjs → PortalProductsApiProvider-Ca1oeTtJ.cjs} +2 -2
- package/dist/{PortalProductsApiProvider-DaQUq6vq.cjs.map → PortalProductsApiProvider-Ca1oeTtJ.cjs.map} +1 -1
- package/dist/{PortalProductsApiProvider-Y_4IQZBP.mjs → PortalProductsApiProvider-DHni3Y1V.mjs} +2 -2
- package/dist/{PortalProductsApiProvider-Y_4IQZBP.mjs.map → PortalProductsApiProvider-DHni3Y1V.mjs.map} +1 -1
- package/dist/{ProductsScreen-BQ4pOdSM.cjs → ProductsScreen-BZG_hkqN.cjs} +3 -3
- package/dist/{ProductsScreen-BQ4pOdSM.cjs.map → ProductsScreen-BZG_hkqN.cjs.map} +1 -1
- package/dist/{ProductsScreen-BXVezV86.mjs → ProductsScreen-DNXJ6Pml.mjs} +3 -3
- package/dist/{ProductsScreen-BXVezV86.mjs.map → ProductsScreen-DNXJ6Pml.mjs.map} +1 -1
- package/dist/{ProductsScreen-CwuS5xwA.cjs → ProductsScreen-DfKQAJ8t.cjs} +3 -3
- package/dist/{ProductsScreen-BuYB8ARn.mjs → ProductsScreen-dbTX6T_M.mjs} +3 -3
- package/dist/{ProfileScreen-BXyMS54d.cjs → ProfileScreen-CBwwNrKI.cjs} +2 -2
- package/dist/{ProfileScreen-AEC-nP75.mjs → ProfileScreen-Mb6dPLPo.mjs} +2 -2
- package/dist/{ProfileScreen-AEC-nP75.mjs.map → ProfileScreen-Mb6dPLPo.mjs.map} +1 -1
- package/dist/{ProfileScreen-BwB62fMh.cjs → ProfileScreen-Xym_39QW.cjs} +2 -2
- package/dist/{ProfileScreen-BwB62fMh.cjs.map → ProfileScreen-Xym_39QW.cjs.map} +1 -1
- package/dist/{ShareablesScreen-iI_TDe30.cjs → ShareablesScreen-B-q3ovAv.cjs} +3 -3
- package/dist/{ShareablesScreen-BncSEvDU.mjs → ShareablesScreen-Be0YXQ2y.mjs} +3 -3
- package/dist/{ShareablesScreen-BncSEvDU.mjs.map → ShareablesScreen-Be0YXQ2y.mjs.map} +1 -1
- package/dist/{ShareablesScreen-BRLq4OJS.mjs → ShareablesScreen-CpFuhYs5.mjs} +3 -3
- package/dist/{ShareablesScreen-DooJX53H.cjs → ShareablesScreen-vk_JZ-_9.cjs} +3 -3
- package/dist/{ShareablesScreen-DooJX53H.cjs.map → ShareablesScreen-vk_JZ-_9.cjs.map} +1 -1
- package/dist/{ShopScreen-B-D-upOl.cjs → ShopScreen-B92DRQkQ.cjs} +3 -3
- package/dist/{ShopScreen-B-D-upOl.cjs.map → ShopScreen-B92DRQkQ.cjs.map} +1 -1
- package/dist/{ShopScreen-Ja1W8IMs.mjs → ShopScreen-BOd8LD3L.mjs} +3 -3
- package/dist/{ShopScreen-Ja1W8IMs.mjs.map → ShopScreen-BOd8LD3L.mjs.map} +1 -1
- package/dist/{ShopScreen-CzPTkvqY.cjs → ShopScreen-BRN3JY4l.cjs} +3 -3
- package/dist/{SubscriptionsScreen-e2lCfnL0.cjs → SubscriptionsScreen-CQQPtSbM.cjs} +1 -1
- package/dist/{SubscriptionsScreen-COOAJ8r5.mjs → SubscriptionsScreen-CuP9OfBI.mjs} +94 -11
- package/dist/SubscriptionsScreen-CuP9OfBI.mjs.map +1 -0
- package/dist/{SubscriptionsScreen-Cx6u1tDv.cjs → SubscriptionsScreen-YUtsF_Eq.cjs} +92 -9
- package/dist/SubscriptionsScreen-YUtsF_Eq.cjs.map +1 -0
- package/dist/index.cjs +24 -24
- package/dist/index.mjs +24 -24
- package/dist/{portal_tenant-VLrtyCZ3.mjs → portal_tenant-Mu12SQA1.mjs} +2 -2
- package/dist/portal_tenant-Mu12SQA1.mjs.map +1 -0
- package/dist/{portal_tenant-DMF89PmN.cjs → portal_tenant-dfv03Fyi.cjs} +2 -2
- package/dist/portal_tenant-dfv03Fyi.cjs.map +1 -0
- package/package.json +13 -13
- package/dist/PortalContentApiProvider-DqAbDYgq.cjs.map +0 -1
- package/dist/PortalContentApiProvider-DxCHKK04.mjs.map +0 -1
- package/dist/SubscriptionsScreen-COOAJ8r5.mjs.map +0 -1
- package/dist/SubscriptionsScreen-Cx6u1tDv.cjs.map +0 -1
- package/dist/portal_tenant-DMF89PmN.cjs.map +0 -1
- package/dist/portal_tenant-VLrtyCZ3.mjs.map +0 -1
package/dist/{PortalContentApiProvider-DqAbDYgq.cjs → PortalContentApiProvider-C5WzWC3k.cjs}
RENAMED
|
@@ -8,7 +8,7 @@ const require_es = require("./es-DHLLltoR.cjs");
|
|
|
8
8
|
const require_SearchSort = require("./SearchSort-ztRXlRwu.cjs");
|
|
9
9
|
const require_dist$4 = require("./dist-DDZMFlal.cjs");
|
|
10
10
|
const require_dist$5 = require("./dist-DWs3-WOI.cjs");
|
|
11
|
-
const require_PortalProductsApiProvider = require("./PortalProductsApiProvider-
|
|
11
|
+
const require_PortalProductsApiProvider = require("./PortalProductsApiProvider-Ca1oeTtJ.cjs");
|
|
12
12
|
let react = require("react");
|
|
13
13
|
react = require_chunk.__toESM(react);
|
|
14
14
|
let _tanstack_react_query = require("@tanstack/react-query");
|
|
@@ -510,9 +510,76 @@ function ShareProductCard({ product, mediaCount }) {
|
|
|
510
510
|
});
|
|
511
511
|
}
|
|
512
512
|
//#endregion
|
|
513
|
+
//#region ../../shareables/ui/src/components/shared/ShareableListLayout.tsx
|
|
514
|
+
/**
|
|
515
|
+
* Grid column class shared by all shareable listing screens (products, media,
|
|
516
|
+
* playlists, files). Exposed so the list-content slot can reuse it directly.
|
|
517
|
+
*/
|
|
518
|
+
const SHAREABLE_GRID_CLASS = "grid grid-cols-1 gap-8 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-4";
|
|
519
|
+
/**
|
|
520
|
+
* Standard page chrome for shareable listing screens. Provides:
|
|
521
|
+
*
|
|
522
|
+
* - Page-level padding (matching all existing listing screens).
|
|
523
|
+
* - Loading skeleton (filter bar + grid of 8 card placeholders).
|
|
524
|
+
* - Inline error rendering.
|
|
525
|
+
* - Empty state rendering.
|
|
526
|
+
* - Optional filter/footer/sentinel slots.
|
|
527
|
+
*
|
|
528
|
+
* Domain-specific UI (cards, rows, filter controls) is slotted in via
|
|
529
|
+
* `filters` and `children`. This component does NOT own data fetching or
|
|
530
|
+
* any state — callers pass in the derived flags.
|
|
531
|
+
*/
|
|
532
|
+
function ShareableListLayout({ filters, children, isLoading, error, errorMessage = "Failed to load. Please try again.", isEmpty, emptyMessage, footer, loadingFilterShape = "search", sentinelRef }) {
|
|
533
|
+
if (isLoading) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
534
|
+
className: "space-y-6 px-4 py-4 md:px-10 md:py-6",
|
|
535
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
536
|
+
className: "flex items-center gap-3",
|
|
537
|
+
children: [
|
|
538
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Skeleton, { className: "h-10 flex-1" }),
|
|
539
|
+
loadingFilterShape === "search-view" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Skeleton, { className: "h-10 w-10" }),
|
|
540
|
+
loadingFilterShape === "search-action" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Skeleton, { className: "h-10 w-24" })
|
|
541
|
+
]
|
|
542
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
543
|
+
className: SHAREABLE_GRID_CLASS,
|
|
544
|
+
children: Array.from({ length: 8 }).map((_, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
545
|
+
className: "space-y-2",
|
|
546
|
+
children: [
|
|
547
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Skeleton, { className: "aspect-square w-full rounded-lg" }),
|
|
548
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Skeleton, { className: "h-4 w-3/4" }),
|
|
549
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Skeleton, { className: "h-3 w-1/2" })
|
|
550
|
+
]
|
|
551
|
+
}, i))
|
|
552
|
+
})]
|
|
553
|
+
});
|
|
554
|
+
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
555
|
+
className: "flex flex-col items-center justify-center py-16",
|
|
556
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
557
|
+
className: "text-destructive text-sm",
|
|
558
|
+
children: errorMessage
|
|
559
|
+
})
|
|
560
|
+
});
|
|
561
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
562
|
+
className: "space-y-6 px-4 py-4 md:px-10 md:py-6",
|
|
563
|
+
children: [
|
|
564
|
+
filters,
|
|
565
|
+
isEmpty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
566
|
+
className: "flex flex-col items-center justify-center py-16",
|
|
567
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
568
|
+
className: "text-muted-foreground text-sm",
|
|
569
|
+
children: emptyMessage
|
|
570
|
+
})
|
|
571
|
+
}) : children,
|
|
572
|
+
footer,
|
|
573
|
+
sentinelRef && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
574
|
+
ref: sentinelRef,
|
|
575
|
+
className: "h-1"
|
|
576
|
+
})
|
|
577
|
+
]
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
//#endregion
|
|
513
581
|
//#region ../../shareables/ui/src/components/screens/ProductsScreen.tsx
|
|
514
582
|
const PAGE_SIZE$4 = 24;
|
|
515
|
-
const GRID_CLASS$3 = "grid grid-cols-1 gap-8 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-4";
|
|
516
583
|
const SORT_OPTIONS$1 = [
|
|
517
584
|
{
|
|
518
585
|
label: "Newest",
|
|
@@ -632,73 +699,42 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
|
|
|
632
699
|
media_count: void 0
|
|
633
700
|
})) ?? [];
|
|
634
701
|
}, [data, usePortal]);
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
653
|
-
className: "flex flex-col items-center justify-center py-16",
|
|
654
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
655
|
-
className: "text-destructive text-sm",
|
|
656
|
-
children: "Failed to load products. Please try again."
|
|
657
|
-
})
|
|
658
|
-
});
|
|
659
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
660
|
-
className: "space-y-6 px-4 py-4 md:px-10 md:py-6",
|
|
661
|
-
children: [
|
|
662
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
663
|
-
className: "flex justify-end",
|
|
664
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
665
|
-
className: "w-full max-w-sm",
|
|
666
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SearchSort.SearchSort, {
|
|
667
|
-
searchValue: searchTerm,
|
|
668
|
-
onSearchChange: setSearchTerm,
|
|
669
|
-
placeholder: "Search products...",
|
|
670
|
-
sortOptions: SORT_OPTIONS$1,
|
|
671
|
-
sortValue,
|
|
672
|
-
onSortChange: setSortValue
|
|
673
|
-
})
|
|
674
|
-
})
|
|
675
|
-
}),
|
|
676
|
-
products.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
677
|
-
className: "flex flex-col items-center justify-center py-16",
|
|
678
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
679
|
-
className: "text-muted-foreground text-sm",
|
|
680
|
-
children: debouncedSearch ? "No products match your search." : "No products available."
|
|
702
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareableListLayout, {
|
|
703
|
+
isLoading,
|
|
704
|
+
error,
|
|
705
|
+
errorMessage: "Failed to load products. Please try again.",
|
|
706
|
+
isEmpty: products.length === 0,
|
|
707
|
+
emptyMessage: debouncedSearch ? "No products match your search." : "No products available.",
|
|
708
|
+
filters: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
709
|
+
className: "flex justify-end",
|
|
710
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
711
|
+
className: "w-full max-w-sm",
|
|
712
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SearchSort.SearchSort, {
|
|
713
|
+
searchValue: searchTerm,
|
|
714
|
+
onSearchChange: setSearchTerm,
|
|
715
|
+
placeholder: "Search products...",
|
|
716
|
+
sortOptions: SORT_OPTIONS$1,
|
|
717
|
+
sortValue,
|
|
718
|
+
onSortChange: setSortValue
|
|
681
719
|
})
|
|
682
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
683
|
-
className: GRID_CLASS$3,
|
|
684
|
-
children: products.map((product) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareProductCard, {
|
|
685
|
-
product: {
|
|
686
|
-
id: product.id,
|
|
687
|
-
title: product.title,
|
|
688
|
-
image_url: product.image_url
|
|
689
|
-
},
|
|
690
|
-
mediaCount: product.media_count
|
|
691
|
-
}, product.id))
|
|
692
|
-
}),
|
|
693
|
-
isFetchingNextPage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
694
|
-
className: "flex justify-center py-4",
|
|
695
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "border-primary h-6 w-6 animate-spin rounded-full border-2 border-t-transparent" })
|
|
696
|
-
}),
|
|
697
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
698
|
-
ref: observerTarget,
|
|
699
|
-
className: "h-1"
|
|
700
720
|
})
|
|
701
|
-
|
|
721
|
+
}),
|
|
722
|
+
footer: isFetchingNextPage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
723
|
+
className: "flex justify-center py-4",
|
|
724
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "border-primary h-6 w-6 animate-spin rounded-full border-2 border-t-transparent" })
|
|
725
|
+
}),
|
|
726
|
+
sentinelRef: observerTarget,
|
|
727
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
728
|
+
className: SHAREABLE_GRID_CLASS,
|
|
729
|
+
children: products.map((product) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareProductCard, {
|
|
730
|
+
product: {
|
|
731
|
+
id: product.id,
|
|
732
|
+
title: product.title,
|
|
733
|
+
image_url: product.image_url
|
|
734
|
+
},
|
|
735
|
+
mediaCount: product.media_count
|
|
736
|
+
}, product.id))
|
|
737
|
+
})
|
|
702
738
|
});
|
|
703
739
|
}
|
|
704
740
|
//#endregion
|
|
@@ -1217,13 +1253,85 @@ function MarketingAssetsGrid({ isLoading, error, activeTab, onTabChange, mediaIt
|
|
|
1217
1253
|
}
|
|
1218
1254
|
var MarketingAssetsGrid_default = react.default.memo(MarketingAssetsGrid);
|
|
1219
1255
|
//#endregion
|
|
1256
|
+
//#region ../../shareables/ui/src/components/shared/ShareableDetailLayout.tsx
|
|
1257
|
+
/**
|
|
1258
|
+
* Standard page chrome for shareable detail screens (product/media/playlist).
|
|
1259
|
+
* Provides the two-column hero + details layout, loading/not-found states,
|
|
1260
|
+
* title, and the read-more description block.
|
|
1261
|
+
*
|
|
1262
|
+
* Domain-specific chrome (breadcrumbs, header actions) is still wired up by
|
|
1263
|
+
* each screen via the shell header context — this layout purposefully does
|
|
1264
|
+
* NOT touch the shell header. Dialogs (delete confirmation, etc.) belong to
|
|
1265
|
+
* the caller and should be rendered as siblings to this component.
|
|
1266
|
+
*/
|
|
1267
|
+
function ShareableDetailLayout({ isLoading, notFound, notFoundMessage = "Not found or failed to load.", title, description, image, actions, meta, children, containerHeightClass = "md:h-[calc(100vh-140px)]" }) {
|
|
1268
|
+
if (isLoading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1269
|
+
className: "flex items-center justify-center py-16",
|
|
1270
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Spinner, { className: "size-8" })
|
|
1271
|
+
});
|
|
1272
|
+
if (notFound) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1273
|
+
className: "flex flex-col items-center justify-center py-16",
|
|
1274
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1275
|
+
className: "text-destructive text-sm",
|
|
1276
|
+
children: notFoundMessage
|
|
1277
|
+
})
|
|
1278
|
+
});
|
|
1279
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1280
|
+
className: "flex flex-col gap-4 px-4 py-4 md:px-10 md:py-6",
|
|
1281
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1282
|
+
className: `mx-auto flex w-full max-w-[480px] flex-col gap-6 md:max-w-none md:flex-row ${containerHeightClass}`,
|
|
1283
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1284
|
+
className: "aspect-square w-full md:aspect-auto md:h-full",
|
|
1285
|
+
children: image
|
|
1286
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1287
|
+
className: "flex w-full flex-col md:overflow-y-auto",
|
|
1288
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1289
|
+
className: "space-y-4",
|
|
1290
|
+
children: [
|
|
1291
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
|
|
1292
|
+
className: "text-foreground text-[26px] leading-[1.2] font-semibold break-words",
|
|
1293
|
+
children: title
|
|
1294
|
+
}),
|
|
1295
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareableDescription, { html: description }),
|
|
1296
|
+
meta,
|
|
1297
|
+
actions
|
|
1298
|
+
]
|
|
1299
|
+
}), children]
|
|
1300
|
+
})]
|
|
1301
|
+
})
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1304
|
+
/**
|
|
1305
|
+
* Read-more description block. Extracted so detail screens don't have to
|
|
1306
|
+
* reimplement the identical toggle + line-clamp logic. Pass the raw HTML
|
|
1307
|
+
* (e.g. mediaItem.description.body) — tags are stripped internally.
|
|
1308
|
+
*/
|
|
1309
|
+
function ShareableDescription({ html, threshold = 150 }) {
|
|
1310
|
+
const [isExpanded, setIsExpanded] = (0, react.useState)(false);
|
|
1311
|
+
const stripped = stripTags(html ?? "");
|
|
1312
|
+
if (!stripped) return null;
|
|
1313
|
+
const shouldShowReadMore = stripped.length > threshold;
|
|
1314
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1315
|
+
className: "text-foreground/70 text-sm leading-relaxed",
|
|
1316
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1317
|
+
className: !isExpanded && shouldShowReadMore ? "line-clamp-3" : "",
|
|
1318
|
+
children: stripped
|
|
1319
|
+
}), shouldShowReadMore && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Button, {
|
|
1320
|
+
onClick: () => setIsExpanded((prev) => !prev),
|
|
1321
|
+
variant: "ghost",
|
|
1322
|
+
size: "sm",
|
|
1323
|
+
className: "text-foreground hover:text-foreground/80 mt-1 h-auto p-0 text-xs font-normal underline",
|
|
1324
|
+
children: isExpanded ? "Read less" : "Read more"
|
|
1325
|
+
})]
|
|
1326
|
+
});
|
|
1327
|
+
}
|
|
1328
|
+
//#endregion
|
|
1220
1329
|
//#region ../../shareables/ui/src/components/screens/ProductDetailScreen.tsx
|
|
1221
1330
|
function ProductDetailScreen({ productId, countryCode, fetchProduct: fetchPortalProduct, onNavigate, onBack }) {
|
|
1222
1331
|
const api = useShareablesApi();
|
|
1223
1332
|
const client = useShareablesClient();
|
|
1224
1333
|
const { navigate } = useShareablesUI();
|
|
1225
1334
|
const [activeTab, setActiveTab] = (0, react.useState)("All");
|
|
1226
|
-
const [isDescriptionExpanded, setIsDescriptionExpanded] = (0, react.useState)(false);
|
|
1227
1335
|
const { data: portalProductResponse, isLoading: isLoadingPortalProduct } = (0, _tanstack_react_query.useQuery)({
|
|
1228
1336
|
queryKey: [
|
|
1229
1337
|
"portal-products",
|
|
@@ -1279,8 +1387,6 @@ function ProductDetailScreen({ productId, countryCode, fetchProduct: fetchPortal
|
|
|
1279
1387
|
onBack,
|
|
1280
1388
|
navigate
|
|
1281
1389
|
]));
|
|
1282
|
-
const strippedDescription = stripTags(displayDescription);
|
|
1283
|
-
const shouldShowReadMore = strippedDescription.length > 150;
|
|
1284
1390
|
const displayPrice = (() => {
|
|
1285
1391
|
if (legacyProduct?.display_price) return legacyProduct.display_price;
|
|
1286
1392
|
const price = portalProduct?.price ?? legacyProduct?.price;
|
|
@@ -1313,114 +1419,74 @@ function ProductDetailScreen({ productId, countryCode, fetchProduct: fetchPortal
|
|
|
1313
1419
|
const handleMediaItemClick = (0, react.useCallback)((mediaItem) => {
|
|
1314
1420
|
onNavigate?.("media", String(mediaItem.id));
|
|
1315
1421
|
}, [onNavigate]);
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
className: "
|
|
1324
|
-
children:
|
|
1325
|
-
|
|
1326
|
-
});
|
|
1327
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1328
|
-
className: "flex flex-col gap-4 px-4 py-4 md:px-10 md:py-6",
|
|
1329
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1330
|
-
className: "mx-auto flex w-full max-w-480 flex-col gap-6 md:h-[calc(100vh-140px)] md:flex-row",
|
|
1331
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1332
|
-
className: "aspect-square w-full md:aspect-auto md:h-full",
|
|
1333
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1334
|
-
className: "relative h-full overflow-hidden rounded-2xl",
|
|
1335
|
-
children: !productImage ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1336
|
-
className: "bg-muted flex h-full w-full flex-col items-center justify-center rounded-2xl",
|
|
1337
|
-
children: [
|
|
1338
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1339
|
-
className: "mb-2 text-gray-400",
|
|
1340
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Image, { className: "mx-auto h-12 w-12" })
|
|
1341
|
-
}),
|
|
1342
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1343
|
-
className: "mb-1 text-sm text-gray-500",
|
|
1344
|
-
children: "No Product Image"
|
|
1345
|
-
}),
|
|
1346
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1347
|
-
className: "text-xs text-gray-400",
|
|
1348
|
-
children: "This product does not have any associated media"
|
|
1349
|
-
})
|
|
1350
|
-
]
|
|
1351
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SharePageImageDisplay, {
|
|
1352
|
-
displayImage: productImage,
|
|
1353
|
-
displayTitle,
|
|
1354
|
-
isVideo: false,
|
|
1355
|
-
badgeLabel: "Product"
|
|
1356
|
-
})
|
|
1357
|
-
})
|
|
1358
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1359
|
-
className: "flex w-full flex-col md:overflow-y-auto",
|
|
1422
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ShareableDetailLayout, {
|
|
1423
|
+
isLoading: isLoadingProduct,
|
|
1424
|
+
notFound: !product,
|
|
1425
|
+
notFoundMessage: "Product not found or failed to load.",
|
|
1426
|
+
title: displayTitle,
|
|
1427
|
+
description: displayDescription,
|
|
1428
|
+
image: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1429
|
+
className: "relative h-full overflow-hidden rounded-2xl",
|
|
1430
|
+
children: !productImage ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1431
|
+
className: "bg-muted flex h-full w-full flex-col items-center justify-center rounded-2xl",
|
|
1360
1432
|
children: [
|
|
1361
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1362
|
-
className: "
|
|
1363
|
-
children:
|
|
1364
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
|
|
1365
|
-
className: "text-foreground text-[26px] leading-[1.2] font-semibold",
|
|
1366
|
-
children: displayTitle
|
|
1367
|
-
}),
|
|
1368
|
-
strippedDescription && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1369
|
-
className: "text-foreground/70 text-sm leading-relaxed",
|
|
1370
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1371
|
-
className: !isDescriptionExpanded && shouldShowReadMore ? "line-clamp-3" : "",
|
|
1372
|
-
children: strippedDescription
|
|
1373
|
-
}), shouldShowReadMore && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Button, {
|
|
1374
|
-
onClick: () => setIsDescriptionExpanded(!isDescriptionExpanded),
|
|
1375
|
-
variant: "ghost",
|
|
1376
|
-
size: "sm",
|
|
1377
|
-
className: "text-foreground hover:text-foreground/80 mt-1 h-auto p-0 text-xs font-normal underline",
|
|
1378
|
-
children: isDescriptionExpanded ? "Read less" : "Read more"
|
|
1379
|
-
})]
|
|
1380
|
-
}),
|
|
1381
|
-
displayPrice && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1382
|
-
className: "text-foreground flex items-center gap-2 text-sm",
|
|
1383
|
-
children: [
|
|
1384
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1385
|
-
className: "font-semibold",
|
|
1386
|
-
children: "Price"
|
|
1387
|
-
}),
|
|
1388
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "|" }),
|
|
1389
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1390
|
-
className: "font-semibold",
|
|
1391
|
-
children: displayPrice
|
|
1392
|
-
})
|
|
1393
|
-
]
|
|
1394
|
-
}),
|
|
1395
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssetActions, {
|
|
1396
|
-
downloadUrl: productImage || null,
|
|
1397
|
-
displayTitle,
|
|
1398
|
-
shareLink: shareLinkError ? null : shareLink || null,
|
|
1399
|
-
shareLinkLoading,
|
|
1400
|
-
isVideo: false,
|
|
1401
|
-
relateableId: Number(productId),
|
|
1402
|
-
relateableType: "Product"
|
|
1403
|
-
})
|
|
1404
|
-
]
|
|
1433
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1434
|
+
className: "mb-2 text-gray-400",
|
|
1435
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Image, { className: "mx-auto h-12 w-12" })
|
|
1405
1436
|
}),
|
|
1406
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Separator, { className: "border-foreground my-4" }),
|
|
1407
1437
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1408
|
-
className: "
|
|
1409
|
-
children:
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
mediaItems: filteredMediaItems,
|
|
1415
|
-
onMediaItemClick: handleMediaItemClick,
|
|
1416
|
-
showEmptyState: !hasMedia,
|
|
1417
|
-
activeMainTab: "Related Sharables",
|
|
1418
|
-
relateable_type: "Product"
|
|
1419
|
-
})
|
|
1438
|
+
className: "mb-1 text-sm text-gray-500",
|
|
1439
|
+
children: "No Product Image"
|
|
1440
|
+
}),
|
|
1441
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1442
|
+
className: "text-xs text-gray-400",
|
|
1443
|
+
children: "This product does not have any associated media"
|
|
1420
1444
|
})
|
|
1421
1445
|
]
|
|
1422
|
-
})
|
|
1423
|
-
|
|
1446
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SharePageImageDisplay, {
|
|
1447
|
+
displayImage: productImage,
|
|
1448
|
+
displayTitle,
|
|
1449
|
+
isVideo: false,
|
|
1450
|
+
badgeLabel: "Product"
|
|
1451
|
+
})
|
|
1452
|
+
}),
|
|
1453
|
+
meta: displayPrice ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1454
|
+
className: "text-foreground flex items-center gap-2 text-sm",
|
|
1455
|
+
children: [
|
|
1456
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1457
|
+
className: "font-semibold",
|
|
1458
|
+
children: "Price"
|
|
1459
|
+
}),
|
|
1460
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "|" }),
|
|
1461
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1462
|
+
className: "font-semibold",
|
|
1463
|
+
children: displayPrice
|
|
1464
|
+
})
|
|
1465
|
+
]
|
|
1466
|
+
}) : null,
|
|
1467
|
+
actions: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssetActions, {
|
|
1468
|
+
downloadUrl: productImage || null,
|
|
1469
|
+
displayTitle,
|
|
1470
|
+
shareLink: shareLinkError ? null : shareLink || null,
|
|
1471
|
+
shareLinkLoading,
|
|
1472
|
+
isVideo: false,
|
|
1473
|
+
relateableId: Number(productId),
|
|
1474
|
+
relateableType: "Product"
|
|
1475
|
+
}),
|
|
1476
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Separator, { className: "border-foreground my-4" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1477
|
+
className: "hide-scrollbar bg-background h-full overflow-y-auto rounded-lg",
|
|
1478
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MarketingAssetsGrid_default, {
|
|
1479
|
+
isLoading: isLoadingMedia,
|
|
1480
|
+
error: mediaError,
|
|
1481
|
+
activeTab,
|
|
1482
|
+
onTabChange: setActiveTab,
|
|
1483
|
+
mediaItems: filteredMediaItems,
|
|
1484
|
+
onMediaItemClick: handleMediaItemClick,
|
|
1485
|
+
showEmptyState: !hasMedia,
|
|
1486
|
+
activeMainTab: "Related Sharables",
|
|
1487
|
+
relateable_type: "Product"
|
|
1488
|
+
})
|
|
1489
|
+
})]
|
|
1424
1490
|
});
|
|
1425
1491
|
}
|
|
1426
1492
|
//#endregion
|
|
@@ -1455,7 +1521,6 @@ function OwnerFilterTabs({ value, onValueChange, myLabel = "Mine" }) {
|
|
|
1455
1521
|
//#endregion
|
|
1456
1522
|
//#region ../../shareables/ui/src/components/screens/MediaListingScreen.tsx
|
|
1457
1523
|
const PAGE_SIZE$3 = 24;
|
|
1458
|
-
const GRID_CLASS$2 = "grid grid-cols-1 gap-8 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-4";
|
|
1459
1524
|
function getMediaKindLabel(kind) {
|
|
1460
1525
|
switch (kind) {
|
|
1461
1526
|
case "video": return "Video";
|
|
@@ -1575,229 +1640,203 @@ function MediaListingScreen({ onNavigate }) {
|
|
|
1575
1640
|
const allItems = data?.media ?? [];
|
|
1576
1641
|
const ownerFiltered = ownerFilter === "all" ? allItems : ownerFilter === "my" ? allItems.filter((item) => item.owner_type === "user") : allItems.filter((item) => item.owner_type === "company");
|
|
1577
1642
|
const filteredItems = kindFilter === "all" ? ownerFiltered : ownerFiltered.filter((item) => kindBucket(item.kind) === kindFilter);
|
|
1578
|
-
|
|
1579
|
-
className: "
|
|
1580
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1603
|
-
className: "space-y-6 px-4 py-4 md:px-10 md:py-6",
|
|
1604
|
-
children: [
|
|
1605
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1606
|
-
className: "flex items-center gap-3",
|
|
1607
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(OwnerFilterTabs, {
|
|
1608
|
-
value: ownerFilter,
|
|
1609
|
-
onValueChange: setOwnerFilter,
|
|
1610
|
-
myLabel: "My Media"
|
|
1611
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1612
|
-
className: "ml-auto flex items-center gap-2",
|
|
1613
|
-
children: [
|
|
1614
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1615
|
-
className: "w-full max-w-sm",
|
|
1616
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SearchSort.SearchSort, {
|
|
1617
|
-
searchValue: searchTerm,
|
|
1618
|
-
onSearchChange: setSearchTerm,
|
|
1619
|
-
placeholder: "Search media...",
|
|
1620
|
-
sortOptions: [{
|
|
1621
|
-
label: "Name (A-Z)",
|
|
1622
|
-
value: "title_asc"
|
|
1623
|
-
}, {
|
|
1624
|
-
label: "Name (Z-A)",
|
|
1625
|
-
value: "title_desc"
|
|
1626
|
-
}],
|
|
1627
|
-
sortValue,
|
|
1628
|
-
onSortChange: setSortValue
|
|
1629
|
-
})
|
|
1630
|
-
}),
|
|
1631
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.DropdownMenu, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.DropdownMenuTrigger, {
|
|
1632
|
-
asChild: true,
|
|
1633
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.Button, {
|
|
1634
|
-
variant: "outline",
|
|
1635
|
-
"aria-label": `Filter: ${kindFilter === "all" ? "All types" : kindFilter}`,
|
|
1636
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Filter, { className: "size-4" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1637
|
-
className: "hidden sm:inline",
|
|
1638
|
-
children: kindFilter === "all" ? "All types" : kindFilter === "image" ? "Images" : kindFilter === "video" ? "Videos" : "PDFs"
|
|
1639
|
-
})]
|
|
1640
|
-
})
|
|
1641
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.DropdownMenuContent, {
|
|
1642
|
-
align: "end",
|
|
1643
|
-
children: [
|
|
1644
|
-
{
|
|
1645
|
-
label: "All types",
|
|
1646
|
-
value: "all"
|
|
1647
|
-
},
|
|
1648
|
-
{
|
|
1649
|
-
label: "Images",
|
|
1650
|
-
value: "image"
|
|
1651
|
-
},
|
|
1652
|
-
{
|
|
1653
|
-
label: "Videos",
|
|
1654
|
-
value: "video"
|
|
1655
|
-
},
|
|
1656
|
-
{
|
|
1657
|
-
label: "PDFs",
|
|
1658
|
-
value: "pdf"
|
|
1659
|
-
}
|
|
1660
|
-
].map((opt) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.DropdownMenuItem, {
|
|
1661
|
-
onClick: () => setKindFilter(opt.value),
|
|
1662
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1663
|
-
className: "flex-1",
|
|
1664
|
-
children: opt.label
|
|
1665
|
-
}), kindFilter === opt.value && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Check, { className: "text-muted-foreground size-4" })]
|
|
1666
|
-
}, opt.value))
|
|
1667
|
-
})] }),
|
|
1668
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1669
|
-
className: "border-input bg-muted flex items-center rounded-lg border p-0.5",
|
|
1670
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1671
|
-
type: "button",
|
|
1672
|
-
onClick: () => setViewMode("list"),
|
|
1673
|
-
className: `flex h-8 w-8 items-center justify-center rounded-md transition-all ${viewMode === "list" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
|
|
1674
|
-
title: "List view",
|
|
1675
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.List, { className: "h-4 w-4" })
|
|
1676
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1677
|
-
type: "button",
|
|
1678
|
-
onClick: () => setViewMode("grid"),
|
|
1679
|
-
className: `flex h-8 w-8 items-center justify-center rounded-md transition-all ${viewMode === "grid" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
|
|
1680
|
-
title: "Grid view",
|
|
1681
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.LayoutGrid, { className: "h-4 w-4" })
|
|
1682
|
-
})]
|
|
1683
|
-
})
|
|
1684
|
-
]
|
|
1685
|
-
})]
|
|
1686
|
-
}),
|
|
1687
|
-
filteredItems.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1688
|
-
className: "flex flex-col items-center justify-center py-16",
|
|
1689
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1690
|
-
className: "text-muted-foreground text-sm",
|
|
1691
|
-
children: getFilteredEmptyMessage({
|
|
1692
|
-
searchTerm: debouncedSearch,
|
|
1693
|
-
ownerFilter,
|
|
1694
|
-
hasOtherFilters: kindFilter !== "all",
|
|
1695
|
-
entityName: "media",
|
|
1696
|
-
defaultMessage: "No media available."
|
|
1643
|
+
const filterBar = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1644
|
+
className: "flex items-center gap-3",
|
|
1645
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(OwnerFilterTabs, {
|
|
1646
|
+
value: ownerFilter,
|
|
1647
|
+
onValueChange: setOwnerFilter,
|
|
1648
|
+
myLabel: "My Media"
|
|
1649
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1650
|
+
className: "ml-auto flex items-center gap-2",
|
|
1651
|
+
children: [
|
|
1652
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1653
|
+
className: "w-full max-w-sm",
|
|
1654
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SearchSort.SearchSort, {
|
|
1655
|
+
searchValue: searchTerm,
|
|
1656
|
+
onSearchChange: setSearchTerm,
|
|
1657
|
+
placeholder: "Search media...",
|
|
1658
|
+
sortOptions: [{
|
|
1659
|
+
label: "Name (A-Z)",
|
|
1660
|
+
value: "title_asc"
|
|
1661
|
+
}, {
|
|
1662
|
+
label: "Name (Z-A)",
|
|
1663
|
+
value: "title_desc"
|
|
1664
|
+
}],
|
|
1665
|
+
sortValue,
|
|
1666
|
+
onSortChange: setSortValue
|
|
1697
1667
|
})
|
|
1698
|
-
})
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
className: "
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
imageUrl: item.image_url,
|
|
1708
|
-
href: `media/${item.id}`,
|
|
1709
|
-
badge: { text: getMediaKindLabel(item.kind) },
|
|
1710
|
-
isVideo: item.kind === "video",
|
|
1711
|
-
subtitle: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1712
|
-
className: "flex items-center gap-1.5",
|
|
1713
|
-
children: [getMediaKindLabel(item.kind), item.owner_type === "user" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Badge, {
|
|
1714
|
-
variant: "secondary",
|
|
1715
|
-
className: "px-1.5 py-0 text-[10px] leading-4",
|
|
1716
|
-
children: "My Media"
|
|
1717
|
-
})]
|
|
1718
|
-
})
|
|
1719
|
-
}), canEdit && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1720
|
-
className: "absolute top-2 right-2",
|
|
1721
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MediaRowActionsMenu, { onDelete: () => setPendingDeleteId(item.id) })
|
|
1668
|
+
}),
|
|
1669
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.DropdownMenu, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.DropdownMenuTrigger, {
|
|
1670
|
+
asChild: true,
|
|
1671
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.Button, {
|
|
1672
|
+
variant: "outline",
|
|
1673
|
+
"aria-label": `Filter: ${kindFilter === "all" ? "All types" : kindFilter}`,
|
|
1674
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Filter, { className: "size-4" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1675
|
+
className: "hidden sm:inline",
|
|
1676
|
+
children: kindFilter === "all" ? "All types" : kindFilter === "image" ? "Images" : kindFilter === "video" ? "Videos" : "PDFs"
|
|
1722
1677
|
})]
|
|
1723
|
-
}
|
|
1724
|
-
})
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1678
|
+
})
|
|
1679
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.DropdownMenuContent, {
|
|
1680
|
+
align: "end",
|
|
1681
|
+
children: [
|
|
1682
|
+
{
|
|
1683
|
+
label: "All types",
|
|
1684
|
+
value: "all"
|
|
1685
|
+
},
|
|
1686
|
+
{
|
|
1687
|
+
label: "Images",
|
|
1688
|
+
value: "image"
|
|
1689
|
+
},
|
|
1690
|
+
{
|
|
1691
|
+
label: "Videos",
|
|
1692
|
+
value: "video"
|
|
1693
|
+
},
|
|
1694
|
+
{
|
|
1695
|
+
label: "PDFs",
|
|
1696
|
+
value: "pdf"
|
|
1697
|
+
}
|
|
1698
|
+
].map((opt) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.DropdownMenuItem, {
|
|
1699
|
+
onClick: () => setKindFilter(opt.value),
|
|
1700
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1701
|
+
className: "flex-1",
|
|
1702
|
+
children: opt.label
|
|
1703
|
+
}), kindFilter === opt.value && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Check, { className: "text-muted-foreground size-4" })]
|
|
1704
|
+
}, opt.value))
|
|
1705
|
+
})] }),
|
|
1706
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1707
|
+
className: "border-input bg-muted flex items-center rounded-lg border p-0.5",
|
|
1708
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1709
|
+
type: "button",
|
|
1710
|
+
onClick: () => setViewMode("list"),
|
|
1711
|
+
className: `flex h-8 w-8 items-center justify-center rounded-md transition-all ${viewMode === "list" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
|
|
1712
|
+
title: "List view",
|
|
1713
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.List, { className: "h-4 w-4" })
|
|
1714
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1715
|
+
type: "button",
|
|
1716
|
+
onClick: () => setViewMode("grid"),
|
|
1717
|
+
className: `flex h-8 w-8 items-center justify-center rounded-md transition-all ${viewMode === "grid" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
|
|
1718
|
+
title: "Grid view",
|
|
1719
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.LayoutGrid, { className: "h-4 w-4" })
|
|
1720
|
+
})]
|
|
1758
1721
|
})
|
|
1722
|
+
]
|
|
1723
|
+
})]
|
|
1724
|
+
});
|
|
1725
|
+
const paginationFooter = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1726
|
+
className: "flex items-center justify-center gap-4 pt-4",
|
|
1727
|
+
children: [
|
|
1728
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.Button, {
|
|
1729
|
+
variant: "outline",
|
|
1730
|
+
size: "sm",
|
|
1731
|
+
onClick: () => setPage((p) => p - 1),
|
|
1732
|
+
disabled: page === 1 || isFetching,
|
|
1733
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronLeft, { className: "h-4 w-4" }), "Previous"]
|
|
1759
1734
|
}),
|
|
1760
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.AlertDialogContent, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.AlertDialogHeader, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialogTitle, { children: "Delete this media?" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialogDescription, { children: "This removes the item from your media library. Shared links that point to it will stop working." })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.AlertDialogFooter, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialogCancel, {
|
|
1764
|
-
disabled: isDeleting,
|
|
1765
|
-
children: "Cancel"
|
|
1766
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialogAction, {
|
|
1767
|
-
onClick: (e) => {
|
|
1768
|
-
e.preventDefault();
|
|
1769
|
-
confirmDelete();
|
|
1770
|
-
},
|
|
1771
|
-
disabled: isDeleting,
|
|
1772
|
-
className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
1773
|
-
children: isDeleting ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Spinner, { className: "size-4" }) : "Delete"
|
|
1774
|
-
})] })] })
|
|
1735
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1736
|
+
className: "text-muted-foreground text-sm",
|
|
1737
|
+
children: ["Page ", page]
|
|
1775
1738
|
}),
|
|
1776
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1739
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.Button, {
|
|
1740
|
+
variant: "outline",
|
|
1741
|
+
size: "sm",
|
|
1742
|
+
onClick: () => setPage((p) => p + 1),
|
|
1743
|
+
disabled: !hasNextPage || isFetching,
|
|
1744
|
+
children: ["Next", /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronRight, { className: "h-4 w-4" })]
|
|
1745
|
+
})
|
|
1746
|
+
]
|
|
1747
|
+
});
|
|
1748
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareableListLayout, {
|
|
1749
|
+
isLoading,
|
|
1750
|
+
error,
|
|
1751
|
+
errorMessage: "Failed to load media. Please try again.",
|
|
1752
|
+
isEmpty: filteredItems.length === 0,
|
|
1753
|
+
emptyMessage: getFilteredEmptyMessage({
|
|
1754
|
+
searchTerm: debouncedSearch,
|
|
1755
|
+
ownerFilter,
|
|
1756
|
+
hasOtherFilters: kindFilter !== "all",
|
|
1757
|
+
entityName: "media",
|
|
1758
|
+
defaultMessage: "No media available."
|
|
1759
|
+
}),
|
|
1760
|
+
filters: filterBar,
|
|
1761
|
+
footer: paginationFooter,
|
|
1762
|
+
loadingFilterShape: "search-view",
|
|
1763
|
+
children: viewMode === "grid" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1764
|
+
className: SHAREABLE_GRID_CLASS,
|
|
1765
|
+
children: filteredItems.map((item) => {
|
|
1766
|
+
const canEdit = !readOnly && item.owner_type === "user";
|
|
1767
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1768
|
+
className: "relative",
|
|
1769
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareItemCard, {
|
|
1770
|
+
title: item.title ?? "",
|
|
1771
|
+
imageUrl: item.image_url,
|
|
1772
|
+
href: `media/${item.id}`,
|
|
1773
|
+
badge: { text: getMediaKindLabel(item.kind) },
|
|
1774
|
+
isVideo: item.kind === "video",
|
|
1775
|
+
subtitle: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1776
|
+
className: "flex items-center gap-1.5",
|
|
1777
|
+
children: [getMediaKindLabel(item.kind), item.owner_type === "user" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Badge, {
|
|
1778
|
+
variant: "secondary",
|
|
1779
|
+
className: "px-1.5 py-0 text-[10px] leading-4",
|
|
1780
|
+
children: "My Media"
|
|
1781
|
+
})]
|
|
1782
|
+
})
|
|
1783
|
+
}), canEdit && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1784
|
+
className: "absolute top-2 right-2",
|
|
1785
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MediaRowActionsMenu, { onDelete: () => setPendingDeleteId(item.id) })
|
|
1786
|
+
})]
|
|
1787
|
+
}, item.id);
|
|
1788
|
+
})
|
|
1789
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1790
|
+
className: "divide-border divide-y rounded-lg border",
|
|
1791
|
+
children: filteredItems.map((item) => {
|
|
1792
|
+
const canEdit = !readOnly && item.owner_type === "user";
|
|
1793
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1794
|
+
className: "hover:bg-muted flex items-center gap-4 px-4 py-3 transition-colors",
|
|
1795
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1796
|
+
type: "button",
|
|
1797
|
+
onClick: () => navigate(`media/${item.id}`),
|
|
1798
|
+
className: "flex min-w-0 flex-1 items-center gap-4 text-left",
|
|
1799
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1800
|
+
className: "bg-muted h-12 w-12 shrink-0 overflow-hidden rounded-md",
|
|
1801
|
+
children: item.image_url ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
1802
|
+
src: item.image_url,
|
|
1803
|
+
alt: item.title ?? "",
|
|
1804
|
+
className: "h-full w-full object-cover"
|
|
1805
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "bg-muted h-full w-full" })
|
|
1806
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1807
|
+
className: "min-w-0 flex-1",
|
|
1808
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1809
|
+
className: "text-foreground truncate text-sm font-medium",
|
|
1810
|
+
children: item.title ?? "Untitled"
|
|
1811
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
1812
|
+
className: "text-muted-foreground flex items-center gap-1.5 text-xs",
|
|
1813
|
+
children: [getMediaKindLabel(item.kind), item.owner_type === "user" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Badge, {
|
|
1814
|
+
variant: "secondary",
|
|
1815
|
+
className: "px-1.5 py-0 text-[10px] leading-4",
|
|
1816
|
+
children: "My Media"
|
|
1817
|
+
})]
|
|
1818
|
+
})]
|
|
1819
|
+
})]
|
|
1820
|
+
}), canEdit && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MediaRowActionsMenu, { onDelete: () => setPendingDeleteId(item.id) })]
|
|
1821
|
+
}, item.id);
|
|
1798
1822
|
})
|
|
1799
|
-
|
|
1800
|
-
})
|
|
1823
|
+
})
|
|
1824
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialog, {
|
|
1825
|
+
open: pendingDeleteId !== null,
|
|
1826
|
+
onOpenChange: (open) => !open && setPendingDeleteId(null),
|
|
1827
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.AlertDialogContent, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.AlertDialogHeader, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialogTitle, { children: "Delete this media?" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialogDescription, { children: "This removes the item from your media library. Shared links that point to it will stop working." })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.AlertDialogFooter, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialogCancel, {
|
|
1828
|
+
disabled: isDeleting,
|
|
1829
|
+
children: "Cancel"
|
|
1830
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialogAction, {
|
|
1831
|
+
onClick: (e) => {
|
|
1832
|
+
e.preventDefault();
|
|
1833
|
+
confirmDelete();
|
|
1834
|
+
},
|
|
1835
|
+
disabled: isDeleting,
|
|
1836
|
+
className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
1837
|
+
children: isDeleting ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Spinner, { className: "size-4" }) : "Delete"
|
|
1838
|
+
})] })] })
|
|
1839
|
+
})] });
|
|
1801
1840
|
}
|
|
1802
1841
|
//#endregion
|
|
1803
1842
|
//#region ../../shareables/ui/src/components/screens/MediaDetailScreen.tsx
|
|
@@ -1813,7 +1852,6 @@ function MediaDetailScreen({ mediaId, onNavigate: _onNavigate, onBack }) {
|
|
|
1813
1852
|
const api = useShareablesApi();
|
|
1814
1853
|
const repContext = useRepContext();
|
|
1815
1854
|
const { navigate, readOnly } = useShareablesUI();
|
|
1816
|
-
const [isDescriptionExpanded, setIsDescriptionExpanded] = (0, react.useState)(false);
|
|
1817
1855
|
const { data: mediaResponse, isLoading } = (0, _tanstack_react_query.useQuery)({
|
|
1818
1856
|
queryKey: shareablesKeys.media.detail(Number(mediaId), repContext),
|
|
1819
1857
|
queryFn: () => api.media.getMediaById(Number(mediaId))
|
|
@@ -1862,75 +1900,38 @@ function MediaDetailScreen({ mediaId, onNavigate: _onNavigate, onBack }) {
|
|
|
1862
1900
|
mediaId
|
|
1863
1901
|
]));
|
|
1864
1902
|
const badgeLabel = getBadgeLabel(mediaItem?.kind ?? null);
|
|
1865
|
-
const
|
|
1866
|
-
const shouldShowReadMore = strippedDescription.length > 150;
|
|
1903
|
+
const rawDescription = mediaItem?.description?.body || mediaItem?.stripped || "";
|
|
1867
1904
|
const downloadUrl = isVideo ? displayVideo : mediaItem?.pdf_url || displayImage;
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
displayImage,
|
|
1889
|
-
displayTitle,
|
|
1890
|
-
displayVideo: isVideo ? displayVideo : void 0,
|
|
1891
|
-
isVideo,
|
|
1892
|
-
badgeLabel,
|
|
1893
|
-
rounded: true,
|
|
1894
|
-
showBadge: false
|
|
1895
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1896
|
-
className: "bg-background/80 text-foreground absolute top-3 right-3 z-0 inline-flex h-8 items-center rounded-full px-3 text-xs font-medium shadow-md backdrop-blur-sm",
|
|
1897
|
-
children: badgeLabel
|
|
1898
|
-
})]
|
|
1899
|
-
})
|
|
1900
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1901
|
-
className: "flex w-full flex-col md:overflow-y-auto",
|
|
1902
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1903
|
-
className: "space-y-4",
|
|
1904
|
-
children: [
|
|
1905
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
|
|
1906
|
-
className: "text-foreground text-[26px] leading-[1.2] font-semibold break-words",
|
|
1907
|
-
children: displayTitle
|
|
1908
|
-
}),
|
|
1909
|
-
strippedDescription && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1910
|
-
className: "text-foreground/70 text-sm leading-relaxed",
|
|
1911
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1912
|
-
className: !isDescriptionExpanded && shouldShowReadMore ? "line-clamp-3" : "",
|
|
1913
|
-
children: strippedDescription
|
|
1914
|
-
}), shouldShowReadMore && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Button, {
|
|
1915
|
-
onClick: () => setIsDescriptionExpanded(!isDescriptionExpanded),
|
|
1916
|
-
variant: "ghost",
|
|
1917
|
-
size: "sm",
|
|
1918
|
-
className: "text-foreground hover:text-foreground/80 mt-1 h-auto p-0 text-xs font-normal underline",
|
|
1919
|
-
children: isDescriptionExpanded ? "Read less" : "Read more"
|
|
1920
|
-
})]
|
|
1921
|
-
}),
|
|
1922
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssetActions, {
|
|
1923
|
-
downloadUrl: downloadUrl || null,
|
|
1924
|
-
displayTitle,
|
|
1925
|
-
shareLink: shareLinkError ? null : shareLink || null,
|
|
1926
|
-
shareLinkLoading,
|
|
1927
|
-
isVideo,
|
|
1928
|
-
relateableId: Number(mediaId),
|
|
1929
|
-
relateableType: "Medium"
|
|
1930
|
-
})
|
|
1931
|
-
]
|
|
1932
|
-
})
|
|
1905
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareableDetailLayout, {
|
|
1906
|
+
isLoading,
|
|
1907
|
+
notFound: !mediaItem,
|
|
1908
|
+
notFoundMessage: "Media not found or failed to load.",
|
|
1909
|
+
title: displayTitle,
|
|
1910
|
+
description: rawDescription,
|
|
1911
|
+
containerHeightClass: "md:h-[calc(95vh-140px)]",
|
|
1912
|
+
image: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1913
|
+
className: "relative h-full overflow-hidden",
|
|
1914
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SharePageImageDisplay, {
|
|
1915
|
+
displayImage,
|
|
1916
|
+
displayTitle,
|
|
1917
|
+
displayVideo: isVideo ? displayVideo : void 0,
|
|
1918
|
+
isVideo,
|
|
1919
|
+
badgeLabel,
|
|
1920
|
+
rounded: true,
|
|
1921
|
+
showBadge: false
|
|
1922
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1923
|
+
className: "bg-background/80 text-foreground absolute top-3 right-3 z-0 inline-flex h-8 items-center rounded-full px-3 text-xs font-medium shadow-md backdrop-blur-sm",
|
|
1924
|
+
children: badgeLabel
|
|
1933
1925
|
})]
|
|
1926
|
+
}),
|
|
1927
|
+
actions: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssetActions, {
|
|
1928
|
+
downloadUrl: downloadUrl || null,
|
|
1929
|
+
displayTitle,
|
|
1930
|
+
shareLink: shareLinkError ? null : shareLink || null,
|
|
1931
|
+
shareLinkLoading,
|
|
1932
|
+
isVideo,
|
|
1933
|
+
relateableId: Number(mediaId),
|
|
1934
|
+
relateableType: "Medium"
|
|
1934
1935
|
})
|
|
1935
1936
|
});
|
|
1936
1937
|
}
|
|
@@ -8917,7 +8918,7 @@ function BulkSelectionBar({ selectedCount, totalCount, onSelectAll, onClearSelec
|
|
|
8917
8918
|
//#endregion
|
|
8918
8919
|
//#region ../../shareables/ui/src/components/screens/PlaylistsListingScreen.tsx
|
|
8919
8920
|
const PAGE_SIZE$1 = 12;
|
|
8920
|
-
const GRID_CLASS
|
|
8921
|
+
const GRID_CLASS = "grid grid-cols-1 gap-8 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4";
|
|
8921
8922
|
function PlaylistsListingScreen(_props) {
|
|
8922
8923
|
const api = useShareablesApi();
|
|
8923
8924
|
const { navigate, showToast, user, onToggleFavorite, onDeletePlaylist, readOnly } = useShareablesUI();
|
|
@@ -9096,129 +9097,108 @@ function PlaylistsListingScreen(_props) {
|
|
|
9096
9097
|
const confirmDelete = (0, react.useCallback)(() => {
|
|
9097
9098
|
if (pendingDeleteId != null) deletePlaylist(pendingDeleteId);
|
|
9098
9099
|
}, [pendingDeleteId, deletePlaylist]);
|
|
9099
|
-
|
|
9100
|
-
|
|
9101
|
-
|
|
9102
|
-
|
|
9103
|
-
|
|
9100
|
+
const filterBar = hasSelection ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BulkSelectionBar, {
|
|
9101
|
+
selectedCount: selectedIds.size,
|
|
9102
|
+
totalCount: filteredPlaylists.length,
|
|
9103
|
+
onSelectAll: handleSelectAll,
|
|
9104
|
+
onClearSelection: handleClearSelection,
|
|
9105
|
+
onBulkFavorite: handleBulkFavorite
|
|
9106
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9107
|
+
className: "flex items-center gap-3",
|
|
9108
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(OwnerFilterTabs, {
|
|
9109
|
+
value: ownerFilter,
|
|
9110
|
+
onValueChange: setOwnerFilter,
|
|
9111
|
+
myLabel: "My Playlists"
|
|
9104
9112
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9105
|
-
className:
|
|
9106
|
-
children:
|
|
9107
|
-
|
|
9108
|
-
|
|
9109
|
-
|
|
9110
|
-
|
|
9111
|
-
|
|
9112
|
-
|
|
9113
|
-
|
|
9114
|
-
children: [
|
|
9115
|
-
hasSelection ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BulkSelectionBar, {
|
|
9116
|
-
selectedCount: selectedIds.size,
|
|
9117
|
-
totalCount: filteredPlaylists.length,
|
|
9118
|
-
onSelectAll: handleSelectAll,
|
|
9119
|
-
onClearSelection: handleClearSelection,
|
|
9120
|
-
onBulkFavorite: handleBulkFavorite
|
|
9121
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9122
|
-
className: "flex items-center gap-3",
|
|
9123
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(OwnerFilterTabs, {
|
|
9124
|
-
value: ownerFilter,
|
|
9125
|
-
onValueChange: setOwnerFilter,
|
|
9126
|
-
myLabel: "My Playlists"
|
|
9127
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9128
|
-
className: "ml-auto w-full max-w-sm",
|
|
9129
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SearchSort.SearchSort, {
|
|
9130
|
-
searchValue: searchTerm,
|
|
9131
|
-
onSearchChange: setSearchTerm,
|
|
9132
|
-
placeholder: "Search playlists...",
|
|
9133
|
-
sortOptions: [
|
|
9134
|
-
{
|
|
9135
|
-
label: "Name (A-Z)",
|
|
9136
|
-
value: "title"
|
|
9137
|
-
},
|
|
9138
|
-
{
|
|
9139
|
-
label: "Name (Z-A)",
|
|
9140
|
-
value: "-title"
|
|
9141
|
-
},
|
|
9142
|
-
{
|
|
9143
|
-
label: "Date Created (Newest)",
|
|
9144
|
-
value: "-created_at"
|
|
9145
|
-
},
|
|
9146
|
-
{
|
|
9147
|
-
label: "Date Created (Oldest)",
|
|
9148
|
-
value: "created_at"
|
|
9149
|
-
}
|
|
9150
|
-
],
|
|
9151
|
-
sortValue,
|
|
9152
|
-
onSortChange: setSortValue
|
|
9153
|
-
})
|
|
9154
|
-
})]
|
|
9155
|
-
}),
|
|
9156
|
-
filteredPlaylists.length === 0 && !isFetchingNextPage && !hasNextPage ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9157
|
-
className: "flex flex-col items-center justify-center py-16",
|
|
9158
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
9159
|
-
className: "text-muted-foreground text-sm",
|
|
9160
|
-
children: getFilteredEmptyMessage({
|
|
9161
|
-
searchTerm,
|
|
9162
|
-
ownerFilter,
|
|
9163
|
-
entityName: "playlists",
|
|
9164
|
-
defaultMessage: "There are no playlists available at the moment."
|
|
9165
|
-
})
|
|
9166
|
-
})
|
|
9167
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9168
|
-
className: GRID_CLASS$1,
|
|
9169
|
-
children: filteredPlaylists.map((playlist) => {
|
|
9170
|
-
const firstItem = playlist.items?.[0];
|
|
9171
|
-
const imageUrl = playlist.image_url ?? firstItem?.image_url ?? firstItem?.relateable?.image_url ?? firstItem?.relateable?.compressed_image_url;
|
|
9172
|
-
const itemCount = playlist.items_count ?? playlist.items?.length ?? 0;
|
|
9173
|
-
const canEdit = !readOnly && playlist.user_id === user?.id;
|
|
9174
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlaylistCard, {
|
|
9175
|
-
title: playlist.title || "Untitled Playlist",
|
|
9176
|
-
imageUrl,
|
|
9177
|
-
href: `playlists/${playlist.id}`,
|
|
9178
|
-
itemCount,
|
|
9179
|
-
isFavorited: playlist.is_favorited,
|
|
9180
|
-
isSelectable: true,
|
|
9181
|
-
isSelected: selectedIds.has(playlist.id),
|
|
9182
|
-
canEdit,
|
|
9183
|
-
onSelectionChange: (selected) => handleToggleSelection(playlist.id, selected),
|
|
9184
|
-
onToggleFavorite: onToggleFavorite ? () => handleFavorite(playlist.id) : void 0,
|
|
9185
|
-
onEdit: () => handleEdit(playlist.id),
|
|
9186
|
-
onDelete: onDeletePlaylist ? () => setPendingDeleteId(playlist.id) : void 0
|
|
9187
|
-
}, playlist.id);
|
|
9188
|
-
})
|
|
9189
|
-
}),
|
|
9190
|
-
isFetchingNextPage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9191
|
-
className: "flex justify-center py-4",
|
|
9192
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "border-primary h-6 w-6 animate-spin rounded-full border-2 border-t-transparent" })
|
|
9193
|
-
}),
|
|
9194
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9195
|
-
ref: observerTarget,
|
|
9196
|
-
className: "h-1"
|
|
9197
|
-
}),
|
|
9198
|
-
error && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
9199
|
-
className: "bg-destructive/10 text-destructive rounded-lg px-3 py-2",
|
|
9200
|
-
children: ["Error: ", error.message]
|
|
9201
|
-
}),
|
|
9202
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialog, {
|
|
9203
|
-
open: pendingDeleteId !== null,
|
|
9204
|
-
onOpenChange: (open) => {
|
|
9205
|
-
if (!open && !isDeleting) setPendingDeleteId(null);
|
|
9206
|
-
},
|
|
9207
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.AlertDialogContent, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.AlertDialogHeader, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialogTitle, { children: "Delete this playlist?" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialogDescription, { children: "This removes the playlist from your library. Shared links that point to it will stop working." })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.AlertDialogFooter, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialogCancel, {
|
|
9208
|
-
disabled: isDeleting,
|
|
9209
|
-
children: "Cancel"
|
|
9210
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialogAction, {
|
|
9211
|
-
onClick: (e) => {
|
|
9212
|
-
e.preventDefault();
|
|
9213
|
-
confirmDelete();
|
|
9113
|
+
className: "ml-auto w-full max-w-sm",
|
|
9114
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SearchSort.SearchSort, {
|
|
9115
|
+
searchValue: searchTerm,
|
|
9116
|
+
onSearchChange: setSearchTerm,
|
|
9117
|
+
placeholder: "Search playlists...",
|
|
9118
|
+
sortOptions: [
|
|
9119
|
+
{
|
|
9120
|
+
label: "Name (A-Z)",
|
|
9121
|
+
value: "title"
|
|
9214
9122
|
},
|
|
9215
|
-
|
|
9216
|
-
|
|
9217
|
-
|
|
9218
|
-
|
|
9123
|
+
{
|
|
9124
|
+
label: "Name (Z-A)",
|
|
9125
|
+
value: "-title"
|
|
9126
|
+
},
|
|
9127
|
+
{
|
|
9128
|
+
label: "Date Created (Newest)",
|
|
9129
|
+
value: "-created_at"
|
|
9130
|
+
},
|
|
9131
|
+
{
|
|
9132
|
+
label: "Date Created (Oldest)",
|
|
9133
|
+
value: "created_at"
|
|
9134
|
+
}
|
|
9135
|
+
],
|
|
9136
|
+
sortValue,
|
|
9137
|
+
onSortChange: setSortValue
|
|
9219
9138
|
})
|
|
9220
|
-
]
|
|
9139
|
+
})]
|
|
9221
9140
|
});
|
|
9141
|
+
const footer = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [isFetchingNextPage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9142
|
+
className: "flex justify-center py-4",
|
|
9143
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "border-primary h-6 w-6 animate-spin rounded-full border-2 border-t-transparent" })
|
|
9144
|
+
}), error && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
9145
|
+
className: "bg-destructive/10 text-destructive rounded-lg px-3 py-2",
|
|
9146
|
+
children: ["Error: ", error.message]
|
|
9147
|
+
})] });
|
|
9148
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareableListLayout, {
|
|
9149
|
+
isLoading,
|
|
9150
|
+
filters: filterBar,
|
|
9151
|
+
isEmpty: filteredPlaylists.length === 0 && !isFetchingNextPage && !hasNextPage,
|
|
9152
|
+
emptyMessage: getFilteredEmptyMessage({
|
|
9153
|
+
searchTerm,
|
|
9154
|
+
ownerFilter,
|
|
9155
|
+
entityName: "playlists",
|
|
9156
|
+
defaultMessage: "There are no playlists available at the moment."
|
|
9157
|
+
}),
|
|
9158
|
+
footer,
|
|
9159
|
+
sentinelRef: observerTarget,
|
|
9160
|
+
loadingFilterShape: "search-action",
|
|
9161
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9162
|
+
className: GRID_CLASS,
|
|
9163
|
+
children: filteredPlaylists.map((playlist) => {
|
|
9164
|
+
const firstItem = playlist.items?.[0];
|
|
9165
|
+
const imageUrl = playlist.image_url ?? firstItem?.image_url ?? firstItem?.relateable?.image_url ?? firstItem?.relateable?.compressed_image_url;
|
|
9166
|
+
const itemCount = playlist.items_count ?? playlist.items?.length ?? 0;
|
|
9167
|
+
const canEdit = !readOnly && playlist.user_id === user?.id;
|
|
9168
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlaylistCard, {
|
|
9169
|
+
title: playlist.title || "Untitled Playlist",
|
|
9170
|
+
imageUrl,
|
|
9171
|
+
href: `playlists/${playlist.id}`,
|
|
9172
|
+
itemCount,
|
|
9173
|
+
isFavorited: playlist.is_favorited,
|
|
9174
|
+
isSelectable: true,
|
|
9175
|
+
isSelected: selectedIds.has(playlist.id),
|
|
9176
|
+
canEdit,
|
|
9177
|
+
onSelectionChange: (selected) => handleToggleSelection(playlist.id, selected),
|
|
9178
|
+
onToggleFavorite: onToggleFavorite ? () => handleFavorite(playlist.id) : void 0,
|
|
9179
|
+
onEdit: () => handleEdit(playlist.id),
|
|
9180
|
+
onDelete: onDeletePlaylist ? () => setPendingDeleteId(playlist.id) : void 0
|
|
9181
|
+
}, playlist.id);
|
|
9182
|
+
})
|
|
9183
|
+
})
|
|
9184
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialog, {
|
|
9185
|
+
open: pendingDeleteId !== null,
|
|
9186
|
+
onOpenChange: (open) => {
|
|
9187
|
+
if (!open && !isDeleting) setPendingDeleteId(null);
|
|
9188
|
+
},
|
|
9189
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.AlertDialogContent, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.AlertDialogHeader, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialogTitle, { children: "Delete this playlist?" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialogDescription, { children: "This removes the playlist from your library. Shared links that point to it will stop working." })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.AlertDialogFooter, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialogCancel, {
|
|
9190
|
+
disabled: isDeleting,
|
|
9191
|
+
children: "Cancel"
|
|
9192
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialogAction, {
|
|
9193
|
+
onClick: (e) => {
|
|
9194
|
+
e.preventDefault();
|
|
9195
|
+
confirmDelete();
|
|
9196
|
+
},
|
|
9197
|
+
disabled: isDeleting,
|
|
9198
|
+
className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
9199
|
+
children: isDeleting ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Spinner, { className: "size-4" }) : "Delete"
|
|
9200
|
+
})] })] })
|
|
9201
|
+
})] });
|
|
9222
9202
|
}
|
|
9223
9203
|
//#endregion
|
|
9224
9204
|
//#region ../../shareables/ui/src/constants.ts
|
|
@@ -9484,7 +9464,6 @@ const DEFAULT_IMAGE$1 = "https://assets.fluid.app/fluid-admin/images/we-commerce
|
|
|
9484
9464
|
function PlaylistDetailScreen({ playlistId, onNavigate }) {
|
|
9485
9465
|
const api = useShareablesApi();
|
|
9486
9466
|
const { navigate, user, readOnly } = useShareablesUI();
|
|
9487
|
-
const [isDescriptionExpanded, setIsDescriptionExpanded] = (0, react.useState)(false);
|
|
9488
9467
|
const [selectedPlaylistItemIndex, setSelectedPlaylistItemIndex] = (0, react.useState)(0);
|
|
9489
9468
|
const { data: playlistResponse, isLoading } = (0, _tanstack_react_query.useQuery)({
|
|
9490
9469
|
queryKey: shareablesKeys.playlists.detail(Number(playlistId)),
|
|
@@ -9530,94 +9509,53 @@ function PlaylistDetailScreen({ playlistId, onNavigate }) {
|
|
|
9530
9509
|
}) }), [displayTitle, navigate]));
|
|
9531
9510
|
const selectedPlaylistItem = playlist?.items?.[selectedPlaylistItemIndex];
|
|
9532
9511
|
const displayImage = selectedPlaylistItem?.image_url ?? selectedPlaylistItem?.relateable?.image_url ?? selectedPlaylistItem?.relateable?.compressed_image_url ?? DEFAULT_IMAGE$1;
|
|
9533
|
-
const
|
|
9534
|
-
const shouldShowReadMore = strippedDescription.length > 150;
|
|
9512
|
+
const displayDescription = playlist?.description || playlist?.search_engine_optimizer?.description || "";
|
|
9535
9513
|
const selectedKind = selectedPlaylistItem?.kind ?? selectedPlaylistItem?.relateable?.kind;
|
|
9536
9514
|
const displayVideo = selectedKind === "video" ? selectedPlaylistItem?.video_url ?? selectedPlaylistItem?.relateable?.video_url ?? void 0 : void 0;
|
|
9537
9515
|
const isVideo = selectedKind === "video" && !!displayVideo;
|
|
9538
9516
|
const taggedProducts = playlist?.items?.filter((item) => item.relateable_type === "Product").map((item) => item.relateable).filter((p) => !!p) || [];
|
|
9539
|
-
|
|
9540
|
-
|
|
9541
|
-
|
|
9542
|
-
|
|
9543
|
-
|
|
9544
|
-
|
|
9545
|
-
|
|
9546
|
-
className: "
|
|
9547
|
-
children:
|
|
9548
|
-
|
|
9549
|
-
|
|
9550
|
-
|
|
9551
|
-
|
|
9552
|
-
|
|
9553
|
-
|
|
9554
|
-
|
|
9555
|
-
|
|
9556
|
-
|
|
9557
|
-
|
|
9558
|
-
|
|
9559
|
-
|
|
9560
|
-
|
|
9561
|
-
|
|
9562
|
-
|
|
9563
|
-
|
|
9564
|
-
|
|
9565
|
-
|
|
9566
|
-
|
|
9567
|
-
|
|
9568
|
-
|
|
9569
|
-
|
|
9570
|
-
|
|
9571
|
-
|
|
9572
|
-
|
|
9573
|
-
|
|
9574
|
-
|
|
9575
|
-
|
|
9576
|
-
|
|
9577
|
-
|
|
9578
|
-
|
|
9579
|
-
className: !isDescriptionExpanded && shouldShowReadMore ? "line-clamp-3" : "",
|
|
9580
|
-
children: strippedDescription
|
|
9581
|
-
}), shouldShowReadMore && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Button, {
|
|
9582
|
-
onClick: () => setIsDescriptionExpanded(!isDescriptionExpanded),
|
|
9583
|
-
variant: "ghost",
|
|
9584
|
-
size: "sm",
|
|
9585
|
-
className: "text-foreground hover:text-foreground/80 mt-1 h-auto p-0 text-xs font-normal underline",
|
|
9586
|
-
children: isDescriptionExpanded ? "Read less" : "Read more"
|
|
9587
|
-
})]
|
|
9588
|
-
}),
|
|
9589
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssetActions, {
|
|
9590
|
-
downloadUrl: null,
|
|
9591
|
-
displayTitle,
|
|
9592
|
-
shareLink: shareLinkError ? null : shareLink || null,
|
|
9593
|
-
shareLinkLoading,
|
|
9594
|
-
isVideo,
|
|
9595
|
-
relateableId: Number(playlistId),
|
|
9596
|
-
relateableType: "Library"
|
|
9597
|
-
})
|
|
9598
|
-
]
|
|
9599
|
-
}),
|
|
9600
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Separator, { className: "border-foreground my-4" }),
|
|
9601
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9602
|
-
className: "bg-background rounded-lg",
|
|
9603
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TaggedProductsList, {
|
|
9604
|
-
products: taggedProducts,
|
|
9605
|
-
onProductClick: (productId) => onNavigate?.("product", String(productId))
|
|
9606
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlaylistItemsList, {
|
|
9607
|
-
items: playlist?.items || [],
|
|
9608
|
-
onSelectItem: setSelectedPlaylistItemIndex,
|
|
9609
|
-
selectedItemIndex: selectedPlaylistItemIndex,
|
|
9610
|
-
onNavigateToItem: (itemId, relateableType) => {
|
|
9611
|
-
if (!NAVIGABLE_RELATEABLE_TYPES.has(relateableType ?? "")) return;
|
|
9612
|
-
if (relateableType === "Product") onNavigate?.("product", String(itemId));
|
|
9613
|
-
else if (relateableType === "Page") onNavigate?.("page", String(itemId));
|
|
9614
|
-
else if (relateableType === "Medium") onNavigate?.("media", String(itemId));
|
|
9615
|
-
}
|
|
9616
|
-
})]
|
|
9617
|
-
})
|
|
9618
|
-
]
|
|
9517
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ShareableDetailLayout, {
|
|
9518
|
+
isLoading,
|
|
9519
|
+
notFound: !playlist,
|
|
9520
|
+
notFoundMessage: "Playlist not found or failed to load.",
|
|
9521
|
+
title: displayTitle,
|
|
9522
|
+
description: displayDescription,
|
|
9523
|
+
image: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9524
|
+
className: "relative h-full overflow-hidden rounded-2xl",
|
|
9525
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SharePageImageDisplay, {
|
|
9526
|
+
displayImage,
|
|
9527
|
+
displayTitle,
|
|
9528
|
+
displayVideo,
|
|
9529
|
+
isVideo,
|
|
9530
|
+
badgeLabel: "Playlist"
|
|
9531
|
+
})
|
|
9532
|
+
}),
|
|
9533
|
+
actions: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssetActions, {
|
|
9534
|
+
downloadUrl: null,
|
|
9535
|
+
displayTitle,
|
|
9536
|
+
shareLink: shareLinkError ? null : shareLink || null,
|
|
9537
|
+
shareLinkLoading,
|
|
9538
|
+
isVideo,
|
|
9539
|
+
relateableId: Number(playlistId),
|
|
9540
|
+
relateableType: "Library"
|
|
9541
|
+
}),
|
|
9542
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Separator, { className: "border-foreground my-4" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9543
|
+
className: "bg-background rounded-lg",
|
|
9544
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TaggedProductsList, {
|
|
9545
|
+
products: taggedProducts,
|
|
9546
|
+
onProductClick: (productId) => onNavigate?.("product", String(productId))
|
|
9547
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlaylistItemsList, {
|
|
9548
|
+
items: playlist?.items || [],
|
|
9549
|
+
onSelectItem: setSelectedPlaylistItemIndex,
|
|
9550
|
+
selectedItemIndex: selectedPlaylistItemIndex,
|
|
9551
|
+
onNavigateToItem: (itemId, relateableType) => {
|
|
9552
|
+
if (!NAVIGABLE_RELATEABLE_TYPES.has(relateableType ?? "")) return;
|
|
9553
|
+
if (relateableType === "Product") onNavigate?.("product", String(itemId));
|
|
9554
|
+
else if (relateableType === "Page") onNavigate?.("page", String(itemId));
|
|
9555
|
+
else if (relateableType === "Medium") onNavigate?.("media", String(itemId));
|
|
9556
|
+
}
|
|
9619
9557
|
})]
|
|
9620
|
-
})
|
|
9558
|
+
})]
|
|
9621
9559
|
});
|
|
9622
9560
|
}
|
|
9623
9561
|
//#endregion
|
|
@@ -10674,7 +10612,6 @@ function PlaylistCreateScreen({ playlistId, onBack, hideHeader, renderHeaderSlot
|
|
|
10674
10612
|
//#endregion
|
|
10675
10613
|
//#region ../../shareables/ui/src/components/screens/FilesListingScreen.tsx
|
|
10676
10614
|
const PAGE_SIZE = 24;
|
|
10677
|
-
const GRID_CLASS = "grid grid-cols-1 gap-8 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-4";
|
|
10678
10615
|
function formatFileSize(bytes) {
|
|
10679
10616
|
if (bytes < 1024) return `${bytes} B`;
|
|
10680
10617
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
@@ -10734,110 +10671,79 @@ function FilesListingScreen({ onNavigate }) {
|
|
|
10734
10671
|
observer.observe(target);
|
|
10735
10672
|
return () => observer.disconnect();
|
|
10736
10673
|
}, [handleIntersect]);
|
|
10737
|
-
|
|
10738
|
-
|
|
10739
|
-
|
|
10740
|
-
|
|
10741
|
-
|
|
10742
|
-
}
|
|
10743
|
-
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
|
|
10747
|
-
|
|
10748
|
-
|
|
10749
|
-
|
|
10750
|
-
|
|
10751
|
-
}, i))
|
|
10752
|
-
})]
|
|
10753
|
-
});
|
|
10754
|
-
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10755
|
-
className: "flex flex-col items-center justify-center py-16",
|
|
10756
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10757
|
-
className: "text-destructive text-sm",
|
|
10758
|
-
children: "Failed to load files. Please try again."
|
|
10759
|
-
})
|
|
10760
|
-
});
|
|
10761
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10762
|
-
className: "space-y-6 px-4 py-4 md:px-10 md:py-6",
|
|
10763
|
-
children: [
|
|
10764
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10765
|
-
className: "flex justify-end",
|
|
10766
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10767
|
-
className: "w-full max-w-sm",
|
|
10768
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SearchSort.SearchSort, {
|
|
10769
|
-
searchValue: searchTerm,
|
|
10770
|
-
onSearchChange: setSearchTerm,
|
|
10771
|
-
placeholder: "Search files..."
|
|
10772
|
-
})
|
|
10773
|
-
})
|
|
10774
|
-
}),
|
|
10775
|
-
files.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10776
|
-
className: "flex flex-col items-center justify-center py-16",
|
|
10777
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10778
|
-
className: "text-muted-foreground text-sm",
|
|
10779
|
-
children: debouncedSearch ? `No files match "${debouncedSearch}". Try a different search term.` : "No files available."
|
|
10674
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareableListLayout, {
|
|
10675
|
+
isLoading,
|
|
10676
|
+
error,
|
|
10677
|
+
errorMessage: "Failed to load files. Please try again.",
|
|
10678
|
+
isEmpty: files.length === 0,
|
|
10679
|
+
emptyMessage: debouncedSearch ? `No files match "${debouncedSearch}". Try a different search term.` : "No files available.",
|
|
10680
|
+
filters: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10681
|
+
className: "flex justify-end",
|
|
10682
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10683
|
+
className: "w-full max-w-sm",
|
|
10684
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SearchSort.SearchSort, {
|
|
10685
|
+
searchValue: searchTerm,
|
|
10686
|
+
onSearchChange: setSearchTerm,
|
|
10687
|
+
placeholder: "Search files..."
|
|
10780
10688
|
})
|
|
10781
|
-
})
|
|
10782
|
-
|
|
10783
|
-
|
|
10784
|
-
|
|
10785
|
-
|
|
10786
|
-
|
|
10787
|
-
|
|
10788
|
-
|
|
10789
|
-
|
|
10790
|
-
|
|
10791
|
-
|
|
10792
|
-
|
|
10793
|
-
|
|
10794
|
-
|
|
10795
|
-
|
|
10796
|
-
|
|
10797
|
-
|
|
10798
|
-
|
|
10799
|
-
|
|
10800
|
-
|
|
10801
|
-
|
|
10802
|
-
|
|
10803
|
-
|
|
10804
|
-
|
|
10805
|
-
|
|
10806
|
-
|
|
10807
|
-
|
|
10808
|
-
|
|
10809
|
-
|
|
10810
|
-
|
|
10811
|
-
|
|
10812
|
-
|
|
10813
|
-
|
|
10814
|
-
|
|
10815
|
-
|
|
10816
|
-
|
|
10689
|
+
})
|
|
10690
|
+
}),
|
|
10691
|
+
footer: isFetchingNextPage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10692
|
+
className: "flex justify-center py-4",
|
|
10693
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "border-primary h-6 w-6 animate-spin rounded-full border-2 border-t-transparent" })
|
|
10694
|
+
}),
|
|
10695
|
+
sentinelRef: observerTarget,
|
|
10696
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10697
|
+
className: SHAREABLE_GRID_CLASS,
|
|
10698
|
+
children: files.map((file) => {
|
|
10699
|
+
const isVideo = file.content_type?.startsWith("video/");
|
|
10700
|
+
const fileUrl = file.url || "#";
|
|
10701
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.Card, {
|
|
10702
|
+
role: "button",
|
|
10703
|
+
tabIndex: 0,
|
|
10704
|
+
onClick: () => window.open(fileUrl, "_blank"),
|
|
10705
|
+
onKeyDown: (e) => {
|
|
10706
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
10707
|
+
e.preventDefault();
|
|
10708
|
+
window.open(fileUrl, "_blank");
|
|
10709
|
+
}
|
|
10710
|
+
},
|
|
10711
|
+
className: "group hover:bg-muted cursor-pointer gap-0 overflow-hidden rounded-lg border-0 p-0 shadow-none transition-colors",
|
|
10712
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10713
|
+
className: "bg-muted relative aspect-square overflow-hidden rounded-lg",
|
|
10714
|
+
children: [
|
|
10715
|
+
renderImage({
|
|
10716
|
+
src: file.preview_image_url || DEFAULT_IMAGE,
|
|
10717
|
+
alt: file.filename || "Untitled File",
|
|
10718
|
+
fill: true,
|
|
10719
|
+
className: "object-cover transition-transform group-hover:scale-105"
|
|
10720
|
+
}),
|
|
10721
|
+
isVideo && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10722
|
+
className: "absolute inset-0 flex items-center justify-center",
|
|
10723
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10724
|
+
className: "bg-foreground/50 flex h-16 w-16 items-center justify-center rounded-full backdrop-blur-sm",
|
|
10725
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.CirclePlay, { className: "text-background h-12 w-12" })
|
|
10817
10726
|
})
|
|
10818
|
-
|
|
10819
|
-
|
|
10820
|
-
|
|
10821
|
-
|
|
10822
|
-
|
|
10823
|
-
|
|
10824
|
-
|
|
10825
|
-
|
|
10826
|
-
|
|
10827
|
-
|
|
10727
|
+
}),
|
|
10728
|
+
!isVideo && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Badge, {
|
|
10729
|
+
className: "absolute top-2 right-2 shadow-lg",
|
|
10730
|
+
variant: "default",
|
|
10731
|
+
children: formatFileSize(file.content_size)
|
|
10732
|
+
})
|
|
10733
|
+
]
|
|
10734
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10735
|
+
className: "px-2 pt-2 pb-4",
|
|
10736
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
10737
|
+
className: "text-foreground line-clamp-2 text-sm leading-tight font-bold",
|
|
10738
|
+
children: file.filename || "Untitled File"
|
|
10739
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10740
|
+
className: "text-muted-foreground mt-1 text-xs",
|
|
10741
|
+
children: file.content_type || "File"
|
|
10828
10742
|
})]
|
|
10829
|
-
}
|
|
10830
|
-
})
|
|
10831
|
-
}),
|
|
10832
|
-
isFetchingNextPage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10833
|
-
className: "flex justify-center py-4",
|
|
10834
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "border-primary h-6 w-6 animate-spin rounded-full border-2 border-t-transparent" })
|
|
10835
|
-
}),
|
|
10836
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10837
|
-
ref: observerTarget,
|
|
10838
|
-
className: "h-1"
|
|
10743
|
+
})]
|
|
10744
|
+
}, file.id);
|
|
10839
10745
|
})
|
|
10840
|
-
|
|
10746
|
+
})
|
|
10841
10747
|
});
|
|
10842
10748
|
}
|
|
10843
10749
|
//#endregion
|
|
@@ -12002,4 +11908,4 @@ Object.defineProperty(exports, "usePortalContentContext", {
|
|
|
12002
11908
|
}
|
|
12003
11909
|
});
|
|
12004
11910
|
|
|
12005
|
-
//# sourceMappingURL=PortalContentApiProvider-
|
|
11911
|
+
//# sourceMappingURL=PortalContentApiProvider-C5WzWC3k.cjs.map
|