@tangle-network/sandbox-ui 0.131.0 → 0.131.2
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/assets.d.ts +21 -1
- package/dist/assets.js +408 -249
- package/dist/{dashboard-BW-rPRwj.js → dashboard-B7mrHa2A.js} +1 -1
- package/dist/dashboard.js +1 -1
- package/dist/globals.css +35 -31
- package/dist/index-BVMgdFU9.d.ts +30 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -5
- package/dist/primitives-DVo5ldkk.js +25 -0
- package/dist/primitives.d.ts +2 -2
- package/dist/primitives.js +2 -2
- package/dist/styles.css +35 -31
- package/dist/{workbench-C2CzWiZU.js → workbench-syQB06Hc.js} +1 -1
- package/dist/workbench.js +1 -1
- package/dist/{workspace-DRz3SoJc.js → workspace-CgG0B5NC.js} +10 -8
- package/dist/workspace.js +1 -1
- package/package.json +5 -5
- package/dist/index-C6oItkj5.d.ts +0 -30
- package/dist/primitives-JjV1ruzp.js +0 -25
package/dist/assets.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as cn } from "./utils-DzWbktWG.js";
|
|
2
|
-
import { Badge, Button, Input, Label, Textarea } from "@tangle-network/ui/primitives";
|
|
3
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Badge, Button, DatePicker, FilterField, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Textarea, Toolbar, localToday } from "@tangle-network/ui/primitives";
|
|
3
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
import * as React$1 from "react";
|
|
5
5
|
import { Fragment as Fragment$1 } from "react";
|
|
6
6
|
import { Check, CheckCheck, ChevronDown, ChevronLeft, ChevronRight, Film, GitBranch, Loader2, Maximize2, MessageSquare, Pencil, Play, Save, Search, X } from "lucide-react";
|
|
@@ -118,6 +118,283 @@ function ImagePreview({ content, brand, format = "feed", className }) {
|
|
|
118
118
|
});
|
|
119
119
|
}
|
|
120
120
|
//#endregion
|
|
121
|
+
//#region src/assets/preview/email-preview.tsx
|
|
122
|
+
/** sRGB relative luminance of a #rgb or #rrggbb colour; null for anything else. */
|
|
123
|
+
function luminance(color) {
|
|
124
|
+
const hex = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(color.trim())?.[1];
|
|
125
|
+
if (!hex) return null;
|
|
126
|
+
const full = hex.length === 3 ? hex.split("").map((c) => c + c).join("") : hex;
|
|
127
|
+
const [r, g, b] = [
|
|
128
|
+
0,
|
|
129
|
+
2,
|
|
130
|
+
4
|
|
131
|
+
].map((i) => {
|
|
132
|
+
const channel = parseInt(full.slice(i, i + 2), 16) / 255;
|
|
133
|
+
return channel <= .03928 ? channel / 12.92 : ((channel + .055) / 1.055) ** 2.4;
|
|
134
|
+
});
|
|
135
|
+
return .2126 * r + .7152 * g + .0722 * b;
|
|
136
|
+
}
|
|
137
|
+
function contrast(a, b) {
|
|
138
|
+
return (Math.max(a, b) + .05) / (Math.min(a, b) + .05);
|
|
139
|
+
}
|
|
140
|
+
const PAPER = {
|
|
141
|
+
light: "#ffffff",
|
|
142
|
+
dark: "#111218"
|
|
143
|
+
};
|
|
144
|
+
const INK = {
|
|
145
|
+
light: "#16171d",
|
|
146
|
+
dark: "#f4f4f6"
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* The colours an email body renders in. A brand whose text colour is light
|
|
150
|
+
* writes on a dark page; any brand colour that would not read on that page
|
|
151
|
+
* falls back to the page's own ink.
|
|
152
|
+
*/
|
|
153
|
+
function emailPalette(brand) {
|
|
154
|
+
const text = luminance(brand.textColor);
|
|
155
|
+
const scheme = text !== null && text > .5 ? "dark" : "light";
|
|
156
|
+
const paper = PAPER[scheme];
|
|
157
|
+
const paperLum = luminance(paper);
|
|
158
|
+
const readable = (color, minimum) => {
|
|
159
|
+
const lum = luminance(color);
|
|
160
|
+
return lum !== null && contrast(lum, paperLum) >= minimum;
|
|
161
|
+
};
|
|
162
|
+
const ink = readable(brand.textColor, 4.5) ? brand.textColor : INK[scheme];
|
|
163
|
+
const accent = readable(brand.primaryColor, 3) ? brand.primaryColor : ink;
|
|
164
|
+
const primary = luminance(brand.primaryColor);
|
|
165
|
+
const buttonText = primary !== null && contrast(primary, 1) < contrast(primary, 0) ? "#111111" : "#ffffff";
|
|
166
|
+
return {
|
|
167
|
+
scheme,
|
|
168
|
+
paper,
|
|
169
|
+
ink,
|
|
170
|
+
accent,
|
|
171
|
+
button: brand.primaryColor,
|
|
172
|
+
buttonText,
|
|
173
|
+
quote: brand.accentColor
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function Button$1({ href, label, palette }) {
|
|
177
|
+
return /* @__PURE__ */ jsx("a", {
|
|
178
|
+
href,
|
|
179
|
+
onClick: (event) => event.preventDefault(),
|
|
180
|
+
className: "inline-block rounded-md px-5 py-2.5 text-sm font-semibold no-underline",
|
|
181
|
+
style: {
|
|
182
|
+
background: palette.button,
|
|
183
|
+
color: palette.buttonText
|
|
184
|
+
},
|
|
185
|
+
children: label
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
function Section({ section, palette }) {
|
|
189
|
+
const muted = {
|
|
190
|
+
color: palette.ink,
|
|
191
|
+
opacity: .72
|
|
192
|
+
};
|
|
193
|
+
switch (section.type) {
|
|
194
|
+
case "hero": return /* @__PURE__ */ jsxs("div", {
|
|
195
|
+
className: "flex flex-col items-center gap-3 py-2 text-center",
|
|
196
|
+
children: [
|
|
197
|
+
section.imageUrl && /* @__PURE__ */ jsx("img", {
|
|
198
|
+
src: section.imageUrl,
|
|
199
|
+
alt: "",
|
|
200
|
+
className: "w-full rounded-md object-cover"
|
|
201
|
+
}),
|
|
202
|
+
/* @__PURE__ */ jsx("h2", {
|
|
203
|
+
className: "text-2xl font-bold leading-tight tracking-tight",
|
|
204
|
+
style: { color: palette.accent },
|
|
205
|
+
children: section.headline
|
|
206
|
+
}),
|
|
207
|
+
section.subheadline && /* @__PURE__ */ jsx("p", {
|
|
208
|
+
className: "text-base leading-relaxed",
|
|
209
|
+
style: muted,
|
|
210
|
+
children: section.subheadline
|
|
211
|
+
}),
|
|
212
|
+
section.ctaLabel && /* @__PURE__ */ jsx("div", {
|
|
213
|
+
className: "pt-1",
|
|
214
|
+
children: /* @__PURE__ */ jsx(Button$1, {
|
|
215
|
+
href: section.ctaUrl ?? "#",
|
|
216
|
+
label: section.ctaLabel,
|
|
217
|
+
palette
|
|
218
|
+
})
|
|
219
|
+
})
|
|
220
|
+
]
|
|
221
|
+
});
|
|
222
|
+
case "body": return /* @__PURE__ */ jsx("p", {
|
|
223
|
+
className: "text-base leading-7 whitespace-pre-wrap",
|
|
224
|
+
children: section.text
|
|
225
|
+
});
|
|
226
|
+
case "feature": return /* @__PURE__ */ jsxs("div", {
|
|
227
|
+
className: "flex items-start gap-4",
|
|
228
|
+
children: [section.imageUrl && /* @__PURE__ */ jsx("img", {
|
|
229
|
+
src: section.imageUrl,
|
|
230
|
+
alt: "",
|
|
231
|
+
className: "size-16 shrink-0 rounded-md object-cover"
|
|
232
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
233
|
+
className: "flex flex-col gap-1",
|
|
234
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
235
|
+
className: "text-base font-semibold",
|
|
236
|
+
children: section.headline
|
|
237
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
238
|
+
className: "text-sm leading-relaxed",
|
|
239
|
+
style: muted,
|
|
240
|
+
children: section.description
|
|
241
|
+
})]
|
|
242
|
+
})]
|
|
243
|
+
});
|
|
244
|
+
case "testimonial": return /* @__PURE__ */ jsxs("blockquote", {
|
|
245
|
+
className: "border-l-4 pl-4",
|
|
246
|
+
style: { borderColor: palette.quote },
|
|
247
|
+
children: [/* @__PURE__ */ jsxs("p", {
|
|
248
|
+
className: "text-base italic leading-relaxed",
|
|
249
|
+
children: [
|
|
250
|
+
"“",
|
|
251
|
+
section.quote,
|
|
252
|
+
"”"
|
|
253
|
+
]
|
|
254
|
+
}), /* @__PURE__ */ jsxs("footer", {
|
|
255
|
+
className: "mt-2 text-sm font-medium",
|
|
256
|
+
style: muted,
|
|
257
|
+
children: [section.author, section.role ? `, ${section.role}` : ""]
|
|
258
|
+
})]
|
|
259
|
+
});
|
|
260
|
+
case "cta": return /* @__PURE__ */ jsxs("div", {
|
|
261
|
+
className: "flex flex-col items-center gap-2 py-2 text-center",
|
|
262
|
+
children: [/* @__PURE__ */ jsx(Button$1, {
|
|
263
|
+
href: section.url,
|
|
264
|
+
label: section.label,
|
|
265
|
+
palette
|
|
266
|
+
}), section.subtext && /* @__PURE__ */ jsx("p", {
|
|
267
|
+
className: "text-sm",
|
|
268
|
+
style: muted,
|
|
269
|
+
children: section.subtext
|
|
270
|
+
})]
|
|
271
|
+
});
|
|
272
|
+
case "divider": return /* @__PURE__ */ jsx("hr", {
|
|
273
|
+
className: "border-0 border-t",
|
|
274
|
+
style: {
|
|
275
|
+
borderColor: palette.ink,
|
|
276
|
+
opacity: .15
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
default: return null;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* An email as a reader meets it: who it is from, the subject and the inbox
|
|
284
|
+
* preview line, then the body on the brand's page and in its typeface.
|
|
285
|
+
*/
|
|
286
|
+
function EmailPreview({ content, brand, previewUrl, className }) {
|
|
287
|
+
const palette = emailPalette(brand);
|
|
288
|
+
return /* @__PURE__ */ jsxs("article", {
|
|
289
|
+
className: cn("overflow-hidden rounded-lg border border-border bg-card shadow-sm", className),
|
|
290
|
+
children: [/* @__PURE__ */ jsxs("header", {
|
|
291
|
+
className: "flex flex-col gap-1 border-b border-border px-5 py-4",
|
|
292
|
+
children: [
|
|
293
|
+
/* @__PURE__ */ jsxs("div", {
|
|
294
|
+
className: "flex items-center gap-2 text-sm",
|
|
295
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
296
|
+
"aria-hidden": true,
|
|
297
|
+
className: "flex size-7 shrink-0 items-center justify-center rounded-full text-xs font-semibold",
|
|
298
|
+
style: {
|
|
299
|
+
background: palette.button,
|
|
300
|
+
color: palette.buttonText
|
|
301
|
+
},
|
|
302
|
+
children: brand.businessName.trim().charAt(0).toUpperCase() || "?"
|
|
303
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
304
|
+
className: "font-medium",
|
|
305
|
+
children: brand.businessName
|
|
306
|
+
})]
|
|
307
|
+
}),
|
|
308
|
+
/* @__PURE__ */ jsx("h3", {
|
|
309
|
+
className: "text-base font-semibold leading-snug",
|
|
310
|
+
children: content.subject
|
|
311
|
+
}),
|
|
312
|
+
content.preheader && /* @__PURE__ */ jsx("p", {
|
|
313
|
+
className: "text-sm text-muted-foreground",
|
|
314
|
+
children: content.preheader
|
|
315
|
+
})
|
|
316
|
+
]
|
|
317
|
+
}), previewUrl ? /* @__PURE__ */ jsx("iframe", {
|
|
318
|
+
src: previewUrl,
|
|
319
|
+
title: "Email preview",
|
|
320
|
+
sandbox: "allow-same-origin",
|
|
321
|
+
className: "block h-[480px] w-full bg-white"
|
|
322
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
323
|
+
className: "px-5 py-8 sm:px-8",
|
|
324
|
+
style: {
|
|
325
|
+
background: palette.paper,
|
|
326
|
+
color: palette.ink,
|
|
327
|
+
fontFamily: brand.fontFamily
|
|
328
|
+
},
|
|
329
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
330
|
+
className: "mx-auto flex max-w-[560px] flex-col gap-5",
|
|
331
|
+
children: content.sections.map((section, index) => /* @__PURE__ */ jsx(Section, {
|
|
332
|
+
section,
|
|
333
|
+
palette
|
|
334
|
+
}, index))
|
|
335
|
+
})
|
|
336
|
+
})]
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
//#endregion
|
|
340
|
+
//#region src/assets/preview/copy-preview.tsx
|
|
341
|
+
const PLATFORM_LIMITS = {
|
|
342
|
+
instagram: 2200,
|
|
343
|
+
tiktok: 2200,
|
|
344
|
+
x: 280,
|
|
345
|
+
linkedin: 3e3,
|
|
346
|
+
sms: 160,
|
|
347
|
+
"email-subject": 60
|
|
348
|
+
};
|
|
349
|
+
const COPY_PLATFORM_LABEL = {
|
|
350
|
+
instagram: "Instagram",
|
|
351
|
+
tiktok: "TikTok",
|
|
352
|
+
x: "X",
|
|
353
|
+
linkedin: "LinkedIn",
|
|
354
|
+
sms: "SMS",
|
|
355
|
+
"email-subject": "Email subject"
|
|
356
|
+
};
|
|
357
|
+
/** Copy as it will read: the channel and its length budget, the headline, the body and its hashtags. */
|
|
358
|
+
function CopyPreview({ content, className }) {
|
|
359
|
+
const limit = PLATFORM_LIMITS[content.platform];
|
|
360
|
+
const length = content.body.length;
|
|
361
|
+
const over = limit !== null && length > limit;
|
|
362
|
+
const near = !over && limit !== null && length >= limit * .9;
|
|
363
|
+
return /* @__PURE__ */ jsxs("article", {
|
|
364
|
+
className: cn("flex flex-col gap-4 rounded-xl border border-border bg-card p-6 shadow-sm", className),
|
|
365
|
+
children: [
|
|
366
|
+
/* @__PURE__ */ jsxs("div", {
|
|
367
|
+
className: "flex items-center justify-between gap-3",
|
|
368
|
+
children: [/* @__PURE__ */ jsx(Badge, {
|
|
369
|
+
variant: "secondary",
|
|
370
|
+
className: "text-xs",
|
|
371
|
+
children: COPY_PLATFORM_LABEL[content.platform] ?? content.platform
|
|
372
|
+
}), limit !== null && /* @__PURE__ */ jsxs("span", {
|
|
373
|
+
className: cn("text-xs tabular-nums", over ? "font-medium text-destructive" : near ? "text-warning" : "text-muted-foreground"),
|
|
374
|
+
children: [
|
|
375
|
+
length,
|
|
376
|
+
" / ",
|
|
377
|
+
limit,
|
|
378
|
+
" characters"
|
|
379
|
+
]
|
|
380
|
+
})]
|
|
381
|
+
}),
|
|
382
|
+
content.headline && /* @__PURE__ */ jsx("h3", {
|
|
383
|
+
className: "text-xl font-semibold leading-snug tracking-tight",
|
|
384
|
+
children: content.headline
|
|
385
|
+
}),
|
|
386
|
+
/* @__PURE__ */ jsx("p", {
|
|
387
|
+
className: "text-base leading-7 whitespace-pre-wrap [overflow-wrap:anywhere]",
|
|
388
|
+
children: content.body
|
|
389
|
+
}),
|
|
390
|
+
content.hashtags && content.hashtags.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
391
|
+
className: "flex flex-wrap gap-x-2 gap-y-1 text-sm text-primary",
|
|
392
|
+
children: content.hashtags.map((tag) => /* @__PURE__ */ jsxs("span", { children: ["#", tag.replace(/^#/, "")] }, tag))
|
|
393
|
+
})
|
|
394
|
+
]
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
//#endregion
|
|
121
398
|
//#region src/assets/labels.ts
|
|
122
399
|
/** Reader-facing name for each asset format. */
|
|
123
400
|
const ASSET_FORMAT_LABEL = {
|
|
@@ -177,15 +454,46 @@ function Thumbnail({ spec }) {
|
|
|
177
454
|
const { format, brand, content } = spec;
|
|
178
455
|
if (format === "email") {
|
|
179
456
|
const ec = content;
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
className: "
|
|
187
|
-
children: [
|
|
188
|
-
|
|
457
|
+
const palette = emailPalette(brand);
|
|
458
|
+
const hero = ec.sections.find((section) => section.type === "hero");
|
|
459
|
+
const body = ec.sections.find((section) => section.type === "body");
|
|
460
|
+
return /* @__PURE__ */ jsx("div", {
|
|
461
|
+
className: "flex h-full flex-col p-3",
|
|
462
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
463
|
+
className: "flex h-full flex-col overflow-hidden rounded-md border border-border bg-card shadow-sm",
|
|
464
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
465
|
+
className: "flex flex-col gap-0.5 border-b border-border px-3 py-2",
|
|
466
|
+
children: [
|
|
467
|
+
/* @__PURE__ */ jsx("div", {
|
|
468
|
+
className: "truncate text-xs text-muted-foreground",
|
|
469
|
+
children: brand.businessName
|
|
470
|
+
}),
|
|
471
|
+
/* @__PURE__ */ jsx("div", {
|
|
472
|
+
className: "line-clamp-2 text-sm font-semibold leading-snug",
|
|
473
|
+
children: ec.subject
|
|
474
|
+
}),
|
|
475
|
+
ec.preheader && /* @__PURE__ */ jsx("div", {
|
|
476
|
+
className: "truncate text-xs text-muted-foreground",
|
|
477
|
+
children: ec.preheader
|
|
478
|
+
})
|
|
479
|
+
]
|
|
480
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
481
|
+
className: "flex flex-1 flex-col gap-1 overflow-hidden px-3 py-2",
|
|
482
|
+
style: {
|
|
483
|
+
background: palette.paper,
|
|
484
|
+
color: palette.ink,
|
|
485
|
+
fontFamily: brand.fontFamily
|
|
486
|
+
},
|
|
487
|
+
children: [hero?.type === "hero" && /* @__PURE__ */ jsx("div", {
|
|
488
|
+
className: "line-clamp-2 text-sm font-bold leading-snug",
|
|
489
|
+
style: { color: palette.accent },
|
|
490
|
+
children: hero.headline
|
|
491
|
+
}), body?.type === "body" && /* @__PURE__ */ jsx("div", {
|
|
492
|
+
className: "line-clamp-4 text-xs leading-relaxed opacity-75",
|
|
493
|
+
children: body.text
|
|
494
|
+
})]
|
|
495
|
+
})]
|
|
496
|
+
})
|
|
189
497
|
});
|
|
190
498
|
}
|
|
191
499
|
if (format.startsWith("image:")) {
|
|
@@ -196,7 +504,7 @@ function Thumbnail({ spec }) {
|
|
|
196
504
|
alt: "",
|
|
197
505
|
loading: "lazy",
|
|
198
506
|
decoding: "async",
|
|
199
|
-
className: "h-full w-full object-contain"
|
|
507
|
+
className: "h-full w-full object-contain p-2"
|
|
200
508
|
});
|
|
201
509
|
return /* @__PURE__ */ jsx("div", {
|
|
202
510
|
className: "h-full overflow-hidden",
|
|
@@ -218,7 +526,7 @@ function Thumbnail({ spec }) {
|
|
|
218
526
|
alt: "",
|
|
219
527
|
loading: "lazy",
|
|
220
528
|
decoding: "async",
|
|
221
|
-
className: "h-full w-full object-contain"
|
|
529
|
+
className: "h-full w-full object-contain p-2"
|
|
222
530
|
}) : /* @__PURE__ */ jsx("div", {
|
|
223
531
|
className: "flex h-full flex-col gap-1 p-3 text-sm",
|
|
224
532
|
children: /* @__PURE__ */ jsxs("div", {
|
|
@@ -244,14 +552,21 @@ function Thumbnail({ spec }) {
|
|
|
244
552
|
if (format.startsWith("copy:")) {
|
|
245
553
|
const cc = content;
|
|
246
554
|
return /* @__PURE__ */ jsxs("div", {
|
|
247
|
-
className: "flex h-full flex-col gap-
|
|
248
|
-
children: [
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
555
|
+
className: "flex h-full flex-col gap-2 overflow-hidden p-4",
|
|
556
|
+
children: [
|
|
557
|
+
/* @__PURE__ */ jsx("span", {
|
|
558
|
+
className: "text-xs font-medium text-muted-foreground",
|
|
559
|
+
children: COPY_PLATFORM_LABEL[cc.platform] ?? cc.platform
|
|
560
|
+
}),
|
|
561
|
+
cc.headline && /* @__PURE__ */ jsx("div", {
|
|
562
|
+
className: "line-clamp-3 text-base font-semibold leading-snug",
|
|
563
|
+
children: cc.headline
|
|
564
|
+
}),
|
|
565
|
+
/* @__PURE__ */ jsx("div", {
|
|
566
|
+
className: "line-clamp-5 text-sm leading-relaxed text-muted-foreground",
|
|
567
|
+
children: cc.body
|
|
568
|
+
})
|
|
569
|
+
]
|
|
255
570
|
});
|
|
256
571
|
}
|
|
257
572
|
return null;
|
|
@@ -325,125 +640,6 @@ function AssetCard({ spec, variantCount, onApprove, onReject, onEdit, onOpen, cl
|
|
|
325
640
|
});
|
|
326
641
|
}
|
|
327
642
|
//#endregion
|
|
328
|
-
//#region src/assets/preview/email-preview.tsx
|
|
329
|
-
function EmailPreview({ content, brand, previewUrl, className }) {
|
|
330
|
-
if (previewUrl) return jsxs("div", {
|
|
331
|
-
className: cn("flex flex-col gap-1", className),
|
|
332
|
-
children: [
|
|
333
|
-
jsx("div", {
|
|
334
|
-
className: "text-xs text-muted-foreground font-medium truncate",
|
|
335
|
-
children: content.subject
|
|
336
|
-
}),
|
|
337
|
-
content.preheader && jsx("div", {
|
|
338
|
-
className: "text-xs text-muted-foreground/60 truncate",
|
|
339
|
-
children: content.preheader
|
|
340
|
-
}),
|
|
341
|
-
jsx("iframe", {
|
|
342
|
-
src: previewUrl,
|
|
343
|
-
className: "w-full rounded border border-border",
|
|
344
|
-
style: {
|
|
345
|
-
height: 480,
|
|
346
|
-
background: "#fff"
|
|
347
|
-
},
|
|
348
|
-
title: "Email preview",
|
|
349
|
-
sandbox: "allow-same-origin"
|
|
350
|
-
})
|
|
351
|
-
]
|
|
352
|
-
});
|
|
353
|
-
return jsxs("div", {
|
|
354
|
-
className: cn("flex flex-col gap-2", className),
|
|
355
|
-
children: [
|
|
356
|
-
jsx("div", {
|
|
357
|
-
className: "text-sm font-semibold truncate",
|
|
358
|
-
children: content.subject
|
|
359
|
-
}),
|
|
360
|
-
content.preheader && jsx("div", {
|
|
361
|
-
className: "text-xs text-muted-foreground truncate",
|
|
362
|
-
children: content.preheader
|
|
363
|
-
}),
|
|
364
|
-
jsx("div", {
|
|
365
|
-
className: "rounded border border-border p-4 space-y-3 overflow-y-auto",
|
|
366
|
-
style: {
|
|
367
|
-
maxHeight: 480,
|
|
368
|
-
fontFamily: brand.fontFamily,
|
|
369
|
-
color: brand.textColor
|
|
370
|
-
},
|
|
371
|
-
children: content.sections.map((section, i) => {
|
|
372
|
-
if (section.type === "hero") return jsxs("div", {
|
|
373
|
-
className: "text-center py-4 space-y-2",
|
|
374
|
-
children: [
|
|
375
|
-
section.imageUrl && jsx("img", {
|
|
376
|
-
src: section.imageUrl,
|
|
377
|
-
alt: "",
|
|
378
|
-
className: "mx-auto max-h-40 object-cover rounded"
|
|
379
|
-
}),
|
|
380
|
-
jsx("div", {
|
|
381
|
-
className: "text-xl font-bold",
|
|
382
|
-
style: { color: brand.primaryColor },
|
|
383
|
-
children: section.headline
|
|
384
|
-
}),
|
|
385
|
-
section.subheadline && jsx("div", {
|
|
386
|
-
className: "text-sm text-muted-foreground",
|
|
387
|
-
children: section.subheadline
|
|
388
|
-
}),
|
|
389
|
-
section.ctaLabel && jsx("a", {
|
|
390
|
-
href: section.ctaUrl ?? "#",
|
|
391
|
-
className: "inline-block px-4 py-2 rounded text-sm font-medium text-white",
|
|
392
|
-
style: { background: brand.primaryColor },
|
|
393
|
-
children: section.ctaLabel
|
|
394
|
-
})
|
|
395
|
-
]
|
|
396
|
-
}, i);
|
|
397
|
-
if (section.type === "body") return jsx("p", {
|
|
398
|
-
className: "text-sm leading-relaxed whitespace-pre-wrap",
|
|
399
|
-
children: section.text
|
|
400
|
-
}, i);
|
|
401
|
-
if (section.type === "feature") return jsxs("div", {
|
|
402
|
-
className: "flex gap-3 items-start",
|
|
403
|
-
children: [section.imageUrl && jsx("img", {
|
|
404
|
-
src: section.imageUrl,
|
|
405
|
-
alt: "",
|
|
406
|
-
className: "w-16 h-16 object-cover rounded shrink-0"
|
|
407
|
-
}), jsxs("div", { children: [jsx("div", {
|
|
408
|
-
className: "text-sm font-semibold",
|
|
409
|
-
children: section.headline
|
|
410
|
-
}), jsx("div", {
|
|
411
|
-
className: "text-xs text-muted-foreground mt-0.5",
|
|
412
|
-
children: section.description
|
|
413
|
-
})] })]
|
|
414
|
-
}, i);
|
|
415
|
-
if (section.type === "testimonial") return jsxs("blockquote", {
|
|
416
|
-
className: "border-l-2 pl-3 italic text-sm text-muted-foreground",
|
|
417
|
-
style: { borderColor: brand.accentColor },
|
|
418
|
-
children: [jsxs("p", { children: [
|
|
419
|
-
"\"",
|
|
420
|
-
section.quote,
|
|
421
|
-
"\""
|
|
422
|
-
] }), jsxs("footer", {
|
|
423
|
-
className: "mt-1 text-xs not-italic font-medium",
|
|
424
|
-
children: [section.author, section.role ? `, ${section.role}` : ""]
|
|
425
|
-
})]
|
|
426
|
-
}, i);
|
|
427
|
-
if (section.type === "cta") return jsxs("div", {
|
|
428
|
-
className: "text-center py-3 space-y-1",
|
|
429
|
-
children: [jsx("a", {
|
|
430
|
-
href: section.url,
|
|
431
|
-
className: "inline-block px-5 py-2.5 rounded font-medium text-white text-sm",
|
|
432
|
-
style: { background: brand.primaryColor },
|
|
433
|
-
children: section.label
|
|
434
|
-
}), section.subtext && jsx("p", {
|
|
435
|
-
className: "text-xs text-muted-foreground",
|
|
436
|
-
children: section.subtext
|
|
437
|
-
})]
|
|
438
|
-
}, i);
|
|
439
|
-
if (section.type === "divider") return jsx("hr", { className: "border-border" }, i);
|
|
440
|
-
return null;
|
|
441
|
-
})
|
|
442
|
-
})
|
|
443
|
-
]
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
|
-
//#endregion
|
|
447
643
|
//#region src/assets/preview/video-preview.tsx
|
|
448
644
|
function VideoPreview({ content, brand, onRenderRequest, isRendering, className }) {
|
|
449
645
|
if (content.renderedUrl) return /* @__PURE__ */ jsx("div", {
|
|
@@ -534,64 +730,6 @@ function VideoPreview({ content, brand, onRenderRequest, isRendering, className
|
|
|
534
730
|
});
|
|
535
731
|
}
|
|
536
732
|
//#endregion
|
|
537
|
-
//#region src/assets/preview/copy-preview.tsx
|
|
538
|
-
const PLATFORM_LIMITS = {
|
|
539
|
-
instagram: 2200,
|
|
540
|
-
tiktok: 2200,
|
|
541
|
-
x: 280,
|
|
542
|
-
linkedin: 3e3,
|
|
543
|
-
sms: 160,
|
|
544
|
-
"email-subject": 60
|
|
545
|
-
};
|
|
546
|
-
const PLATFORM_LABELS = {
|
|
547
|
-
instagram: "Instagram",
|
|
548
|
-
tiktok: "TikTok",
|
|
549
|
-
x: "X / Twitter",
|
|
550
|
-
linkedin: "LinkedIn",
|
|
551
|
-
sms: "SMS",
|
|
552
|
-
"email-subject": "Email Subject"
|
|
553
|
-
};
|
|
554
|
-
function CopyPreview({ content, className }) {
|
|
555
|
-
const limit = PLATFORM_LIMITS[content.platform];
|
|
556
|
-
const bodyLen = content.body.length;
|
|
557
|
-
const isOverLimit = limit !== null && bodyLen > limit;
|
|
558
|
-
const warningThreshold = limit !== null ? limit * .9 : null;
|
|
559
|
-
const isNearLimit = !isOverLimit && warningThreshold !== null && bodyLen >= warningThreshold;
|
|
560
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
561
|
-
className: cn("flex flex-col gap-2", className),
|
|
562
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
563
|
-
className: "flex items-center justify-between",
|
|
564
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
565
|
-
className: "text-xs font-medium text-muted-foreground",
|
|
566
|
-
children: PLATFORM_LABELS[content.platform]
|
|
567
|
-
}), limit !== null && /* @__PURE__ */ jsxs("span", {
|
|
568
|
-
className: cn("text-xs tabular-nums", isOverLimit ? "text-destructive font-medium" : isNearLimit ? "text-warning" : "text-muted-foreground"),
|
|
569
|
-
children: [
|
|
570
|
-
bodyLen,
|
|
571
|
-
" / ",
|
|
572
|
-
limit
|
|
573
|
-
]
|
|
574
|
-
})]
|
|
575
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
576
|
-
className: "rounded border border-border p-3 space-y-2 bg-card",
|
|
577
|
-
children: [
|
|
578
|
-
content.headline && /* @__PURE__ */ jsx("div", {
|
|
579
|
-
className: "text-sm font-semibold",
|
|
580
|
-
children: content.headline
|
|
581
|
-
}),
|
|
582
|
-
/* @__PURE__ */ jsx("p", {
|
|
583
|
-
className: "text-sm whitespace-pre-wrap leading-relaxed",
|
|
584
|
-
children: content.body
|
|
585
|
-
}),
|
|
586
|
-
content.hashtags && content.hashtags.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
587
|
-
className: "text-sm text-blue-500 flex flex-wrap gap-1",
|
|
588
|
-
children: content.hashtags.map((tag) => /* @__PURE__ */ jsxs("span", { children: ["#", tag] }, tag))
|
|
589
|
-
})
|
|
590
|
-
]
|
|
591
|
-
})]
|
|
592
|
-
});
|
|
593
|
-
}
|
|
594
|
-
//#endregion
|
|
595
733
|
//#region src/assets/asset-editor.tsx
|
|
596
734
|
function BrandPanel({ brand, onChange }) {
|
|
597
735
|
const [open, setOpen] = React$1.useState(false);
|
|
@@ -977,6 +1115,9 @@ function ApprovalQueue({ assets, variantCounts = {}, onApprove, onReject, onEdit
|
|
|
977
1115
|
const [statusFilter, setStatusFilter] = React$1.useState("pending_review");
|
|
978
1116
|
const [editingId, setEditingId] = React$1.useState(null);
|
|
979
1117
|
const [scheduleDate, setScheduleDate] = React$1.useState("");
|
|
1118
|
+
const formatId = React$1.useId();
|
|
1119
|
+
const statusId = React$1.useId();
|
|
1120
|
+
const scheduleId = React$1.useId();
|
|
980
1121
|
const filtered = assets.filter((a) => {
|
|
981
1122
|
if (formatFilter !== "all" && a.format !== formatFilter) return false;
|
|
982
1123
|
if (statusFilter !== "all" && a.status !== statusFilter) return false;
|
|
@@ -1034,60 +1175,78 @@ function ApprovalQueue({ assets, variantCounts = {}, onApprove, onReject, onEdit
|
|
|
1034
1175
|
});
|
|
1035
1176
|
return /* @__PURE__ */ jsxs("div", {
|
|
1036
1177
|
className: cn("flex flex-col gap-3", className),
|
|
1037
|
-
children: [/* @__PURE__ */
|
|
1038
|
-
className: "
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
})
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1178
|
+
children: [/* @__PURE__ */ jsx(Toolbar, {
|
|
1179
|
+
className: "mb-0",
|
|
1180
|
+
search: /* @__PURE__ */ jsxs("div", {
|
|
1181
|
+
className: "relative",
|
|
1182
|
+
children: [/* @__PURE__ */ jsx(Search, {
|
|
1183
|
+
size: 14,
|
|
1184
|
+
"aria-hidden": true,
|
|
1185
|
+
className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground"
|
|
1186
|
+
}), /* @__PURE__ */ jsx(Input, {
|
|
1187
|
+
value: search,
|
|
1188
|
+
onChange: (e) => setSearch(e.target.value),
|
|
1189
|
+
placeholder: "Filter assets…",
|
|
1190
|
+
"aria-label": "Filter assets",
|
|
1191
|
+
className: "pl-9"
|
|
1192
|
+
})]
|
|
1193
|
+
}),
|
|
1194
|
+
filters: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1195
|
+
/* @__PURE__ */ jsx(FilterField, {
|
|
1196
|
+
label: "Format",
|
|
1197
|
+
htmlFor: formatId,
|
|
1198
|
+
children: /* @__PURE__ */ jsxs(Select, {
|
|
1199
|
+
value: formatFilter,
|
|
1200
|
+
onValueChange: setFormatFilter,
|
|
1201
|
+
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
1202
|
+
id: formatId,
|
|
1203
|
+
className: "w-36",
|
|
1204
|
+
children: /* @__PURE__ */ jsx(SelectValue, {})
|
|
1205
|
+
}), /* @__PURE__ */ jsx(SelectContent, { children: FORMAT_OPTIONS.map((o) => /* @__PURE__ */ jsx(SelectItem, {
|
|
1206
|
+
value: o.value,
|
|
1207
|
+
children: o.label
|
|
1208
|
+
}, o.value)) })]
|
|
1209
|
+
})
|
|
1060
1210
|
}),
|
|
1061
|
-
/* @__PURE__ */ jsx(
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
children:
|
|
1068
|
-
|
|
1211
|
+
/* @__PURE__ */ jsx(FilterField, {
|
|
1212
|
+
label: "Status",
|
|
1213
|
+
htmlFor: statusId,
|
|
1214
|
+
children: /* @__PURE__ */ jsxs(Select, {
|
|
1215
|
+
value: statusFilter,
|
|
1216
|
+
onValueChange: setStatusFilter,
|
|
1217
|
+
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
1218
|
+
id: statusId,
|
|
1219
|
+
className: "w-36",
|
|
1220
|
+
children: /* @__PURE__ */ jsx(SelectValue, {})
|
|
1221
|
+
}), /* @__PURE__ */ jsx(SelectContent, { children: STATUS_OPTIONS.map((o) => /* @__PURE__ */ jsx(SelectItem, {
|
|
1222
|
+
value: o.value,
|
|
1223
|
+
children: o.label
|
|
1224
|
+
}, o.value)) })]
|
|
1225
|
+
})
|
|
1069
1226
|
}),
|
|
1070
|
-
pendingCount > 0 && onApprove && /* @__PURE__ */
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1227
|
+
pendingCount > 0 && onApprove && /* @__PURE__ */ jsx(FilterField, {
|
|
1228
|
+
label: "Schedule for",
|
|
1229
|
+
htmlFor: scheduleId,
|
|
1230
|
+
children: /* @__PURE__ */ jsx(DatePicker, {
|
|
1231
|
+
id: scheduleId,
|
|
1232
|
+
className: "w-40",
|
|
1233
|
+
placeholder: "Not scheduled",
|
|
1234
|
+
min: localToday(),
|
|
1074
1235
|
value: scheduleDate,
|
|
1075
|
-
onChange:
|
|
1076
|
-
|
|
1077
|
-
}), /* @__PURE__ */ jsxs(Button, {
|
|
1078
|
-
size: "sm",
|
|
1079
|
-
variant: "outline",
|
|
1080
|
-
onClick: handleBulkApprove,
|
|
1081
|
-
className: "h-8 gap-1.5 text-xs",
|
|
1082
|
-
children: [
|
|
1083
|
-
/* @__PURE__ */ jsx(CheckCheck, { size: 13 }),
|
|
1084
|
-
"Approve all (",
|
|
1085
|
-
pendingCount,
|
|
1086
|
-
")"
|
|
1087
|
-
]
|
|
1088
|
-
})]
|
|
1236
|
+
onChange: setScheduleDate
|
|
1237
|
+
})
|
|
1089
1238
|
})
|
|
1090
|
-
]
|
|
1239
|
+
] }),
|
|
1240
|
+
actions: pendingCount > 0 && onApprove ? /* @__PURE__ */ jsxs(Button, {
|
|
1241
|
+
variant: "outline",
|
|
1242
|
+
onClick: handleBulkApprove,
|
|
1243
|
+
children: [
|
|
1244
|
+
/* @__PURE__ */ jsx(CheckCheck, {}),
|
|
1245
|
+
"Approve all (",
|
|
1246
|
+
pendingCount,
|
|
1247
|
+
")"
|
|
1248
|
+
]
|
|
1249
|
+
}) : void 0
|
|
1091
1250
|
}), filtered.length === 0 ? /* @__PURE__ */ jsx("div", {
|
|
1092
1251
|
className: "py-12 text-center text-sm text-muted-foreground",
|
|
1093
1252
|
children: "No assets match your filters."
|
|
@@ -1105,4 +1264,4 @@ function ApprovalQueue({ assets, variantCounts = {}, onApprove, onReject, onEdit
|
|
|
1105
1264
|
});
|
|
1106
1265
|
}
|
|
1107
1266
|
//#endregion
|
|
1108
|
-
export { ASSET_FORMAT_LABEL, ASSET_STATUS_LABEL, ApprovalQueue, AssetCard, AssetEditor, CopyPreview, EmailPreview, ImagePreview, VideoPreview, imageOnlyUrl, videoPosterUrl };
|
|
1267
|
+
export { ASSET_FORMAT_LABEL, ASSET_STATUS_LABEL, ApprovalQueue, AssetCard, AssetEditor, COPY_PLATFORM_LABEL, CopyPreview, EmailPreview, ImagePreview, VideoPreview, emailPalette, imageOnlyUrl, videoPosterUrl };
|