@fluid-app/portal-sdk 0.1.217 → 0.1.219
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/{ContactsScreen-D-g7XEB-.cjs → ContactsScreen-DYVR-UvO.cjs} +1 -1
- package/dist/{FluidProvider-02beRTpR.mjs → FluidProvider-DTttgSXi.mjs} +8 -8
- package/dist/{FluidProvider-02beRTpR.mjs.map → FluidProvider-DTttgSXi.mjs.map} +1 -1
- package/dist/{FluidProvider-BgFmXtHo.cjs → FluidProvider-Dm4BhF_t.cjs} +8 -8
- package/dist/{FluidProvider-BgFmXtHo.cjs.map → FluidProvider-Dm4BhF_t.cjs.map} +1 -1
- package/dist/{ListWidget-C0ltFhxE.cjs → ListWidget-BE7uA4W4.cjs} +1 -2
- package/dist/{ListWidget-Ct8IDkio.mjs → ListWidget-D7y8bfvT.mjs} +252 -120
- package/dist/ListWidget-D7y8bfvT.mjs.map +1 -0
- package/dist/{ListWidget-C7ouNpEo.cjs → ListWidget-DJ-_dMOK.cjs} +251 -119
- package/dist/ListWidget-DJ-_dMOK.cjs.map +1 -0
- package/dist/{MessagingScreen-CJlVOY5R.mjs → MessagingScreen-CwEXQJlW.mjs} +2 -2
- package/dist/{MessagingScreen-CJlVOY5R.mjs.map → MessagingScreen-CwEXQJlW.mjs.map} +1 -1
- package/dist/{MessagingScreen-BkLcqJbs.cjs → MessagingScreen-DLQ5V0m4.cjs} +2 -2
- package/dist/{MessagingScreen-BkLcqJbs.cjs.map → MessagingScreen-DLQ5V0m4.cjs.map} +1 -1
- package/dist/{MessagingScreen-sN7aBvGk.cjs → MessagingScreen-YBXJL7a9.cjs} +6 -6
- package/dist/{MySiteScreen-DUN5TTvU.mjs → MySiteScreen-CyzM9hX3.mjs} +11 -30
- package/dist/{MySiteScreen-DUN5TTvU.mjs.map → MySiteScreen-CyzM9hX3.mjs.map} +1 -1
- package/dist/{MySiteScreen-B0aOIzU4.cjs → MySiteScreen-DPQ66oRs.cjs} +2 -2
- package/dist/{MySiteScreen-B1L8coGs.cjs → MySiteScreen-DxLcG3-S.cjs} +11 -30
- package/dist/MySiteScreen-DxLcG3-S.cjs.map +1 -0
- package/dist/{MySiteWidget-CDQjyrRA.cjs → MySiteWidget-8UsfEK-w.cjs} +1 -1
- package/dist/{MySiteWidget-CDQjyrRA.cjs.map → MySiteWidget-8UsfEK-w.cjs.map} +1 -1
- package/dist/{MySiteWidget-BlUbduit.mjs → MySiteWidget-D46TVWnf.mjs} +1 -1
- package/dist/{MySiteWidget-BlUbduit.mjs.map → MySiteWidget-D46TVWnf.mjs.map} +1 -1
- package/dist/{NestedWidget-ChAWwsRP.cjs → NestedWidget-BjT-UrSi.cjs} +2 -2
- package/dist/{NestedWidget-ChAWwsRP.cjs.map → NestedWidget-BjT-UrSi.cjs.map} +1 -1
- package/dist/{NestedWidget-Dw0QHoqw.mjs → NestedWidget-CEeQeCq0.mjs} +2 -2
- package/dist/{NestedWidget-Dw0QHoqw.mjs.map → NestedWidget-CEeQeCq0.mjs.map} +1 -1
- package/dist/{NestedWidget--suTLM6l.cjs → NestedWidget-D4amXykk.cjs} +2 -2
- package/dist/{PortalContentApiProvider-RXBp8FNj.cjs → PortalContentApiProvider-DXnplIOD.cjs} +273 -82
- package/dist/PortalContentApiProvider-DXnplIOD.cjs.map +1 -0
- package/dist/{PortalContentApiProvider-C9FeVwRb.mjs → PortalContentApiProvider-x81DXmOR.mjs} +273 -82
- package/dist/PortalContentApiProvider-x81DXmOR.mjs.map +1 -0
- package/dist/{ProductsScreen-DNpzJ6lh.cjs → ProductsScreen-3yjIMjYY.cjs} +2 -2
- package/dist/{ProductsScreen-pkOeOW8M.mjs → ProductsScreen-BVyLOe2K.mjs} +2 -2
- package/dist/{ProductsScreen-BD53vh6Y.cjs → ProductsScreen-R0MfWYZJ.cjs} +2 -2
- package/dist/{ProductsScreen-BD53vh6Y.cjs.map → ProductsScreen-R0MfWYZJ.cjs.map} +1 -1
- package/dist/{ProductsScreen-BtUZxJCt.mjs → ProductsScreen-z9hXfFeJ.mjs} +2 -2
- package/dist/{ProductsScreen-BtUZxJCt.mjs.map → ProductsScreen-z9hXfFeJ.mjs.map} +1 -1
- package/dist/{ProfileScreen-rPqgsNCc.cjs → ProfileScreen-B0WRifk_.cjs} +2 -2
- package/dist/{ProfileScreen-rPqgsNCc.cjs.map → ProfileScreen-B0WRifk_.cjs.map} +1 -1
- package/dist/{ProfileScreen-CNYqUDNB.mjs → ProfileScreen-BuejQU_V.mjs} +2 -2
- package/dist/{ProfileScreen-CNYqUDNB.mjs.map → ProfileScreen-BuejQU_V.mjs.map} +1 -1
- package/dist/{ProfileScreen-Bgo6iTKe.cjs → ProfileScreen-g3se9Jw-.cjs} +6 -6
- package/dist/{ShareablesScreen-DC8xXUo4.cjs → ShareablesScreen-Co_gFZva.cjs} +3 -3
- package/dist/{ShareablesScreen-DC8xXUo4.cjs.map → ShareablesScreen-Co_gFZva.cjs.map} +1 -1
- package/dist/{ShareablesScreen-D1J2Kljk.mjs → ShareablesScreen-DpwFh0ky.mjs} +3 -3
- package/dist/{ShareablesScreen-smU5pGyH.cjs → ShareablesScreen-YlMqyP-B.cjs} +3 -3
- package/dist/{ShareablesScreen-CW1e9x4K.mjs → ShareablesScreen-tkaf9R5N.mjs} +3 -3
- package/dist/{ShareablesScreen-CW1e9x4K.mjs.map → ShareablesScreen-tkaf9R5N.mjs.map} +1 -1
- package/dist/{ShopScreen-B9lHJ8L2.mjs → ShopScreen-B4afB5sE.mjs} +2 -2
- package/dist/{ShopScreen-B9lHJ8L2.mjs.map → ShopScreen-B4afB5sE.mjs.map} +1 -1
- package/dist/{ShopScreen-g6FQ4R1_.cjs → ShopScreen-BOjri6Dm.cjs} +6 -6
- package/dist/{ShopScreen-DUHzufCU.cjs → ShopScreen-Untg6XBY.cjs} +2 -2
- package/dist/{ShopScreen-DUHzufCU.cjs.map → ShopScreen-Untg6XBY.cjs.map} +1 -1
- package/dist/index.cjs +27 -27
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +25 -25
- package/dist/{portal_tenant_content-0zpnjBot.cjs → portal_tenant_content-BvYxmADB.cjs} +18 -1
- package/dist/portal_tenant_content-BvYxmADB.cjs.map +1 -0
- package/dist/{portal_tenant_content-DzIQtSLE.mjs → portal_tenant_content-nHEI2qEY.mjs} +13 -2
- package/dist/portal_tenant_content-nHEI2qEY.mjs.map +1 -0
- package/dist/{scroll-arrows-fK_MFlSX.mjs → scroll-arrows-COrfvJk9.mjs} +1 -1
- package/dist/{scroll-arrows-fK_MFlSX.mjs.map → scroll-arrows-COrfvJk9.mjs.map} +1 -1
- package/dist/{scroll-arrows-DVwMDTt3.cjs → scroll-arrows-i0E2N-ct.cjs} +1 -1
- package/dist/{scroll-arrows-DVwMDTt3.cjs.map → scroll-arrows-i0E2N-ct.cjs.map} +1 -1
- package/dist/{use-mysite-portal-BV-BP3CE.mjs → use-mysite-portal-D29HLD1z.mjs} +3 -2
- package/dist/use-mysite-portal-D29HLD1z.mjs.map +1 -0
- package/dist/{use-mysite-portal-DzDYRU0u.cjs → use-mysite-portal-DxNQ3uTi.cjs} +3 -2
- package/dist/use-mysite-portal-DxNQ3uTi.cjs.map +1 -0
- package/package.json +9 -9
- package/dist/ListWidget-C7ouNpEo.cjs.map +0 -1
- package/dist/ListWidget-Ct8IDkio.mjs.map +0 -1
- package/dist/MySiteScreen-B1L8coGs.cjs.map +0 -1
- package/dist/PortalContentApiProvider-C9FeVwRb.mjs.map +0 -1
- package/dist/PortalContentApiProvider-RXBp8FNj.cjs.map +0 -1
- package/dist/portal_tenant_content-0zpnjBot.cjs.map +0 -1
- package/dist/portal_tenant_content-DzIQtSLE.mjs.map +0 -1
- package/dist/use-mysite-portal-BV-BP3CE.mjs.map +0 -1
- package/dist/use-mysite-portal-DzDYRU0u.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NestedWidget-Dw0QHoqw.mjs","names":[],"sources":["../../widgets/src/widgets/NestedWidget.tsx"],"sourcesContent":["import { useRef, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport {\n MediaRenderer,\n getMediaPropsFromShareable,\n} from \"../components/MediaRenderer\";\nimport type {\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n AlignOptions,\n GapOptions,\n BackgroundValue,\n} from \"@fluid-app/portal-core/types\";\nimport {\n getHeightField,\n type WidgetPropertySchema,\n} from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getBorderWidthField,\n getBorderColorField,\n borderWidthClasses,\n borderColorClasses,\n getColorField,\n getFontSizeField,\n getGapField,\n getPaddingField,\n gapValues,\n} from \"../core/fields\";\nimport { ScrollArrows } from \"../ui/scroll-arrows\";\nimport { type ShareableItem } from \"@fluid-app/portal-core/types\";\nimport { useWidgetInteraction } from \"../contexts/WidgetInteractionContext\";\n\nconst DEFAULT_SHAREABLES: ShareableItem[] = [];\n\ntype NestedWidgetProps = ComponentProps<\"div\"> & {\n // Content\n resource?: ShareableItem;\n titleEnabled?: boolean;\n titleText?: string;\n shareables?: ShareableItem[];\n\n // Layout\n gap?: GapOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n primaryMediaHeight?: string;\n\n // Title styling\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n titleAlignment?: AlignOptions;\n\n // Nested media styling\n nestedTextColor?: ColorOptions;\n background?: BackgroundValue;\n\n // Overlay\n overlayEnabled?: boolean;\n overlayType?: \"solid\" | \"gradient\";\n overlayIntensity?: number;\n};\n\nexport function NestedWidget({\n resource,\n titleEnabled = true,\n titleText = \"Featured Collection\",\n shareables = DEFAULT_SHAREABLES,\n gap = \"md\",\n padding = 4,\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n primaryMediaHeight = \"400px\",\n titleFontSize = \"xl\",\n titleColor = \"background\",\n titleAlignment = { horizontal: \"left\", vertical: \"bottom\" },\n nestedTextColor = \"foreground\",\n background = {\n type: \"solid\",\n color: \"background\",\n },\n overlayEnabled = true,\n overlayType = \"gradient\",\n overlayIntensity = 50,\n className,\n ...props\n}: NestedWidgetProps): React.JSX.Element {\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n\n const scrollByAmount = (direction: \"prev\" | \"next\") => {\n const container = scrollContainerRef.current;\n if (!container) return;\n\n const computedGap = parseFloat(getComputedStyle(container).gap) || 0;\n const firstItem = container.firstElementChild as HTMLElement | null;\n const itemWidth = firstItem?.offsetWidth ?? 0;\n const scrollAmount = itemWidth + computedGap;\n\n container.scrollTo({\n left:\n container.scrollLeft +\n (direction === \"next\" ? scrollAmount : -scrollAmount),\n behavior: \"smooth\",\n });\n };\n\n // Cap border radius for the primary media container: \"full\" creates a circle that clips\n // the absolutely-positioned title overlay to the narrow bottom of the circle.\n const primaryMediaRadius = borderRadius === \"full\" ? \"2xl\" : borderRadius;\n\n const { onItemClick } = useWidgetInteraction();\n\n const hasNestedMedia = shareables.length > 0;\n\n const titleAlignmentClasses = {\n left: \"text-left\",\n center: \"text-center\",\n right: \"text-right\",\n };\n\n const backgroundColor = background.color || \"background\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n background.type === \"image\"\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n\n return (\n <div\n className={`@container flex w-full overflow-hidden p-${padding} rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} bg-${backgroundColor} ${className}`}\n {...props}\n style={{\n maxHeight: primaryMediaHeight,\n backgroundImage: backgroundImage,\n }}\n >\n {/* Primary Media Container - Full width on mobile, fixed on desktop */}\n <div\n className={`relative @md:flex-none`}\n style={{\n width: primaryMediaHeight,\n }}\n >\n {/* Media + overlay clipped to rounded shape — title is a sibling so it isn't clipped */}\n <div\n className={`overflow-hidden rounded-${primaryMediaRadius} absolute inset-0`}\n >\n <MediaRenderer\n {...(resource ? getMediaPropsFromShareable(resource) : {})}\n autoplay\n loop\n muted\n />\n\n {/* Overlay */}\n {overlayEnabled && (\n <div\n className={`pointer-events-none absolute inset-0 z-10 ${\n overlayType === \"gradient\"\n ? \"bg-gradient-to-t from-black to-transparent\"\n : \"bg-black\"\n }`}\n style={{\n opacity:\n (Number(String(overlayIntensity).replace(\"%\", \"\")) || 50) /\n 100,\n }}\n />\n )}\n </div>\n\n {/* Title and Mobile Nested Media — outside the overflow-hidden clip */}\n {((titleEnabled && titleText) || hasNestedMedia) && (\n <div\n className={`absolute z-20 w-full ${titleAlignmentClasses[titleAlignment?.horizontal ?? \"left\"]} p-${padding} ${\n titleAlignment.vertical === \"top\"\n ? `top-0 pt-${padding}`\n : titleAlignment.vertical === \"center\"\n ? \"top-1/2 -translate-y-1/2\"\n : `bottom-0 pb-${padding}`\n }`}\n >\n {titleEnabled && titleText && (\n <h2\n className={`font-header leading-tight font-bold text-${titleColor} text-${titleFontSize === \"md\" ? \"base\" : titleFontSize}`}\n >\n {titleText}\n </h2>\n )}\n\n {/* Mobile: Products overlay inside primary media */}\n {hasNestedMedia && (\n <div className={`pt-${padding} @md:hidden`}>\n <div\n className={`flex overflow-x-auto gap-${gapValues[gap]} bg-transparent`}\n >\n {shareables.map((shareable) => (\n <div\n key={shareable.id}\n className={`flex shrink-0 flex-col items-center ${onItemClick ? \"cursor-pointer\" : \"\"}`}\n {...(onItemClick\n ? {\n role: \"button\",\n tabIndex: 0,\n onClick: () => onItemClick(shareable),\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onItemClick(shareable);\n }\n },\n }\n : {})}\n >\n <div\n className={`aspect-3/4 h-40 overflow-hidden rounded-${borderRadius}`}\n >\n <MediaRenderer\n {...getMediaPropsFromShareable(shareable)}\n />\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n\n {/* Desktop: Products Container - Single row beside primary media */}\n {hasNestedMedia && (\n <div\n className={`relative hidden min-w-0 self-stretch @md:flex @md:flex-1 px-${padding}`}\n >\n <div\n ref={scrollContainerRef}\n className={`flex h-full flex-row overflow-x-auto gap-${gapValues[gap]}`}\n style={{ scrollSnapType: \"x mandatory\" }}\n >\n {shareables.map((shareable) => (\n <div\n key={shareable.id}\n className={`flex shrink-0 flex-col gap-1 ${onItemClick ? \"cursor-pointer\" : \"\"}`}\n style={{\n width: `calc(${primaryMediaHeight} * 0.75)`,\n scrollSnapAlign: \"start\",\n }}\n {...(onItemClick\n ? {\n role: \"button\",\n tabIndex: 0,\n onClick: () => onItemClick(shareable),\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onItemClick(shareable);\n }\n },\n }\n : {})}\n >\n <div\n className={`aspect-3/4 h-full rounded-${borderRadius} overflow-hidden`}\n >\n <MediaRenderer {...getMediaPropsFromShareable(shareable)} />\n </div>\n <span className={`flex-none text-sm text-${nestedTextColor}`}>\n <p className=\"truncate\">{shareable.title || \"\"}</p>\n <p className=\"truncate\">\n {((shareable.display_price as string) ?? shareable.price) ||\n \"\"}\n </p>\n </span>\n </div>\n ))}\n </div>\n\n {/* Navigation arrows */}\n <div\n className={`absolute inset-x-0 top-1/2 flex w-full -translate-y-1/2 items-center justify-between px-8`}\n >\n <ScrollArrows\n onPrevious={() => scrollByAmount(\"prev\")}\n onNext={() => scrollByAmount(\"next\")}\n />\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const nestedWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"NestedWidget\",\n displayName: \"Nested Widget\",\n tabsConfig: [\n { id: \"styling\", label: \"Styling\" },\n { id: \"data\", label: \"Data\" },\n ],\n dataSourceTargetProps: [\"shareables\"],\n fields: [\n // Content tab - Resource group\n {\n key: \"resource\",\n label: \"Primary Media\",\n type: \"resource\",\n description: \"Select the primary media displayed in the large panel\",\n allowedTypes: [\"Medium\"],\n tab: \"styling\",\n group: \"Content\",\n },\n // Content tab - Title group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed over the primary media\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Main title displayed over the primary media\",\n defaultValue: \"Featured Collection\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n label: \"Title Font Size\",\n defaultValue: \"xl\",\n key: \"titleFontSize\",\n description: \"Font size for the widget title\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n defaultValue: \"background\",\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n // Styling tab - Design group\n getHeightField({\n key: \"primaryMediaHeight\",\n label: \"Primary Media Height\",\n description: \"Height of the primary media container\",\n defaultValue: \"400px\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"titleAlignment\",\n label: \"Content Alignment\",\n type: \"alignment\",\n description: \"Alignment of the content inside the primary media\",\n defaultValue: { horizontal: \"left\", vertical: \"bottom\" },\n options: {\n horizontalEnabled: true,\n verticalEnabled: true,\n },\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"separator2\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n defaultValue: 4,\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding used throughout the widget\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n defaultValue: \"md\",\n label: \"Border Radius\",\n key: \"borderRadius\",\n description: \"Rounded corners for the widget\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget\",\n defaultValue: \"none\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"overlayEnabled\",\n label: \"Enable Overlay\",\n type: \"boolean\",\n description:\n \"Add a dark overlay to the primary media for better text readability\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"overlayType\",\n label: \"Overlay Type\",\n type: \"buttonGroup\",\n description: \"Type of overlay effect\",\n defaultValue: \"gradient\",\n options: [\n { label: \"Solid\", value: \"solid\" },\n { label: \"Gradient\", value: \"gradient\" },\n ],\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"overlayEnabled\",\n },\n {\n key: \"overlayIntensity\",\n label: \"Overlay Intensity\",\n type: \"slider\",\n description: \"Opacity of the overlay (0-100)\",\n min: 0,\n max: 100,\n step: 5,\n defaultValue: 50,\n unit: \"%\",\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"overlayEnabled\",\n },\n // Styling tab - Nested Media Styling group\n getGapField({\n label: \"Gap\",\n defaultValue: \"md\",\n key: \"gap\",\n description: \"Gap between nested media items\",\n tab: \"styling\",\n group: \"Nested Design\",\n }),\n getColorField({\n defaultValue: \"foreground\",\n key: \"nestedTextColor\",\n label: \"Nested Text Color\",\n description: \"Color for nested media labels\",\n tab: \"styling\",\n group: \"Nested Design\",\n }),\n {\n type: \"background\",\n defaultValue: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background color for nested media container\",\n tab: \"styling\",\n group: \"Nested Design\",\n },\n // Data tab\n {\n key: \"dataSource\",\n label: \"Data Source\",\n type: \"dataSource\",\n description: \"Configure dynamic data fetching from an API\",\n tab: \"data\",\n group: \"Data Configuration\",\n },\n ],\n // Per-item configuration schema for custom data sources\n itemConfigSchema: {\n description: \"Configure settings for this item\",\n fields: [\n {\n key: \"title\",\n label: \"Custom Title\",\n type: \"text\",\n description: \"Override the item's title for this widget\",\n },\n ],\n },\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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ACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;IAAE,YAAY;IAAQ,UAAU;IAAU;GACxD,SAAS;IACP,mBAAmB;IACnB,iBAAiB;IAClB;GACD,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;EACD,gBAAgB;GACd,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF,qBAAqB;GACnB,cAAc;GACd,OAAO;GACP,KAAK;GACL,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aACE;GACF,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,SAAS,CACP;IAAE,OAAO;IAAS,OAAO;IAAS,EAClC;IAAE,OAAO;IAAY,OAAO;IAAY,CACzC;GACD,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,KAAK;GACL,MAAM;GACN,cAAc;GACd,MAAM;GACN,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EAED,YAAY;GACV,OAAO;GACP,cAAc;GACd,KAAK;GACL,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF,cAAc;GACZ,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,MAAM;GACN,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR;EAED;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACR;EACF;CAED,kBAAkB;EAChB,aAAa;EACb,QAAQ,CACN;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACd,CACF;EACF;CACF"}
|
|
1
|
+
{"version":3,"file":"NestedWidget-CEeQeCq0.mjs","names":[],"sources":["../../widgets/src/widgets/NestedWidget.tsx"],"sourcesContent":["import { useRef, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport {\n MediaRenderer,\n getMediaPropsFromShareable,\n} from \"../components/MediaRenderer\";\nimport type {\n BorderRadiusOptions,\n BorderWidthOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n AlignOptions,\n GapOptions,\n BackgroundValue,\n} from \"@fluid-app/portal-core/types\";\nimport {\n getHeightField,\n type WidgetPropertySchema,\n} from \"@fluid-app/portal-core/registries\";\nimport {\n getBorderRadiusField,\n getBorderWidthField,\n getBorderColorField,\n borderWidthClasses,\n borderColorClasses,\n getColorField,\n getFontSizeField,\n getGapField,\n getPaddingField,\n gapValues,\n} from \"../core/fields\";\nimport { ScrollArrows } from \"../ui/scroll-arrows\";\nimport { type ShareableItem } from \"@fluid-app/portal-core/types\";\nimport { useWidgetInteraction } from \"../contexts/WidgetInteractionContext\";\n\nconst DEFAULT_SHAREABLES: ShareableItem[] = [];\n\ntype NestedWidgetProps = ComponentProps<\"div\"> & {\n // Content\n resource?: ShareableItem;\n titleEnabled?: boolean;\n titleText?: string;\n shareables?: ShareableItem[];\n\n // Layout\n gap?: GapOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n borderWidth?: BorderWidthOptions;\n borderColor?: ColorOptions;\n primaryMediaHeight?: string;\n\n // Title styling\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n titleAlignment?: AlignOptions;\n\n // Nested media styling\n nestedTextColor?: ColorOptions;\n background?: BackgroundValue;\n\n // Overlay\n overlayEnabled?: boolean;\n overlayType?: \"solid\" | \"gradient\";\n overlayIntensity?: number;\n};\n\nexport function NestedWidget({\n resource,\n titleEnabled = true,\n titleText = \"Featured Collection\",\n shareables = DEFAULT_SHAREABLES,\n gap = \"md\",\n padding = 4,\n borderRadius = \"md\",\n borderWidth = \"none\",\n borderColor = \"muted\",\n primaryMediaHeight = \"400px\",\n titleFontSize = \"xl\",\n titleColor = \"background\",\n titleAlignment = { horizontal: \"left\", vertical: \"bottom\" },\n nestedTextColor = \"foreground\",\n background = {\n type: \"solid\",\n color: \"background\",\n },\n overlayEnabled = true,\n overlayType = \"gradient\",\n overlayIntensity = 50,\n className,\n ...props\n}: NestedWidgetProps): React.JSX.Element {\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n\n const scrollByAmount = (direction: \"prev\" | \"next\") => {\n const container = scrollContainerRef.current;\n if (!container) return;\n\n const computedGap = parseFloat(getComputedStyle(container).gap) || 0;\n const firstItem = container.firstElementChild as HTMLElement | null;\n const itemWidth = firstItem?.offsetWidth ?? 0;\n const scrollAmount = itemWidth + computedGap;\n\n container.scrollTo({\n left:\n container.scrollLeft +\n (direction === \"next\" ? scrollAmount : -scrollAmount),\n behavior: \"smooth\",\n });\n };\n\n // Cap border radius for the primary media container: \"full\" creates a circle that clips\n // the absolutely-positioned title overlay to the narrow bottom of the circle.\n const primaryMediaRadius = borderRadius === \"full\" ? \"2xl\" : borderRadius;\n\n const { onItemClick } = useWidgetInteraction();\n\n const hasNestedMedia = shareables.length > 0;\n\n const titleAlignmentClasses = {\n left: \"text-left\",\n center: \"text-center\",\n right: \"text-right\",\n };\n\n const backgroundColor = background.color || \"background\";\n const backgroundImage =\n (background.resource?.image_url || background.resource?.imageUrl) &&\n background.type === \"image\"\n ? `url(${background.resource.image_url || background.resource.imageUrl})`\n : \"none\";\n\n return (\n <div\n className={`@container flex w-full overflow-hidden p-${padding} rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} bg-${backgroundColor} ${className}`}\n {...props}\n style={{\n maxHeight: primaryMediaHeight,\n backgroundImage: backgroundImage,\n }}\n >\n {/* Primary Media Container - Full width on mobile, fixed on desktop */}\n <div\n className={`relative @md:flex-none`}\n style={{\n width: primaryMediaHeight,\n }}\n >\n {/* Media + overlay clipped to rounded shape — title is a sibling so it isn't clipped */}\n <div\n className={`overflow-hidden rounded-${primaryMediaRadius} absolute inset-0`}\n >\n <MediaRenderer\n {...(resource ? getMediaPropsFromShareable(resource) : {})}\n autoplay\n loop\n muted\n />\n\n {/* Overlay */}\n {overlayEnabled && (\n <div\n className={`pointer-events-none absolute inset-0 z-10 ${\n overlayType === \"gradient\"\n ? \"bg-gradient-to-t from-black to-transparent\"\n : \"bg-black\"\n }`}\n style={{\n opacity:\n (Number(String(overlayIntensity).replace(\"%\", \"\")) || 50) /\n 100,\n }}\n />\n )}\n </div>\n\n {/* Title and Mobile Nested Media — outside the overflow-hidden clip */}\n {((titleEnabled && titleText) || hasNestedMedia) && (\n <div\n className={`absolute z-20 w-full ${titleAlignmentClasses[titleAlignment?.horizontal ?? \"left\"]} p-${padding} ${\n titleAlignment.vertical === \"top\"\n ? `top-0 pt-${padding}`\n : titleAlignment.vertical === \"center\"\n ? \"top-1/2 -translate-y-1/2\"\n : `bottom-0 pb-${padding}`\n }`}\n >\n {titleEnabled && titleText && (\n <h2\n className={`font-header leading-tight font-bold text-${titleColor} text-${titleFontSize === \"md\" ? \"base\" : titleFontSize}`}\n >\n {titleText}\n </h2>\n )}\n\n {/* Mobile: Products overlay inside primary media */}\n {hasNestedMedia && (\n <div className={`pt-${padding} @md:hidden`}>\n <div\n className={`flex overflow-x-auto gap-${gapValues[gap]} bg-transparent`}\n >\n {shareables.map((shareable) => (\n <div\n key={shareable.id}\n className={`flex shrink-0 flex-col items-center ${onItemClick ? \"cursor-pointer\" : \"\"}`}\n {...(onItemClick\n ? {\n role: \"button\",\n tabIndex: 0,\n onClick: () => onItemClick(shareable),\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onItemClick(shareable);\n }\n },\n }\n : {})}\n >\n <div\n className={`aspect-3/4 h-40 overflow-hidden rounded-${borderRadius}`}\n >\n <MediaRenderer\n {...getMediaPropsFromShareable(shareable)}\n />\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n\n {/* Desktop: Products Container - Single row beside primary media */}\n {hasNestedMedia && (\n <div\n className={`relative hidden min-w-0 self-stretch @md:flex @md:flex-1 px-${padding}`}\n >\n <div\n ref={scrollContainerRef}\n className={`flex h-full flex-row overflow-x-auto gap-${gapValues[gap]}`}\n style={{ scrollSnapType: \"x mandatory\" }}\n >\n {shareables.map((shareable) => (\n <div\n key={shareable.id}\n className={`flex shrink-0 flex-col gap-1 ${onItemClick ? \"cursor-pointer\" : \"\"}`}\n style={{\n width: `calc(${primaryMediaHeight} * 0.75)`,\n scrollSnapAlign: \"start\",\n }}\n {...(onItemClick\n ? {\n role: \"button\",\n tabIndex: 0,\n onClick: () => onItemClick(shareable),\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onItemClick(shareable);\n }\n },\n }\n : {})}\n >\n <div\n className={`aspect-3/4 h-full rounded-${borderRadius} overflow-hidden`}\n >\n <MediaRenderer {...getMediaPropsFromShareable(shareable)} />\n </div>\n <span className={`flex-none text-sm text-${nestedTextColor}`}>\n <p className=\"truncate\">{shareable.title || \"\"}</p>\n <p className=\"truncate\">\n {((shareable.display_price as string) ?? shareable.price) ||\n \"\"}\n </p>\n </span>\n </div>\n ))}\n </div>\n\n {/* Navigation arrows */}\n <div\n className={`absolute inset-x-0 top-1/2 flex w-full -translate-y-1/2 items-center justify-between px-8`}\n >\n <ScrollArrows\n onPrevious={() => scrollByAmount(\"prev\")}\n onNext={() => scrollByAmount(\"next\")}\n />\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const nestedWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"NestedWidget\",\n displayName: \"Nested Widget\",\n tabsConfig: [\n { id: \"styling\", label: \"Styling\" },\n { id: \"data\", label: \"Data\" },\n ],\n dataSourceTargetProps: [\"shareables\"],\n fields: [\n // Content tab - Resource group\n {\n key: \"resource\",\n label: \"Primary Media\",\n type: \"resource\",\n description: \"Select the primary media displayed in the large panel\",\n allowedTypes: [\"Medium\"],\n tab: \"styling\",\n group: \"Content\",\n },\n // Content tab - Title group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed over the primary media\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Main title displayed over the primary media\",\n defaultValue: \"Featured Collection\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n label: \"Title Font Size\",\n defaultValue: \"xl\",\n key: \"titleFontSize\",\n description: \"Font size for the widget title\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n defaultValue: \"background\",\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n // Styling tab - Design group\n getHeightField({\n key: \"primaryMediaHeight\",\n label: \"Primary Media Height\",\n description: \"Height of the primary media container\",\n defaultValue: \"400px\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"titleAlignment\",\n label: \"Content Alignment\",\n type: \"alignment\",\n description: \"Alignment of the content inside the primary media\",\n defaultValue: { horizontal: \"left\", vertical: \"bottom\" },\n options: {\n horizontalEnabled: true,\n verticalEnabled: true,\n },\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"separator2\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n defaultValue: 4,\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding used throughout the widget\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n defaultValue: \"md\",\n label: \"Border Radius\",\n key: \"borderRadius\",\n description: \"Rounded corners for the widget\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderWidthField({\n key: \"borderWidth\",\n label: \"Border Width\",\n description: \"Border width for the widget\",\n defaultValue: \"none\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderColorField({\n key: \"borderColor\",\n label: \"Border Color\",\n description: \"Border color for the widget\",\n defaultValue: \"muted\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"overlayEnabled\",\n label: \"Enable Overlay\",\n type: \"boolean\",\n description:\n \"Add a dark overlay to the primary media for better text readability\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Design\",\n },\n {\n key: \"overlayType\",\n label: \"Overlay Type\",\n type: \"buttonGroup\",\n description: \"Type of overlay effect\",\n defaultValue: \"gradient\",\n options: [\n { label: \"Solid\", value: \"solid\" },\n { label: \"Gradient\", value: \"gradient\" },\n ],\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"overlayEnabled\",\n },\n {\n key: \"overlayIntensity\",\n label: \"Overlay Intensity\",\n type: \"slider\",\n description: \"Opacity of the overlay (0-100)\",\n min: 0,\n max: 100,\n step: 5,\n defaultValue: 50,\n unit: \"%\",\n tab: \"styling\",\n group: \"Design\",\n requiresKeyToBeTrue: \"overlayEnabled\",\n },\n // Styling tab - Nested Media Styling group\n getGapField({\n label: \"Gap\",\n defaultValue: \"md\",\n key: \"gap\",\n description: \"Gap between nested media items\",\n tab: \"styling\",\n group: \"Nested Design\",\n }),\n getColorField({\n defaultValue: \"foreground\",\n key: \"nestedTextColor\",\n label: \"Nested Text Color\",\n description: \"Color for nested media labels\",\n tab: \"styling\",\n group: \"Nested Design\",\n }),\n {\n type: \"background\",\n defaultValue: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background color for nested media container\",\n tab: \"styling\",\n group: \"Nested Design\",\n },\n // Data tab\n {\n key: \"dataSource\",\n label: \"Data Source\",\n type: \"dataSource\",\n description: \"Configure dynamic data fetching from an API\",\n tab: \"data\",\n group: \"Data Configuration\",\n },\n ],\n // Per-item configuration schema for custom data sources\n itemConfigSchema: {\n description: \"Configure settings for this item\",\n fields: [\n {\n key: \"title\",\n label: \"Custom Title\",\n type: \"text\",\n description: \"Override the item's title for this widget\",\n },\n ],\n },\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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ACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;IAAE,YAAY;IAAQ,UAAU;IAAU;GACxD,SAAS;IACP,mBAAmB;IACnB,iBAAiB;IAClB;GACD,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;EACD,gBAAgB;GACd,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF,qBAAqB;GACnB,cAAc;GACd,OAAO;GACP,KAAK;GACL,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,oBAAoB;GAClB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aACE;GACF,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,SAAS,CACP;IAAE,OAAO;IAAS,OAAO;IAAS,EAClC;IAAE,OAAO;IAAY,OAAO;IAAY,CACzC;GACD,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,KAAK;GACL,MAAM;GACN,cAAc;GACd,MAAM;GACN,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EAED,YAAY;GACV,OAAO;GACP,cAAc;GACd,KAAK;GACL,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF,cAAc;GACZ,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,MAAM;GACN,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR;EAED;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,KAAK;GACL,OAAO;GACR;EACF;CAED,kBAAkB;EAChB,aAAa;EACb,QAAQ,CACN;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACd,CACF;EACF;CACF"}
|
|
@@ -3,6 +3,6 @@ require("./WidgetInteractionContext-Bd1hEEV2.cjs");
|
|
|
3
3
|
require("./registries-CpUM406S.cjs");
|
|
4
4
|
require("./fields-C8gY9GlT.cjs");
|
|
5
5
|
require("./MediaRenderer-D4HnIAbN.cjs");
|
|
6
|
-
require("./scroll-arrows-
|
|
7
|
-
const require_NestedWidget = require("./NestedWidget-
|
|
6
|
+
require("./scroll-arrows-i0E2N-ct.cjs");
|
|
7
|
+
const require_NestedWidget = require("./NestedWidget-BjT-UrSi.cjs");
|
|
8
8
|
exports.nestedWidgetPropertySchema = require_NestedWidget.nestedWidgetPropertySchema;
|
package/dist/{PortalContentApiProvider-RXBp8FNj.cjs → PortalContentApiProvider-DXnplIOD.cjs}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-9hOWP6kD.cjs");
|
|
2
|
-
const require_portal_tenant_content = require("./portal_tenant_content-
|
|
2
|
+
const require_portal_tenant_content = require("./portal_tenant_content-BvYxmADB.cjs");
|
|
3
3
|
const require_PortalTenantClientProvider = require("./PortalTenantClientProvider-CVv-4rQ9.cjs");
|
|
4
4
|
const require_src = require("./src-aItPhUAR.cjs");
|
|
5
5
|
const require_ScreenHeaderContext = require("./ScreenHeaderContext-BXgWydjB.cjs");
|
|
@@ -288,6 +288,25 @@ const useUpdatePlaylistMutation = (options) => {
|
|
|
288
288
|
}
|
|
289
289
|
});
|
|
290
290
|
};
|
|
291
|
+
const useReorderPlaylistItemsMutation = (options) => {
|
|
292
|
+
const api = useShareablesApi();
|
|
293
|
+
const queryClient = (0, _tanstack_react_query.useQueryClient)();
|
|
294
|
+
return (0, _tanstack_react_query.useMutation)({
|
|
295
|
+
mutationFn: ({ playlistId, data }) => {
|
|
296
|
+
if (!api.playlists.reorderPlaylistItems) return Promise.resolve();
|
|
297
|
+
return api.playlists.reorderPlaylistItems(playlistId, data);
|
|
298
|
+
},
|
|
299
|
+
onSuccess: (_, { playlistId }) => {
|
|
300
|
+
if (api.playlists.reorderPlaylistItems) queryClient.invalidateQueries({ queryKey: shareablesKeys.playlists.detail(playlistId) });
|
|
301
|
+
options?.onSuccess?.(playlistId);
|
|
302
|
+
},
|
|
303
|
+
onError: (error, { playlistId }) => {
|
|
304
|
+
if (isCancellationError(error)) return;
|
|
305
|
+
console.error("Error reordering playlist items:", error);
|
|
306
|
+
options?.onError?.(error, playlistId);
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
};
|
|
291
310
|
//#endregion
|
|
292
311
|
//#region ../../shareables/ui/src/context.tsx
|
|
293
312
|
const MISSING_PROVIDER = Symbol("missing-shareables-provider");
|
|
@@ -578,6 +597,83 @@ function ShareableListLayout({ filters, children, isLoading, error, errorMessage
|
|
|
578
597
|
});
|
|
579
598
|
}
|
|
580
599
|
//#endregion
|
|
600
|
+
//#region ../../shareables/ui/src/components/shared/ShareableListRow.tsx
|
|
601
|
+
/**
|
|
602
|
+
* Container className for a list-view rendering of shareables. Pairs with
|
|
603
|
+
* `ShareableListRow` and mirrors `SHAREABLE_GRID_CLASS` for symmetry.
|
|
604
|
+
*/
|
|
605
|
+
const SHAREABLE_LIST_CLASS = "divide-border divide-y rounded-lg border";
|
|
606
|
+
/**
|
|
607
|
+
* Single row in a shareables list view. The row body (thumbnail + title) is
|
|
608
|
+
* a `<button>` for keyboard/click navigation; `leading` and `trailing` slots
|
|
609
|
+
* are siblings so their interactive elements don't nest inside the body
|
|
610
|
+
* button. Hover styling applies to the entire row container.
|
|
611
|
+
*/
|
|
612
|
+
function ShareableListRow({ imageUrl, imageAlt, title, subtitle, onClick, leading, trailing }) {
|
|
613
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
614
|
+
className: "hover:bg-muted flex items-center gap-3 px-4 py-3 transition-colors",
|
|
615
|
+
children: [
|
|
616
|
+
leading,
|
|
617
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
618
|
+
type: "button",
|
|
619
|
+
onClick,
|
|
620
|
+
className: "flex min-w-0 flex-1 items-center gap-4 text-left",
|
|
621
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
622
|
+
className: "bg-muted h-12 w-12 shrink-0 overflow-hidden rounded-md",
|
|
623
|
+
children: imageUrl ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
624
|
+
src: imageUrl,
|
|
625
|
+
alt: imageAlt ?? title,
|
|
626
|
+
className: "h-full w-full object-cover"
|
|
627
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "bg-muted h-full w-full" })
|
|
628
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
629
|
+
className: "min-w-0 flex-1",
|
|
630
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
631
|
+
className: "text-foreground truncate text-sm font-medium",
|
|
632
|
+
children: title || "Untitled"
|
|
633
|
+
}), subtitle != null && subtitle !== false && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
634
|
+
className: "text-muted-foreground flex items-center gap-1.5 text-xs",
|
|
635
|
+
children: subtitle
|
|
636
|
+
})]
|
|
637
|
+
})]
|
|
638
|
+
}),
|
|
639
|
+
trailing
|
|
640
|
+
]
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
//#endregion
|
|
644
|
+
//#region ../../shareables/ui/src/components/shared/ViewModeToggle.tsx
|
|
645
|
+
/**
|
|
646
|
+
* Segmented list/grid toggle used in the filter bar of every shareable
|
|
647
|
+
* listing screen. Stateless — callers own the `viewMode` state.
|
|
648
|
+
*/
|
|
649
|
+
function ViewModeToggle({ value, onChange }) {
|
|
650
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
651
|
+
className: "border-input bg-muted flex items-center rounded-lg border p-0.5",
|
|
652
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleButton, {
|
|
653
|
+
active: value === "list",
|
|
654
|
+
label: "List view",
|
|
655
|
+
onClick: () => onChange("list"),
|
|
656
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.List, { className: "h-4 w-4" })
|
|
657
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleButton, {
|
|
658
|
+
active: value === "grid",
|
|
659
|
+
label: "Grid view",
|
|
660
|
+
onClick: () => onChange("grid"),
|
|
661
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.LayoutGrid, { className: "h-4 w-4" })
|
|
662
|
+
})]
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
function ToggleButton({ active, label, onClick, children }) {
|
|
666
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
667
|
+
type: "button",
|
|
668
|
+
onClick,
|
|
669
|
+
title: label,
|
|
670
|
+
"aria-label": label,
|
|
671
|
+
"aria-pressed": active,
|
|
672
|
+
className: require_src.cn("flex h-8 w-8 items-center justify-center rounded-md transition-all", active ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"),
|
|
673
|
+
children
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
//#endregion
|
|
581
677
|
//#region ../../shareables/ui/src/components/screens/ProductsScreen.tsx
|
|
582
678
|
const PAGE_SIZE$4 = 24;
|
|
583
679
|
const SORT_OPTIONS$1 = [
|
|
@@ -608,6 +704,7 @@ const SORT_OPTIONS$1 = [
|
|
|
608
704
|
];
|
|
609
705
|
function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNavigate }) {
|
|
610
706
|
const client = useShareablesClient();
|
|
707
|
+
const { navigate } = useShareablesUI();
|
|
611
708
|
require_ScreenHeaderContext.useScreenHeaderBreadcrumbs((0, react.useMemo)(() => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Breadcrumb, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.BreadcrumbList, {
|
|
612
709
|
className: "text-lg",
|
|
613
710
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.BreadcrumbItem, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.BreadcrumbPage, {
|
|
@@ -618,6 +715,7 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
|
|
|
618
715
|
const [searchTerm, setSearchTerm] = (0, react.useState)("");
|
|
619
716
|
const [debouncedSearch, setDebouncedSearch] = (0, react.useState)("");
|
|
620
717
|
const [sortValue, setSortValue] = (0, react.useState)("created_at_desc");
|
|
718
|
+
const [viewMode, setViewMode] = (0, react.useState)("grid");
|
|
621
719
|
const observerTarget = (0, react.useRef)(null);
|
|
622
720
|
(0, react.useEffect)(() => {
|
|
623
721
|
const timer = setTimeout(() => {
|
|
@@ -705,9 +803,9 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
|
|
|
705
803
|
errorMessage: "Failed to load products. Please try again.",
|
|
706
804
|
isEmpty: products.length === 0,
|
|
707
805
|
emptyMessage: debouncedSearch ? "No products match your search." : "No products available.",
|
|
708
|
-
filters: /* @__PURE__ */ (0, react_jsx_runtime.
|
|
709
|
-
className: "flex justify-end",
|
|
710
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
806
|
+
filters: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
807
|
+
className: "flex items-center justify-end gap-2",
|
|
808
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
711
809
|
className: "w-full max-w-sm",
|
|
712
810
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SearchSort.SearchSort, {
|
|
713
811
|
searchValue: searchTerm,
|
|
@@ -717,14 +815,18 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
|
|
|
717
815
|
sortValue,
|
|
718
816
|
onSortChange: setSortValue
|
|
719
817
|
})
|
|
720
|
-
})
|
|
818
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ViewModeToggle, {
|
|
819
|
+
value: viewMode,
|
|
820
|
+
onChange: setViewMode
|
|
821
|
+
})]
|
|
721
822
|
}),
|
|
823
|
+
loadingFilterShape: "search-view",
|
|
722
824
|
footer: isFetchingNextPage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
723
825
|
className: "flex justify-center py-4",
|
|
724
826
|
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
827
|
}),
|
|
726
828
|
sentinelRef: observerTarget,
|
|
727
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
829
|
+
children: viewMode === "grid" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
728
830
|
className: SHAREABLE_GRID_CLASS,
|
|
729
831
|
children: products.map((product) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareProductCard, {
|
|
730
832
|
product: {
|
|
@@ -734,6 +836,14 @@ function ProductsScreen({ countryCode, fetchProducts: fetchPortalProducts, onNav
|
|
|
734
836
|
},
|
|
735
837
|
mediaCount: product.media_count
|
|
736
838
|
}, product.id))
|
|
839
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
840
|
+
className: SHAREABLE_LIST_CLASS,
|
|
841
|
+
children: products.map((product) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareableListRow, {
|
|
842
|
+
imageUrl: product.image_url,
|
|
843
|
+
title: product.title,
|
|
844
|
+
subtitle: product.media_count != null ? `${product.media_count} assets` : void 0,
|
|
845
|
+
onClick: () => navigate(`product/${product.id}`)
|
|
846
|
+
}, product.id))
|
|
737
847
|
})
|
|
738
848
|
});
|
|
739
849
|
}
|
|
@@ -1703,21 +1813,9 @@ function MediaListingScreen({ onNavigate }) {
|
|
|
1703
1813
|
}), kindFilter === opt.value && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Check, { className: "text-muted-foreground size-4" })]
|
|
1704
1814
|
}, opt.value))
|
|
1705
1815
|
})] }),
|
|
1706
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1707
|
-
|
|
1708
|
-
|
|
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
|
-
})]
|
|
1816
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ViewModeToggle, {
|
|
1817
|
+
value: viewMode,
|
|
1818
|
+
onChange: setViewMode
|
|
1721
1819
|
})
|
|
1722
1820
|
]
|
|
1723
1821
|
})]
|
|
@@ -1787,37 +1885,20 @@ function MediaListingScreen({ onNavigate }) {
|
|
|
1787
1885
|
}, item.id);
|
|
1788
1886
|
})
|
|
1789
1887
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1790
|
-
className:
|
|
1888
|
+
className: SHAREABLE_LIST_CLASS,
|
|
1791
1889
|
children: filteredItems.map((item) => {
|
|
1792
1890
|
const canEdit = !readOnly && item.owner_type === "user";
|
|
1793
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
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) })]
|
|
1891
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareableListRow, {
|
|
1892
|
+
imageUrl: item.image_url,
|
|
1893
|
+
imageAlt: item.title ?? "",
|
|
1894
|
+
title: item.title ?? "Untitled",
|
|
1895
|
+
subtitle: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [getMediaKindLabel(item.kind), item.owner_type === "user" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Badge, {
|
|
1896
|
+
variant: "secondary",
|
|
1897
|
+
className: "px-1.5 py-0 text-[10px] leading-4",
|
|
1898
|
+
children: "My Media"
|
|
1899
|
+
})] }),
|
|
1900
|
+
onClick: () => navigate(`media/${item.id}`),
|
|
1901
|
+
trailing: canEdit && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MediaRowActionsMenu, { onDelete: () => setPendingDeleteId(item.id) })
|
|
1821
1902
|
}, item.id);
|
|
1822
1903
|
})
|
|
1823
1904
|
})
|
|
@@ -8936,6 +9017,7 @@ function PlaylistsListingScreen(_props) {
|
|
|
8936
9017
|
const [debouncedSearch, setDebouncedSearch] = (0, react.useState)("");
|
|
8937
9018
|
const [sortValue, setSortValue] = (0, react.useState)("title");
|
|
8938
9019
|
const [ownerFilter, setOwnerFilter] = (0, react.useState)("all");
|
|
9020
|
+
const [viewMode, setViewMode] = (0, react.useState)("grid");
|
|
8939
9021
|
const [selectedIds, setSelectedIds] = (0, react.useState)(/* @__PURE__ */ new Set());
|
|
8940
9022
|
const [pendingDeleteId, setPendingDeleteId] = (0, react.useState)(null);
|
|
8941
9023
|
(0, react.useEffect)(() => {
|
|
@@ -9106,33 +9188,39 @@ function PlaylistsListingScreen(_props) {
|
|
|
9106
9188
|
value: ownerFilter,
|
|
9107
9189
|
onValueChange: setOwnerFilter,
|
|
9108
9190
|
myLabel: "My Playlists"
|
|
9109
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.
|
|
9110
|
-
className: "ml-auto
|
|
9111
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
9112
|
-
|
|
9113
|
-
|
|
9114
|
-
|
|
9115
|
-
|
|
9116
|
-
|
|
9117
|
-
|
|
9118
|
-
|
|
9119
|
-
|
|
9120
|
-
|
|
9121
|
-
|
|
9122
|
-
|
|
9123
|
-
|
|
9124
|
-
|
|
9125
|
-
|
|
9126
|
-
|
|
9127
|
-
|
|
9128
|
-
|
|
9129
|
-
|
|
9130
|
-
|
|
9131
|
-
|
|
9132
|
-
|
|
9133
|
-
|
|
9134
|
-
|
|
9135
|
-
|
|
9191
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9192
|
+
className: "ml-auto flex items-center gap-2",
|
|
9193
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9194
|
+
className: "w-full max-w-sm",
|
|
9195
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SearchSort.SearchSort, {
|
|
9196
|
+
searchValue: searchTerm,
|
|
9197
|
+
onSearchChange: setSearchTerm,
|
|
9198
|
+
placeholder: "Search playlists...",
|
|
9199
|
+
sortOptions: [
|
|
9200
|
+
{
|
|
9201
|
+
label: "Name (A-Z)",
|
|
9202
|
+
value: "title"
|
|
9203
|
+
},
|
|
9204
|
+
{
|
|
9205
|
+
label: "Name (Z-A)",
|
|
9206
|
+
value: "-title"
|
|
9207
|
+
},
|
|
9208
|
+
{
|
|
9209
|
+
label: "Date Created (Newest)",
|
|
9210
|
+
value: "-created_at"
|
|
9211
|
+
},
|
|
9212
|
+
{
|
|
9213
|
+
label: "Date Created (Oldest)",
|
|
9214
|
+
value: "created_at"
|
|
9215
|
+
}
|
|
9216
|
+
],
|
|
9217
|
+
sortValue,
|
|
9218
|
+
onSortChange: setSortValue
|
|
9219
|
+
})
|
|
9220
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ViewModeToggle, {
|
|
9221
|
+
value: viewMode,
|
|
9222
|
+
onChange: setViewMode
|
|
9223
|
+
})]
|
|
9136
9224
|
})]
|
|
9137
9225
|
});
|
|
9138
9226
|
const footer = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [isFetchingNextPage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -9154,8 +9242,8 @@ function PlaylistsListingScreen(_props) {
|
|
|
9154
9242
|
}),
|
|
9155
9243
|
footer,
|
|
9156
9244
|
sentinelRef: observerTarget,
|
|
9157
|
-
loadingFilterShape: "search-
|
|
9158
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9245
|
+
loadingFilterShape: "search-view",
|
|
9246
|
+
children: viewMode === "grid" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9159
9247
|
className: GRID_CLASS,
|
|
9160
9248
|
children: filteredPlaylists.map((playlist) => {
|
|
9161
9249
|
const firstItem = playlist.items?.[0];
|
|
@@ -9177,6 +9265,61 @@ function PlaylistsListingScreen(_props) {
|
|
|
9177
9265
|
onDelete: onDeletePlaylist ? () => setPendingDeleteId(playlist.id) : void 0
|
|
9178
9266
|
}, playlist.id);
|
|
9179
9267
|
})
|
|
9268
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9269
|
+
className: SHAREABLE_LIST_CLASS,
|
|
9270
|
+
children: filteredPlaylists.map((playlist) => {
|
|
9271
|
+
const firstItem = playlist.items?.[0];
|
|
9272
|
+
const imageUrl = playlist.image_url ?? firstItem?.image_url ?? firstItem?.relateable?.image_url ?? firstItem?.relateable?.compressed_image_url;
|
|
9273
|
+
const itemCount = playlist.items_count ?? playlist.items?.length ?? 0;
|
|
9274
|
+
const canEdit = !readOnly && playlist.user_id === user?.id;
|
|
9275
|
+
const isSelected = selectedIds.has(playlist.id);
|
|
9276
|
+
const title = playlist.title || "Untitled Playlist";
|
|
9277
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShareableListRow, {
|
|
9278
|
+
imageUrl,
|
|
9279
|
+
title,
|
|
9280
|
+
subtitle: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.Badge, {
|
|
9281
|
+
variant: "secondary",
|
|
9282
|
+
className: "px-1.5 py-0 text-[10px] leading-4",
|
|
9283
|
+
children: [
|
|
9284
|
+
itemCount,
|
|
9285
|
+
" ",
|
|
9286
|
+
itemCount === 1 ? "item" : "items"
|
|
9287
|
+
]
|
|
9288
|
+
}),
|
|
9289
|
+
onClick: () => navigate(`playlists/${playlist.id}`),
|
|
9290
|
+
leading: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Checkbox, {
|
|
9291
|
+
checked: isSelected,
|
|
9292
|
+
onCheckedChange: (checked) => handleToggleSelection(playlist.id, checked === true),
|
|
9293
|
+
"aria-label": `Select ${title}`
|
|
9294
|
+
}),
|
|
9295
|
+
trailing: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [onToggleFavorite && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9296
|
+
type: "button",
|
|
9297
|
+
onClick: () => handleFavorite(playlist.id),
|
|
9298
|
+
"aria-label": playlist.is_favorited ? "Unfavorite" : "Favorite",
|
|
9299
|
+
className: "hover:bg-muted-foreground/10 flex h-8 w-8 items-center justify-center rounded-md transition-colors",
|
|
9300
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Heart, { className: require_src.cn("h-4 w-4 transition-colors", playlist.is_favorited ? "fill-destructive text-destructive" : "text-muted-foreground") })
|
|
9301
|
+
}), canEdit && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.DropdownMenu, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.DropdownMenuTrigger, {
|
|
9302
|
+
asChild: true,
|
|
9303
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.Button, {
|
|
9304
|
+
variant: "ghost",
|
|
9305
|
+
size: "sm",
|
|
9306
|
+
className: "h-8 w-8 p-0",
|
|
9307
|
+
"aria-label": "Playlist actions",
|
|
9308
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.MoreVertical, { className: "h-4 w-4" })
|
|
9309
|
+
})
|
|
9310
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.DropdownMenuContent, {
|
|
9311
|
+
align: "end",
|
|
9312
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.DropdownMenuItem, {
|
|
9313
|
+
onClick: () => handleEdit(playlist.id),
|
|
9314
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Pencil, { className: "mr-2 h-4 w-4" }), "Edit"]
|
|
9315
|
+
}), onDeletePlaylist && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.DropdownMenuSeparator, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_src.DropdownMenuItem, {
|
|
9316
|
+
variant: "destructive",
|
|
9317
|
+
onClick: () => setPendingDeleteId(playlist.id),
|
|
9318
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Trash2, { className: "mr-2 h-4 w-4" }), "Delete"]
|
|
9319
|
+
})] })]
|
|
9320
|
+
})] })] })
|
|
9321
|
+
}, playlist.id);
|
|
9322
|
+
})
|
|
9180
9323
|
})
|
|
9181
9324
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_src.AlertDialog, {
|
|
9182
9325
|
open: pendingDeleteId !== null,
|
|
@@ -10065,6 +10208,7 @@ function SortableTable({ items, setItems, onDeleteItem, isDeletePending, enableR
|
|
|
10065
10208
|
}
|
|
10066
10209
|
//#endregion
|
|
10067
10210
|
//#region ../../shareables/ui/src/components/playlists/form/PlaylistItemsSection.tsx
|
|
10211
|
+
const REORDER_DEBOUNCE_MS = 500;
|
|
10068
10212
|
const PLAYLIST_CONTENT_TYPES = new Set([
|
|
10069
10213
|
"Medium",
|
|
10070
10214
|
"Page",
|
|
@@ -10134,9 +10278,53 @@ function PlaylistItemsSection({ playlistId }) {
|
|
|
10134
10278
|
});
|
|
10135
10279
|
}
|
|
10136
10280
|
});
|
|
10281
|
+
const reorderItemsMutation = useReorderPlaylistItemsMutation();
|
|
10282
|
+
const reorderTimerRef = (0, react.useRef)(null);
|
|
10283
|
+
const reorderRollbackRef = (0, react.useRef)(null);
|
|
10284
|
+
(0, react.useEffect)(() => () => {
|
|
10285
|
+
if (reorderTimerRef.current) clearTimeout(reorderTimerRef.current);
|
|
10286
|
+
}, []);
|
|
10287
|
+
const canPersistReorder = !!api.playlists.reorderPlaylistItems;
|
|
10137
10288
|
const mergeAndOrder = (0, react.useCallback)((reorderedContent) => {
|
|
10138
|
-
|
|
10139
|
-
|
|
10289
|
+
const ordered = computeOrderedItems([...reorderedContent, ...tailItems]);
|
|
10290
|
+
if (playlistId && canPersistReorder && reorderTimerRef.current === null && reorderRollbackRef.current === null) reorderRollbackRef.current = tableItems;
|
|
10291
|
+
updateItems(ordered);
|
|
10292
|
+
if (!playlistId || !canPersistReorder) return;
|
|
10293
|
+
if (reorderTimerRef.current) clearTimeout(reorderTimerRef.current);
|
|
10294
|
+
reorderTimerRef.current = setTimeout(() => {
|
|
10295
|
+
reorderTimerRef.current = null;
|
|
10296
|
+
const rollback = reorderRollbackRef.current;
|
|
10297
|
+
reorderItemsMutation.mutate({
|
|
10298
|
+
playlistId,
|
|
10299
|
+
data: { items: ordered.filter((item) => Number.isInteger(item.id) && typeof item.order === "number").map((item) => ({
|
|
10300
|
+
id: item.id,
|
|
10301
|
+
order: item.order
|
|
10302
|
+
})) }
|
|
10303
|
+
}, {
|
|
10304
|
+
onSuccess: () => {
|
|
10305
|
+
if (reorderTimerRef.current === null) reorderRollbackRef.current = null;
|
|
10306
|
+
else reorderRollbackRef.current = ordered;
|
|
10307
|
+
},
|
|
10308
|
+
onError: (error) => {
|
|
10309
|
+
if (rollback) updateItems(rollback);
|
|
10310
|
+
reorderRollbackRef.current = null;
|
|
10311
|
+
showToast({
|
|
10312
|
+
title: "Failed to save new item order",
|
|
10313
|
+
type: "error",
|
|
10314
|
+
error
|
|
10315
|
+
});
|
|
10316
|
+
}
|
|
10317
|
+
});
|
|
10318
|
+
}, REORDER_DEBOUNCE_MS);
|
|
10319
|
+
}, [
|
|
10320
|
+
tailItems,
|
|
10321
|
+
tableItems,
|
|
10322
|
+
updateItems,
|
|
10323
|
+
playlistId,
|
|
10324
|
+
canPersistReorder,
|
|
10325
|
+
reorderItemsMutation.mutate,
|
|
10326
|
+
showToast
|
|
10327
|
+
]);
|
|
10140
10328
|
const handleDeleteItem = (itemId) => {
|
|
10141
10329
|
removeItem(itemId);
|
|
10142
10330
|
if (playlistId) removeItemMutation.mutate({
|
|
@@ -11490,6 +11678,9 @@ function createPlaylistsAdapter(client) {
|
|
|
11490
11678
|
items: [],
|
|
11491
11679
|
items_count: 0
|
|
11492
11680
|
};
|
|
11681
|
+
},
|
|
11682
|
+
reorderPlaylistItems: async (playlistId, data) => {
|
|
11683
|
+
await require_portal_tenant_content.playlists_items_reorder(client, playlistId, { items: data.items });
|
|
11493
11684
|
}
|
|
11494
11685
|
};
|
|
11495
11686
|
}
|
|
@@ -11905,4 +12096,4 @@ Object.defineProperty(exports, "usePortalContentContext", {
|
|
|
11905
12096
|
}
|
|
11906
12097
|
});
|
|
11907
12098
|
|
|
11908
|
-
//# sourceMappingURL=PortalContentApiProvider-
|
|
12099
|
+
//# sourceMappingURL=PortalContentApiProvider-DXnplIOD.cjs.map
|