@feedmepos/mf-media 0.0.7 → 0.0.8

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.
@@ -0,0 +1,792 @@
1
+ import { defineComponent as j, computed as S, resolveComponent as B, openBlock as c, createElementBlock as y, createElementVNode as t, normalizeStyle as ee, createVNode as k, toDisplayString as d, unref as a, createCommentVNode as A, normalizeClass as V, createTextVNode as oe, createBlock as q, Fragment as M, renderList as O, mergeModels as H, useModel as G, renderSlot as ae, withCtx as te, ref as E, withDirectives as ne, vModelText as ie, onMounted as le } from "vue";
2
+ import { defineStore as re, storeToRefs as de } from "pinia";
3
+ import { useI18n as N, useCoreStore as ce } from "@feedmepos/mf-common";
4
+ import { useDialog as ue, useSnackbar as me } from "@feedmepos/ui-library";
5
+ import { z as W, p as fe, G as pe, K as ve } from "./media-picker-1af09b4a.js";
6
+ const xe = { class: "rounded-xl border border-fm-color-neutral-gray-200 bg-white overflow-hidden" }, ge = ["src", "alt"], ye = {
7
+ key: 1,
8
+ class: "absolute inset-0 flex flex-col items-center justify-center gap-4 p-12 text-center"
9
+ }, be = { class: "text-xs font-semibold" }, he = { class: "text-xs text-fm-color-typo-secondary line-clamp-3" }, _e = {
10
+ key: 2,
11
+ class: "absolute inset-0 flex items-center justify-center"
12
+ }, $e = { class: "flex flex-col items-center gap-8" }, ke = { class: "text-xs text-fm-color-typo-secondary" }, Ie = {
13
+ key: 3,
14
+ class: "absolute left-8 top-8 px-4 py-4 rounded text-xs font-bold bg-black/60 text-white"
15
+ }, we = {
16
+ key: 0,
17
+ class: "flex items-center gap-4 px-8 py-8"
18
+ }, Te = { class: "flex-1 text-xs text-fm-color-typo-secondary truncate" }, Ce = ["title"], Fe = ["title"], Se = ["title"], Re = {
19
+ key: 1,
20
+ class: "flex justify-end px-8 py-8"
21
+ }, Y = "w-32 h-32 rounded-md flex items-center justify-center text-fm-color-typo-secondary hover:bg-fm-color-neutral-gray-100", Be = /* @__PURE__ */ j({
22
+ __name: "StudioImageCard",
23
+ props: {
24
+ item: {},
25
+ ratio: {},
26
+ fromRef: { type: Boolean }
27
+ },
28
+ emits: ["preview", "variant", "discard", "save"],
29
+ setup(e, { emit: f }) {
30
+ const s = e, l = f, { t: r } = N(), m = S(() => s.item.status === "success" && !!s.item.url), p = S(() => s.item.status === "failed"), w = S(() => s.ratio.replace("x", " / ")), n = S(
31
+ () => s.item.width && s.item.height ? `${s.item.width}×${s.item.height}` : ""
32
+ );
33
+ return ($, g) => {
34
+ const C = B("FmIcon"), T = B("FmCircularProgress"), F = B("FmButton");
35
+ return c(), y("div", xe, [
36
+ t("div", {
37
+ class: "relative bg-fm-color-neutral-gray-100",
38
+ style: ee({ aspectRatio: w.value })
39
+ }, [
40
+ m.value ? (c(), y("img", {
41
+ key: 0,
42
+ src: e.item.url,
43
+ class: "w-full h-full object-cover",
44
+ alt: n.value
45
+ }, null, 8, ge)) : p.value ? (c(), y("div", ye, [
46
+ k(C, {
47
+ name: "error_outline",
48
+ size: "md"
49
+ }),
50
+ t("span", be, d(a(r)("media.studio.failed")), 1),
51
+ t("span", he, d(e.item.error), 1)
52
+ ])) : (c(), y("div", _e, [
53
+ t("div", $e, [
54
+ k(T, { size: "md" }),
55
+ t("span", ke, d(a(r)("media.studio.rendering")), 1)
56
+ ])
57
+ ])),
58
+ m.value ? (c(), y("span", Ie, d(e.fromRef ? a(r)("media.studio.refTag") : a(r)("media.studio.aiTag")), 1)) : A("", !0)
59
+ ], 4),
60
+ m.value ? (c(), y("div", we, [
61
+ t("span", Te, d(n.value), 1),
62
+ t("button", {
63
+ type: "button",
64
+ class: V(Y),
65
+ title: a(r)("media.studio.preview"),
66
+ onClick: g[0] || (g[0] = (u) => l("preview"))
67
+ }, [
68
+ k(C, {
69
+ name: "open_in_full",
70
+ size: "sm"
71
+ })
72
+ ], 8, Ce),
73
+ t("button", {
74
+ type: "button",
75
+ class: V(Y),
76
+ title: a(r)("media.studio.variant"),
77
+ onClick: g[1] || (g[1] = (u) => l("variant"))
78
+ }, [
79
+ k(C, {
80
+ name: "add_photo_alternate",
81
+ size: "sm"
82
+ })
83
+ ], 8, Fe),
84
+ t("button", {
85
+ type: "button",
86
+ class: V(Y),
87
+ title: a(r)("media.studio.discard"),
88
+ onClick: g[2] || (g[2] = (u) => l("discard"))
89
+ }, [
90
+ k(C, {
91
+ name: "delete",
92
+ size: "sm"
93
+ })
94
+ ], 8, Se),
95
+ k(F, {
96
+ label: e.item.saved ? a(r)("media.studio.saved") : a(r)("media.studio.save"),
97
+ variant: "primary",
98
+ size: "md",
99
+ disabled: e.item.saved,
100
+ onClick: g[3] || (g[3] = (u) => l("save"))
101
+ }, null, 8, ["label", "disabled"])
102
+ ])) : p.value ? (c(), y("div", Re, [
103
+ k(F, {
104
+ label: a(r)("media.studio.retry"),
105
+ variant: "tertiary",
106
+ size: "md",
107
+ onClick: g[4] || (g[4] = (u) => l("variant"))
108
+ }, null, 8, ["label"])
109
+ ])) : A("", !0)
110
+ ]);
111
+ };
112
+ }
113
+ }), ze = { class: "flex flex-col gap-12" }, Ee = { class: "flex items-center gap-12" }, Pe = { class: "flex-1 min-w-0 flex flex-col gap-4" }, Ue = { class: "text-sm font-semibold line-clamp-2" }, Ae = { class: "text-xs text-fm-color-typo-secondary" }, De = {
114
+ key: 0,
115
+ class: "flex items-center gap-4 text-xs font-semibold"
116
+ }, Me = { class: "grid gap-16 grid-cols-[repeat(auto-fill,minmax(min(240px,100%),1fr))]" }, Oe = /* @__PURE__ */ j({
117
+ __name: "StudioBatch",
118
+ props: {
119
+ batch: {}
120
+ },
121
+ emits: ["regenerate", "preview", "variant", "discard", "save"],
122
+ setup(e, { emit: f }) {
123
+ const s = e, l = f, { t: r } = N(), m = S(
124
+ () => s.batch.items.some((n) => n.status === "pending" || n.status === "processing")
125
+ ), p = S(
126
+ () => !!(s.batch.params.refAssetId || s.batch.params.refTmpToken)
127
+ ), w = S(() => {
128
+ const n = {
129
+ style: r(`media.studio.styles.${s.batch.params.style}`),
130
+ ratio: s.batch.params.ratio,
131
+ count: s.batch.items.length
132
+ };
133
+ return p.value ? r("media.studio.batchMetaRef", { ...n, strength: s.batch.params.refStrength ?? 55 }) : r("media.studio.batchMeta", n);
134
+ });
135
+ return (n, $) => {
136
+ const g = B("FmCircularProgress"), C = B("FmButton");
137
+ return c(), y("div", ze, [
138
+ t("div", Ee, [
139
+ t("div", Pe, [
140
+ t("span", Ue, d(e.batch.params.prompt), 1),
141
+ t("span", Ae, d(w.value), 1)
142
+ ]),
143
+ m.value ? (c(), y("span", De, [
144
+ k(g, { size: "md" }),
145
+ oe(" " + d(a(r)("media.studio.generating")), 1)
146
+ ])) : (c(), q(C, {
147
+ key: 1,
148
+ label: a(r)("media.studio.regenerate"),
149
+ variant: "tertiary",
150
+ size: "md",
151
+ "prepend-icon": "refresh",
152
+ onClick: $[0] || ($[0] = (T) => l("regenerate"))
153
+ }, null, 8, ["label"]))
154
+ ]),
155
+ t("div", Me, [
156
+ (c(!0), y(M, null, O(e.batch.items, (T) => (c(), q(Be, {
157
+ key: T.taskId,
158
+ item: T,
159
+ ratio: e.batch.params.ratio,
160
+ "from-ref": p.value,
161
+ onPreview: (F) => l("preview", T),
162
+ onVariant: $[1] || ($[1] = (F) => l("variant")),
163
+ onDiscard: (F) => l("discard", T),
164
+ onSave: (F) => l("save", T)
165
+ }, null, 8, ["item", "ratio", "from-ref", "onPreview", "onDiscard", "onSave"]))), 128))
166
+ ])
167
+ ]);
168
+ };
169
+ }
170
+ }), Ve = [
171
+ "none",
172
+ "photo",
173
+ "flatlay",
174
+ "studio",
175
+ "warm",
176
+ "illus"
177
+ ], je = ["1x1", "4x3", "3x4", "16x9"], Ne = [1, 2, 4];
178
+ function J(e) {
179
+ return `/media-v1/businesses/${e}/generations`;
180
+ }
181
+ async function Le(e, f) {
182
+ const { data: s } = await W().post(J(e), f);
183
+ return s;
184
+ }
185
+ async function Ge(e, f) {
186
+ const { data: s } = await W().get(
187
+ `${J(e)}/${f}`
188
+ );
189
+ return s;
190
+ }
191
+ async function qe(e, f) {
192
+ const { data: s } = await W().post(
193
+ `${J(e)}/ref-upload-intent`,
194
+ f
195
+ );
196
+ return s;
197
+ }
198
+ async function He(e, f) {
199
+ const s = await fetch(e.uploadUrl, {
200
+ method: e.method,
201
+ headers: { "Content-Type": f.type },
202
+ body: f
203
+ });
204
+ if (!s.ok)
205
+ throw new Error(`reference upload failed: ${s.status} ${await s.text()}`);
206
+ }
207
+ const Ke = { class: "w-[320px] max-h-screen overflow-auto flex flex-col gap-16 p-16 rounded-xl border border-fm-color-neutral-gray-200 bg-white sticky top-0 self-start" }, Ye = { class: "flex flex-col gap-8" }, We = { class: "flex items-baseline gap-8" }, Je = { class: "text-sm font-semibold" }, Qe = { class: "text-xs text-fm-color-typo-tertiary" }, Xe = { class: "grid grid-cols-2 gap-8" }, Ze = ["onClick"], et = { class: "flex items-center gap-8" }, tt = { class: "text-sm font-semibold" }, st = { class: "text-xs text-fm-color-typo-secondary" }, ot = { class: "flex flex-col gap-8" }, at = {
208
+ key: 0,
209
+ class: "flex items-center gap-8 px-8 py-8 rounded-lg bg-[#FFF7F0]"
210
+ }, nt = { class: "text-xs" }, it = { class: "flex flex-col gap-8" }, lt = { class: "text-sm font-semibold" }, rt = { class: "flex flex-wrap gap-4" }, dt = { class: "flex flex-col gap-8" }, ct = { class: "text-sm font-semibold" }, ut = { class: "grid grid-cols-2 gap-8" }, mt = ["onClick"], ft = { class: "text-fm-color-typo-secondary" }, pt = { class: "flex flex-col gap-8" }, vt = { class: "text-sm font-semibold" }, xt = { class: "flex gap-8" }, gt = ["onClick"], yt = { class: "flex flex-col gap-8 sticky bottom-0 bg-white pt-12" }, bt = { class: "text-xs text-fm-color-typo-tertiary text-center" }, ht = "border-[--fm-color-brand-primary,#FF7823] bg-[#FFF7F0]", _t = "border-fm-color-neutral-gray-200 bg-white", $t = /* @__PURE__ */ j({
211
+ __name: "StudioControls",
212
+ props: /* @__PURE__ */ H({
213
+ busy: { type: Boolean },
214
+ hasRef: { type: Boolean }
215
+ }, {
216
+ prompt: { required: !0 },
217
+ promptModifiers: {},
218
+ style: { required: !0 },
219
+ styleModifiers: {},
220
+ ratio: { required: !0 },
221
+ ratioModifiers: {},
222
+ count: { required: !0 },
223
+ countModifiers: {}
224
+ }),
225
+ emits: /* @__PURE__ */ H(["generate"], ["update:prompt", "update:style", "update:ratio", "update:count"]),
226
+ setup(e, { emit: f }) {
227
+ const s = e, l = G(e, "prompt"), r = G(e, "style"), m = G(e, "ratio"), p = G(e, "count"), w = f, { t: n } = N(), $ = ["hero", "banner", "social", "menu"], g = {
228
+ hero: "restaurant",
229
+ banner: "campaign",
230
+ social: "photo_camera",
231
+ menu: "menu_book"
232
+ }, C = S(
233
+ () => $.map((o) => ({
234
+ key: o,
235
+ icon: g[o],
236
+ name: n(`media.studio.tpl.${o}.name`),
237
+ desc: n(`media.studio.tpl.${o}.desc`),
238
+ prompt: n(`media.studio.tpl.${o}.prompt`)
239
+ }))
240
+ ), T = S(
241
+ () => {
242
+ var o;
243
+ return (o = C.value.find((v) => v.prompt === l.value)) == null ? void 0 : o.key;
244
+ }
245
+ ), F = S(() => /\[[^\]]+\]/.test(l.value)), u = S(() => l.value.trim().length > 0 && !s.busy);
246
+ function i(o) {
247
+ return o ? ht : _t;
248
+ }
249
+ return (o, v) => {
250
+ const _ = B("FmIcon"), R = B("FmTextarea"), K = B("FmChip"), z = B("FmButton");
251
+ return c(), y("div", Ke, [
252
+ t("div", Ye, [
253
+ t("div", We, [
254
+ t("span", Je, d(a(n)("media.studio.templates")), 1),
255
+ t("span", Qe, d(a(n)("media.studio.templatesHint")), 1)
256
+ ]),
257
+ t("div", Xe, [
258
+ (c(!0), y(M, null, O(C.value, (b) => (c(), y("button", {
259
+ key: b.key,
260
+ type: "button",
261
+ class: V(["flex flex-col items-start gap-4 p-12 rounded-lg border text-left", i(T.value === b.key)]),
262
+ onClick: (L) => l.value = b.prompt
263
+ }, [
264
+ t("span", et, [
265
+ k(_, {
266
+ name: b.icon,
267
+ size: "sm"
268
+ }, null, 8, ["name"]),
269
+ t("span", tt, d(b.name), 1)
270
+ ]),
271
+ t("span", st, d(b.desc), 1)
272
+ ], 10, Ze))), 128))
273
+ ])
274
+ ]),
275
+ t("div", ot, [
276
+ k(R, {
277
+ modelValue: l.value,
278
+ "onUpdate:modelValue": v[0] || (v[0] = (b) => l.value = b),
279
+ label: a(n)("media.studio.prompt"),
280
+ placeholder: e.hasRef ? a(n)("media.studio.promptPlaceholderRef") : a(n)("media.studio.promptPlaceholder"),
281
+ "max-length": 500,
282
+ "show-word-count": ""
283
+ }, null, 8, ["modelValue", "label", "placeholder"]),
284
+ F.value ? (c(), y("div", at, [
285
+ k(_, {
286
+ name: "info",
287
+ size: "sm"
288
+ }),
289
+ t("span", nt, d(a(n)("media.studio.slotHint")), 1)
290
+ ])) : A("", !0)
291
+ ]),
292
+ ae(o.$slots, "default"),
293
+ t("div", it, [
294
+ t("span", lt, d(a(n)("media.studio.style")), 1),
295
+ t("div", rt, [
296
+ (c(!0), y(M, null, O(a(Ve), (b) => (c(), q(K, {
297
+ key: b,
298
+ label: a(n)(`media.studio.styles.${b}`),
299
+ selected: r.value === b,
300
+ selectable: "",
301
+ compact: "",
302
+ onClick: (L) => r.value = b
303
+ }, null, 8, ["label", "selected", "onClick"]))), 128))
304
+ ])
305
+ ]),
306
+ t("div", dt, [
307
+ t("span", ct, d(a(n)("media.studio.ratio")), 1),
308
+ t("div", ut, [
309
+ (c(!0), y(M, null, O(a(je), (b) => (c(), y("button", {
310
+ key: b,
311
+ type: "button",
312
+ class: V(["flex items-center justify-center gap-4 h-40 rounded-lg border text-xs font-semibold", i(m.value === b)]),
313
+ onClick: (L) => m.value = b
314
+ }, [
315
+ t("span", null, d(b), 1),
316
+ t("span", ft, d(a(n)(`media.studio.ratios.${b}`)), 1)
317
+ ], 10, mt))), 128))
318
+ ])
319
+ ]),
320
+ t("div", pt, [
321
+ t("span", vt, d(a(n)("media.studio.count")), 1),
322
+ t("div", xt, [
323
+ (c(!0), y(M, null, O(a(Ne), (b) => (c(), y("button", {
324
+ key: b,
325
+ type: "button",
326
+ class: V(["flex-1 h-40 rounded-lg border text-sm font-semibold", i(p.value === b)]),
327
+ onClick: (L) => p.value = b
328
+ }, " × " + d(b), 11, gt))), 128))
329
+ ])
330
+ ]),
331
+ t("div", yt, [
332
+ k(z, {
333
+ label: e.busy ? a(n)("media.studio.generateBusy") : a(n)("media.studio.generate"),
334
+ "prepend-icon": "auto_awesome",
335
+ variant: "primary",
336
+ size: "md",
337
+ disabled: !u.value,
338
+ onClick: v[1] || (v[1] = (b) => w("generate"))
339
+ }, null, 8, ["label", "disabled"]),
340
+ t("span", bt, d(a(n)("media.studio.disclaimer")), 1)
341
+ ])
342
+ ]);
343
+ };
344
+ }
345
+ }), kt = {
346
+ key: 0,
347
+ class: "flex h-[560px]"
348
+ }, It = { class: "flex-1 min-w-0 flex items-center justify-center bg-black p-16" }, wt = ["src", "alt"], Tt = { class: "w-[300px] flex-shrink-0 flex flex-col gap-12 p-16 overflow-y-auto" }, Ct = { class: "flex items-start justify-between gap-8" }, Ft = { class: "fm-typo-en-title-sm-600" }, St = ["title"], Rt = { class: "text-sm font-semibold break-words" }, Bt = { class: "text-xs text-fm-color-typo-secondary" }, zt = /* @__PURE__ */ j({
349
+ __name: "StudioPreviewDialog",
350
+ props: {
351
+ item: {},
352
+ prompt: {}
353
+ },
354
+ emits: ["close", "save", "variant"],
355
+ setup(e, { emit: f }) {
356
+ const s = e, l = f, { t: r } = N();
357
+ return (m, p) => {
358
+ const w = B("FmIcon"), n = B("FmButton"), $ = B("FmDialog");
359
+ return c(), q($, {
360
+ "model-value": !!s.item,
361
+ "max-width": 920,
362
+ "max-height": "560px",
363
+ "content-class": "!p-0 studio-preview-dialog-content",
364
+ "close-button": !1,
365
+ "onUpdate:modelValue": p[3] || (p[3] = (g) => !g && l("close"))
366
+ }, {
367
+ default: te(() => [
368
+ s.item ? (c(), y("div", kt, [
369
+ t("div", It, [
370
+ t("img", {
371
+ src: s.item.url,
372
+ class: "max-w-full max-h-full object-contain",
373
+ alt: s.prompt
374
+ }, null, 8, wt)
375
+ ]),
376
+ t("div", Tt, [
377
+ t("div", Ct, [
378
+ t("span", Ft, d(a(r)("media.studio.preview")), 1),
379
+ t("button", {
380
+ type: "button",
381
+ class: "w-32 h-32 rounded-lg bg-fm-color-neutral-gray-100 flex items-center justify-center flex-shrink-0",
382
+ title: a(r)("media.library.cancelButton"),
383
+ onClick: p[0] || (p[0] = (g) => l("close"))
384
+ }, [
385
+ k(w, {
386
+ name: "close",
387
+ size: "sm"
388
+ })
389
+ ], 8, St)
390
+ ]),
391
+ t("span", Rt, d(s.prompt), 1),
392
+ t("span", Bt, d(s.item.width) + "×" + d(s.item.height), 1),
393
+ p[4] || (p[4] = t("div", { class: "flex-1" }, null, -1)),
394
+ k(n, {
395
+ label: a(r)("media.studio.variant"),
396
+ variant: "tertiary",
397
+ size: "md",
398
+ onClick: p[1] || (p[1] = (g) => l("variant"))
399
+ }, null, 8, ["label"]),
400
+ k(n, {
401
+ label: s.item.saved ? a(r)("media.studio.saved") : a(r)("media.studio.save"),
402
+ variant: "primary",
403
+ size: "md",
404
+ disabled: s.item.saved,
405
+ onClick: p[2] || (p[2] = (g) => l("save"))
406
+ }, null, 8, ["label", "disabled"])
407
+ ])
408
+ ])) : A("", !0)
409
+ ]),
410
+ _: 1
411
+ }, 8, ["model-value"]);
412
+ };
413
+ }
414
+ }), Et = { class: "flex flex-col gap-8" }, Pt = { class: "flex items-baseline gap-8" }, Ut = { class: "text-sm font-semibold" }, At = { class: "text-xs text-fm-color-typo-tertiary" }, Dt = {
415
+ key: 0,
416
+ class: "flex items-center gap-8 p-8 rounded-lg border border-fm-color-neutral-gray-200"
417
+ }, Mt = ["src"], Ot = { class: "flex-1 text-xs truncate" }, Vt = { class: "flex gap-8" }, jt = { class: "text-xs text-fm-color-typo-tertiary" }, Nt = {
418
+ key: 2,
419
+ class: "text-xs text-[--fm-color-typo-critical,#FF3B30]"
420
+ }, Lt = {
421
+ key: 3,
422
+ class: "flex flex-col gap-4"
423
+ }, Gt = { class: "flex items-baseline gap-8" }, qt = { class: "text-xs font-semibold" }, Ht = { class: "text-xs font-semibold" }, Kt = { class: "text-xs text-fm-color-typo-secondary" }, Yt = /* @__PURE__ */ j({
424
+ __name: "StudioRefPicker",
425
+ props: /* @__PURE__ */ H({
426
+ businessId: {},
427
+ restaurantId: {}
428
+ }, {
429
+ strength: { required: !0 },
430
+ strengthModifiers: {}
431
+ }),
432
+ emits: /* @__PURE__ */ H(["change"], ["update:strength"]),
433
+ setup(e, { emit: f }) {
434
+ const s = e, l = G(e, "strength"), r = f, { t: m } = N(), p = E(!1), w = E(!1), n = E(""), $ = E(null), g = E(null), C = S(() => l.value <= 35 ? m("media.studio.refWeak") : l.value >= 70 ? m("media.studio.refStrong") : m("media.studio.refMid"));
435
+ function T(i) {
436
+ p.value = !1, n.value = "", $.value = { url: i.url, label: i.asset.fileName }, r("change", {
437
+ refAssetId: i.asset.id,
438
+ // null means the original was picked, and the request omits refRatio for that.
439
+ refRatio: i.ratio ?? void 0,
440
+ label: i.asset.fileName
441
+ });
442
+ }
443
+ async function F(i) {
444
+ var v;
445
+ const o = (v = i.target.files) == null ? void 0 : v[0];
446
+ if (o) {
447
+ w.value = !0, n.value = "";
448
+ try {
449
+ const _ = await qe(s.businessId, {
450
+ contentType: o.type,
451
+ fileSize: o.size
452
+ });
453
+ await He(_, o), $.value = { url: URL.createObjectURL(o), label: o.name }, r("change", { refTmpToken: _.token, label: o.name });
454
+ } catch (_) {
455
+ n.value = _ instanceof Error ? _.message : String(_), $.value = null, r("change", null);
456
+ } finally {
457
+ w.value = !1, g.value && (g.value.value = "");
458
+ }
459
+ }
460
+ }
461
+ function u() {
462
+ $.value = null, n.value = "", r("change", null);
463
+ }
464
+ return (i, o) => {
465
+ const v = B("FmButton");
466
+ return c(), y("div", Et, [
467
+ t("div", Pt, [
468
+ t("span", Ut, d(a(m)("media.studio.ref")), 1),
469
+ t("span", At, d(a(m)("media.studio.refHint")), 1)
470
+ ]),
471
+ $.value ? (c(), y("div", Dt, [
472
+ $.value.url ? (c(), y("img", {
473
+ key: 0,
474
+ src: $.value.url,
475
+ class: "w-48 h-48 rounded object-cover",
476
+ alt: ""
477
+ }, null, 8, Mt)) : A("", !0),
478
+ t("span", Ot, d($.value.label), 1),
479
+ k(v, {
480
+ label: a(m)("media.studio.refClear"),
481
+ variant: "tertiary",
482
+ size: "md",
483
+ onClick: u
484
+ }, null, 8, ["label"])
485
+ ])) : (c(), y(M, { key: 1 }, [
486
+ t("div", Vt, [
487
+ k(v, {
488
+ label: a(m)("media.studio.refPick"),
489
+ variant: "tertiary",
490
+ size: "md",
491
+ class: "flex-1",
492
+ onClick: o[0] || (o[0] = (_) => p.value = !0)
493
+ }, null, 8, ["label"]),
494
+ k(v, {
495
+ label: a(m)("media.studio.refUpload"),
496
+ variant: "tertiary",
497
+ size: "md",
498
+ class: "flex-1",
499
+ disabled: w.value,
500
+ onClick: o[1] || (o[1] = (_) => {
501
+ var R;
502
+ return (R = g.value) == null ? void 0 : R.click();
503
+ })
504
+ }, null, 8, ["label", "disabled"]),
505
+ t("input", {
506
+ ref_key: "fileInput",
507
+ ref: g,
508
+ type: "file",
509
+ accept: "image/jpeg,image/png,image/webp",
510
+ class: "hidden",
511
+ onChange: F
512
+ }, null, 544)
513
+ ]),
514
+ t("span", jt, d(a(m)("media.studio.refUploadHint")), 1)
515
+ ], 64)),
516
+ n.value ? (c(), y("span", Nt, d(n.value), 1)) : A("", !0),
517
+ $.value ? (c(), y("div", Lt, [
518
+ t("div", Gt, [
519
+ t("span", qt, d(a(m)("media.studio.refStrength")), 1),
520
+ o[4] || (o[4] = t("span", { class: "flex-1" }, null, -1)),
521
+ t("span", Ht, d(l.value) + "%", 1)
522
+ ]),
523
+ ne(t("input", {
524
+ "onUpdate:modelValue": o[2] || (o[2] = (_) => l.value = _),
525
+ type: "range",
526
+ min: "10",
527
+ max: "90",
528
+ step: "5",
529
+ class: "w-full cursor-pointer accent-[--fm-color-brand-primary,#FF7823]"
530
+ }, null, 512), [
531
+ [
532
+ ie,
533
+ l.value,
534
+ void 0,
535
+ { number: !0 }
536
+ ]
537
+ ]),
538
+ t("span", Kt, d(C.value), 1)
539
+ ])) : A("", !0),
540
+ k(a(fe), {
541
+ open: p.value,
542
+ "onUpdate:open": o[3] || (o[3] = (_) => p.value = _),
543
+ "business-id": e.businessId,
544
+ "restaurant-id": e.restaurantId,
545
+ "allow-upload": !1,
546
+ onSelect: T
547
+ }, null, 8, ["open", "business-id", "restaurant-id"])
548
+ ]);
549
+ };
550
+ }
551
+ }), Wt = "ai", Jt = "ai-generated";
552
+ function Qt(e) {
553
+ return e === "success" || e === "failed";
554
+ }
555
+ function Z(e) {
556
+ return e.some((f) => !Qt(f.status));
557
+ }
558
+ function Xt(e, f) {
559
+ return e.map((s) => {
560
+ const l = f.find((r) => r.taskId === s.taskId);
561
+ return l ? { ...s, ...l, saved: s.saved } : s;
562
+ });
563
+ }
564
+ function Zt(e) {
565
+ const f = !!(e.refAssetId || e.refTmpToken);
566
+ return {
567
+ prompt: e.prompt.trim(),
568
+ style: e.style,
569
+ ratio: e.ratio,
570
+ count: e.count,
571
+ refAssetId: e.refAssetId,
572
+ refRatio: e.refRatio,
573
+ refTmpToken: e.refTmpToken,
574
+ refStrength: f ? e.refStrength : void 0,
575
+ restaurantId: e.restaurantId
576
+ };
577
+ }
578
+ const es = 3e3, ts = re("mediaGeneration", () => {
579
+ const e = E([]), f = S(() => e.value.some((u) => Z(u.items)));
580
+ let s, l = "";
581
+ function r(u, i) {
582
+ const o = e.value.find((v) => v.batchId === u);
583
+ o && (o.items = Xt(o.items, i));
584
+ }
585
+ function m() {
586
+ s !== void 0 || !l || (s = setTimeout(async () => {
587
+ s = void 0;
588
+ const u = e.value.filter((i) => Z(i.items));
589
+ for (const i of u)
590
+ try {
591
+ const o = await Ge(l, i.batchId);
592
+ r(i.batchId, o.items);
593
+ } catch {
594
+ }
595
+ f.value && m();
596
+ }, es));
597
+ }
598
+ async function p(u, i) {
599
+ l = u;
600
+ const o = await Le(u, Zt(i));
601
+ e.value.unshift({
602
+ batchId: o.batchId,
603
+ params: i,
604
+ items: o.items.map((v) => ({
605
+ taskId: v.taskId,
606
+ assetId: v.assetId,
607
+ imageId: v.imageId,
608
+ status: v.status,
609
+ attempts: 0,
610
+ error: v.error,
611
+ saved: !1
612
+ }))
613
+ }), m();
614
+ }
615
+ async function w(u, i) {
616
+ await p(u, i);
617
+ }
618
+ async function n(u, i) {
619
+ await p(u, { ...i.params });
620
+ }
621
+ async function $(u, i) {
622
+ await p(u, { ...i.params, count: 1 });
623
+ }
624
+ async function g(u, i, o) {
625
+ var _;
626
+ await pe(u, o.assetId, [Jt]);
627
+ const v = (_ = e.value.find((R) => R.batchId === i.batchId)) == null ? void 0 : _.items.find((R) => R.taskId === o.taskId);
628
+ v && (v.saved = !0);
629
+ }
630
+ async function C(u, i, o) {
631
+ await ve(u, [
632
+ {
633
+ refType: Wt,
634
+ refId: i.batchId,
635
+ imageId: o.imageId,
636
+ aspectRatios: null
637
+ }
638
+ ]);
639
+ const v = e.value.find((_) => _.batchId === i.batchId);
640
+ v && (v.items = v.items.filter((_) => _.taskId !== o.taskId), v.items.length === 0 && (e.value = e.value.filter((_) => _.batchId !== i.batchId)));
641
+ }
642
+ function T(u) {
643
+ l = u, f.value && m();
644
+ }
645
+ function F() {
646
+ s !== void 0 && clearTimeout(s), s = void 0, e.value = [];
647
+ }
648
+ return { batches: e, busy: f, compose: w, regenerate: n, variantOf: $, save: g, discard: C, resume: T, reset: F };
649
+ }), ss = { class: "flex items-start gap-24 p-24" }, os = { class: "flex-1 min-w-0 flex flex-col gap-24" }, as = {
650
+ key: 0,
651
+ class: "min-h-[340px] flex flex-col items-center justify-center gap-12 border-2 border-dashed border-fm-color-neutral-gray-300 rounded-2xl"
652
+ }, ns = { class: "text-lg font-semibold" }, is = { class: "text-sm text-fm-color-typo-secondary" }, ms = /* @__PURE__ */ j({
653
+ __name: "AiStudio",
654
+ setup(e) {
655
+ const f = ce(), { t: s } = N(), l = ue(), r = me(), m = S(() => {
656
+ var h;
657
+ return ((h = f.currentBusiness.value) == null ? void 0 : h.id) ?? "";
658
+ }), p = S(() => {
659
+ var h;
660
+ return (h = f.currentRestaurant.value) == null ? void 0 : h._id;
661
+ }), w = ts(), { batches: n, busy: $ } = de(w);
662
+ le(() => w.resume(m.value));
663
+ const g = E(""), C = E("photo"), T = E("1x1"), F = E(2), u = E(55), i = E(null), o = S(() => !!i.value);
664
+ function v() {
665
+ var h, x, P, U;
666
+ return {
667
+ prompt: g.value,
668
+ style: C.value,
669
+ ratio: T.value,
670
+ count: F.value,
671
+ refAssetId: (h = i.value) == null ? void 0 : h.refAssetId,
672
+ refRatio: (x = i.value) == null ? void 0 : x.refRatio,
673
+ refTmpToken: (P = i.value) == null ? void 0 : P.refTmpToken,
674
+ refStrength: i.value ? u.value : void 0,
675
+ refLabel: (U = i.value) == null ? void 0 : U.label,
676
+ restaurantId: p.value
677
+ };
678
+ }
679
+ function _(h) {
680
+ var P, U;
681
+ return ((U = (P = h == null ? void 0 : h.response) == null ? void 0 : P.data) == null ? void 0 : U.message) ?? (h instanceof Error ? h.message : String(h));
682
+ }
683
+ function R(h) {
684
+ r.open({ type: "error", title: _(h) });
685
+ }
686
+ async function K() {
687
+ try {
688
+ await w.compose(m.value, v());
689
+ } catch (h) {
690
+ R(h);
691
+ }
692
+ }
693
+ const z = E(null);
694
+ async function b(h, x) {
695
+ try {
696
+ await w.save(m.value, h, x), r.open({ type: "success", title: s("media.studio.savedToast") });
697
+ } catch (P) {
698
+ R(P);
699
+ }
700
+ }
701
+ function L(h, x) {
702
+ l.open({
703
+ title: s("media.studio.discardTitle"),
704
+ message: s("media.studio.discardMessage"),
705
+ primaryActions: { text: s("media.studio.discard"), close: !1, variant: "destructive" },
706
+ secondaryActions: { text: s("media.library.cancelButton"), close: !0 }
707
+ }).onPrimary(async () => {
708
+ var P;
709
+ try {
710
+ await w.discard(m.value, h, x), ((P = z.value) == null ? void 0 : P.item.taskId) === x.taskId && (z.value = null), r.open({ type: "success", title: s("media.studio.discardedToast") });
711
+ } catch (U) {
712
+ R(U);
713
+ }
714
+ l.close();
715
+ });
716
+ }
717
+ async function Q(h) {
718
+ try {
719
+ await w.variantOf(m.value, h);
720
+ } catch (x) {
721
+ R(x);
722
+ }
723
+ }
724
+ async function se(h) {
725
+ try {
726
+ await w.regenerate(m.value, h);
727
+ } catch (x) {
728
+ R(x);
729
+ }
730
+ }
731
+ return (h, x) => {
732
+ var U, X;
733
+ const P = B("FmIcon");
734
+ return c(), y("div", ss, [
735
+ k($t, {
736
+ prompt: g.value,
737
+ "onUpdate:prompt": x[2] || (x[2] = (I) => g.value = I),
738
+ style: ee(C.value),
739
+ "onUpdate:style": x[3] || (x[3] = (I) => C.value = I),
740
+ ratio: T.value,
741
+ "onUpdate:ratio": x[4] || (x[4] = (I) => T.value = I),
742
+ count: F.value,
743
+ "onUpdate:count": x[5] || (x[5] = (I) => F.value = I),
744
+ class: "flex-shrink-0",
745
+ busy: a($),
746
+ "has-ref": o.value,
747
+ onGenerate: K
748
+ }, {
749
+ default: te(() => [
750
+ k(Yt, {
751
+ strength: u.value,
752
+ "onUpdate:strength": x[0] || (x[0] = (I) => u.value = I),
753
+ "business-id": m.value,
754
+ "restaurant-id": p.value,
755
+ onChange: x[1] || (x[1] = (I) => i.value = I)
756
+ }, null, 8, ["strength", "business-id", "restaurant-id"])
757
+ ]),
758
+ _: 1
759
+ }, 8, ["prompt", "style", "ratio", "count", "busy", "has-ref"]),
760
+ t("div", os, [
761
+ a(n).length === 0 ? (c(), y("div", as, [
762
+ k(P, {
763
+ name: "auto_awesome",
764
+ size: "xl"
765
+ }),
766
+ t("span", ns, d(a(s)("media.studio.emptyTitle")), 1),
767
+ t("span", is, d(a(s)("media.studio.emptyHint")), 1)
768
+ ])) : A("", !0),
769
+ (c(!0), y(M, null, O(a(n), (I) => (c(), q(Oe, {
770
+ key: I.batchId,
771
+ batch: I,
772
+ onRegenerate: (D) => se(I),
773
+ onVariant: (D) => Q(I),
774
+ onPreview: (D) => z.value = { batch: I, item: D },
775
+ onDiscard: (D) => L(I, D),
776
+ onSave: (D) => b(I, D)
777
+ }, null, 8, ["batch", "onRegenerate", "onVariant", "onPreview", "onDiscard", "onSave"]))), 128))
778
+ ]),
779
+ k(zt, {
780
+ item: ((U = z.value) == null ? void 0 : U.item) ?? null,
781
+ prompt: ((X = z.value) == null ? void 0 : X.batch.params.prompt) ?? "",
782
+ onClose: x[6] || (x[6] = (I) => z.value = null),
783
+ onSave: x[7] || (x[7] = (I) => z.value && b(z.value.batch, z.value.item)),
784
+ onVariant: x[8] || (x[8] = (I) => z.value && Q(z.value.batch))
785
+ }, null, 8, ["item", "prompt"])
786
+ ]);
787
+ };
788
+ }
789
+ });
790
+ export {
791
+ ms as default
792
+ };