@volchoklv/socialfire-widget 1.0.2 → 1.0.4
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/README.md +6 -1
- package/dist/core/styles.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/utils-IMx49iyq.js +2 -0
- package/dist/utils-IMx49iyq.js.map +1 -0
- package/dist/widget.js +1 -1
- package/package.json +2 -1
- package/dist/utils-BNIlvbZe.js +0 -2
- package/dist/utils-BNIlvbZe.js.map +0 -1
package/README.md
CHANGED
|
@@ -155,12 +155,17 @@ Requires:
|
|
|
155
155
|
- React component: ~6 KB gzipped
|
|
156
156
|
- Vanilla Web Component: ~2 KB gzipped
|
|
157
157
|
|
|
158
|
+
## Author
|
|
159
|
+
|
|
160
|
+
**Volchok** - [volchok.dev](https://volchok.dev)
|
|
161
|
+
|
|
158
162
|
## License
|
|
159
163
|
|
|
160
164
|
MIT
|
|
161
165
|
|
|
162
166
|
## Links
|
|
163
167
|
|
|
168
|
+
- [Socialfire](https://socialfire.dev) - Create and manage Instagram feeds
|
|
169
|
+
- [Documentation](https://socialfire.dev/help)
|
|
164
170
|
- [GitHub Repository](https://github.com/VolchokLV/socialfire-widget)
|
|
165
171
|
- [NPM Package](https://www.npmjs.com/package/@volchoklv/socialfire-widget)
|
|
166
|
-
- [Documentation](https://docs.socialfire.com/widget)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/core/styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,eAAO,MAAM,MAAM;oBAED,MAAM,OAAO,MAAM,KAAG,aAAa;cAgB9C,aAAa;mBAIb,aAAa;WAUb,aAAa;eAUb,aAAa;aAMb,aAAa;kBAcb,aAAa;yBAIb,aAAa;mBAMb,aAAa;cAKb,aAAa;cAIb,aAAa;oBAUb,aAAa;iBAUb,aAAa;sBAQb,aAAa;kBAOb,aAAa;aASb,aAAa;iBAKb,aAAa;oBAQb,aAAa;gBAKb,aAAa;kBAMb,aAAa;oBAOb,aAAa;CACnB,CAAC;AAGF,eAAO,MAAM,kBAAkB,
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/core/styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,eAAO,MAAM,MAAM;oBAED,MAAM,OAAO,MAAM,KAAG,aAAa;cAgB9C,aAAa;mBAIb,aAAa;WAUb,aAAa;eAUb,aAAa;aAMb,aAAa;kBAcb,aAAa;yBAIb,aAAa;mBAMb,aAAa;cAKb,aAAa;cAIb,aAAa;oBAUb,aAAa;iBAUb,aAAa;sBAQb,aAAa;kBAOb,aAAa;aASb,aAAa;iBAKb,aAAa;oBAQb,aAAa;gBAKb,aAAa;kBAMb,aAAa;oBAOb,aAAa;CACnB,CAAC;AAGF,eAAO,MAAM,kBAAkB,YAe9B,CAAC;AAGF,eAAO,MAAM,YAAY,mrFA+JxB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{jsxs as e,jsx as r,Fragment as n}from"react/jsx-runtime";import{useState as t,useEffect as o}from"react";import{s as i,g as l,f as s,i as a,F as c}from"./utils-
|
|
1
|
+
import{jsxs as e,jsx as r,Fragment as n}from"react/jsx-runtime";import{useState as t,useEffect as o}from"react";import{s as i,g as l,f as s,i as a,F as c}from"./utils-IMx49iyq.js";function d({post:n,feed:o}){const[a,c]=t(!1);/* @__PURE__ */
|
|
2
2
|
return e("a",{href:n.permalink,target:"_blank",rel:"noopener noreferrer",style:{...i.postLink,...a?i.postLinkHover:{}},onMouseEnter:()=>c(!0),onMouseLeave:()=>c(!1),children:[
|
|
3
3
|
/* @__PURE__ */r("img",{src:l(n),alt:n.caption||"Instagram post",style:i.image,loading:"lazy"}),"VIDEO"===n.mediaType&&/* @__PURE__ */r("div",{style:i.mediaIcon,children:/* @__PURE__ */r("svg",{style:i.svgIcon,fill:"currentColor",viewBox:"0 0 24 24",children:/* @__PURE__ */r("path",{d:"M8 5v14l11-7z"})})}),"CAROUSEL_ALBUM"===n.mediaType&&/* @__PURE__ */r("div",{style:i.mediaIcon,children:/* @__PURE__ */r("svg",{style:i.svgIcon,fill:"currentColor",viewBox:"0 0 24 24",children:/* @__PURE__ */r("path",{d:"M22 16V4c0-1.1-.9-2-2-2H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2zm-11-4l2.03 2.71L16 11l4 5H8l3-4zM2 6v14c0 1.1.9 2 2 2h14v-2H4V6H2z"})})}),(o.showLikes||o.showComments)&&/* @__PURE__ */e("div",{style:{...i.hoverOverlay,...a?i.hoverOverlayVisible:{}},children:[o.showLikes&&/* @__PURE__ */e("div",{style:i.statContainer,children:[
|
|
4
4
|
/* @__PURE__ */r("svg",{style:i.statIcon,fill:"currentColor",viewBox:"0 0 24 24",children:/* @__PURE__ */r("path",{d:"M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"})}),
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
class n{constructor(n){this.baseUrl=n||this.getDefaultBaseUrl()}getDefaultBaseUrl(){return"undefined"!=typeof window?"undefined"!=typeof process&&process.env?.NEXT_PUBLIC_APP_URL?process.env.NEXT_PUBLIC_APP_URL:window.location.origin:""}async fetchFeed(n,e){const t=`${this.baseUrl}/api/feeds/${n}`,o=await fetch(t,{signal:e,headers:{"Content-Type":"application/json"}});if(!o.ok)throw new Error(`Failed to fetch feed: ${o.statusText}`);return await o.json()}}const e={grid:(n,e)=>({display:"grid",gridTemplateColumns:`repeat(${n}, minmax(0, 1fr))`,gap:`${e}px`}),postLink:{position:"relative",aspectRatio:"1 / 1",overflow:"hidden",borderRadius:"8px",backgroundColor:"#f3f4f6",display:"block",transition:"opacity 0.2s",textDecoration:"none"},postLinkHover:{opacity:.9},image:{position:"absolute",top:0,left:0,width:"100%",height:"100%",objectFit:"cover"},mediaIcon:{position:"absolute",top:"8px",right:"8px",backgroundColor:"rgba(0, 0, 0, 0.5)",borderRadius:"9999px",padding:"4px"},svgIcon:{width:"16px",height:"16px",color:"white"},hoverOverlay:{position:"absolute",inset:0,backgroundColor:"rgba(0, 0, 0, 0.6)",opacity:0,transition:"opacity 0.2s",display:"flex",alignItems:"center",justifyContent:"center",gap:"16px",color:"white"},hoverOverlayVisible:{opacity:1},statContainer:{display:"flex",alignItems:"center",gap:"6px"},statIcon:{width:"20px",height:"20px"},statText:{fontWeight:600},captionOverlay:{position:"absolute",bottom:0,left:0,right:0,background:"linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent)",padding:"12px"},captionText:{color:"white",fontSize:"12px",lineHeight:"16px",display:"-webkit-box",WebkitLineClamp:2,WebkitBoxOrient:"vertical",overflow:"hidden"},loadingContainer:{display:"flex",alignItems:"center",justifyContent:"center",padding:"48px"},loadingInner:{display:"flex",flexDirection:"column",alignItems:"center",gap:"12px"},spinner:{width:"32px",height:"32px",border:"4px solid #2563eb",borderTopColor:"transparent",borderRadius:"9999px",animation:"spin 1s linear infinite"},loadingText:{fontSize:"14px",color:"#6b7280"},errorContainer:{padding:"24px",backgroundColor:"#fef2f2",border:"1px solid #fecaca",borderRadius:"8px"},errorTitle:{color:"#dc2626",fontWeight:500},errorMessage:{fontSize:"14px",color:"#ef4444",marginTop:"4px"},emptyContainer:{padding:"48px",textAlign:"center",color:"#6b7280"}},t=()=>{if("undefined"==typeof document)return;if(document.getElementById("socialfire-widget-global"))return;const n=document.createElement("style");n.id="socialfire-widget-global",n.textContent="\n .socialfire-widget {\n width: 100%;\n }\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n ",document.head.appendChild(n)},o="\n :host {\n display: block;\n }\n\n .socialfire-widget {\n width: 100%;\n }\n\n .socialfire-grid {\n display: grid;\n }\n\n .post-link {\n position: relative;\n aspect-ratio: 1 / 1;\n overflow: hidden;\n border-radius: 8px;\n background-color: #f3f4f6;\n display: block;\n transition: opacity 0.2s;\n text-decoration: none;\n }\n\n .post-link:hover {\n opacity: 0.9;\n }\n\n .post-image {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n .media-icon {\n position: absolute;\n top: 8px;\n right: 8px;\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: 9999px;\n padding: 4px;\n }\n\n .media-icon svg {\n width: 16px;\n height: 16px;\n color: white;\n display: block;\n }\n\n .hover-overlay {\n position: absolute;\n inset: 0;\n background-color: rgba(0, 0, 0, 0.6);\n opacity: 0;\n transition: opacity 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 16px;\n color: white;\n }\n\n .post-link:hover .hover-overlay {\n opacity: 1;\n }\n\n .stat-container {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .stat-container svg {\n width: 20px;\n height: 20px;\n }\n\n .stat-text {\n font-weight: 600;\n }\n\n .caption-overlay {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);\n padding: 12px;\n }\n\n .caption-text {\n color: white;\n font-size: 12px;\n line-height: 16px;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n\n .loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 48px;\n }\n\n .loading-inner {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n .spinner {\n width: 32px;\n height: 32px;\n border: 4px solid #2563eb;\n border-top-color: transparent;\n border-radius: 9999px;\n animation: spin 1s linear infinite;\n }\n\n .loading-text {\n font-size: 14px;\n color: #6b7280;\n }\n\n .error-container {\n padding: 24px;\n background-color: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 8px;\n }\n\n .error-title {\n color: #dc2626;\n font-weight: 500;\n }\n\n .error-message {\n font-size: 14px;\n color: #ef4444;\n margin-top: 4px;\n }\n\n .empty-container {\n padding: 48px;\n text-align: center;\n color: #6b7280;\n }\n";function i(n){return n>=1e6?(n/1e6).toFixed(1).replace(/\.0$/,"")+"M":n>=1e3?(n/1e3).toFixed(1).replace(/\.0$/,"")+"K":n.toString()}function r(n){return"VIDEO"===n.mediaType&&n.thumbnailUrl?n.thumbnailUrl:n.mediaUrl}function a(n){const e=document.createElement("div");return e.textContent=n,e.innerHTML}export{n as F,o as a,a as e,i as f,r as g,t as i,e as s};
|
|
2
|
+
//# sourceMappingURL=utils-IMx49iyq.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils-IMx49iyq.js","sources":["../src/core/fetcher.ts","../src/core/styles.ts","../src/core/utils.ts"],"sourcesContent":["import { SocialfireFeed } from './types';\r\n\r\nexport class FeedFetcher {\r\n private baseUrl: string;\r\n\r\n constructor(baseUrl?: string) {\r\n this.baseUrl = baseUrl || this.getDefaultBaseUrl();\r\n }\r\n\r\n private getDefaultBaseUrl(): string {\r\n if (typeof window !== 'undefined') {\r\n // Check for Next.js env var\r\n if (typeof process !== 'undefined' && process.env?.NEXT_PUBLIC_APP_URL) {\r\n return process.env.NEXT_PUBLIC_APP_URL;\r\n }\r\n // Use current origin\r\n return window.location.origin;\r\n }\r\n return '';\r\n }\r\n\r\n async fetchFeed(feedId: string, signal?: AbortSignal): Promise<SocialfireFeed> {\r\n const endpoint = `${this.baseUrl}/api/feeds/${feedId}`;\r\n\r\n const response = await fetch(endpoint, {\r\n signal,\r\n headers: { 'Content-Type': 'application/json' },\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch feed: ${response.statusText}`);\r\n }\r\n\r\n return await response.json();\r\n }\r\n}\r\n","import type { CSSProperties } from 'react';\r\n\r\nexport const styles = {\r\n // Grid container\r\n grid: (columns: number, gap: number): CSSProperties => ({\r\n display: 'grid',\r\n gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,\r\n gap: `${gap}px`,\r\n }),\r\n\r\n // Post link wrapper\r\n postLink: {\r\n position: 'relative' as const,\r\n aspectRatio: '1 / 1',\r\n overflow: 'hidden',\r\n borderRadius: '8px',\r\n backgroundColor: '#f3f4f6',\r\n display: 'block',\r\n transition: 'opacity 0.2s',\r\n textDecoration: 'none',\r\n } as CSSProperties,\r\n\r\n postLinkHover: {\r\n opacity: 0.9,\r\n } as CSSProperties,\r\n\r\n // Image styles\r\n image: {\r\n position: 'absolute' as const,\r\n top: 0,\r\n left: 0,\r\n width: '100%',\r\n height: '100%',\r\n objectFit: 'cover' as const,\r\n } as CSSProperties,\r\n\r\n // Media type icons (video, carousel)\r\n mediaIcon: {\r\n position: 'absolute' as const,\r\n top: '8px',\r\n right: '8px',\r\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\r\n borderRadius: '9999px',\r\n padding: '4px',\r\n } as CSSProperties,\r\n\r\n svgIcon: {\r\n width: '16px',\r\n height: '16px',\r\n color: 'white',\r\n } as CSSProperties,\r\n\r\n // Hover overlay with stats\r\n hoverOverlay: {\r\n position: 'absolute' as const,\r\n inset: 0,\r\n backgroundColor: 'rgba(0, 0, 0, 0.6)',\r\n opacity: 0,\r\n transition: 'opacity 0.2s',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n gap: '16px',\r\n color: 'white',\r\n } as CSSProperties,\r\n\r\n hoverOverlayVisible: {\r\n opacity: 1,\r\n } as CSSProperties,\r\n\r\n statContainer: {\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '6px',\r\n } as CSSProperties,\r\n\r\n statIcon: {\r\n width: '20px',\r\n height: '20px',\r\n } as CSSProperties,\r\n\r\n statText: {\r\n fontWeight: 600,\r\n } as CSSProperties,\r\n\r\n // Caption overlay\r\n captionOverlay: {\r\n position: 'absolute' as const,\r\n bottom: 0,\r\n left: 0,\r\n right: 0,\r\n background: 'linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent)',\r\n padding: '12px',\r\n } as CSSProperties,\r\n\r\n captionText: {\r\n color: 'white',\r\n fontSize: '12px',\r\n lineHeight: '16px',\r\n display: '-webkit-box',\r\n WebkitLineClamp: 2,\r\n WebkitBoxOrient: 'vertical' as const,\r\n overflow: 'hidden',\r\n } as CSSProperties,\r\n\r\n // Loading state\r\n loadingContainer: {\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n padding: '48px',\r\n } as CSSProperties,\r\n\r\n loadingInner: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n alignItems: 'center',\r\n gap: '12px',\r\n } as CSSProperties,\r\n\r\n spinner: {\r\n width: '32px',\r\n height: '32px',\r\n border: '4px solid #2563eb',\r\n borderTopColor: 'transparent',\r\n borderRadius: '9999px',\r\n animation: 'spin 1s linear infinite',\r\n } as CSSProperties,\r\n\r\n loadingText: {\r\n fontSize: '14px',\r\n color: '#6b7280',\r\n } as CSSProperties,\r\n\r\n // Error state\r\n errorContainer: {\r\n padding: '24px',\r\n backgroundColor: '#fef2f2',\r\n border: '1px solid #fecaca',\r\n borderRadius: '8px',\r\n } as CSSProperties,\r\n\r\n errorTitle: {\r\n color: '#dc2626',\r\n fontWeight: 500,\r\n } as CSSProperties,\r\n\r\n errorMessage: {\r\n fontSize: '14px',\r\n color: '#ef4444',\r\n marginTop: '4px',\r\n } as CSSProperties,\r\n\r\n // Empty state\r\n emptyContainer: {\r\n padding: '48px',\r\n textAlign: 'center' as const,\r\n color: '#6b7280',\r\n } as CSSProperties,\r\n};\r\n\r\n// Inject global styles for animations (used by both React and vanilla)\r\nexport const injectGlobalStyles = () => {\r\n if (typeof document === 'undefined') return;\r\n if (document.getElementById('socialfire-widget-global')) return;\r\n\r\n const style = document.createElement('style');\r\n style.id = 'socialfire-widget-global';\r\n style.textContent = `\r\n .socialfire-widget {\r\n width: 100%;\r\n }\r\n @keyframes spin {\r\n to { transform: rotate(360deg); }\r\n }\r\n `;\r\n document.head.appendChild(style);\r\n};\r\n\r\n// CSS string for Shadow DOM (vanilla component)\r\nexport const shadowStyles = `\r\n :host {\r\n display: block;\r\n }\r\n\r\n .socialfire-widget {\r\n width: 100%;\r\n }\r\n\r\n .socialfire-grid {\r\n display: grid;\r\n }\r\n\r\n .post-link {\r\n position: relative;\r\n aspect-ratio: 1 / 1;\r\n overflow: hidden;\r\n border-radius: 8px;\r\n background-color: #f3f4f6;\r\n display: block;\r\n transition: opacity 0.2s;\r\n text-decoration: none;\r\n }\r\n\r\n .post-link:hover {\r\n opacity: 0.9;\r\n }\r\n\r\n .post-image {\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n width: 100%;\r\n height: 100%;\r\n object-fit: cover;\r\n }\r\n\r\n .media-icon {\r\n position: absolute;\r\n top: 8px;\r\n right: 8px;\r\n background-color: rgba(0, 0, 0, 0.5);\r\n border-radius: 9999px;\r\n padding: 4px;\r\n }\r\n\r\n .media-icon svg {\r\n width: 16px;\r\n height: 16px;\r\n color: white;\r\n display: block;\r\n }\r\n\r\n .hover-overlay {\r\n position: absolute;\r\n inset: 0;\r\n background-color: rgba(0, 0, 0, 0.6);\r\n opacity: 0;\r\n transition: opacity 0.2s;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 16px;\r\n color: white;\r\n }\r\n\r\n .post-link:hover .hover-overlay {\r\n opacity: 1;\r\n }\r\n\r\n .stat-container {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n }\r\n\r\n .stat-container svg {\r\n width: 20px;\r\n height: 20px;\r\n }\r\n\r\n .stat-text {\r\n font-weight: 600;\r\n }\r\n\r\n .caption-overlay {\r\n position: absolute;\r\n bottom: 0;\r\n left: 0;\r\n right: 0;\r\n background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);\r\n padding: 12px;\r\n }\r\n\r\n .caption-text {\r\n color: white;\r\n font-size: 12px;\r\n line-height: 16px;\r\n display: -webkit-box;\r\n -webkit-line-clamp: 2;\r\n -webkit-box-orient: vertical;\r\n overflow: hidden;\r\n }\r\n\r\n .loading-container {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 48px;\r\n }\r\n\r\n .loading-inner {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n gap: 12px;\r\n }\r\n\r\n @keyframes spin {\r\n to { transform: rotate(360deg); }\r\n }\r\n\r\n .spinner {\r\n width: 32px;\r\n height: 32px;\r\n border: 4px solid #2563eb;\r\n border-top-color: transparent;\r\n border-radius: 9999px;\r\n animation: spin 1s linear infinite;\r\n }\r\n\r\n .loading-text {\r\n font-size: 14px;\r\n color: #6b7280;\r\n }\r\n\r\n .error-container {\r\n padding: 24px;\r\n background-color: #fef2f2;\r\n border: 1px solid #fecaca;\r\n border-radius: 8px;\r\n }\r\n\r\n .error-title {\r\n color: #dc2626;\r\n font-weight: 500;\r\n }\r\n\r\n .error-message {\r\n font-size: 14px;\r\n color: #ef4444;\r\n margin-top: 4px;\r\n }\r\n\r\n .empty-container {\r\n padding: 48px;\r\n text-align: center;\r\n color: #6b7280;\r\n }\r\n`;\r\n","export function formatNumber(num: number): string {\r\n if (num >= 1000000) {\r\n return (num / 1000000).toFixed(1).replace(/\\.0$/, '') + 'M';\r\n }\r\n if (num >= 1000) {\r\n return (num / 1000).toFixed(1).replace(/\\.0$/, '') + 'K';\r\n }\r\n return num.toString();\r\n}\r\n\r\nexport function getMediaUrl(post: {\r\n mediaType: string;\r\n thumbnailUrl: string | null;\r\n mediaUrl: string;\r\n}): string {\r\n return post.mediaType === 'VIDEO' && post.thumbnailUrl\r\n ? post.thumbnailUrl\r\n : post.mediaUrl;\r\n}\r\n\r\nexport function escapeHtml(text: string): string {\r\n const div = document.createElement('div');\r\n div.textContent = text;\r\n return div.innerHTML;\r\n}\r\n"],"names":["FeedFetcher","constructor","baseUrl","this","getDefaultBaseUrl","window","process","env","NEXT_PUBLIC_APP_URL","location","origin","fetchFeed","feedId","signal","endpoint","response","fetch","headers","ok","Error","statusText","json","styles","grid","columns","gap","display","gridTemplateColumns","postLink","position","aspectRatio","overflow","borderRadius","backgroundColor","transition","textDecoration","postLinkHover","opacity","image","top","left","width","height","objectFit","mediaIcon","right","padding","svgIcon","color","hoverOverlay","inset","alignItems","justifyContent","hoverOverlayVisible","statContainer","statIcon","statText","fontWeight","captionOverlay","bottom","background","captionText","fontSize","lineHeight","WebkitLineClamp","WebkitBoxOrient","loadingContainer","loadingInner","flexDirection","spinner","border","borderTopColor","animation","loadingText","errorContainer","errorTitle","errorMessage","marginTop","emptyContainer","textAlign","injectGlobalStyles","document","getElementById","style","createElement","id","textContent","head","appendChild","shadowStyles","formatNumber","num","toFixed","replace","toString","getMediaUrl","post","mediaType","thumbnailUrl","mediaUrl","escapeHtml","text","div","innerHTML"],"mappings":"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"}
|
package/dist/widget.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{e as n,a as t,g as e,f as s,F as i}from"./utils-
|
|
1
|
+
import{e as n,a as t,g as e,f as s,F as i}from"./utils-IMx49iyq.js";function o(n){if(n.querySelector("style"))return;const e=document.createElement("style");e.textContent=t,n.appendChild(e)}function r(t){const i=t.posts.map(i=>function(t,i){const o=e(t),r=t.caption?n(t.caption):"";return`\n <a\n href="${t.permalink}"\n target="_blank"\n rel="noopener noreferrer"\n class="post-link"\n >\n <img\n src="${o}"\n alt="${r||"Instagram post"}"\n class="post-image"\n loading="lazy"\n />\n\n ${"VIDEO"===t.mediaType?'\n <div class="media-icon">\n <svg fill="currentColor" viewBox="0 0 24 24">\n <path d="M8 5v14l11-7z" />\n </svg>\n </div>\n ':""}\n\n ${"CAROUSEL_ALBUM"===t.mediaType?'\n <div class="media-icon">\n <svg fill="currentColor" viewBox="0 0 24 24">\n <path d="M22 16V4c0-1.1-.9-2-2-2H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2zm-11-4l2.03 2.71L16 11l4 5H8l3-4zM2 6v14c0 1.1.9 2 2 2h14v-2H4V6H2z" />\n </svg>\n </div>\n ':""}\n\n ${i.showLikes||i.showComments?`\n <div class="hover-overlay">\n ${i.showLikes?`\n <div class="stat-container">\n <svg fill="currentColor" viewBox="0 0 24 24">\n <path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" />\n </svg>\n <span class="stat-text">${s(t.likeCount||0)}</span>\n </div>\n `:""}\n ${i.showComments?`\n <div class="stat-container">\n <svg fill="currentColor" viewBox="0 0 24 24">\n <path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z" />\n </svg>\n <span class="stat-text">${s(t.commentsCount||0)}</span>\n </div>\n `:""}\n </div>\n `:""}\n\n ${i.showCaptions&&t.caption?`\n <div class="caption-overlay">\n <p class="caption-text">${r}</p>\n </div>\n `:""}\n </a>\n `}(i,t)).join("");return`\n <div class="socialfire-widget">\n <div\n class="socialfire-grid"\n style="grid-template-columns: repeat(${t.columns}, minmax(0, 1fr)); gap: ${t.gap}px;"\n >\n ${i}\n </div>\n </div>\n `}const a=t=>function(t){return`\n <div class="error-container">\n <p class="error-title">Failed to load Instagram feed</p>\n <p class="error-message">${n(t.message)}</p>\n </div>\n `}(t);class l extends HTMLElement{constructor(){super(),this.abortController=null,this.shadow=this.attachShadow({mode:"open"}),this.fetcher=new i}static get observedAttributes(){return["feed-id","api-url"]}connectedCallback(){this.render()}disconnectedCallback(){this.abortController?.abort()}attributeChangedCallback(){this.render()}async render(){const n=this.getAttribute("feed-id"),t=this.getAttribute("api-url")||void 0;if(!n)return this.shadow.innerHTML=a(new Error("feed-id attribute is required")),void o(this.shadow);this.shadow.innerHTML='\n <div class="loading-container">\n <div class="loading-inner">\n <div class="spinner"></div>\n <p class="loading-text">Loading feed...</p>\n </div>\n </div>\n ',o(this.shadow),this.abortController?.abort(),this.abortController=new AbortController,t&&(this.fetcher=new i(t));try{const t=await this.fetcher.fetchFeed(n,this.abortController.signal);this.shadow.innerHTML=t.posts?.length>0?r(t):'\n <div class="empty-container">\n <p>No posts available</p>\n </div>\n ',o(this.shadow),this.dispatchEvent(new CustomEvent("load",{detail:t,bubbles:!0,composed:!0}))}catch(e){if(e instanceof Error&&"AbortError"===e.name)return;const n=e instanceof Error?e:new Error("Unknown error");this.shadow.innerHTML=a(n),o(this.shadow),this.dispatchEvent(new CustomEvent("error",{detail:n,bubbles:!0,composed:!0}))}}}"undefined"==typeof window||customElements.get("socialfire-widget")||customElements.define("socialfire-widget",l);export{l as SocialfireWidgetElement};
|
|
2
2
|
//# sourceMappingURL=widget.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volchoklv/socialfire-widget",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Embeddable Instagram feed widget - React & vanilla JS",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
],
|
|
47
47
|
"author": "Socialfire",
|
|
48
48
|
"license": "MIT",
|
|
49
|
+
"homepage": "https://socialfire.dev",
|
|
49
50
|
"repository": {
|
|
50
51
|
"type": "git",
|
|
51
52
|
"url": "https://github.com/VolchokLV/socialfire-widget.git"
|
package/dist/utils-BNIlvbZe.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
class n{constructor(n){this.baseUrl=n||this.getDefaultBaseUrl()}getDefaultBaseUrl(){return"undefined"!=typeof window?"undefined"!=typeof process&&process.env?.NEXT_PUBLIC_APP_URL?process.env.NEXT_PUBLIC_APP_URL:window.location.origin:""}async fetchFeed(n,e){const t=`${this.baseUrl}/api/feeds/${n}`,o=await fetch(t,{signal:e,headers:{"Content-Type":"application/json"}});if(!o.ok)throw new Error(`Failed to fetch feed: ${o.statusText}`);return await o.json()}}const e={grid:(n,e)=>({display:"grid",gridTemplateColumns:`repeat(${n}, minmax(0, 1fr))`,gap:`${e}px`}),postLink:{position:"relative",aspectRatio:"1 / 1",overflow:"hidden",borderRadius:"8px",backgroundColor:"#f3f4f6",display:"block",transition:"opacity 0.2s",textDecoration:"none"},postLinkHover:{opacity:.9},image:{position:"absolute",top:0,left:0,width:"100%",height:"100%",objectFit:"cover"},mediaIcon:{position:"absolute",top:"8px",right:"8px",backgroundColor:"rgba(0, 0, 0, 0.5)",borderRadius:"9999px",padding:"4px"},svgIcon:{width:"16px",height:"16px",color:"white"},hoverOverlay:{position:"absolute",inset:0,backgroundColor:"rgba(0, 0, 0, 0.6)",opacity:0,transition:"opacity 0.2s",display:"flex",alignItems:"center",justifyContent:"center",gap:"16px",color:"white"},hoverOverlayVisible:{opacity:1},statContainer:{display:"flex",alignItems:"center",gap:"6px"},statIcon:{width:"20px",height:"20px"},statText:{fontWeight:600},captionOverlay:{position:"absolute",bottom:0,left:0,right:0,background:"linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent)",padding:"12px"},captionText:{color:"white",fontSize:"12px",lineHeight:"16px",display:"-webkit-box",WebkitLineClamp:2,WebkitBoxOrient:"vertical",overflow:"hidden"},loadingContainer:{display:"flex",alignItems:"center",justifyContent:"center",padding:"48px"},loadingInner:{display:"flex",flexDirection:"column",alignItems:"center",gap:"12px"},spinner:{width:"32px",height:"32px",border:"4px solid #2563eb",borderTopColor:"transparent",borderRadius:"9999px",animation:"spin 1s linear infinite"},loadingText:{fontSize:"14px",color:"#6b7280"},errorContainer:{padding:"24px",backgroundColor:"#fef2f2",border:"1px solid #fecaca",borderRadius:"8px"},errorTitle:{color:"#dc2626",fontWeight:500},errorMessage:{fontSize:"14px",color:"#ef4444",marginTop:"4px"},emptyContainer:{padding:"48px",textAlign:"center",color:"#6b7280"}},t=()=>{if("undefined"==typeof document)return;if(document.getElementById("socialfire-widget-global"))return;const n=document.createElement("style");n.id="socialfire-widget-global",n.textContent="\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n ",document.head.appendChild(n)},o="\n :host {\n display: block;\n }\n\n .socialfire-widget {\n width: 100%;\n }\n\n .socialfire-grid {\n display: grid;\n }\n\n .post-link {\n position: relative;\n aspect-ratio: 1 / 1;\n overflow: hidden;\n border-radius: 8px;\n background-color: #f3f4f6;\n display: block;\n transition: opacity 0.2s;\n text-decoration: none;\n }\n\n .post-link:hover {\n opacity: 0.9;\n }\n\n .post-image {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n .media-icon {\n position: absolute;\n top: 8px;\n right: 8px;\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: 9999px;\n padding: 4px;\n }\n\n .media-icon svg {\n width: 16px;\n height: 16px;\n color: white;\n display: block;\n }\n\n .hover-overlay {\n position: absolute;\n inset: 0;\n background-color: rgba(0, 0, 0, 0.6);\n opacity: 0;\n transition: opacity 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 16px;\n color: white;\n }\n\n .post-link:hover .hover-overlay {\n opacity: 1;\n }\n\n .stat-container {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .stat-container svg {\n width: 20px;\n height: 20px;\n }\n\n .stat-text {\n font-weight: 600;\n }\n\n .caption-overlay {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);\n padding: 12px;\n }\n\n .caption-text {\n color: white;\n font-size: 12px;\n line-height: 16px;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n\n .loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 48px;\n }\n\n .loading-inner {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n .spinner {\n width: 32px;\n height: 32px;\n border: 4px solid #2563eb;\n border-top-color: transparent;\n border-radius: 9999px;\n animation: spin 1s linear infinite;\n }\n\n .loading-text {\n font-size: 14px;\n color: #6b7280;\n }\n\n .error-container {\n padding: 24px;\n background-color: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 8px;\n }\n\n .error-title {\n color: #dc2626;\n font-weight: 500;\n }\n\n .error-message {\n font-size: 14px;\n color: #ef4444;\n margin-top: 4px;\n }\n\n .empty-container {\n padding: 48px;\n text-align: center;\n color: #6b7280;\n }\n";function i(n){return n>=1e6?(n/1e6).toFixed(1).replace(/\.0$/,"")+"M":n>=1e3?(n/1e3).toFixed(1).replace(/\.0$/,"")+"K":n.toString()}function r(n){return"VIDEO"===n.mediaType&&n.thumbnailUrl?n.thumbnailUrl:n.mediaUrl}function a(n){const e=document.createElement("div");return e.textContent=n,e.innerHTML}export{n as F,o as a,a as e,i as f,r as g,t as i,e as s};
|
|
2
|
-
//# sourceMappingURL=utils-BNIlvbZe.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils-BNIlvbZe.js","sources":["../src/core/fetcher.ts","../src/core/styles.ts","../src/core/utils.ts"],"sourcesContent":["import { SocialfireFeed } from './types';\r\n\r\nexport class FeedFetcher {\r\n private baseUrl: string;\r\n\r\n constructor(baseUrl?: string) {\r\n this.baseUrl = baseUrl || this.getDefaultBaseUrl();\r\n }\r\n\r\n private getDefaultBaseUrl(): string {\r\n if (typeof window !== 'undefined') {\r\n // Check for Next.js env var\r\n if (typeof process !== 'undefined' && process.env?.NEXT_PUBLIC_APP_URL) {\r\n return process.env.NEXT_PUBLIC_APP_URL;\r\n }\r\n // Use current origin\r\n return window.location.origin;\r\n }\r\n return '';\r\n }\r\n\r\n async fetchFeed(feedId: string, signal?: AbortSignal): Promise<SocialfireFeed> {\r\n const endpoint = `${this.baseUrl}/api/feeds/${feedId}`;\r\n\r\n const response = await fetch(endpoint, {\r\n signal,\r\n headers: { 'Content-Type': 'application/json' },\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch feed: ${response.statusText}`);\r\n }\r\n\r\n return await response.json();\r\n }\r\n}\r\n","import type { CSSProperties } from 'react';\r\n\r\nexport const styles = {\r\n // Grid container\r\n grid: (columns: number, gap: number): CSSProperties => ({\r\n display: 'grid',\r\n gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,\r\n gap: `${gap}px`,\r\n }),\r\n\r\n // Post link wrapper\r\n postLink: {\r\n position: 'relative' as const,\r\n aspectRatio: '1 / 1',\r\n overflow: 'hidden',\r\n borderRadius: '8px',\r\n backgroundColor: '#f3f4f6',\r\n display: 'block',\r\n transition: 'opacity 0.2s',\r\n textDecoration: 'none',\r\n } as CSSProperties,\r\n\r\n postLinkHover: {\r\n opacity: 0.9,\r\n } as CSSProperties,\r\n\r\n // Image styles\r\n image: {\r\n position: 'absolute' as const,\r\n top: 0,\r\n left: 0,\r\n width: '100%',\r\n height: '100%',\r\n objectFit: 'cover' as const,\r\n } as CSSProperties,\r\n\r\n // Media type icons (video, carousel)\r\n mediaIcon: {\r\n position: 'absolute' as const,\r\n top: '8px',\r\n right: '8px',\r\n backgroundColor: 'rgba(0, 0, 0, 0.5)',\r\n borderRadius: '9999px',\r\n padding: '4px',\r\n } as CSSProperties,\r\n\r\n svgIcon: {\r\n width: '16px',\r\n height: '16px',\r\n color: 'white',\r\n } as CSSProperties,\r\n\r\n // Hover overlay with stats\r\n hoverOverlay: {\r\n position: 'absolute' as const,\r\n inset: 0,\r\n backgroundColor: 'rgba(0, 0, 0, 0.6)',\r\n opacity: 0,\r\n transition: 'opacity 0.2s',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n gap: '16px',\r\n color: 'white',\r\n } as CSSProperties,\r\n\r\n hoverOverlayVisible: {\r\n opacity: 1,\r\n } as CSSProperties,\r\n\r\n statContainer: {\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '6px',\r\n } as CSSProperties,\r\n\r\n statIcon: {\r\n width: '20px',\r\n height: '20px',\r\n } as CSSProperties,\r\n\r\n statText: {\r\n fontWeight: 600,\r\n } as CSSProperties,\r\n\r\n // Caption overlay\r\n captionOverlay: {\r\n position: 'absolute' as const,\r\n bottom: 0,\r\n left: 0,\r\n right: 0,\r\n background: 'linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent)',\r\n padding: '12px',\r\n } as CSSProperties,\r\n\r\n captionText: {\r\n color: 'white',\r\n fontSize: '12px',\r\n lineHeight: '16px',\r\n display: '-webkit-box',\r\n WebkitLineClamp: 2,\r\n WebkitBoxOrient: 'vertical' as const,\r\n overflow: 'hidden',\r\n } as CSSProperties,\r\n\r\n // Loading state\r\n loadingContainer: {\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n padding: '48px',\r\n } as CSSProperties,\r\n\r\n loadingInner: {\r\n display: 'flex',\r\n flexDirection: 'column' as const,\r\n alignItems: 'center',\r\n gap: '12px',\r\n } as CSSProperties,\r\n\r\n spinner: {\r\n width: '32px',\r\n height: '32px',\r\n border: '4px solid #2563eb',\r\n borderTopColor: 'transparent',\r\n borderRadius: '9999px',\r\n animation: 'spin 1s linear infinite',\r\n } as CSSProperties,\r\n\r\n loadingText: {\r\n fontSize: '14px',\r\n color: '#6b7280',\r\n } as CSSProperties,\r\n\r\n // Error state\r\n errorContainer: {\r\n padding: '24px',\r\n backgroundColor: '#fef2f2',\r\n border: '1px solid #fecaca',\r\n borderRadius: '8px',\r\n } as CSSProperties,\r\n\r\n errorTitle: {\r\n color: '#dc2626',\r\n fontWeight: 500,\r\n } as CSSProperties,\r\n\r\n errorMessage: {\r\n fontSize: '14px',\r\n color: '#ef4444',\r\n marginTop: '4px',\r\n } as CSSProperties,\r\n\r\n // Empty state\r\n emptyContainer: {\r\n padding: '48px',\r\n textAlign: 'center' as const,\r\n color: '#6b7280',\r\n } as CSSProperties,\r\n};\r\n\r\n// Inject global styles for animations (used by both React and vanilla)\r\nexport const injectGlobalStyles = () => {\r\n if (typeof document === 'undefined') return;\r\n if (document.getElementById('socialfire-widget-global')) return;\r\n\r\n const style = document.createElement('style');\r\n style.id = 'socialfire-widget-global';\r\n style.textContent = `\r\n @keyframes spin {\r\n to { transform: rotate(360deg); }\r\n }\r\n `;\r\n document.head.appendChild(style);\r\n};\r\n\r\n// CSS string for Shadow DOM (vanilla component)\r\nexport const shadowStyles = `\r\n :host {\r\n display: block;\r\n }\r\n\r\n .socialfire-widget {\r\n width: 100%;\r\n }\r\n\r\n .socialfire-grid {\r\n display: grid;\r\n }\r\n\r\n .post-link {\r\n position: relative;\r\n aspect-ratio: 1 / 1;\r\n overflow: hidden;\r\n border-radius: 8px;\r\n background-color: #f3f4f6;\r\n display: block;\r\n transition: opacity 0.2s;\r\n text-decoration: none;\r\n }\r\n\r\n .post-link:hover {\r\n opacity: 0.9;\r\n }\r\n\r\n .post-image {\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n width: 100%;\r\n height: 100%;\r\n object-fit: cover;\r\n }\r\n\r\n .media-icon {\r\n position: absolute;\r\n top: 8px;\r\n right: 8px;\r\n background-color: rgba(0, 0, 0, 0.5);\r\n border-radius: 9999px;\r\n padding: 4px;\r\n }\r\n\r\n .media-icon svg {\r\n width: 16px;\r\n height: 16px;\r\n color: white;\r\n display: block;\r\n }\r\n\r\n .hover-overlay {\r\n position: absolute;\r\n inset: 0;\r\n background-color: rgba(0, 0, 0, 0.6);\r\n opacity: 0;\r\n transition: opacity 0.2s;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 16px;\r\n color: white;\r\n }\r\n\r\n .post-link:hover .hover-overlay {\r\n opacity: 1;\r\n }\r\n\r\n .stat-container {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n }\r\n\r\n .stat-container svg {\r\n width: 20px;\r\n height: 20px;\r\n }\r\n\r\n .stat-text {\r\n font-weight: 600;\r\n }\r\n\r\n .caption-overlay {\r\n position: absolute;\r\n bottom: 0;\r\n left: 0;\r\n right: 0;\r\n background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);\r\n padding: 12px;\r\n }\r\n\r\n .caption-text {\r\n color: white;\r\n font-size: 12px;\r\n line-height: 16px;\r\n display: -webkit-box;\r\n -webkit-line-clamp: 2;\r\n -webkit-box-orient: vertical;\r\n overflow: hidden;\r\n }\r\n\r\n .loading-container {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 48px;\r\n }\r\n\r\n .loading-inner {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n gap: 12px;\r\n }\r\n\r\n @keyframes spin {\r\n to { transform: rotate(360deg); }\r\n }\r\n\r\n .spinner {\r\n width: 32px;\r\n height: 32px;\r\n border: 4px solid #2563eb;\r\n border-top-color: transparent;\r\n border-radius: 9999px;\r\n animation: spin 1s linear infinite;\r\n }\r\n\r\n .loading-text {\r\n font-size: 14px;\r\n color: #6b7280;\r\n }\r\n\r\n .error-container {\r\n padding: 24px;\r\n background-color: #fef2f2;\r\n border: 1px solid #fecaca;\r\n border-radius: 8px;\r\n }\r\n\r\n .error-title {\r\n color: #dc2626;\r\n font-weight: 500;\r\n }\r\n\r\n .error-message {\r\n font-size: 14px;\r\n color: #ef4444;\r\n margin-top: 4px;\r\n }\r\n\r\n .empty-container {\r\n padding: 48px;\r\n text-align: center;\r\n color: #6b7280;\r\n }\r\n`;\r\n","export function formatNumber(num: number): string {\r\n if (num >= 1000000) {\r\n return (num / 1000000).toFixed(1).replace(/\\.0$/, '') + 'M';\r\n }\r\n if (num >= 1000) {\r\n return (num / 1000).toFixed(1).replace(/\\.0$/, '') + 'K';\r\n }\r\n return num.toString();\r\n}\r\n\r\nexport function getMediaUrl(post: {\r\n mediaType: string;\r\n thumbnailUrl: string | null;\r\n mediaUrl: string;\r\n}): string {\r\n return post.mediaType === 'VIDEO' && post.thumbnailUrl\r\n ? post.thumbnailUrl\r\n : post.mediaUrl;\r\n}\r\n\r\nexport function escapeHtml(text: string): string {\r\n const div = document.createElement('div');\r\n div.textContent = text;\r\n return div.innerHTML;\r\n}\r\n"],"names":["FeedFetcher","constructor","baseUrl","this","getDefaultBaseUrl","window","process","env","NEXT_PUBLIC_APP_URL","location","origin","fetchFeed","feedId","signal","endpoint","response","fetch","headers","ok","Error","statusText","json","styles","grid","columns","gap","display","gridTemplateColumns","postLink","position","aspectRatio","overflow","borderRadius","backgroundColor","transition","textDecoration","postLinkHover","opacity","image","top","left","width","height","objectFit","mediaIcon","right","padding","svgIcon","color","hoverOverlay","inset","alignItems","justifyContent","hoverOverlayVisible","statContainer","statIcon","statText","fontWeight","captionOverlay","bottom","background","captionText","fontSize","lineHeight","WebkitLineClamp","WebkitBoxOrient","loadingContainer","loadingInner","flexDirection","spinner","border","borderTopColor","animation","loadingText","errorContainer","errorTitle","errorMessage","marginTop","emptyContainer","textAlign","injectGlobalStyles","document","getElementById","style","createElement","id","textContent","head","appendChild","shadowStyles","formatNumber","num","toFixed","replace","toString","getMediaUrl","post","mediaType","thumbnailUrl","mediaUrl","escapeHtml","text","div","innerHTML"],"mappings":"AAEO,MAAMA,EAGX,WAAAC,CAAYC,GACVC,KAAKD,QAAUA,GAAWC,KAAKC,mBACjC,CAEQ,iBAAAA,GACN,MAAsB,oBAAXC,OAEc,oBAAZC,SAA2BA,QAAQC,KAAKC,oBAC1CF,QAAQC,IAAIC,oBAGdH,OAAOI,SAASC,OAElB,EACT,CAEA,eAAMC,CAAUC,EAAgBC,GAC9B,MAAMC,EAAW,GAAGX,KAAKD,qBAAqBU,IAExCG,QAAiBC,MAAMF,EAAU,CACrCD,SACAI,QAAS,CAAE,eAAgB,sBAG7B,IAAKF,EAASG,GACZ,MAAM,IAAIC,MAAM,yBAAyBJ,EAASK,cAGpD,aAAaL,EAASM,MACxB,EChCK,MAAMC,EAAS,CAEpBC,KAAM,CAACC,EAAiBC,KAAA,CACtBC,QAAS,OACTC,oBAAqB,UAAUH,qBAC/BC,IAAK,GAAGA,QAIVG,SAAU,CACRC,SAAU,WACVC,YAAa,QACbC,SAAU,SACVC,aAAc,MACdC,gBAAiB,UACjBP,QAAS,QACTQ,WAAY,eACZC,eAAgB,QAGlBC,cAAe,CACbC,QAAS,IAIXC,MAAO,CACLT,SAAU,WACVU,IAAK,EACLC,KAAM,EACNC,MAAO,OACPC,OAAQ,OACRC,UAAW,SAIbC,UAAW,CACTf,SAAU,WACVU,IAAK,MACLM,MAAO,MACPZ,gBAAiB,qBACjBD,aAAc,SACdc,QAAS,OAGXC,QAAS,CACPN,MAAO,OACPC,OAAQ,OACRM,MAAO,SAITC,aAAc,CACZpB,SAAU,WACVqB,MAAO,EACPjB,gBAAiB,qBACjBI,QAAS,EACTH,WAAY,eACZR,QAAS,OACTyB,WAAY,SACZC,eAAgB,SAChB3B,IAAK,OACLuB,MAAO,SAGTK,oBAAqB,CACnBhB,QAAS,GAGXiB,cAAe,CACb5B,QAAS,OACTyB,WAAY,SACZ1B,IAAK,OAGP8B,SAAU,CACRd,MAAO,OACPC,OAAQ,QAGVc,SAAU,CACRC,WAAY,KAIdC,eAAgB,CACd7B,SAAU,WACV8B,OAAQ,EACRnB,KAAM,EACNK,MAAO,EACPe,WAAY,2DACZd,QAAS,QAGXe,YAAa,CACXb,MAAO,QACPc,SAAU,OACVC,WAAY,OACZrC,QAAS,cACTsC,gBAAiB,EACjBC,gBAAiB,WACjBlC,SAAU,UAIZmC,iBAAkB,CAChBxC,QAAS,OACTyB,WAAY,SACZC,eAAgB,SAChBN,QAAS,QAGXqB,aAAc,CACZzC,QAAS,OACT0C,cAAe,SACfjB,WAAY,SACZ1B,IAAK,QAGP4C,QAAS,CACP5B,MAAO,OACPC,OAAQ,OACR4B,OAAQ,oBACRC,eAAgB,cAChBvC,aAAc,SACdwC,UAAW,2BAGbC,YAAa,CACXX,SAAU,OACVd,MAAO,WAIT0B,eAAgB,CACd5B,QAAS,OACTb,gBAAiB,UACjBqC,OAAQ,oBACRtC,aAAc,OAGhB2C,WAAY,CACV3B,MAAO,UACPS,WAAY,KAGdmB,aAAc,CACZd,SAAU,OACVd,MAAO,UACP6B,UAAW,OAIbC,eAAgB,CACdhC,QAAS,OACTiC,UAAW,SACX/B,MAAO,YAKEgC,EAAqB,KAChC,GAAwB,oBAAbC,SAA0B,OACrC,GAAIA,SAASC,eAAe,4BAA6B,OAEzD,MAAMC,EAAQF,SAASG,cAAc,SACrCD,EAAME,GAAK,2BACXF,EAAMG,YAAc,8EAKpBL,SAASM,KAAKC,YAAYL,IAIfM,EAAe,irFCjLrB,SAASC,EAAaC,GAC3B,OAAIA,GAAO,KACDA,EAAM,KAASC,QAAQ,GAAGC,QAAQ,OAAQ,IAAM,IAEtDF,GAAO,KACDA,EAAM,KAAMC,QAAQ,GAAGC,QAAQ,OAAQ,IAAM,IAEhDF,EAAIG,UACb,CAEO,SAASC,EAAYC,GAK1B,MAA0B,UAAnBA,EAAKC,WAAyBD,EAAKE,aACtCF,EAAKE,aACLF,EAAKG,QACX,CAEO,SAASC,EAAWC,GACzB,MAAMC,EAAMrB,SAASG,cAAc,OAEnC,OADAkB,EAAIhB,YAAce,EACXC,EAAIC,SACb"}
|