@fluid-app/rep-widgets 0.1.18 → 0.1.20
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/AlertWidget-CiMRJYmn.mjs.map +1 -1
- package/dist/AlertWidget-DU_HP0EW.cjs.map +1 -1
- package/dist/CalendarWidget-DshBk5tG.mjs.map +1 -1
- package/dist/CalendarWidget-s7KgQ5JD.cjs.map +1 -1
- package/dist/CarouselWidget-0RP-Rd1D.mjs.map +1 -1
- package/dist/CarouselWidget-DLADgLPJ.cjs.map +1 -1
- package/dist/CatchUpWidget-CUnCumIf.mjs.map +1 -1
- package/dist/CatchUpWidget-DiqdwPvE.cjs.map +1 -1
- package/dist/ChartWidget-DhAVW8w4.cjs.map +1 -1
- package/dist/ChartWidget-DrF1e1sy.mjs.map +1 -1
- package/dist/ContainerWidget-8FdPHgLz.cjs +2 -0
- package/dist/{ContainerWidget-Cp0_vPZB.cjs → ContainerWidget-BTKOl5XX.cjs} +3 -13
- package/dist/ContainerWidget-BTKOl5XX.cjs.map +1 -0
- package/dist/ContainerWidget-Xd231yys.mjs.map +1 -1
- package/dist/{EmbedWidget-BQyYm50g.cjs → EmbedWidget-Cfv65pBr.cjs} +1 -1
- package/dist/EmbedWidget-Cfv65pBr.cjs.map +1 -0
- package/dist/EmbedWidget-DQ2rCA4j.mjs.map +1 -1
- package/dist/{ImageWidget-DTwM7xCz.cjs → ImageWidget-BXkjWEEn.cjs} +1 -1
- package/dist/ImageWidget-BXkjWEEn.cjs.map +1 -0
- package/dist/ImageWidget-DBBul7ca.mjs.map +1 -1
- package/dist/LayoutWidget-B1itwSsn.mjs.map +1 -1
- package/dist/{LayoutWidget-CWE_9JB5.cjs → LayoutWidget-BVv--tp3.cjs} +5 -15
- package/dist/LayoutWidget-BVv--tp3.cjs.map +1 -0
- package/dist/LayoutWidget-BsOPpmVb.cjs +2 -0
- package/dist/{ListWidget-CxaLm0D5.cjs → ListWidget-ByLHcRHL.cjs} +1 -1
- package/dist/ListWidget-ByLHcRHL.cjs.map +1 -0
- package/dist/ListWidget-EXPlzfUE.mjs.map +1 -1
- package/dist/MediaRenderer-CcJvyOJ1.cjs.map +1 -1
- package/dist/MediaRenderer-Uq90PZcY.mjs.map +1 -1
- package/dist/MySiteWidget-BTyb5AJM.mjs.map +1 -1
- package/dist/{MySiteWidget-iRPl6b2F.cjs → MySiteWidget-DrUI7OTT.cjs} +1 -1
- package/dist/MySiteWidget-DrUI7OTT.cjs.map +1 -0
- package/dist/{NestedWidget-DavPMVii.cjs → NestedWidget-CbuuxK7U.cjs} +1 -1
- package/dist/NestedWidget-CbuuxK7U.cjs.map +1 -0
- package/dist/NestedWidget-CwyVsZ-f.mjs.map +1 -1
- package/dist/QuickShareWidget-BUbuTQFQ.mjs.map +1 -1
- package/dist/{QuickShareWidget-BIOkquPG.cjs → QuickShareWidget-DjhPbMsy.cjs} +1 -1
- package/dist/QuickShareWidget-DjhPbMsy.cjs.map +1 -0
- package/dist/{RecentActivityWidget-u1zCrwGF.cjs → RecentActivityWidget-BPs8xmPD.cjs} +1 -1
- package/dist/RecentActivityWidget-BPs8xmPD.cjs.map +1 -0
- package/dist/RecentActivityWidget-CxEgRz3c.mjs.map +1 -1
- package/dist/RegistryContext-CscXrsRa.mjs.map +1 -1
- package/dist/{RegistryContext-6KXd4t6d.cjs → RegistryContext-xjea4xVV.cjs} +3 -2
- package/dist/RegistryContext-xjea4xVV.cjs.map +1 -0
- package/dist/{ScreenRenderer-BCd4Rsba.cjs → ScreenRenderer-B-nGFObe.cjs} +2 -2
- package/dist/ScreenRenderer-B-nGFObe.cjs.map +1 -0
- package/dist/ScreenRenderer-CVJMpQ9A.mjs.map +1 -1
- package/dist/{ScreenRendererContext-D62_Fazh.cjs → ScreenRendererContext-B660JoZO.cjs} +3 -2
- package/dist/ScreenRendererContext-B660JoZO.cjs.map +1 -0
- package/dist/ScreenRendererContext-DaldtZnX.mjs.map +1 -1
- package/dist/SpacerWidget-Bs18KYH9.mjs.map +1 -1
- package/dist/{SpacerWidget-D-Foe9wG.cjs → SpacerWidget-DGccATXA.cjs} +1 -1
- package/dist/SpacerWidget-DGccATXA.cjs.map +1 -0
- package/dist/TableWidget-Cc4kQaOE.mjs.map +1 -1
- package/dist/{TableWidget-BeG92tkU.cjs → TableWidget-GSCLhWDu.cjs} +1 -1
- package/dist/TableWidget-GSCLhWDu.cjs.map +1 -0
- package/dist/TextWidget-CQxOWNZK.mjs.map +1 -1
- package/dist/TextWidget-Cn7-yZGk.cjs.map +1 -1
- package/dist/ToDoWidget--KBpHqbA.mjs.map +1 -1
- package/dist/{ToDoWidget-CK87BavM.cjs → ToDoWidget-B4Lrb4FT.cjs} +1 -1
- package/dist/ToDoWidget-B4Lrb4FT.cjs.map +1 -0
- package/dist/{VideoWidget-DxuqyD5L.cjs → VideoWidget-CiydQ4xO.cjs} +1 -1
- package/dist/VideoWidget-CiydQ4xO.cjs.map +1 -0
- package/dist/VideoWidget-uKkRf5pm.mjs.map +1 -1
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.cts +2 -2
- package/dist/components/index.d.cts.map +1 -1
- package/dist/components/index.d.mts +2 -2
- package/dist/components/index.d.mts.map +1 -1
- package/dist/components/index.mjs.map +1 -1
- package/dist/contexts/index.cjs +2 -2
- package/dist/contexts/index.d.cts +40 -42
- package/dist/contexts/index.d.cts.map +1 -1
- package/dist/contexts/index.d.mts +40 -42
- package/dist/contexts/index.d.mts.map +1 -1
- package/dist/core/index.cjs +1 -1
- package/dist/core/index.d.cts +30 -31
- package/dist/core/index.d.cts.map +1 -1
- package/dist/core/index.d.mts +30 -31
- package/dist/core/index.d.mts.map +1 -1
- package/dist/error-state-DErSxZwH.mjs.map +1 -1
- package/dist/error-state-DSzVUtEl.cjs.map +1 -1
- package/dist/scroll-arrows-BZIlsE_x.cjs.map +1 -1
- package/dist/scroll-arrows-BevCYRNT.mjs.map +1 -1
- package/dist/ui/index.d.cts +2 -2
- package/dist/ui/index.d.cts.map +1 -1
- package/dist/ui/index.d.mts +2 -2
- package/dist/ui/index.d.mts.map +1 -1
- package/dist/widgets/index.cjs +26 -26
- package/dist/widgets/index.cjs.map +1 -1
- package/dist/widgets/index.d.cts +53 -256
- package/dist/widgets/index.d.cts.map +1 -1
- package/dist/widgets/index.d.mts +53 -256
- package/dist/widgets/index.d.mts.map +1 -1
- package/dist/widgets/index.mjs.map +1 -1
- package/package.json +6 -6
- package/{styles → src/styles}/globals.css +4 -2
- package/src/styles/index.ts +1 -0
- package/dist/ContainerWidget-Cp0_vPZB.cjs.map +0 -1
- package/dist/EmbedWidget-BQyYm50g.cjs.map +0 -1
- package/dist/ImageWidget-DTwM7xCz.cjs.map +0 -1
- package/dist/LayoutWidget-CWE_9JB5.cjs.map +0 -1
- package/dist/ListWidget-CxaLm0D5.cjs.map +0 -1
- package/dist/MySiteWidget-iRPl6b2F.cjs.map +0 -1
- package/dist/NestedWidget-DavPMVii.cjs.map +0 -1
- package/dist/QuickShareWidget-BIOkquPG.cjs.map +0 -1
- package/dist/RecentActivityWidget-u1zCrwGF.cjs.map +0 -1
- package/dist/RegistryContext-6KXd4t6d.cjs.map +0 -1
- package/dist/ScreenRenderer-BCd4Rsba.cjs.map +0 -1
- package/dist/ScreenRendererContext-D62_Fazh.cjs.map +0 -1
- package/dist/SpacerWidget-D-Foe9wG.cjs.map +0 -1
- package/dist/TableWidget-BeG92tkU.cjs.map +0 -1
- package/dist/ToDoWidget-CK87BavM.cjs.map +0 -1
- package/dist/VideoWidget-DxuqyD5L.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MediaRenderer-Uq90PZcY.mjs","names":[],"sources":["../src/components/MediaRenderer.tsx"],"sourcesContent":["import { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\nimport { faImage, faVideo } from \"@fortawesome/pro-regular-svg-icons\";\nimport type { ShareableItem, WidgetSchema } from \"@fluid-app/rep-core/types\";\n\nexport type MediaRendererProps = {\n src?: string | undefined;\n alt?: string | undefined;\n objectFit?: \"contain\" | \"cover\" | \"fill\" | \"none\" | undefined;\n focusPoint?: string | undefined;\n mediaType?: \"image\" | \"video\" | undefined;\n poster?: string | undefined;\n autoplay?: boolean | undefined;\n loop?: boolean | undefined;\n muted?: boolean | undefined;\n controls?: boolean | undefined;\n};\n\nexport function MediaRenderer({\n src,\n alt = \"Media\",\n objectFit = \"cover\",\n focusPoint,\n mediaType = \"image\",\n poster,\n autoplay = false,\n loop = false,\n muted = false,\n controls = true,\n}: MediaRendererProps) {\n const hasValidSrc = src && src.trim() !== \"\";\n const objectPosition = focusPoint?.replace(\"-\", \" \");\n\n if (!hasValidSrc) {\n const icon = mediaType === \"video\" ? faVideo : faImage;\n const label =\n mediaType === \"video\" ? \"No video selected\" : \"No image selected\";\n return (\n <div className=\"bg-muted flex h-full min-h-[200px] w-full items-center justify-center\">\n <div className=\"text-muted-foreground flex flex-col items-center gap-2\">\n <FontAwesomeIcon icon={icon} className=\"h-12 w-12\" />\n <p className=\"text-sm\">{label}</p>\n </div>\n </div>\n );\n }\n\n const isContainMode = objectFit === \"contain\";\n const blurSrc = isContainMode ? `${src}?tr=bl-50` : undefined;\n\n if (mediaType === \"video\") {\n const blurredBgSrc = isContainMode\n ? poster\n ? `${poster}?tr=bl-50`\n : blurSrc\n : undefined;\n\n if (isContainMode && blurredBgSrc) {\n return (\n <div className=\"relative h-full w-full overflow-hidden\">\n <img\n src={blurredBgSrc}\n alt=\"\"\n className=\"absolute inset-0 h-full w-full object-cover\"\n aria-hidden=\"true\"\n />\n <div className=\"absolute inset-0 bg-black/30\" aria-hidden=\"true\" />\n <video\n src={src}\n poster={poster}\n controls={controls}\n autoPlay={autoplay}\n loop={loop}\n muted={muted}\n className={`relative z-10 h-full w-full object-contain ${!controls ? \"pointer-events-none\" : \"\"}`}\n >\n Your browser does not support the video tag.\n </video>\n </div>\n );\n }\n\n return (\n <video\n src={src}\n poster={poster}\n controls={controls}\n autoPlay={autoplay}\n loop={loop}\n muted={muted}\n className={`h-full w-full object-${objectFit} ${!controls ? \"pointer-events-none\" : \"\"}`}\n style={objectPosition ? { objectPosition } : undefined}\n >\n Your browser does not support the video tag.\n </video>\n );\n }\n\n if (isContainMode) {\n return (\n <div className=\"relative h-full w-full overflow-hidden\">\n <img\n src={blurSrc}\n alt=\"\"\n className=\"absolute inset-0 h-full w-full object-cover\"\n aria-hidden=\"true\"\n />\n <div className=\"absolute inset-0 bg-black/30\" aria-hidden=\"true\" />\n <img\n src={src}\n alt={alt}\n className=\"relative z-10 h-full w-full object-contain\"\n />\n </div>\n );\n }\n\n return (\n <img\n src={src}\n alt={alt}\n className={`h-full w-full object-${objectFit}`}\n style={objectPosition ? { objectPosition } : undefined}\n />\n );\n}\n\n/**\n * Converts a ShareableItem to MediaRenderer props.\n * Replaces the createWidgetFromShareable → ScreenRenderer pattern.\n */\nexport function getMediaPropsFromShareable(\n item: ShareableItem,\n): MediaRendererProps {\n const isVideo = item.kind === \"video\" || !!item.videoUrl;\n\n if (isVideo && item.videoUrl) {\n const result: MediaRendererProps = {\n mediaType: \"video\",\n src: item.videoUrl,\n alt: item.title ?? \"Video\",\n };\n if (item.imageUrl != null) result.poster = item.imageUrl;\n return result;\n }\n\n const result: MediaRendererProps = {\n mediaType: \"image\",\n alt: item.title || \"Image\",\n objectFit: \"cover\",\n };\n if (item.imageUrl != null) result.src = item.imageUrl;\n return result;\n}\n\n/**\n * Extracts media props from an ImageWidget/VideoWidget schema.\n * Used by CarouselWidget for slide.content rendering.\n */\nexport function getMediaPropsFromWidgetSchema(\n schema: WidgetSchema,\n): MediaRendererProps {\n const props = schema.props;\n\n const resource = props.resource as ShareableItem | undefined;\n const useCustomUrl = props.useCustomUrl as boolean | undefined;\n const focusPoint = props.focusPoint as string | undefined;\n const displayFit = props.displayFit as\n | MediaRendererProps[\"objectFit\"]\n | undefined;\n\n if (schema.type === \"VideoWidget\") {\n const result: MediaRendererProps = {\n mediaType: \"video\",\n autoplay: (props.autoplay as boolean | undefined) ?? false,\n loop: (props.loop as boolean | undefined) ?? false,\n muted: (props.muted as boolean | undefined) ?? false,\n controls: (props.controls as boolean | undefined) ?? true,\n objectFit: displayFit ?? \"cover\",\n focusPoint,\n };\n if (useCustomUrl) {\n if (typeof props.src === \"string\") result.src = props.src;\n if (typeof props.poster === \"string\") result.poster = props.poster;\n } else if (resource) {\n if (resource.videoUrl) result.src = resource.videoUrl;\n else if (typeof props.src === \"string\") result.src = props.src;\n if (resource.imageUrl) result.poster = resource.imageUrl;\n else if (typeof props.poster === \"string\") result.poster = props.poster;\n } else {\n if (typeof props.src === \"string\") result.src = props.src;\n if (typeof props.poster === \"string\") result.poster = props.poster;\n }\n return result;\n }\n\n const result: MediaRendererProps = {\n mediaType: \"image\",\n alt: (props.alt as string | undefined) ?? \"Image\",\n objectFit: displayFit ?? \"cover\",\n focusPoint,\n };\n if (useCustomUrl) {\n if (typeof props.src === \"string\") result.src = props.src;\n } else if (resource) {\n if (resource.imageUrl) result.src = resource.imageUrl;\n else if (typeof props.src === \"string\") result.src = props.src;\n if (resource.title) result.alt = resource.title;\n } else {\n if (typeof props.src === \"string\") result.src = props.src;\n }\n return result;\n}\n"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"MediaRenderer-Uq90PZcY.mjs","names":[],"sources":["../src/components/MediaRenderer.tsx"],"sourcesContent":["import type React from \"react\";\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\nimport { faImage, faVideo } from \"@fortawesome/pro-regular-svg-icons\";\nimport type { ShareableItem, WidgetSchema } from \"@fluid-app/rep-core/types\";\n\nexport type MediaRendererProps = {\n src?: string | undefined;\n alt?: string | undefined;\n objectFit?: \"contain\" | \"cover\" | \"fill\" | \"none\" | undefined;\n focusPoint?: string | undefined;\n mediaType?: \"image\" | \"video\" | undefined;\n poster?: string | undefined;\n autoplay?: boolean | undefined;\n loop?: boolean | undefined;\n muted?: boolean | undefined;\n controls?: boolean | undefined;\n};\n\nexport function MediaRenderer({\n src,\n alt = \"Media\",\n objectFit = \"cover\",\n focusPoint,\n mediaType = \"image\",\n poster,\n autoplay = false,\n loop = false,\n muted = false,\n controls = true,\n}: MediaRendererProps): React.JSX.Element {\n const hasValidSrc = src && src.trim() !== \"\";\n const objectPosition = focusPoint?.replace(\"-\", \" \");\n\n if (!hasValidSrc) {\n const icon = mediaType === \"video\" ? faVideo : faImage;\n const label =\n mediaType === \"video\" ? \"No video selected\" : \"No image selected\";\n return (\n <div className=\"bg-muted flex h-full min-h-[200px] w-full items-center justify-center\">\n <div className=\"text-muted-foreground flex flex-col items-center gap-2\">\n <FontAwesomeIcon icon={icon} className=\"h-12 w-12\" />\n <p className=\"text-sm\">{label}</p>\n </div>\n </div>\n );\n }\n\n const isContainMode = objectFit === \"contain\";\n const blurSrc = isContainMode ? `${src}?tr=bl-50` : undefined;\n\n if (mediaType === \"video\") {\n const blurredBgSrc = isContainMode\n ? poster\n ? `${poster}?tr=bl-50`\n : blurSrc\n : undefined;\n\n if (isContainMode && blurredBgSrc) {\n return (\n <div className=\"relative h-full w-full overflow-hidden\">\n <img\n src={blurredBgSrc}\n alt=\"\"\n className=\"absolute inset-0 h-full w-full object-cover\"\n aria-hidden=\"true\"\n />\n <div className=\"absolute inset-0 bg-black/30\" aria-hidden=\"true\" />\n <video\n src={src}\n poster={poster}\n controls={controls}\n autoPlay={autoplay}\n loop={loop}\n muted={muted}\n className={`relative z-10 h-full w-full object-contain ${!controls ? \"pointer-events-none\" : \"\"}`}\n >\n Your browser does not support the video tag.\n </video>\n </div>\n );\n }\n\n return (\n <video\n src={src}\n poster={poster}\n controls={controls}\n autoPlay={autoplay}\n loop={loop}\n muted={muted}\n className={`h-full w-full object-${objectFit} ${!controls ? \"pointer-events-none\" : \"\"}`}\n style={objectPosition ? { objectPosition } : undefined}\n >\n Your browser does not support the video tag.\n </video>\n );\n }\n\n if (isContainMode) {\n return (\n <div className=\"relative h-full w-full overflow-hidden\">\n <img\n src={blurSrc}\n alt=\"\"\n className=\"absolute inset-0 h-full w-full object-cover\"\n aria-hidden=\"true\"\n />\n <div className=\"absolute inset-0 bg-black/30\" aria-hidden=\"true\" />\n <img\n src={src}\n alt={alt}\n className=\"relative z-10 h-full w-full object-contain\"\n />\n </div>\n );\n }\n\n return (\n <img\n src={src}\n alt={alt}\n className={`h-full w-full object-${objectFit}`}\n style={objectPosition ? { objectPosition } : undefined}\n />\n );\n}\n\n/**\n * Converts a ShareableItem to MediaRenderer props.\n * Replaces the createWidgetFromShareable → ScreenRenderer pattern.\n */\nexport function getMediaPropsFromShareable(\n item: ShareableItem,\n): MediaRendererProps {\n const isVideo = item.kind === \"video\" || !!item.videoUrl;\n\n if (isVideo && item.videoUrl) {\n const result: MediaRendererProps = {\n mediaType: \"video\",\n src: item.videoUrl,\n alt: item.title ?? \"Video\",\n };\n if (item.imageUrl != null) result.poster = item.imageUrl;\n return result;\n }\n\n const result: MediaRendererProps = {\n mediaType: \"image\",\n alt: item.title || \"Image\",\n objectFit: \"cover\",\n };\n if (item.imageUrl != null) result.src = item.imageUrl;\n return result;\n}\n\n/**\n * Extracts media props from an ImageWidget/VideoWidget schema.\n * Used by CarouselWidget for slide.content rendering.\n */\nexport function getMediaPropsFromWidgetSchema(\n schema: WidgetSchema,\n): MediaRendererProps {\n const props = schema.props;\n\n const resource = props.resource as ShareableItem | undefined;\n const useCustomUrl = props.useCustomUrl as boolean | undefined;\n const focusPoint = props.focusPoint as string | undefined;\n const displayFit = props.displayFit as\n | MediaRendererProps[\"objectFit\"]\n | undefined;\n\n if (schema.type === \"VideoWidget\") {\n const result: MediaRendererProps = {\n mediaType: \"video\",\n autoplay: (props.autoplay as boolean | undefined) ?? false,\n loop: (props.loop as boolean | undefined) ?? false,\n muted: (props.muted as boolean | undefined) ?? false,\n controls: (props.controls as boolean | undefined) ?? true,\n objectFit: displayFit ?? \"cover\",\n focusPoint,\n };\n if (useCustomUrl) {\n if (typeof props.src === \"string\") result.src = props.src;\n if (typeof props.poster === \"string\") result.poster = props.poster;\n } else if (resource) {\n if (resource.videoUrl) result.src = resource.videoUrl;\n else if (typeof props.src === \"string\") result.src = props.src;\n if (resource.imageUrl) result.poster = resource.imageUrl;\n else if (typeof props.poster === \"string\") result.poster = props.poster;\n } else {\n if (typeof props.src === \"string\") result.src = props.src;\n if (typeof props.poster === \"string\") result.poster = props.poster;\n }\n return result;\n }\n\n const result: MediaRendererProps = {\n mediaType: \"image\",\n alt: (props.alt as string | undefined) ?? \"Image\",\n objectFit: displayFit ?? \"cover\",\n focusPoint,\n };\n if (useCustomUrl) {\n if (typeof props.src === \"string\") result.src = props.src;\n } else if (resource) {\n if (resource.imageUrl) result.src = resource.imageUrl;\n else if (typeof props.src === \"string\") result.src = props.src;\n if (resource.title) result.alt = resource.title;\n } else {\n if (typeof props.src === \"string\") result.src = props.src;\n }\n return result;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MySiteWidget-BTyb5AJM.mjs","names":[],"sources":["../src/hooks/use-mysite.preview.ts","../src/hooks/use-mysite.ts","../src/widgets/MySiteWidget.tsx"],"sourcesContent":["import type { MySiteData } from \"./use-mysite.types\";\n\nexport const PREVIEW_DATA: MySiteData = {\n url: \"https://mysite.example.com\",\n views: 1248,\n leads: 43,\n userName: \"Jane\",\n};\n","import { useQuery } from \"@tanstack/react-query\";\nimport { useDataSourceConfig } from \"@fluid-app/rep-core/data-sources/context\";\nimport { useWidgetPreviewContext } from \"@fluid-app/rep-core/data-sources/preview-context\";\nimport { PREVIEW_DATA } from \"./use-mysite.preview\";\n\nimport type { MySiteData } from \"./use-mysite.types\";\n\nexport type { MySiteData } from \"./use-mysite.types\";\n\nexport function useMySite() {\n const { baseUrl, getApiHeaders } = useDataSourceConfig();\n const { isPreview } = useWidgetPreviewContext();\n\n return useQuery({\n queryKey: [\n \"rep-widget-use\",\n \"mysite\",\n isPreview ? \"preview\" : baseUrl,\n ] as const,\n queryFn: async ({ signal }): Promise<MySiteData> => {\n const url = baseUrl ? `${baseUrl}/me` : \"/me\";\n const response = await fetch(url, {\n headers: {\n \"content-type\": \"application/json\",\n ...getApiHeaders?.(),\n },\n signal,\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch MySite data: ${response.status}`);\n }\n\n const data = await response.json();\n return {\n url: data.mysite_url ?? null,\n views: data.mysite_views ?? 0,\n leads: data.mysite_leads ?? 0,\n userName: data.name || data.first_name || \"User\",\n };\n },\n enabled: !isPreview,\n ...(isPreview && { placeholderData: PREVIEW_DATA }),\n });\n}\n","import { useMemo, type ComponentProps } from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/rep-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/rep-core/registries\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport { useMySite } from \"../hooks/use-mysite\";\nimport { ErrorState } from \"../components/error-state\";\n\ntype MySiteWidgetProps = ComponentProps<\"div\"> & {\n // Title settings\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Design settings\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n\n // Display settings\n showPreview?: boolean;\n showAnalytics?: boolean;\n};\n\nexport function MySiteWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"My Site\",\n titleFontSize = \"lg\",\n titleColor = \"foreground\",\n\n // Design defaults\n background = {\n type: \"solid\",\n color: \"background\",\n },\n textColor = \"foreground\",\n accentColor = \"primary\",\n padding = 4,\n borderRadius = \"md\",\n\n // Display defaults\n showPreview = true,\n showAnalytics = true,\n\n className,\n ...props\n}: MySiteWidgetProps) {\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 const { data: mySite, isLoading, isError } = useMySite();\n\n // Generate preview URL with preview=true parameter\n const previewUrl = useMemo(() => {\n if (!mySite?.url) return \"\";\n try {\n const urlObj = new URL(mySite.url);\n urlObj.searchParams.set(\"preview\", \"true\");\n return urlObj.toString();\n } catch {\n return mySite.url;\n }\n }, [mySite?.url]);\n\n // Display URL without protocol\n const displayUrl = useMemo(\n () => (mySite?.url ? mySite.url.replace(/^https?:\\/\\//, \"\") : \"\"),\n [mySite?.url],\n );\n\n // Don't render if no MySite URL exists (but still render if errored or loading)\n if (!isLoading && !isError && !mySite?.url) {\n return null;\n }\n\n return (\n <div\n className={`@container overflow-hidden rounded-${borderRadius} bg-${backgroundColor} text-${textColor} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n {/* Title */}\n {titleEnabled && titleText && (\n <div className={`p-${padding} pb-0`}>\n <h2 className={`text-${titleFontSize} font-bold text-${titleColor}`}>\n {mySite?.userName ? `${mySite.userName}'s ${titleText}` : titleText}\n </h2>\n </div>\n )}\n\n {/* Loading state */}\n {isLoading ? (\n <div\n className={`flex min-h-[200px] items-center justify-center p-${padding}`}\n >\n <div className=\"h-8 w-8 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n </div>\n ) : isError ? (\n <ErrorState />\n ) : (\n <div className={`p-${padding}`}>\n {/* MySite iframe preview */}\n {showPreview && (\n <div className=\"border-muted mb-4 overflow-hidden rounded-lg border\">\n {/* Browser chrome */}\n <div className=\"bg-[#f3f4f6] px-3 py-2 text-[#6b7280]\">\n <div className=\"flex items-center gap-2\">\n <div className=\"flex gap-1\">\n <div className=\"h-3 w-3 rounded-full bg-[#ff5f57]\" />\n <div className=\"h-3 w-3 rounded-full bg-[#febc2e]\" />\n <div className=\"h-3 w-3 rounded-full bg-[#28c840]\" />\n </div>\n <div className=\"flex-1 text-center\">\n <a\n href={mySite?.url ?? \"\"}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm opacity-60\"\n >\n {displayUrl}\n </a>\n </div>\n </div>\n </div>\n {/* iframe container */}\n <div className=\"h-[200px] overflow-hidden bg-[#ffffff] @md:h-[280px]\">\n <iframe\n className=\"pointer-events-none h-[700%] w-[700%] origin-top-left scale-[0.14] bg-[#ffffff]\"\n src={previewUrl}\n title=\"MySite Preview\"\n />\n </div>\n </div>\n )}\n\n {/* Analytics data */}\n {showAnalytics && (\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"border-muted bg-background rounded-lg border p-3\">\n <div className=\"text-xs opacity-60\">Visitors This Month</div>\n <div className={`text-xl font-bold text-${accentColor}`}>\n {mySite?.views ?? 0}\n </div>\n </div>\n <div className=\"border-muted bg-background rounded-lg border p-3\">\n <div className=\"text-xs opacity-60\">Total Leads</div>\n <div className={`text-xl font-bold text-${accentColor}`}>\n {mySite?.leads ?? 0}\n </div>\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n\nexport const mySiteWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"MySiteWidget\",\n displayName: \"MySite Widget\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [\n // Styling Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the widget\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the widget\",\n defaultValue: \"My Site\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleFontSize\",\n label: \"Title Font Size\",\n description: \"Font size for the widget title\",\n defaultValue: \"xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling Tab - Design Group\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the widget container\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for widget content\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description: \"Color used for analytics numbers\",\n defaultValue: \"primary\",\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 getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the widget container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the widget container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n\n // Styling Tab - Display Group\n {\n key: \"showPreview\",\n label: \"Show Preview\",\n type: \"boolean\",\n description: \"Show the MySite iframe preview\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Display\",\n },\n {\n key: \"showAnalytics\",\n label: \"Show Analytics\",\n type: \"boolean\",\n description: \"Show the analytics section\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Display\",\n },\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MySiteWidget-BTyb5AJM.mjs","names":[],"sources":["../src/hooks/use-mysite.preview.ts","../src/hooks/use-mysite.ts","../src/widgets/MySiteWidget.tsx"],"sourcesContent":["import type { MySiteData } from \"./use-mysite.types\";\n\nexport const PREVIEW_DATA: MySiteData = {\n url: \"https://mysite.example.com\",\n views: 1248,\n leads: 43,\n userName: \"Jane\",\n};\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useDataSourceConfig } from \"@fluid-app/rep-core/data-sources/context\";\nimport { useWidgetPreviewContext } from \"@fluid-app/rep-core/data-sources/preview-context\";\nimport { PREVIEW_DATA } from \"./use-mysite.preview\";\n\nimport type { MySiteData } from \"./use-mysite.types\";\n\nexport type { MySiteData } from \"./use-mysite.types\";\n\nexport function useMySite(): UseQueryResult<MySiteData, Error> {\n const { baseUrl, getApiHeaders } = useDataSourceConfig();\n const { isPreview } = useWidgetPreviewContext();\n\n return useQuery({\n queryKey: [\n \"rep-widget-use\",\n \"mysite\",\n isPreview ? \"preview\" : baseUrl,\n ] as const,\n queryFn: async ({ signal }): Promise<MySiteData> => {\n const url = baseUrl ? `${baseUrl}/me` : \"/me\";\n const response = await fetch(url, {\n headers: {\n \"content-type\": \"application/json\",\n ...getApiHeaders?.(),\n },\n signal,\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch MySite data: ${response.status}`);\n }\n\n const data = await response.json();\n return {\n url: data.mysite_url ?? null,\n views: data.mysite_views ?? 0,\n leads: data.mysite_leads ?? 0,\n userName: data.name || data.first_name || \"User\",\n };\n },\n enabled: !isPreview,\n ...(isPreview && { placeholderData: PREVIEW_DATA }),\n });\n}\n","import { useMemo, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/rep-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/rep-core/registries\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport { useMySite } from \"../hooks/use-mysite\";\nimport { ErrorState } from \"../components/error-state\";\n\ntype MySiteWidgetProps = ComponentProps<\"div\"> & {\n // Title settings\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Design settings\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n\n // Display settings\n showPreview?: boolean;\n showAnalytics?: boolean;\n};\n\nexport function MySiteWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"My Site\",\n titleFontSize = \"lg\",\n titleColor = \"foreground\",\n\n // Design defaults\n background = {\n type: \"solid\",\n color: \"background\",\n },\n textColor = \"foreground\",\n accentColor = \"primary\",\n padding = 4,\n borderRadius = \"md\",\n\n // Display defaults\n showPreview = true,\n showAnalytics = true,\n\n className,\n ...props\n}: MySiteWidgetProps): React.JSX.Element | null {\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 const { data: mySite, isLoading, isError } = useMySite();\n\n // Generate preview URL with preview=true parameter\n const previewUrl = useMemo(() => {\n if (!mySite?.url) return \"\";\n try {\n const urlObj = new URL(mySite.url);\n urlObj.searchParams.set(\"preview\", \"true\");\n return urlObj.toString();\n } catch {\n return mySite.url;\n }\n }, [mySite?.url]);\n\n // Display URL without protocol\n const displayUrl = useMemo(\n () => (mySite?.url ? mySite.url.replace(/^https?:\\/\\//, \"\") : \"\"),\n [mySite?.url],\n );\n\n // Don't render if no MySite URL exists (but still render if errored or loading)\n if (!isLoading && !isError && !mySite?.url) {\n return null;\n }\n\n return (\n <div\n className={`@container overflow-hidden rounded-${borderRadius} bg-${backgroundColor} text-${textColor} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n {/* Title */}\n {titleEnabled && titleText && (\n <div className={`p-${padding} pb-0`}>\n <h2 className={`text-${titleFontSize} font-bold text-${titleColor}`}>\n {mySite?.userName ? `${mySite.userName}'s ${titleText}` : titleText}\n </h2>\n </div>\n )}\n\n {/* Loading state */}\n {isLoading ? (\n <div\n className={`flex min-h-[200px] items-center justify-center p-${padding}`}\n >\n <div className=\"h-8 w-8 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n </div>\n ) : isError ? (\n <ErrorState />\n ) : (\n <div className={`p-${padding}`}>\n {/* MySite iframe preview */}\n {showPreview && (\n <div className=\"border-muted mb-4 overflow-hidden rounded-lg border\">\n {/* Browser chrome */}\n <div className=\"bg-[#f3f4f6] px-3 py-2 text-[#6b7280]\">\n <div className=\"flex items-center gap-2\">\n <div className=\"flex gap-1\">\n <div className=\"h-3 w-3 rounded-full bg-[#ff5f57]\" />\n <div className=\"h-3 w-3 rounded-full bg-[#febc2e]\" />\n <div className=\"h-3 w-3 rounded-full bg-[#28c840]\" />\n </div>\n <div className=\"flex-1 text-center\">\n <a\n href={mySite?.url ?? \"\"}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm opacity-60\"\n >\n {displayUrl}\n </a>\n </div>\n </div>\n </div>\n {/* iframe container */}\n <div className=\"h-[200px] overflow-hidden bg-[#ffffff] @md:h-[280px]\">\n <iframe\n className=\"pointer-events-none h-[700%] w-[700%] origin-top-left scale-[0.14] bg-[#ffffff]\"\n src={previewUrl}\n title=\"MySite Preview\"\n />\n </div>\n </div>\n )}\n\n {/* Analytics data */}\n {showAnalytics && (\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"border-muted bg-background rounded-lg border p-3\">\n <div className=\"text-xs opacity-60\">Visitors This Month</div>\n <div className={`text-xl font-bold text-${accentColor}`}>\n {mySite?.views ?? 0}\n </div>\n </div>\n <div className=\"border-muted bg-background rounded-lg border p-3\">\n <div className=\"text-xs opacity-60\">Total Leads</div>\n <div className={`text-xl font-bold text-${accentColor}`}>\n {mySite?.leads ?? 0}\n </div>\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n\nexport const mySiteWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"MySiteWidget\",\n displayName: \"MySite Widget\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [\n // Styling Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the widget\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the widget\",\n defaultValue: \"My Site\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleFontSize\",\n label: \"Title Font Size\",\n description: \"Font size for the widget title\",\n defaultValue: \"xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling Tab - Design Group\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the widget container\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for widget content\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description: \"Color used for analytics numbers\",\n defaultValue: \"primary\",\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 getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the widget container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the widget container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n\n // Styling Tab - Display Group\n {\n key: \"showPreview\",\n label: \"Show Preview\",\n type: \"boolean\",\n description: \"Show the MySite iframe preview\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Display\",\n },\n {\n key: \"showAnalytics\",\n label: \"Show Analytics\",\n type: \"boolean\",\n description: \"Show the analytics section\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Display\",\n },\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MySiteWidget-DrUI7OTT.cjs","names":["ErrorState"],"sources":["../src/hooks/use-mysite.preview.ts","../src/hooks/use-mysite.ts","../src/widgets/MySiteWidget.tsx"],"sourcesContent":["import type { MySiteData } from \"./use-mysite.types\";\n\nexport const PREVIEW_DATA: MySiteData = {\n url: \"https://mysite.example.com\",\n views: 1248,\n leads: 43,\n userName: \"Jane\",\n};\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useDataSourceConfig } from \"@fluid-app/rep-core/data-sources/context\";\nimport { useWidgetPreviewContext } from \"@fluid-app/rep-core/data-sources/preview-context\";\nimport { PREVIEW_DATA } from \"./use-mysite.preview\";\n\nimport type { MySiteData } from \"./use-mysite.types\";\n\nexport type { MySiteData } from \"./use-mysite.types\";\n\nexport function useMySite(): UseQueryResult<MySiteData, Error> {\n const { baseUrl, getApiHeaders } = useDataSourceConfig();\n const { isPreview } = useWidgetPreviewContext();\n\n return useQuery({\n queryKey: [\n \"rep-widget-use\",\n \"mysite\",\n isPreview ? \"preview\" : baseUrl,\n ] as const,\n queryFn: async ({ signal }): Promise<MySiteData> => {\n const url = baseUrl ? `${baseUrl}/me` : \"/me\";\n const response = await fetch(url, {\n headers: {\n \"content-type\": \"application/json\",\n ...getApiHeaders?.(),\n },\n signal,\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch MySite data: ${response.status}`);\n }\n\n const data = await response.json();\n return {\n url: data.mysite_url ?? null,\n views: data.mysite_views ?? 0,\n leads: data.mysite_leads ?? 0,\n userName: data.name || data.first_name || \"User\",\n };\n },\n enabled: !isPreview,\n ...(isPreview && { placeholderData: PREVIEW_DATA }),\n });\n}\n","import { useMemo, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/rep-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/rep-core/registries\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport { useMySite } from \"../hooks/use-mysite\";\nimport { ErrorState } from \"../components/error-state\";\n\ntype MySiteWidgetProps = ComponentProps<\"div\"> & {\n // Title settings\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Design settings\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n\n // Display settings\n showPreview?: boolean;\n showAnalytics?: boolean;\n};\n\nexport function MySiteWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"My Site\",\n titleFontSize = \"lg\",\n titleColor = \"foreground\",\n\n // Design defaults\n background = {\n type: \"solid\",\n color: \"background\",\n },\n textColor = \"foreground\",\n accentColor = \"primary\",\n padding = 4,\n borderRadius = \"md\",\n\n // Display defaults\n showPreview = true,\n showAnalytics = true,\n\n className,\n ...props\n}: MySiteWidgetProps): React.JSX.Element | null {\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 const { data: mySite, isLoading, isError } = useMySite();\n\n // Generate preview URL with preview=true parameter\n const previewUrl = useMemo(() => {\n if (!mySite?.url) return \"\";\n try {\n const urlObj = new URL(mySite.url);\n urlObj.searchParams.set(\"preview\", \"true\");\n return urlObj.toString();\n } catch {\n return mySite.url;\n }\n }, [mySite?.url]);\n\n // Display URL without protocol\n const displayUrl = useMemo(\n () => (mySite?.url ? mySite.url.replace(/^https?:\\/\\//, \"\") : \"\"),\n [mySite?.url],\n );\n\n // Don't render if no MySite URL exists (but still render if errored or loading)\n if (!isLoading && !isError && !mySite?.url) {\n return null;\n }\n\n return (\n <div\n className={`@container overflow-hidden rounded-${borderRadius} bg-${backgroundColor} text-${textColor} ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n {/* Title */}\n {titleEnabled && titleText && (\n <div className={`p-${padding} pb-0`}>\n <h2 className={`text-${titleFontSize} font-bold text-${titleColor}`}>\n {mySite?.userName ? `${mySite.userName}'s ${titleText}` : titleText}\n </h2>\n </div>\n )}\n\n {/* Loading state */}\n {isLoading ? (\n <div\n className={`flex min-h-[200px] items-center justify-center p-${padding}`}\n >\n <div className=\"h-8 w-8 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n </div>\n ) : isError ? (\n <ErrorState />\n ) : (\n <div className={`p-${padding}`}>\n {/* MySite iframe preview */}\n {showPreview && (\n <div className=\"border-muted mb-4 overflow-hidden rounded-lg border\">\n {/* Browser chrome */}\n <div className=\"bg-[#f3f4f6] px-3 py-2 text-[#6b7280]\">\n <div className=\"flex items-center gap-2\">\n <div className=\"flex gap-1\">\n <div className=\"h-3 w-3 rounded-full bg-[#ff5f57]\" />\n <div className=\"h-3 w-3 rounded-full bg-[#febc2e]\" />\n <div className=\"h-3 w-3 rounded-full bg-[#28c840]\" />\n </div>\n <div className=\"flex-1 text-center\">\n <a\n href={mySite?.url ?? \"\"}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm opacity-60\"\n >\n {displayUrl}\n </a>\n </div>\n </div>\n </div>\n {/* iframe container */}\n <div className=\"h-[200px] overflow-hidden bg-[#ffffff] @md:h-[280px]\">\n <iframe\n className=\"pointer-events-none h-[700%] w-[700%] origin-top-left scale-[0.14] bg-[#ffffff]\"\n src={previewUrl}\n title=\"MySite Preview\"\n />\n </div>\n </div>\n )}\n\n {/* Analytics data */}\n {showAnalytics && (\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"border-muted bg-background rounded-lg border p-3\">\n <div className=\"text-xs opacity-60\">Visitors This Month</div>\n <div className={`text-xl font-bold text-${accentColor}`}>\n {mySite?.views ?? 0}\n </div>\n </div>\n <div className=\"border-muted bg-background rounded-lg border p-3\">\n <div className=\"text-xs opacity-60\">Total Leads</div>\n <div className={`text-xl font-bold text-${accentColor}`}>\n {mySite?.leads ?? 0}\n </div>\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n\nexport const mySiteWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"MySiteWidget\",\n displayName: \"MySite Widget\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [\n // Styling Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the widget\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the widget\",\n defaultValue: \"My Site\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleFontSize\",\n label: \"Title Font Size\",\n description: \"Font size for the widget title\",\n defaultValue: \"xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling Tab - Design Group\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the widget container\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for widget content\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description: \"Color used for analytics numbers\",\n defaultValue: \"primary\",\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 getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the widget container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the widget container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n\n // Styling Tab - Display Group\n {\n key: \"showPreview\",\n label: \"Show Preview\",\n type: \"boolean\",\n description: \"Show the MySite iframe preview\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Display\",\n },\n {\n key: \"showAnalytics\",\n label: \"Show Analytics\",\n type: \"boolean\",\n description: \"Show the analytics section\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Display\",\n },\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NestedWidget-CbuuxK7U.cjs","names":["MediaRenderer","getMediaPropsFromShareable","gapValues","ScrollArrows"],"sources":["../src/widgets/NestedWidget.tsx"],"sourcesContent":["import { useRef, useState, useEffect, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport {\n MediaRenderer,\n getMediaPropsFromShareable,\n} from \"../components/MediaRenderer\";\nimport type {\n BorderRadiusOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n AlignOptions,\n GapOptions,\n BackgroundValue,\n} from \"@fluid-app/rep-core/types\";\nimport {\n getHeightField,\n type WidgetPropertySchema,\n} from \"@fluid-app/rep-core/registries\";\nimport {\n getBorderRadiusField,\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/rep-core/types\";\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 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 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 const primaryMediaRef = useRef<HTMLDivElement>(null);\n const [primaryMediaWidthPx, setPrimaryMediaWidthPx] = useState(400);\n\n useEffect(() => {\n const el = primaryMediaRef.current;\n if (!el) return;\n const observer = new ResizeObserver(([entry]) => {\n if (entry) setPrimaryMediaWidthPx(entry.contentRect.width);\n });\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\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 itemWidth = primaryMediaWidthPx * 0.75;\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 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 p-${padding} rounded-${borderRadius} 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 ref={primaryMediaRef}\n className={`overflow-hidden @md:flex-none rounded-${borderRadius}`}\n style={{\n width: primaryMediaHeight,\n }}\n >\n {/* Primary Media */}\n <div className=\"relative h-full w-full\">\n <MediaRenderer\n {...(resource ? getMediaPropsFromShareable(resource) : {})}\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\n {/* Title and Mobile Nested Media */}\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={`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\"\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 </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 flex-col gap-1\"\n style={{\n width: `${primaryMediaWidthPx * 0.75}px`,\n scrollSnapAlign: \"start\",\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 min: 100,\n max: 1200,\n step: 10,\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 {\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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Y;GACZ,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;qDAEa;GACb,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,KAAK;GACL,MAAM;GACN,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,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;sDACe;GACd,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;2DACmB;GACnB,cAAc;GACd,OAAO;GACP,KAAK;GACL,aAAa;GACb,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;kDAEW;GACV,OAAO;GACP,cAAc;GACd,KAAK;GACL,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;oDACY;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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NestedWidget-CwyVsZ-f.mjs","names":["getBorderRadiusField"],"sources":["../src/widgets/NestedWidget.tsx"],"sourcesContent":["import { useRef, useState, useEffect, type ComponentProps } from \"react\";\nimport {\n MediaRenderer,\n getMediaPropsFromShareable,\n} from \"../components/MediaRenderer\";\nimport type {\n BorderRadiusOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n AlignOptions,\n GapOptions,\n BackgroundValue,\n} from \"@fluid-app/rep-core/types\";\nimport {\n getHeightField,\n type WidgetPropertySchema,\n} from \"@fluid-app/rep-core/registries\";\nimport {\n getBorderRadiusField,\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/rep-core/types\";\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 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 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) {\n const scrollContainerRef = useRef<HTMLDivElement>(null);\n const primaryMediaRef = useRef<HTMLDivElement>(null);\n const [primaryMediaWidthPx, setPrimaryMediaWidthPx] = useState(400);\n\n useEffect(() => {\n const el = primaryMediaRef.current;\n if (!el) return;\n const observer = new ResizeObserver(([entry]) => {\n if (entry) setPrimaryMediaWidthPx(entry.contentRect.width);\n });\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\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 itemWidth = primaryMediaWidthPx * 0.75;\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 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 p-${padding} rounded-${borderRadius} 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 ref={primaryMediaRef}\n className={`overflow-hidden @md:flex-none rounded-${borderRadius}`}\n style={{\n width: primaryMediaHeight,\n }}\n >\n {/* Primary Media */}\n <div className=\"relative h-full w-full\">\n <MediaRenderer\n {...(resource ? getMediaPropsFromShareable(resource) : {})}\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\n {/* Title and Mobile Nested Media */}\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={`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\"\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 </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 flex-col gap-1\"\n style={{\n width: `${primaryMediaWidthPx * 0.75}px`,\n scrollSnapAlign: \"start\",\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 min: 100,\n max: 1200,\n step: 10,\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 {\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":";;;;;;;;;;;;;AA6BA,MAAM,qBAAsC,EAAE;AA8B9C,SAAgB,aAAa,EAC3B,UACA,eAAe,MACf,YAAY,uBACZ,aAAa,oBACb,MAAM,MACN,UAAU,GACV,eAAe,MACf,qBAAqB,SACrB,gBAAgB,MAChB,aAAa,cACb,iBAAiB;CAAE,YAAY;CAAQ,UAAU;CAAU,EAC3D,kBAAkB,cAClB,aAAa;CACX,MAAM;CACN,OAAO;CACR,EACD,iBAAiB,MACjB,cAAc,YACd,mBAAmB,IACnB,WACA,GAAG,SACiB;CACpB,MAAM,qBAAqB,OAAuB,KAAK;CACvD,MAAM,kBAAkB,OAAuB,KAAK;CACpD,MAAM,CAAC,qBAAqB,0BAA0B,SAAS,IAAI;AAEnE,iBAAgB;EACd,MAAM,KAAK,gBAAgB;AAC3B,MAAI,CAAC,GAAI;EACT,MAAM,WAAW,IAAI,gBAAgB,CAAC,WAAW;AAC/C,OAAI,MAAO,wBAAuB,MAAM,YAAY,MAAM;IAC1D;AACF,WAAS,QAAQ,GAAG;AACpB,eAAa,SAAS,YAAY;IACjC,EAAE,CAAC;CAEN,MAAM,kBAAkB,cAA+B;EACrD,MAAM,YAAY,mBAAmB;AACrC,MAAI,CAAC,UAAW;EAEhB,MAAM,cAAc,WAAW,iBAAiB,UAAU,CAAC,IAAI,IAAI;EAEnE,MAAM,eADY,sBAAsB,MACP;AAEjC,YAAU,SAAS;GACjB,MACE,UAAU,cACT,cAAc,SAAS,eAAe,CAAC;GAC1C,UAAU;GACX,CAAC;;CAGJ,MAAM,iBAAiB,WAAW,SAAS;CAE3C,MAAM,wBAAwB;EAC5B,MAAM;EACN,QAAQ;EACR,OAAO;EACR;CAED,MAAM,kBAAkB,WAAW,SAAS;CAC5C,MAAM,mBACH,WAAW,UAAU,aAAa,WAAW,UAAU,aACxD,WAAW,SAAS,UAChB,OAAO,WAAW,SAAS,aAAa,WAAW,SAAS,SAAS,KACrE;AAEN,QACE,qBAAC,OAAD;EACE,WAAW,4BAA4B,QAAQ,WAAW,aAAa,MAAM,gBAAgB,GAAG;EAChG,GAAI;EACJ,OAAO;GACL,WAAW;GACM;GAClB;YANH,CASE,oBAAC,OAAD;GACE,KAAK;GACL,WAAW,yCAAyC;GACpD,OAAO,EACL,OAAO,oBACR;aAGD,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,eAAD,EACE,GAAK,WAAW,2BAA2B,SAAS,GAAG,EAAE,EACzD,CAAA;KAGD,kBACC,oBAAC,OAAD;MACE,WAAW,6CACT,gBAAgB,aACZ,+CACA;MAEN,OAAO,EACL,UACG,OAAO,OAAO,iBAAiB,CAAC,QAAQ,KAAK,GAAG,CAAC,IAAI,MACtD,KACH;MACD,CAAA;MAID,gBAAgB,aAAc,mBAC/B,qBAAC,OAAD;MACE,WAAW,wBAAwB,sBAAsB,gBAAgB,cAAc,QAAQ,KAAK,QAAQ,GAC1G,eAAe,aAAa,QACxB,YAAY,YACZ,eAAe,aAAa,WAC1B,6BACA,eAAe;gBANzB,CASG,gBAAgB,aACf,oBAAC,MAAD;OACE,WAAW,gCAAgC,WAAW,QAAQ,kBAAkB,OAAO,SAAS;iBAE/F;OACE,CAAA,EAIN,kBACC,oBAAC,OAAD;OAAK,WAAW,MAAM,QAAQ;iBAC5B,oBAAC,OAAD;QACE,WAAW,4BAA4B,UAAU,KAAK;kBAErD,WAAW,KAAK,cACf,oBAAC,OAAD;SAEE,WAAU;mBAEV,oBAAC,OAAD;UACE,WAAW,2CAA2C;oBAEtD,oBAAC,eAAD,EACE,GAAI,2BAA2B,UAAU,EACzC,CAAA;UACE,CAAA;SACF,EAVC,UAAU,GAUX,CACN;QACE,CAAA;OACF,CAAA,CAEJ;;KAEJ;;GACF,CAAA,EAGL,kBACC,qBAAC,OAAD;GACE,WAAW,+DAA+D;aAD5E,CAGE,oBAAC,OAAD;IACE,KAAK;IACL,WAAW,4CAA4C,UAAU;IACjE,OAAO,EAAE,gBAAgB,eAAe;cAEvC,WAAW,KAAK,cACf,qBAAC,OAAD;KAEE,WAAU;KACV,OAAO;MACL,OAAO,GAAG,sBAAsB,IAAK;MACrC,iBAAiB;MAClB;eANH,CAQE,oBAAC,OAAD;MACE,WAAW,6BAA6B,aAAa;gBAErD,oBAAC,eAAD,EAAe,GAAI,2BAA2B,UAAU,EAAI,CAAA;MACxD,CAAA,EACN,qBAAC,QAAD;MAAM,WAAW,0BAA0B;gBAA3C,CACE,oBAAC,KAAD;OAAG,WAAU;iBAAY,UAAU,SAAS;OAAO,CAAA,EACnD,oBAAC,KAAD;OAAG,WAAU;kBACR,UAAU,iBAA4B,UAAU,UACjD;OACA,CAAA,CACC;QACH;OAnBC,UAAU,GAmBX,CACN;IACE,CAAA,EAGN,oBAAC,OAAD;IACE,WAAW;cAEX,oBAAC,cAAD;KACE,kBAAkB,eAAe,OAAO;KACxC,cAAc,eAAe,OAAO;KACpC,CAAA;IACE,CAAA,CACF;KAEJ;;;AAIV,MAAa,6BAAmD;CAC9D,YAAY;CACZ,aAAa;CACb,YAAY,CACV;EAAE,IAAI;EAAW,OAAO;EAAW,EACnC;EAAE,IAAI;EAAQ,OAAO;EAAQ,CAC9B;CACD,uBAAuB,CAAC,aAAa;CACrC,QAAQ;EAEN;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc,CAAC,SAAS;GACxB,KAAK;GACL,OAAO;GACR;EAED;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;EACD,iBAAiB;GACf,OAAO;GACP,cAAc;GACd,KAAK;GACL,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EACF,cAAc;GACZ,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EAEF,eAAe;GACb,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,KAAK;GACL,MAAM;GACN,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,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;EACFA,uBAAqB;GACnB,cAAc;GACd,OAAO;GACP,KAAK;GACL,aAAa;GACb,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-CwyVsZ-f.mjs","names":["getBorderRadiusField"],"sources":["../src/widgets/NestedWidget.tsx"],"sourcesContent":["import { useRef, useState, useEffect, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport {\n MediaRenderer,\n getMediaPropsFromShareable,\n} from \"../components/MediaRenderer\";\nimport type {\n BorderRadiusOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n AlignOptions,\n GapOptions,\n BackgroundValue,\n} from \"@fluid-app/rep-core/types\";\nimport {\n getHeightField,\n type WidgetPropertySchema,\n} from \"@fluid-app/rep-core/registries\";\nimport {\n getBorderRadiusField,\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/rep-core/types\";\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 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 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 const primaryMediaRef = useRef<HTMLDivElement>(null);\n const [primaryMediaWidthPx, setPrimaryMediaWidthPx] = useState(400);\n\n useEffect(() => {\n const el = primaryMediaRef.current;\n if (!el) return;\n const observer = new ResizeObserver(([entry]) => {\n if (entry) setPrimaryMediaWidthPx(entry.contentRect.width);\n });\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\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 itemWidth = primaryMediaWidthPx * 0.75;\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 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 p-${padding} rounded-${borderRadius} 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 ref={primaryMediaRef}\n className={`overflow-hidden @md:flex-none rounded-${borderRadius}`}\n style={{\n width: primaryMediaHeight,\n }}\n >\n {/* Primary Media */}\n <div className=\"relative h-full w-full\">\n <MediaRenderer\n {...(resource ? getMediaPropsFromShareable(resource) : {})}\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\n {/* Title and Mobile Nested Media */}\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={`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\"\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 </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 flex-col gap-1\"\n style={{\n width: `${primaryMediaWidthPx * 0.75}px`,\n scrollSnapAlign: \"start\",\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 min: 100,\n max: 1200,\n step: 10,\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 {\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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GACR;EACD,gBAAgB;GACd,cAAc;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,KAAK;GACL,OAAO;GACR,CAAC;EACFA,uBAAqB;GACnB,cAAc;GACd,OAAO;GACP,KAAK;GACL,aAAa;GACb,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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QuickShareWidget-BUbuTQFQ.mjs","names":[],"sources":["../src/widgets/QuickShareWidget.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport type {\n BorderRadiusOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/rep-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/rep-core/registries\";\nimport type { ShareableItem } from \"@fluid-app/rep-core/types\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport { QRCodeSVG } from \"qrcode.react\";\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\nimport {\n faCopy,\n faCartShopping,\n faImage,\n} from \"@fortawesome/pro-regular-svg-icons\";\n\ntype QuickShareWidgetProps = ComponentProps<\"div\"> & {\n // Resource\n shareableResource?: ShareableItem;\n\n // Title\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Styling\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n\n // Overlay\n overlayEnabled?: boolean;\n overlayType?: \"solid\" | \"gradient\";\n overlayIntensity?: number;\n\n // Actions\n showBuyButton?: boolean;\n};\n\nexport function QuickShareWidget({\n // Resource\n shareableResource,\n\n // Title defaults\n titleEnabled = true,\n titleText = \"\",\n titleFontSize = \"2xl\",\n titleColor = \"foreground\",\n\n textColor = \"foreground\",\n accentColor = \"primary\",\n padding = 4,\n borderRadius = \"md\",\n\n // Overlay defaults\n overlayEnabled = true,\n overlayType = \"solid\",\n overlayIntensity = 50,\n\n // Actions defaults\n showBuyButton = false,\n\n className,\n ...props\n}: QuickShareWidgetProps) {\n // Determine background styling\n const backgroundImageUrl =\n shareableResource?.image_url || shareableResource?.imageUrl;\n\n // Get share link from resource\n const shareLink = shareableResource?.share_link || \"\";\n const displayUrl = shareLink || \"Select a resource to generate link\";\n\n // Determine title - use provided title or fall back to resource title\n const displayTitle =\n titleText || shareableResource?.title || \"Select a resource to display!\";\n\n // Check if resource is a Product for buy button visibility\n const isProduct =\n shareableResource?.type === \"Product\" ||\n shareableResource?.shareableType === \"Product\";\n const shouldShowBuyButton = showBuyButton && isProduct;\n\n // Copy to clipboard handler\n const handleCopyToClipboard = async () => {\n if (shareLink) {\n try {\n await navigator.clipboard.writeText(shareLink);\n } catch (error) {\n console.error(\"Failed to copy to clipboard:\", error);\n }\n }\n };\n\n return (\n <div\n className={`relative overflow-hidden rounded-${borderRadius} bg-muted text-${textColor} ${className ?? \"\"}`}\n {...props}\n >\n {/* Background Image with Overlay */}\n {backgroundImageUrl ? (\n <div className=\"absolute inset-0\">\n <img\n src={backgroundImageUrl}\n alt=\"\"\n className=\"h-full w-full object-cover\"\n />\n {overlayEnabled && (\n <div\n className={`absolute inset-0 ${\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 <div\n className={`bg-muted absolute inset-0 flex items-center justify-center`}\n >\n <FontAwesomeIcon icon={faImage} className=\"h-16 w-16 opacity-20\" />\n </div>\n )}\n\n {/* Content Container */}\n <div className={`relative flex min-h-[400px] flex-col p-${padding}`}>\n {/* Title Overlay */}\n {titleEnabled && displayTitle && (\n <div className=\"flex flex-1 items-center justify-center\">\n <h2\n className={`text-center text-${titleFontSize} font-semibold text-${titleColor} drop-shadow-lg`}\n >\n {displayTitle}\n </h2>\n </div>\n )}\n\n {/* Bottom Section - QR Code, URL, and Buttons */}\n <div className=\"mt-auto flex flex-col gap-4\">\n <div className=\"flex items-end justify-between gap-4\">\n {/* QR Code */}\n <div className=\"shrink-0 rounded-lg bg-white p-2\">\n <QRCodeSVG\n value={shareLink || \"https://example.com\"}\n size={100}\n level=\"H\"\n />\n </div>\n\n {/* URL Display */}\n <div className=\"min-w-0 flex-1\">\n <p className=\"mb-2 text-sm font-semibold tracking-wide drop-shadow\">\n Your Shareable URL\n </p>\n <div className=\"flex items-center justify-between rounded-md border border-white/20 bg-black/50 p-2 text-sm text-white backdrop-blur\">\n <span className=\"truncate\">{displayUrl}</span>\n <button\n type=\"button\"\n onClick={handleCopyToClipboard}\n className={`ml-2 shrink-0 rounded p-1 transition-colors hover:bg-${accentColor}/20`}\n aria-label=\"Copy link\"\n >\n <FontAwesomeIcon icon={faCopy} className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n </div>\n\n {/* Action Buttons */}\n {/* TODO: Needs button link implmented, once it is uncomment the config for showBuyButton */}\n {shouldShowBuyButton && (\n <div className=\"flex\">\n <button\n type=\"button\"\n className={`flex w-full items-center justify-center gap-2 rounded-lg bg-${accentColor} p-3 font-medium text-${accentColor}-foreground transition-all hover:bg-${accentColor}-500`}\n >\n <FontAwesomeIcon icon={faCartShopping} className=\"h-4 w-4\" />\n <span>Buy</span>\n </button>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n\nexport const quickShareWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"QuickShareWidget\",\n displayName: \"Quick Share Widget\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [\n // Styling Tab - Resource\n {\n key: \"shareableResource\",\n label: \"Shareable Content\",\n type: \"resource\",\n description: \"Select the content to generate a share link for\",\n allowedTypes: [\"Product\", \"Page\", \"EnrollmentPack\", \"Medium\", \"Library\"],\n tab: \"styling\",\n group: \"Content\",\n },\n\n // Styling Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Show Title\",\n type: \"boolean\",\n description: \"Display a title overlay on the widget\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Custom title text (defaults to resource title if empty)\",\n defaultValue: \"\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleFontSize\",\n label: \"Title Font Size\",\n description: \"Font size for the title text\",\n defaultValue: \"2xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the title text\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling Tab - Actions Group\n // {\n // key: \"showBuyButton\",\n // label: \"Show Buy Button\",\n // type: \"boolean\",\n // description: \"Display the buy button (only visible for Product type)\",\n // defaultValue: false,\n // tab: \"styling\",\n // group: \"Actions\",\n // },\n\n // Styling Tab - Design Group\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for the widget\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description: \"Color for accent elements and buy button\",\n defaultValue: \"primary\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"overlayEnabled\",\n label: \"Enable Overlay\",\n type: \"boolean\",\n description: \"Add background overlay for 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 to add to the background\",\n defaultValue: \"solid\",\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 background (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 {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the widget content\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the widget container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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Ac;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,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;EACD;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;EACD,gBAAgB;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,qBAAqB;GACnB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACH;CACF"}
|
|
1
|
+
{"version":3,"file":"QuickShareWidget-BUbuTQFQ.mjs","names":[],"sources":["../src/widgets/QuickShareWidget.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BorderRadiusOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/rep-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/rep-core/registries\";\nimport type { ShareableItem } from \"@fluid-app/rep-core/types\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport { QRCodeSVG } from \"qrcode.react\";\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\nimport {\n faCopy,\n faCartShopping,\n faImage,\n} from \"@fortawesome/pro-regular-svg-icons\";\n\ntype QuickShareWidgetProps = ComponentProps<\"div\"> & {\n // Resource\n shareableResource?: ShareableItem;\n\n // Title\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Styling\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n\n // Overlay\n overlayEnabled?: boolean;\n overlayType?: \"solid\" | \"gradient\";\n overlayIntensity?: number;\n\n // Actions\n showBuyButton?: boolean;\n};\n\nexport function QuickShareWidget({\n // Resource\n shareableResource,\n\n // Title defaults\n titleEnabled = true,\n titleText = \"\",\n titleFontSize = \"2xl\",\n titleColor = \"foreground\",\n\n textColor = \"foreground\",\n accentColor = \"primary\",\n padding = 4,\n borderRadius = \"md\",\n\n // Overlay defaults\n overlayEnabled = true,\n overlayType = \"solid\",\n overlayIntensity = 50,\n\n // Actions defaults\n showBuyButton = false,\n\n className,\n ...props\n}: QuickShareWidgetProps): React.JSX.Element {\n // Determine background styling\n const backgroundImageUrl =\n shareableResource?.image_url || shareableResource?.imageUrl;\n\n // Get share link from resource\n const shareLink = shareableResource?.share_link || \"\";\n const displayUrl = shareLink || \"Select a resource to generate link\";\n\n // Determine title - use provided title or fall back to resource title\n const displayTitle =\n titleText || shareableResource?.title || \"Select a resource to display!\";\n\n // Check if resource is a Product for buy button visibility\n const isProduct =\n shareableResource?.type === \"Product\" ||\n shareableResource?.shareableType === \"Product\";\n const shouldShowBuyButton = showBuyButton && isProduct;\n\n // Copy to clipboard handler\n const handleCopyToClipboard = async () => {\n if (shareLink) {\n try {\n await navigator.clipboard.writeText(shareLink);\n } catch (error) {\n console.error(\"Failed to copy to clipboard:\", error);\n }\n }\n };\n\n return (\n <div\n className={`relative overflow-hidden rounded-${borderRadius} bg-muted text-${textColor} ${className ?? \"\"}`}\n {...props}\n >\n {/* Background Image with Overlay */}\n {backgroundImageUrl ? (\n <div className=\"absolute inset-0\">\n <img\n src={backgroundImageUrl}\n alt=\"\"\n className=\"h-full w-full object-cover\"\n />\n {overlayEnabled && (\n <div\n className={`absolute inset-0 ${\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 <div\n className={`bg-muted absolute inset-0 flex items-center justify-center`}\n >\n <FontAwesomeIcon icon={faImage} className=\"h-16 w-16 opacity-20\" />\n </div>\n )}\n\n {/* Content Container */}\n <div className={`relative flex min-h-[400px] flex-col p-${padding}`}>\n {/* Title Overlay */}\n {titleEnabled && displayTitle && (\n <div className=\"flex flex-1 items-center justify-center\">\n <h2\n className={`text-center text-${titleFontSize} font-semibold text-${titleColor} drop-shadow-lg`}\n >\n {displayTitle}\n </h2>\n </div>\n )}\n\n {/* Bottom Section - QR Code, URL, and Buttons */}\n <div className=\"mt-auto flex flex-col gap-4\">\n <div className=\"flex items-end justify-between gap-4\">\n {/* QR Code */}\n <div className=\"shrink-0 rounded-lg bg-white p-2\">\n <QRCodeSVG\n value={shareLink || \"https://example.com\"}\n size={100}\n level=\"H\"\n />\n </div>\n\n {/* URL Display */}\n <div className=\"min-w-0 flex-1\">\n <p className=\"mb-2 text-sm font-semibold tracking-wide drop-shadow\">\n Your Shareable URL\n </p>\n <div className=\"flex items-center justify-between rounded-md border border-white/20 bg-black/50 p-2 text-sm text-white backdrop-blur\">\n <span className=\"truncate\">{displayUrl}</span>\n <button\n type=\"button\"\n onClick={handleCopyToClipboard}\n className={`ml-2 shrink-0 rounded p-1 transition-colors hover:bg-${accentColor}/20`}\n aria-label=\"Copy link\"\n >\n <FontAwesomeIcon icon={faCopy} className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n </div>\n\n {/* Action Buttons */}\n {/* TODO: Needs button link implmented, once it is uncomment the config for showBuyButton */}\n {shouldShowBuyButton && (\n <div className=\"flex\">\n <button\n type=\"button\"\n className={`flex w-full items-center justify-center gap-2 rounded-lg bg-${accentColor} p-3 font-medium text-${accentColor}-foreground transition-all hover:bg-${accentColor}-500`}\n >\n <FontAwesomeIcon icon={faCartShopping} className=\"h-4 w-4\" />\n <span>Buy</span>\n </button>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n\nexport const quickShareWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"QuickShareWidget\",\n displayName: \"Quick Share Widget\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [\n // Styling Tab - Resource\n {\n key: \"shareableResource\",\n label: \"Shareable Content\",\n type: \"resource\",\n description: \"Select the content to generate a share link for\",\n allowedTypes: [\"Product\", \"Page\", \"EnrollmentPack\", \"Medium\", \"Library\"],\n tab: \"styling\",\n group: \"Content\",\n },\n\n // Styling Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Show Title\",\n type: \"boolean\",\n description: \"Display a title overlay on the widget\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Custom title text (defaults to resource title if empty)\",\n defaultValue: \"\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleFontSize\",\n label: \"Title Font Size\",\n description: \"Font size for the title text\",\n defaultValue: \"2xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the title text\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling Tab - Actions Group\n // {\n // key: \"showBuyButton\",\n // label: \"Show Buy Button\",\n // type: \"boolean\",\n // description: \"Display the buy button (only visible for Product type)\",\n // defaultValue: false,\n // tab: \"styling\",\n // group: \"Actions\",\n // },\n\n // Styling Tab - Design Group\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for the widget\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description: \"Color for accent elements and buy button\",\n defaultValue: \"primary\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"overlayEnabled\",\n label: \"Enable Overlay\",\n type: \"boolean\",\n description: \"Add background overlay for 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 to add to the background\",\n defaultValue: \"solid\",\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 background (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 {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the widget content\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the widget container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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Ac;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,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;EACD;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;EACD,gBAAgB;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF,qBAAqB;GACnB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACH;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QuickShareWidget-DjhPbMsy.cjs","names":["FontAwesomeIcon","faImage","QRCodeSVG","faCopy","faCartShopping"],"sources":["../src/widgets/QuickShareWidget.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BorderRadiusOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/rep-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/rep-core/registries\";\nimport type { ShareableItem } from \"@fluid-app/rep-core/types\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport { QRCodeSVG } from \"qrcode.react\";\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\nimport {\n faCopy,\n faCartShopping,\n faImage,\n} from \"@fortawesome/pro-regular-svg-icons\";\n\ntype QuickShareWidgetProps = ComponentProps<\"div\"> & {\n // Resource\n shareableResource?: ShareableItem;\n\n // Title\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Styling\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n\n // Overlay\n overlayEnabled?: boolean;\n overlayType?: \"solid\" | \"gradient\";\n overlayIntensity?: number;\n\n // Actions\n showBuyButton?: boolean;\n};\n\nexport function QuickShareWidget({\n // Resource\n shareableResource,\n\n // Title defaults\n titleEnabled = true,\n titleText = \"\",\n titleFontSize = \"2xl\",\n titleColor = \"foreground\",\n\n textColor = \"foreground\",\n accentColor = \"primary\",\n padding = 4,\n borderRadius = \"md\",\n\n // Overlay defaults\n overlayEnabled = true,\n overlayType = \"solid\",\n overlayIntensity = 50,\n\n // Actions defaults\n showBuyButton = false,\n\n className,\n ...props\n}: QuickShareWidgetProps): React.JSX.Element {\n // Determine background styling\n const backgroundImageUrl =\n shareableResource?.image_url || shareableResource?.imageUrl;\n\n // Get share link from resource\n const shareLink = shareableResource?.share_link || \"\";\n const displayUrl = shareLink || \"Select a resource to generate link\";\n\n // Determine title - use provided title or fall back to resource title\n const displayTitle =\n titleText || shareableResource?.title || \"Select a resource to display!\";\n\n // Check if resource is a Product for buy button visibility\n const isProduct =\n shareableResource?.type === \"Product\" ||\n shareableResource?.shareableType === \"Product\";\n const shouldShowBuyButton = showBuyButton && isProduct;\n\n // Copy to clipboard handler\n const handleCopyToClipboard = async () => {\n if (shareLink) {\n try {\n await navigator.clipboard.writeText(shareLink);\n } catch (error) {\n console.error(\"Failed to copy to clipboard:\", error);\n }\n }\n };\n\n return (\n <div\n className={`relative overflow-hidden rounded-${borderRadius} bg-muted text-${textColor} ${className ?? \"\"}`}\n {...props}\n >\n {/* Background Image with Overlay */}\n {backgroundImageUrl ? (\n <div className=\"absolute inset-0\">\n <img\n src={backgroundImageUrl}\n alt=\"\"\n className=\"h-full w-full object-cover\"\n />\n {overlayEnabled && (\n <div\n className={`absolute inset-0 ${\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 <div\n className={`bg-muted absolute inset-0 flex items-center justify-center`}\n >\n <FontAwesomeIcon icon={faImage} className=\"h-16 w-16 opacity-20\" />\n </div>\n )}\n\n {/* Content Container */}\n <div className={`relative flex min-h-[400px] flex-col p-${padding}`}>\n {/* Title Overlay */}\n {titleEnabled && displayTitle && (\n <div className=\"flex flex-1 items-center justify-center\">\n <h2\n className={`text-center text-${titleFontSize} font-semibold text-${titleColor} drop-shadow-lg`}\n >\n {displayTitle}\n </h2>\n </div>\n )}\n\n {/* Bottom Section - QR Code, URL, and Buttons */}\n <div className=\"mt-auto flex flex-col gap-4\">\n <div className=\"flex items-end justify-between gap-4\">\n {/* QR Code */}\n <div className=\"shrink-0 rounded-lg bg-white p-2\">\n <QRCodeSVG\n value={shareLink || \"https://example.com\"}\n size={100}\n level=\"H\"\n />\n </div>\n\n {/* URL Display */}\n <div className=\"min-w-0 flex-1\">\n <p className=\"mb-2 text-sm font-semibold tracking-wide drop-shadow\">\n Your Shareable URL\n </p>\n <div className=\"flex items-center justify-between rounded-md border border-white/20 bg-black/50 p-2 text-sm text-white backdrop-blur\">\n <span className=\"truncate\">{displayUrl}</span>\n <button\n type=\"button\"\n onClick={handleCopyToClipboard}\n className={`ml-2 shrink-0 rounded p-1 transition-colors hover:bg-${accentColor}/20`}\n aria-label=\"Copy link\"\n >\n <FontAwesomeIcon icon={faCopy} className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n </div>\n\n {/* Action Buttons */}\n {/* TODO: Needs button link implmented, once it is uncomment the config for showBuyButton */}\n {shouldShowBuyButton && (\n <div className=\"flex\">\n <button\n type=\"button\"\n className={`flex w-full items-center justify-center gap-2 rounded-lg bg-${accentColor} p-3 font-medium text-${accentColor}-foreground transition-all hover:bg-${accentColor}-500`}\n >\n <FontAwesomeIcon icon={faCartShopping} className=\"h-4 w-4\" />\n <span>Buy</span>\n </button>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n\nexport const quickShareWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"QuickShareWidget\",\n displayName: \"Quick Share Widget\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [\n // Styling Tab - Resource\n {\n key: \"shareableResource\",\n label: \"Shareable Content\",\n type: \"resource\",\n description: \"Select the content to generate a share link for\",\n allowedTypes: [\"Product\", \"Page\", \"EnrollmentPack\", \"Medium\", \"Library\"],\n tab: \"styling\",\n group: \"Content\",\n },\n\n // Styling Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Show Title\",\n type: \"boolean\",\n description: \"Display a title overlay on the widget\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Custom title text (defaults to resource title if empty)\",\n defaultValue: \"\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleFontSize\",\n label: \"Title Font Size\",\n description: \"Font size for the title text\",\n defaultValue: \"2xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the title text\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling Tab - Actions Group\n // {\n // key: \"showBuyButton\",\n // label: \"Show Buy Button\",\n // type: \"boolean\",\n // description: \"Display the buy button (only visible for Product type)\",\n // defaultValue: false,\n // tab: \"styling\",\n // group: \"Actions\",\n // },\n\n // Styling Tab - Design Group\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for the widget\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description: \"Color for accent elements and buy button\",\n defaultValue: \"primary\",\n tab: \"styling\",\n group: \"Design\",\n }),\n {\n key: \"overlayEnabled\",\n label: \"Enable Overlay\",\n type: \"boolean\",\n description: \"Add background overlay for 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 to add to the background\",\n defaultValue: \"solid\",\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 background (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 {\n key: \"separator\",\n type: \"separator\",\n label: \"Separator\",\n tab: \"styling\",\n group: \"Design\",\n },\n getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the widget content\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the widget container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACD;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB;uDACgB;GACf,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;oDACY;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;oDAcY;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;oDACY;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,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;EACD;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;sDACe;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;2DACmB;GACnB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACH;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RecentActivityWidget-BPs8xmPD.cjs","names":["faCartShopping","faComment","faPlay","faUserPlus","faEye","faCalendar","faStar","faSquareCheck","faBell","faTrophy","faUser","FontAwesomeIcon","ErrorState"],"sources":["../src/hooks/use-activities.preview.ts","../src/hooks/use-activities.ts","../src/widgets/RecentActivityWidget.tsx"],"sourcesContent":["import type { Activity } from \"./use-activities.types\";\n\nconst now = new Date();\n\nfunction minutesAgo(minutes: number): string {\n return new Date(now.getTime() - minutes * 60_000).toISOString();\n}\n\nexport const PREVIEW_DATA: Activity[] = [\n {\n id: 1,\n userName: \"Sarah Johnson\",\n avatarUrl: null,\n activityType: \"Order Placed\",\n targetName: \"Wellness Starter Kit\",\n timestamp: minutesAgo(12),\n slug: \"order_placed\",\n },\n {\n id: 2,\n userName: \"Mike Chen\",\n avatarUrl: null,\n activityType: \"New Lead\",\n targetName: \"Signed up from Instagram link\",\n timestamp: minutesAgo(45),\n slug: \"new_lead\",\n },\n {\n id: 3,\n userName: \"Visitor from Austin, TX\",\n avatarUrl: null,\n activityType: \"Page Views\",\n targetName: \"Viewed product catalog (3 pages)\",\n timestamp: minutesAgo(90),\n slug: \"page_views\",\n },\n {\n id: 4,\n userName: \"Lisa Park\",\n avatarUrl: null,\n activityType: \"Video Complete\",\n targetName: \"Watched: Getting Started Guide\",\n timestamp: minutesAgo(180),\n slug: \"video_complete\",\n },\n];\n","import { useQuery, type UseQueryResult } from \"@tanstack/react-query\";\nimport { useDataSourceConfig } from \"@fluid-app/rep-core/data-sources/context\";\nimport { useWidgetPreviewContext } from \"@fluid-app/rep-core/data-sources/preview-context\";\nimport { PREVIEW_DATA } from \"./use-activities.preview\";\nimport type {\n Activity,\n ActivityContact,\n ActivityVisitor,\n ApiActivity,\n} from \"./use-activities.types\";\n\nexport type {\n ActivityContact,\n ActivityVisitor,\n ActivitySlug,\n ApiActivity,\n Activity,\n} from \"./use-activities.types\";\n\ntype PaginationInfo = {\n current: number;\n previous: number | null;\n next: number | null;\n per_page: number;\n pages: number;\n count: number;\n};\n\ntype ApiResponse = [{ pagination: PaginationInfo }, { items: ApiActivity[] }];\n\nexport function useActivities(): UseQueryResult<Activity[], Error> {\n const { baseUrl, getApiHeaders } = useDataSourceConfig();\n const { isPreview } = useWidgetPreviewContext();\n\n return useQuery({\n queryKey: [\n \"rep-widget-use\",\n \"activities\",\n isPreview ? \"preview\" : baseUrl,\n ] as const,\n queryFn: async ({ signal }): Promise<Activity[]> => {\n const url = baseUrl\n ? `${baseUrl}/v1.1/activities.json`\n : \"/v1.1/activities.json\";\n const response = await fetch(url, {\n headers: {\n \"content-type\": \"application/json\",\n ...getApiHeaders?.(),\n },\n signal,\n });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch activities: ${response.status}`);\n }\n\n const data: ApiResponse = await response.json();\n return transformActivities(data);\n },\n enabled: !isPreview,\n ...(isPreview && { placeholderData: PREVIEW_DATA }),\n });\n}\n\n// Transform and format helpers\nfunction getUserName(\n contact: ActivityContact | null,\n visitor: ActivityVisitor | null,\n): string {\n if (contact?.full_name) {\n return contact.full_name;\n }\n if (contact?.first_name && contact?.last_name) {\n return `${contact.first_name} ${contact.last_name}`;\n }\n if (visitor?.city && visitor?.state) {\n return `Visitor from ${visitor.city}, ${visitor.state}`;\n }\n return \"Unknown Visitor\";\n}\n\nfunction transformActivities(rawData: ApiResponse): Activity[] {\n const itemsObj = rawData[1];\n if (!itemsObj?.items) return [];\n\n return itemsObj.items\n .map((activity) => ({\n id: activity.id,\n userName: getUserName(activity.contact, activity.visitor),\n avatarUrl: activity.contact?.avatar_url ?? null,\n activityType: formatActivityType(activity.slug),\n targetName: activity.description || activity.title,\n timestamp: activity.created_at,\n slug: activity.slug,\n }))\n .sort(\n (a, b) =>\n new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime(),\n );\n}\n\nfunction formatActivityType(slug: string): string {\n return slug\n .split(\"_\")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n}\n","import { useMemo, type ComponentProps } from \"react\";\nimport type React from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n FontSizeOptions,\n PaddingOptions,\n} from \"@fluid-app/rep-core/types\";\nimport type { WidgetPropertySchema } from \"@fluid-app/rep-core/registries\";\nimport {\n getBorderRadiusField,\n getColorField,\n getFontSizeField,\n getPaddingField,\n} from \"../core/fields\";\nimport {\n useActivities,\n type Activity,\n type ActivitySlug,\n} from \"../hooks/use-activities\";\nimport { ErrorState } from \"../components/error-state\";\nimport { FontAwesomeIcon } from \"@fortawesome/react-fontawesome\";\nimport type { IconDefinition } from \"@fortawesome/fontawesome-svg-core\";\nimport {\n faBell,\n faCalendar,\n faSquareCheck,\n faEye,\n faComment,\n faPlay,\n faCartShopping,\n faStar,\n faTrophy,\n faUser,\n faUserPlus,\n} from \"@fortawesome/pro-regular-svg-icons\";\n\n// Format timestamp to time string\nconst formatTimestamp = (timestamp: string): string => {\n const date = new Date(timestamp);\n return date.toLocaleTimeString(\"en-US\", {\n hour: \"numeric\",\n minute: \"2-digit\",\n hour12: true,\n });\n};\n\n// Format date for grouping header\nconst formatDateHeader = (timestamp: string): string => {\n const date = new Date(timestamp);\n return date.toLocaleDateString(\"en-US\", {\n month: \"long\",\n day: \"numeric\",\n });\n};\n\n// Get date string for grouping (without time)\nconst getDateKey = (timestamp: string): string => {\n const date = new Date(timestamp);\n return date.toISOString().split(\"T\")[0] ?? timestamp;\n};\n\n// Group activities by date\nconst groupActivitiesByDate = (\n activities: Activity[],\n): Map<string, Activity[]> => {\n const grouped = new Map<string, Activity[]>();\n\n for (const activity of activities) {\n const dateKey = getDateKey(activity.timestamp);\n const existing = grouped.get(dateKey);\n if (existing) {\n existing.push(activity);\n } else {\n grouped.set(dateKey, [activity]);\n }\n }\n\n return grouped;\n};\n\n// Activity slug to icon mapping\nconst ACTIVITY_ICON_MAP: Record<ActivitySlug, IconDefinition> = {\n // Orders/Cart\n order_placed: faCartShopping,\n abandoned_cart: faCartShopping,\n cart_items_added: faCartShopping,\n new_cart_items_added: faCartShopping,\n // Messages\n direct_message: faComment,\n comment_reply: faComment,\n message_received: faComment,\n message_sent: faComment,\n // Video\n video: faPlay,\n video_complete: faPlay,\n video_contact: faPlay,\n video_complete_contact: faPlay,\n // Leads\n new_lead: faUserPlus,\n page_views_contact: faUserPlus,\n smart_link_clicked: faUserPlus,\n // Page Views\n page_views: faEye,\n // Events\n upcoming_event: faCalendar,\n // Reviews\n review_left: faStar,\n // Tasks\n tasks: faSquareCheck,\n // Announcements\n announcements: faBell,\n // Fantasy\n fantasy_point: faTrophy,\n};\n\nconst getActivityIcon = (slug: ActivitySlug) =>\n ACTIVITY_ICON_MAP[slug] ?? faUser;\n\n// Activity feed item component\ntype ActivityFeedItemProps = {\n activity: Activity;\n accentColor: ColorOptions;\n textColor: ColorOptions;\n};\n\nfunction ActivityFeedItem({\n activity,\n accentColor,\n textColor,\n}: ActivityFeedItemProps) {\n const icon = getActivityIcon(activity.slug);\n\n return (\n <div className=\"flex w-full items-start gap-1.5\">\n {/* Avatar */}\n <div className=\"shrink-0\">\n {activity.avatarUrl ? (\n <div className=\"relative size-8 overflow-hidden rounded-full\">\n <img\n src={activity.avatarUrl}\n alt={activity.userName}\n className=\"size-full object-cover\"\n />\n <div className=\"border-foreground/[0.08] absolute inset-0 rounded-full border\" />\n </div>\n ) : (\n <div\n className={`bg-muted flex size-8 items-center justify-center rounded-full`}\n >\n <FontAwesomeIcon\n icon={icon}\n className={`size-3.5 text-${textColor} opacity-60`}\n />\n </div>\n )}\n </div>\n\n {/* Content */}\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex w-full items-center gap-1.5\">\n <p\n className={`flex-1 text-base font-semibold text-${textColor} truncate`}\n >\n {activity.activityType}\n </p>\n <p className={`text-xs text-${textColor} shrink-0 opacity-50`}>\n {formatTimestamp(activity.timestamp)}\n </p>\n </div>\n <p className={`text-sm text-${textColor} opacity-80`}>\n <span className={`font-medium text-${accentColor}`}>\n {activity.userName}\n </span>{\" \"}\n {activity.targetName}\n </p>\n </div>\n </div>\n );\n}\n\ntype RecentActivityWidgetProps = ComponentProps<\"div\"> & {\n // Title\n titleEnabled?: boolean;\n titleText?: string;\n titleFontSize?: FontSizeOptions;\n titleColor?: ColorOptions;\n\n // Styling\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n\n // Activity settings\n maxItemsToShow?: number;\n};\n\nexport function RecentActivityWidget({\n // Title defaults\n titleEnabled = true,\n titleText = \"Recent Activity\",\n titleFontSize = \"lg\",\n titleColor = \"foreground\",\n\n // Styling defaults\n background = {\n type: \"solid\",\n color: \"background\",\n },\n textColor = \"foreground\",\n accentColor = \"primary\",\n padding = 4,\n borderRadius = \"md\",\n\n // Activity defaults\n maxItemsToShow = 5,\n\n className,\n ...props\n}: RecentActivityWidgetProps): React.JSX.Element {\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 const { data: activities = [], isLoading, isError } = useActivities();\n\n const groupedActivities = useMemo(\n () => groupActivitiesByDate(activities),\n [activities],\n );\n\n const totalCount = Math.min(activities.length, maxItemsToShow);\n\n // Get activities to display (limited by maxItemsToShow)\n const activitiesToShow = useMemo(() => {\n const result: { date: string; items: Activity[] }[] = [];\n let count = 0;\n\n for (const [dateKey, items] of groupedActivities) {\n if (count >= maxItemsToShow) break;\n\n const remainingSlots = maxItemsToShow - count;\n const itemsToAdd = items.slice(0, remainingSlots);\n\n if (itemsToAdd.length > 0) {\n result.push({\n date: formatDateHeader(items[0]?.timestamp ?? dateKey),\n items: itemsToAdd,\n });\n count += itemsToAdd.length;\n }\n }\n\n return result;\n }, [groupedActivities, maxItemsToShow]);\n\n return (\n <div\n className={`@container overflow-hidden rounded-${borderRadius} bg-${backgroundColor} text-${textColor} border-muted border ${className}`}\n style={{ backgroundImage }}\n {...props}\n >\n <div className={`p-${padding} flex flex-col gap-2`}>\n {/* Header */}\n {titleEnabled && titleText && (\n <div className=\"flex w-full items-start gap-2\">\n <h2\n className={`flex-1 text-${titleFontSize} font-bold text-${titleColor}`}\n >\n {titleText}\n </h2>\n {!isLoading && (\n <span\n className={`text-4xl font-bold text-${textColor} leading-none`}\n >\n {totalCount.toString().padStart(2, \"0\")}\n </span>\n )}\n </div>\n )}\n\n {/* Loading state */}\n {isLoading ? (\n <div className=\"flex min-h-[200px] items-center justify-center\">\n <div className=\"h-8 w-8 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n </div>\n ) : isError ? (\n /* Error state */\n <ErrorState />\n ) : activities.length === 0 ? (\n /* Empty state */\n <div className=\"flex min-h-[200px] flex-col items-center justify-center gap-2\">\n <FontAwesomeIcon\n icon={faUser}\n className={`size-12 text-${textColor} opacity-30`}\n />\n <p\n className={`text-base font-semibold text-${textColor} opacity-50`}\n >\n No Activity To Report\n </p>\n <p className={`text-sm text-${textColor} opacity-40`}>\n You'll Do Great!\n </p>\n </div>\n ) : (\n /* Activity list */\n <div className=\"flex flex-col gap-4\">\n {activitiesToShow.map((group, groupIndex) => (\n <div key={groupIndex} className=\"flex flex-col gap-4\">\n {/* Date header */}\n <p className={`text-base font-semibold text-${textColor}`}>\n {group.date}\n </p>\n\n {/* Activity items */}\n <div className=\"flex flex-col gap-4\">\n {group.items.map((activity) => (\n <ActivityFeedItem\n key={activity.id}\n activity={activity}\n accentColor={accentColor}\n textColor={textColor}\n />\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nexport const recentActivityWidgetPropertySchema: WidgetPropertySchema = {\n widgetType: \"RecentActivityWidget\",\n displayName: \"Recent Activity Widget\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [\n // Styling Tab - Title Group\n {\n key: \"titleEnabled\",\n label: \"Widget Title\",\n type: \"boolean\",\n description: \"Enable the title displayed above the activity feed\",\n defaultValue: true,\n tab: \"styling\",\n group: \"Title\",\n },\n {\n key: \"titleText\",\n label: \"Title\",\n type: \"text\",\n description: \"Title text displayed above the activity feed\",\n defaultValue: \"Recent Activity\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n },\n getFontSizeField({\n key: \"titleFontSize\",\n label: \"Title Font Size\",\n description: \"Font size for the widget title\",\n defaultValue: \"xl\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n getColorField({\n key: \"titleColor\",\n label: \"Title Color\",\n description: \"Color for the widget title\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Title\",\n requiresKeyToBeTrue: \"titleEnabled\",\n }),\n\n // Styling Tab - Design Group\n {\n type: \"background\",\n key: \"background\",\n label: \"Background\",\n description: \"Background for the widget container\",\n defaultValue: \"background\",\n tab: \"styling\",\n group: \"Design\",\n },\n getColorField({\n key: \"textColor\",\n label: \"Text Color\",\n description: \"Default text color for activity content\",\n defaultValue: \"foreground\",\n tab: \"styling\",\n group: \"Design\",\n }),\n getColorField({\n key: \"accentColor\",\n label: \"Accent Color\",\n description: \"Color used for links and highlights\",\n defaultValue: \"primary\",\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 getPaddingField({\n key: \"padding\",\n label: \"Padding\",\n description: \"Padding around the widget container\",\n defaultValue: 4,\n tab: \"styling\",\n group: \"Design\",\n }),\n getBorderRadiusField({\n key: \"borderRadius\",\n label: \"Border Radius\",\n description: \"Border radius for the widget container\",\n defaultValue: \"md\",\n tab: \"styling\",\n group: \"Design\",\n }),\n\n // Styling Tab - Display Group\n {\n key: \"maxItemsToShow\",\n label: \"Max Items\",\n type: \"number\",\n description: \"Maximum number of activity items to display\",\n defaultValue: 5,\n tab: \"styling\",\n group: \"Display\",\n },\n ],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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P,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;oDACY;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACP,qBAAqB;GACtB,CAAC;EAGF;GACE,MAAM;GACN,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;oDACa;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;oDACY;GACZ,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EACF;GACE,KAAK;GACL,MAAM;GACN,OAAO;GACP,KAAK;GACL,OAAO;GACR;sDACe;GACd,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;2DACmB;GACnB,KAAK;GACL,OAAO;GACP,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR,CAAC;EAGF;GACE,KAAK;GACL,OAAO;GACP,MAAM;GACN,aAAa;GACb,cAAc;GACd,KAAK;GACL,OAAO;GACR;EACF;CACF"}
|