@medialane/ui 0.323.0 → 0.325.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/account/input-otp.d.cts +2 -2
- package/dist/components/account/input-otp.d.ts +2 -2
- package/dist/components/button.d.cts +2 -2
- package/dist/components/button.d.ts +2 -2
- package/dist/components/collection-filters.cjs +0 -1
- package/dist/components/collection-filters.cjs.map +1 -1
- package/dist/components/collection-filters.js +0 -1
- package/dist/components/collection-filters.js.map +1 -1
- package/dist/components/currency-icon.cjs +7 -2
- package/dist/components/currency-icon.cjs.map +1 -1
- package/dist/components/currency-icon.d.cts +2 -1
- package/dist/components/currency-icon.d.ts +2 -1
- package/dist/components/currency-icon.js +5 -1
- package/dist/components/currency-icon.js.map +1 -1
- package/dist/components/ip-type-page.cjs +1 -1
- package/dist/components/ip-type-page.cjs.map +1 -1
- package/dist/components/ip-type-page.js +1 -1
- package/dist/components/ip-type-page.js.map +1 -1
- package/dist/components/launchpad/edition-mint-schema.d.cts +4 -4
- package/dist/components/launchpad/edition-mint-schema.d.ts +4 -4
- package/dist/components/listing-card.cjs +17 -12
- package/dist/components/listing-card.cjs.map +1 -1
- package/dist/components/listing-card.js +17 -12
- package/dist/components/listing-card.js.map +1 -1
- package/dist/components/marketplace-filters.cjs +1 -1
- package/dist/components/marketplace-filters.cjs.map +1 -1
- package/dist/components/marketplace-filters.js +1 -1
- package/dist/components/marketplace-filters.js.map +1 -1
- package/dist/utils/media-wallet/use-erc20-balance.d.cts +1 -1
- package/dist/utils/media-wallet/use-erc20-balance.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as input_otp from 'input-otp';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
|
|
4
|
-
declare const InputOTP: React.ForwardRefExoticComponent<(Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "
|
|
4
|
+
declare const InputOTP: React.ForwardRefExoticComponent<(Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "value" | "onChange" | "maxLength" | "textAlign" | "onComplete" | "pushPasswordManagerStrategy" | "pasteTransformer" | "containerClassName" | "noScriptCSSFallback"> & {
|
|
5
5
|
value?: string;
|
|
6
6
|
onChange?: (newValue: string) => unknown;
|
|
7
7
|
maxLength: number;
|
|
@@ -14,7 +14,7 @@ declare const InputOTP: React.ForwardRefExoticComponent<(Omit<Omit<React.InputHT
|
|
|
14
14
|
} & {
|
|
15
15
|
render: (props: input_otp.RenderProps) => React.ReactNode;
|
|
16
16
|
children?: never;
|
|
17
|
-
} & React.RefAttributes<HTMLInputElement>, "ref"> | Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "
|
|
17
|
+
} & React.RefAttributes<HTMLInputElement>, "ref"> | Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "value" | "onChange" | "maxLength" | "textAlign" | "onComplete" | "pushPasswordManagerStrategy" | "pasteTransformer" | "containerClassName" | "noScriptCSSFallback"> & {
|
|
18
18
|
value?: string;
|
|
19
19
|
onChange?: (newValue: string) => unknown;
|
|
20
20
|
maxLength: number;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as input_otp from 'input-otp';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
|
|
4
|
-
declare const InputOTP: React.ForwardRefExoticComponent<(Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "
|
|
4
|
+
declare const InputOTP: React.ForwardRefExoticComponent<(Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "value" | "onChange" | "maxLength" | "textAlign" | "onComplete" | "pushPasswordManagerStrategy" | "pasteTransformer" | "containerClassName" | "noScriptCSSFallback"> & {
|
|
5
5
|
value?: string;
|
|
6
6
|
onChange?: (newValue: string) => unknown;
|
|
7
7
|
maxLength: number;
|
|
@@ -14,7 +14,7 @@ declare const InputOTP: React.ForwardRefExoticComponent<(Omit<Omit<React.InputHT
|
|
|
14
14
|
} & {
|
|
15
15
|
render: (props: input_otp.RenderProps) => React.ReactNode;
|
|
16
16
|
children?: never;
|
|
17
|
-
} & React.RefAttributes<HTMLInputElement>, "ref"> | Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "
|
|
17
|
+
} & React.RefAttributes<HTMLInputElement>, "ref"> | Omit<Omit<React.InputHTMLAttributes<HTMLInputElement>, "value" | "onChange" | "maxLength" | "textAlign" | "onComplete" | "pushPasswordManagerStrategy" | "pasteTransformer" | "containerClassName" | "noScriptCSSFallback"> & {
|
|
18
18
|
value?: string;
|
|
19
19
|
onChange?: (newValue: string) => unknown;
|
|
20
20
|
maxLength: number;
|
|
@@ -3,8 +3,8 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const buttonVariants: (props?: ({
|
|
6
|
-
variant?: "
|
|
7
|
-
size?: "
|
|
6
|
+
variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | "premium" | "tonal" | "gradient-border" | "gradient-fill" | null | undefined;
|
|
7
|
+
size?: "icon" | "default" | "sm" | "lg" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
10
10
|
asChild?: boolean;
|
|
@@ -3,8 +3,8 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const buttonVariants: (props?: ({
|
|
6
|
-
variant?: "
|
|
7
|
-
size?: "
|
|
6
|
+
variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | "premium" | "tonal" | "gradient-border" | "gradient-fill" | null | undefined;
|
|
7
|
+
size?: "icon" | "default" | "sm" | "lg" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
10
10
|
asChild?: boolean;
|
|
@@ -98,7 +98,6 @@ function CollectionFiltersTrigger({
|
|
|
98
98
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-end gap-2 flex-wrap", children: [
|
|
99
99
|
showButton && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { onClick: onOpen, className: TRIGGER_BTN, "aria-label": "Filters", children: [
|
|
100
100
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.SlidersHorizontal, { className: "h-3.5 w-3.5" }),
|
|
101
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "hidden sm:inline", children: "Filters" }),
|
|
102
101
|
totalActiveCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "h-4 min-w-4 rounded-full bg-primary text-2xs font-bold text-primary-foreground flex items-center justify-center px-1 -mr-1", children: totalActiveCount })
|
|
103
102
|
] }),
|
|
104
103
|
showChips && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/collection-filters.tsx"],"sourcesContent":["\"use client\";\n\nimport { useMemo } from \"react\";\nimport { SlidersHorizontal, X, Check } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport type { ApiToken, CollectionTokensSort } from \"@medialane/sdk\";\n\nconst EXCLUDED_TRAIT_TYPES = new Set([\"registration\"]);\n\nexport const SORT_OPTIONS: { value: CollectionTokensSort; label: string }[] = [\n { value: \"recent\", label: \"Recent\" },\n { value: \"oldest\", label: \"Oldest\" },\n { value: \"name\", label: \"Name\" },\n { value: \"price\", label: \"Price\" },\n];\n\nexport interface TraitSection {\n traitType: string;\n values: { value: string; count: number }[];\n}\n\nexport function useCollectionFilters(\n tokens: ApiToken[],\n selected: Record<string, string[]>,\n onChange: (filters: Record<string, string[]>) => void,\n sort: CollectionTokensSort,\n onSortChange: (sort: CollectionTokensSort) => void,\n) {\n\n const traitSections: TraitSection[] = useMemo(() => {\n const map = new Map<string, Map<string, number>>();\n for (const token of tokens) {\n const attrs = Array.isArray(token.metadata?.attributes)\n ? (token.metadata.attributes as { trait_type?: string; value?: string }[])\n : [];\n for (const attr of attrs) {\n if (!attr.trait_type || attr.value == null) continue;\n if (EXCLUDED_TRAIT_TYPES.has(attr.trait_type.toLowerCase())) continue;\n if (!map.has(attr.trait_type)) map.set(attr.trait_type, new Map());\n const counts = map.get(attr.trait_type)!;\n const v = String(attr.value);\n counts.set(v, (counts.get(v) ?? 0) + 1);\n }\n }\n return Array.from(map.entries())\n .map(([traitType, counts]) => ({\n traitType,\n values: Array.from(counts.entries())\n .map(([value, count]) => ({ value, count }))\n .sort((a, b) => b.count - a.count || a.value.localeCompare(b.value)),\n }))\n .filter((section) => section.values.length >= 2);\n }, [tokens]);\n\n const activeEntries = Object.entries(selected).flatMap(([traitType, values]) =>\n values.map((value) => ({ traitType, value }))\n );\n const traitActiveCount = activeEntries.length;\n const sortIsDefault = sort === \"recent\";\n const totalActiveCount = traitActiveCount + (sortIsDefault ? 0 : 1);\n\n function toggleValue(traitType: string, value: string) {\n const current = selected[traitType] ?? [];\n const next = current.includes(value)\n ? current.filter((v) => v !== value)\n : [...current, value];\n const nextSelected = { ...selected };\n if (next.length === 0) {\n delete nextSelected[traitType];\n } else {\n nextSelected[traitType] = next;\n }\n onChange(nextSelected);\n }\n\n function clearAll() {\n onChange({});\n onSortChange(\"recent\");\n }\n\n function removeFilter(traitType: string, value: string) {\n toggleValue(traitType, value);\n }\n\n return { traitSections, activeEntries, totalActiveCount, sortIsDefault, toggleValue, clearAll, removeFilter };\n}\n\nconst TRIGGER_BTN = \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md border border-input bg-background text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground h-8 px-3 shrink-0\";\n\nexport interface CollectionFiltersTriggerProps {\n totalActiveCount: number;\n sortIsDefault: boolean;\n sort: CollectionTokensSort;\n activeEntries: { traitType: string; value: string }[];\n onOpen: () => void;\n onSortReset: () => void;\n onRemoveFilter: (traitType: string, value: string) => void;\n onClearAll: () => void;\n showButton?: boolean;\n showChips?: boolean;\n}\n\nexport function CollectionFiltersTrigger({\n totalActiveCount,\n sortIsDefault,\n sort,\n activeEntries,\n onOpen,\n onSortReset,\n onRemoveFilter,\n onClearAll,\n showButton = true,\n showChips = true,\n}: CollectionFiltersTriggerProps) {\n if (!showButton && (!showChips || (sortIsDefault && activeEntries.length === 0))) return null;\n return (\n <div className=\"flex items-center justify-end gap-2 flex-wrap\">\n {showButton && (\n <button onClick={onOpen} className={TRIGGER_BTN} aria-label=\"Filters\">\n <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n <span className=\"hidden sm:inline\">Filters</span>\n {totalActiveCount > 0 && (\n <span className=\"h-4 min-w-4 rounded-full bg-primary text-2xs font-bold text-primary-foreground flex items-center justify-center px-1 -mr-1\">\n {totalActiveCount}\n </span>\n )}\n </button>\n )}\n {showChips && (\n <>\n\n {!sortIsDefault && (\n <button\n onClick={onSortReset}\n className=\"inline-flex items-center gap-1 h-8 px-2.5 rounded-md border border-primary/40 bg-primary/10 text-xs font-medium text-foreground hover:bg-primary/20 transition-colors\"\n >\n <span className=\"text-muted-foreground text-2xs\">Sort:</span>\n <span>{SORT_OPTIONS.find((o) => o.value === sort)?.label}</span>\n <X className=\"h-3 w-3 text-muted-foreground ml-0.5\" />\n </button>\n )}\n\n {activeEntries.map(({ traitType, value }) => (\n <button\n key={`${traitType}:${value}`}\n onClick={() => onRemoveFilter(traitType, value)}\n title={`${traitType}: ${value}`}\n className=\"inline-flex max-w-full min-w-0 items-center gap-1 h-8 px-2.5 rounded-md border border-primary/40 bg-primary/10 text-xs font-medium text-foreground hover:bg-primary/20 transition-colors\"\n >\n <span className=\"text-muted-foreground text-2xs shrink-0\">{traitType}:</span>\n <span className=\"truncate\">{value}</span>\n <X className=\"h-3 w-3 text-muted-foreground ml-0.5 shrink-0\" />\n </button>\n ))}\n\n {totalActiveCount > 1 && (\n <button\n onClick={onClearAll}\n className=\"text-xs text-muted-foreground hover:text-foreground underline-offset-2 hover:underline transition-colors\"\n >\n Clear all\n </button>\n )}\n </>\n )}\n </div>\n );\n}\n\nexport interface CollectionFiltersBodyProps {\n sort: CollectionTokensSort;\n onSortChange: (sort: CollectionTokensSort) => void;\n traitSections: TraitSection[];\n selected: Record<string, string[]>;\n onToggleValue: (traitType: string, value: string) => void;\n}\n\nconst PILL_BASE = \"inline-flex max-w-full min-w-0 items-center gap-1 h-7 px-2.5 rounded-full border text-xs font-medium transition-colors\";\nconst PILL_ON = \"border-primary bg-primary text-primary-foreground\";\nconst PILL_OFF = \"border-border bg-transparent text-muted-foreground hover:text-foreground hover:border-foreground/30\";\n\nexport function CollectionFiltersBody({\n sort,\n onSortChange,\n traitSections,\n selected,\n onToggleValue,\n}: CollectionFiltersBodyProps) {\n return (\n <div className=\"flex-1 min-w-0 overflow-y-auto overflow-x-hidden px-5 py-3 space-y-4\">\n\n <div>\n <div className=\"mb-2\">\n <span className=\"text-sm font-medium\">Sort by</span>\n </div>\n <div className=\"flex flex-wrap gap-1.5\">\n {SORT_OPTIONS.map(({ value, label }) => {\n const isSelected = sort === value;\n return (\n <button\n key={value}\n onClick={() => onSortChange(value)}\n className={cn(PILL_BASE, isSelected ? PILL_ON : PILL_OFF)}\n >\n {isSelected && <Check className=\"h-3 w-3\" />}\n <span>{label}</span>\n </button>\n );\n })}\n </div>\n </div>\n\n {traitSections.length > 0 && (\n <>\n <div className=\"h-px w-full bg-border\" />\n {traitSections.map((section, i) => {\n const activeValues = selected[section.traitType] ?? [];\n return (\n <div key={section.traitType}>\n {i > 0 && <div className=\"h-px w-full bg-border mb-4\" />}\n <div className=\"flex items-center justify-between gap-3 mb-2\">\n <span className=\"min-w-0 truncate text-sm font-medium\" title={section.traitType}>{section.traitType}</span>\n <span className=\"shrink-0 text-2xs text-muted-foreground\">\n {section.values.length} values\n </span>\n </div>\n <div className=\"flex flex-wrap gap-1.5\">\n {section.values.map(({ value, count }) => {\n const isSelected = activeValues.includes(value);\n return (\n <button\n key={value}\n onClick={() => onToggleValue(section.traitType, value)}\n title={value}\n className={cn(PILL_BASE, isSelected ? PILL_ON : PILL_OFF)}\n >\n {isSelected && <Check className=\"h-3 w-3 shrink-0\" />}\n <span className=\"truncate\">{value}</span>\n <span className={cn(\"shrink-0\", isSelected ? \"opacity-80\" : \"opacity-60\")}>\n {count}\n </span>\n </button>\n );\n })}\n </div>\n </div>\n );\n })}\n </>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsHQ;AApHR,mBAAwB;AACxB,0BAA4C;AAC5C,gBAAmB;AAGnB,MAAM,uBAAuB,oBAAI,IAAI,CAAC,cAAc,CAAC;AAE9C,MAAM,eAAiE;AAAA,EAC5E,EAAE,OAAO,UAAU,OAAO,SAAS;AAAA,EACnC,EAAE,OAAO,UAAU,OAAO,SAAS;AAAA,EACnC,EAAE,OAAO,QAAQ,OAAO,OAAO;AAAA,EAC/B,EAAE,OAAO,SAAS,OAAO,QAAQ;AACnC;AAOO,SAAS,qBACd,QACA,UACA,UACA,MACA,cACA;AAEA,QAAM,oBAAgC,sBAAQ,MAAM;AAClD,UAAM,MAAM,oBAAI,IAAiC;AACjD,eAAW,SAAS,QAAQ;AAC1B,YAAM,QAAQ,MAAM,QAAQ,MAAM,UAAU,UAAU,IACjD,MAAM,SAAS,aAChB,CAAC;AACL,iBAAW,QAAQ,OAAO;AACxB,YAAI,CAAC,KAAK,cAAc,KAAK,SAAS,KAAM;AAC5C,YAAI,qBAAqB,IAAI,KAAK,WAAW,YAAY,CAAC,EAAG;AAC7D,YAAI,CAAC,IAAI,IAAI,KAAK,UAAU,EAAG,KAAI,IAAI,KAAK,YAAY,oBAAI,IAAI,CAAC;AACjE,cAAM,SAAS,IAAI,IAAI,KAAK,UAAU;AACtC,cAAM,IAAI,OAAO,KAAK,KAAK;AAC3B,eAAO,IAAI,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,CAAC;AAAA,MACxC;AAAA,IACF;AACA,WAAO,MAAM,KAAK,IAAI,QAAQ,CAAC,EAC5B,IAAI,CAAC,CAAC,WAAW,MAAM,OAAO;AAAA,MAC7B;AAAA,MACA,QAAQ,MAAM,KAAK,OAAO,QAAQ,CAAC,EAChC,IAAI,CAAC,CAAC,OAAO,KAAK,OAAO,EAAE,OAAO,MAAM,EAAE,EAC1C,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;AAAA,IACvE,EAAE,EACD,OAAO,CAAC,YAAY,QAAQ,OAAO,UAAU,CAAC;AAAA,EACnD,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,gBAAgB,OAAO,QAAQ,QAAQ,EAAE;AAAA,IAAQ,CAAC,CAAC,WAAW,MAAM,MACxE,OAAO,IAAI,CAAC,WAAW,EAAE,WAAW,MAAM,EAAE;AAAA,EAC9C;AACA,QAAM,mBAAmB,cAAc;AACvC,QAAM,gBAAgB,SAAS;AAC/B,QAAM,mBAAmB,oBAAoB,gBAAgB,IAAI;AAEjE,WAAS,YAAY,WAAmB,OAAe;AACrD,UAAM,UAAU,SAAS,SAAS,KAAK,CAAC;AACxC,UAAM,OAAO,QAAQ,SAAS,KAAK,IAC/B,QAAQ,OAAO,CAAC,MAAM,MAAM,KAAK,IACjC,CAAC,GAAG,SAAS,KAAK;AACtB,UAAM,eAAe,EAAE,GAAG,SAAS;AACnC,QAAI,KAAK,WAAW,GAAG;AACrB,aAAO,aAAa,SAAS;AAAA,IAC/B,OAAO;AACL,mBAAa,SAAS,IAAI;AAAA,IAC5B;AACA,aAAS,YAAY;AAAA,EACvB;AAEA,WAAS,WAAW;AAClB,aAAS,CAAC,CAAC;AACX,iBAAa,QAAQ;AAAA,EACvB;AAEA,WAAS,aAAa,WAAmB,OAAe;AACtD,gBAAY,WAAW,KAAK;AAAA,EAC9B;AAEA,SAAO,EAAE,eAAe,eAAe,kBAAkB,eAAe,aAAa,UAAU,aAAa;AAC9G;AAEA,MAAM,cAAc;AAeb,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb,YAAY;AACd,GAAkC;AAChC,MAAI,CAAC,eAAe,CAAC,aAAc,iBAAiB,cAAc,WAAW,GAAK,QAAO;AACzF,SACE,6CAAC,SAAI,WAAU,iDACZ;AAAA,kBACC,6CAAC,YAAO,SAAS,QAAQ,WAAW,aAAa,cAAW,WAC1D;AAAA,kDAAC,yCAAkB,WAAU,eAAc;AAAA,MAC3C,4CAAC,UAAK,WAAU,oBAAmB,qBAAO;AAAA,MACzC,mBAAmB,KAClB,4CAAC,UAAK,WAAU,8HACb,4BACH;AAAA,OAEJ;AAAA,IAED,aACC,4EAED;AAAA,OAAC,iBACA;AAAA,QAAC;AAAA;AAAA,UACC,SAAS;AAAA,UACT,WAAU;AAAA,UAEV;AAAA,wDAAC,UAAK,WAAU,kCAAiC,mBAAK;AAAA,YACtD,4CAAC,UAAM,uBAAa,KAAK,CAAC,MAAM,EAAE,UAAU,IAAI,GAAG,OAAM;AAAA,YACzD,4CAAC,yBAAE,WAAU,wCAAuC;AAAA;AAAA;AAAA,MACtD;AAAA,MAGD,cAAc,IAAI,CAAC,EAAE,WAAW,MAAM,MACrC;AAAA,QAAC;AAAA;AAAA,UAEC,SAAS,MAAM,eAAe,WAAW,KAAK;AAAA,UAC9C,OAAO,GAAG,SAAS,KAAK,KAAK;AAAA,UAC7B,WAAU;AAAA,UAEV;AAAA,yDAAC,UAAK,WAAU,2CAA2C;AAAA;AAAA,cAAU;AAAA,eAAC;AAAA,YACtE,4CAAC,UAAK,WAAU,YAAY,iBAAM;AAAA,YAClC,4CAAC,yBAAE,WAAU,iDAAgD;AAAA;AAAA;AAAA,QAPxD,GAAG,SAAS,IAAI,KAAK;AAAA,MAQ5B,CACD;AAAA,MAEA,mBAAmB,KAClB;AAAA,QAAC;AAAA;AAAA,UACC,SAAS;AAAA,UACT,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,OAEA;AAAA,KAEJ;AAEJ;AAUA,MAAM,YAAY;AAClB,MAAM,UAAU;AAChB,MAAM,WAAW;AAEV,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA+B;AAC7B,SACE,6CAAC,SAAI,WAAU,wEAEb;AAAA,iDAAC,SACC;AAAA,kDAAC,SAAI,WAAU,QACb,sDAAC,UAAK,WAAU,uBAAsB,qBAAO,GAC/C;AAAA,MACA,4CAAC,SAAI,WAAU,0BACZ,uBAAa,IAAI,CAAC,EAAE,OAAO,MAAM,MAAM;AACtC,cAAM,aAAa,SAAS;AAC5B,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,SAAS,MAAM,aAAa,KAAK;AAAA,YACjC,eAAW,cAAG,WAAW,aAAa,UAAU,QAAQ;AAAA,YAEvD;AAAA,4BAAc,4CAAC,6BAAM,WAAU,WAAU;AAAA,cAC1C,4CAAC,UAAM,iBAAM;AAAA;AAAA;AAAA,UALR;AAAA,QAMP;AAAA,MAEJ,CAAC,GACH;AAAA,OACF;AAAA,IAEC,cAAc,SAAS,KACtB,4EACE;AAAA,kDAAC,SAAI,WAAU,yBAAwB;AAAA,MACtC,cAAc,IAAI,CAAC,SAAS,MAAM;AACjC,cAAM,eAAe,SAAS,QAAQ,SAAS,KAAK,CAAC;AACrD,eACE,6CAAC,SACE;AAAA,cAAI,KAAK,4CAAC,SAAI,WAAU,8BAA6B;AAAA,UACtD,6CAAC,SAAI,WAAU,gDACb;AAAA,wDAAC,UAAK,WAAU,wCAAuC,OAAO,QAAQ,WAAY,kBAAQ,WAAU;AAAA,YACpG,6CAAC,UAAK,WAAU,2CACb;AAAA,sBAAQ,OAAO;AAAA,cAAO;AAAA,eACzB;AAAA,aACF;AAAA,UACA,4CAAC,SAAI,WAAU,0BACZ,kBAAQ,OAAO,IAAI,CAAC,EAAE,OAAO,MAAM,MAAM;AACxC,kBAAM,aAAa,aAAa,SAAS,KAAK;AAC9C,mBACE;AAAA,cAAC;AAAA;AAAA,gBAEC,SAAS,MAAM,cAAc,QAAQ,WAAW,KAAK;AAAA,gBACrD,OAAO;AAAA,gBACP,eAAW,cAAG,WAAW,aAAa,UAAU,QAAQ;AAAA,gBAEvD;AAAA,gCAAc,4CAAC,6BAAM,WAAU,oBAAmB;AAAA,kBACnD,4CAAC,UAAK,WAAU,YAAY,iBAAM;AAAA,kBAClC,4CAAC,UAAK,eAAW,cAAG,YAAY,aAAa,eAAe,YAAY,GACrE,iBACH;AAAA;AAAA;AAAA,cATK;AAAA,YAUP;AAAA,UAEJ,CAAC,GACH;AAAA,aA1BQ,QAAQ,SA2BlB;AAAA,MAEJ,CAAC;AAAA,OACH;AAAA,KAEJ;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/collection-filters.tsx"],"sourcesContent":["\"use client\";\n\nimport { useMemo } from \"react\";\nimport { SlidersHorizontal, X, Check } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport type { ApiToken, CollectionTokensSort } from \"@medialane/sdk\";\n\nconst EXCLUDED_TRAIT_TYPES = new Set([\"registration\"]);\n\nexport const SORT_OPTIONS: { value: CollectionTokensSort; label: string }[] = [\n { value: \"recent\", label: \"Recent\" },\n { value: \"oldest\", label: \"Oldest\" },\n { value: \"name\", label: \"Name\" },\n { value: \"price\", label: \"Price\" },\n];\n\nexport interface TraitSection {\n traitType: string;\n values: { value: string; count: number }[];\n}\n\nexport function useCollectionFilters(\n tokens: ApiToken[],\n selected: Record<string, string[]>,\n onChange: (filters: Record<string, string[]>) => void,\n sort: CollectionTokensSort,\n onSortChange: (sort: CollectionTokensSort) => void,\n) {\n\n const traitSections: TraitSection[] = useMemo(() => {\n const map = new Map<string, Map<string, number>>();\n for (const token of tokens) {\n const attrs = Array.isArray(token.metadata?.attributes)\n ? (token.metadata.attributes as { trait_type?: string; value?: string }[])\n : [];\n for (const attr of attrs) {\n if (!attr.trait_type || attr.value == null) continue;\n if (EXCLUDED_TRAIT_TYPES.has(attr.trait_type.toLowerCase())) continue;\n if (!map.has(attr.trait_type)) map.set(attr.trait_type, new Map());\n const counts = map.get(attr.trait_type)!;\n const v = String(attr.value);\n counts.set(v, (counts.get(v) ?? 0) + 1);\n }\n }\n return Array.from(map.entries())\n .map(([traitType, counts]) => ({\n traitType,\n values: Array.from(counts.entries())\n .map(([value, count]) => ({ value, count }))\n .sort((a, b) => b.count - a.count || a.value.localeCompare(b.value)),\n }))\n .filter((section) => section.values.length >= 2);\n }, [tokens]);\n\n const activeEntries = Object.entries(selected).flatMap(([traitType, values]) =>\n values.map((value) => ({ traitType, value }))\n );\n const traitActiveCount = activeEntries.length;\n const sortIsDefault = sort === \"recent\";\n const totalActiveCount = traitActiveCount + (sortIsDefault ? 0 : 1);\n\n function toggleValue(traitType: string, value: string) {\n const current = selected[traitType] ?? [];\n const next = current.includes(value)\n ? current.filter((v) => v !== value)\n : [...current, value];\n const nextSelected = { ...selected };\n if (next.length === 0) {\n delete nextSelected[traitType];\n } else {\n nextSelected[traitType] = next;\n }\n onChange(nextSelected);\n }\n\n function clearAll() {\n onChange({});\n onSortChange(\"recent\");\n }\n\n function removeFilter(traitType: string, value: string) {\n toggleValue(traitType, value);\n }\n\n return { traitSections, activeEntries, totalActiveCount, sortIsDefault, toggleValue, clearAll, removeFilter };\n}\n\nconst TRIGGER_BTN = \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md border border-input bg-background text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground h-8 px-3 shrink-0\";\n\nexport interface CollectionFiltersTriggerProps {\n totalActiveCount: number;\n sortIsDefault: boolean;\n sort: CollectionTokensSort;\n activeEntries: { traitType: string; value: string }[];\n onOpen: () => void;\n onSortReset: () => void;\n onRemoveFilter: (traitType: string, value: string) => void;\n onClearAll: () => void;\n showButton?: boolean;\n showChips?: boolean;\n}\n\nexport function CollectionFiltersTrigger({\n totalActiveCount,\n sortIsDefault,\n sort,\n activeEntries,\n onOpen,\n onSortReset,\n onRemoveFilter,\n onClearAll,\n showButton = true,\n showChips = true,\n}: CollectionFiltersTriggerProps) {\n if (!showButton && (!showChips || (sortIsDefault && activeEntries.length === 0))) return null;\n return (\n <div className=\"flex items-center justify-end gap-2 flex-wrap\">\n {showButton && (\n <button onClick={onOpen} className={TRIGGER_BTN} aria-label=\"Filters\">\n <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n {totalActiveCount > 0 && (\n <span className=\"h-4 min-w-4 rounded-full bg-primary text-2xs font-bold text-primary-foreground flex items-center justify-center px-1 -mr-1\">\n {totalActiveCount}\n </span>\n )}\n </button>\n )}\n {showChips && (\n <>\n\n {!sortIsDefault && (\n <button\n onClick={onSortReset}\n className=\"inline-flex items-center gap-1 h-8 px-2.5 rounded-md border border-primary/40 bg-primary/10 text-xs font-medium text-foreground hover:bg-primary/20 transition-colors\"\n >\n <span className=\"text-muted-foreground text-2xs\">Sort:</span>\n <span>{SORT_OPTIONS.find((o) => o.value === sort)?.label}</span>\n <X className=\"h-3 w-3 text-muted-foreground ml-0.5\" />\n </button>\n )}\n\n {activeEntries.map(({ traitType, value }) => (\n <button\n key={`${traitType}:${value}`}\n onClick={() => onRemoveFilter(traitType, value)}\n title={`${traitType}: ${value}`}\n className=\"inline-flex max-w-full min-w-0 items-center gap-1 h-8 px-2.5 rounded-md border border-primary/40 bg-primary/10 text-xs font-medium text-foreground hover:bg-primary/20 transition-colors\"\n >\n <span className=\"text-muted-foreground text-2xs shrink-0\">{traitType}:</span>\n <span className=\"truncate\">{value}</span>\n <X className=\"h-3 w-3 text-muted-foreground ml-0.5 shrink-0\" />\n </button>\n ))}\n\n {totalActiveCount > 1 && (\n <button\n onClick={onClearAll}\n className=\"text-xs text-muted-foreground hover:text-foreground underline-offset-2 hover:underline transition-colors\"\n >\n Clear all\n </button>\n )}\n </>\n )}\n </div>\n );\n}\n\nexport interface CollectionFiltersBodyProps {\n sort: CollectionTokensSort;\n onSortChange: (sort: CollectionTokensSort) => void;\n traitSections: TraitSection[];\n selected: Record<string, string[]>;\n onToggleValue: (traitType: string, value: string) => void;\n}\n\nconst PILL_BASE = \"inline-flex max-w-full min-w-0 items-center gap-1 h-7 px-2.5 rounded-full border text-xs font-medium transition-colors\";\nconst PILL_ON = \"border-primary bg-primary text-primary-foreground\";\nconst PILL_OFF = \"border-border bg-transparent text-muted-foreground hover:text-foreground hover:border-foreground/30\";\n\nexport function CollectionFiltersBody({\n sort,\n onSortChange,\n traitSections,\n selected,\n onToggleValue,\n}: CollectionFiltersBodyProps) {\n return (\n <div className=\"flex-1 min-w-0 overflow-y-auto overflow-x-hidden px-5 py-3 space-y-4\">\n\n <div>\n <div className=\"mb-2\">\n <span className=\"text-sm font-medium\">Sort by</span>\n </div>\n <div className=\"flex flex-wrap gap-1.5\">\n {SORT_OPTIONS.map(({ value, label }) => {\n const isSelected = sort === value;\n return (\n <button\n key={value}\n onClick={() => onSortChange(value)}\n className={cn(PILL_BASE, isSelected ? PILL_ON : PILL_OFF)}\n >\n {isSelected && <Check className=\"h-3 w-3\" />}\n <span>{label}</span>\n </button>\n );\n })}\n </div>\n </div>\n\n {traitSections.length > 0 && (\n <>\n <div className=\"h-px w-full bg-border\" />\n {traitSections.map((section, i) => {\n const activeValues = selected[section.traitType] ?? [];\n return (\n <div key={section.traitType}>\n {i > 0 && <div className=\"h-px w-full bg-border mb-4\" />}\n <div className=\"flex items-center justify-between gap-3 mb-2\">\n <span className=\"min-w-0 truncate text-sm font-medium\" title={section.traitType}>{section.traitType}</span>\n <span className=\"shrink-0 text-2xs text-muted-foreground\">\n {section.values.length} values\n </span>\n </div>\n <div className=\"flex flex-wrap gap-1.5\">\n {section.values.map(({ value, count }) => {\n const isSelected = activeValues.includes(value);\n return (\n <button\n key={value}\n onClick={() => onToggleValue(section.traitType, value)}\n title={value}\n className={cn(PILL_BASE, isSelected ? PILL_ON : PILL_OFF)}\n >\n {isSelected && <Check className=\"h-3 w-3 shrink-0\" />}\n <span className=\"truncate\">{value}</span>\n <span className={cn(\"shrink-0\", isSelected ? \"opacity-80\" : \"opacity-60\")}>\n {count}\n </span>\n </button>\n );\n })}\n </div>\n </div>\n );\n })}\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -72,7 +72,6 @@ function CollectionFiltersTrigger({
|
|
|
72
72
|
return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2 flex-wrap", children: [
|
|
73
73
|
showButton && /* @__PURE__ */ jsxs("button", { onClick: onOpen, className: TRIGGER_BTN, "aria-label": "Filters", children: [
|
|
74
74
|
/* @__PURE__ */ jsx(SlidersHorizontal, { className: "h-3.5 w-3.5" }),
|
|
75
|
-
/* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: "Filters" }),
|
|
76
75
|
totalActiveCount > 0 && /* @__PURE__ */ jsx("span", { className: "h-4 min-w-4 rounded-full bg-primary text-2xs font-bold text-primary-foreground flex items-center justify-center px-1 -mr-1", children: totalActiveCount })
|
|
77
76
|
] }),
|
|
78
77
|
showChips && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/collection-filters.tsx"],"sourcesContent":["\"use client\";\n\nimport { useMemo } from \"react\";\nimport { SlidersHorizontal, X, Check } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport type { ApiToken, CollectionTokensSort } from \"@medialane/sdk\";\n\nconst EXCLUDED_TRAIT_TYPES = new Set([\"registration\"]);\n\nexport const SORT_OPTIONS: { value: CollectionTokensSort; label: string }[] = [\n { value: \"recent\", label: \"Recent\" },\n { value: \"oldest\", label: \"Oldest\" },\n { value: \"name\", label: \"Name\" },\n { value: \"price\", label: \"Price\" },\n];\n\nexport interface TraitSection {\n traitType: string;\n values: { value: string; count: number }[];\n}\n\nexport function useCollectionFilters(\n tokens: ApiToken[],\n selected: Record<string, string[]>,\n onChange: (filters: Record<string, string[]>) => void,\n sort: CollectionTokensSort,\n onSortChange: (sort: CollectionTokensSort) => void,\n) {\n\n const traitSections: TraitSection[] = useMemo(() => {\n const map = new Map<string, Map<string, number>>();\n for (const token of tokens) {\n const attrs = Array.isArray(token.metadata?.attributes)\n ? (token.metadata.attributes as { trait_type?: string; value?: string }[])\n : [];\n for (const attr of attrs) {\n if (!attr.trait_type || attr.value == null) continue;\n if (EXCLUDED_TRAIT_TYPES.has(attr.trait_type.toLowerCase())) continue;\n if (!map.has(attr.trait_type)) map.set(attr.trait_type, new Map());\n const counts = map.get(attr.trait_type)!;\n const v = String(attr.value);\n counts.set(v, (counts.get(v) ?? 0) + 1);\n }\n }\n return Array.from(map.entries())\n .map(([traitType, counts]) => ({\n traitType,\n values: Array.from(counts.entries())\n .map(([value, count]) => ({ value, count }))\n .sort((a, b) => b.count - a.count || a.value.localeCompare(b.value)),\n }))\n .filter((section) => section.values.length >= 2);\n }, [tokens]);\n\n const activeEntries = Object.entries(selected).flatMap(([traitType, values]) =>\n values.map((value) => ({ traitType, value }))\n );\n const traitActiveCount = activeEntries.length;\n const sortIsDefault = sort === \"recent\";\n const totalActiveCount = traitActiveCount + (sortIsDefault ? 0 : 1);\n\n function toggleValue(traitType: string, value: string) {\n const current = selected[traitType] ?? [];\n const next = current.includes(value)\n ? current.filter((v) => v !== value)\n : [...current, value];\n const nextSelected = { ...selected };\n if (next.length === 0) {\n delete nextSelected[traitType];\n } else {\n nextSelected[traitType] = next;\n }\n onChange(nextSelected);\n }\n\n function clearAll() {\n onChange({});\n onSortChange(\"recent\");\n }\n\n function removeFilter(traitType: string, value: string) {\n toggleValue(traitType, value);\n }\n\n return { traitSections, activeEntries, totalActiveCount, sortIsDefault, toggleValue, clearAll, removeFilter };\n}\n\nconst TRIGGER_BTN = \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md border border-input bg-background text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground h-8 px-3 shrink-0\";\n\nexport interface CollectionFiltersTriggerProps {\n totalActiveCount: number;\n sortIsDefault: boolean;\n sort: CollectionTokensSort;\n activeEntries: { traitType: string; value: string }[];\n onOpen: () => void;\n onSortReset: () => void;\n onRemoveFilter: (traitType: string, value: string) => void;\n onClearAll: () => void;\n showButton?: boolean;\n showChips?: boolean;\n}\n\nexport function CollectionFiltersTrigger({\n totalActiveCount,\n sortIsDefault,\n sort,\n activeEntries,\n onOpen,\n onSortReset,\n onRemoveFilter,\n onClearAll,\n showButton = true,\n showChips = true,\n}: CollectionFiltersTriggerProps) {\n if (!showButton && (!showChips || (sortIsDefault && activeEntries.length === 0))) return null;\n return (\n <div className=\"flex items-center justify-end gap-2 flex-wrap\">\n {showButton && (\n <button onClick={onOpen} className={TRIGGER_BTN} aria-label=\"Filters\">\n <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n <span className=\"hidden sm:inline\">Filters</span>\n {totalActiveCount > 0 && (\n <span className=\"h-4 min-w-4 rounded-full bg-primary text-2xs font-bold text-primary-foreground flex items-center justify-center px-1 -mr-1\">\n {totalActiveCount}\n </span>\n )}\n </button>\n )}\n {showChips && (\n <>\n\n {!sortIsDefault && (\n <button\n onClick={onSortReset}\n className=\"inline-flex items-center gap-1 h-8 px-2.5 rounded-md border border-primary/40 bg-primary/10 text-xs font-medium text-foreground hover:bg-primary/20 transition-colors\"\n >\n <span className=\"text-muted-foreground text-2xs\">Sort:</span>\n <span>{SORT_OPTIONS.find((o) => o.value === sort)?.label}</span>\n <X className=\"h-3 w-3 text-muted-foreground ml-0.5\" />\n </button>\n )}\n\n {activeEntries.map(({ traitType, value }) => (\n <button\n key={`${traitType}:${value}`}\n onClick={() => onRemoveFilter(traitType, value)}\n title={`${traitType}: ${value}`}\n className=\"inline-flex max-w-full min-w-0 items-center gap-1 h-8 px-2.5 rounded-md border border-primary/40 bg-primary/10 text-xs font-medium text-foreground hover:bg-primary/20 transition-colors\"\n >\n <span className=\"text-muted-foreground text-2xs shrink-0\">{traitType}:</span>\n <span className=\"truncate\">{value}</span>\n <X className=\"h-3 w-3 text-muted-foreground ml-0.5 shrink-0\" />\n </button>\n ))}\n\n {totalActiveCount > 1 && (\n <button\n onClick={onClearAll}\n className=\"text-xs text-muted-foreground hover:text-foreground underline-offset-2 hover:underline transition-colors\"\n >\n Clear all\n </button>\n )}\n </>\n )}\n </div>\n );\n}\n\nexport interface CollectionFiltersBodyProps {\n sort: CollectionTokensSort;\n onSortChange: (sort: CollectionTokensSort) => void;\n traitSections: TraitSection[];\n selected: Record<string, string[]>;\n onToggleValue: (traitType: string, value: string) => void;\n}\n\nconst PILL_BASE = \"inline-flex max-w-full min-w-0 items-center gap-1 h-7 px-2.5 rounded-full border text-xs font-medium transition-colors\";\nconst PILL_ON = \"border-primary bg-primary text-primary-foreground\";\nconst PILL_OFF = \"border-border bg-transparent text-muted-foreground hover:text-foreground hover:border-foreground/30\";\n\nexport function CollectionFiltersBody({\n sort,\n onSortChange,\n traitSections,\n selected,\n onToggleValue,\n}: CollectionFiltersBodyProps) {\n return (\n <div className=\"flex-1 min-w-0 overflow-y-auto overflow-x-hidden px-5 py-3 space-y-4\">\n\n <div>\n <div className=\"mb-2\">\n <span className=\"text-sm font-medium\">Sort by</span>\n </div>\n <div className=\"flex flex-wrap gap-1.5\">\n {SORT_OPTIONS.map(({ value, label }) => {\n const isSelected = sort === value;\n return (\n <button\n key={value}\n onClick={() => onSortChange(value)}\n className={cn(PILL_BASE, isSelected ? PILL_ON : PILL_OFF)}\n >\n {isSelected && <Check className=\"h-3 w-3\" />}\n <span>{label}</span>\n </button>\n );\n })}\n </div>\n </div>\n\n {traitSections.length > 0 && (\n <>\n <div className=\"h-px w-full bg-border\" />\n {traitSections.map((section, i) => {\n const activeValues = selected[section.traitType] ?? [];\n return (\n <div key={section.traitType}>\n {i > 0 && <div className=\"h-px w-full bg-border mb-4\" />}\n <div className=\"flex items-center justify-between gap-3 mb-2\">\n <span className=\"min-w-0 truncate text-sm font-medium\" title={section.traitType}>{section.traitType}</span>\n <span className=\"shrink-0 text-2xs text-muted-foreground\">\n {section.values.length} values\n </span>\n </div>\n <div className=\"flex flex-wrap gap-1.5\">\n {section.values.map(({ value, count }) => {\n const isSelected = activeValues.includes(value);\n return (\n <button\n key={value}\n onClick={() => onToggleValue(section.traitType, value)}\n title={value}\n className={cn(PILL_BASE, isSelected ? PILL_ON : PILL_OFF)}\n >\n {isSelected && <Check className=\"h-3 w-3 shrink-0\" />}\n <span className=\"truncate\">{value}</span>\n <span className={cn(\"shrink-0\", isSelected ? \"opacity-80\" : \"opacity-60\")}>\n {count}\n </span>\n </button>\n );\n })}\n </div>\n </div>\n );\n })}\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/collection-filters.tsx"],"sourcesContent":["\"use client\";\n\nimport { useMemo } from \"react\";\nimport { SlidersHorizontal, X, Check } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport type { ApiToken, CollectionTokensSort } from \"@medialane/sdk\";\n\nconst EXCLUDED_TRAIT_TYPES = new Set([\"registration\"]);\n\nexport const SORT_OPTIONS: { value: CollectionTokensSort; label: string }[] = [\n { value: \"recent\", label: \"Recent\" },\n { value: \"oldest\", label: \"Oldest\" },\n { value: \"name\", label: \"Name\" },\n { value: \"price\", label: \"Price\" },\n];\n\nexport interface TraitSection {\n traitType: string;\n values: { value: string; count: number }[];\n}\n\nexport function useCollectionFilters(\n tokens: ApiToken[],\n selected: Record<string, string[]>,\n onChange: (filters: Record<string, string[]>) => void,\n sort: CollectionTokensSort,\n onSortChange: (sort: CollectionTokensSort) => void,\n) {\n\n const traitSections: TraitSection[] = useMemo(() => {\n const map = new Map<string, Map<string, number>>();\n for (const token of tokens) {\n const attrs = Array.isArray(token.metadata?.attributes)\n ? (token.metadata.attributes as { trait_type?: string; value?: string }[])\n : [];\n for (const attr of attrs) {\n if (!attr.trait_type || attr.value == null) continue;\n if (EXCLUDED_TRAIT_TYPES.has(attr.trait_type.toLowerCase())) continue;\n if (!map.has(attr.trait_type)) map.set(attr.trait_type, new Map());\n const counts = map.get(attr.trait_type)!;\n const v = String(attr.value);\n counts.set(v, (counts.get(v) ?? 0) + 1);\n }\n }\n return Array.from(map.entries())\n .map(([traitType, counts]) => ({\n traitType,\n values: Array.from(counts.entries())\n .map(([value, count]) => ({ value, count }))\n .sort((a, b) => b.count - a.count || a.value.localeCompare(b.value)),\n }))\n .filter((section) => section.values.length >= 2);\n }, [tokens]);\n\n const activeEntries = Object.entries(selected).flatMap(([traitType, values]) =>\n values.map((value) => ({ traitType, value }))\n );\n const traitActiveCount = activeEntries.length;\n const sortIsDefault = sort === \"recent\";\n const totalActiveCount = traitActiveCount + (sortIsDefault ? 0 : 1);\n\n function toggleValue(traitType: string, value: string) {\n const current = selected[traitType] ?? [];\n const next = current.includes(value)\n ? current.filter((v) => v !== value)\n : [...current, value];\n const nextSelected = { ...selected };\n if (next.length === 0) {\n delete nextSelected[traitType];\n } else {\n nextSelected[traitType] = next;\n }\n onChange(nextSelected);\n }\n\n function clearAll() {\n onChange({});\n onSortChange(\"recent\");\n }\n\n function removeFilter(traitType: string, value: string) {\n toggleValue(traitType, value);\n }\n\n return { traitSections, activeEntries, totalActiveCount, sortIsDefault, toggleValue, clearAll, removeFilter };\n}\n\nconst TRIGGER_BTN = \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md border border-input bg-background text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground h-8 px-3 shrink-0\";\n\nexport interface CollectionFiltersTriggerProps {\n totalActiveCount: number;\n sortIsDefault: boolean;\n sort: CollectionTokensSort;\n activeEntries: { traitType: string; value: string }[];\n onOpen: () => void;\n onSortReset: () => void;\n onRemoveFilter: (traitType: string, value: string) => void;\n onClearAll: () => void;\n showButton?: boolean;\n showChips?: boolean;\n}\n\nexport function CollectionFiltersTrigger({\n totalActiveCount,\n sortIsDefault,\n sort,\n activeEntries,\n onOpen,\n onSortReset,\n onRemoveFilter,\n onClearAll,\n showButton = true,\n showChips = true,\n}: CollectionFiltersTriggerProps) {\n if (!showButton && (!showChips || (sortIsDefault && activeEntries.length === 0))) return null;\n return (\n <div className=\"flex items-center justify-end gap-2 flex-wrap\">\n {showButton && (\n <button onClick={onOpen} className={TRIGGER_BTN} aria-label=\"Filters\">\n <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n {totalActiveCount > 0 && (\n <span className=\"h-4 min-w-4 rounded-full bg-primary text-2xs font-bold text-primary-foreground flex items-center justify-center px-1 -mr-1\">\n {totalActiveCount}\n </span>\n )}\n </button>\n )}\n {showChips && (\n <>\n\n {!sortIsDefault && (\n <button\n onClick={onSortReset}\n className=\"inline-flex items-center gap-1 h-8 px-2.5 rounded-md border border-primary/40 bg-primary/10 text-xs font-medium text-foreground hover:bg-primary/20 transition-colors\"\n >\n <span className=\"text-muted-foreground text-2xs\">Sort:</span>\n <span>{SORT_OPTIONS.find((o) => o.value === sort)?.label}</span>\n <X className=\"h-3 w-3 text-muted-foreground ml-0.5\" />\n </button>\n )}\n\n {activeEntries.map(({ traitType, value }) => (\n <button\n key={`${traitType}:${value}`}\n onClick={() => onRemoveFilter(traitType, value)}\n title={`${traitType}: ${value}`}\n className=\"inline-flex max-w-full min-w-0 items-center gap-1 h-8 px-2.5 rounded-md border border-primary/40 bg-primary/10 text-xs font-medium text-foreground hover:bg-primary/20 transition-colors\"\n >\n <span className=\"text-muted-foreground text-2xs shrink-0\">{traitType}:</span>\n <span className=\"truncate\">{value}</span>\n <X className=\"h-3 w-3 text-muted-foreground ml-0.5 shrink-0\" />\n </button>\n ))}\n\n {totalActiveCount > 1 && (\n <button\n onClick={onClearAll}\n className=\"text-xs text-muted-foreground hover:text-foreground underline-offset-2 hover:underline transition-colors\"\n >\n Clear all\n </button>\n )}\n </>\n )}\n </div>\n );\n}\n\nexport interface CollectionFiltersBodyProps {\n sort: CollectionTokensSort;\n onSortChange: (sort: CollectionTokensSort) => void;\n traitSections: TraitSection[];\n selected: Record<string, string[]>;\n onToggleValue: (traitType: string, value: string) => void;\n}\n\nconst PILL_BASE = \"inline-flex max-w-full min-w-0 items-center gap-1 h-7 px-2.5 rounded-full border text-xs font-medium transition-colors\";\nconst PILL_ON = \"border-primary bg-primary text-primary-foreground\";\nconst PILL_OFF = \"border-border bg-transparent text-muted-foreground hover:text-foreground hover:border-foreground/30\";\n\nexport function CollectionFiltersBody({\n sort,\n onSortChange,\n traitSections,\n selected,\n onToggleValue,\n}: CollectionFiltersBodyProps) {\n return (\n <div className=\"flex-1 min-w-0 overflow-y-auto overflow-x-hidden px-5 py-3 space-y-4\">\n\n <div>\n <div className=\"mb-2\">\n <span className=\"text-sm font-medium\">Sort by</span>\n </div>\n <div className=\"flex flex-wrap gap-1.5\">\n {SORT_OPTIONS.map(({ value, label }) => {\n const isSelected = sort === value;\n return (\n <button\n key={value}\n onClick={() => onSortChange(value)}\n className={cn(PILL_BASE, isSelected ? PILL_ON : PILL_OFF)}\n >\n {isSelected && <Check className=\"h-3 w-3\" />}\n <span>{label}</span>\n </button>\n );\n })}\n </div>\n </div>\n\n {traitSections.length > 0 && (\n <>\n <div className=\"h-px w-full bg-border\" />\n {traitSections.map((section, i) => {\n const activeValues = selected[section.traitType] ?? [];\n return (\n <div key={section.traitType}>\n {i > 0 && <div className=\"h-px w-full bg-border mb-4\" />}\n <div className=\"flex items-center justify-between gap-3 mb-2\">\n <span className=\"min-w-0 truncate text-sm font-medium\" title={section.traitType}>{section.traitType}</span>\n <span className=\"shrink-0 text-2xs text-muted-foreground\">\n {section.values.length} values\n </span>\n </div>\n <div className=\"flex flex-wrap gap-1.5\">\n {section.values.map(({ value, count }) => {\n const isSelected = activeValues.includes(value);\n return (\n <button\n key={value}\n onClick={() => onToggleValue(section.traitType, value)}\n title={value}\n className={cn(PILL_BASE, isSelected ? PILL_ON : PILL_OFF)}\n >\n {isSelected && <Check className=\"h-3 w-3 shrink-0\" />}\n <span className=\"truncate\">{value}</span>\n <span className={cn(\"shrink-0\", isSelected ? \"opacity-80\" : \"opacity-60\")}>\n {count}\n </span>\n </button>\n );\n })}\n </div>\n </div>\n );\n })}\n </>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -30,7 +30,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
var currency_icon_exports = {};
|
|
31
31
|
__export(currency_icon_exports, {
|
|
32
32
|
CurrencyAmount: () => CurrencyAmount,
|
|
33
|
-
CurrencyIcon: () => CurrencyIcon
|
|
33
|
+
CurrencyIcon: () => CurrencyIcon,
|
|
34
|
+
hasCurrencyIcon: () => hasCurrencyIcon
|
|
34
35
|
});
|
|
35
36
|
module.exports = __toCommonJS(currency_icon_exports);
|
|
36
37
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -43,6 +44,9 @@ const CURRENCY_ICON_PATHS = {
|
|
|
43
44
|
STRK: "/strk.svg",
|
|
44
45
|
WBTC: "/btc.svg"
|
|
45
46
|
};
|
|
47
|
+
function hasCurrencyIcon(symbol) {
|
|
48
|
+
return !!symbol && symbol in CURRENCY_ICON_PATHS;
|
|
49
|
+
}
|
|
46
50
|
function CurrencyIcon({ symbol, size = 16, className, iconsBasePath = "" }) {
|
|
47
51
|
const path = symbol ? CURRENCY_ICON_PATHS[symbol] : void 0;
|
|
48
52
|
if (!path) return null;
|
|
@@ -74,6 +78,7 @@ function CurrencyAmount({
|
|
|
74
78
|
// Annotate the CommonJS export names for ESM import in node:
|
|
75
79
|
0 && (module.exports = {
|
|
76
80
|
CurrencyAmount,
|
|
77
|
-
CurrencyIcon
|
|
81
|
+
CurrencyIcon,
|
|
82
|
+
hasCurrencyIcon
|
|
78
83
|
});
|
|
79
84
|
//# sourceMappingURL=currency-icon.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/currency-icon.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"./image.js\";\nimport { cn } from \"../utils/cn.js\";\n\nconst CURRENCY_ICON_PATHS: Record<string, string> = {\n USDC: \"/usdc.svg\",\n USDT: \"/usdt.svg\",\n ETH: \"/eth.svg\",\n STRK: \"/strk.svg\",\n WBTC: \"/btc.svg\",\n};\n\nexport interface CurrencyIconProps {\n symbol: string | null | undefined;\n size?: number;\n className?: string;\n\n iconsBasePath?: string;\n}\n\nexport function CurrencyIcon({ symbol, size = 16, className, iconsBasePath = \"\" }: CurrencyIconProps) {\n const path = symbol ? CURRENCY_ICON_PATHS[symbol] : undefined;\n if (!path) return null;\n return (\n <Image\n src={`${iconsBasePath}${path}`}\n alt={symbol ?? \"\"}\n width={size}\n height={size}\n className={cn(\"inline-block shrink-0\", className)}\n unoptimized\n />\n );\n}\n\nexport interface CurrencyAmountProps {\n amount: string;\n symbol: string | null | undefined;\n amountClassName?: string;\n iconSize?: number;\n className?: string;\n\n iconsBasePath?: string;\n}\n\nexport function CurrencyAmount({\n amount,\n symbol,\n amountClassName,\n iconSize = 14,\n className,\n iconsBasePath,\n}: CurrencyAmountProps) {\n return (\n <span className={cn(\"inline-flex items-center gap-1\", className)}>\n <CurrencyIcon symbol={symbol} size={iconSize} iconsBasePath={iconsBasePath} />\n <span className={amountClassName}>{amount}</span>\n </span>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
1
|
+
{"version":3,"sources":["../../src/components/currency-icon.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"./image.js\";\nimport { cn } from \"../utils/cn.js\";\n\nconst CURRENCY_ICON_PATHS: Record<string, string> = {\n USDC: \"/usdc.svg\",\n USDT: \"/usdt.svg\",\n ETH: \"/eth.svg\",\n STRK: \"/strk.svg\",\n WBTC: \"/btc.svg\",\n};\n\nexport function hasCurrencyIcon(symbol: string | null | undefined): boolean {\n return !!symbol && symbol in CURRENCY_ICON_PATHS;\n}\n\nexport interface CurrencyIconProps {\n symbol: string | null | undefined;\n size?: number;\n className?: string;\n\n iconsBasePath?: string;\n}\n\nexport function CurrencyIcon({ symbol, size = 16, className, iconsBasePath = \"\" }: CurrencyIconProps) {\n const path = symbol ? CURRENCY_ICON_PATHS[symbol] : undefined;\n if (!path) return null;\n return (\n <Image\n src={`${iconsBasePath}${path}`}\n alt={symbol ?? \"\"}\n width={size}\n height={size}\n className={cn(\"inline-block shrink-0\", className)}\n unoptimized\n />\n );\n}\n\nexport interface CurrencyAmountProps {\n amount: string;\n symbol: string | null | undefined;\n amountClassName?: string;\n iconSize?: number;\n className?: string;\n\n iconsBasePath?: string;\n}\n\nexport function CurrencyAmount({\n amount,\n symbol,\n amountClassName,\n iconSize = 14,\n className,\n iconsBasePath,\n}: CurrencyAmountProps) {\n return (\n <span className={cn(\"inline-flex items-center gap-1\", className)}>\n <CurrencyIcon symbol={symbol} size={iconSize} iconsBasePath={iconsBasePath} />\n <span className={amountClassName}>{amount}</span>\n </span>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6BI;AA3BJ,mBAAkB;AAClB,gBAAmB;AAEnB,MAAM,sBAA8C;AAAA,EAClD,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,MAAM;AACR;AAEO,SAAS,gBAAgB,QAA4C;AAC1E,SAAO,CAAC,CAAC,UAAU,UAAU;AAC/B;AAUO,SAAS,aAAa,EAAE,QAAQ,OAAO,IAAI,WAAW,gBAAgB,GAAG,GAAsB;AACpG,QAAM,OAAO,SAAS,oBAAoB,MAAM,IAAI;AACpD,MAAI,CAAC,KAAM,QAAO;AAClB,SACE;AAAA,IAAC,aAAAA;AAAA,IAAA;AAAA,MACC,KAAK,GAAG,aAAa,GAAG,IAAI;AAAA,MAC5B,KAAK,UAAU;AAAA,MACf,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,eAAW,cAAG,yBAAyB,SAAS;AAAA,MAChD,aAAW;AAAA;AAAA,EACb;AAEJ;AAYO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AACF,GAAwB;AACtB,SACE,6CAAC,UAAK,eAAW,cAAG,kCAAkC,SAAS,GAC7D;AAAA,gDAAC,gBAAa,QAAgB,MAAM,UAAU,eAA8B;AAAA,IAC5E,4CAAC,UAAK,WAAW,iBAAkB,kBAAO;AAAA,KAC5C;AAEJ;","names":["Image"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
|
|
3
|
+
declare function hasCurrencyIcon(symbol: string | null | undefined): boolean;
|
|
3
4
|
interface CurrencyIconProps {
|
|
4
5
|
symbol: string | null | undefined;
|
|
5
6
|
size?: number;
|
|
@@ -17,4 +18,4 @@ interface CurrencyAmountProps {
|
|
|
17
18
|
}
|
|
18
19
|
declare function CurrencyAmount({ amount, symbol, amountClassName, iconSize, className, iconsBasePath, }: CurrencyAmountProps): react_jsx_runtime.JSX.Element;
|
|
19
20
|
|
|
20
|
-
export { CurrencyAmount, type CurrencyAmountProps, CurrencyIcon, type CurrencyIconProps };
|
|
21
|
+
export { CurrencyAmount, type CurrencyAmountProps, CurrencyIcon, type CurrencyIconProps, hasCurrencyIcon };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
|
|
3
|
+
declare function hasCurrencyIcon(symbol: string | null | undefined): boolean;
|
|
3
4
|
interface CurrencyIconProps {
|
|
4
5
|
symbol: string | null | undefined;
|
|
5
6
|
size?: number;
|
|
@@ -17,4 +18,4 @@ interface CurrencyAmountProps {
|
|
|
17
18
|
}
|
|
18
19
|
declare function CurrencyAmount({ amount, symbol, amountClassName, iconSize, className, iconsBasePath, }: CurrencyAmountProps): react_jsx_runtime.JSX.Element;
|
|
19
20
|
|
|
20
|
-
export { CurrencyAmount, type CurrencyAmountProps, CurrencyIcon, type CurrencyIconProps };
|
|
21
|
+
export { CurrencyAmount, type CurrencyAmountProps, CurrencyIcon, type CurrencyIconProps, hasCurrencyIcon };
|
|
@@ -9,6 +9,9 @@ const CURRENCY_ICON_PATHS = {
|
|
|
9
9
|
STRK: "/strk.svg",
|
|
10
10
|
WBTC: "/btc.svg"
|
|
11
11
|
};
|
|
12
|
+
function hasCurrencyIcon(symbol) {
|
|
13
|
+
return !!symbol && symbol in CURRENCY_ICON_PATHS;
|
|
14
|
+
}
|
|
12
15
|
function CurrencyIcon({ symbol, size = 16, className, iconsBasePath = "" }) {
|
|
13
16
|
const path = symbol ? CURRENCY_ICON_PATHS[symbol] : void 0;
|
|
14
17
|
if (!path) return null;
|
|
@@ -39,6 +42,7 @@ function CurrencyAmount({
|
|
|
39
42
|
}
|
|
40
43
|
export {
|
|
41
44
|
CurrencyAmount,
|
|
42
|
-
CurrencyIcon
|
|
45
|
+
CurrencyIcon,
|
|
46
|
+
hasCurrencyIcon
|
|
43
47
|
};
|
|
44
48
|
//# sourceMappingURL=currency-icon.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/currency-icon.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"./image.js\";\nimport { cn } from \"../utils/cn.js\";\n\nconst CURRENCY_ICON_PATHS: Record<string, string> = {\n USDC: \"/usdc.svg\",\n USDT: \"/usdt.svg\",\n ETH: \"/eth.svg\",\n STRK: \"/strk.svg\",\n WBTC: \"/btc.svg\",\n};\n\nexport interface CurrencyIconProps {\n symbol: string | null | undefined;\n size?: number;\n className?: string;\n\n iconsBasePath?: string;\n}\n\nexport function CurrencyIcon({ symbol, size = 16, className, iconsBasePath = \"\" }: CurrencyIconProps) {\n const path = symbol ? CURRENCY_ICON_PATHS[symbol] : undefined;\n if (!path) return null;\n return (\n <Image\n src={`${iconsBasePath}${path}`}\n alt={symbol ?? \"\"}\n width={size}\n height={size}\n className={cn(\"inline-block shrink-0\", className)}\n unoptimized\n />\n );\n}\n\nexport interface CurrencyAmountProps {\n amount: string;\n symbol: string | null | undefined;\n amountClassName?: string;\n iconSize?: number;\n className?: string;\n\n iconsBasePath?: string;\n}\n\nexport function CurrencyAmount({\n amount,\n symbol,\n amountClassName,\n iconSize = 14,\n className,\n iconsBasePath,\n}: CurrencyAmountProps) {\n return (\n <span className={cn(\"inline-flex items-center gap-1\", className)}>\n <CurrencyIcon symbol={symbol} size={iconSize} iconsBasePath={iconsBasePath} />\n <span className={amountClassName}>{amount}</span>\n </span>\n );\n}\n"],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../../src/components/currency-icon.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"./image.js\";\nimport { cn } from \"../utils/cn.js\";\n\nconst CURRENCY_ICON_PATHS: Record<string, string> = {\n USDC: \"/usdc.svg\",\n USDT: \"/usdt.svg\",\n ETH: \"/eth.svg\",\n STRK: \"/strk.svg\",\n WBTC: \"/btc.svg\",\n};\n\nexport function hasCurrencyIcon(symbol: string | null | undefined): boolean {\n return !!symbol && symbol in CURRENCY_ICON_PATHS;\n}\n\nexport interface CurrencyIconProps {\n symbol: string | null | undefined;\n size?: number;\n className?: string;\n\n iconsBasePath?: string;\n}\n\nexport function CurrencyIcon({ symbol, size = 16, className, iconsBasePath = \"\" }: CurrencyIconProps) {\n const path = symbol ? CURRENCY_ICON_PATHS[symbol] : undefined;\n if (!path) return null;\n return (\n <Image\n src={`${iconsBasePath}${path}`}\n alt={symbol ?? \"\"}\n width={size}\n height={size}\n className={cn(\"inline-block shrink-0\", className)}\n unoptimized\n />\n );\n}\n\nexport interface CurrencyAmountProps {\n amount: string;\n symbol: string | null | undefined;\n amountClassName?: string;\n iconSize?: number;\n className?: string;\n\n iconsBasePath?: string;\n}\n\nexport function CurrencyAmount({\n amount,\n symbol,\n amountClassName,\n iconSize = 14,\n className,\n iconsBasePath,\n}: CurrencyAmountProps) {\n return (\n <span className={cn(\"inline-flex items-center gap-1\", className)}>\n <CurrencyIcon symbol={symbol} size={iconSize} iconsBasePath={iconsBasePath} />\n <span className={amountClassName}>{amount}</span>\n </span>\n );\n}\n"],"mappings":";AA6BI,cA8BA,YA9BA;AA3BJ,OAAO,WAAW;AAClB,SAAS,UAAU;AAEnB,MAAM,sBAA8C;AAAA,EAClD,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,MAAM;AACR;AAEO,SAAS,gBAAgB,QAA4C;AAC1E,SAAO,CAAC,CAAC,UAAU,UAAU;AAC/B;AAUO,SAAS,aAAa,EAAE,QAAQ,OAAO,IAAI,WAAW,gBAAgB,GAAG,GAAsB;AACpG,QAAM,OAAO,SAAS,oBAAoB,MAAM,IAAI;AACpD,MAAI,CAAC,KAAM,QAAO;AAClB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK,GAAG,aAAa,GAAG,IAAI;AAAA,MAC5B,KAAK,UAAU;AAAA,MACf,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,WAAW,GAAG,yBAAyB,SAAS;AAAA,MAChD,aAAW;AAAA;AAAA,EACb;AAEJ;AAYO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AACF,GAAwB;AACtB,SACE,qBAAC,UAAK,WAAW,GAAG,kCAAkC,SAAS,GAC7D;AAAA,wBAAC,gBAAa,QAAgB,MAAM,UAAU,eAA8B;AAAA,IAC5E,oBAAC,UAAK,WAAW,iBAAkB,kBAAO;AAAA,KAC5C;AAEJ;","names":[]}
|
|
@@ -162,13 +162,13 @@ function IpTypePage({ slug, useMarketActions }) {
|
|
|
162
162
|
"button",
|
|
163
163
|
{
|
|
164
164
|
onClick: () => setFiltersOpen(true),
|
|
165
|
+
"aria-label": "Filters",
|
|
165
166
|
className: (0, import_cn.cn)(
|
|
166
167
|
"inline-flex items-center gap-1.5 text-xs px-3.5 py-2 rounded-full border font-medium transition-colors",
|
|
167
168
|
hasActiveFilters ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground"
|
|
168
169
|
),
|
|
169
170
|
children: [
|
|
170
171
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.SlidersHorizontal, { className: "h-3.5 w-3.5" }),
|
|
171
|
-
"Filters",
|
|
172
172
|
activeChipCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-0.5 bg-primary text-primary-foreground rounded-full px-1.5 text-2xs font-bold leading-4", children: activeChipCount })
|
|
173
173
|
]
|
|
174
174
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/ip-type-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useRef } from \"react\";\nimport { SlidersHorizontal, Search, X as XIcon } from \"lucide-react\";\nimport type { ApiToken } from \"@medialane/sdk\";\nimport Link from \"./link.js\";\nimport { Badge } from \"./badge.js\";\nimport { Button } from \"./button.js\";\nimport { Dialog, DialogContent, DialogTitle } from \"./dialog.js\";\nimport { Input } from \"./input.js\";\nimport { PageContainer } from \"./page-container.js\";\nimport { LoadMoreSentinel } from \"./load-more-sentinel.js\";\nimport { IP_TYPE_CONFIG, IP_TYPE_MAP } from \"./ip-type-badge.js\";\nimport { TokenCard, TokenCardSkeleton } from \"./token-card.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport type { CollectionMarketActions } from \"./collection-page.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { isSameAddress } from \"../utils/same-address.js\";\nimport { useTokensByIpType } from \"../utils/use-tokens-by-ip-type.js\";\nimport { emptyMessages } from \"../utils/empty-messages.js\";\n\nconst PAGE_SIZE = 24;\n\nfunction FilterChip({ active, onClick, label }: { active: boolean; onClick: () => void; label: string }) {\n return (\n <button\n onClick={onClick}\n className={cn(\n \"text-xs px-3 py-1.5 rounded-full border transition-colors whitespace-nowrap\",\n active\n ? \"border-primary bg-primary/10 text-primary font-medium\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n {label}\n </button>\n );\n}\n\nexport interface IpTypePageProps {\n slug: string;\n useMarketActions: () => CollectionMarketActions;\n}\n\nexport function IpTypePage({ slug, useMarketActions }: IpTypePageProps) {\n const { walletAddress } = useMedialaneApp();\n const market = useMarketActions();\n const config = IP_TYPE_MAP[slug];\n const Icon = config?.icon;\n const [page, setPage] = useState(1);\n const [listedOnly, setListedOnly] = useState(false);\n const [allTokens, setAllTokens] = useState<ApiToken[]>([]);\n const prevSlug = useRef(slug);\n\n const [filtersOpen, setFiltersOpen] = useState(false);\n const [sortOrder, setSortOrder] = useState<\"recent\" | \"price_asc\" | \"price_desc\">(\"recent\");\n const [licenseFilter, setLicenseFilter] = useState<string>(\"all\");\n const [creatorSearchInput, setCreatorSearchInput] = useState(\"\");\n const [creatorSearch, setCreatorSearch] = useState(\"\");\n\n useEffect(() => {\n if (prevSlug.current !== slug) {\n prevSlug.current = slug;\n setPage(1);\n setAllTokens([]);\n }\n }, [slug]);\n\n useEffect(() => {\n const t = setTimeout(() => setCreatorSearch(creatorSearchInput), 300);\n return () => clearTimeout(t);\n }, [creatorSearchInput]);\n\n const { tokens, meta, isLoading } = useTokensByIpType(slug, page, PAGE_SIZE);\n\n useEffect(() => {\n if (isLoading) return;\n if (page === 1) {\n setAllTokens(tokens);\n } else {\n setAllTokens((prev) => {\n const seen = new Set(prev.map((t) => `${t.contractAddress}:${t.tokenId}`));\n const fresh = tokens.filter((t) => !seen.has(`${t.contractAddress}:${t.tokenId}`));\n return fresh.length > 0 ? [...prev, ...fresh] : prev;\n });\n }\n }, [tokens, isLoading, page]);\n\n const activeFilterCount =\n (sortOrder !== \"recent\" ? 1 : 0) +\n (licenseFilter !== \"all\" ? 1 : 0) +\n (creatorSearch !== \"\" ? 1 : 0);\n const activeChipCount = activeFilterCount + (listedOnly ? 1 : 0);\n const hasActiveFilters = activeChipCount > 0;\n const resetAll = () => {\n setSortOrder(\"recent\");\n setLicenseFilter(\"all\");\n setCreatorSearch(\"\");\n setCreatorSearchInput(\"\");\n setListedOnly(false);\n };\n\n let displayed = listedOnly\n ? allTokens.filter((t) => (t.activeOrders?.length ?? 0) > 0)\n : [...allTokens];\n\n if (licenseFilter !== \"all\") {\n displayed = displayed.filter((t) =>\n t.metadata?.attributes?.some(\n (a) => a.trait_type === \"License\" && a.value === licenseFilter\n )\n );\n }\n if (creatorSearch) {\n const q = creatorSearch.toLowerCase();\n displayed = displayed.filter((t) => {\n const creatorVal =\n t.metadata?.attributes?.find((a) => a.trait_type === \"Creator\")?.value ?? \"\";\n return (\n String(creatorVal).toLowerCase().includes(q) ||\n t.contractAddress.toLowerCase().includes(q)\n );\n });\n }\n if (sortOrder === \"price_asc\") {\n displayed = [...displayed].sort((a, b) => {\n const pa = parseFloat(a.activeOrders?.[0]?.price?.formatted ?? \"Infinity\");\n const pb = parseFloat(b.activeOrders?.[0]?.price?.formatted ?? \"Infinity\");\n return pa - pb;\n });\n } else if (sortOrder === \"price_desc\") {\n displayed = [...displayed].sort((a, b) => {\n const pa = parseFloat(a.activeOrders?.[0]?.price?.formatted ?? \"0\");\n const pb = parseFloat(b.activeOrders?.[0]?.price?.formatted ?? \"0\");\n return pb - pa;\n });\n }\n\n const isInitialLoading = isLoading && allTokens.length === 0;\n const isLoadingMore = isLoading && allTokens.length > 0;\n const hasMore = meta?.total != null ? allTokens.length < meta.total : false;\n const listedCount = allTokens.filter((t) => (t.activeOrders?.length ?? 0) > 0).length;\n\n return (\n <PageContainer className=\"box-border max-w-full pt-20 pb-16 space-y-8\">\n\n <div className=\"space-y-4\">\n <div className=\"flex items-center gap-4\">\n {config && Icon && (\n <div className={cn(\"h-14 w-14 rounded-2xl flex items-center justify-center shadow-lg\", config.bgClass)}>\n <Icon className={cn(\"h-7 w-7\", config.colorClass)} />\n </div>\n )}\n <div>\n <h1 className=\"text-3xl font-semibold\">{config?.label ?? slug}</h1>\n <p className=\"text-muted-foreground mt-0.5\">\n {meta?.total != null ? (\n <>{meta.total.toLocaleString()} assets · {listedCount} market</>\n ) : (\n \"Browsing indexed digital assets on Medialane\"\n )}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2 flex-wrap\">\n <button\n onClick={() => setFiltersOpen(true)}\n className={cn(\n \"inline-flex items-center gap-1.5 text-xs px-3.5 py-2 rounded-full border font-medium transition-colors\",\n hasActiveFilters\n ? \"border-primary bg-primary/10 text-primary\"\n : \"border-border text-muted-foreground\"\n )}\n >\n <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n Filters\n {activeChipCount > 0 && (\n <span className=\"ml-0.5 bg-primary text-primary-foreground rounded-full px-1.5 text-2xs font-bold leading-4\">\n {activeChipCount}\n </span>\n )}\n </button>\n\n {listedOnly && (\n <Badge variant=\"secondary\" className=\"cursor-pointer gap-1 text-xs\" onClick={() => setListedOnly(false)}>\n Listed only\n <XIcon className=\"h-3 w-3\" />\n </Badge>\n )}\n {sortOrder !== \"recent\" && (\n <Badge variant=\"secondary\" className=\"cursor-pointer gap-1 text-xs\" onClick={() => setSortOrder(\"recent\")}>\n {sortOrder === \"price_asc\" ? \"Price ↑\" : \"Price ↓\"}\n <XIcon className=\"h-3 w-3\" />\n </Badge>\n )}\n {licenseFilter !== \"all\" && (\n <Badge variant=\"secondary\" className=\"cursor-pointer gap-1 text-xs\" onClick={() => setLicenseFilter(\"all\")}>\n {licenseFilter}\n <XIcon className=\"h-3 w-3\" />\n </Badge>\n )}\n {creatorSearch && (\n <Badge variant=\"secondary\" className=\"cursor-pointer gap-1 text-xs\" onClick={() => { setCreatorSearch(\"\"); setCreatorSearchInput(\"\"); }}>\n {creatorSearch.length > 10 ? `${creatorSearch.slice(0, 10)}…` : creatorSearch}\n <XIcon className=\"h-3 w-3\" />\n </Badge>\n )}\n </div>\n\n <Dialog open={filtersOpen} onOpenChange={setFiltersOpen}>\n <DialogContent className=\"w-full max-w-sm sm:max-w-md p-0 overflow-hidden gap-0 flex flex-col max-h-[85svh]\">\n <div className=\"flex items-center justify-between px-5 py-4 border-b border-border/60 pr-12\">\n <DialogTitle className=\"text-base font-bold flex items-center gap-2\">\n <SlidersHorizontal className=\"h-4 w-4 text-primary\" />\n Filters\n </DialogTitle>\n {hasActiveFilters && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 text-xs text-muted-foreground\" onClick={resetAll}>\n Clear all\n </Button>\n )}\n </div>\n\n <div className=\"flex-1 overflow-y-auto px-5 py-4 space-y-5\">\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Status</p>\n <div className=\"flex flex-wrap gap-1.5\">\n <FilterChip active={!listedOnly} onClick={() => setListedOnly(false)} label=\"All\" />\n <FilterChip\n active={listedOnly}\n onClick={() => setListedOnly(true)}\n label={`Listed only${listedCount > 0 ? ` (${listedCount})` : \"\"}`}\n />\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Sort</p>\n <div className=\"flex flex-wrap gap-1.5\">\n <FilterChip active={sortOrder === \"recent\"} onClick={() => setSortOrder(\"recent\")} label=\"Recent\" />\n <FilterChip active={sortOrder === \"price_asc\"} onClick={() => setSortOrder(\"price_asc\")} label=\"Price ↑\" />\n <FilterChip active={sortOrder === \"price_desc\"} onClick={() => setSortOrder(\"price_desc\")} label=\"Price ↓\" />\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">License</p>\n <div className=\"flex flex-wrap gap-1.5\">\n {[\"all\", \"CC0\", \"CC BY\", \"CC BY-SA\", \"CC BY-NC\", \"CC BY-ND\", \"Custom\"].map((lic) => (\n <FilterChip\n key={lic}\n active={licenseFilter === lic}\n onClick={() => setLicenseFilter(lic)}\n label={lic === \"all\" ? \"All licenses\" : lic}\n />\n ))}\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Creator</p>\n <div className=\"relative\">\n <Search className=\"absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-muted-foreground\" />\n <Input\n className=\"h-9 text-sm pl-8\"\n placeholder=\"Name or wallet address…\"\n value={creatorSearchInput}\n onChange={(e) => setCreatorSearchInput(e.target.value)}\n />\n </div>\n </div>\n\n <div className=\"space-y-2 pt-1 border-t border-border/60\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">IP Type</p>\n <div className=\"flex flex-wrap gap-1.5\">\n {IP_TYPE_CONFIG.map((t) => (\n <Link\n key={t.slug}\n href={`/${t.slug}`}\n className={cn(\n \"inline-flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full border transition-colors whitespace-nowrap\",\n t.slug === slug\n ? \"border-primary bg-primary/10 text-primary font-medium\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n <t.icon className={cn(\"h-3 w-3\", t.slug === slug ? t.colorClass : \"\")} />\n {t.label}\n </Link>\n ))}\n </div>\n </div>\n </div>\n\n <div className=\"px-5 py-3 border-t border-border/60\">\n <Button className=\"w-full\" onClick={() => setFiltersOpen(false)}>\n Apply filters\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n </div>\n\n {isInitialLoading ? (\n <div className=\"grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4\">\n {Array.from({ length: PAGE_SIZE }).map((_, i) => (\n <TokenCardSkeleton key={i} />\n ))}\n </div>\n ) : displayed.length === 0 ? (\n <div className=\"py-24 flex flex-col items-center gap-4 text-center\">\n {config && Icon && (\n <div className={cn(\"h-16 w-16 rounded-2xl flex items-center justify-center\", config.bgClass)}>\n <Icon className={cn(\"h-8 w-8\", config.colorClass)} />\n </div>\n )}\n <div>\n <p className=\"font-semibold text-lg\">\n {listedOnly ? \"Listed assets appear here\" : emptyMessages.assetsOfType.title}\n </p>\n <p className=\"text-muted-foreground text-sm mt-1\">\n {listedOnly\n ? \"Try removing the 'Listed only' filter to see all assets.\"\n : emptyMessages.assetsOfType.description}\n </p>\n </div>\n <Button asChild variant=\"outline\">\n <Link href=\"/launchpad/single-editions\">Create Asset</Link>\n </Button>\n </div>\n ) : (\n <div className=\"space-y-6\">\n <div className=\"grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4\">\n {displayed.map((token) => {\n const listing = token.activeOrders?.find((o) => o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\");\n const isOwner = !!walletAddress && !!token.owner && isSameAddress(token.owner, walletAddress);\n return (\n <TokenCard\n key={`${token.contractAddress}:${token.tokenId}`}\n token={token}\n isOwner={isOwner}\n onBuy={!isOwner && listing ? () => market.buy(listing) : undefined}\n onOffer={isOwner ? undefined : market.offer}\n />\n );\n })}\n </div>\n\n {!listedOnly && (\n <LoadMoreSentinel\n hasMore={hasMore}\n isLoading={isLoadingMore}\n onLoadMore={() => setPage((p) => p + 1)}\n />\n )}\n </div>\n )}\n\n {market.dialogs}\n </PageContainer>\n );\n}\n"],"mappings":"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","names":["XIcon","Link"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/ip-type-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useRef } from \"react\";\nimport { SlidersHorizontal, Search, X as XIcon } from \"lucide-react\";\nimport type { ApiToken } from \"@medialane/sdk\";\nimport Link from \"./link.js\";\nimport { Badge } from \"./badge.js\";\nimport { Button } from \"./button.js\";\nimport { Dialog, DialogContent, DialogTitle } from \"./dialog.js\";\nimport { Input } from \"./input.js\";\nimport { PageContainer } from \"./page-container.js\";\nimport { LoadMoreSentinel } from \"./load-more-sentinel.js\";\nimport { IP_TYPE_CONFIG, IP_TYPE_MAP } from \"./ip-type-badge.js\";\nimport { TokenCard, TokenCardSkeleton } from \"./token-card.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport type { CollectionMarketActions } from \"./collection-page.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { isSameAddress } from \"../utils/same-address.js\";\nimport { useTokensByIpType } from \"../utils/use-tokens-by-ip-type.js\";\nimport { emptyMessages } from \"../utils/empty-messages.js\";\n\nconst PAGE_SIZE = 24;\n\nfunction FilterChip({ active, onClick, label }: { active: boolean; onClick: () => void; label: string }) {\n return (\n <button\n onClick={onClick}\n className={cn(\n \"text-xs px-3 py-1.5 rounded-full border transition-colors whitespace-nowrap\",\n active\n ? \"border-primary bg-primary/10 text-primary font-medium\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n {label}\n </button>\n );\n}\n\nexport interface IpTypePageProps {\n slug: string;\n useMarketActions: () => CollectionMarketActions;\n}\n\nexport function IpTypePage({ slug, useMarketActions }: IpTypePageProps) {\n const { walletAddress } = useMedialaneApp();\n const market = useMarketActions();\n const config = IP_TYPE_MAP[slug];\n const Icon = config?.icon;\n const [page, setPage] = useState(1);\n const [listedOnly, setListedOnly] = useState(false);\n const [allTokens, setAllTokens] = useState<ApiToken[]>([]);\n const prevSlug = useRef(slug);\n\n const [filtersOpen, setFiltersOpen] = useState(false);\n const [sortOrder, setSortOrder] = useState<\"recent\" | \"price_asc\" | \"price_desc\">(\"recent\");\n const [licenseFilter, setLicenseFilter] = useState<string>(\"all\");\n const [creatorSearchInput, setCreatorSearchInput] = useState(\"\");\n const [creatorSearch, setCreatorSearch] = useState(\"\");\n\n useEffect(() => {\n if (prevSlug.current !== slug) {\n prevSlug.current = slug;\n setPage(1);\n setAllTokens([]);\n }\n }, [slug]);\n\n useEffect(() => {\n const t = setTimeout(() => setCreatorSearch(creatorSearchInput), 300);\n return () => clearTimeout(t);\n }, [creatorSearchInput]);\n\n const { tokens, meta, isLoading } = useTokensByIpType(slug, page, PAGE_SIZE);\n\n useEffect(() => {\n if (isLoading) return;\n if (page === 1) {\n setAllTokens(tokens);\n } else {\n setAllTokens((prev) => {\n const seen = new Set(prev.map((t) => `${t.contractAddress}:${t.tokenId}`));\n const fresh = tokens.filter((t) => !seen.has(`${t.contractAddress}:${t.tokenId}`));\n return fresh.length > 0 ? [...prev, ...fresh] : prev;\n });\n }\n }, [tokens, isLoading, page]);\n\n const activeFilterCount =\n (sortOrder !== \"recent\" ? 1 : 0) +\n (licenseFilter !== \"all\" ? 1 : 0) +\n (creatorSearch !== \"\" ? 1 : 0);\n const activeChipCount = activeFilterCount + (listedOnly ? 1 : 0);\n const hasActiveFilters = activeChipCount > 0;\n const resetAll = () => {\n setSortOrder(\"recent\");\n setLicenseFilter(\"all\");\n setCreatorSearch(\"\");\n setCreatorSearchInput(\"\");\n setListedOnly(false);\n };\n\n let displayed = listedOnly\n ? allTokens.filter((t) => (t.activeOrders?.length ?? 0) > 0)\n : [...allTokens];\n\n if (licenseFilter !== \"all\") {\n displayed = displayed.filter((t) =>\n t.metadata?.attributes?.some(\n (a) => a.trait_type === \"License\" && a.value === licenseFilter\n )\n );\n }\n if (creatorSearch) {\n const q = creatorSearch.toLowerCase();\n displayed = displayed.filter((t) => {\n const creatorVal =\n t.metadata?.attributes?.find((a) => a.trait_type === \"Creator\")?.value ?? \"\";\n return (\n String(creatorVal).toLowerCase().includes(q) ||\n t.contractAddress.toLowerCase().includes(q)\n );\n });\n }\n if (sortOrder === \"price_asc\") {\n displayed = [...displayed].sort((a, b) => {\n const pa = parseFloat(a.activeOrders?.[0]?.price?.formatted ?? \"Infinity\");\n const pb = parseFloat(b.activeOrders?.[0]?.price?.formatted ?? \"Infinity\");\n return pa - pb;\n });\n } else if (sortOrder === \"price_desc\") {\n displayed = [...displayed].sort((a, b) => {\n const pa = parseFloat(a.activeOrders?.[0]?.price?.formatted ?? \"0\");\n const pb = parseFloat(b.activeOrders?.[0]?.price?.formatted ?? \"0\");\n return pb - pa;\n });\n }\n\n const isInitialLoading = isLoading && allTokens.length === 0;\n const isLoadingMore = isLoading && allTokens.length > 0;\n const hasMore = meta?.total != null ? allTokens.length < meta.total : false;\n const listedCount = allTokens.filter((t) => (t.activeOrders?.length ?? 0) > 0).length;\n\n return (\n <PageContainer className=\"box-border max-w-full pt-20 pb-16 space-y-8\">\n\n <div className=\"space-y-4\">\n <div className=\"flex items-center gap-4\">\n {config && Icon && (\n <div className={cn(\"h-14 w-14 rounded-2xl flex items-center justify-center shadow-lg\", config.bgClass)}>\n <Icon className={cn(\"h-7 w-7\", config.colorClass)} />\n </div>\n )}\n <div>\n <h1 className=\"text-3xl font-semibold\">{config?.label ?? slug}</h1>\n <p className=\"text-muted-foreground mt-0.5\">\n {meta?.total != null ? (\n <>{meta.total.toLocaleString()} assets · {listedCount} market</>\n ) : (\n \"Browsing indexed digital assets on Medialane\"\n )}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2 flex-wrap\">\n <button\n onClick={() => setFiltersOpen(true)}\n aria-label=\"Filters\"\n className={cn(\n \"inline-flex items-center gap-1.5 text-xs px-3.5 py-2 rounded-full border font-medium transition-colors\",\n hasActiveFilters\n ? \"border-primary bg-primary/10 text-primary\"\n : \"border-border text-muted-foreground\"\n )}\n >\n <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n {activeChipCount > 0 && (\n <span className=\"ml-0.5 bg-primary text-primary-foreground rounded-full px-1.5 text-2xs font-bold leading-4\">\n {activeChipCount}\n </span>\n )}\n </button>\n\n {listedOnly && (\n <Badge variant=\"secondary\" className=\"cursor-pointer gap-1 text-xs\" onClick={() => setListedOnly(false)}>\n Listed only\n <XIcon className=\"h-3 w-3\" />\n </Badge>\n )}\n {sortOrder !== \"recent\" && (\n <Badge variant=\"secondary\" className=\"cursor-pointer gap-1 text-xs\" onClick={() => setSortOrder(\"recent\")}>\n {sortOrder === \"price_asc\" ? \"Price ↑\" : \"Price ↓\"}\n <XIcon className=\"h-3 w-3\" />\n </Badge>\n )}\n {licenseFilter !== \"all\" && (\n <Badge variant=\"secondary\" className=\"cursor-pointer gap-1 text-xs\" onClick={() => setLicenseFilter(\"all\")}>\n {licenseFilter}\n <XIcon className=\"h-3 w-3\" />\n </Badge>\n )}\n {creatorSearch && (\n <Badge variant=\"secondary\" className=\"cursor-pointer gap-1 text-xs\" onClick={() => { setCreatorSearch(\"\"); setCreatorSearchInput(\"\"); }}>\n {creatorSearch.length > 10 ? `${creatorSearch.slice(0, 10)}…` : creatorSearch}\n <XIcon className=\"h-3 w-3\" />\n </Badge>\n )}\n </div>\n\n <Dialog open={filtersOpen} onOpenChange={setFiltersOpen}>\n <DialogContent className=\"w-full max-w-sm sm:max-w-md p-0 overflow-hidden gap-0 flex flex-col max-h-[85svh]\">\n <div className=\"flex items-center justify-between px-5 py-4 border-b border-border/60 pr-12\">\n <DialogTitle className=\"text-base font-bold flex items-center gap-2\">\n <SlidersHorizontal className=\"h-4 w-4 text-primary\" />\n Filters\n </DialogTitle>\n {hasActiveFilters && (\n <Button variant=\"ghost\" size=\"sm\" className=\"h-7 text-xs text-muted-foreground\" onClick={resetAll}>\n Clear all\n </Button>\n )}\n </div>\n\n <div className=\"flex-1 overflow-y-auto px-5 py-4 space-y-5\">\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Status</p>\n <div className=\"flex flex-wrap gap-1.5\">\n <FilterChip active={!listedOnly} onClick={() => setListedOnly(false)} label=\"All\" />\n <FilterChip\n active={listedOnly}\n onClick={() => setListedOnly(true)}\n label={`Listed only${listedCount > 0 ? ` (${listedCount})` : \"\"}`}\n />\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Sort</p>\n <div className=\"flex flex-wrap gap-1.5\">\n <FilterChip active={sortOrder === \"recent\"} onClick={() => setSortOrder(\"recent\")} label=\"Recent\" />\n <FilterChip active={sortOrder === \"price_asc\"} onClick={() => setSortOrder(\"price_asc\")} label=\"Price ↑\" />\n <FilterChip active={sortOrder === \"price_desc\"} onClick={() => setSortOrder(\"price_desc\")} label=\"Price ↓\" />\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">License</p>\n <div className=\"flex flex-wrap gap-1.5\">\n {[\"all\", \"CC0\", \"CC BY\", \"CC BY-SA\", \"CC BY-NC\", \"CC BY-ND\", \"Custom\"].map((lic) => (\n <FilterChip\n key={lic}\n active={licenseFilter === lic}\n onClick={() => setLicenseFilter(lic)}\n label={lic === \"all\" ? \"All licenses\" : lic}\n />\n ))}\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">Creator</p>\n <div className=\"relative\">\n <Search className=\"absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-muted-foreground\" />\n <Input\n className=\"h-9 text-sm pl-8\"\n placeholder=\"Name or wallet address…\"\n value={creatorSearchInput}\n onChange={(e) => setCreatorSearchInput(e.target.value)}\n />\n </div>\n </div>\n\n <div className=\"space-y-2 pt-1 border-t border-border/60\">\n <p className=\"text-2xs font-semibold text-muted-foreground\">IP Type</p>\n <div className=\"flex flex-wrap gap-1.5\">\n {IP_TYPE_CONFIG.map((t) => (\n <Link\n key={t.slug}\n href={`/${t.slug}`}\n className={cn(\n \"inline-flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-full border transition-colors whitespace-nowrap\",\n t.slug === slug\n ? \"border-primary bg-primary/10 text-primary font-medium\"\n : \"border-border text-muted-foreground hover:border-primary/50\"\n )}\n >\n <t.icon className={cn(\"h-3 w-3\", t.slug === slug ? t.colorClass : \"\")} />\n {t.label}\n </Link>\n ))}\n </div>\n </div>\n </div>\n\n <div className=\"px-5 py-3 border-t border-border/60\">\n <Button className=\"w-full\" onClick={() => setFiltersOpen(false)}>\n Apply filters\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n </div>\n\n {isInitialLoading ? (\n <div className=\"grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4\">\n {Array.from({ length: PAGE_SIZE }).map((_, i) => (\n <TokenCardSkeleton key={i} />\n ))}\n </div>\n ) : displayed.length === 0 ? (\n <div className=\"py-24 flex flex-col items-center gap-4 text-center\">\n {config && Icon && (\n <div className={cn(\"h-16 w-16 rounded-2xl flex items-center justify-center\", config.bgClass)}>\n <Icon className={cn(\"h-8 w-8\", config.colorClass)} />\n </div>\n )}\n <div>\n <p className=\"font-semibold text-lg\">\n {listedOnly ? \"Listed assets appear here\" : emptyMessages.assetsOfType.title}\n </p>\n <p className=\"text-muted-foreground text-sm mt-1\">\n {listedOnly\n ? \"Try removing the 'Listed only' filter to see all assets.\"\n : emptyMessages.assetsOfType.description}\n </p>\n </div>\n <Button asChild variant=\"outline\">\n <Link href=\"/launchpad/single-editions\">Create Asset</Link>\n </Button>\n </div>\n ) : (\n <div className=\"space-y-6\">\n <div className=\"grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4\">\n {displayed.map((token) => {\n const listing = token.activeOrders?.find((o) => o.offer.itemType === \"ERC721\" || o.offer.itemType === \"ERC1155\");\n const isOwner = !!walletAddress && !!token.owner && isSameAddress(token.owner, walletAddress);\n return (\n <TokenCard\n key={`${token.contractAddress}:${token.tokenId}`}\n token={token}\n isOwner={isOwner}\n onBuy={!isOwner && listing ? () => market.buy(listing) : undefined}\n onOffer={isOwner ? undefined : market.offer}\n />\n );\n })}\n </div>\n\n {!listedOnly && (\n <LoadMoreSentinel\n hasMore={hasMore}\n isLoading={isLoadingMore}\n onLoadMore={() => setPage((p) => p + 1)}\n />\n )}\n </div>\n )}\n\n {market.dialogs}\n </PageContainer>\n );\n}\n"],"mappings":"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","names":["XIcon","Link"]}
|
|
@@ -129,13 +129,13 @@ function IpTypePage({ slug, useMarketActions }) {
|
|
|
129
129
|
"button",
|
|
130
130
|
{
|
|
131
131
|
onClick: () => setFiltersOpen(true),
|
|
132
|
+
"aria-label": "Filters",
|
|
132
133
|
className: cn(
|
|
133
134
|
"inline-flex items-center gap-1.5 text-xs px-3.5 py-2 rounded-full border font-medium transition-colors",
|
|
134
135
|
hasActiveFilters ? "border-primary bg-primary/10 text-primary" : "border-border text-muted-foreground"
|
|
135
136
|
),
|
|
136
137
|
children: [
|
|
137
138
|
/* @__PURE__ */ jsx(SlidersHorizontal, { className: "h-3.5 w-3.5" }),
|
|
138
|
-
"Filters",
|
|
139
139
|
activeChipCount > 0 && /* @__PURE__ */ jsx("span", { className: "ml-0.5 bg-primary text-primary-foreground rounded-full px-1.5 text-2xs font-bold leading-4", children: activeChipCount })
|
|
140
140
|
]
|
|
141
141
|
}
|