UNPKG

sanity-plugin-wistia-input

Version:
541 lines (540 loc) 22.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: !0 }); var sanity = require("sanity"), jsxRuntime = require("react/jsx-runtime"), react = require("react"), ui = require("@sanity/ui"), icons = require("@sanity/icons"); const wistiaMedia = { name: "wistiaMedia", type: "object", title: "Wistia media", fields: [ { type: "number", name: "id" }, { type: "string", name: "hashed_id" } ], preview: { select: { title: "title", subtitle: "hashed_id" }, prepare({ title, subtitle }) { return { title: title || "Wistia media", subtitle }; } } }, playerUrl = (mediaUrl) => { let params = new URLSearchParams(), wistiaSettings = { playbar: !0, playButton: !0, seo: !1, controlsVisibleOnLoad: !0, autoPlay: !1, doNotTrack: !0, preload: "none", volumeControl: !0, copyLinkAndThumbnailEnabled: !0, fullscreenButton: !0, wmode: "transparent", videoFoam: !1, fitStrategy: "fill" }; for (let key in wistiaSettings) params.append(key, wistiaSettings[key]); return `${mediaUrl}?${params.toString()}`; }; function Player({ mediaUrl }) { return /* @__PURE__ */ jsxRuntime.jsx( "div", { style: { width: "100%", borderRadius: "3px", overflow: "hidden" }, children: mediaUrl && /* @__PURE__ */ jsxRuntime.jsx( "iframe", { allow: "autoplay; fullscreen;", "allow-transparency": "true", width: "100%", style: { aspectRatio: "16/9", border: 0, display: "block" }, src: playerUrl(mediaUrl) } ) } ); } const WistiaFoldersComponent = ({ folders, loadingFolderId, error, hasMore, loadingMore, onFolderClick, onLoadMore, config }) => { const [hoveredId, setHoveredId] = react.useState(null); return error ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { padding: 3, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: [3, 3, 4], radius: 2, shadow: 1, tone: "critical", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { align: "center", children: error }) }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [ folders.length ? folders.map((folder) => /* @__PURE__ */ jsxRuntime.jsx( ui.Card, { paddingTop: 3, paddingBottom: 3, paddingRight: 3, paddingLeft: 4, radius: 1, style: { cursor: "pointer" }, onClick: () => onFolderClick(folder), tone: loadingFolderId === folder.id || hoveredId === folder.id ? "primary" : "inherit", onMouseEnter: () => setHoveredId(folder.id), onMouseLeave: () => setHoveredId(null), as: "button", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "space-between", align: "center", gap: 2, children: [ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", gap: 3, paddingLeft: 1, children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: "none", children: loadingFolderId === folder.id ? /* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, { size: 2 }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 2, children: folder.public ? /* @__PURE__ */ jsxRuntime.jsx(icons.FolderIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: "none", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 2, children: /* @__PURE__ */ jsxRuntime.jsx( ui.Tooltip, { content: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, size: 1, children: "Private" }), fallbackPlacements: ["right", "left"], placement: "top", portal: !0, children: /* @__PURE__ */ jsxRuntime.jsx(icons.LockIcon, {}) } ) }) }) }) }), /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, { space: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 2, weight: "semibold", children: folder.name }) }) ] }), /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", gap: 3, children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { "aria-label": `${folder.media_count} media items`, tone: "default", children: folder.media_count }), /* @__PURE__ */ jsxRuntime.jsx( ui.Tooltip, { content: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: "Open in Wistia" }), placement: "top", fallbackPlacements: ["left", "bottom"], portal: !0, children: /* @__PURE__ */ jsxRuntime.jsx( ui.Button, { as: "a", href: `https://${config.accountSubdomain || "app"}.wistia.com/folders/${folder.hashed_id}`, target: "_blank", rel: "noopener noreferrer", icon: icons.LaunchIcon, mode: "bleed", padding: 2, onClick: (e) => e.stopPropagation() } ) } ) ] }) ] }) }, folder.id )) : /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: 4, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { align: "center", muted: !0, size: 1, children: "No folders found." }) }), hasMore && /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: 3, borderTop: !0, children: /* @__PURE__ */ jsxRuntime.jsx( ui.Button, { mode: "bleed", text: loadingMore ? "Loading\u2026" : "Show more", onClick: onLoadMore, disabled: loadingMore, width: "fill" } ) }) ] }); }; var Folder = react.memo(WistiaFoldersComponent); const groupBy = (array) => array.reduce((rv, x) => { const key = x.section ?? "undefined"; return rv[key] = rv[key] ? [...rv[key], x] : [x], rv; }, {}), wistiaMediasComponent = ({ medias, hasMore, loadingMore, onVideoClick, onLoadMore, config }) => { const [hoveredId, setHoveredId] = react.useState(null), groupedMedias = react.useMemo(() => groupBy(medias), [medias]); return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [ Object.keys(groupedMedias).length ? Object.keys(groupedMedias).map((section) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [ section !== "undefined" && /* @__PURE__ */ jsxRuntime.jsx( ui.Card, { padding: 3, paddingLeft: 4, borderBottom: !0, style: { position: "sticky", top: 0, zIndex: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { as: "h3", size: 1, children: section }) } ), groupedMedias[section].map((media) => /* @__PURE__ */ jsxRuntime.jsx( ui.Card, { padding: 3, paddingLeft: 4, radius: 1, style: { cursor: "pointer" }, onClick: () => onVideoClick({ id: media.id, hashed_id: media.hashed_id }), tone: hoveredId === media.id ? "primary" : "inherit", onMouseEnter: () => setHoveredId(media.id), onMouseLeave: () => setHoveredId(null), as: "button", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 3, align: "center", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: 0, overflow: "hidden", radius: 2, shadow: 1, flex: "none", children: /* @__PURE__ */ jsxRuntime.jsx( "img", { src: media.thumbnail.url, width: 70, height: Math.round(70 / (media.thumbnail.width / media.thumbnail.height)), style: { display: "block" }, alt: media.name } ) }), /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, { space: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { title: media.name, textOverflow: "ellipsis", weight: "semibold", children: media.name }) }), /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: "none", style: { marginLeft: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, children: new Date(media.duration * 1e3).toISOString().slice(11, 19) }) }), /* @__PURE__ */ jsxRuntime.jsx( ui.Tooltip, { content: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: "Open in Wistia" }), placement: "top", fallbackPlacements: ["left", "bottom"], portal: !0, children: /* @__PURE__ */ jsxRuntime.jsx( ui.Button, { as: "a", href: `https://${config.accountSubdomain || "app"}.wistia.com/medias/${media.hashed_id}`, target: "_blank", rel: "noopener noreferrer", icon: icons.LaunchIcon, mode: "bleed", padding: 2, onClick: (e) => e.stopPropagation() } ) } ) ] }) }, media.id )) ] }, section)) : /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: 5, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { align: "center", muted: !0, size: 1, children: "No media found." }) }), hasMore && /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: 3, borderTop: !0, children: /* @__PURE__ */ jsxRuntime.jsx( ui.Button, { mode: "bleed", text: loadingMore ? "Loading\u2026" : "Show more", onClick: onLoadMore, disabled: loadingMore, width: "fill" } ) }) ] }); }; var Medias = react.memo(wistiaMediasComponent); const RESULTS_PER_PAGE = 100, WISTIA_API_URL = "https://api.wistia.com/modern"; function useWistiaData(path, config, onFirstLoad) { const [data, setData] = react.useState([]), [loadingMore, setLoadingMore] = react.useState(!1), [error, setError] = react.useState(""), [page, setPage] = react.useState(1), [hasMore, setHasMore] = react.useState(!1), wistiaAPIOptions = { headers: { "X-Wistia-API-Version": "2026-01", Authorization: `Bearer ${config.token}` } }, onFirstLoadRef = react.useRef(onFirstLoad); onFirstLoadRef.current = onFirstLoad, react.useEffect(() => { if (!path) { setData([]), setHasMore(!1), setError(""), setPage(1); return; } setPage(1), fetch(`${WISTIA_API_URL}${path}&page=1&per_page=${RESULTS_PER_PAGE}`, wistiaAPIOptions).then((r) => { if (!r.ok) throw new Error( r.status === 401 ? "401 Not authorised - check your API key permissions." : `${r.status} error` ); return r.json(); }).then((result) => { setHasMore(result.length === RESULTS_PER_PAGE), setData(result), onFirstLoadRef.current?.(result); }).catch((err) => setError(err.message)); }, [path, config.token]); const loadMore = react.useCallback(() => { if (!path) return; const nextPage = page + 1; setPage(nextPage), setLoadingMore(!0), fetch(`${WISTIA_API_URL}${path}&page=${nextPage}&per_page=${RESULTS_PER_PAGE}`, wistiaAPIOptions).then((r) => r.json()).then((result) => { setHasMore(result.length === RESULTS_PER_PAGE), setData((prev) => [...prev, ...result]), setLoadingMore(!1); }).catch(console.error); }, [page, path, config.token]); return { data, loadingMore, error, hasMore, loadMore }; } const WistiaInputComponent = (props) => { const { value, onChange, config, schemaType, renderDefault } = props, { push: pushToast } = ui.useToast(), [isPickerMounted, setIsPickerMounted] = react.useState(!1), [isDialogOpen, setIsDialogOpen] = react.useState(!1), [isFolderLoading, setIsFolderLoading] = react.useState(!1), [selectedFolder, setSelectedFolder] = react.useState(null), [loadingFolderId, setLoadingFolderId] = react.useState(null), [visibleFolder, setVisibleFolder] = react.useState(null), { data: folders, loadingMore: foldersLoadingMore, error: foldersError, hasMore: hasMoreFolders, loadMore: loadMoreFolders } = useWistiaData( isPickerMounted ? "/folders?sort_by=updated&sort_direction=0" : null, config, () => { setIsFolderLoading(!1), setIsDialogOpen(!0); } ), { data: medias, loadingMore: mediasLoadingMore, hasMore: hasMoreMedias, loadMore: loadMoreMedias } = useWistiaData( selectedFolder ? `/medias?folder_id=${selectedFolder.id}&sort_by=name` : null, config, () => { setLoadingFolderId(null), setVisibleFolder(selectedFolder); } ), handleChange = react.useCallback( (newValue) => { setIsPickerMounted(!1), setIsDialogOpen(!1), setSelectedFolder(null), setVisibleFolder(null), onChange([ sanity.setIfMissing({ _type: schemaType.name }), sanity.set(newValue.hashed_id, ["hashed_id"]), sanity.set(newValue.id, ["id"]) ]); }, [onChange, schemaType] ), handleClear = react.useCallback(() => { onChange(sanity.unset()); }, [onChange]), handleCopyUrl = react.useCallback(() => { navigator.clipboard.writeText(`https://fast.wistia.net/embed/iframe/${value?.hashed_id}`), pushToast({ closable: !0, status: "success", title: "URL copied to clipboard" }); }, [value, pushToast]), handleOpenPicker = react.useCallback(() => { setIsFolderLoading(!0), setIsPickerMounted(!0); }, []), handleClosePicker = react.useCallback(() => { setIsPickerMounted(!1), setIsDialogOpen(!1), setSelectedFolder(null), setVisibleFolder(null), setLoadingFolderId(null), setIsFolderLoading(!1); }, []), handleFolderClick = react.useCallback((folder) => { setLoadingFolderId(folder.id), setSelectedFolder(folder); }, []); if (!config?.token?.length) return /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: [3, 3, 4], radius: 2, shadow: 1, tone: "critical", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { align: "center", children: [ "Missing required API token in Sanity config.", " ", /* @__PURE__ */ jsxRuntime.jsx("a", { href: "https://docs.wistia.com/docs/making-api-requests", children: "See Wistia documentation." }) ] }) }); const mediaUrl = value?.hashed_id ? `https://fast.wistia.net/embed/iframe/${value.hashed_id}` : null, picker = isDialogOpen && /* @__PURE__ */ jsxRuntime.jsx( ui.Dialog, { id: "wistia-picker", onClose: handleClosePicker, animate: !0, width: 1, header: visibleFolder ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "space-between", children: [ /* @__PURE__ */ jsxRuntime.jsx( ui.Button, { icon: icons.ChevronLeftIcon, onClick: () => { setSelectedFolder(null), setVisibleFolder(null); }, mode: "bleed", padding: 2, space: 2, text: "All folders" } ), /* @__PURE__ */ jsxRuntime.jsx( ui.Button, { as: "a", href: `https://${config.accountSubdomain || "app"}.wistia.com/folders/${visibleFolder.hashed_id}`, target: "_blank", rel: "noopener noreferrer", icon: icons.LaunchIcon, mode: "bleed", padding: 2, space: 2, text: "Open in Wistia" } ) ] }), /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { justify: "space-between", align: "center", flex: 1, paddingBottom: 0, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 3, children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { as: "h2", size: 2, children: visibleFolder.name }), visibleFolder.description ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { textOverflow: "ellipsis", size: 1, muted: !0, children: visibleFolder.description.replace(/<[^>]*>/g, "").trim() }) : null ] }) }) ] }) : "Select a folder", footer: visibleFolder ? /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { tone: "transparent", paddingX: 4, paddingY: 4, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", justify: "flex-start", gap: 3, children: [ !visibleFolder.public && /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { tone: "caution", children: "Private" }), /* @__PURE__ */ jsxRuntime.jsxs(ui.Badge, { title: `${visibleFolder.media_count} items`, tone: "default", children: [ visibleFolder.media_count, " items" ] }), /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { title: visibleFolder.updated, size: 1, children: [ /* @__PURE__ */ jsxRuntime.jsx("b", { children: "Updated" }), " ", new Date(visibleFolder.updated).toLocaleDateString(void 0, { day: "numeric", month: "short", year: "numeric", hour: "2-digit", minute: "2-digit" }) ] }) ] }) }) : void 0, children: visibleFolder ? /* @__PURE__ */ jsxRuntime.jsx( Medias, { config, medias, hasMore: hasMoreMedias, loadingMore: mediasLoadingMore, onVideoClick: handleChange, onLoadMore: loadMoreMedias } ) : /* @__PURE__ */ jsxRuntime.jsx( Folder, { config, folders, loadingFolderId, error: foldersError, hasMore: hasMoreFolders, loadingMore: foldersLoadingMore, onFolderClick: handleFolderClick, onLoadMore: loadMoreFolders } ) } ), extraFields = config.fields?.length ? /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, { marginTop: 4, children: renderDefault({ ...props, members: props.members.filter( (m) => m.kind === "field" && config.fields.some((f) => f.name === m.name) ) }) }) : null; return mediaUrl ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 0, children: [ /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { radius: 2, shadow: 1, padding: 2, children: [ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "space-between", align: "center", padding: 0, paddingBottom: 2, gap: 1, children: [ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { gap: 1, children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { animate: !0, content: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: "Open in Wistia" }), placement: "top", portal: !0, children: /* @__PURE__ */ jsxRuntime.jsx( ui.Button, { as: "a", href: `https://${config.accountSubdomain || "app"}.wistia.com/medias/${value?.hashed_id}`, target: "_blank", rel: "noopener noreferrer", icon: icons.LaunchIcon, mode: "bleed", padding: 2 } ) }), /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { animate: !0, content: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, children: "Copy embed URL" }), placement: "top", portal: !0, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { mode: "bleed", padding: 2, icon: icons.LinkIcon, onClick: handleCopyUrl }) }) ] }), /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", gap: 1, children: [ /* @__PURE__ */ jsxRuntime.jsx( ui.Button, { text: "Replace", padding: 2, space: 2, mode: "bleed", icon: icons.SearchIcon, loading: isFolderLoading, onClick: handleOpenPicker } ), /* @__PURE__ */ jsxRuntime.jsx( ui.Button, { text: "Clear", padding: 2, space: 2, mode: "bleed", icon: icons.ResetIcon, tone: "critical", onClick: handleClear } ) ] }) ] }), /* @__PURE__ */ jsxRuntime.jsx(Player, { mediaUrl }) ] }), picker, extraFields ] }) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { tone: "inherit", radius: 2, border: !0, padding: 2, paddingLeft: 3, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "space-between", align: "center", children: [ /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", gap: 3, children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: "none", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 2, children: /* @__PURE__ */ jsxRuntime.jsx(icons.DocumentVideoIcon, {}) }) }), /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: 1, muted: !0, children: "No media selected" }) ] }), /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { align: "center", gap: 1, children: [ /* @__PURE__ */ jsxRuntime.jsx( ui.Button, { as: "a", href: `https://${config.accountSubdomain || "app"}.wistia.com/home`, target: "_blank", rel: "noopener noreferrer", icon: icons.LaunchIcon, mode: "bleed", onClick: (e) => e.stopPropagation(), text: "Open Wistia", padding: 2, space: 2 } ), /* @__PURE__ */ jsxRuntime.jsx( ui.Button, { mode: "bleed", text: "Select", icon: icons.SearchIcon, loading: isFolderLoading, onClick: handleOpenPicker, padding: 2, space: 2 } ) ] }) ] }) }), picker, extraFields ] }); }; var Preview = (props) => { const { subtitle: hashed_id, renderDefault } = props; return /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 1, children: [ renderDefault({ ...props }), hashed_id && /* @__PURE__ */ jsxRuntime.jsx(Player, { mediaUrl: `https://fast.wistia.net/embed/iframe/${hashed_id}` }) ] }); }; function wistiaMediaRender(config) { return { components: { input: (props) => /* @__PURE__ */ jsxRuntime.jsx(WistiaInputComponent, { config, ...props }), preview: (props) => /* @__PURE__ */ jsxRuntime.jsx(Preview, { ...props }) } }; } const wistiaInput = sanity.definePlugin((config) => ({ name: "sanity-plugin-wistia-input", schema: { types: [ { ...wistiaMedia, fields: [ ...wistiaMedia.fields, ...(config.fields ?? []).filter( (f) => !wistiaMedia.fields.some((base) => base.name === f.name) ) ], ...wistiaMediaRender(config) } ] } })); exports.wistiaInput = wistiaInput; //# sourceMappingURL=index.js.map