@medialane/ui 0.294.0 → 0.296.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.
Files changed (101) hide show
  1. package/dist/components/create-sponsorship-aside.cjs +52 -0
  2. package/dist/components/create-sponsorship-aside.cjs.map +1 -0
  3. package/dist/components/create-sponsorship-aside.d.cts +5 -0
  4. package/dist/components/create-sponsorship-aside.d.ts +5 -0
  5. package/dist/components/create-sponsorship-aside.js +28 -0
  6. package/dist/components/create-sponsorship-aside.js.map +1 -0
  7. package/dist/components/fast-mint/asset-form-parts.cjs +194 -0
  8. package/dist/components/fast-mint/asset-form-parts.cjs.map +1 -0
  9. package/dist/components/fast-mint/asset-form-parts.d.cts +33 -0
  10. package/dist/components/fast-mint/asset-form-parts.d.ts +33 -0
  11. package/dist/components/fast-mint/asset-form-parts.js +158 -0
  12. package/dist/components/fast-mint/asset-form-parts.js.map +1 -0
  13. package/dist/components/fast-mint/collection-section.cjs +211 -0
  14. package/dist/components/fast-mint/collection-section.cjs.map +1 -0
  15. package/dist/components/fast-mint/collection-section.d.cts +27 -0
  16. package/dist/components/fast-mint/collection-section.d.ts +27 -0
  17. package/dist/components/fast-mint/collection-section.js +176 -0
  18. package/dist/components/fast-mint/collection-section.js.map +1 -0
  19. package/dist/components/fast-mint/fast-mint.cjs +116 -653
  20. package/dist/components/fast-mint/fast-mint.cjs.map +1 -1
  21. package/dist/components/fast-mint/fast-mint.js +115 -661
  22. package/dist/components/fast-mint/fast-mint.js.map +1 -1
  23. package/dist/components/fast-mint/form.cjs +40 -0
  24. package/dist/components/fast-mint/form.cjs.map +1 -0
  25. package/dist/components/fast-mint/form.d.cts +15 -0
  26. package/dist/components/fast-mint/form.d.ts +15 -0
  27. package/dist/components/fast-mint/form.js +16 -0
  28. package/dist/components/fast-mint/form.js.map +1 -0
  29. package/dist/components/fast-mint/ip-type-section.cjs +76 -0
  30. package/dist/components/fast-mint/ip-type-section.cjs.map +1 -0
  31. package/dist/components/fast-mint/ip-type-section.d.cts +17 -0
  32. package/dist/components/fast-mint/ip-type-section.d.ts +17 -0
  33. package/dist/components/fast-mint/ip-type-section.js +52 -0
  34. package/dist/components/fast-mint/ip-type-section.js.map +1 -0
  35. package/dist/components/fast-mint/licensing-section.cjs +124 -0
  36. package/dist/components/fast-mint/licensing-section.cjs.map +1 -0
  37. package/dist/components/fast-mint/licensing-section.d.cts +14 -0
  38. package/dist/components/fast-mint/licensing-section.d.ts +14 -0
  39. package/dist/components/fast-mint/licensing-section.js +99 -0
  40. package/dist/components/fast-mint/licensing-section.js.map +1 -0
  41. package/dist/components/fast-mint/media-kind.cjs +48 -0
  42. package/dist/components/fast-mint/media-kind.cjs.map +1 -0
  43. package/dist/components/fast-mint/media-kind.d.cts +12 -0
  44. package/dist/components/fast-mint/media-kind.d.ts +12 -0
  45. package/dist/components/fast-mint/media-kind.js +22 -0
  46. package/dist/components/fast-mint/media-kind.js.map +1 -0
  47. package/dist/components/fast-mint/mint-asset.cjs +124 -0
  48. package/dist/components/fast-mint/mint-asset.cjs.map +1 -0
  49. package/dist/components/fast-mint/mint-asset.d.cts +41 -0
  50. package/dist/components/fast-mint/mint-asset.d.ts +41 -0
  51. package/dist/components/fast-mint/mint-asset.js +100 -0
  52. package/dist/components/fast-mint/mint-asset.js.map +1 -0
  53. package/dist/components/fast-mint/use-ipfs-upload.cjs +64 -0
  54. package/dist/components/fast-mint/use-ipfs-upload.cjs.map +1 -0
  55. package/dist/components/fast-mint/use-ipfs-upload.d.cts +9 -0
  56. package/dist/components/fast-mint/use-ipfs-upload.d.ts +9 -0
  57. package/dist/components/fast-mint/use-ipfs-upload.js +40 -0
  58. package/dist/components/fast-mint/use-ipfs-upload.js.map +1 -0
  59. package/dist/components/fast-mint/use-new-collection-draft.cjs +66 -0
  60. package/dist/components/fast-mint/use-new-collection-draft.cjs.map +1 -0
  61. package/dist/components/fast-mint/use-new-collection-draft.d.cts +13 -0
  62. package/dist/components/fast-mint/use-new-collection-draft.d.ts +13 -0
  63. package/dist/components/fast-mint/use-new-collection-draft.js +42 -0
  64. package/dist/components/fast-mint/use-new-collection-draft.js.map +1 -0
  65. package/dist/components/journey-content.cjs +156 -0
  66. package/dist/components/journey-content.cjs.map +1 -0
  67. package/dist/components/journey-content.d.cts +7 -0
  68. package/dist/components/journey-content.d.ts +7 -0
  69. package/dist/components/journey-content.js +122 -0
  70. package/dist/components/journey-content.js.map +1 -0
  71. package/dist/components/page-skeletons.cjs +152 -0
  72. package/dist/components/page-skeletons.cjs.map +1 -0
  73. package/dist/components/page-skeletons.d.cts +10 -0
  74. package/dist/components/page-skeletons.d.ts +10 -0
  75. package/dist/components/page-skeletons.js +123 -0
  76. package/dist/components/page-skeletons.js.map +1 -0
  77. package/dist/components/rewards-page.cjs +41 -0
  78. package/dist/components/rewards-page.cjs.map +1 -0
  79. package/dist/components/rewards-page.d.cts +5 -0
  80. package/dist/components/rewards-page.d.ts +5 -0
  81. package/dist/components/rewards-page.js +17 -0
  82. package/dist/components/rewards-page.js.map +1 -0
  83. package/dist/components/route-error.cjs +65 -0
  84. package/dist/components/route-error.cjs.map +1 -0
  85. package/dist/components/route-error.d.cts +10 -0
  86. package/dist/components/route-error.d.ts +10 -0
  87. package/dist/components/route-error.js +41 -0
  88. package/dist/components/route-error.js.map +1 -0
  89. package/dist/components/settings-snapshots.cjs +124 -0
  90. package/dist/components/settings-snapshots.cjs.map +1 -0
  91. package/dist/components/settings-snapshots.d.cts +12 -0
  92. package/dist/components/settings-snapshots.d.ts +12 -0
  93. package/dist/components/settings-snapshots.js +89 -0
  94. package/dist/components/settings-snapshots.js.map +1 -0
  95. package/dist/index.cjs +30 -0
  96. package/dist/index.cjs.map +1 -1
  97. package/dist/index.d.cts +6 -0
  98. package/dist/index.d.ts +6 -0
  99. package/dist/index.js +18 -0
  100. package/dist/index.js.map +1 -1
  101. package/package.json +1 -1
