@flamingo-stack/openframe-frontend-core 0.0.287 → 0.0.288
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/chunk-AISIZLZP.js +619 -0
- package/dist/chunk-AISIZLZP.js.map +1 -0
- package/dist/chunk-DVUFNTI2.cjs +619 -0
- package/dist/chunk-DVUFNTI2.cjs.map +1 -0
- package/dist/components/embeds/index.cjs +6 -2
- package/dist/components/embeds/index.cjs.map +1 -1
- package/dist/components/embeds/index.d.ts +2 -0
- package/dist/components/embeds/index.d.ts.map +1 -1
- package/dist/components/embeds/index.js +5 -1
- package/dist/components/embeds/og-link-preview.d.ts +114 -0
- package/dist/components/embeds/og-link-preview.d.ts.map +1 -0
- package/dist/components/index.cjs +6 -2
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +5 -1
- package/dist/components/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/embeds/index.ts +7 -0
- package/src/components/embeds/og-link-preview.tsx +446 -0
- package/dist/chunk-MV67MBV3.js +0 -290
- package/dist/chunk-MV67MBV3.js.map +0 -1
- package/dist/chunk-MWS25U4U.cjs +0 -290
- package/dist/chunk-MWS25U4U.cjs.map +0 -1
package/dist/chunk-MV67MBV3.js
DELETED
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import {
|
|
3
|
-
ToggleGroup,
|
|
4
|
-
ToggleGroupItem
|
|
5
|
-
} from "./chunk-EFYXPR43.js";
|
|
6
|
-
import {
|
|
7
|
-
isFigmaSlidesUrl,
|
|
8
|
-
toFigmaEmbedUrl,
|
|
9
|
-
toFigmaOriginalUrl,
|
|
10
|
-
toGoogleSheetsEmbedUrl,
|
|
11
|
-
toGoogleSheetsOriginalUrl
|
|
12
|
-
} from "./chunk-ODR6A6FC.js";
|
|
13
|
-
import {
|
|
14
|
-
Button
|
|
15
|
-
} from "./chunk-5IJ46KAV.js";
|
|
16
|
-
import {
|
|
17
|
-
AdobePdfIcon,
|
|
18
|
-
FigmaIcon,
|
|
19
|
-
GoogleSheetsIcon
|
|
20
|
-
} from "./chunk-J7AV6H63.js";
|
|
21
|
-
|
|
22
|
-
// src/components/embeds/embed-iframe.tsx
|
|
23
|
-
import { useState, useCallback, useRef, useEffect } from "react";
|
|
24
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
25
|
-
function EmbedLoadingSkeleton({ height }) {
|
|
26
|
-
return /* @__PURE__ */ jsx(
|
|
27
|
-
"div",
|
|
28
|
-
{
|
|
29
|
-
className: "w-full rounded-lg border border-ods-border overflow-hidden bg-ods-skeleton animate-pulse",
|
|
30
|
-
style: { height: height || "calc(100vh - 250px)" },
|
|
31
|
-
children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center h-full gap-4", children: [
|
|
32
|
-
/* @__PURE__ */ jsx("div", { className: "w-12 h-12 rounded-lg bg-ods-card" }),
|
|
33
|
-
/* @__PURE__ */ jsx("div", { className: "h-4 w-48 rounded bg-ods-card" }),
|
|
34
|
-
/* @__PURE__ */ jsx("div", { className: "h-3 w-32 rounded bg-ods-card" })
|
|
35
|
-
] })
|
|
36
|
-
}
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
function EmbedIframe({
|
|
40
|
-
src,
|
|
41
|
-
title,
|
|
42
|
-
className,
|
|
43
|
-
height,
|
|
44
|
-
allow,
|
|
45
|
-
referrerPolicy,
|
|
46
|
-
loading,
|
|
47
|
-
allowFullScreen
|
|
48
|
-
}) {
|
|
49
|
-
const [isLoaded, setIsLoaded] = useState(false);
|
|
50
|
-
const iframeRef = useRef(null);
|
|
51
|
-
const handleLoad = useCallback(() => setIsLoaded(true), []);
|
|
52
|
-
useEffect(() => {
|
|
53
|
-
setIsLoaded(false);
|
|
54
|
-
}, [src]);
|
|
55
|
-
useEffect(() => {
|
|
56
|
-
const iframe = iframeRef.current;
|
|
57
|
-
return () => {
|
|
58
|
-
if (iframe) {
|
|
59
|
-
try {
|
|
60
|
-
iframe.src = "about:blank";
|
|
61
|
-
} catch {
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
}, [src]);
|
|
66
|
-
const resolvedHeight = height || "calc(100vh - 250px)";
|
|
67
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
68
|
-
!isLoaded && /* @__PURE__ */ jsx(EmbedLoadingSkeleton, { height: resolvedHeight }),
|
|
69
|
-
/* @__PURE__ */ jsx(
|
|
70
|
-
"div",
|
|
71
|
-
{
|
|
72
|
-
className: `w-full rounded-lg border border-ods-border overflow-hidden ${!isLoaded ? "h-0 overflow-hidden" : ""} ${className || ""}`,
|
|
73
|
-
style: isLoaded ? { height: resolvedHeight } : void 0,
|
|
74
|
-
children: /* @__PURE__ */ jsx(
|
|
75
|
-
"iframe",
|
|
76
|
-
{
|
|
77
|
-
ref: iframeRef,
|
|
78
|
-
src,
|
|
79
|
-
className: "w-full h-full border-0",
|
|
80
|
-
title,
|
|
81
|
-
onLoad: handleLoad,
|
|
82
|
-
allow,
|
|
83
|
-
referrerPolicy,
|
|
84
|
-
loading,
|
|
85
|
-
allowFullScreen: allow?.includes("fullscreen") ? void 0 : allowFullScreen
|
|
86
|
-
},
|
|
87
|
-
src
|
|
88
|
-
)
|
|
89
|
-
}
|
|
90
|
-
)
|
|
91
|
-
] });
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// src/components/embeds/pdf-viewer.tsx
|
|
95
|
-
import { Download, Eye } from "lucide-react";
|
|
96
|
-
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
97
|
-
function PdfViewer({ src, fileName, onPreview, onDownload, height }) {
|
|
98
|
-
const displayName = fileName || "PDF Document";
|
|
99
|
-
if (!src) {
|
|
100
|
-
return /* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [
|
|
101
|
-
/* @__PURE__ */ jsx2(AdobePdfIcon, { className: "w-16 h-16 text-ods-text-secondary mb-4" }),
|
|
102
|
-
/* @__PURE__ */ jsx2("p", { className: "text-ods-text-secondary", children: "PDF file not available" })
|
|
103
|
-
] });
|
|
104
|
-
}
|
|
105
|
-
return /* @__PURE__ */ jsxs2("div", { className: "space-y-4", children: [
|
|
106
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
107
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
108
|
-
/* @__PURE__ */ jsx2(AdobePdfIcon, { className: "w-5 h-5 shrink-0" }),
|
|
109
|
-
/* @__PURE__ */ jsx2("h2", { className: "text-xl font-semibold text-ods-text-primary truncate", children: displayName })
|
|
110
|
-
] }),
|
|
111
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 w-full sm:w-auto", children: [
|
|
112
|
-
/* @__PURE__ */ jsx2(
|
|
113
|
-
Button,
|
|
114
|
-
{
|
|
115
|
-
variant: "outline",
|
|
116
|
-
size: "small-legacy",
|
|
117
|
-
href: onPreview ? void 0 : src,
|
|
118
|
-
openInNewTab: !onPreview,
|
|
119
|
-
onClick: onPreview,
|
|
120
|
-
leftIcon: /* @__PURE__ */ jsx2(Eye, { className: "w-4 h-4" }),
|
|
121
|
-
className: "flex-1 sm:flex-initial",
|
|
122
|
-
children: "Preview"
|
|
123
|
-
}
|
|
124
|
-
),
|
|
125
|
-
/* @__PURE__ */ jsx2(
|
|
126
|
-
Button,
|
|
127
|
-
{
|
|
128
|
-
variant: "outline",
|
|
129
|
-
size: "small-legacy",
|
|
130
|
-
href: onDownload ? void 0 : src,
|
|
131
|
-
openInNewTab: !onDownload,
|
|
132
|
-
onClick: onDownload,
|
|
133
|
-
leftIcon: /* @__PURE__ */ jsx2(Download, { className: "w-4 h-4" }),
|
|
134
|
-
className: "flex-1 sm:flex-initial",
|
|
135
|
-
children: "Download"
|
|
136
|
-
}
|
|
137
|
-
)
|
|
138
|
-
] })
|
|
139
|
-
] }),
|
|
140
|
-
/* @__PURE__ */ jsx2(EmbedIframe, { src, title: displayName, height })
|
|
141
|
-
] });
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// src/components/embeds/google-sheets-viewer.tsx
|
|
145
|
-
import { ExternalLink } from "lucide-react";
|
|
146
|
-
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
147
|
-
function GoogleSheetsViewer({ externalUrl, fileName, height }) {
|
|
148
|
-
const displayName = fileName || "Google Sheet";
|
|
149
|
-
if (!externalUrl) {
|
|
150
|
-
return /* @__PURE__ */ jsxs3("div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [
|
|
151
|
-
/* @__PURE__ */ jsx3(GoogleSheetsIcon, { className: "w-16 h-16 text-ods-text-secondary mb-4" }),
|
|
152
|
-
/* @__PURE__ */ jsx3("p", { className: "text-ods-text-secondary", children: "Google Sheet URL not configured" })
|
|
153
|
-
] });
|
|
154
|
-
}
|
|
155
|
-
return /* @__PURE__ */ jsxs3("div", { className: "space-y-4", children: [
|
|
156
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
157
|
-
/* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
158
|
-
/* @__PURE__ */ jsx3(GoogleSheetsIcon, { className: "w-5 h-5 shrink-0" }),
|
|
159
|
-
/* @__PURE__ */ jsx3("h2", { className: "text-xl font-semibold text-ods-text-primary truncate", children: displayName })
|
|
160
|
-
] }),
|
|
161
|
-
/* @__PURE__ */ jsx3(
|
|
162
|
-
Button,
|
|
163
|
-
{
|
|
164
|
-
variant: "outline",
|
|
165
|
-
size: "small-legacy",
|
|
166
|
-
href: toGoogleSheetsOriginalUrl(externalUrl),
|
|
167
|
-
openInNewTab: true,
|
|
168
|
-
leftIcon: /* @__PURE__ */ jsx3(GoogleSheetsIcon, { className: "w-4 h-4" }),
|
|
169
|
-
rightIcon: /* @__PURE__ */ jsx3(ExternalLink, { className: "w-4 h-4" }),
|
|
170
|
-
className: "w-full sm:w-auto",
|
|
171
|
-
children: "Open in Google Sheets"
|
|
172
|
-
}
|
|
173
|
-
)
|
|
174
|
-
] }),
|
|
175
|
-
/* @__PURE__ */ jsx3(
|
|
176
|
-
EmbedIframe,
|
|
177
|
-
{
|
|
178
|
-
src: toGoogleSheetsEmbedUrl(externalUrl),
|
|
179
|
-
title: displayName,
|
|
180
|
-
height
|
|
181
|
-
}
|
|
182
|
-
)
|
|
183
|
-
] });
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// src/components/embeds/figma-embed.tsx
|
|
187
|
-
import { useState as useState2 } from "react";
|
|
188
|
-
import { ExternalLink as ExternalLink2, Play, LayoutGrid } from "lucide-react";
|
|
189
|
-
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
190
|
-
function SlidesViewToggle({
|
|
191
|
-
view,
|
|
192
|
-
onChange
|
|
193
|
-
}) {
|
|
194
|
-
const options = [
|
|
195
|
-
{ key: "present", label: "Present", Icon: Play },
|
|
196
|
-
{ key: "browse", label: "Browse", Icon: LayoutGrid }
|
|
197
|
-
];
|
|
198
|
-
return /* @__PURE__ */ jsx4(
|
|
199
|
-
ToggleGroup,
|
|
200
|
-
{
|
|
201
|
-
type: "single",
|
|
202
|
-
value: view,
|
|
203
|
-
onValueChange: (v) => {
|
|
204
|
-
if (v && v !== view) onChange(v);
|
|
205
|
-
},
|
|
206
|
-
"aria-label": "Figma slides view mode",
|
|
207
|
-
className: "flex shrink-0 items-center gap-0.5 rounded-lg border border-ods-border bg-ods-card p-0.5",
|
|
208
|
-
children: options.map(({ key, label, Icon }) => {
|
|
209
|
-
const active = view === key;
|
|
210
|
-
return /* @__PURE__ */ jsxs4(
|
|
211
|
-
ToggleGroupItem,
|
|
212
|
-
{
|
|
213
|
-
value: key,
|
|
214
|
-
"aria-label": label,
|
|
215
|
-
className: `flex items-center gap-1.5 rounded-md px-2.5 py-1 text-sm font-medium transition-colors ${active ? "bg-ods-accent text-ods-text-on-accent" : "text-ods-text-secondary hover:text-ods-text-primary hover:bg-ods-bg-hover"}`,
|
|
216
|
-
children: [
|
|
217
|
-
/* @__PURE__ */ jsx4(Icon, { className: "h-4 w-4 shrink-0" }),
|
|
218
|
-
label
|
|
219
|
-
]
|
|
220
|
-
},
|
|
221
|
-
key
|
|
222
|
-
);
|
|
223
|
-
})
|
|
224
|
-
}
|
|
225
|
-
);
|
|
226
|
-
}
|
|
227
|
-
function FigmaEmbed({ url, title, height, loading = "lazy" }) {
|
|
228
|
-
const [view, setView] = useState2("present");
|
|
229
|
-
const isSlides = url ? isFigmaSlidesUrl(url) : false;
|
|
230
|
-
const embedSrc = url ? toFigmaEmbedUrl(url, { slidesView: view }) : null;
|
|
231
|
-
const originalUrl = (() => {
|
|
232
|
-
if (!url) return null;
|
|
233
|
-
try {
|
|
234
|
-
const parsed = new URL(toFigmaOriginalUrl(url));
|
|
235
|
-
const host = parsed.hostname.toLowerCase();
|
|
236
|
-
const okHost = host === "figma.com" || host.endsWith(".figma.com");
|
|
237
|
-
const okProtocol = parsed.protocol === "https:" || parsed.protocol === "http:";
|
|
238
|
-
return okHost && okProtocol ? parsed.toString() : null;
|
|
239
|
-
} catch {
|
|
240
|
-
return null;
|
|
241
|
-
}
|
|
242
|
-
})();
|
|
243
|
-
const heading = title || "Figma Design";
|
|
244
|
-
return /* @__PURE__ */ jsxs4("div", { className: "my-6 space-y-3", children: [
|
|
245
|
-
/* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
246
|
-
/* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
247
|
-
/* @__PURE__ */ jsx4(FigmaIcon, { className: "w-5 h-5 shrink-0" }),
|
|
248
|
-
/* @__PURE__ */ jsx4("span", { className: "font-sans text-base font-semibold text-ods-text-primary truncate", children: heading })
|
|
249
|
-
] }),
|
|
250
|
-
/* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-center", children: [
|
|
251
|
-
isSlides && embedSrc && /* @__PURE__ */ jsx4(SlidesViewToggle, { view, onChange: setView }),
|
|
252
|
-
originalUrl && /* @__PURE__ */ jsx4(
|
|
253
|
-
Button,
|
|
254
|
-
{
|
|
255
|
-
variant: "outline",
|
|
256
|
-
size: "small-legacy",
|
|
257
|
-
href: originalUrl,
|
|
258
|
-
openInNewTab: true,
|
|
259
|
-
leftIcon: /* @__PURE__ */ jsx4(FigmaIcon, { className: "w-4 h-4" }),
|
|
260
|
-
rightIcon: /* @__PURE__ */ jsx4(ExternalLink2, { className: "w-4 h-4" }),
|
|
261
|
-
className: "w-full sm:w-auto",
|
|
262
|
-
children: "Open in Figma"
|
|
263
|
-
}
|
|
264
|
-
)
|
|
265
|
-
] })
|
|
266
|
-
] }),
|
|
267
|
-
embedSrc ? /* @__PURE__ */ jsx4(
|
|
268
|
-
EmbedIframe,
|
|
269
|
-
{
|
|
270
|
-
src: embedSrc,
|
|
271
|
-
title: heading,
|
|
272
|
-
allow: "clipboard-write; clipboard-read; fullscreen",
|
|
273
|
-
loading,
|
|
274
|
-
height,
|
|
275
|
-
allowFullScreen: true
|
|
276
|
-
}
|
|
277
|
-
) : /* @__PURE__ */ jsxs4("div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [
|
|
278
|
-
/* @__PURE__ */ jsx4(FigmaIcon, { className: "w-16 h-16 text-ods-text-secondary mb-4" }),
|
|
279
|
-
/* @__PURE__ */ jsx4("p", { className: "text-ods-text-secondary", children: "Figma URL not configured" })
|
|
280
|
-
] })
|
|
281
|
-
] });
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
export {
|
|
285
|
-
EmbedIframe,
|
|
286
|
-
PdfViewer,
|
|
287
|
-
GoogleSheetsViewer,
|
|
288
|
-
FigmaEmbed
|
|
289
|
-
};
|
|
290
|
-
//# sourceMappingURL=chunk-MV67MBV3.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/embeds/embed-iframe.tsx","../src/components/embeds/pdf-viewer.tsx","../src/components/embeds/google-sheets-viewer.tsx","../src/components/embeds/figma-embed.tsx"],"sourcesContent":["\"use client\"\n\nimport React, { useState, useCallback, useRef, useEffect } from 'react'\n\n/** Loading skeleton for iframe embeds — matches project skeleton pattern */\nfunction EmbedLoadingSkeleton({ height }: { height?: string }) {\n return (\n <div\n className=\"w-full rounded-lg border border-ods-border overflow-hidden bg-ods-skeleton animate-pulse\"\n style={{ height: height || 'calc(100vh - 250px)' }}\n >\n <div className=\"flex flex-col items-center justify-center h-full gap-4\">\n <div className=\"w-12 h-12 rounded-lg bg-ods-card\" />\n <div className=\"h-4 w-48 rounded bg-ods-card\" />\n <div className=\"h-3 w-32 rounded bg-ods-card\" />\n </div>\n </div>\n )\n}\n\nexport interface EmbedIframeProps {\n /** The URL to embed */\n src: string\n /** Accessible title for the iframe */\n title: string\n /** Additional class names for the outer container */\n className?: string\n /** Container height (CSS value). Defaults to `calc(100vh - 250px)` */\n height?: string\n /** iframe `allow` attribute */\n allow?: string\n /** iframe `referrerPolicy` attribute */\n referrerPolicy?: React.IframeHTMLAttributes<HTMLIFrameElement>['referrerPolicy']\n /** iframe `loading` attribute */\n loading?: 'eager' | 'lazy'\n /** iframe `allowFullScreen` attribute */\n allowFullScreen?: boolean\n}\n\n/**\n * Base iframe wrapper with loading skeleton and proper memory cleanup.\n *\n * Prevents memory leaks by:\n * - Using `key={src}` to force full unmount/remount when src changes\n * - Setting iframe src to about:blank on unmount to release the embedded document\n * - Resetting loaded state when src changes\n */\nexport function EmbedIframe({\n src,\n title,\n className,\n height,\n allow,\n referrerPolicy,\n loading,\n allowFullScreen,\n}: EmbedIframeProps) {\n const [isLoaded, setIsLoaded] = useState(false)\n const iframeRef = useRef<HTMLIFrameElement>(null)\n const handleLoad = useCallback(() => setIsLoaded(true), [])\n\n useEffect(() => {\n setIsLoaded(false)\n }, [src])\n\n useEffect(() => {\n const iframe = iframeRef.current\n return () => {\n if (iframe) {\n try {\n iframe.src = 'about:blank'\n } catch {\n // Cross-origin iframes may throw — safe to ignore\n }\n }\n }\n }, [src])\n\n const resolvedHeight = height || 'calc(100vh - 250px)'\n\n return (\n <>\n {!isLoaded && <EmbedLoadingSkeleton height={resolvedHeight} />}\n <div\n className={`w-full rounded-lg border border-ods-border overflow-hidden ${!isLoaded ? 'h-0 overflow-hidden' : ''} ${className || ''}`}\n style={isLoaded ? { height: resolvedHeight } : undefined}\n >\n <iframe\n key={src}\n ref={iframeRef}\n src={src}\n className=\"w-full h-full border-0\"\n title={title}\n onLoad={handleLoad}\n allow={allow}\n referrerPolicy={referrerPolicy}\n loading={loading}\n allowFullScreen={allow?.includes('fullscreen') ? undefined : allowFullScreen}\n />\n </div>\n </>\n )\n}\n","\"use client\"\n\nimport React from 'react'\nimport { Button } from '../ui'\nimport { Download, Eye } from 'lucide-react'\nimport { AdobePdfIcon } from '../icons-v2-generated'\nimport { EmbedIframe } from './embed-iframe'\n\nexport interface PdfViewerProps {\n src: string\n fileName?: string\n onPreview?: () => void\n onDownload?: () => void\n height?: string\n}\n\nexport function PdfViewer({ src, fileName, onPreview, onDownload, height }: PdfViewerProps) {\n const displayName = fileName || 'PDF Document'\n\n if (!src) {\n return (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n <AdobePdfIcon className=\"w-16 h-16 text-ods-text-secondary mb-4\" />\n <p className=\"text-ods-text-secondary\">PDF file not available</p>\n </div>\n )\n }\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-center gap-2 min-w-0\">\n <AdobePdfIcon className=\"w-5 h-5 shrink-0\" />\n <h2 className=\"text-xl font-semibold text-ods-text-primary truncate\">{displayName}</h2>\n </div>\n <div className=\"flex items-center gap-2 w-full sm:w-auto\">\n <Button\n variant=\"outline\"\n size=\"small-legacy\"\n href={onPreview ? undefined : src}\n openInNewTab={!onPreview}\n onClick={onPreview}\n leftIcon={<Eye className=\"w-4 h-4\" />}\n className=\"flex-1 sm:flex-initial\"\n >\n Preview\n </Button>\n <Button\n variant=\"outline\"\n size=\"small-legacy\"\n href={onDownload ? undefined : src}\n openInNewTab={!onDownload}\n onClick={onDownload}\n leftIcon={<Download className=\"w-4 h-4\" />}\n className=\"flex-1 sm:flex-initial\"\n >\n Download\n </Button>\n </div>\n </div>\n <EmbedIframe src={src} title={displayName} height={height} />\n </div>\n )\n}\n","\"use client\"\n\nimport React from 'react'\nimport { Button } from '../ui'\nimport { ExternalLink } from 'lucide-react'\nimport { GoogleSheetsIcon } from '../icons-v2-generated'\nimport { EmbedIframe } from './embed-iframe'\nimport { toGoogleSheetsEmbedUrl, toGoogleSheetsOriginalUrl } from '../../utils/embed-url-converters'\n\nexport interface GoogleSheetsViewerProps {\n externalUrl: string\n fileName?: string\n height?: string\n}\n\nexport function GoogleSheetsViewer({ externalUrl, fileName, height }: GoogleSheetsViewerProps) {\n const displayName = fileName || 'Google Sheet'\n\n if (!externalUrl) {\n return (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n <GoogleSheetsIcon className=\"w-16 h-16 text-ods-text-secondary mb-4\" />\n <p className=\"text-ods-text-secondary\">Google Sheet URL not configured</p>\n </div>\n )\n }\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-center gap-2 min-w-0\">\n <GoogleSheetsIcon className=\"w-5 h-5 shrink-0\" />\n <h2 className=\"text-xl font-semibold text-ods-text-primary truncate\">{displayName}</h2>\n </div>\n <Button\n variant=\"outline\"\n size=\"small-legacy\"\n href={toGoogleSheetsOriginalUrl(externalUrl)}\n openInNewTab\n leftIcon={<GoogleSheetsIcon className=\"w-4 h-4\" />}\n rightIcon={<ExternalLink className=\"w-4 h-4\" />}\n className=\"w-full sm:w-auto\"\n >\n Open in Google Sheets\n </Button>\n </div>\n <EmbedIframe\n src={toGoogleSheetsEmbedUrl(externalUrl)}\n title={displayName}\n height={height}\n />\n </div>\n )\n}\n","'use client'\n\nimport { useState } from 'react'\nimport { Button, ToggleGroup, ToggleGroupItem } from '../ui'\nimport { FigmaIcon } from '../icons-v2-generated'\nimport { ExternalLink, Play, LayoutGrid } from 'lucide-react'\nimport { toFigmaEmbedUrl, toFigmaOriginalUrl, isFigmaSlidesUrl } from '../../utils/embed-url-converters'\nimport { EmbedIframe } from './embed-iframe'\n\nexport interface FigmaEmbedProps {\n /** Any Figma URL (design/file/proto/board/slides/deck) or an already-resolved embed URL. */\n url: string\n /** Heading shown above the embed. Defaults to \"Figma Design\". */\n title?: string\n /**\n * iframe height (CSS value). The data-room document viewer omits it (full\n * height, `calc(100vh - 250px)`); inline markdown passes e.g. `\"70vh\"` so the\n * embed sits naturally inside article content.\n */\n height?: string\n /** iframe loading strategy. Defaults to `\"lazy\"`; the data-room viewer passes `\"eager\"`. */\n loading?: 'eager' | 'lazy'\n}\n\ntype SlidesView = 'present' | 'browse'\n\n/**\n * Two-state present/browse toggle for Figma Slides. `present` (default) uses\n * Figma's deck viewer (full-bleed slide + `‹ n/N ›` nav bar + keyboard nav);\n * `browse` uses the thumbnail-rail + zoom viewer.\n */\nfunction SlidesViewToggle({\n view,\n onChange,\n}: {\n view: SlidesView\n onChange: (v: SlidesView) => void\n}) {\n const options: { key: SlidesView; label: string; Icon: typeof Play }[] = [\n { key: 'present', label: 'Present', Icon: Play },\n { key: 'browse', label: 'Browse', Icon: LayoutGrid },\n ]\n return (\n <ToggleGroup\n type=\"single\"\n value={view}\n onValueChange={(v: string) => {\n if (v && v !== view) onChange(v as SlidesView)\n }}\n aria-label=\"Figma slides view mode\"\n className=\"flex shrink-0 items-center gap-0.5 rounded-lg border border-ods-border bg-ods-card p-0.5\"\n >\n {options.map(({ key, label, Icon }) => {\n const active = view === key\n return (\n <ToggleGroupItem\n key={key}\n value={key}\n aria-label={label}\n className={`flex items-center gap-1.5 rounded-md px-2.5 py-1 text-sm font-medium transition-colors ${\n active\n ? 'bg-ods-accent text-ods-text-on-accent'\n : 'text-ods-text-secondary hover:text-ods-text-primary hover:bg-ods-bg-hover'\n }`}\n >\n <Icon className=\"h-4 w-4 shrink-0\" />\n {label}\n </ToggleGroupItem>\n )\n })}\n </ToggleGroup>\n )\n}\n\n/**\n * Single source of truth for every Figma surface — the data-room document viewer\n * and in-article markdown both render this. A header (icon + title + \"Open in\n * Figma\") over an interactive Figma iframe, built from the canonical\n * `toFigmaEmbedUrl` / `toFigmaOriginalUrl` converters + the shared `<EmbedIframe>`.\n * Only height/loading differ per surface.\n *\n * For Slides decks, a present/browse toggle (default = present) lets viewers flip\n * slides with Figma's native nav bar + keyboard, or switch to the thumbnail-rail\n * browse view.\n */\nexport function FigmaEmbed({ url, title, height, loading = 'lazy' }: FigmaEmbedProps) {\n const [view, setView] = useState<SlidesView>('present')\n const isSlides = url ? isFigmaSlidesUrl(url) : false\n const embedSrc = url ? toFigmaEmbedUrl(url, { slidesView: view }) : null\n const originalUrl = (() => {\n if (!url) return null\n try {\n const parsed = new URL(toFigmaOriginalUrl(url))\n const host = parsed.hostname.toLowerCase()\n const okHost = host === 'figma.com' || host.endsWith('.figma.com')\n const okProtocol = parsed.protocol === 'https:' || parsed.protocol === 'http:'\n return okHost && okProtocol ? parsed.toString() : null\n } catch {\n return null\n }\n })()\n const heading = title || 'Figma Design'\n\n return (\n <div className=\"my-6 space-y-3\">\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-center gap-2 min-w-0\">\n <FigmaIcon className=\"w-5 h-5 shrink-0\" />\n <span className=\"font-sans text-base font-semibold text-ods-text-primary truncate\">\n {heading}\n </span>\n </div>\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n {isSlides && embedSrc && <SlidesViewToggle view={view} onChange={setView} />}\n {originalUrl && (\n <Button\n variant=\"outline\"\n size=\"small-legacy\"\n href={originalUrl}\n openInNewTab\n leftIcon={<FigmaIcon className=\"w-4 h-4\" />}\n rightIcon={<ExternalLink className=\"w-4 h-4\" />}\n className=\"w-full sm:w-auto\"\n >\n Open in Figma\n </Button>\n )}\n </div>\n </div>\n {embedSrc ? (\n <EmbedIframe\n src={embedSrc}\n title={heading}\n allow=\"clipboard-write; clipboard-read; fullscreen\"\n loading={loading}\n height={height}\n allowFullScreen\n />\n ) : (\n <div className=\"flex flex-col items-center justify-center py-16 text-center\">\n <FigmaIcon className=\"w-16 h-16 text-ods-text-secondary mb-4\" />\n <p className=\"text-ods-text-secondary\">Figma URL not configured</p>\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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","names":["jsx","jsxs","jsx","jsxs","useState","ExternalLink","jsx","jsxs","useState","ExternalLink"]}
|
package/dist/chunk-MWS25U4U.cjs
DELETED
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
var _chunkOXC72UIPcjs = require('./chunk-OXC72UIP.cjs');
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
var _chunkD6RK5YXXcjs = require('./chunk-D6RK5YXX.cjs');
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
var _chunkXXI7BNB6cjs = require('./chunk-XXI7BNB6.cjs');
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
var _chunkZS2SBWBRcjs = require('./chunk-ZS2SBWBR.cjs');
|
|
21
|
-
|
|
22
|
-
// src/components/embeds/embed-iframe.tsx
|
|
23
|
-
var _react = require('react');
|
|
24
|
-
var _jsxruntime = require('react/jsx-runtime');
|
|
25
|
-
function EmbedLoadingSkeleton({ height }) {
|
|
26
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
27
|
-
"div",
|
|
28
|
-
{
|
|
29
|
-
className: "w-full rounded-lg border border-ods-border overflow-hidden bg-ods-skeleton animate-pulse",
|
|
30
|
-
style: { height: height || "calc(100vh - 250px)" },
|
|
31
|
-
children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-center justify-center h-full gap-4", children: [
|
|
32
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-12 h-12 rounded-lg bg-ods-card" }),
|
|
33
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-4 w-48 rounded bg-ods-card" }),
|
|
34
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "h-3 w-32 rounded bg-ods-card" })
|
|
35
|
-
] })
|
|
36
|
-
}
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
function EmbedIframe({
|
|
40
|
-
src,
|
|
41
|
-
title,
|
|
42
|
-
className,
|
|
43
|
-
height,
|
|
44
|
-
allow,
|
|
45
|
-
referrerPolicy,
|
|
46
|
-
loading,
|
|
47
|
-
allowFullScreen
|
|
48
|
-
}) {
|
|
49
|
-
const [isLoaded, setIsLoaded] = _react.useState.call(void 0, false);
|
|
50
|
-
const iframeRef = _react.useRef.call(void 0, null);
|
|
51
|
-
const handleLoad = _react.useCallback.call(void 0, () => setIsLoaded(true), []);
|
|
52
|
-
_react.useEffect.call(void 0, () => {
|
|
53
|
-
setIsLoaded(false);
|
|
54
|
-
}, [src]);
|
|
55
|
-
_react.useEffect.call(void 0, () => {
|
|
56
|
-
const iframe = iframeRef.current;
|
|
57
|
-
return () => {
|
|
58
|
-
if (iframe) {
|
|
59
|
-
try {
|
|
60
|
-
iframe.src = "about:blank";
|
|
61
|
-
} catch (e) {
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
}, [src]);
|
|
66
|
-
const resolvedHeight = height || "calc(100vh - 250px)";
|
|
67
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
68
|
-
!isLoaded && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, EmbedLoadingSkeleton, { height: resolvedHeight }),
|
|
69
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
70
|
-
"div",
|
|
71
|
-
{
|
|
72
|
-
className: `w-full rounded-lg border border-ods-border overflow-hidden ${!isLoaded ? "h-0 overflow-hidden" : ""} ${className || ""}`,
|
|
73
|
-
style: isLoaded ? { height: resolvedHeight } : void 0,
|
|
74
|
-
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
75
|
-
"iframe",
|
|
76
|
-
{
|
|
77
|
-
ref: iframeRef,
|
|
78
|
-
src,
|
|
79
|
-
className: "w-full h-full border-0",
|
|
80
|
-
title,
|
|
81
|
-
onLoad: handleLoad,
|
|
82
|
-
allow,
|
|
83
|
-
referrerPolicy,
|
|
84
|
-
loading,
|
|
85
|
-
allowFullScreen: _optionalChain([allow, 'optionalAccess', _ => _.includes, 'call', _2 => _2("fullscreen")]) ? void 0 : allowFullScreen
|
|
86
|
-
},
|
|
87
|
-
src
|
|
88
|
-
)
|
|
89
|
-
}
|
|
90
|
-
)
|
|
91
|
-
] });
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// src/components/embeds/pdf-viewer.tsx
|
|
95
|
-
var _lucidereact = require('lucide-react');
|
|
96
|
-
|
|
97
|
-
function PdfViewer({ src, fileName, onPreview, onDownload, height }) {
|
|
98
|
-
const displayName = fileName || "PDF Document";
|
|
99
|
-
if (!src) {
|
|
100
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [
|
|
101
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkZS2SBWBRcjs.AdobePdfIcon, { className: "w-16 h-16 text-ods-text-secondary mb-4" }),
|
|
102
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary", children: "PDF file not available" })
|
|
103
|
-
] });
|
|
104
|
-
}
|
|
105
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "space-y-4", children: [
|
|
106
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
107
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
108
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkZS2SBWBRcjs.AdobePdfIcon, { className: "w-5 h-5 shrink-0" }),
|
|
109
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "text-xl font-semibold text-ods-text-primary truncate", children: displayName })
|
|
110
|
-
] }),
|
|
111
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2 w-full sm:w-auto", children: [
|
|
112
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
113
|
-
_chunkXXI7BNB6cjs.Button,
|
|
114
|
-
{
|
|
115
|
-
variant: "outline",
|
|
116
|
-
size: "small-legacy",
|
|
117
|
-
href: onPreview ? void 0 : src,
|
|
118
|
-
openInNewTab: !onPreview,
|
|
119
|
-
onClick: onPreview,
|
|
120
|
-
leftIcon: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Eye, { className: "w-4 h-4" }),
|
|
121
|
-
className: "flex-1 sm:flex-initial",
|
|
122
|
-
children: "Preview"
|
|
123
|
-
}
|
|
124
|
-
),
|
|
125
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
126
|
-
_chunkXXI7BNB6cjs.Button,
|
|
127
|
-
{
|
|
128
|
-
variant: "outline",
|
|
129
|
-
size: "small-legacy",
|
|
130
|
-
href: onDownload ? void 0 : src,
|
|
131
|
-
openInNewTab: !onDownload,
|
|
132
|
-
onClick: onDownload,
|
|
133
|
-
leftIcon: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Download, { className: "w-4 h-4" }),
|
|
134
|
-
className: "flex-1 sm:flex-initial",
|
|
135
|
-
children: "Download"
|
|
136
|
-
}
|
|
137
|
-
)
|
|
138
|
-
] })
|
|
139
|
-
] }),
|
|
140
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, EmbedIframe, { src, title: displayName, height })
|
|
141
|
-
] });
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// src/components/embeds/google-sheets-viewer.tsx
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
function GoogleSheetsViewer({ externalUrl, fileName, height }) {
|
|
148
|
-
const displayName = fileName || "Google Sheet";
|
|
149
|
-
if (!externalUrl) {
|
|
150
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [
|
|
151
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkZS2SBWBRcjs.GoogleSheetsIcon, { className: "w-16 h-16 text-ods-text-secondary mb-4" }),
|
|
152
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary", children: "Google Sheet URL not configured" })
|
|
153
|
-
] });
|
|
154
|
-
}
|
|
155
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "space-y-4", children: [
|
|
156
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
157
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
158
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkZS2SBWBRcjs.GoogleSheetsIcon, { className: "w-5 h-5 shrink-0" }),
|
|
159
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "text-xl font-semibold text-ods-text-primary truncate", children: displayName })
|
|
160
|
-
] }),
|
|
161
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
162
|
-
_chunkXXI7BNB6cjs.Button,
|
|
163
|
-
{
|
|
164
|
-
variant: "outline",
|
|
165
|
-
size: "small-legacy",
|
|
166
|
-
href: _chunkD6RK5YXXcjs.toGoogleSheetsOriginalUrl.call(void 0, externalUrl),
|
|
167
|
-
openInNewTab: true,
|
|
168
|
-
leftIcon: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkZS2SBWBRcjs.GoogleSheetsIcon, { className: "w-4 h-4" }),
|
|
169
|
-
rightIcon: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.ExternalLink, { className: "w-4 h-4" }),
|
|
170
|
-
className: "w-full sm:w-auto",
|
|
171
|
-
children: "Open in Google Sheets"
|
|
172
|
-
}
|
|
173
|
-
)
|
|
174
|
-
] }),
|
|
175
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
176
|
-
EmbedIframe,
|
|
177
|
-
{
|
|
178
|
-
src: _chunkD6RK5YXXcjs.toGoogleSheetsEmbedUrl.call(void 0, externalUrl),
|
|
179
|
-
title: displayName,
|
|
180
|
-
height
|
|
181
|
-
}
|
|
182
|
-
)
|
|
183
|
-
] });
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// src/components/embeds/figma-embed.tsx
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
function SlidesViewToggle({
|
|
191
|
-
view,
|
|
192
|
-
onChange
|
|
193
|
-
}) {
|
|
194
|
-
const options = [
|
|
195
|
-
{ key: "present", label: "Present", Icon: _lucidereact.Play },
|
|
196
|
-
{ key: "browse", label: "Browse", Icon: _lucidereact.LayoutGrid }
|
|
197
|
-
];
|
|
198
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
199
|
-
_chunkOXC72UIPcjs.ToggleGroup,
|
|
200
|
-
{
|
|
201
|
-
type: "single",
|
|
202
|
-
value: view,
|
|
203
|
-
onValueChange: (v) => {
|
|
204
|
-
if (v && v !== view) onChange(v);
|
|
205
|
-
},
|
|
206
|
-
"aria-label": "Figma slides view mode",
|
|
207
|
-
className: "flex shrink-0 items-center gap-0.5 rounded-lg border border-ods-border bg-ods-card p-0.5",
|
|
208
|
-
children: options.map(({ key, label, Icon }) => {
|
|
209
|
-
const active = view === key;
|
|
210
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
211
|
-
_chunkOXC72UIPcjs.ToggleGroupItem,
|
|
212
|
-
{
|
|
213
|
-
value: key,
|
|
214
|
-
"aria-label": label,
|
|
215
|
-
className: `flex items-center gap-1.5 rounded-md px-2.5 py-1 text-sm font-medium transition-colors ${active ? "bg-ods-accent text-ods-text-on-accent" : "text-ods-text-secondary hover:text-ods-text-primary hover:bg-ods-bg-hover"}`,
|
|
216
|
-
children: [
|
|
217
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, Icon, { className: "h-4 w-4 shrink-0" }),
|
|
218
|
-
label
|
|
219
|
-
]
|
|
220
|
-
},
|
|
221
|
-
key
|
|
222
|
-
);
|
|
223
|
-
})
|
|
224
|
-
}
|
|
225
|
-
);
|
|
226
|
-
}
|
|
227
|
-
function FigmaEmbed({ url, title, height, loading = "lazy" }) {
|
|
228
|
-
const [view, setView] = _react.useState.call(void 0, "present");
|
|
229
|
-
const isSlides = url ? _chunkD6RK5YXXcjs.isFigmaSlidesUrl.call(void 0, url) : false;
|
|
230
|
-
const embedSrc = url ? _chunkD6RK5YXXcjs.toFigmaEmbedUrl.call(void 0, url, { slidesView: view }) : null;
|
|
231
|
-
const originalUrl = (() => {
|
|
232
|
-
if (!url) return null;
|
|
233
|
-
try {
|
|
234
|
-
const parsed = new URL(_chunkD6RK5YXXcjs.toFigmaOriginalUrl.call(void 0, url));
|
|
235
|
-
const host = parsed.hostname.toLowerCase();
|
|
236
|
-
const okHost = host === "figma.com" || host.endsWith(".figma.com");
|
|
237
|
-
const okProtocol = parsed.protocol === "https:" || parsed.protocol === "http:";
|
|
238
|
-
return okHost && okProtocol ? parsed.toString() : null;
|
|
239
|
-
} catch (e2) {
|
|
240
|
-
return null;
|
|
241
|
-
}
|
|
242
|
-
})();
|
|
243
|
-
const heading = title || "Figma Design";
|
|
244
|
-
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "my-6 space-y-3", children: [
|
|
245
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
246
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
247
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkZS2SBWBRcjs.FigmaIcon, { className: "w-5 h-5 shrink-0" }),
|
|
248
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "font-sans text-base font-semibold text-ods-text-primary truncate", children: heading })
|
|
249
|
-
] }),
|
|
250
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-2 sm:flex-row sm:items-center", children: [
|
|
251
|
-
isSlides && embedSrc && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SlidesViewToggle, { view, onChange: setView }),
|
|
252
|
-
originalUrl && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
253
|
-
_chunkXXI7BNB6cjs.Button,
|
|
254
|
-
{
|
|
255
|
-
variant: "outline",
|
|
256
|
-
size: "small-legacy",
|
|
257
|
-
href: originalUrl,
|
|
258
|
-
openInNewTab: true,
|
|
259
|
-
leftIcon: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkZS2SBWBRcjs.FigmaIcon, { className: "w-4 h-4" }),
|
|
260
|
-
rightIcon: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.ExternalLink, { className: "w-4 h-4" }),
|
|
261
|
-
className: "w-full sm:w-auto",
|
|
262
|
-
children: "Open in Figma"
|
|
263
|
-
}
|
|
264
|
-
)
|
|
265
|
-
] })
|
|
266
|
-
] }),
|
|
267
|
-
embedSrc ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
268
|
-
EmbedIframe,
|
|
269
|
-
{
|
|
270
|
-
src: embedSrc,
|
|
271
|
-
title: heading,
|
|
272
|
-
allow: "clipboard-write; clipboard-read; fullscreen",
|
|
273
|
-
loading,
|
|
274
|
-
height,
|
|
275
|
-
allowFullScreen: true
|
|
276
|
-
}
|
|
277
|
-
) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-center justify-center py-16 text-center", children: [
|
|
278
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkZS2SBWBRcjs.FigmaIcon, { className: "w-16 h-16 text-ods-text-secondary mb-4" }),
|
|
279
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary", children: "Figma URL not configured" })
|
|
280
|
-
] })
|
|
281
|
-
] });
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
exports.EmbedIframe = EmbedIframe; exports.PdfViewer = PdfViewer; exports.GoogleSheetsViewer = GoogleSheetsViewer; exports.FigmaEmbed = FigmaEmbed;
|
|
290
|
-
//# sourceMappingURL=chunk-MWS25U4U.cjs.map
|