@medialane/ui 0.141.1 → 0.142.0
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/components/asset-card.cjs +1 -1
- package/dist/components/asset-card.cjs.map +1 -1
- package/dist/components/asset-card.js +1 -1
- package/dist/components/asset-card.js.map +1 -1
- package/dist/components/collection-card.cjs +1 -1
- package/dist/components/collection-card.cjs.map +1 -1
- package/dist/components/collection-card.js +1 -1
- package/dist/components/collection-card.js.map +1 -1
- package/dist/components/fast-mint/dropzone.cjs +120 -0
- package/dist/components/fast-mint/dropzone.cjs.map +1 -0
- package/dist/components/fast-mint/dropzone.d.cts +17 -0
- package/dist/components/fast-mint/dropzone.d.ts +17 -0
- package/dist/components/fast-mint/dropzone.js +96 -0
- package/dist/components/fast-mint/dropzone.js.map +1 -0
- package/dist/components/fast-mint/fast-mint.cjs +887 -0
- package/dist/components/fast-mint/fast-mint.cjs.map +1 -0
- package/dist/components/fast-mint/fast-mint.d.cts +10 -0
- package/dist/components/fast-mint/fast-mint.d.ts +10 -0
- package/dist/components/fast-mint/fast-mint.js +873 -0
- package/dist/components/fast-mint/fast-mint.js.map +1 -0
- package/dist/components/fast-mint/success-view.cjs +113 -0
- package/dist/components/fast-mint/success-view.cjs.map +1 -0
- package/dist/components/fast-mint/success-view.d.cts +17 -0
- package/dist/components/fast-mint/success-view.d.ts +17 -0
- package/dist/components/fast-mint/success-view.js +79 -0
- package/dist/components/fast-mint/success-view.js.map +1 -0
- package/dist/components/listing-card.cjs +1 -1
- package/dist/components/listing-card.cjs.map +1 -1
- package/dist/components/listing-card.js +1 -1
- package/dist/components/listing-card.js.map +1 -1
- package/dist/components/token-card.cjs +1 -1
- package/dist/components/token-card.cjs.map +1 -1
- package/dist/components/token-card.js +1 -1
- package/dist/components/token-card.js.map +1 -1
- package/dist/data/drop-create-schema.d.cts +2 -2
- package/dist/data/drop-create-schema.d.ts +2 -2
- package/dist/index.cjs +18 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -1
- package/dist/types-7TZuHZVP.d.cts +35 -0
- package/dist/types-7TZuHZVP.d.ts +35 -0
- package/dist/utils/ipfs-upload.cjs +87 -0
- package/dist/utils/ipfs-upload.cjs.map +1 -0
- package/dist/utils/ipfs-upload.d.cts +13 -0
- package/dist/utils/ipfs-upload.d.ts +13 -0
- package/dist/utils/ipfs-upload.js +60 -0
- package/dist/utils/ipfs-upload.js.map +1 -0
- package/dist/utils/ipfs.cjs +11 -3
- package/dist/utils/ipfs.cjs.map +1 -1
- package/dist/utils/ipfs.d.cts +4 -1
- package/dist/utils/ipfs.d.ts +4 -1
- package/dist/utils/ipfs.js +11 -3
- package/dist/utils/ipfs.js.map +1 -1
- package/package.json +5 -3
|
@@ -0,0 +1,887 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
var fast_mint_exports = {};
|
|
31
|
+
__export(fast_mint_exports, {
|
|
32
|
+
FastMint: () => FastMint
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(fast_mint_exports);
|
|
35
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
36
|
+
var import_react = require("react");
|
|
37
|
+
var import_image = __toESM(require("next/image"), 1);
|
|
38
|
+
var import_react_hook_form = require("react-hook-form");
|
|
39
|
+
var import_starknet = require("starknet");
|
|
40
|
+
var import_sdk = require("@medialane/sdk");
|
|
41
|
+
var import_starknet2 = require("@medialane/sdk/starknet");
|
|
42
|
+
var import_lucide_react = require("lucide-react");
|
|
43
|
+
var import_input = require("../input.js");
|
|
44
|
+
var import_textarea = require("../textarea.js");
|
|
45
|
+
var import_select = require("../select.js");
|
|
46
|
+
var import_collapsible = require("../collapsible.js");
|
|
47
|
+
var import_popover = require("../popover.js");
|
|
48
|
+
var import_medialane_collection_card = require("../medialane-collection-card.js");
|
|
49
|
+
var import_action_dialog = require("../action-dialog.js");
|
|
50
|
+
var import_ip_type_fields = require("../ip-type-fields.js");
|
|
51
|
+
var import_ip = require("../../data/ip.js");
|
|
52
|
+
var import_launchpad_defaults = require("../../utils/launchpad-defaults.js");
|
|
53
|
+
var import_ipfs_upload = require("../../utils/ipfs-upload.js");
|
|
54
|
+
var import_ipfs = require("../../utils/ipfs.js");
|
|
55
|
+
var import_cn = require("../../utils/cn.js");
|
|
56
|
+
var import_dropzone = require("./dropzone.js");
|
|
57
|
+
var import_success_view = require("./success-view.js");
|
|
58
|
+
const COLLECTION_DEPLOYED_SELECTOR = import_starknet.hash.getSelectorFromName("CollectionDeployed");
|
|
59
|
+
const IP_MINTED_SELECTOR = import_starknet.hash.getSelectorFromName("IPMinted");
|
|
60
|
+
async function readMintedTokenId(provider, txHash, contractAddress) {
|
|
61
|
+
let receipt = null;
|
|
62
|
+
for (let attempt = 0; attempt < 3 && !receipt; attempt++) {
|
|
63
|
+
try {
|
|
64
|
+
if (attempt > 0) await new Promise((r) => setTimeout(r, 2e3));
|
|
65
|
+
const raw = await provider.getTransactionReceipt(txHash);
|
|
66
|
+
receipt = raw;
|
|
67
|
+
} catch {
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const events = receipt?.events ?? [];
|
|
71
|
+
const mintEvent = events.find(
|
|
72
|
+
(e) => e.from_address && BigInt(e.from_address) === BigInt(contractAddress) && e.keys?.[0] && BigInt(e.keys[0]) === BigInt(IP_MINTED_SELECTOR)
|
|
73
|
+
);
|
|
74
|
+
if (!mintEvent?.keys?.[1]) return null;
|
|
75
|
+
const low = BigInt(mintEvent.keys[1] ?? 0);
|
|
76
|
+
const high = BigInt(mintEvent.keys[2] ?? 0);
|
|
77
|
+
return (low + (high << 128n)).toString();
|
|
78
|
+
}
|
|
79
|
+
const MEDIA_ROUTE_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
80
|
+
"image/jpeg",
|
|
81
|
+
"image/png",
|
|
82
|
+
"image/gif",
|
|
83
|
+
"image/webp",
|
|
84
|
+
"image/svg+xml",
|
|
85
|
+
"image/avif",
|
|
86
|
+
"video/mp4",
|
|
87
|
+
"video/webm",
|
|
88
|
+
"video/ogg",
|
|
89
|
+
"audio/mpeg",
|
|
90
|
+
"audio/ogg",
|
|
91
|
+
"audio/wav",
|
|
92
|
+
"audio/webm",
|
|
93
|
+
"audio/flac",
|
|
94
|
+
"application/pdf"
|
|
95
|
+
]);
|
|
96
|
+
const DOCUMENT_SIGNED_URL_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
97
|
+
"application/msword",
|
|
98
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
99
|
+
"application/vnd.oasis.opendocument.text",
|
|
100
|
+
"application/rtf",
|
|
101
|
+
"text/plain",
|
|
102
|
+
"text/markdown"
|
|
103
|
+
]);
|
|
104
|
+
const MEDIA_MAX_BYTES = 100 * 1024 * 1024;
|
|
105
|
+
const DOCUMENT_MAX_BYTES = 20 * 1024 * 1024;
|
|
106
|
+
function detectMediaKind(mime) {
|
|
107
|
+
if (mime.startsWith("image/")) return MEDIA_ROUTE_MIME_TYPES.has(mime) ? "image" : null;
|
|
108
|
+
if (mime.startsWith("video/")) return MEDIA_ROUTE_MIME_TYPES.has(mime) ? "video" : null;
|
|
109
|
+
if (mime.startsWith("audio/")) return MEDIA_ROUTE_MIME_TYPES.has(mime) ? "audio" : null;
|
|
110
|
+
if (mime === "application/pdf" || DOCUMENT_SIGNED_URL_MIME_TYPES.has(mime)) return "document";
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const IP_TYPE_BY_KIND = {
|
|
114
|
+
image: "NFT",
|
|
115
|
+
audio: "Audio",
|
|
116
|
+
video: "Video",
|
|
117
|
+
document: "Documents"
|
|
118
|
+
};
|
|
119
|
+
const MEDIA_KIND_ICON = {
|
|
120
|
+
image: import_lucide_react.ImagePlus,
|
|
121
|
+
audio: import_lucide_react.Music,
|
|
122
|
+
video: import_lucide_react.Video,
|
|
123
|
+
document: import_lucide_react.FileText
|
|
124
|
+
};
|
|
125
|
+
function ToggleGroup({
|
|
126
|
+
value,
|
|
127
|
+
options,
|
|
128
|
+
onChange
|
|
129
|
+
}) {
|
|
130
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex rounded-lg border border-border overflow-hidden w-full", children: options.map((opt, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
131
|
+
"button",
|
|
132
|
+
{
|
|
133
|
+
type: "button",
|
|
134
|
+
onClick: () => onChange(opt),
|
|
135
|
+
className: (0, import_cn.cn)(
|
|
136
|
+
"flex-1 px-3 py-2 text-sm transition-colors",
|
|
137
|
+
i > 0 && "border-l border-border",
|
|
138
|
+
value === opt ? "bg-primary text-primary-foreground font-medium" : "bg-background hover:bg-muted text-muted-foreground"
|
|
139
|
+
),
|
|
140
|
+
children: opt
|
|
141
|
+
},
|
|
142
|
+
opt
|
|
143
|
+
)) });
|
|
144
|
+
}
|
|
145
|
+
function collectionDisplayLabel(col) {
|
|
146
|
+
return col.name || col.symbol || `Collection #${col.collectionId}`;
|
|
147
|
+
}
|
|
148
|
+
function CollectionThumb({ image }) {
|
|
149
|
+
const imageUrl = image ? (0, import_ipfs.ipfsToHttp)(image) : null;
|
|
150
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "relative h-10 w-10 rounded-lg overflow-hidden bg-muted shrink-0", children: imageUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_image.default, { src: imageUrl, alt: "", fill: true, className: "object-cover", unoptimized: true }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Boxes, { className: "h-4 w-4 text-muted-foreground/40" }) }) });
|
|
151
|
+
}
|
|
152
|
+
function CollectionPicker({
|
|
153
|
+
collections,
|
|
154
|
+
value,
|
|
155
|
+
onChange
|
|
156
|
+
}) {
|
|
157
|
+
const [open, setOpen] = (0, import_react.useState)(false);
|
|
158
|
+
const selected = collections.find((c) => c.collectionId === value) ?? null;
|
|
159
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_popover.Popover, { open, onOpenChange: setOpen, children: [
|
|
160
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_popover.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
161
|
+
"button",
|
|
162
|
+
{
|
|
163
|
+
type: "button",
|
|
164
|
+
"aria-expanded": open,
|
|
165
|
+
className: "flex w-full items-center gap-3 rounded-xl border border-border p-3 text-left transition-colors hover:bg-muted/40",
|
|
166
|
+
children: [
|
|
167
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CollectionThumb, { image: selected?.image }),
|
|
168
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "min-w-0 flex-1", children: [
|
|
169
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm font-semibold truncate", children: selected ? collectionDisplayLabel(selected) : collections.length ? "Choose a collection" : "No collections yet" }),
|
|
170
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-xs text-muted-foreground", children: selected ? `${selected.totalSupply ?? 0} work${selected.totalSupply === 1 ? "" : "s"}` : "Where this work will live" })
|
|
171
|
+
] }),
|
|
172
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground shrink-0" })
|
|
173
|
+
]
|
|
174
|
+
}
|
|
175
|
+
) }),
|
|
176
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_popover.PopoverContent, { className: "w-[var(--radix-popover-trigger-width)] p-0", align: "start", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "max-h-64 overflow-y-auto p-1", children: collections.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "No collections yet \u2014 create one instead." }) : collections.map((col) => {
|
|
177
|
+
const isSelected = value === col.collectionId;
|
|
178
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
179
|
+
"button",
|
|
180
|
+
{
|
|
181
|
+
type: "button",
|
|
182
|
+
onClick: () => {
|
|
183
|
+
onChange(col.collectionId);
|
|
184
|
+
setOpen(false);
|
|
185
|
+
},
|
|
186
|
+
className: "flex w-full items-center gap-2.5 rounded-lg px-2 py-2 text-left transition-colors hover:bg-muted/60",
|
|
187
|
+
children: [
|
|
188
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CollectionThumb, { image: col.image }),
|
|
189
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "min-w-0 flex-1", children: [
|
|
190
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm font-medium truncate", children: collectionDisplayLabel(col) }),
|
|
191
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "text-xs text-muted-foreground", children: [
|
|
192
|
+
col.totalSupply ?? 0,
|
|
193
|
+
" work",
|
|
194
|
+
col.totalSupply === 1 ? "" : "s"
|
|
195
|
+
] })
|
|
196
|
+
] }),
|
|
197
|
+
isSelected && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Check, { className: "h-4 w-4 text-brand-blue shrink-0" })
|
|
198
|
+
]
|
|
199
|
+
},
|
|
200
|
+
col.collectionId
|
|
201
|
+
);
|
|
202
|
+
}) }) })
|
|
203
|
+
] });
|
|
204
|
+
}
|
|
205
|
+
function FastMint(props) {
|
|
206
|
+
const {
|
|
207
|
+
presentation = "inline",
|
|
208
|
+
open = true,
|
|
209
|
+
onClose,
|
|
210
|
+
mediaKindLock,
|
|
211
|
+
onMinted,
|
|
212
|
+
collections,
|
|
213
|
+
refetchCollections,
|
|
214
|
+
hasWallet,
|
|
215
|
+
walletAddress,
|
|
216
|
+
onRequireWallet,
|
|
217
|
+
getUploadToken,
|
|
218
|
+
getSigner,
|
|
219
|
+
client,
|
|
220
|
+
provider
|
|
221
|
+
} = props;
|
|
222
|
+
const [status, setStatus] = (0, import_react.useState)("idle");
|
|
223
|
+
const [errorMsg, setErrorMsg] = (0, import_react.useState)(null);
|
|
224
|
+
const [mediaFile, setMediaFile] = (0, import_react.useState)(null);
|
|
225
|
+
const [mediaPreview, setMediaPreview] = (0, import_react.useState)(null);
|
|
226
|
+
const [mediaUri, setMediaUri] = (0, import_react.useState)(null);
|
|
227
|
+
const [mediaKind, setMediaKind] = (0, import_react.useState)("image");
|
|
228
|
+
const [mediaUploading, setMediaUploading] = (0, import_react.useState)(false);
|
|
229
|
+
const previewUrlRef = (0, import_react.useRef)(null);
|
|
230
|
+
const mediaInputRef = (0, import_react.useRef)(null);
|
|
231
|
+
const [featurePreview, setFeaturePreview] = (0, import_react.useState)(null);
|
|
232
|
+
const [featureUri, setFeatureUri] = (0, import_react.useState)(null);
|
|
233
|
+
const [featureUploading, setFeatureUploading] = (0, import_react.useState)(false);
|
|
234
|
+
const featurePreviewRef = (0, import_react.useRef)(null);
|
|
235
|
+
const featureInputRef = (0, import_react.useRef)(null);
|
|
236
|
+
const [assetType, setAssetType] = (0, import_react.useState)("single");
|
|
237
|
+
const [editionCount, setEditionCount] = (0, import_react.useState)("10");
|
|
238
|
+
const [collectionMode, setCollectionMode] = (0, import_react.useState)("existing");
|
|
239
|
+
const [existingCollectionId, setExistingCollectionId] = (0, import_react.useState)("");
|
|
240
|
+
const [existingCollectionContract, setExistingCollectionContract] = (0, import_react.useState)("");
|
|
241
|
+
const [newCollectionName, setNewCollectionName] = (0, import_react.useState)("");
|
|
242
|
+
const [newCollectionSymbol, setNewCollectionSymbol] = (0, import_react.useState)("");
|
|
243
|
+
const [autoSymbol, setAutoSymbol] = (0, import_react.useState)("");
|
|
244
|
+
const [autoCollectionName, setAutoCollectionName] = (0, import_react.useState)("");
|
|
245
|
+
const [ipType, setIpType] = (0, import_react.useState)("NFT");
|
|
246
|
+
const [advancedOpen, setAdvancedOpen] = (0, import_react.useState)(false);
|
|
247
|
+
const [ipTypeOpen, setIpTypeOpen] = (0, import_react.useState)(false);
|
|
248
|
+
const templateFieldsRef = (0, import_react.useRef)([]);
|
|
249
|
+
const [mintedAsset, setMintedAsset] = (0, import_react.useState)(null);
|
|
250
|
+
(0, import_react.useEffect)(() => () => {
|
|
251
|
+
if (previewUrlRef.current) URL.revokeObjectURL(previewUrlRef.current);
|
|
252
|
+
if (featurePreviewRef.current) URL.revokeObjectURL(featurePreviewRef.current);
|
|
253
|
+
}, []);
|
|
254
|
+
const form = (0, import_react_hook_form.useForm)({
|
|
255
|
+
defaultValues: {
|
|
256
|
+
name: "",
|
|
257
|
+
description: "",
|
|
258
|
+
external_url: "",
|
|
259
|
+
licenseType: "CC BY-SA",
|
|
260
|
+
commercialUse: "Yes",
|
|
261
|
+
derivatives: "Share-Alike",
|
|
262
|
+
attribution: "Required",
|
|
263
|
+
geographicScope: "Worldwide",
|
|
264
|
+
aiPolicy: "Not Allowed",
|
|
265
|
+
royalty: 0
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
const name = form.watch("name");
|
|
269
|
+
(0, import_react.useEffect)(() => {
|
|
270
|
+
const s = (0, import_launchpad_defaults.suggestLaunchpadSymbol)(name);
|
|
271
|
+
if (!s) return;
|
|
272
|
+
if (!newCollectionSymbol || newCollectionSymbol === autoSymbol) {
|
|
273
|
+
setNewCollectionSymbol(s);
|
|
274
|
+
setAutoSymbol(s);
|
|
275
|
+
}
|
|
276
|
+
if (!newCollectionName || newCollectionName === autoCollectionName) {
|
|
277
|
+
setNewCollectionName(name);
|
|
278
|
+
setAutoCollectionName(name);
|
|
279
|
+
}
|
|
280
|
+
}, [name, autoSymbol, autoCollectionName, newCollectionSymbol, newCollectionName]);
|
|
281
|
+
const erc721Collections = collections.filter((c) => (0, import_sdk.getService)(c.service)?.id === "mip-erc721");
|
|
282
|
+
const erc1155Collections = collections.filter((c) => c.standard === "ERC1155");
|
|
283
|
+
const handleMediaSelect = async (file) => {
|
|
284
|
+
const kind = detectMediaKind(file.type);
|
|
285
|
+
if (!kind) {
|
|
286
|
+
setErrorMsg("Publish an image, audio, video (JPG/PNG/GIF/SVG/WebP, MP3/WAV/OGG/FLAC, MP4/WebM), or document (PDF, DOC, DOCX, ODT, RTF, TXT, MD).");
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
if (mediaKindLock && kind !== mediaKindLock) {
|
|
290
|
+
setErrorMsg(`Please upload a${mediaKindLock === "image" ? "n" : ""} ${mediaKindLock}.`);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
const viaMediaRoute = MEDIA_ROUTE_MIME_TYPES.has(file.type);
|
|
294
|
+
const maxBytes = viaMediaRoute ? MEDIA_MAX_BYTES : DOCUMENT_MAX_BYTES;
|
|
295
|
+
if (file.size > maxBytes) {
|
|
296
|
+
setErrorMsg(`Maximum size is ${maxBytes / (1024 * 1024)} MB.`);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
setMediaFile(file);
|
|
300
|
+
setMediaKind(kind);
|
|
301
|
+
setIpType(IP_TYPE_BY_KIND[kind]);
|
|
302
|
+
if (previewUrlRef.current) URL.revokeObjectURL(previewUrlRef.current);
|
|
303
|
+
const objectUrl = URL.createObjectURL(file);
|
|
304
|
+
previewUrlRef.current = objectUrl;
|
|
305
|
+
setMediaPreview(objectUrl);
|
|
306
|
+
setMediaUri(null);
|
|
307
|
+
setMediaUploading(true);
|
|
308
|
+
try {
|
|
309
|
+
const token = await getUploadToken();
|
|
310
|
+
if (!token) throw new Error("Sign in first");
|
|
311
|
+
const { uri } = await (0, import_ipfs_upload.uploadFileToIpfs)(file, token, viaMediaRoute ? "media" : "document");
|
|
312
|
+
setMediaUri(uri);
|
|
313
|
+
} catch (err) {
|
|
314
|
+
const t = (0, import_ipfs_upload.uploadFailureToast)(err);
|
|
315
|
+
setErrorMsg(t.description ?? t.title);
|
|
316
|
+
} finally {
|
|
317
|
+
setMediaUploading(false);
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
const clearMedia = () => {
|
|
321
|
+
setMediaFile(null);
|
|
322
|
+
setMediaPreview(null);
|
|
323
|
+
setMediaUri(null);
|
|
324
|
+
if (mediaInputRef.current) mediaInputRef.current.value = "";
|
|
325
|
+
};
|
|
326
|
+
const handleFeatureSelect = async (file) => {
|
|
327
|
+
if (featurePreviewRef.current) URL.revokeObjectURL(featurePreviewRef.current);
|
|
328
|
+
const objectUrl = URL.createObjectURL(file);
|
|
329
|
+
featurePreviewRef.current = objectUrl;
|
|
330
|
+
setFeaturePreview(objectUrl);
|
|
331
|
+
setFeatureUri(null);
|
|
332
|
+
setFeatureUploading(true);
|
|
333
|
+
try {
|
|
334
|
+
const token = await getUploadToken();
|
|
335
|
+
if (!token) throw new Error("Sign in first");
|
|
336
|
+
const { uri } = await (0, import_ipfs_upload.uploadFileToIpfs)(file, token, "image");
|
|
337
|
+
setFeatureUri(uri);
|
|
338
|
+
} catch (err) {
|
|
339
|
+
const t = (0, import_ipfs_upload.uploadFailureToast)(err);
|
|
340
|
+
setErrorMsg(t.description ?? t.title);
|
|
341
|
+
} finally {
|
|
342
|
+
setFeatureUploading(false);
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
const handleLicenseChange = (value) => {
|
|
346
|
+
form.setValue("licenseType", value);
|
|
347
|
+
const def = import_ip.LICENSE_TYPES.find((l) => l.value === value);
|
|
348
|
+
if (def) {
|
|
349
|
+
form.setValue("commercialUse", def.commercialUse);
|
|
350
|
+
form.setValue("derivatives", def.derivatives);
|
|
351
|
+
form.setValue("attribution", def.attribution);
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
const ready = !!mediaUri && !mediaUploading && name.trim().length > 0 && (mediaKind === "image" || !!featureUri) && (collectionMode === "existing" ? assetType === "single" ? !!existingCollectionId : !!existingCollectionContract : newCollectionName.trim().length > 0 && newCollectionSymbol.trim().length > 0);
|
|
355
|
+
async function pollForNewCollection(name2, symbol) {
|
|
356
|
+
for (let attempt = 0; attempt < 8; attempt++) {
|
|
357
|
+
const list = await refetchCollections();
|
|
358
|
+
const match = list.find((c) => c.name === name2 && c.symbol === symbol);
|
|
359
|
+
if (match?.collectionId) return match;
|
|
360
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
361
|
+
}
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
const onSubmit = async (values) => {
|
|
365
|
+
if (!hasWallet) {
|
|
366
|
+
onRequireWallet();
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
if (!walletAddress || !mediaUri) return;
|
|
370
|
+
if (values.external_url && !values.external_url.startsWith("http://") && !values.external_url.startsWith("https://")) {
|
|
371
|
+
setErrorMsg("External link must start with http:// or https://");
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
setStatus("minting");
|
|
375
|
+
setErrorMsg(null);
|
|
376
|
+
try {
|
|
377
|
+
const signer = await getSigner();
|
|
378
|
+
const image = mediaKind === "image" ? mediaUri : featureUri;
|
|
379
|
+
const animationUrl = mediaKind === "image" ? void 0 : mediaUri;
|
|
380
|
+
const built = (0, import_sdk.buildAssetMetadata)({
|
|
381
|
+
name: values.name,
|
|
382
|
+
description: values.description || "",
|
|
383
|
+
externalUrl: values.external_url || "",
|
|
384
|
+
imageUri: image,
|
|
385
|
+
creator: walletAddress,
|
|
386
|
+
ipType,
|
|
387
|
+
licenseType: values.licenseType,
|
|
388
|
+
commercialUse: values.commercialUse,
|
|
389
|
+
derivatives: values.derivatives,
|
|
390
|
+
attribution: values.attribution,
|
|
391
|
+
geographicScope: values.geographicScope,
|
|
392
|
+
aiPolicy: values.aiPolicy,
|
|
393
|
+
royalty: String(values.royalty),
|
|
394
|
+
templateTraits: templateFieldsRef.current.filter(({ traitType, value }) => traitType.trim() && value.trim()).map(({ traitType, value }) => ({ traitType, value }))
|
|
395
|
+
});
|
|
396
|
+
const metadata = { ...built };
|
|
397
|
+
if (animationUrl) metadata.animation_url = animationUrl;
|
|
398
|
+
const uploadToken = await getUploadToken();
|
|
399
|
+
if (!uploadToken) throw new Error("Sign in first");
|
|
400
|
+
const tokenUri = await (0, import_ipfs_upload.uploadJsonToIpfs)(metadata, uploadToken);
|
|
401
|
+
let result;
|
|
402
|
+
let finalContractAddress;
|
|
403
|
+
let finalTokenId = null;
|
|
404
|
+
if (assetType === "single") {
|
|
405
|
+
let collectionId = existingCollectionId;
|
|
406
|
+
let contractAddress = erc721Collections.find((c) => c.collectionId === existingCollectionId)?.contractAddress ?? null;
|
|
407
|
+
if (collectionMode === "new") {
|
|
408
|
+
const intentRes2 = await client.api.createCollectionIntent({
|
|
409
|
+
owner: walletAddress,
|
|
410
|
+
name: newCollectionName,
|
|
411
|
+
symbol: newCollectionSymbol
|
|
412
|
+
});
|
|
413
|
+
await (0, import_starknet2.executeIntent)(provider, signer, client, intentRes2.data);
|
|
414
|
+
const found = await pollForNewCollection(newCollectionName, newCollectionSymbol);
|
|
415
|
+
if (!found) throw new Error("Collection created, but it's still indexing \u2014 try minting again in a moment from My Collections.");
|
|
416
|
+
collectionId = found.collectionId;
|
|
417
|
+
contractAddress = found.contractAddress ?? null;
|
|
418
|
+
}
|
|
419
|
+
const intentRes = await client.api.createMintIntent({
|
|
420
|
+
owner: walletAddress,
|
|
421
|
+
collectionId,
|
|
422
|
+
recipient: walletAddress,
|
|
423
|
+
tokenUri,
|
|
424
|
+
royaltyBps: Math.round(values.royalty * 100)
|
|
425
|
+
});
|
|
426
|
+
if (!intentRes.data.requiresSignature) {
|
|
427
|
+
const calls = intentRes.data.calls;
|
|
428
|
+
contractAddress = calls[calls.length - 1]?.contractAddress ?? contractAddress;
|
|
429
|
+
}
|
|
430
|
+
result = await (0, import_starknet2.executeIntent)(provider, signer, client, intentRes.data);
|
|
431
|
+
finalContractAddress = contractAddress;
|
|
432
|
+
if (finalContractAddress) {
|
|
433
|
+
finalTokenId = await readMintedTokenId(provider, result.txHash, finalContractAddress);
|
|
434
|
+
}
|
|
435
|
+
} else {
|
|
436
|
+
let collectionContract = existingCollectionContract;
|
|
437
|
+
if (collectionMode === "new") {
|
|
438
|
+
const intentRes2 = await client.api.createCollectionIntent({
|
|
439
|
+
owner: walletAddress,
|
|
440
|
+
name: newCollectionName,
|
|
441
|
+
symbol: newCollectionSymbol,
|
|
442
|
+
baseUri: "",
|
|
443
|
+
service: "mip-erc1155"
|
|
444
|
+
});
|
|
445
|
+
const deployResult = await (0, import_starknet2.executeIntent)(provider, signer, client, intentRes2.data);
|
|
446
|
+
let receipt = null;
|
|
447
|
+
for (let attempt = 0; attempt < 3 && !receipt; attempt++) {
|
|
448
|
+
try {
|
|
449
|
+
if (attempt > 0) await new Promise((r) => setTimeout(r, 2e3));
|
|
450
|
+
const raw = await provider.getTransactionReceipt(deployResult.txHash);
|
|
451
|
+
receipt = raw;
|
|
452
|
+
} catch {
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
const events = receipt?.events ?? [];
|
|
456
|
+
const deployEvent = events.find(
|
|
457
|
+
(e) => e.keys?.[0] && BigInt(e.keys[0]) === BigInt(COLLECTION_DEPLOYED_SELECTOR)
|
|
458
|
+
);
|
|
459
|
+
if (!deployEvent?.keys?.[1]) throw new Error("Collection deployed, but its address couldn't be read \u2014 check My Collections to mint into it.");
|
|
460
|
+
collectionContract = (0, import_sdk.normalizeAddress)("STARKNET", deployEvent.keys[1]);
|
|
461
|
+
}
|
|
462
|
+
const intentRes = await client.api.createMintIntent({
|
|
463
|
+
owner: walletAddress,
|
|
464
|
+
recipient: walletAddress,
|
|
465
|
+
collectionContract,
|
|
466
|
+
tokenUri,
|
|
467
|
+
value: editionCount,
|
|
468
|
+
royaltyBps: Math.round(values.royalty * 100)
|
|
469
|
+
});
|
|
470
|
+
result = await (0, import_starknet2.executeIntent)(provider, signer, client, intentRes.data);
|
|
471
|
+
finalContractAddress = collectionContract;
|
|
472
|
+
finalTokenId = await readMintedTokenId(provider, result.txHash, collectionContract);
|
|
473
|
+
}
|
|
474
|
+
if (finalContractAddress && finalTokenId) {
|
|
475
|
+
const asset = { contract: finalContractAddress, tokenId: finalTokenId, image };
|
|
476
|
+
setMintedAsset(asset);
|
|
477
|
+
onMinted?.(asset);
|
|
478
|
+
}
|
|
479
|
+
setStatus("success");
|
|
480
|
+
} catch (err) {
|
|
481
|
+
setErrorMsg(err instanceof Error ? err.message : "Something went wrong. Please try again.");
|
|
482
|
+
setStatus("error");
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
const resetAll = () => {
|
|
486
|
+
setStatus("idle");
|
|
487
|
+
setErrorMsg(null);
|
|
488
|
+
setMintedAsset(null);
|
|
489
|
+
form.reset();
|
|
490
|
+
clearMedia();
|
|
491
|
+
setFeaturePreview(null);
|
|
492
|
+
setFeatureUri(null);
|
|
493
|
+
setAssetType("single");
|
|
494
|
+
setEditionCount("10");
|
|
495
|
+
setCollectionMode("existing");
|
|
496
|
+
setExistingCollectionId("");
|
|
497
|
+
setExistingCollectionContract("");
|
|
498
|
+
setNewCollectionName("");
|
|
499
|
+
setNewCollectionSymbol("");
|
|
500
|
+
setAutoSymbol("");
|
|
501
|
+
setAutoCollectionName("");
|
|
502
|
+
templateFieldsRef.current = [];
|
|
503
|
+
};
|
|
504
|
+
const busy = status === "minting";
|
|
505
|
+
const KindIcon = MEDIA_KIND_ICON[mediaKind];
|
|
506
|
+
const selectedExistingCollection = assetType === "single" ? erc721Collections.find((c) => c.collectionId === existingCollectionId) : erc1155Collections.find((c) => c.contractAddress === existingCollectionContract);
|
|
507
|
+
const collectionLabel = mediaUri ? collectionMode === "new" ? newCollectionName || "New collection" : selectedExistingCollection?.name || "IP Asset" : void 0;
|
|
508
|
+
const wrap = (node) => {
|
|
509
|
+
if (presentation !== "dialog") return node;
|
|
510
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_action_dialog.ActionDialog, { open, onClose: onClose ?? (() => {
|
|
511
|
+
}), width: 640, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative p-6 sm:p-8", children: [
|
|
512
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
513
|
+
"button",
|
|
514
|
+
{
|
|
515
|
+
type: "button",
|
|
516
|
+
onClick: onClose,
|
|
517
|
+
"aria-label": "Close",
|
|
518
|
+
className: "absolute top-4 right-4 h-8 w-8 rounded-full hover:bg-muted flex items-center justify-center text-muted-foreground",
|
|
519
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.X, { className: "h-4 w-4" })
|
|
520
|
+
}
|
|
521
|
+
),
|
|
522
|
+
node
|
|
523
|
+
] }) });
|
|
524
|
+
};
|
|
525
|
+
if (status === "success") {
|
|
526
|
+
return wrap(
|
|
527
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
528
|
+
import_success_view.SuccessView,
|
|
529
|
+
{
|
|
530
|
+
presentation,
|
|
531
|
+
previewImage: mediaKind === "image" ? mediaPreview : featurePreview,
|
|
532
|
+
name,
|
|
533
|
+
collectionLabel,
|
|
534
|
+
mintedAsset,
|
|
535
|
+
onPublishAnother: resetAll
|
|
536
|
+
}
|
|
537
|
+
)
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
if (!mediaFile) {
|
|
541
|
+
return wrap(
|
|
542
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
543
|
+
import_dropzone.Dropzone,
|
|
544
|
+
{
|
|
545
|
+
mediaKindLock,
|
|
546
|
+
presentation,
|
|
547
|
+
hasWallet,
|
|
548
|
+
onRequireWallet,
|
|
549
|
+
onFileSelected: handleMediaSelect
|
|
550
|
+
}
|
|
551
|
+
)
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
return wrap(
|
|
555
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "space-y-6", children: [
|
|
556
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-4 rounded-xl border border-border p-3", children: [
|
|
557
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative h-14 w-14 rounded-lg bg-muted overflow-hidden shrink-0", children: [
|
|
558
|
+
mediaKind === "image" && mediaPreview ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_image.default, { src: mediaPreview, alt: "", fill: true, className: "object-cover", unoptimized: true }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(KindIcon, { className: "h-6 w-6 text-muted-foreground" }) }),
|
|
559
|
+
mediaUploading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0 flex items-center justify-center bg-background/70", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Loader2, { className: "h-4 w-4 animate-spin" }) })
|
|
560
|
+
] }),
|
|
561
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "min-w-0 flex-1", children: [
|
|
562
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm font-semibold truncate", children: mediaFile.name }),
|
|
563
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-xs text-muted-foreground", children: mediaUploading ? "Uploading\u2026" : mediaUri ? "Uploaded" : "Upload failed" })
|
|
564
|
+
] }),
|
|
565
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
566
|
+
"button",
|
|
567
|
+
{
|
|
568
|
+
type: "button",
|
|
569
|
+
onClick: () => mediaInputRef.current?.click(),
|
|
570
|
+
className: "text-xs font-semibold text-brand-blue hover:underline shrink-0",
|
|
571
|
+
children: "Change"
|
|
572
|
+
}
|
|
573
|
+
),
|
|
574
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { ref: mediaInputRef, type: "file", className: "hidden", onChange: (e) => {
|
|
575
|
+
const f = e.target.files?.[0];
|
|
576
|
+
if (f) handleMediaSelect(f);
|
|
577
|
+
} })
|
|
578
|
+
] }),
|
|
579
|
+
mediaUri && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "grid grid-cols-1 lg:grid-cols-[1fr_320px] gap-8 items-start", children: [
|
|
580
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-5", children: [
|
|
581
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
|
|
582
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-sm font-medium", children: "Name *" }),
|
|
583
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
584
|
+
import_input.Input,
|
|
585
|
+
{
|
|
586
|
+
value: name,
|
|
587
|
+
onChange: (e) => form.setValue("name", e.target.value),
|
|
588
|
+
placeholder: "My Creative Work"
|
|
589
|
+
}
|
|
590
|
+
)
|
|
591
|
+
] }),
|
|
592
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
|
|
593
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-sm font-medium", children: "Description" }),
|
|
594
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
595
|
+
import_textarea.Textarea,
|
|
596
|
+
{
|
|
597
|
+
value: form.watch("description"),
|
|
598
|
+
onChange: (e) => form.setValue("description", e.target.value),
|
|
599
|
+
placeholder: "Describe your work, its story, and any context for buyers\u2026",
|
|
600
|
+
rows: 3
|
|
601
|
+
}
|
|
602
|
+
)
|
|
603
|
+
] }),
|
|
604
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
|
|
605
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "text-sm font-medium", children: [
|
|
606
|
+
"External link ",
|
|
607
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-muted-foreground font-normal", children: "(optional)" })
|
|
608
|
+
] }),
|
|
609
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
610
|
+
import_input.Input,
|
|
611
|
+
{
|
|
612
|
+
value: form.watch("external_url"),
|
|
613
|
+
onChange: (e) => form.setValue("external_url", e.target.value),
|
|
614
|
+
placeholder: "https://yourwebsite.com"
|
|
615
|
+
}
|
|
616
|
+
)
|
|
617
|
+
] }),
|
|
618
|
+
mediaKind !== "image" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
|
|
619
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-sm font-medium", children: "Feature image *" }),
|
|
620
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-4", children: [
|
|
621
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
622
|
+
"div",
|
|
623
|
+
{
|
|
624
|
+
role: "button",
|
|
625
|
+
tabIndex: 0,
|
|
626
|
+
onClick: () => !featureUploading && featureInputRef.current?.click(),
|
|
627
|
+
onKeyDown: (e) => {
|
|
628
|
+
if ((e.key === "Enter" || e.key === " ") && !featureUploading) {
|
|
629
|
+
e.preventDefault();
|
|
630
|
+
featureInputRef.current?.click();
|
|
631
|
+
}
|
|
632
|
+
},
|
|
633
|
+
className: "relative h-20 w-20 rounded-xl border-2 border-dashed border-border bg-muted flex items-center justify-center overflow-hidden shrink-0 cursor-pointer hover:border-primary/50 transition-colors",
|
|
634
|
+
children: [
|
|
635
|
+
featurePreview ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_image.default, { src: featurePreview, alt: "", fill: true, className: "object-cover", unoptimized: true }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ImagePlus, { className: "h-6 w-6 text-muted-foreground" }),
|
|
636
|
+
featureUploading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute inset-0 flex items-center justify-center bg-background/70", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Loader2, { className: "h-4 w-4 animate-spin" }) }),
|
|
637
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { ref: featureInputRef, type: "file", accept: "image/*", className: "hidden", onChange: (e) => {
|
|
638
|
+
const f = e.target.files?.[0];
|
|
639
|
+
if (f) handleFeatureSelect(f);
|
|
640
|
+
} })
|
|
641
|
+
]
|
|
642
|
+
}
|
|
643
|
+
),
|
|
644
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-xs text-muted-foreground", children: "Cover art shown wherever the work is previewed. JPG, PNG, GIF, SVG or WebP." })
|
|
645
|
+
] })
|
|
646
|
+
] }),
|
|
647
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
|
|
648
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-sm font-medium", children: "Type" }),
|
|
649
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "grid grid-cols-2 gap-3", children: [
|
|
650
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
651
|
+
"button",
|
|
652
|
+
{
|
|
653
|
+
type: "button",
|
|
654
|
+
onClick: () => setAssetType("single"),
|
|
655
|
+
className: (0, import_cn.cn)(
|
|
656
|
+
"flex items-start gap-3 rounded-xl border p-4 text-left transition-colors",
|
|
657
|
+
assetType === "single" ? "border-brand-blue bg-brand-blue/5" : "border-border hover:bg-muted/40"
|
|
658
|
+
),
|
|
659
|
+
children: [
|
|
660
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ImagePlus, { className: (0, import_cn.cn)("h-5 w-5 shrink-0 mt-0.5", assetType === "single" ? "text-brand-blue" : "text-muted-foreground") }),
|
|
661
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
662
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "block text-sm font-semibold", children: "One copy" }),
|
|
663
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "block text-xs mt-0.5 text-muted-foreground", children: "Minted once" })
|
|
664
|
+
] })
|
|
665
|
+
]
|
|
666
|
+
}
|
|
667
|
+
),
|
|
668
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
669
|
+
"button",
|
|
670
|
+
{
|
|
671
|
+
type: "button",
|
|
672
|
+
onClick: () => setAssetType("editions"),
|
|
673
|
+
className: (0, import_cn.cn)(
|
|
674
|
+
"flex items-start gap-3 rounded-xl border p-4 text-left transition-colors",
|
|
675
|
+
assetType === "editions" ? "border-brand-blue bg-brand-blue/5" : "border-border hover:bg-muted/40"
|
|
676
|
+
),
|
|
677
|
+
children: [
|
|
678
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Layers, { className: (0, import_cn.cn)("h-5 w-5 shrink-0 mt-0.5", assetType === "editions" ? "text-brand-blue" : "text-muted-foreground") }),
|
|
679
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
680
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "block text-sm font-semibold", children: "Numbered copies" }),
|
|
681
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "block text-xs mt-0.5 text-muted-foreground", children: "Several editions" })
|
|
682
|
+
] })
|
|
683
|
+
]
|
|
684
|
+
}
|
|
685
|
+
)
|
|
686
|
+
] })
|
|
687
|
+
] }),
|
|
688
|
+
assetType === "editions" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
|
|
689
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-sm font-medium", children: "Number of copies" }),
|
|
690
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
691
|
+
import_input.Input,
|
|
692
|
+
{
|
|
693
|
+
type: "number",
|
|
694
|
+
min: 1,
|
|
695
|
+
value: editionCount,
|
|
696
|
+
onChange: (e) => setEditionCount(e.target.value),
|
|
697
|
+
className: "max-w-[140px]"
|
|
698
|
+
}
|
|
699
|
+
)
|
|
700
|
+
] }),
|
|
701
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
|
|
702
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
703
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "text-sm font-medium flex items-center gap-1.5", children: [
|
|
704
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Boxes, { className: "h-4 w-4" }),
|
|
705
|
+
"Collection *"
|
|
706
|
+
] }),
|
|
707
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex rounded-lg border border-border overflow-hidden", children: [
|
|
708
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
709
|
+
"button",
|
|
710
|
+
{
|
|
711
|
+
type: "button",
|
|
712
|
+
onClick: () => setCollectionMode("existing"),
|
|
713
|
+
className: (0, import_cn.cn)(
|
|
714
|
+
"px-3 h-7 text-xs font-medium transition-colors",
|
|
715
|
+
collectionMode === "existing" ? "bg-primary text-primary-foreground" : "bg-background hover:bg-muted text-muted-foreground"
|
|
716
|
+
),
|
|
717
|
+
children: "Existing"
|
|
718
|
+
}
|
|
719
|
+
),
|
|
720
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
721
|
+
"button",
|
|
722
|
+
{
|
|
723
|
+
type: "button",
|
|
724
|
+
onClick: () => setCollectionMode("new"),
|
|
725
|
+
className: (0, import_cn.cn)(
|
|
726
|
+
"px-3 h-7 text-xs font-medium border-l border-border transition-colors flex items-center gap-1",
|
|
727
|
+
collectionMode === "new" ? "bg-primary text-primary-foreground" : "bg-background hover:bg-muted text-muted-foreground"
|
|
728
|
+
),
|
|
729
|
+
children: [
|
|
730
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Plus, { className: "h-3 w-3" }),
|
|
731
|
+
"New"
|
|
732
|
+
]
|
|
733
|
+
}
|
|
734
|
+
)
|
|
735
|
+
] })
|
|
736
|
+
] }),
|
|
737
|
+
collectionMode === "existing" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
738
|
+
CollectionPicker,
|
|
739
|
+
{
|
|
740
|
+
collections: assetType === "single" ? erc721Collections : erc1155Collections,
|
|
741
|
+
value: assetType === "single" ? existingCollectionId : existingCollectionContract,
|
|
742
|
+
onChange: assetType === "single" ? setExistingCollectionId : setExistingCollectionContract
|
|
743
|
+
}
|
|
744
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
745
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
746
|
+
import_input.Input,
|
|
747
|
+
{
|
|
748
|
+
value: newCollectionName,
|
|
749
|
+
onChange: (e) => setNewCollectionName(e.target.value),
|
|
750
|
+
placeholder: "Collection name"
|
|
751
|
+
}
|
|
752
|
+
),
|
|
753
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
754
|
+
import_input.Input,
|
|
755
|
+
{
|
|
756
|
+
value: newCollectionSymbol,
|
|
757
|
+
onChange: (e) => setNewCollectionSymbol(e.target.value.toUpperCase()),
|
|
758
|
+
placeholder: "SYMBOL"
|
|
759
|
+
}
|
|
760
|
+
)
|
|
761
|
+
] })
|
|
762
|
+
] }),
|
|
763
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_collapsible.Collapsible, { open: advancedOpen, onOpenChange: setAdvancedOpen, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rounded-xl border border-border overflow-hidden", children: [
|
|
764
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_collapsible.CollapsibleTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "w-full flex items-center justify-between px-4 py-3.5 hover:bg-muted/30 transition-colors", children: [
|
|
765
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "flex items-center gap-2", children: [
|
|
766
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ShieldCheck, { className: "h-4 w-4 text-primary" }),
|
|
767
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-sm font-semibold", children: "Licensing Terms" }),
|
|
768
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xs text-muted-foreground font-normal", children: "Optional \xB7 Berne Convention" })
|
|
769
|
+
] }),
|
|
770
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ChevronDown, { className: (0, import_cn.cn)("h-4 w-4 text-muted-foreground transition-transform", advancedOpen && "rotate-180") })
|
|
771
|
+
] }) }),
|
|
772
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_collapsible.CollapsibleContent, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "px-4 pb-4 space-y-4 border-t border-border/60 pt-4", children: [
|
|
773
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-1.5", children: [
|
|
774
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-xs font-medium text-muted-foreground", children: "License" }),
|
|
775
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_select.Select, { value: form.watch("licenseType"), onValueChange: handleLicenseChange, children: [
|
|
776
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectValue, {}) }),
|
|
777
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectContent, { children: import_ip.LICENSE_TYPES.map((l) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectItem, { value: l.value, children: l.label }, l.value)) })
|
|
778
|
+
] })
|
|
779
|
+
] }),
|
|
780
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-1.5", children: [
|
|
781
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-xs font-medium text-muted-foreground", children: "Commercial use" }),
|
|
782
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToggleGroup, { value: form.watch("commercialUse"), options: ["Yes", "No"], onChange: (v) => form.setValue("commercialUse", v) })
|
|
783
|
+
] }),
|
|
784
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-1.5", children: [
|
|
785
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-xs font-medium text-muted-foreground", children: "Derivatives" }),
|
|
786
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToggleGroup, { value: form.watch("derivatives"), options: import_ip.DERIVATIVES_OPTIONS, onChange: (v) => form.setValue("derivatives", v) })
|
|
787
|
+
] }),
|
|
788
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-1.5", children: [
|
|
789
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-xs font-medium text-muted-foreground", children: "Territory" }),
|
|
790
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_select.Select, { value: form.watch("geographicScope"), onValueChange: (v) => form.setValue("geographicScope", v), children: [
|
|
791
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectValue, {}) }),
|
|
792
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectContent, { children: import_ip.GEOGRAPHIC_SCOPES.map((s) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectItem, { value: s, children: s }, s)) })
|
|
793
|
+
] })
|
|
794
|
+
] }),
|
|
795
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-1.5", children: [
|
|
796
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-xs font-medium text-muted-foreground", children: "AI & data mining" }),
|
|
797
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToggleGroup, { value: form.watch("aiPolicy"), options: import_ip.AI_POLICIES, onChange: (v) => form.setValue("aiPolicy", v) })
|
|
798
|
+
] }),
|
|
799
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-1.5", children: [
|
|
800
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-xs font-medium text-muted-foreground", children: "Royalty % (0\u201350)" }),
|
|
801
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
802
|
+
import_input.Input,
|
|
803
|
+
{
|
|
804
|
+
type: "number",
|
|
805
|
+
min: 0,
|
|
806
|
+
max: 50,
|
|
807
|
+
step: 0.5,
|
|
808
|
+
value: form.watch("royalty"),
|
|
809
|
+
onChange: (e) => form.setValue("royalty", parseFloat(e.target.value) || 0),
|
|
810
|
+
className: "max-w-[120px]"
|
|
811
|
+
}
|
|
812
|
+
)
|
|
813
|
+
] })
|
|
814
|
+
] }) })
|
|
815
|
+
] }) }),
|
|
816
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_collapsible.Collapsible, { open: ipTypeOpen, onOpenChange: setIpTypeOpen, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rounded-xl border border-border overflow-hidden", children: [
|
|
817
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_collapsible.CollapsibleTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "w-full flex items-center justify-between px-4 py-3.5 hover:bg-muted/30 transition-colors", children: [
|
|
818
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "flex items-center gap-2", children: [
|
|
819
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Layers, { className: "h-4 w-4 text-primary" }),
|
|
820
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-sm font-semibold", children: "IP Type & Metadata" }),
|
|
821
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xs text-muted-foreground font-normal", children: "Optional" })
|
|
822
|
+
] }),
|
|
823
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ChevronDown, { className: (0, import_cn.cn)("h-4 w-4 text-muted-foreground transition-transform", ipTypeOpen && "rotate-180") })
|
|
824
|
+
] }) }),
|
|
825
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_collapsible.CollapsibleContent, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "px-4 pb-4 space-y-4 border-t border-border/60 pt-4", children: [
|
|
826
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-1.5", children: [
|
|
827
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-xs font-medium text-muted-foreground", children: "IP Type" }),
|
|
828
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_select.Select, { value: ipType, onValueChange: (v) => setIpType(v), children: [
|
|
829
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectValue, {}) }),
|
|
830
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectContent, { children: import_ip.IP_TYPES.map((t) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectItem, { value: t, children: t }, t)) })
|
|
831
|
+
] })
|
|
832
|
+
] }),
|
|
833
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
834
|
+
import_ip_type_fields.IPTypeFields,
|
|
835
|
+
{
|
|
836
|
+
ipType,
|
|
837
|
+
onChange: (fields) => {
|
|
838
|
+
templateFieldsRef.current = fields;
|
|
839
|
+
},
|
|
840
|
+
uploadDocument: async (file) => {
|
|
841
|
+
const token = await getUploadToken();
|
|
842
|
+
if (!token) throw new Error("Sign in first");
|
|
843
|
+
const { uri } = await (0, import_ipfs_upload.uploadFileToIpfs)(file, token, "document");
|
|
844
|
+
return uri;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
)
|
|
848
|
+
] }) })
|
|
849
|
+
] }) }),
|
|
850
|
+
status === "error" && errorMsg && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-xs text-destructive", children: errorMsg }),
|
|
851
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
852
|
+
"button",
|
|
853
|
+
{
|
|
854
|
+
type: "button",
|
|
855
|
+
disabled: !ready || busy || !hasWallet,
|
|
856
|
+
onClick: form.handleSubmit(onSubmit),
|
|
857
|
+
className: (0, import_cn.cn)(
|
|
858
|
+
"w-full h-12 text-base font-semibold text-white rounded-xl flex items-center justify-center gap-2 transition-all hover:brightness-110 active:scale-[0.98] bg-brand-blue",
|
|
859
|
+
(!ready || busy || !hasWallet) && "opacity-40 pointer-events-none"
|
|
860
|
+
),
|
|
861
|
+
children: busy ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
862
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
863
|
+
"Minting\u2026"
|
|
864
|
+
] }) : assetType === "single" ? "Mint NFT" : "Mint Editions"
|
|
865
|
+
}
|
|
866
|
+
),
|
|
867
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-xs text-center text-muted-foreground", children: "Zero platform fees to mint." })
|
|
868
|
+
] }),
|
|
869
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "lg:sticky lg:top-20", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
870
|
+
import_medialane_collection_card.MedialaneCollectionCard,
|
|
871
|
+
{
|
|
872
|
+
image: mediaKind === "image" ? mediaPreview : featurePreview,
|
|
873
|
+
name,
|
|
874
|
+
collection: collectionLabel,
|
|
875
|
+
creator: walletAddress ? `${walletAddress.slice(0, 6)}\u2026${walletAddress.slice(-4)}` : void 0,
|
|
876
|
+
creatorHref: walletAddress ? `/account/${walletAddress}` : void 0
|
|
877
|
+
}
|
|
878
|
+
) })
|
|
879
|
+
] })
|
|
880
|
+
] })
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
884
|
+
0 && (module.exports = {
|
|
885
|
+
FastMint
|
|
886
|
+
});
|
|
887
|
+
//# sourceMappingURL=fast-mint.cjs.map
|