@@ -1,10 +1,8 @@
1
1
  "use strict";
2
2
  "use client";
3
- var __create = Object.create;
4
3
  var __defProp = Object.defineProperty;
5
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getProtoOf = Object.getPrototypeOf;
8
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
7
  var __export = (target, all) => {
10
8
  for (var name in all)
@@ -18,14 +16,6 @@ var __copyProps = (to, from, except, desc) => {
18
16
  }
19
17
  return to;
20
18
  };
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
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
20
  var fast_mint_exports = {};
31
21
  __export(fast_mint_exports, {
@@ -34,137 +24,29 @@ __export(fast_mint_exports, {
34
24
  module.exports = __toCommonJS(fast_mint_exports);
35
25
  var import_jsx_runtime = require("react/jsx-runtime");
36
26
  var import_react = require("react");
37
- var import_image = __toESM(require("next/image"), 1);
38
27
  var import_react_hook_form = require("react-hook-form");
28
+ var import_lucide_react = require("lucide-react");
39
29
  var import_sdk = require("@medialane/sdk");
40
30
  var import_describe_error = require("../../utils/describe-error.js");
41
31
  var import_upload_limits = require("../../utils/upload-limits.js");
42
- var import_starknet = require("@medialane/sdk/starknet");
43
- var import_mintable_collections = require("./mintable-collections.js");
44
- var import_lucide_react = require("lucide-react");
32
+ var import_ipfs_upload = require("../../utils/ipfs-upload.js");
33
+ var import_cn = require("../../utils/cn.js");
45
34
  var import_input = require("../input.js");
46
35
  var import_textarea = require("../textarea.js");
47
- var import_select = require("../select.js");
48
- var import_collapsible = require("../collapsible.js");
49
- var import_popover = require("../popover.js");
50
36
  var import_medialane_collection_card = require("../medialane-collection-card.js");
51
37
  var import_dialog = require("../dialog.js");
52
- var import_ip_type_fields = require("../ip-type-fields.js");
53
- var import_ip = require("../../data/ip.js");
54
- var import_ip_templates = require("../../data/ip-templates.js");
55
- var import_launchpad_defaults = require("../../utils/launchpad-defaults.js");
56
- var import_ipfs_upload = require("../../utils/ipfs-upload.js");
57
- var import_cn = require("../../utils/cn.js");
58
38
  var import_dropzone = require("./dropzone.js");
59
39
  var import_success_view = require("./success-view.js");
60
- var import_sdk2 = require("@medialane/sdk");
61
- var import_use_image_url = require("../../utils/use-image-url.js");
62
- const MEDIA_ROUTE_MIME_TYPES = new Set(import_upload_limits.UPLOAD_LIMITS.media.mimeTypes);
63
- const DOCUMENT_MIME_TYPES = new Set(import_upload_limits.UPLOAD_LIMITS.document.mimeTypes.filter((type) => type !== "application/octet-stream"));
64
- function detectMediaKind(mime) {
65
- if (mime.startsWith("image/")) return MEDIA_ROUTE_MIME_TYPES.has(mime) ? "image" : null;
66
- if (mime.startsWith("video/")) return MEDIA_ROUTE_MIME_TYPES.has(mime) ? "video" : null;
67
- if (mime.startsWith("audio/")) return MEDIA_ROUTE_MIME_TYPES.has(mime) ? "audio" : null;
68
- if (DOCUMENT_MIME_TYPES.has(mime)) return "document";
69
- return null;
70
- }
71
- const IP_TYPE_BY_KIND = {
72
- image: "NFT",
73
- audio: "Audio",
74
- video: "Video",
75
- document: "Documents"
76
- };
77
- const MEDIA_KIND_ICON = {
78
- image: import_lucide_react.ImagePlus,
79
- audio: import_lucide_react.Music,
80
- video: import_lucide_react.Video,
81
- document: import_lucide_react.FileText
82
- };
83
- function ToggleGroup({
84
- value,
85
- options,
86
- onChange
87
- }) {
88
- 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)(
89
- "button",
90
- {
91
- type: "button",
92
- onClick: () => onChange(opt),
93
- className: (0, import_cn.cn)(
94
- "flex-1 px-3 py-2 text-sm transition-colors",
95
- i > 0 && "border-l border-border",
96
- value === opt ? "bg-primary text-primary-foreground font-medium" : "bg-background hover:bg-muted text-muted-foreground"
97
- ),
98
- children: opt
99
- },
100
- opt
101
- )) });
102
- }
103
- function collectionDisplayLabel(col) {
104
- return col.name || col.symbol || `Collection #${col.collectionId}`;
105
- }
106
- function CollectionThumb({ image }) {
107
- const resolveImage = (0, import_use_image_url.useImageUrl)();
108
- const imageUrl = resolveImage(image);
109
- 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" }) }) });
110
- }
111
- function CollectionPicker({
112
- collections,
113
- value,
114
- onChange,
115
- valueOf
116
- }) {
117
- const [open, setOpen] = (0, import_react.useState)(false);
118
- const selected = value ? collections.find((c) => valueOf(c) === value) ?? null : null;
119
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_popover.Popover, { open, onOpenChange: setOpen, children: [
120
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_popover.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
121
- "button",
122
- {
123
- type: "button",
124
- "aria-expanded": open,
125
- className: "flex w-full items-center gap-3 rounded-xl border border-border p-3 text-left transition-colors hover:bg-muted/40",
126
- children: [
127
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CollectionThumb, { image: selected?.image }),
128
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "min-w-0 flex-1", children: [
129
- /* @__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" }),
130
- /* @__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" })
131
- ] }),
132
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground shrink-0" })
133
- ]
134
- }
135
- ) }),
136
- /* @__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) => {
137
- const id = valueOf(col);
138
- const isSelected = !!id && value === id;
139
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
140
- "button",
141
- {
142
- type: "button",
143
- disabled: !id,
144
- onClick: () => {
145
- if (!id) return;
146
- onChange(id);
147
- setOpen(false);
148
- },
149
- className: "flex w-full items-center gap-2.5 rounded-lg px-2 py-2 text-left transition-colors hover:bg-muted/60",
150
- children: [
151
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CollectionThumb, { image: col.image }),
152
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "min-w-0 flex-1", children: [
153
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm font-medium truncate", children: collectionDisplayLabel(col) }),
154
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "text-xs text-muted-foreground", children: [
155
- col.totalSupply ?? 0,
156
- " work",
157
- col.totalSupply === 1 ? "" : "s"
158
- ] })
159
- ] }),
160
- isSelected && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Check, { className: "h-4 w-4 text-brand-blue shrink-0" })
161
- ]
162
- },
163
- id ?? col.contractAddress ?? col.name
164
- );
165
- }) }) })
166
- ] });
167
- }
40
+ var import_asset_form_parts = require("./asset-form-parts.js");
41
+ var import_collection_section = require("./collection-section.js");
42
+ var import_licensing_section = require("./licensing-section.js");
43
+ var import_ip_type_section = require("./ip-type-section.js");
44
+ var import_form = require("./form.js");
45
+ var import_media_kind = require("./media-kind.js");
46
+ var import_mint_asset = require("./mint-asset.js");
47
+ var import_mintable_collections = require("./mintable-collections.js");
48
+ var import_use_ipfs_upload = require("./use-ipfs-upload.js");
49
+ var import_use_new_collection_draft = require("./use-new-collection-draft.js");
168
50
  function FastMint(props) {
169
51
  const {
170
52
  presentation = "inline",
@@ -185,81 +67,38 @@ function FastMint(props) {
185
67
  } = props;
186
68
  const [status, setStatus] = (0, import_react.useState)("idle");
187
69
  const [errorMsg, setErrorMsg] = (0, import_react.useState)(null);
70
+ const media = (0, import_use_ipfs_upload.useIpfsUpload)();
71
+ const feature = (0, import_use_ipfs_upload.useIpfsUpload)();
188
72
  const [mediaFile, setMediaFile] = (0, import_react.useState)(null);
189
- const [mediaPreview, setMediaPreview] = (0, import_react.useState)(null);
190
- const [mediaUri, setMediaUri] = (0, import_react.useState)(null);
191
73
  const [mediaKind, setMediaKind] = (0, import_react.useState)("image");
192
- const [mediaUploading, setMediaUploading] = (0, import_react.useState)(false);
193
- const previewUrlRef = (0, import_react.useRef)(null);
194
74
  const mediaInputRef = (0, import_react.useRef)(null);
195
- const [featurePreview, setFeaturePreview] = (0, import_react.useState)(null);
196
- const [featureUri, setFeatureUri] = (0, import_react.useState)(null);
197
- const [featureUploading, setFeatureUploading] = (0, import_react.useState)(false);
198
- const featurePreviewRef = (0, import_react.useRef)(null);
199
75
  const featureInputRef = (0, import_react.useRef)(null);
200
76
  const [assetType, setAssetType] = (0, import_react.useState)("single");
201
77
  const [editionCount, setEditionCount] = (0, import_react.useState)("10");
202
78
  const [collectionMode, setCollectionMode] = (0, import_react.useState)("existing");
203
79
  const [existingCollectionId, setExistingCollectionId] = (0, import_react.useState)("");
204
80
  const [existingCollectionContract, setExistingCollectionContract] = (0, import_react.useState)("");
205
- const [newCollectionName, setNewCollectionName] = (0, import_react.useState)("");
206
- const [newCollectionSymbol, setNewCollectionSymbol] = (0, import_react.useState)("");
207
- const [newCollectionDescription, setNewCollectionDescription] = (0, import_react.useState)("");
208
- const [autoSymbol, setAutoSymbol] = (0, import_react.useState)("");
209
- const [autoCollectionName, setAutoCollectionName] = (0, import_react.useState)("");
210
- const [autoCollectionDescription, setAutoCollectionDescription] = (0, import_react.useState)("");
211
81
  const [ipType, setIpType] = (0, import_react.useState)("NFT");
212
- const [advancedOpen, setAdvancedOpen] = (0, import_react.useState)(false);
213
- const [ipTypeOpen, setIpTypeOpen] = (0, import_react.useState)(false);
214
82
  const templateFieldsRef = (0, import_react.useRef)([]);
215
83
  const [mintedAsset, setMintedAsset] = (0, import_react.useState)(null);
216
- (0, import_react.useEffect)(() => () => {
217
- if (previewUrlRef.current) URL.revokeObjectURL(previewUrlRef.current);
218
- if (featurePreviewRef.current) URL.revokeObjectURL(featurePreviewRef.current);
219
- }, []);
220
- const form = (0, import_react_hook_form.useForm)({
221
- defaultValues: {
222
- name: "",
223
- description: "",
224
- external_url: "",
225
- licenseType: "CC BY-SA",
226
- commercialUse: "Yes",
227
- derivatives: "Share-Alike",
228
- attribution: "Required",
229
- geographicScope: "Worldwide",
230
- aiPolicy: "Allowed",
231
- royalty: 0
232
- }
233
- });
84
+ const form = (0, import_react_hook_form.useForm)({ defaultValues: import_form.DEFAULT_VALUES });
234
85
  const name = form.watch("name");
86
+ const description = form.watch("description");
87
+ const draft = (0, import_use_new_collection_draft.useNewCollectionDraft)(name, description);
235
88
  (0, import_react.useEffect)(() => {
236
89
  if (walletAddress && !form.getValues("external_url")) {
237
90
  form.setValue("external_url", `https://medialane.io/account/${walletAddress}`);
238
91
  }
239
92
  }, [walletAddress, form]);
240
- (0, import_react.useEffect)(() => {
241
- const s = (0, import_launchpad_defaults.suggestLaunchpadSymbol)(name);
242
- if (!s) return;
243
- if (!newCollectionSymbol || newCollectionSymbol === autoSymbol) {
244
- setNewCollectionSymbol(s);
245
- setAutoSymbol(s);
246
- }
247
- if (!newCollectionName || newCollectionName === autoCollectionName) {
248
- setNewCollectionName(name);
249
- setAutoCollectionName(name);
250
- }
251
- }, [name, autoSymbol, autoCollectionName, newCollectionSymbol, newCollectionName]);
252
- const description = form.watch("description");
253
- (0, import_react.useEffect)(() => {
254
- if (!newCollectionDescription || newCollectionDescription === autoCollectionDescription) {
255
- setNewCollectionDescription(description);
256
- setAutoCollectionDescription(description);
257
- }
258
- }, [description, autoCollectionDescription, newCollectionDescription]);
259
93
  const erc721Collections = (0, import_mintable_collections.mintableCollections)("single", collections);
260
94
  const erc1155Collections = (0, import_mintable_collections.mintableCollections)("editions", collections);
95
+ const uploadFile = async (file, kind) => {
96
+ const token = await getUploadToken();
97
+ if (!token) throw new Error("Sign in first");
98
+ return (await (0, import_ipfs_upload.uploadFileToIpfs)(client.api, file, kind)).uri;
99
+ };
261
100
  const handleMediaSelect = async (file) => {
262
- const kind = detectMediaKind(file.type);
101
+ const kind = (0, import_media_kind.detectMediaKind)(file.type);
263
102
  if (!kind) {
264
103
  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).");
265
104
  return;
@@ -268,83 +107,29 @@ function FastMint(props) {
268
107
  setErrorMsg(`Please upload a${mediaKindLock === "image" ? "n" : ""} ${mediaKindLock}.`);
269
108
  return;
270
109
  }
271
- const viaMediaRoute = MEDIA_ROUTE_MIME_TYPES.has(file.type);
272
- const fileError = (0, import_upload_limits.uploadError)(file, viaMediaRoute ? "media" : "document");
110
+ const route = import_media_kind.MEDIA_ROUTE_MIME_TYPES.has(file.type) ? "media" : "document";
111
+ const fileError = (0, import_upload_limits.uploadError)(file, route);
273
112
  if (fileError) {
274
113
  setErrorMsg(fileError);
275
114
  return;
276
115
  }
277
116
  setMediaFile(file);
278
117
  setMediaKind(kind);
279
- setIpType(IP_TYPE_BY_KIND[kind]);
280
- if (previewUrlRef.current) URL.revokeObjectURL(previewUrlRef.current);
281
- const objectUrl = URL.createObjectURL(file);
282
- previewUrlRef.current = objectUrl;
283
- setMediaPreview(objectUrl);
284
- setMediaUri(null);
285
- setMediaUploading(true);
286
- try {
287
- const token = await getUploadToken();
288
- if (!token) throw new Error("Sign in first");
289
- const { uri } = await (0, import_ipfs_upload.uploadFileToIpfs)(client.api, file, viaMediaRoute ? "media" : "document");
290
- setMediaUri(uri);
291
- } catch (err) {
292
- const t = (0, import_ipfs_upload.uploadFailureToast)(err);
293
- setErrorMsg(t.description ?? t.title);
294
- } finally {
295
- setMediaUploading(false);
296
- }
118
+ setIpType(import_media_kind.IP_TYPE_BY_KIND[kind]);
119
+ await media.start(file, (f) => uploadFile(f, route), setErrorMsg);
297
120
  };
298
121
  const clearMedia = () => {
299
122
  setMediaFile(null);
300
- setMediaPreview(null);
301
- setMediaUri(null);
123
+ media.clear();
302
124
  if (mediaInputRef.current) mediaInputRef.current.value = "";
303
125
  };
304
- const handleFeatureSelect = async (file) => {
305
- if (featurePreviewRef.current) URL.revokeObjectURL(featurePreviewRef.current);
306
- const objectUrl = URL.createObjectURL(file);
307
- featurePreviewRef.current = objectUrl;
308
- setFeaturePreview(objectUrl);
309
- setFeatureUri(null);
310
- setFeatureUploading(true);
311
- try {
312
- const token = await getUploadToken();
313
- if (!token) throw new Error("Sign in first");
314
- const { uri } = await (0, import_ipfs_upload.uploadFileToIpfs)(client.api, file, "image");
315
- setFeatureUri(uri);
316
- } catch (err) {
317
- const t = (0, import_ipfs_upload.uploadFailureToast)(err);
318
- setErrorMsg(t.description ?? t.title);
319
- } finally {
320
- setFeatureUploading(false);
321
- }
322
- };
323
- const handleLicenseChange = (value) => {
324
- form.setValue("licenseType", value);
325
- const def = import_ip.LICENSE_TYPES.find((l) => l.value === value);
326
- if (def) {
327
- form.setValue("commercialUse", def.commercialUse);
328
- form.setValue("derivatives", def.derivatives);
329
- form.setValue("attribution", def.attribution);
330
- }
331
- };
332
- 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);
333
- async function pollForNewCollection(name2, symbol) {
334
- for (let attempt = 0; attempt < 8; attempt++) {
335
- const list = await refetchCollections();
336
- const match = list.find((c) => c.name === name2 && c.symbol === symbol);
337
- if (match?.collectionId) return match;
338
- await new Promise((r) => setTimeout(r, 1500));
339
- }
340
- return null;
341
- }
126
+ const ready = !!media.uri && !media.uploading && name.trim().length > 0 && (mediaKind === "image" || !!feature.uri) && (collectionMode === "existing" ? assetType === "single" ? !!existingCollectionId : !!existingCollectionContract : draft.name.trim().length > 0 && draft.symbol.trim().length > 0);
342
127
  const onSubmit = async (values) => {
343
128
  if (!hasWallet) {
344
129
  onRequireWallet();
345
130
  return;
346
131
  }
347
- if (!walletAddress || !mediaUri) return;
132
+ if (!walletAddress || !media.uri) return;
348
133
  if (values.external_url && !values.external_url.startsWith("http://") && !values.external_url.startsWith("https://")) {
349
134
  setErrorMsg("External link must start with http:// or https://");
350
135
  return;
@@ -352,93 +137,24 @@ function FastMint(props) {
352
137
  setStatus("minting");
353
138
  setErrorMsg(null);
354
139
  try {
355
- const signer = await getSigner();
356
- const image = mediaKind === "image" ? mediaUri : featureUri;
357
- const animationUrl = mediaKind === "image" ? void 0 : mediaUri;
358
- const built = (0, import_sdk.buildAssetMetadata)({
359
- name: values.name,
360
- description: values.description || "",
361
- externalUrl: values.external_url || "",
362
- imageUri: image,
363
- creator: walletAddress,
140
+ const asset = await (0, import_mint_asset.mintAsset)({
141
+ client,
142
+ signer: await getSigner(),
143
+ walletAddress,
144
+ values,
364
145
  ipType,
365
- licenseType: values.licenseType,
366
- commercialUse: values.commercialUse,
367
- derivatives: values.derivatives,
368
- attribution: values.attribution,
369
- geographicScope: values.geographicScope,
370
- aiPolicy: values.aiPolicy,
371
- royalty: String(values.royalty),
372
- templateTraits: templateFieldsRef.current.filter(({ traitType, value }) => traitType.trim() && value.trim()).map(({ traitType, value }) => ({ traitType, value }))
146
+ templateFields: templateFieldsRef.current,
147
+ mediaKind,
148
+ mediaUri: media.uri,
149
+ featureUri: feature.uri,
150
+ assetType,
151
+ editionCount,
152
+ destination: collectionMode === "new" ? { mode: "new", name: draft.name, symbol: draft.symbol, description: draft.description } : { mode: "existing", collectionId: existingCollectionId, collectionContract: existingCollectionContract },
153
+ singleCollections: erc721Collections,
154
+ refetchCollections,
155
+ getUploadToken
373
156
  });
374
- const metadata = { ...built };
375
- if (animationUrl) metadata.animation_url = animationUrl;
376
- const uploadToken = await getUploadToken();
377
- if (!uploadToken) throw new Error("Sign in first");
378
- const tokenUri = await (0, import_ipfs_upload.uploadJsonToIpfs)(client.api, metadata);
379
- let result;
380
- let finalContractAddress;
381
- let finalTokenId = null;
382
- if (assetType === "single") {
383
- let collectionId = existingCollectionId;
384
- let contractAddress = erc721Collections.find((c) => c.collectionId === existingCollectionId)?.contractAddress ?? null;
385
- if (collectionMode === "new") {
386
- const intentRes2 = await client.api.intents.create("create-collection", {
387
- owner: walletAddress,
388
- name: newCollectionName,
389
- symbol: newCollectionSymbol,
390
- description: newCollectionDescription || void 0,
391
- image
392
- });
393
- await (0, import_starknet.executeIntent)(signer, client, intentRes2);
394
- const found = await pollForNewCollection(newCollectionName, newCollectionSymbol);
395
- if (!found) throw new Error("Collection created, but it's still indexing \u2014 try minting again in a moment from My Collections.");
396
- collectionId = found.collectionId;
397
- contractAddress = found.contractAddress ?? null;
398
- }
399
- const intentRes = await client.api.intents.create("mint", {
400
- owner: walletAddress,
401
- collectionId,
402
- recipient: walletAddress,
403
- tokenUri,
404
- royaltyBps: Math.round(values.royalty * 100)
405
- });
406
- result = await (0, import_starknet.executeIntent)(signer, client, intentRes);
407
- finalContractAddress = contractAddress;
408
- if (finalContractAddress) {
409
- finalTokenId = (0, import_starknet.mintedTokenIdFromReceipt)(result.receipt, finalContractAddress);
410
- }
411
- } else {
412
- let collectionContract = existingCollectionContract;
413
- if (collectionMode === "new") {
414
- const intentRes2 = await client.api.intents.create("create-collection", {
415
- owner: walletAddress,
416
- name: newCollectionName,
417
- symbol: newCollectionSymbol,
418
- description: newCollectionDescription || void 0,
419
- image,
420
- baseUri: "",
421
- service: "mip-erc1155"
422
- });
423
- const deployResult = await (0, import_starknet.executeIntent)(signer, client, intentRes2);
424
- const deployed = (0, import_starknet.deployedCollectionFromReceipt)(deployResult.receipt, "mip-erc1155");
425
- if (!deployed) throw new Error("Collection deployed, but its address couldn't be read \u2014 check My Collections to mint into it.");
426
- collectionContract = deployed;
427
- }
428
- const intentRes = await client.api.intents.create("mint", {
429
- owner: walletAddress,
430
- recipient: walletAddress,
431
- collectionContract,
432
- tokenUri,
433
- value: editionCount,
434
- royaltyBps: Math.round(values.royalty * 100)
435
- });
436
- result = await (0, import_starknet.executeIntent)(signer, client, intentRes);
437
- finalContractAddress = collectionContract;
438
- finalTokenId = (0, import_starknet.mintedTokenIdFromReceipt)(result.receipt, collectionContract);
439
- }
440
- if (finalContractAddress && finalTokenId) {
441
- const asset = { contract: finalContractAddress, tokenId: finalTokenId, image };
157
+ if (asset) {
442
158
  setMintedAsset(asset);
443
159
  onMinted?.(asset);
444
160
  }
@@ -454,25 +170,19 @@ function FastMint(props) {
454
170
  setMintedAsset(null);
455
171
  form.reset();
456
172
  clearMedia();
457
- setFeaturePreview(null);
458
- setFeatureUri(null);
173
+ feature.clear();
459
174
  setAssetType("single");
460
175
  setEditionCount("10");
461
176
  setCollectionMode("existing");
462
177
  setExistingCollectionId("");
463
178
  setExistingCollectionContract("");
464
- setNewCollectionName("");
465
- setNewCollectionSymbol("");
466
- setNewCollectionDescription("");
467
- setAutoSymbol("");
468
- setAutoCollectionName("");
469
- setAutoCollectionDescription("");
179
+ draft.reset();
470
180
  templateFieldsRef.current = [];
471
181
  };
472
182
  const busy = status === "minting";
473
- const KindIcon = MEDIA_KIND_ICON[mediaKind];
183
+ const previewImage = mediaKind === "image" ? media.preview : feature.preview;
474
184
  const selectedExistingCollection = assetType === "single" ? erc721Collections.find((c) => c.collectionId === existingCollectionId) : erc1155Collections.find((c) => c.contractAddress === existingCollectionContract);
475
- const collectionLabel = mediaUri ? collectionMode === "new" ? newCollectionName || "New collection" : selectedExistingCollection?.name || "IP Asset" : void 0;
185
+ const collectionLabel = media.uri ? collectionMode === "new" ? draft.name || "New collection" : selectedExistingCollection?.name || "IP Asset" : void 0;
476
186
  const wrap = (node) => {
477
187
  if (presentation !== "dialog") return node;
478
188
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dialog.Dialog, { open, onOpenChange: (next) => {
@@ -490,7 +200,7 @@ function FastMint(props) {
490
200
  {
491
201
  footer: successFooter,
492
202
  presentation,
493
- previewImage: mediaKind === "image" ? mediaPreview : featurePreview,
203
+ previewImage,
494
204
  name,
495
205
  collectionLabel,
496
206
  mintedAsset,
@@ -514,53 +224,23 @@ function FastMint(props) {
514
224
  )
515
225
  );
516
226
  }
227
+ const submitBlocked = !ready || busy || !hasWallet;
517
228
  return wrap(
518
229
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "space-y-6", children: [
519
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-4 rounded-xl border border-border p-3", children: [
520
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative h-14 w-14 rounded-lg bg-muted overflow-hidden shrink-0", children: [
521
- 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" }) }),
522
- 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" }) })
523
- ] }),
524
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "min-w-0 flex-1 space-y-1", children: [
525
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm font-semibold truncate", children: mediaFile.name }),
526
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-2 flex-wrap", children: [
527
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-xs text-muted-foreground", children: mediaUploading ? "Uploading\u2026" : mediaUri ? "Uploaded" : "Upload failed" }),
528
- mediaUri && (() => {
529
- const template = import_ip_templates.IP_TEMPLATES[ipType];
530
- const TemplateIcon = template.icon;
531
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
532
- "span",
533
- {
534
- className: (0, import_cn.cn)(
535
- "inline-flex shrink-0 items-center gap-1 rounded-full border px-2 py-0.5 text-2xs font-medium",
536
- template.color.bg,
537
- template.color.text,
538
- template.color.border
539
- ),
540
- children: [
541
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TemplateIcon, { className: "h-3 w-3" }),
542
- template.label
543
- ]
544
- }
545
- );
546
- })()
547
- ] })
548
- ] }),
549
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
550
- "button",
551
- {
552
- type: "button",
553
- onClick: () => mediaInputRef.current?.click(),
554
- className: "text-xs font-semibold text-brand-blue hover:underline shrink-0",
555
- children: "Change"
556
- }
557
- ),
558
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { ref: mediaInputRef, type: "file", className: "hidden", onChange: (e) => {
559
- const f = e.target.files?.[0];
560
- if (f) handleMediaSelect(f);
561
- } })
562
- ] }),
563
- mediaUri && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "grid grid-cols-1 lg:grid-cols-[1fr_320px] gap-8 items-start", children: [
230
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
231
+ import_asset_form_parts.MediaRow,
232
+ {
233
+ file: mediaFile,
234
+ kind: mediaKind,
235
+ preview: media.preview,
236
+ uri: media.uri,
237
+ uploading: media.uploading,
238
+ ipType,
239
+ inputRef: mediaInputRef,
240
+ onSelect: handleMediaSelect
241
+ }
242
+ ),
243
+ media.uri && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "grid grid-cols-1 lg:grid-cols-[1fr_320px] gap-8 items-start", children: [
564
244
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-5", children: [
565
245
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
566
246
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-sm font-medium", children: "Title *" }),
@@ -578,7 +258,7 @@ function FastMint(props) {
578
258
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
579
259
  import_textarea.Textarea,
580
260
  {
581
- value: form.watch("description"),
261
+ value: description,
582
262
  onChange: (e) => form.setValue("description", e.target.value),
583
263
  placeholder: "Describe your work, its story, and any context for buyers\u2026",
584
264
  rows: 3
@@ -599,277 +279,60 @@ function FastMint(props) {
599
279
  }
600
280
  )
601
281
  ] }),
602
- mediaKind !== "image" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
603
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-sm font-medium", children: "Upload a cover image for your asset *" }),
604
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-4", children: [
605
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
606
- "div",
607
- {
608
- role: "button",
609
- tabIndex: 0,
610
- onClick: () => !featureUploading && featureInputRef.current?.click(),
611
- onKeyDown: (e) => {
612
- if ((e.key === "Enter" || e.key === " ") && !featureUploading) {
613
- e.preventDefault();
614
- featureInputRef.current?.click();
615
- }
616
- },
617
- 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",
618
- children: [
619
- 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" }),
620
- 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" }) }),
621
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { ref: featureInputRef, type: "file", accept: (0, import_upload_limits.acceptFor)("image"), className: "hidden", onChange: (e) => {
622
- const f = e.target.files?.[0];
623
- if (f) handleFeatureSelect(f);
624
- } })
625
- ]
626
- }
627
- ),
628
- /* @__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." })
629
- ] })
630
- ] }),
631
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
632
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-sm font-medium", children: "Asset Type" }),
633
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "grid grid-cols-2 gap-3", children: [
634
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
635
- "button",
636
- {
637
- type: "button",
638
- onClick: () => setAssetType("single"),
639
- className: (0, import_cn.cn)(
640
- "flex items-start gap-3 rounded-xl border p-4 text-left transition-colors",
641
- assetType === "single" ? "border-brand-blue bg-brand-blue/5" : "border-border hover:bg-muted/40"
642
- ),
643
- children: [
644
- /* @__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") }),
645
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
646
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "block text-sm font-semibold", children: "Single Edition NFT" }),
647
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "block text-xs mt-0.5 text-muted-foreground", children: "Minted once" })
648
- ] })
649
- ]
650
- }
651
- ),
652
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
653
- "button",
654
- {
655
- type: "button",
656
- onClick: () => setAssetType("editions"),
657
- className: (0, import_cn.cn)(
658
- "flex items-start gap-3 rounded-xl border p-4 text-left transition-colors",
659
- assetType === "editions" ? "border-brand-blue bg-brand-blue/5" : "border-border hover:bg-muted/40"
660
- ),
661
- children: [
662
- /* @__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") }),
663
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
664
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "block text-sm font-semibold", children: "Limited Editions NFT" }),
665
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "block text-xs mt-0.5 text-muted-foreground", children: "Several numbered copies" })
666
- ] })
667
- ]
668
- }
669
- )
670
- ] })
671
- ] }),
672
- assetType === "editions" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
673
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-sm font-medium", children: "Number of copies" }),
674
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
675
- import_input.Input,
676
- {
677
- type: "number",
678
- min: 1,
679
- value: editionCount,
680
- onChange: (e) => setEditionCount(e.target.value),
681
- className: "max-w-[140px]"
682
- }
683
- )
684
- ] }),
685
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-2", children: [
686
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between", children: [
687
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "text-sm font-medium flex items-center gap-1.5", children: [
688
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Boxes, { className: "h-4 w-4" }),
689
- "Collection *"
690
- ] }),
691
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex rounded-lg border border-border overflow-hidden", children: [
692
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
693
- "button",
694
- {
695
- type: "button",
696
- onClick: () => setCollectionMode("existing"),
697
- className: (0, import_cn.cn)(
698
- "px-3 h-7 text-xs font-medium transition-colors",
699
- collectionMode === "existing" ? "bg-primary text-primary-foreground" : "bg-background hover:bg-muted text-muted-foreground"
700
- ),
701
- children: "Existing"
702
- }
703
- ),
704
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
705
- "button",
706
- {
707
- type: "button",
708
- onClick: () => setCollectionMode("new"),
709
- className: (0, import_cn.cn)(
710
- "px-3 h-7 text-xs font-medium border-l border-border transition-colors flex items-center gap-1",
711
- collectionMode === "new" ? "bg-primary text-primary-foreground" : "bg-background hover:bg-muted text-muted-foreground"
712
- ),
713
- children: [
714
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Plus, { className: "h-3 w-3" }),
715
- "New"
716
- ]
717
- }
718
- )
719
- ] })
720
- ] }),
721
- collectionMode === "existing" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
722
- CollectionPicker,
723
- {
724
- collections: assetType === "single" ? erc721Collections : erc1155Collections,
725
- value: assetType === "single" ? existingCollectionId : existingCollectionContract,
726
- onChange: assetType === "single" ? setExistingCollectionId : setExistingCollectionContract,
727
- valueOf: (0, import_mintable_collections.collectionKey)(assetType === "single" ? "single" : "editions")
728
- }
729
- ) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex gap-3 rounded-xl border border-border p-3", children: [
730
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "relative h-16 w-16 rounded-lg overflow-hidden bg-muted shrink-0", children: (mediaKind === "image" ? mediaPreview : featurePreview) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
731
- import_image.default,
732
- {
733
- src: mediaKind === "image" ? mediaPreview : featurePreview,
734
- alt: "",
735
- fill: true,
736
- className: "object-cover",
737
- unoptimized: true
738
- }
739
- ) : /* @__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-5 w-5 text-muted-foreground/40" }) }) }),
740
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "min-w-0 flex-1 space-y-2", children: [
741
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "grid grid-cols-[1fr_100px] gap-2", children: [
742
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
743
- import_input.Input,
744
- {
745
- value: newCollectionName,
746
- onChange: (e) => setNewCollectionName(e.target.value),
747
- placeholder: "Collection name",
748
- className: "h-9 text-sm"
749
- }
750
- ),
751
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
752
- import_input.Input,
753
- {
754
- value: newCollectionSymbol,
755
- onChange: (e) => setNewCollectionSymbol(e.target.value.toUpperCase()),
756
- placeholder: "SYMBOL",
757
- className: "h-9 text-sm"
758
- }
759
- )
760
- ] }),
761
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
762
- import_textarea.Textarea,
763
- {
764
- value: newCollectionDescription,
765
- onChange: (e) => setNewCollectionDescription(e.target.value),
766
- placeholder: "Describe this collection\u2026",
767
- rows: 2,
768
- className: "text-sm resize-none"
769
- }
770
- ),
771
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-2xs text-muted-foreground", children: "Prefilled from your asset \u2014 edit anything above." })
772
- ] })
773
- ] })
774
- ] }),
775
- /* @__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: [
776
- /* @__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: [
777
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "flex items-center gap-2", children: [
778
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ShieldCheck, { className: "h-4 w-4 text-primary" }),
779
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-sm font-semibold", children: "Licensing Terms" }),
780
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xs text-muted-foreground font-normal", children: "Optional \xB7 Berne Convention" })
781
- ] }),
782
- /* @__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") })
783
- ] }) }),
784
- /* @__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: [
785
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-1.5", children: [
786
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-xs font-medium text-muted-foreground", children: "License" }),
787
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_select.Select, { value: form.watch("licenseType"), onValueChange: handleLicenseChange, children: [
788
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectValue, {}) }),
789
- /* @__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)) })
790
- ] })
791
- ] }),
792
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-1.5", children: [
793
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-xs font-medium text-muted-foreground", children: "Commercial use" }),
794
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToggleGroup, { value: form.watch("commercialUse"), options: ["Yes", "No"], onChange: (v) => form.setValue("commercialUse", v) })
795
- ] }),
796
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-1.5", children: [
797
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-xs font-medium text-muted-foreground", children: "Derivatives" }),
798
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToggleGroup, { value: form.watch("derivatives"), options: import_ip.DERIVATIVES_OPTIONS, onChange: (v) => form.setValue("derivatives", v) })
799
- ] }),
800
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-1.5", children: [
801
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-xs font-medium text-muted-foreground", children: "Territory" }),
802
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_select.Select, { value: form.watch("geographicScope"), onValueChange: (v) => form.setValue("geographicScope", v), children: [
803
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectValue, {}) }),
804
- /* @__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)) })
805
- ] })
806
- ] }),
807
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-1.5", children: [
808
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-xs font-medium text-muted-foreground", children: "AI & data mining" }),
809
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToggleGroup, { value: form.watch("aiPolicy"), options: import_ip.AI_POLICIES, onChange: (v) => form.setValue("aiPolicy", v) })
810
- ] }),
811
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-1.5", children: [
812
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-xs font-medium text-muted-foreground", children: "Royalty % (0\u201350)" }),
813
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
814
- import_input.Input,
815
- {
816
- type: "number",
817
- min: 0,
818
- max: 50,
819
- step: 0.5,
820
- value: form.watch("royalty"),
821
- onChange: (e) => form.setValue("royalty", parseFloat(e.target.value) || 0),
822
- className: "max-w-[120px]"
823
- }
824
- )
825
- ] })
826
- ] }) })
827
- ] }) }),
828
- /* @__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: [
829
- /* @__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: [
830
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "flex items-center gap-2", children: [
831
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Layers, { className: "h-4 w-4 text-primary" }),
832
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-sm font-semibold", children: "IP Type & Metadata" }),
833
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-xs text-muted-foreground font-normal", children: "Optional" })
834
- ] }),
835
- /* @__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") })
836
- ] }) }),
837
- /* @__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: [
838
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-1.5", children: [
839
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: "text-xs font-medium text-muted-foreground", children: "IP Type" }),
840
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_select.Select, { value: ipType, onValueChange: (v) => setIpType(v), children: [
841
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_select.SelectValue, {}) }),
842
- /* @__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)) })
843
- ] })
844
- ] }),
845
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
846
- import_ip_type_fields.IPTypeFields,
847
- {
848
- ipType,
849
- onChange: (fields) => {
850
- templateFieldsRef.current = fields;
851
- },
852
- uploadDocument: async (file) => {
853
- const token = await getUploadToken();
854
- if (!token) throw new Error("Sign in first");
855
- const { uri } = await (0, import_ipfs_upload.uploadFileToIpfs)(client.api, file, "document");
856
- return uri;
857
- },
858
- existingDocument: mediaKind === "document" && mediaUri && mediaFile ? { uri: mediaUri, name: mediaFile.name } : null
859
- }
860
- )
861
- ] }) })
862
- ] }) }),
282
+ mediaKind !== "image" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
283
+ import_asset_form_parts.CoverUpload,
284
+ {
285
+ preview: feature.preview,
286
+ uploading: feature.uploading,
287
+ inputRef: featureInputRef,
288
+ onSelect: (file) => void feature.start(file, (f) => uploadFile(f, "image"), setErrorMsg)
289
+ }
290
+ ),
291
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
292
+ import_asset_form_parts.AssetTypePicker,
293
+ {
294
+ value: assetType,
295
+ onChange: setAssetType,
296
+ editionCount,
297
+ onEditionCount: setEditionCount
298
+ }
299
+ ),
300
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
301
+ import_collection_section.CollectionSection,
302
+ {
303
+ assetType,
304
+ mode: collectionMode,
305
+ onModeChange: setCollectionMode,
306
+ collections: assetType === "single" ? erc721Collections : erc1155Collections,
307
+ existingId: existingCollectionId,
308
+ existingContract: existingCollectionContract,
309
+ onExistingId: setExistingCollectionId,
310
+ onExistingContract: setExistingCollectionContract,
311
+ draft,
312
+ previewImage
313
+ }
314
+ ),
315
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_licensing_section.LicensingSection, { form }),
316
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
317
+ import_ip_type_section.IpTypeSection,
318
+ {
319
+ ipType,
320
+ onIpTypeChange: setIpType,
321
+ fieldsRef: templateFieldsRef,
322
+ uploadDocument: (file) => uploadFile(file, "document"),
323
+ existingDocument: mediaKind === "document" ? { uri: media.uri, name: mediaFile.name } : null
324
+ }
325
+ ),
863
326
  status === "error" && errorMsg && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-xs text-destructive", children: errorMsg }),
864
327
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
865
328
  "button",
866
329
  {
867
330
  type: "button",
868
- disabled: !ready || busy || !hasWallet,
331
+ disabled: submitBlocked,
869
332
  onClick: form.handleSubmit(onSubmit),
870
333
  className: (0, import_cn.cn)(
871
334
  "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",
872
- (!ready || busy || !hasWallet) && "opacity-40 pointer-events-none"
335
+ submitBlocked && "opacity-40 pointer-events-none"
873
336
  ),
874
337
  children: busy ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
875
338
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Loader2, { className: "h-4 w-4 animate-spin" }),
@@ -882,11 +345,11 @@ function FastMint(props) {
882
345
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "order-first lg:order-last lg:sticky lg:top-20 max-w-[260px] mx-auto w-full lg:max-w-none lg:mx-0", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
883
346
  import_medialane_collection_card.MedialaneCollectionCard,
884
347
  {
885
- image: mediaKind === "image" ? mediaPreview : featurePreview,
348
+ image: previewImage,
886
349
  name,
887
350
  collection: collectionLabel,
888
351
  creator: walletAddress ? `${walletAddress.slice(0, 6)}\u2026${walletAddress.slice(-4)}` : void 0,
889
- creatorHref: walletAddress ? (0, import_sdk2.profileHref)({ address: walletAddress }) : void 0
352
+ creatorHref: walletAddress ? (0, import_sdk.profileHref)({ address: walletAddress }) : void 0
890
353
  }
891
354
  ) })
892
355
  ] })