@medialane/ui 0.104.0 → 0.106.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-collection-bar.cjs +1 -1
- package/dist/components/asset-collection-bar.cjs.map +1 -1
- package/dist/components/asset-collection-bar.js +1 -1
- package/dist/components/asset-collection-bar.js.map +1 -1
- package/dist/components/asset-lightbox.cjs +66 -0
- package/dist/components/asset-lightbox.cjs.map +1 -0
- package/dist/components/asset-lightbox.d.cts +11 -0
- package/dist/components/asset-lightbox.d.ts +11 -0
- package/dist/components/asset-lightbox.js +42 -0
- package/dist/components/asset-lightbox.js.map +1 -0
- package/dist/components/asset-marketplace-panel.cjs +19 -9
- package/dist/components/asset-marketplace-panel.cjs.map +1 -1
- package/dist/components/asset-marketplace-panel.js +19 -9
- package/dist/components/asset-marketplace-panel.js.map +1 -1
- package/dist/components/club-owner-actions.cjs +56 -0
- package/dist/components/club-owner-actions.cjs.map +1 -0
- package/dist/components/club-owner-actions.d.cts +11 -0
- package/dist/components/club-owner-actions.d.ts +11 -0
- package/dist/components/club-owner-actions.js +22 -0
- package/dist/components/club-owner-actions.js.map +1 -0
- package/dist/components/collection-hero-banner.cjs +114 -0
- package/dist/components/collection-hero-banner.cjs.map +1 -0
- package/dist/components/collection-hero-banner.d.cts +26 -0
- package/dist/components/collection-hero-banner.d.ts +26 -0
- package/dist/components/collection-hero-banner.js +90 -0
- package/dist/components/collection-hero-banner.js.map +1 -0
- package/dist/components/create-form-primitives.cjs +61 -0
- package/dist/components/create-form-primitives.cjs.map +1 -0
- package/dist/components/create-form-primitives.d.cts +16 -0
- package/dist/components/create-form-primitives.d.ts +16 -0
- package/dist/components/create-form-primitives.js +36 -0
- package/dist/components/create-form-primitives.js.map +1 -0
- package/dist/components/creation-record.cjs +86 -0
- package/dist/components/creation-record.cjs.map +1 -0
- package/dist/components/creation-record.d.cts +14 -0
- package/dist/components/creation-record.d.ts +14 -0
- package/dist/components/creation-record.js +52 -0
- package/dist/components/creation-record.js.map +1 -0
- package/dist/components/dialog.d.cts +9 -9
- package/dist/components/dialog.d.ts +9 -9
- package/dist/components/ip-type-fields.cjs +307 -0
- package/dist/components/ip-type-fields.cjs.map +1 -0
- package/dist/components/ip-type-fields.d.cts +17 -0
- package/dist/components/ip-type-fields.d.ts +17 -0
- package/dist/components/ip-type-fields.js +293 -0
- package/dist/components/ip-type-fields.js.map +1 -0
- package/dist/components/json-ld.cjs +39 -0
- package/dist/components/json-ld.cjs.map +1 -0
- package/dist/components/json-ld.d.cts +8 -0
- package/dist/components/json-ld.d.ts +8 -0
- package/dist/components/json-ld.js +15 -0
- package/dist/components/json-ld.js.map +1 -0
- package/dist/components/nav-theme-toggle.cjs +66 -0
- package/dist/components/nav-theme-toggle.cjs.map +1 -0
- package/dist/components/nav-theme-toggle.d.cts +9 -0
- package/dist/components/nav-theme-toggle.d.ts +9 -0
- package/dist/components/nav-theme-toggle.js +42 -0
- package/dist/components/nav-theme-toggle.js.map +1 -0
- package/dist/components/order-sort-control.cjs +58 -0
- package/dist/components/order-sort-control.cjs.map +1 -0
- package/dist/components/order-sort-control.d.cts +13 -0
- package/dist/components/order-sort-control.d.ts +13 -0
- package/dist/components/order-sort-control.js +39 -0
- package/dist/components/order-sort-control.js.map +1 -0
- package/dist/components/price-history-chart.cjs +130 -0
- package/dist/components/price-history-chart.cjs.map +1 -0
- package/dist/components/price-history-chart.d.cts +9 -0
- package/dist/components/price-history-chart.d.ts +9 -0
- package/dist/components/price-history-chart.js +114 -0
- package/dist/components/price-history-chart.js.map +1 -0
- package/dist/components/sheet.cjs +160 -0
- package/dist/components/sheet.cjs.map +1 -0
- package/dist/components/sheet.d.cts +30 -0
- package/dist/components/sheet.d.ts +30 -0
- package/dist/components/sheet.js +117 -0
- package/dist/components/sheet.js.map +1 -0
- package/dist/components/textarea.cjs +57 -0
- package/dist/components/textarea.cjs.map +1 -0
- package/dist/components/textarea.d.cts +6 -0
- package/dist/components/textarea.d.ts +6 -0
- package/dist/components/textarea.js +23 -0
- package/dist/components/textarea.js.map +1 -0
- package/dist/index.cjs +70 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/format-activity.cjs +143 -0
- package/dist/utils/format-activity.cjs.map +1 -0
- package/dist/utils/format-activity.d.cts +14 -0
- package/dist/utils/format-activity.d.ts +14 -0
- package/dist/utils/format-activity.js +116 -0
- package/dist/utils/format-activity.js.map +1 -0
- package/dist/utils/proxy-body.cjs +60 -0
- package/dist/utils/proxy-body.cjs.map +1 -0
- package/dist/utils/proxy-body.d.cts +22 -0
- package/dist/utils/proxy-body.d.ts +22 -0
- package/dist/utils/proxy-body.js +36 -0
- package/dist/utils/proxy-body.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/ip-type-fields.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport type { IPType } from \"../data/ip.js\";\nimport {\n IP_TEMPLATES,\n EMBED_PLATFORM_META,\n SOCIAL_PLATFORM_META,\n type TraitSuggestion,\n} from \"../data/ip-templates.js\";\nimport { Label } from \"./label.js\";\nimport { Input } from \"./input.js\";\nimport { Button } from \"./button.js\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"./select.js\";\nimport { Check, FileText, FileUp, Loader2, Plus, Trash2, X } from \"lucide-react\";\n\nexport type MetadataField = {\n traitType: string;\n value: string;\n};\n\ntype TraitRow = {\n id: string;\n key: string;\n value: string;\n options?: string[];\n};\n\nconst createId = () =>\n globalThis.crypto?.randomUUID?.() ?? `trait-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n\nconst looksLikeUrl = (v: string) => /^https?:\\/\\/\\S+/i.test(v.trim());\n\nexport interface IPTypeFieldsProps {\n ipType: IPType | null;\n onChange: (fields: MetadataField[]) => void;\n /** Uploads a document file to IPFS, resolving to its ipfs:// URI.\n * Enables the document upload field for types with template.docUpload. */\n uploadDocument?: (file: File) => Promise<string>;\n}\n\nexport function IPTypeFields({ ipType, onChange, uploadDocument }: IPTypeFieldsProps) {\n const template = ipType ? IP_TEMPLATES[ipType] : null;\n\n // URL inputs keyed by their stored trait_type (e.g. \"Spotify URL\", \"X\").\n const [embedValues, setEmbedValues] = useState<Record<string, string>>({});\n const [socialValues, setSocialValues] = useState<Record<string, string>>({});\n // One unified, ordered list of traits (suggestions pre-fill rows; custom = blank).\n const [traits, setTraits] = useState<TraitRow[]>([]);\n // Document pinned to IPFS (Documents / Patents / Publications / Software).\n const [docUri, setDocUri] = useState<string | null>(null);\n const [docName, setDocName] = useState<string | null>(null);\n const [docUploading, setDocUploading] = useState(false);\n const [docError, setDocError] = useState<string | null>(null);\n const docInputRef = useRef<HTMLInputElement>(null);\n\n // Embeds, socials & document are type-specific — reset them when the IP type\n // changes. Trait rows are generic key/value and persist across type switches.\n useEffect(() => {\n setEmbedValues({});\n setSocialValues({});\n setDocUri(null);\n setDocName(null);\n setDocError(null);\n }, [ipType]);\n\n const docTraitType = template?.docUpload?.traitType ?? null;\n\n const metadataFields = useMemo(() => {\n const fields: MetadataField[] = [];\n const seen = new Set<string>();\n const add = (traitType: string, value: string) => {\n const t = traitType.trim();\n const v = value.trim();\n const k = t.toLowerCase();\n if (!t || !v || seen.has(k)) return;\n seen.add(k);\n fields.push({ traitType: t, value: v });\n };\n if (docTraitType && docUri) add(docTraitType, docUri);\n Object.entries(embedValues).forEach(([key, value]) => add(key, value));\n Object.entries(socialValues).forEach(([key, value]) => add(key, value));\n traits.forEach((row) => add(row.key, row.value));\n return fields;\n }, [embedValues, socialValues, traits, docTraitType, docUri]);\n\n useEffect(() => {\n onChange(metadataFields);\n }, [metadataFields, onChange]);\n\n const addedKeys = useMemo(\n () => new Set(traits.map((t) => t.key.trim().toLowerCase())),\n [traits]\n );\n\n const addSuggestion = (s: TraitSuggestion) => {\n setTraits((cur) => [\n ...cur,\n { id: createId(), key: s.key, value: \"\", options: s.options },\n ]);\n };\n const addCustomTrait = () =>\n setTraits((cur) => [...cur, { id: createId(), key: \"\", value: \"\" }]);\n const updateTrait = (id: string, patch: Partial<TraitRow>) =>\n setTraits((cur) => cur.map((t) => (t.id === id ? { ...t, ...patch } : t)));\n const removeTrait = (id: string) =>\n setTraits((cur) => cur.filter((t) => t.id !== id));\n\n if (!template) return null;\n\n const Icon = template.icon;\n const docUpload = template.docUpload;\n\n const handleDocPick = async (file: File) => {\n if (!uploadDocument || !docUpload) return;\n if (file.size > docUpload.maxMb * 1024 * 1024) {\n setDocError(`File must be under ${docUpload.maxMb} MB`);\n return;\n }\n setDocError(null);\n setDocUploading(true);\n try {\n const uri = await uploadDocument(file);\n setDocUri(uri);\n setDocName(file.name);\n } catch (err) {\n setDocError(err instanceof Error ? err.message : \"Document upload failed\");\n } finally {\n setDocUploading(false);\n if (docInputRef.current) docInputRef.current.value = \"\";\n }\n };\n\n const clearDoc = () => {\n setDocUri(null);\n setDocName(null);\n setDocError(null);\n };\n\n return (\n <div className=\"space-y-5\">\n <div className=\"flex items-center gap-2\">\n <Icon className={`h-4 w-4 ${template.color.text}`} />\n <p className=\"text-sm font-semibold\">{template.label} Details</p>\n </div>\n\n {/* ── Document file → IPFS (Documents / Patents / Publications / Software) ── */}\n {docUpload && uploadDocument && (\n <section className=\"space-y-2\">\n <p className=\"text-[11px] font-semibold text-muted-foreground\">\n Document\n </p>\n {docUri ? (\n <div className=\"flex items-center gap-3 rounded-xl border border-emerald-500/30 bg-emerald-500/5 px-4 py-3\">\n <FileText className=\"h-5 w-5 text-emerald-500 shrink-0\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium truncate\">{docName}</p>\n <p className=\"text-xs text-muted-foreground truncate\">{docUri}</p>\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 shrink-0 text-muted-foreground hover:text-destructive\"\n onClick={clearDoc}\n aria-label=\"Remove document\"\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n ) : (\n <div className=\"space-y-1.5\">\n <input\n ref={docInputRef}\n type=\"file\"\n accept={docUpload.accept}\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) void handleDocPick(f);\n }}\n />\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n disabled={docUploading}\n onClick={() => docInputRef.current?.click()}\n >\n {docUploading ? (\n <>\n <Loader2 className=\"mr-1.5 h-3.5 w-3.5 animate-spin\" />\n Uploading…\n </>\n ) : (\n <>\n <FileUp className=\"mr-1.5 h-3.5 w-3.5\" />\n Upload document\n </>\n )}\n </Button>\n {docError && <p className=\"text-xs text-destructive\">{docError}</p>}\n <p className=\"text-xs text-muted-foreground leading-relaxed\">{docUpload.hint}</p>\n </div>\n )}\n </section>\n )}\n\n {/* ── Embeds (inline players) ─────────────────────────────── */}\n {template.embeds && template.embeds.length > 0 && (\n <section className=\"space-y-3\">\n <p className=\"text-[11px] font-semibold text-muted-foreground\">Embeds</p>\n {template.embeds.map((platform) => {\n const meta = EMBED_PLATFORM_META[platform];\n const PIcon = meta.icon;\n const value = embedValues[meta.traitKey] ?? \"\";\n return (\n <div key={platform} className=\"space-y-1.5\">\n <Label className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <PIcon className=\"h-3.5 w-3.5\" />\n {meta.label}\n {looksLikeUrl(value) && (\n <span className=\"ml-1 inline-flex items-center gap-0.5 text-[10px] font-medium text-emerald-400\">\n <Check className=\"h-3 w-3\" /> connected\n </span>\n )}\n </Label>\n <Input\n type=\"url\"\n inputMode=\"url\"\n placeholder={meta.placeholder}\n value={value}\n onChange={(e) =>\n setEmbedValues((cur) => ({ ...cur, [meta.traitKey]: e.target.value }))\n }\n className=\"h-10 text-sm\"\n />\n </div>\n );\n })}\n </section>\n )}\n\n {/* ── Social links (icon chips on the asset page) ─────────── */}\n {template.socials && template.socials.length > 0 && (\n <section className=\"space-y-3\">\n <p className=\"text-[11px] font-semibold text-muted-foreground\">Social links</p>\n {template.socials.map((platform) => {\n const meta = SOCIAL_PLATFORM_META[platform];\n const PIcon = meta.icon;\n const value = socialValues[meta.traitKey] ?? \"\";\n return (\n <div key={platform} className=\"space-y-1.5\">\n <Label className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <PIcon className=\"h-3.5 w-3.5\" />\n {meta.label}\n </Label>\n <Input\n type=\"url\"\n inputMode=\"url\"\n placeholder={meta.placeholder}\n value={value}\n onChange={(e) =>\n setSocialValues((cur) => ({ ...cur, [meta.traitKey]: e.target.value }))\n }\n className=\"h-10 text-sm\"\n />\n </div>\n );\n })}\n </section>\n )}\n\n {/* ── Traits ───────────────────────────────────────────────── */}\n <section className=\"space-y-3 border-t border-border/60 pt-4\">\n <p className=\"text-sm font-semibold\">Traits</p>\n\n {/* Suggestion chips */}\n {template.traitSuggestions && template.traitSuggestions.length > 0 && (\n <div className=\"flex flex-wrap gap-2\">\n {template.traitSuggestions\n .filter((s) => !addedKeys.has(s.key.toLowerCase()))\n .map((s) => (\n <button\n key={s.key}\n type=\"button\"\n onClick={() => addSuggestion(s)}\n className=\"inline-flex items-center gap-1 rounded-full border border-border bg-muted/40 px-3 py-1 text-xs font-medium text-muted-foreground transition-colors hover:border-primary/40 hover:text-foreground\"\n >\n <Plus className=\"h-3 w-3\" />\n {s.key}\n </button>\n ))}\n </div>\n )}\n\n {/* Trait rows — one trait per card, inputs stacked (mobile-first) */}\n {traits.length > 0 && (\n <div className=\"space-y-2\">\n {traits.map((row) => (\n <div\n key={row.id}\n className=\"grid grid-cols-[1fr_1fr_auto] items-center gap-2\"\n >\n <Input\n value={row.key}\n onChange={(e) => updateTrait(row.id, { key: e.target.value })}\n placeholder=\"Trait name\"\n className=\"h-9 text-sm\"\n maxLength={64}\n />\n {row.options ? (\n <Select\n value={row.value}\n onValueChange={(v) => updateTrait(row.id, { value: v })}\n >\n <SelectTrigger className=\"h-9 text-sm\">\n <SelectValue placeholder=\"Value\" />\n </SelectTrigger>\n <SelectContent>\n {row.options.map((opt) => (\n <SelectItem key={opt} value={opt}>{opt}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : (\n <Input\n value={row.value}\n onChange={(e) => updateTrait(row.id, { value: e.target.value })}\n placeholder=\"Value\"\n className=\"h-9 text-sm\"\n maxLength={512}\n />\n )}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-9 w-9 shrink-0 text-muted-foreground hover:text-destructive\"\n onClick={() => removeTrait(row.id)}\n aria-label=\"Remove trait\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n ))}\n </div>\n )}\n\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={addCustomTrait}>\n <Plus className=\"mr-1.5 h-3.5 w-3.5\" />\n Add custom trait\n </Button>\n </section>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { IPType } from '../data/ip.cjs';
|
|
3
|
+
|
|
4
|
+
type MetadataField = {
|
|
5
|
+
traitType: string;
|
|
6
|
+
value: string;
|
|
7
|
+
};
|
|
8
|
+
interface IPTypeFieldsProps {
|
|
9
|
+
ipType: IPType | null;
|
|
10
|
+
onChange: (fields: MetadataField[]) => void;
|
|
11
|
+
/** Uploads a document file to IPFS, resolving to its ipfs:// URI.
|
|
12
|
+
* Enables the document upload field for types with template.docUpload. */
|
|
13
|
+
uploadDocument?: (file: File) => Promise<string>;
|
|
14
|
+
}
|
|
15
|
+
declare function IPTypeFields({ ipType, onChange, uploadDocument }: IPTypeFieldsProps): react_jsx_runtime.JSX.Element | null;
|
|
16
|
+
|
|
17
|
+
export { IPTypeFields, type IPTypeFieldsProps, type MetadataField };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { IPType } from '../data/ip.js';
|
|
3
|
+
|
|
4
|
+
type MetadataField = {
|
|
5
|
+
traitType: string;
|
|
6
|
+
value: string;
|
|
7
|
+
};
|
|
8
|
+
interface IPTypeFieldsProps {
|
|
9
|
+
ipType: IPType | null;
|
|
10
|
+
onChange: (fields: MetadataField[]) => void;
|
|
11
|
+
/** Uploads a document file to IPFS, resolving to its ipfs:// URI.
|
|
12
|
+
* Enables the document upload field for types with template.docUpload. */
|
|
13
|
+
uploadDocument?: (file: File) => Promise<string>;
|
|
14
|
+
}
|
|
15
|
+
declare function IPTypeFields({ ipType, onChange, uploadDocument }: IPTypeFieldsProps): react_jsx_runtime.JSX.Element | null;
|
|
16
|
+
|
|
17
|
+
export { IPTypeFields, type IPTypeFieldsProps, type MetadataField };
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
+
import {
|
|
5
|
+
IP_TEMPLATES,
|
|
6
|
+
EMBED_PLATFORM_META,
|
|
7
|
+
SOCIAL_PLATFORM_META
|
|
8
|
+
} from "../data/ip-templates.js";
|
|
9
|
+
import { Label } from "./label.js";
|
|
10
|
+
import { Input } from "./input.js";
|
|
11
|
+
import { Button } from "./button.js";
|
|
12
|
+
import {
|
|
13
|
+
Select,
|
|
14
|
+
SelectContent,
|
|
15
|
+
SelectItem,
|
|
16
|
+
SelectTrigger,
|
|
17
|
+
SelectValue
|
|
18
|
+
} from "./select.js";
|
|
19
|
+
import { Check, FileText, FileUp, Loader2, Plus, Trash2, X } from "lucide-react";
|
|
20
|
+
const createId = () => globalThis.crypto?.randomUUID?.() ?? `trait-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
21
|
+
const looksLikeUrl = (v) => /^https?:\/\/\S+/i.test(v.trim());
|
|
22
|
+
function IPTypeFields({ ipType, onChange, uploadDocument }) {
|
|
23
|
+
const template = ipType ? IP_TEMPLATES[ipType] : null;
|
|
24
|
+
const [embedValues, setEmbedValues] = useState({});
|
|
25
|
+
const [socialValues, setSocialValues] = useState({});
|
|
26
|
+
const [traits, setTraits] = useState([]);
|
|
27
|
+
const [docUri, setDocUri] = useState(null);
|
|
28
|
+
const [docName, setDocName] = useState(null);
|
|
29
|
+
const [docUploading, setDocUploading] = useState(false);
|
|
30
|
+
const [docError, setDocError] = useState(null);
|
|
31
|
+
const docInputRef = useRef(null);
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
setEmbedValues({});
|
|
34
|
+
setSocialValues({});
|
|
35
|
+
setDocUri(null);
|
|
36
|
+
setDocName(null);
|
|
37
|
+
setDocError(null);
|
|
38
|
+
}, [ipType]);
|
|
39
|
+
const docTraitType = template?.docUpload?.traitType ?? null;
|
|
40
|
+
const metadataFields = useMemo(() => {
|
|
41
|
+
const fields = [];
|
|
42
|
+
const seen = /* @__PURE__ */ new Set();
|
|
43
|
+
const add = (traitType, value) => {
|
|
44
|
+
const t = traitType.trim();
|
|
45
|
+
const v = value.trim();
|
|
46
|
+
const k = t.toLowerCase();
|
|
47
|
+
if (!t || !v || seen.has(k)) return;
|
|
48
|
+
seen.add(k);
|
|
49
|
+
fields.push({ traitType: t, value: v });
|
|
50
|
+
};
|
|
51
|
+
if (docTraitType && docUri) add(docTraitType, docUri);
|
|
52
|
+
Object.entries(embedValues).forEach(([key, value]) => add(key, value));
|
|
53
|
+
Object.entries(socialValues).forEach(([key, value]) => add(key, value));
|
|
54
|
+
traits.forEach((row) => add(row.key, row.value));
|
|
55
|
+
return fields;
|
|
56
|
+
}, [embedValues, socialValues, traits, docTraitType, docUri]);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
onChange(metadataFields);
|
|
59
|
+
}, [metadataFields, onChange]);
|
|
60
|
+
const addedKeys = useMemo(
|
|
61
|
+
() => new Set(traits.map((t) => t.key.trim().toLowerCase())),
|
|
62
|
+
[traits]
|
|
63
|
+
);
|
|
64
|
+
const addSuggestion = (s) => {
|
|
65
|
+
setTraits((cur) => [
|
|
66
|
+
...cur,
|
|
67
|
+
{ id: createId(), key: s.key, value: "", options: s.options }
|
|
68
|
+
]);
|
|
69
|
+
};
|
|
70
|
+
const addCustomTrait = () => setTraits((cur) => [...cur, { id: createId(), key: "", value: "" }]);
|
|
71
|
+
const updateTrait = (id, patch) => setTraits((cur) => cur.map((t) => t.id === id ? { ...t, ...patch } : t));
|
|
72
|
+
const removeTrait = (id) => setTraits((cur) => cur.filter((t) => t.id !== id));
|
|
73
|
+
if (!template) return null;
|
|
74
|
+
const Icon = template.icon;
|
|
75
|
+
const docUpload = template.docUpload;
|
|
76
|
+
const handleDocPick = async (file) => {
|
|
77
|
+
if (!uploadDocument || !docUpload) return;
|
|
78
|
+
if (file.size > docUpload.maxMb * 1024 * 1024) {
|
|
79
|
+
setDocError(`File must be under ${docUpload.maxMb} MB`);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
setDocError(null);
|
|
83
|
+
setDocUploading(true);
|
|
84
|
+
try {
|
|
85
|
+
const uri = await uploadDocument(file);
|
|
86
|
+
setDocUri(uri);
|
|
87
|
+
setDocName(file.name);
|
|
88
|
+
} catch (err) {
|
|
89
|
+
setDocError(err instanceof Error ? err.message : "Document upload failed");
|
|
90
|
+
} finally {
|
|
91
|
+
setDocUploading(false);
|
|
92
|
+
if (docInputRef.current) docInputRef.current.value = "";
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const clearDoc = () => {
|
|
96
|
+
setDocUri(null);
|
|
97
|
+
setDocName(null);
|
|
98
|
+
setDocError(null);
|
|
99
|
+
};
|
|
100
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
|
|
101
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
102
|
+
/* @__PURE__ */ jsx(Icon, { className: `h-4 w-4 ${template.color.text}` }),
|
|
103
|
+
/* @__PURE__ */ jsxs("p", { className: "text-sm font-semibold", children: [
|
|
104
|
+
template.label,
|
|
105
|
+
" Details"
|
|
106
|
+
] })
|
|
107
|
+
] }),
|
|
108
|
+
docUpload && uploadDocument && /* @__PURE__ */ jsxs("section", { className: "space-y-2", children: [
|
|
109
|
+
/* @__PURE__ */ jsx("p", { className: "text-[11px] font-semibold text-muted-foreground", children: "Document" }),
|
|
110
|
+
docUri ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 rounded-xl border border-emerald-500/30 bg-emerald-500/5 px-4 py-3", children: [
|
|
111
|
+
/* @__PURE__ */ jsx(FileText, { className: "h-5 w-5 text-emerald-500 shrink-0" }),
|
|
112
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
113
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium truncate", children: docName }),
|
|
114
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground truncate", children: docUri })
|
|
115
|
+
] }),
|
|
116
|
+
/* @__PURE__ */ jsx(
|
|
117
|
+
Button,
|
|
118
|
+
{
|
|
119
|
+
type: "button",
|
|
120
|
+
variant: "ghost",
|
|
121
|
+
size: "icon",
|
|
122
|
+
className: "h-8 w-8 shrink-0 text-muted-foreground hover:text-destructive",
|
|
123
|
+
onClick: clearDoc,
|
|
124
|
+
"aria-label": "Remove document",
|
|
125
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
|
|
126
|
+
}
|
|
127
|
+
)
|
|
128
|
+
] }) : /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
129
|
+
/* @__PURE__ */ jsx(
|
|
130
|
+
"input",
|
|
131
|
+
{
|
|
132
|
+
ref: docInputRef,
|
|
133
|
+
type: "file",
|
|
134
|
+
accept: docUpload.accept,
|
|
135
|
+
className: "hidden",
|
|
136
|
+
onChange: (e) => {
|
|
137
|
+
const f = e.target.files?.[0];
|
|
138
|
+
if (f) void handleDocPick(f);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
),
|
|
142
|
+
/* @__PURE__ */ jsx(
|
|
143
|
+
Button,
|
|
144
|
+
{
|
|
145
|
+
type: "button",
|
|
146
|
+
variant: "outline",
|
|
147
|
+
size: "sm",
|
|
148
|
+
disabled: docUploading,
|
|
149
|
+
onClick: () => docInputRef.current?.click(),
|
|
150
|
+
children: docUploading ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
151
|
+
/* @__PURE__ */ jsx(Loader2, { className: "mr-1.5 h-3.5 w-3.5 animate-spin" }),
|
|
152
|
+
"Uploading\u2026"
|
|
153
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
154
|
+
/* @__PURE__ */ jsx(FileUp, { className: "mr-1.5 h-3.5 w-3.5" }),
|
|
155
|
+
"Upload document"
|
|
156
|
+
] })
|
|
157
|
+
}
|
|
158
|
+
),
|
|
159
|
+
docError && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: docError }),
|
|
160
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground leading-relaxed", children: docUpload.hint })
|
|
161
|
+
] })
|
|
162
|
+
] }),
|
|
163
|
+
template.embeds && template.embeds.length > 0 && /* @__PURE__ */ jsxs("section", { className: "space-y-3", children: [
|
|
164
|
+
/* @__PURE__ */ jsx("p", { className: "text-[11px] font-semibold text-muted-foreground", children: "Embeds" }),
|
|
165
|
+
template.embeds.map((platform) => {
|
|
166
|
+
const meta = EMBED_PLATFORM_META[platform];
|
|
167
|
+
const PIcon = meta.icon;
|
|
168
|
+
const value = embedValues[meta.traitKey] ?? "";
|
|
169
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
170
|
+
/* @__PURE__ */ jsxs(Label, { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
|
|
171
|
+
/* @__PURE__ */ jsx(PIcon, { className: "h-3.5 w-3.5" }),
|
|
172
|
+
meta.label,
|
|
173
|
+
looksLikeUrl(value) && /* @__PURE__ */ jsxs("span", { className: "ml-1 inline-flex items-center gap-0.5 text-[10px] font-medium text-emerald-400", children: [
|
|
174
|
+
/* @__PURE__ */ jsx(Check, { className: "h-3 w-3" }),
|
|
175
|
+
" connected"
|
|
176
|
+
] })
|
|
177
|
+
] }),
|
|
178
|
+
/* @__PURE__ */ jsx(
|
|
179
|
+
Input,
|
|
180
|
+
{
|
|
181
|
+
type: "url",
|
|
182
|
+
inputMode: "url",
|
|
183
|
+
placeholder: meta.placeholder,
|
|
184
|
+
value,
|
|
185
|
+
onChange: (e) => setEmbedValues((cur) => ({ ...cur, [meta.traitKey]: e.target.value })),
|
|
186
|
+
className: "h-10 text-sm"
|
|
187
|
+
}
|
|
188
|
+
)
|
|
189
|
+
] }, platform);
|
|
190
|
+
})
|
|
191
|
+
] }),
|
|
192
|
+
template.socials && template.socials.length > 0 && /* @__PURE__ */ jsxs("section", { className: "space-y-3", children: [
|
|
193
|
+
/* @__PURE__ */ jsx("p", { className: "text-[11px] font-semibold text-muted-foreground", children: "Social links" }),
|
|
194
|
+
template.socials.map((platform) => {
|
|
195
|
+
const meta = SOCIAL_PLATFORM_META[platform];
|
|
196
|
+
const PIcon = meta.icon;
|
|
197
|
+
const value = socialValues[meta.traitKey] ?? "";
|
|
198
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
199
|
+
/* @__PURE__ */ jsxs(Label, { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
|
|
200
|
+
/* @__PURE__ */ jsx(PIcon, { className: "h-3.5 w-3.5" }),
|
|
201
|
+
meta.label
|
|
202
|
+
] }),
|
|
203
|
+
/* @__PURE__ */ jsx(
|
|
204
|
+
Input,
|
|
205
|
+
{
|
|
206
|
+
type: "url",
|
|
207
|
+
inputMode: "url",
|
|
208
|
+
placeholder: meta.placeholder,
|
|
209
|
+
value,
|
|
210
|
+
onChange: (e) => setSocialValues((cur) => ({ ...cur, [meta.traitKey]: e.target.value })),
|
|
211
|
+
className: "h-10 text-sm"
|
|
212
|
+
}
|
|
213
|
+
)
|
|
214
|
+
] }, platform);
|
|
215
|
+
})
|
|
216
|
+
] }),
|
|
217
|
+
/* @__PURE__ */ jsxs("section", { className: "space-y-3 border-t border-border/60 pt-4", children: [
|
|
218
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold", children: "Traits" }),
|
|
219
|
+
template.traitSuggestions && template.traitSuggestions.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: template.traitSuggestions.filter((s) => !addedKeys.has(s.key.toLowerCase())).map((s) => /* @__PURE__ */ jsxs(
|
|
220
|
+
"button",
|
|
221
|
+
{
|
|
222
|
+
type: "button",
|
|
223
|
+
onClick: () => addSuggestion(s),
|
|
224
|
+
className: "inline-flex items-center gap-1 rounded-full border border-border bg-muted/40 px-3 py-1 text-xs font-medium text-muted-foreground transition-colors hover:border-primary/40 hover:text-foreground",
|
|
225
|
+
children: [
|
|
226
|
+
/* @__PURE__ */ jsx(Plus, { className: "h-3 w-3" }),
|
|
227
|
+
s.key
|
|
228
|
+
]
|
|
229
|
+
},
|
|
230
|
+
s.key
|
|
231
|
+
)) }),
|
|
232
|
+
traits.length > 0 && /* @__PURE__ */ jsx("div", { className: "space-y-2", children: traits.map((row) => /* @__PURE__ */ jsxs(
|
|
233
|
+
"div",
|
|
234
|
+
{
|
|
235
|
+
className: "grid grid-cols-[1fr_1fr_auto] items-center gap-2",
|
|
236
|
+
children: [
|
|
237
|
+
/* @__PURE__ */ jsx(
|
|
238
|
+
Input,
|
|
239
|
+
{
|
|
240
|
+
value: row.key,
|
|
241
|
+
onChange: (e) => updateTrait(row.id, { key: e.target.value }),
|
|
242
|
+
placeholder: "Trait name",
|
|
243
|
+
className: "h-9 text-sm",
|
|
244
|
+
maxLength: 64
|
|
245
|
+
}
|
|
246
|
+
),
|
|
247
|
+
row.options ? /* @__PURE__ */ jsxs(
|
|
248
|
+
Select,
|
|
249
|
+
{
|
|
250
|
+
value: row.value,
|
|
251
|
+
onValueChange: (v) => updateTrait(row.id, { value: v }),
|
|
252
|
+
children: [
|
|
253
|
+
/* @__PURE__ */ jsx(SelectTrigger, { className: "h-9 text-sm", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Value" }) }),
|
|
254
|
+
/* @__PURE__ */ jsx(SelectContent, { children: row.options.map((opt) => /* @__PURE__ */ jsx(SelectItem, { value: opt, children: opt }, opt)) })
|
|
255
|
+
]
|
|
256
|
+
}
|
|
257
|
+
) : /* @__PURE__ */ jsx(
|
|
258
|
+
Input,
|
|
259
|
+
{
|
|
260
|
+
value: row.value,
|
|
261
|
+
onChange: (e) => updateTrait(row.id, { value: e.target.value }),
|
|
262
|
+
placeholder: "Value",
|
|
263
|
+
className: "h-9 text-sm",
|
|
264
|
+
maxLength: 512
|
|
265
|
+
}
|
|
266
|
+
),
|
|
267
|
+
/* @__PURE__ */ jsx(
|
|
268
|
+
Button,
|
|
269
|
+
{
|
|
270
|
+
type: "button",
|
|
271
|
+
variant: "ghost",
|
|
272
|
+
size: "icon",
|
|
273
|
+
className: "h-9 w-9 shrink-0 text-muted-foreground hover:text-destructive",
|
|
274
|
+
onClick: () => removeTrait(row.id),
|
|
275
|
+
"aria-label": "Remove trait",
|
|
276
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
|
|
277
|
+
}
|
|
278
|
+
)
|
|
279
|
+
]
|
|
280
|
+
},
|
|
281
|
+
row.id
|
|
282
|
+
)) }),
|
|
283
|
+
/* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: addCustomTrait, children: [
|
|
284
|
+
/* @__PURE__ */ jsx(Plus, { className: "mr-1.5 h-3.5 w-3.5" }),
|
|
285
|
+
"Add custom trait"
|
|
286
|
+
] })
|
|
287
|
+
] })
|
|
288
|
+
] });
|
|
289
|
+
}
|
|
290
|
+
export {
|
|
291
|
+
IPTypeFields
|
|
292
|
+
};
|
|
293
|
+
//# sourceMappingURL=ip-type-fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/ip-type-fields.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport type { IPType } from \"../data/ip.js\";\nimport {\n IP_TEMPLATES,\n EMBED_PLATFORM_META,\n SOCIAL_PLATFORM_META,\n type TraitSuggestion,\n} from \"../data/ip-templates.js\";\nimport { Label } from \"./label.js\";\nimport { Input } from \"./input.js\";\nimport { Button } from \"./button.js\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"./select.js\";\nimport { Check, FileText, FileUp, Loader2, Plus, Trash2, X } from \"lucide-react\";\n\nexport type MetadataField = {\n traitType: string;\n value: string;\n};\n\ntype TraitRow = {\n id: string;\n key: string;\n value: string;\n options?: string[];\n};\n\nconst createId = () =>\n globalThis.crypto?.randomUUID?.() ?? `trait-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n\nconst looksLikeUrl = (v: string) => /^https?:\\/\\/\\S+/i.test(v.trim());\n\nexport interface IPTypeFieldsProps {\n ipType: IPType | null;\n onChange: (fields: MetadataField[]) => void;\n /** Uploads a document file to IPFS, resolving to its ipfs:// URI.\n * Enables the document upload field for types with template.docUpload. */\n uploadDocument?: (file: File) => Promise<string>;\n}\n\nexport function IPTypeFields({ ipType, onChange, uploadDocument }: IPTypeFieldsProps) {\n const template = ipType ? IP_TEMPLATES[ipType] : null;\n\n // URL inputs keyed by their stored trait_type (e.g. \"Spotify URL\", \"X\").\n const [embedValues, setEmbedValues] = useState<Record<string, string>>({});\n const [socialValues, setSocialValues] = useState<Record<string, string>>({});\n // One unified, ordered list of traits (suggestions pre-fill rows; custom = blank).\n const [traits, setTraits] = useState<TraitRow[]>([]);\n // Document pinned to IPFS (Documents / Patents / Publications / Software).\n const [docUri, setDocUri] = useState<string | null>(null);\n const [docName, setDocName] = useState<string | null>(null);\n const [docUploading, setDocUploading] = useState(false);\n const [docError, setDocError] = useState<string | null>(null);\n const docInputRef = useRef<HTMLInputElement>(null);\n\n // Embeds, socials & document are type-specific — reset them when the IP type\n // changes. Trait rows are generic key/value and persist across type switches.\n useEffect(() => {\n setEmbedValues({});\n setSocialValues({});\n setDocUri(null);\n setDocName(null);\n setDocError(null);\n }, [ipType]);\n\n const docTraitType = template?.docUpload?.traitType ?? null;\n\n const metadataFields = useMemo(() => {\n const fields: MetadataField[] = [];\n const seen = new Set<string>();\n const add = (traitType: string, value: string) => {\n const t = traitType.trim();\n const v = value.trim();\n const k = t.toLowerCase();\n if (!t || !v || seen.has(k)) return;\n seen.add(k);\n fields.push({ traitType: t, value: v });\n };\n if (docTraitType && docUri) add(docTraitType, docUri);\n Object.entries(embedValues).forEach(([key, value]) => add(key, value));\n Object.entries(socialValues).forEach(([key, value]) => add(key, value));\n traits.forEach((row) => add(row.key, row.value));\n return fields;\n }, [embedValues, socialValues, traits, docTraitType, docUri]);\n\n useEffect(() => {\n onChange(metadataFields);\n }, [metadataFields, onChange]);\n\n const addedKeys = useMemo(\n () => new Set(traits.map((t) => t.key.trim().toLowerCase())),\n [traits]\n );\n\n const addSuggestion = (s: TraitSuggestion) => {\n setTraits((cur) => [\n ...cur,\n { id: createId(), key: s.key, value: \"\", options: s.options },\n ]);\n };\n const addCustomTrait = () =>\n setTraits((cur) => [...cur, { id: createId(), key: \"\", value: \"\" }]);\n const updateTrait = (id: string, patch: Partial<TraitRow>) =>\n setTraits((cur) => cur.map((t) => (t.id === id ? { ...t, ...patch } : t)));\n const removeTrait = (id: string) =>\n setTraits((cur) => cur.filter((t) => t.id !== id));\n\n if (!template) return null;\n\n const Icon = template.icon;\n const docUpload = template.docUpload;\n\n const handleDocPick = async (file: File) => {\n if (!uploadDocument || !docUpload) return;\n if (file.size > docUpload.maxMb * 1024 * 1024) {\n setDocError(`File must be under ${docUpload.maxMb} MB`);\n return;\n }\n setDocError(null);\n setDocUploading(true);\n try {\n const uri = await uploadDocument(file);\n setDocUri(uri);\n setDocName(file.name);\n } catch (err) {\n setDocError(err instanceof Error ? err.message : \"Document upload failed\");\n } finally {\n setDocUploading(false);\n if (docInputRef.current) docInputRef.current.value = \"\";\n }\n };\n\n const clearDoc = () => {\n setDocUri(null);\n setDocName(null);\n setDocError(null);\n };\n\n return (\n <div className=\"space-y-5\">\n <div className=\"flex items-center gap-2\">\n <Icon className={`h-4 w-4 ${template.color.text}`} />\n <p className=\"text-sm font-semibold\">{template.label} Details</p>\n </div>\n\n {/* ── Document file → IPFS (Documents / Patents / Publications / Software) ── */}\n {docUpload && uploadDocument && (\n <section className=\"space-y-2\">\n <p className=\"text-[11px] font-semibold text-muted-foreground\">\n Document\n </p>\n {docUri ? (\n <div className=\"flex items-center gap-3 rounded-xl border border-emerald-500/30 bg-emerald-500/5 px-4 py-3\">\n <FileText className=\"h-5 w-5 text-emerald-500 shrink-0\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-medium truncate\">{docName}</p>\n <p className=\"text-xs text-muted-foreground truncate\">{docUri}</p>\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-8 w-8 shrink-0 text-muted-foreground hover:text-destructive\"\n onClick={clearDoc}\n aria-label=\"Remove document\"\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n ) : (\n <div className=\"space-y-1.5\">\n <input\n ref={docInputRef}\n type=\"file\"\n accept={docUpload.accept}\n className=\"hidden\"\n onChange={(e) => {\n const f = e.target.files?.[0];\n if (f) void handleDocPick(f);\n }}\n />\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n disabled={docUploading}\n onClick={() => docInputRef.current?.click()}\n >\n {docUploading ? (\n <>\n <Loader2 className=\"mr-1.5 h-3.5 w-3.5 animate-spin\" />\n Uploading…\n </>\n ) : (\n <>\n <FileUp className=\"mr-1.5 h-3.5 w-3.5\" />\n Upload document\n </>\n )}\n </Button>\n {docError && <p className=\"text-xs text-destructive\">{docError}</p>}\n <p className=\"text-xs text-muted-foreground leading-relaxed\">{docUpload.hint}</p>\n </div>\n )}\n </section>\n )}\n\n {/* ── Embeds (inline players) ─────────────────────────────── */}\n {template.embeds && template.embeds.length > 0 && (\n <section className=\"space-y-3\">\n <p className=\"text-[11px] font-semibold text-muted-foreground\">Embeds</p>\n {template.embeds.map((platform) => {\n const meta = EMBED_PLATFORM_META[platform];\n const PIcon = meta.icon;\n const value = embedValues[meta.traitKey] ?? \"\";\n return (\n <div key={platform} className=\"space-y-1.5\">\n <Label className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <PIcon className=\"h-3.5 w-3.5\" />\n {meta.label}\n {looksLikeUrl(value) && (\n <span className=\"ml-1 inline-flex items-center gap-0.5 text-[10px] font-medium text-emerald-400\">\n <Check className=\"h-3 w-3\" /> connected\n </span>\n )}\n </Label>\n <Input\n type=\"url\"\n inputMode=\"url\"\n placeholder={meta.placeholder}\n value={value}\n onChange={(e) =>\n setEmbedValues((cur) => ({ ...cur, [meta.traitKey]: e.target.value }))\n }\n className=\"h-10 text-sm\"\n />\n </div>\n );\n })}\n </section>\n )}\n\n {/* ── Social links (icon chips on the asset page) ─────────── */}\n {template.socials && template.socials.length > 0 && (\n <section className=\"space-y-3\">\n <p className=\"text-[11px] font-semibold text-muted-foreground\">Social links</p>\n {template.socials.map((platform) => {\n const meta = SOCIAL_PLATFORM_META[platform];\n const PIcon = meta.icon;\n const value = socialValues[meta.traitKey] ?? \"\";\n return (\n <div key={platform} className=\"space-y-1.5\">\n <Label className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <PIcon className=\"h-3.5 w-3.5\" />\n {meta.label}\n </Label>\n <Input\n type=\"url\"\n inputMode=\"url\"\n placeholder={meta.placeholder}\n value={value}\n onChange={(e) =>\n setSocialValues((cur) => ({ ...cur, [meta.traitKey]: e.target.value }))\n }\n className=\"h-10 text-sm\"\n />\n </div>\n );\n })}\n </section>\n )}\n\n {/* ── Traits ───────────────────────────────────────────────── */}\n <section className=\"space-y-3 border-t border-border/60 pt-4\">\n <p className=\"text-sm font-semibold\">Traits</p>\n\n {/* Suggestion chips */}\n {template.traitSuggestions && template.traitSuggestions.length > 0 && (\n <div className=\"flex flex-wrap gap-2\">\n {template.traitSuggestions\n .filter((s) => !addedKeys.has(s.key.toLowerCase()))\n .map((s) => (\n <button\n key={s.key}\n type=\"button\"\n onClick={() => addSuggestion(s)}\n className=\"inline-flex items-center gap-1 rounded-full border border-border bg-muted/40 px-3 py-1 text-xs font-medium text-muted-foreground transition-colors hover:border-primary/40 hover:text-foreground\"\n >\n <Plus className=\"h-3 w-3\" />\n {s.key}\n </button>\n ))}\n </div>\n )}\n\n {/* Trait rows — one trait per card, inputs stacked (mobile-first) */}\n {traits.length > 0 && (\n <div className=\"space-y-2\">\n {traits.map((row) => (\n <div\n key={row.id}\n className=\"grid grid-cols-[1fr_1fr_auto] items-center gap-2\"\n >\n <Input\n value={row.key}\n onChange={(e) => updateTrait(row.id, { key: e.target.value })}\n placeholder=\"Trait name\"\n className=\"h-9 text-sm\"\n maxLength={64}\n />\n {row.options ? (\n <Select\n value={row.value}\n onValueChange={(v) => updateTrait(row.id, { value: v })}\n >\n <SelectTrigger className=\"h-9 text-sm\">\n <SelectValue placeholder=\"Value\" />\n </SelectTrigger>\n <SelectContent>\n {row.options.map((opt) => (\n <SelectItem key={opt} value={opt}>{opt}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : (\n <Input\n value={row.value}\n onChange={(e) => updateTrait(row.id, { value: e.target.value })}\n placeholder=\"Value\"\n className=\"h-9 text-sm\"\n maxLength={512}\n />\n )}\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-9 w-9 shrink-0 text-muted-foreground hover:text-destructive\"\n onClick={() => removeTrait(row.id)}\n aria-label=\"Remove trait\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </Button>\n </div>\n ))}\n </div>\n )}\n\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={addCustomTrait}>\n <Plus className=\"mr-1.5 h-3.5 w-3.5\" />\n Add custom trait\n </Button>\n </section>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var json_ld_exports = {};
|
|
20
|
+
__export(json_ld_exports, {
|
|
21
|
+
JsonLd: () => JsonLd
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(json_ld_exports);
|
|
24
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
25
|
+
function JsonLd({ data }) {
|
|
26
|
+
const json = JSON.stringify(data).replace(/</g, "\\u003c");
|
|
27
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
28
|
+
"script",
|
|
29
|
+
{
|
|
30
|
+
type: "application/ld+json",
|
|
31
|
+
dangerouslySetInnerHTML: { __html: json }
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
36
|
+
0 && (module.exports = {
|
|
37
|
+
JsonLd
|
|
38
|
+
});
|
|
39
|
+
//# sourceMappingURL=json-ld.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/json-ld.tsx"],"sourcesContent":["export interface JsonLdProps {\n data: Record<string, unknown> | Array<Record<string, unknown>>;\n}\n\nexport function JsonLd({ data }: JsonLdProps) {\n const json = JSON.stringify(data).replace(/</g, \"\\\\u003c\");\n\n return (\n <script\n type=\"application/ld+json\"\n dangerouslySetInnerHTML={{ __html: json }}\n />\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAQI;AAJG,SAAS,OAAO,EAAE,KAAK,GAAgB;AAC5C,QAAM,OAAO,KAAK,UAAU,IAAI,EAAE,QAAQ,MAAM,SAAS;AAEzD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,yBAAyB,EAAE,QAAQ,KAAK;AAAA;AAAA,EAC1C;AAEJ;","names":[]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface JsonLdProps {
|
|
4
|
+
data: Record<string, unknown> | Array<Record<string, unknown>>;
|
|
5
|
+
}
|
|
6
|
+
declare function JsonLd({ data }: JsonLdProps): react_jsx_runtime.JSX.Element;
|
|
7
|
+
|
|
8
|
+
export { JsonLd, type JsonLdProps };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface JsonLdProps {
|
|
4
|
+
data: Record<string, unknown> | Array<Record<string, unknown>>;
|
|
5
|
+
}
|
|
6
|
+
declare function JsonLd({ data }: JsonLdProps): react_jsx_runtime.JSX.Element;
|
|
7
|
+
|
|
8
|
+
export { JsonLd, type JsonLdProps };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
function JsonLd({ data }) {
|
|
3
|
+
const json = JSON.stringify(data).replace(/</g, "\\u003c");
|
|
4
|
+
return /* @__PURE__ */ jsx(
|
|
5
|
+
"script",
|
|
6
|
+
{
|
|
7
|
+
type: "application/ld+json",
|
|
8
|
+
dangerouslySetInnerHTML: { __html: json }
|
|
9
|
+
}
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
JsonLd
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=json-ld.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/json-ld.tsx"],"sourcesContent":["export interface JsonLdProps {\n data: Record<string, unknown> | Array<Record<string, unknown>>;\n}\n\nexport function JsonLd({ data }: JsonLdProps) {\n const json = JSON.stringify(data).replace(/</g, \"\\\\u003c\");\n\n return (\n <script\n type=\"application/ld+json\"\n dangerouslySetInnerHTML={{ __html: json }}\n />\n );\n}\n"],"mappings":"AAQI;AAJG,SAAS,OAAO,EAAE,KAAK,GAAgB;AAC5C,QAAM,OAAO,KAAK,UAAU,IAAI,EAAE,QAAQ,MAAM,SAAS;AAEzD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,yBAAyB,EAAE,QAAQ,KAAK;AAAA;AAAA,EAC1C;AAEJ;","names":[]}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
var nav_theme_toggle_exports = {};
|
|
21
|
+
__export(nav_theme_toggle_exports, {
|
|
22
|
+
NavThemeToggle: () => NavThemeToggle
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(nav_theme_toggle_exports);
|
|
25
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
26
|
+
var import_react = require("react");
|
|
27
|
+
var import_next_themes = require("next-themes");
|
|
28
|
+
var import_lucide_react = require("lucide-react");
|
|
29
|
+
var import_cn = require("../utils/cn.js");
|
|
30
|
+
function NavThemeToggle() {
|
|
31
|
+
const { resolvedTheme, setTheme } = (0, import_next_themes.useTheme)();
|
|
32
|
+
const [mounted, setMounted] = (0, import_react.useState)(false);
|
|
33
|
+
(0, import_react.useEffect)(() => setMounted(true), []);
|
|
34
|
+
const isDark = mounted ? resolvedTheme === "dark" : true;
|
|
35
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
36
|
+
"div",
|
|
37
|
+
{
|
|
38
|
+
role: "group",
|
|
39
|
+
"aria-label": "Theme",
|
|
40
|
+
className: "flex items-center gap-0.5 rounded-lg bg-muted/40 p-0.5",
|
|
41
|
+
children: [
|
|
42
|
+
{ key: "light", label: "Light theme", Icon: import_lucide_react.Sun, active: !isDark },
|
|
43
|
+
{ key: "dark", label: "Dark theme", Icon: import_lucide_react.Moon, active: isDark }
|
|
44
|
+
].map(({ key, label, Icon, active }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
45
|
+
"button",
|
|
46
|
+
{
|
|
47
|
+
type: "button",
|
|
48
|
+
"aria-label": label,
|
|
49
|
+
"aria-pressed": active,
|
|
50
|
+
onClick: () => setTheme(key),
|
|
51
|
+
className: (0, import_cn.cn)(
|
|
52
|
+
"flex h-7 w-7 items-center justify-center rounded-md transition-colors",
|
|
53
|
+
active ? "bg-background text-foreground shadow-sm" : "text-muted-foreground/60 hover:text-foreground"
|
|
54
|
+
),
|
|
55
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { className: "h-3.5 w-3.5" })
|
|
56
|
+
},
|
|
57
|
+
key
|
|
58
|
+
))
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
63
|
+
0 && (module.exports = {
|
|
64
|
+
NavThemeToggle
|
|
65
|
+
});
|
|
66
|
+
//# sourceMappingURL=nav-theme-toggle.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/nav-theme-toggle.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { useTheme } from \"next-themes\";\nimport { Sun, Moon } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\n\n/**\n * Compact Light/Dark segmented toggle for the nav menu footer.\n * Passed to NavCommandMenu via its `footerSlot` prop.\n */\nexport function NavThemeToggle() {\n const { resolvedTheme, setTheme } = useTheme();\n const [mounted, setMounted] = useState(false);\n\n // next-themes can't know the theme until mounted — avoid hydration mismatch.\n useEffect(() => setMounted(true), []);\n\n const isDark = mounted ? resolvedTheme === \"dark\" : true;\n\n return (\n <div\n role=\"group\"\n aria-label=\"Theme\"\n className=\"flex items-center gap-0.5 rounded-lg bg-muted/40 p-0.5\"\n >\n {[\n { key: \"light\", label: \"Light theme\", Icon: Sun, active: !isDark },\n { key: \"dark\", label: \"Dark theme\", Icon: Moon, active: isDark },\n ].map(({ key, label, Icon, active }) => (\n <button\n key={key}\n type=\"button\"\n aria-label={label}\n aria-pressed={active}\n onClick={() => setTheme(key)}\n className={cn(\n \"flex h-7 w-7 items-center justify-center rounded-md transition-colors\",\n active\n ? \"bg-background text-foreground shadow-sm\"\n : \"text-muted-foreground/60 hover:text-foreground\"\n )}\n >\n <Icon className=\"h-3.5 w-3.5\" />\n </button>\n ))}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA2CU;AAzCV,mBAAoC;AACpC,yBAAyB;AACzB,0BAA0B;AAC1B,gBAAmB;AAMZ,SAAS,iBAAiB;AAC/B,QAAM,EAAE,eAAe,SAAS,QAAI,6BAAS;AAC7C,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,KAAK;AAG5C,8BAAU,MAAM,WAAW,IAAI,GAAG,CAAC,CAAC;AAEpC,QAAM,SAAS,UAAU,kBAAkB,SAAS;AAEpD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAW;AAAA,MACX,WAAU;AAAA,MAET;AAAA,QACC,EAAE,KAAK,SAAS,OAAO,eAAe,MAAM,yBAAK,QAAQ,CAAC,OAAO;AAAA,QACjE,EAAE,KAAK,QAAQ,OAAO,cAAc,MAAM,0BAAM,QAAQ,OAAO;AAAA,MACjE,EAAE,IAAI,CAAC,EAAE,KAAK,OAAO,MAAM,OAAO,MAChC;AAAA,QAAC;AAAA;AAAA,UAEC,MAAK;AAAA,UACL,cAAY;AAAA,UACZ,gBAAc;AAAA,UACd,SAAS,MAAM,SAAS,GAAG;AAAA,UAC3B,eAAW;AAAA,YACT;AAAA,YACA,SACI,4CACA;AAAA,UACN;AAAA,UAEA,sDAAC,QAAK,WAAU,eAAc;AAAA;AAAA,QAZzB;AAAA,MAaP,CACD;AAAA;AAAA,EACH;AAEJ;","names":[]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Compact Light/Dark segmented toggle for the nav menu footer.
|
|
5
|
+
* Passed to NavCommandMenu via its `footerSlot` prop.
|
|
6
|
+
*/
|
|
7
|
+
declare function NavThemeToggle(): react_jsx_runtime.JSX.Element;
|
|
8
|
+
|
|
9
|
+
export { NavThemeToggle };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Compact Light/Dark segmented toggle for the nav menu footer.
|
|
5
|
+
* Passed to NavCommandMenu via its `footerSlot` prop.
|
|
6
|
+
*/
|
|
7
|
+
declare function NavThemeToggle(): react_jsx_runtime.JSX.Element;
|
|
8
|
+
|
|
9
|
+
export { NavThemeToggle };
|