@medialane/ui 0.319.0 → 0.321.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-page.cjs +4 -9
- package/dist/components/asset-page.cjs.map +1 -1
- package/dist/components/asset-page.js +4 -9
- package/dist/components/asset-page.js.map +1 -1
- package/dist/components/asset-top-sections.cjs +10 -10
- package/dist/components/asset-top-sections.cjs.map +1 -1
- package/dist/components/asset-top-sections.d.cts +5 -5
- package/dist/components/asset-top-sections.d.ts +5 -5
- package/dist/components/asset-top-sections.js +10 -10
- package/dist/components/asset-top-sections.js.map +1 -1
- package/dist/components/badge.d.cts +1 -1
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/button.d.cts +1 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/collection-filters.cjs +14 -12
- package/dist/components/collection-filters.cjs.map +1 -1
- package/dist/components/collection-filters.js +14 -12
- package/dist/components/collection-filters.js.map +1 -1
- package/dist/components/expandable-text.cjs +1 -1
- package/dist/components/expandable-text.cjs.map +1 -1
- package/dist/components/expandable-text.js +1 -1
- package/dist/components/expandable-text.js.map +1 -1
- package/dist/components/launchpad/edition-mint-schema.d.cts +2 -2
- package/dist/components/launchpad/edition-mint-schema.d.ts +2 -2
- package/package.json +1 -1
|
@@ -34,7 +34,6 @@ var import_page_container = require("./page-container.js");
|
|
|
34
34
|
var import_media_header = require("./media-header.js");
|
|
35
35
|
var import_asset_top_sections = require("./asset-top-sections.js");
|
|
36
36
|
var import_asset_publication = require("./asset-publication.js");
|
|
37
|
-
var import_ip_type_badge = require("./ip-type-badge.js");
|
|
38
37
|
var import_asset_video = require("./asset-video.js");
|
|
39
38
|
var import_asset_audio = require("./asset-audio.js");
|
|
40
39
|
var import_asset_utility_icons = require("./asset-utility-icons.js");
|
|
@@ -211,8 +210,9 @@ function AssetPageView({
|
|
|
211
210
|
market.isERC1155 && holders.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_asset_owners_panel.AssetOwnersPanel, { balances: holders, total: token.holderCount, editions: Number(token.supply ?? 0) }) : null
|
|
212
211
|
] });
|
|
213
212
|
const detailsBlock = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "pt-5 space-y-5", children: [
|
|
214
|
-
|
|
213
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_asset_top_sections.AssetOwnerRow, { ownerAddress, ownerHref: ownerAddress ? (0, import_sdk2.profileHref)({ address: ownerAddress }) : void 0, ipType: token.metadata?.ipType }),
|
|
215
214
|
collection?.service === "drop-collection" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_drop_token_link.DropTokenLink, { contract, name: collection.name ?? null }) : null,
|
|
215
|
+
kind === "pop" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_soulbound_card.SoulboundCard, { history, ownerAddress }) : null,
|
|
216
216
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
217
217
|
import_asset_collection_bar.AssetCollectionBar,
|
|
218
218
|
{
|
|
@@ -228,7 +228,6 @@ function AssetPageView({
|
|
|
228
228
|
floorPriceRaw: collection?.floorPrice
|
|
229
229
|
}
|
|
230
230
|
),
|
|
231
|
-
kind === "pop" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_soulbound_card.SoulboundCard, { history, ownerAddress }) : null,
|
|
232
231
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "-ml-3", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
233
232
|
import_asset_utility_icons.AssetUtilityIcons,
|
|
234
233
|
{
|
|
@@ -264,9 +263,8 @@ function AssetPageView({
|
|
|
264
263
|
}
|
|
265
264
|
),
|
|
266
265
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", { className: "space-y-6 min-w-0", children: [
|
|
267
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ip_type_badge.IpTypeBadge, { ipType: token.metadata?.ipType ?? "Video", size: "md", showLabel: true }),
|
|
268
266
|
marketBlock,
|
|
269
|
-
|
|
267
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_asset_top_sections.AssetOwnerRow, { ownerAddress, ownerHref: ownerAddress ? (0, import_sdk2.profileHref)({ address: ownerAddress }) : void 0, ipType: token.metadata?.ipType ?? "Video" }),
|
|
270
268
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
271
269
|
import_asset_video.AssetRelatedList,
|
|
272
270
|
{
|
|
@@ -304,9 +302,8 @@ function AssetPageView({
|
|
|
304
302
|
}
|
|
305
303
|
),
|
|
306
304
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", { className: "space-y-6 min-w-0", children: [
|
|
307
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ip_type_badge.IpTypeBadge, { ipType: token.metadata?.ipType ?? "Audio", size: "md", showLabel: true }),
|
|
308
305
|
marketBlock,
|
|
309
|
-
|
|
306
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_asset_top_sections.AssetOwnerRow, { ownerAddress, ownerHref: ownerAddress ? (0, import_sdk2.profileHref)({ address: ownerAddress }) : void 0, ipType: token.metadata?.ipType ?? "Audio" }),
|
|
310
307
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
311
308
|
import_asset_video.AssetRelatedList,
|
|
312
309
|
{
|
|
@@ -336,7 +333,6 @@ function AssetPageView({
|
|
|
336
333
|
}
|
|
337
334
|
),
|
|
338
335
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", { className: "space-y-6 min-w-0 lg:sticky lg:top-16", children: [
|
|
339
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ip_type_badge.IpTypeBadge, { ipType: token.metadata?.ipType ?? "Publications", size: "md", showLabel: true }),
|
|
340
336
|
marketBlock,
|
|
341
337
|
detailsBlock
|
|
342
338
|
] })
|
|
@@ -367,7 +363,6 @@ function AssetPageView({
|
|
|
367
363
|
{
|
|
368
364
|
name,
|
|
369
365
|
description: token.metadata?.description,
|
|
370
|
-
ipType: token.metadata?.ipType,
|
|
371
366
|
parentContract,
|
|
372
367
|
parentTokenId,
|
|
373
368
|
badges: kind === "pop" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "inline-flex items-center gap-1 text-2xs font-semibold px-2.5 py-1 rounded-full bg-brand-purple/15 text-brand-purple dark:bg-brand-purple/25", children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/asset-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState, type ComponentType, type ReactNode } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { Award } from \"lucide-react\";\nimport { assetHref, collectionHref, getDerivativesTerm, getService, resolveRemixPolicy, type ApiActivity, type ApiCollection, type ApiOrder, type ApiToken, type Chain } from \"@medialane/sdk\";\nimport { useRouter } from \"./router.js\";\nimport { PageContainer } from \"./page-container.js\";\nimport { PageBackdrop } from \"./media-header.js\";\nimport { AssetHeaderBlock, AssetMediaColumn, AssetOwnerRow } from \"./asset-top-sections.js\";\nimport { AssetPublication } from \"./asset-publication.js\";\nimport { IpTypeBadge } from \"./ip-type-badge.js\";\nimport { AssetRelatedList, AssetVideo, VIDEO_EMBED_TRAITS, videoEmbed } from \"./asset-video.js\";\nimport { AssetAudio, AUDIO_EMBED_TRAITS, audioEmbed } from \"./asset-audio.js\";\nimport { AssetUtilityIcons } from \"./asset-utility-icons.js\";\nimport { AssetMarketplacePanel } from \"./asset-marketplace-panel.js\";\nimport { AssetOwnersPanel } from \"./asset-owners-panel.js\";\nimport { AssetCollectionBar } from \"./asset-collection-bar.js\";\nimport { AssetOverviewContent } from \"./asset-overview-content.js\";\nimport { AssetMarketsTab } from \"./asset-markets-tab.js\";\nimport { AssetProvenanceTab } from \"./asset-provenance-tab.js\";\nimport { AssetUnavailable } from \"./asset-unavailable.js\";\nimport { HiddenContentBanner } from \"./hidden-content-banner.js\";\nimport { DropTokenLink } from \"./drop/drop-token-link.js\";\nimport { FloatingCommentsButton } from \"./floating-comments-button.js\";\nimport { AssetCommentsDialog } from \"./asset-comments-dialog.js\";\nimport { PopBurnButton } from \"./pop-burn-button.js\";\nimport { SoulboundCard } from \"./soulbound-card.js\";\nimport { MembershipPanel, TicketPanel, type AssetTypePanelProps } from \"./asset-type-panels.js\";\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"./tabs.js\";\nimport { Skeleton } from \"./skeleton.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport { ReportDialog } from \"./report-dialog.js\";\nimport { useToken, useTokenBalance, useTokenHistory } from \"../utils/use-tokens.js\";\nimport { useCollection, useNearbyCollectionTokens } from \"../utils/use-collections.js\";\nimport { useTokenListings } from \"../utils/use-orders.js\";\nimport { useTokenRemixes } from \"../utils/use-remix-offers.js\";\nimport { useComments } from \"../utils/use-comments.js\";\nimport { useFullTokenData } from \"../utils/use-full-token-data.js\";\nimport { useAssetMarketState } from \"../utils/asset-market-state.js\";\nimport { assetAttributes } from \"../utils/asset-attributes.js\";\nimport { externalLink } from \"../utils/external-link.js\";\nimport { ASSET_ACCENTS } from \"../utils/asset-accents.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\nimport { EXPLORER_URL } from \"../utils/explorer-url.js\";\nimport { profileHref } from \"@medialane/sdk\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\nexport type AssetKind = \"standard\" | \"edition\" | \"ticket\" | \"membership\" | \"pop\";\n\nexport interface AssetMarketContext {\n contract: string;\n tokenId: string;\n tokenName: string;\n tokenImage: string | null;\n tokenStandard: \"ERC721\" | \"ERC1155\" | \"UNKNOWN\";\n activeListings: ApiOrder[];\n quantityOwned?: string;\n mutateListings: () => void;\n}\n\nexport interface AssetMarketActions {\n isProcessing: boolean;\n buy: (order: ApiOrder) => void;\n list: () => void;\n offer: () => void;\n transfer: () => void;\n cancel: (order: ApiOrder) => void;\n acceptBid: (order: ApiOrder) => void;\n dialogs: ReactNode;\n}\n\ninterface KindConfig {\n namePrefix: string;\n accents: (typeof ASSET_ACCENTS)[keyof typeof ASSET_ACCENTS];\n market: boolean;\n remix: boolean;\n Panel?: ComponentType<AssetTypePanelProps>;\n}\n\nconst KINDS: Record<AssetKind, KindConfig> = {\n standard: { namePrefix: \"Token\", accents: ASSET_ACCENTS.standard, market: true, remix: true },\n edition: { namePrefix: \"Edition\", accents: ASSET_ACCENTS.edition, market: true, remix: false },\n ticket: { namePrefix: \"Ticket\", accents: ASSET_ACCENTS.ticket, market: true, remix: false, Panel: TicketPanel },\n membership: { namePrefix: \"Membership\", accents: ASSET_ACCENTS.membership, market: true, remix: false, Panel: MembershipPanel },\n pop: { namePrefix: \"POP\", accents: ASSET_ACCENTS.standard, market: false, remix: false },\n};\n\nconst PUBLICATION_TYPES = new Set([\"publications\", \"posts\"]);\n\ntype TraitList = { trait_type?: string | null; value?: string | number | boolean | null }[];\n\nfunction traitText(attributes: TraitList, trait: string): string | null {\n const value = attributes.find((a) => a.trait_type === trait)?.value;\n return typeof value === \"string\" && value.trim() !== \"\" ? value.trim() : null;\n}\n\nfunction publicationAuthor(attributes: TraitList, metadataAuthor?: string | null): string | null {\n return traitText(attributes, \"Author\") ?? metadataAuthor ?? traitText(attributes, \"Creator\");\n}\n\nconst VARIANT_KINDS: Partial<Record<string, AssetKind>> = { edition: \"edition\", ticket: \"ticket\", club: \"membership\", pop: \"pop\" };\n\nexport function detectAssetKind(service: string | null | undefined, standard: string | null | undefined): AssetKind {\n const variant = getService(service)?.uiVariant;\n if (variant) return VARIANT_KINDS[variant] ?? \"standard\";\n return standard === \"ERC1155\" ? \"edition\" : \"standard\";\n}\n\nexport function AssetPageSkeleton() {\n return (\n <PageContainer className=\"pt-20 pb-8\">\n <div className=\"grid grid-cols-1 lg:grid-cols-2 lg:gap-10 gap-6 items-start\">\n <Skeleton className=\"aspect-square w-full rounded-3xl\" />\n <div className=\"space-y-6\">\n <div className=\"space-y-3\">\n <Skeleton className=\"h-5 w-24 rounded-full\" />\n <Skeleton className=\"h-9 w-3/4\" />\n <Skeleton className=\"h-4 w-full\" />\n <Skeleton className=\"h-4 w-2/3\" />\n </div>\n <Skeleton className=\"h-[54px] w-full rounded-2xl\" />\n <div className=\"flex gap-2\">\n {Array.from({ length: 3 }).map((_, i) => <Skeleton key={i} className=\"h-[46px] flex-1 rounded-[13px]\" />)}\n </div>\n <Skeleton className=\"h-16 w-full rounded-2xl\" />\n </div>\n </div>\n </PageContainer>\n );\n}\n\nexport interface AssetPageProps {\n contract: string;\n tokenId: string;\n useMarketActions: (context: AssetMarketContext) => AssetMarketActions;\n}\n\nexport function AssetPage({ contract, tokenId, useMarketActions }: AssetPageProps) {\n const { token, isLoading, isIndexing } = useToken(contract, tokenId);\n const { collection, isLoading: collectionLoading } = useCollection(contract);\n if (isLoading || collectionLoading) return <AssetPageSkeleton />;\n if (!token) return <AssetUnavailable isIndexing={isIndexing} />;\n const kind = detectAssetKind(collection?.service, collection?.standard ?? token.standard);\n return <AssetPageView contract={contract} tokenId={tokenId} token={token} collection={collection ?? null} kind={kind} useMarketActions={useMarketActions} />;\n}\n\nfunction AssetPageView({\n contract,\n tokenId,\n token,\n collection,\n kind,\n useMarketActions,\n}: {\n contract: string;\n tokenId: string;\n token: ApiToken & { isHidden?: boolean };\n collection: ApiCollection | null;\n kind: AssetKind;\n useMarketActions: AssetPageProps[\"useMarketActions\"];\n}) {\n const resolveImage = useImageUrl();\n const config = KINDS[kind];\n const router = useRouter();\n const shouldReduce = useReducedMotion();\n const { walletAddress } = useMedialaneApp();\n\n const { listings, mutate: mutateListings, isLoading: listingsLoading } = useTokenListings(contract, tokenId);\n const { history } = useTokenHistory(contract, tokenId);\n const { tokens: collectionTokens } = useNearbyCollectionTokens(contract, tokenId);\n const { total: commentTotal } = useComments(contract, tokenId);\n const { total: remixCount } = useTokenRemixes(contract, tokenId);\n const { data: fullTokenData } = useFullTokenData(contract, tokenId);\n const { amount: walletBalance } = useTokenBalance(contract, tokenId, walletAddress);\n const market = useAssetMarketState({ token, collection, listings, history: history as ApiActivity[], walletAddress, walletBalance });\n\n const [reportOpen, setReportOpen] = useState(false);\n const [commentOpen, setCommentOpen] = useState(false);\n const [imgError, setImgError] = useState(false);\n\n const name = token.metadata?.name || `${config.namePrefix} #${token.tokenId}`;\n const image = resolveImage(token.metadata?.image);\n const tokenStandard = kind === \"standard\" || kind === \"pop\"\n ? ((token.standard ?? collection?.standard ?? \"UNKNOWN\") as AssetMarketContext[\"tokenStandard\"])\n : \"ERC1155\";\n\n const actions = useMarketActions({\n contract,\n tokenId,\n tokenName: name,\n tokenImage: image,\n tokenStandard,\n activeListings: market.activeListings,\n quantityOwned: market.quantityOwned,\n mutateListings,\n });\n\n const autoActionRef = useRef(false);\n useEffect(() => {\n if (autoActionRef.current || !config.market || !market.isOwner) return;\n const action = new URLSearchParams(window.location.search).get(\"action\");\n if (action === \"list\") actions.list();\n else if (action === \"transfer\") actions.transfer();\n else return;\n autoActionRef.current = true;\n }, [config.market, market.isOwner, actions]);\n\n const { attributes, hasTemplateData, isDisplayAttr, parentContract, parentTokenId } = assetAttributes(token.metadata?.attributes);\n const remixPolicy = resolveRemixPolicy({\n parentNoDerivatives: getDerivativesTerm(token.metadata?.attributes) === \"Not Allowed\",\n viewerIsParentOwner: market.isOwner,\n dealAvailable: !!getService(collection?.service),\n });\n const holders = token.balances ?? [];\n const ownerAddress = !market.isERC1155 ? (holders[0]?.owner ?? token.owner ?? null) : null;\n const marketCount = market.activeListings.length + market.activeBids.length;\n const { Panel } = config;\n\n const postContent = traitText(attributes, \"Content\");\n const description = token.metadata?.description?.trim() || null;\n const video = (token.metadata?.ipType ?? \"\").toLowerCase() === \"video\" ? videoEmbed(attributes) : null;\n const audio = (token.metadata?.ipType ?? \"\").toLowerCase() === \"audio\" ? audioEmbed(attributes) : null;\n const isPublication = !!description && PUBLICATION_TYPES.has((token.metadata?.ipType ?? \"\").toLowerCase());\n const publisherName = collection?.name ?? contract.slice(0, 8) + \"…\";\n const overviewAttributes = postContent ? attributes.filter((a) => a.trait_type !== \"Content\") : attributes;\n const overview = video || audio\n ? assetAttributes(overviewAttributes.filter((a) => !VIDEO_EMBED_TRAITS.has(a.trait_type ?? \"\") && !AUDIO_EMBED_TRAITS.has(a.trait_type ?? \"\")))\n : { attributes: overviewAttributes, hasTemplateData, isDisplayAttr };\n const overviewLink = isPublication || video || audio ? null : externalLink(token.metadata?.externalUrl);\n\n const marketBlock = (\n <>\n {Panel ? <Panel contract={contract} tokenId={tokenId} quantityOwned={market.quantityOwned} /> : null}\n\n {config.market ? (\n <AssetMarketplacePanel\n asset={token}\n compact={isPublication || !!video || !!audio}\n cheapest={market.cheapest}\n usdValue={market.cheapestUsd}\n isOwner={market.isOwner}\n isProcessing={actions.isProcessing}\n isERC1155={market.isERC1155}\n canListMoreEditions={market.canListMoreEditions}\n isMarketLoading={listingsLoading}\n myListing={market.myListing}\n activeBids={market.activeBids}\n remixEnabled={config.remix && remixPolicy.canRemixDirect}\n showDealOption={config.remix && remixPolicy.showDealOption}\n onCancelClick={actions.cancel}\n onAcceptBid={actions.acceptBid}\n onOpenListing={actions.list}\n onOpenTransfer={actions.transfer}\n onOpenPurchase={actions.buy}\n onOpenOffer={actions.offer}\n onOpenRemix={() => router.push(`/create/remix/${contract}/${tokenId}`)}\n />\n ) : null}\n\n {kind === \"pop\" && market.isOwner ? <PopBurnButton collectionAddress={contract} tokenId={tokenId} /> : null}\n\n {market.isERC1155 && holders.length > 0 ? (\n <AssetOwnersPanel balances={holders} total={token.holderCount} editions={Number(token.supply ?? 0)} />\n ) : null}\n </>\n );\n\n const detailsBlock = (\n <div className=\"pt-5 space-y-5\">\n {ownerAddress ? <AssetOwnerRow ownerAddress={ownerAddress} ownerHref={profileHref({ address: ownerAddress })} /> : null}\n {collection?.service === \"drop-collection\" ? <DropTokenLink contract={contract} name={collection.name ?? null} /> : null}\n <AssetCollectionBar\n collectionName={publisherName}\n collectionImage={resolveImage(collection?.image)}\n collectionHref={collectionHref(\"STARKNET\", contract)}\n currentTokenId={tokenId}\n siblingTokens={collectionTokens.map((t) => ({\n tokenId: t.tokenId,\n image: resolveImage(t.metadata?.image),\n }))}\n onNavigate={(id) => router.push(assetHref(\"STARKNET\", contract, id))}\n floorPriceRaw={collection?.floorPrice}\n />\n {kind === \"pop\" ? (\n <SoulboundCard history={history as ApiActivity[]} ownerAddress={ownerAddress} />\n ) : null}\n <div className=\"-ml-3\">\n <AssetUtilityIcons\n contractExplorerHref={`${EXPLORER_URL}/contract/${token.contractAddress}`}\n shareTitle={name}\n onReportClick={() => setReportOpen(true)}\n />\n </div>\n </div>\n );\n\n return (\n <div className=\"relative z-0 min-h-screen\">\n {token.isHidden ? <HiddenContentBanner /> : null}\n <PageBackdrop image={image} />\n\n <PageContainer className={isPublication ? \"pt-20 space-y-8 pb-8 lg:px-16 xl:px-24\" : \"pt-20 space-y-8 pb-8\"}>\n {video ? (\n <div className=\"grid grid-cols-1 lg:grid-cols-[minmax(0,2fr)_minmax(0,1fr)] lg:gap-12 gap-8 items-start\">\n <AssetVideo\n name={name}\n embedSrc={video.src}\n embedLabel={video.label}\n description={token.metadata?.description}\n collectionName={publisherName}\n collectionImage={resolveImage(collection?.image)}\n collectionHref={collectionHref(\"STARKNET\", contract)}\n utilities={\n <AssetUtilityIcons\n contractExplorerHref={`${EXPLORER_URL}/contract/${token.contractAddress}`}\n shareTitle={name}\n onReportClick={() => setReportOpen(true)}\n />\n }\n />\n <aside className=\"space-y-6 min-w-0\">\n <IpTypeBadge ipType={token.metadata?.ipType ?? \"Video\"} size=\"md\" showLabel />\n {marketBlock}\n {ownerAddress ? <AssetOwnerRow ownerAddress={ownerAddress} ownerHref={profileHref({ address: ownerAddress })} /> : null}\n <AssetRelatedList\n title={publisherName}\n titleHref={collectionHref(\"STARKNET\", contract)}\n items={collectionTokens\n .filter((t) => String(t.tokenId) !== String(tokenId))\n .map((t) => ({\n tokenId: t.tokenId,\n name: t.metadata?.name || `${config.namePrefix} #${t.tokenId}`,\n image: resolveImage(t.metadata?.image),\n href: assetHref(\"STARKNET\", contract, t.tokenId),\n }))}\n />\n </aside>\n </div>\n ) : audio ? (\n <div className=\"grid grid-cols-1 lg:grid-cols-[minmax(0,2fr)_minmax(0,1fr)] lg:gap-12 gap-8 items-start\">\n <AssetAudio\n name={name}\n image={image}\n embedSrc={audio.src}\n embedLabel={audio.label}\n description={token.metadata?.description}\n collectionName={publisherName}\n collectionImage={resolveImage(collection?.image)}\n collectionHref={collectionHref(\"STARKNET\", contract)}\n utilities={\n <AssetUtilityIcons\n contractExplorerHref={`${EXPLORER_URL}/contract/${token.contractAddress}`}\n shareTitle={name}\n onReportClick={() => setReportOpen(true)}\n />\n }\n />\n <aside className=\"space-y-6 min-w-0\">\n <IpTypeBadge ipType={token.metadata?.ipType ?? \"Audio\"} size=\"md\" showLabel />\n {marketBlock}\n {ownerAddress ? <AssetOwnerRow ownerAddress={ownerAddress} ownerHref={profileHref({ address: ownerAddress })} /> : null}\n <AssetRelatedList\n title={publisherName}\n titleHref={collectionHref(\"STARKNET\", contract)}\n shape=\"square\"\n items={collectionTokens\n .filter((t) => String(t.tokenId) !== String(tokenId))\n .map((t) => ({\n tokenId: t.tokenId,\n name: t.metadata?.name || `${config.namePrefix} #${t.tokenId}`,\n image: resolveImage(t.metadata?.image),\n href: assetHref(\"STARKNET\", contract, t.tokenId),\n }))}\n />\n </aside>\n </div>\n ) : isPublication ? (\n <div className=\"grid grid-cols-1 lg:grid-cols-[minmax(0,2fr)_minmax(0,1fr)] lg:gap-20 gap-8 items-start\">\n <AssetPublication\n name={name}\n text={description!}\n image={image}\n imgError={imgError}\n onImageError={() => setImgError(true)}\n author={publicationAuthor(attributes, token.metadata?.author)}\n externalUrl={token.metadata?.externalUrl}\n />\n <aside className=\"space-y-6 min-w-0 lg:sticky lg:top-16\">\n <IpTypeBadge ipType={token.metadata?.ipType ?? \"Publications\"} size=\"md\" showLabel />\n {marketBlock}\n {detailsBlock}\n </aside>\n </div>\n ) : (\n <div className=\"grid grid-cols-1 lg:grid-cols-2 lg:gap-10 gap-8 items-start\">\n <AssetMediaColumn\n shouldReduce={Boolean(shouldReduce)}\n image={image}\n imageAlt={name}\n imgError={imgError}\n onImageError={() => setImgError(true)}\n animationUrl={token.metadata?.animationUrl}\n live={isLivingRenderCollection(token.chain as Chain, token.contractAddress)}\n fallback={<div className=\"aspect-square bg-muted\" />}\n />\n\n <motion.div\n initial={shouldReduce ? false : { opacity: 0, y: 16 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: 0.5, delay: 0.2 }}\n className=\"space-y-6\"\n >\n <AssetHeaderBlock\n name={name}\n description={token.metadata?.description}\n ipType={token.metadata?.ipType}\n parentContract={parentContract}\n parentTokenId={parentTokenId}\n badges={kind === \"pop\" ? (\n <span className=\"inline-flex items-center gap-1 text-2xs font-semibold px-2.5 py-1 rounded-full bg-brand-purple/15 text-brand-purple dark:bg-brand-purple/25\">\n <Award className=\"h-3 w-3\" />\n POP\n </span>\n ) : null}\n />\n\n {marketBlock}\n\n {detailsBlock}\n </motion.div>\n </div>\n )}\n\n <Tabs defaultValue=\"overview\">\n <TabsList>\n <TabsTrigger value=\"overview\">Overview</TabsTrigger>\n {config.market ? <TabsTrigger value=\"markets\">Markets {marketCount > 0 && `(${marketCount})`}</TabsTrigger> : null}\n <TabsTrigger value=\"provenance\">Provenance {history.length > 0 && `(${history.length})`}</TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"overview\">\n <AssetOverviewContent attributes={overview.attributes} hasTemplateData={overview.hasTemplateData} isDisplayAttr={overview.isDisplayAttr} content={postContent} link={overviewLink} />\n </TabsContent>\n\n {config.market ? (\n <TabsContent value=\"markets\">\n <AssetMarketsTab\n activeListings={market.activeListings}\n activeBids={market.activeBids}\n walletAddress={walletAddress ?? undefined}\n isOwner={market.isOwner}\n isProcessing={actions.isProcessing}\n onBuyClick={actions.buy}\n onCancelClick={actions.cancel}\n onAcceptClick={actions.acceptBid}\n />\n </TabsContent>\n ) : null}\n\n <TabsContent value=\"provenance\">\n <AssetProvenanceTab\n history={history as ApiActivity[]}\n contract={contract}\n tokenId={tokenId}\n remixCount={remixCount}\n originalCreator={fullTokenData?.originalCreator}\n registeredAt={fullTokenData?.registeredAt}\n />\n </TabsContent>\n </Tabs>\n </PageContainer>\n\n <FloatingCommentsButton onClick={() => setCommentOpen(true)} commentTotal={commentTotal} />\n <AssetCommentsDialog\n open={commentOpen}\n onOpenChange={setCommentOpen}\n contract={contract}\n tokenId={tokenId}\n name={name}\n imageUrl={image}\n commentTotal={commentTotal}\n {...config.accents}\n />\n <ReportDialog open={reportOpen} onOpenChange={setReportOpen} target={{ type: \"TOKEN\", contract: token.contractAddress, tokenId: token.tokenId, name }} />\n {actions.dialogs}\n </div>\n );\n}\n"],"mappings":"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","names":["import_sdk"]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/asset-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState, type ComponentType, type ReactNode } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { Award } from \"lucide-react\";\nimport { assetHref, collectionHref, getDerivativesTerm, getService, resolveRemixPolicy, type ApiActivity, type ApiCollection, type ApiOrder, type ApiToken, type Chain } from \"@medialane/sdk\";\nimport { useRouter } from \"./router.js\";\nimport { PageContainer } from \"./page-container.js\";\nimport { PageBackdrop } from \"./media-header.js\";\nimport { AssetHeaderBlock, AssetMediaColumn, AssetOwnerRow } from \"./asset-top-sections.js\";\nimport { AssetPublication } from \"./asset-publication.js\";\nimport { AssetRelatedList, AssetVideo, VIDEO_EMBED_TRAITS, videoEmbed } from \"./asset-video.js\";\nimport { AssetAudio, AUDIO_EMBED_TRAITS, audioEmbed } from \"./asset-audio.js\";\nimport { AssetUtilityIcons } from \"./asset-utility-icons.js\";\nimport { AssetMarketplacePanel } from \"./asset-marketplace-panel.js\";\nimport { AssetOwnersPanel } from \"./asset-owners-panel.js\";\nimport { AssetCollectionBar } from \"./asset-collection-bar.js\";\nimport { AssetOverviewContent } from \"./asset-overview-content.js\";\nimport { AssetMarketsTab } from \"./asset-markets-tab.js\";\nimport { AssetProvenanceTab } from \"./asset-provenance-tab.js\";\nimport { AssetUnavailable } from \"./asset-unavailable.js\";\nimport { HiddenContentBanner } from \"./hidden-content-banner.js\";\nimport { DropTokenLink } from \"./drop/drop-token-link.js\";\nimport { FloatingCommentsButton } from \"./floating-comments-button.js\";\nimport { AssetCommentsDialog } from \"./asset-comments-dialog.js\";\nimport { PopBurnButton } from \"./pop-burn-button.js\";\nimport { SoulboundCard } from \"./soulbound-card.js\";\nimport { MembershipPanel, TicketPanel, type AssetTypePanelProps } from \"./asset-type-panels.js\";\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"./tabs.js\";\nimport { Skeleton } from \"./skeleton.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport { ReportDialog } from \"./report-dialog.js\";\nimport { useToken, useTokenBalance, useTokenHistory } from \"../utils/use-tokens.js\";\nimport { useCollection, useNearbyCollectionTokens } from \"../utils/use-collections.js\";\nimport { useTokenListings } from \"../utils/use-orders.js\";\nimport { useTokenRemixes } from \"../utils/use-remix-offers.js\";\nimport { useComments } from \"../utils/use-comments.js\";\nimport { useFullTokenData } from \"../utils/use-full-token-data.js\";\nimport { useAssetMarketState } from \"../utils/asset-market-state.js\";\nimport { assetAttributes } from \"../utils/asset-attributes.js\";\nimport { externalLink } from \"../utils/external-link.js\";\nimport { ASSET_ACCENTS } from \"../utils/asset-accents.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\nimport { EXPLORER_URL } from \"../utils/explorer-url.js\";\nimport { profileHref } from \"@medialane/sdk\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\nexport type AssetKind = \"standard\" | \"edition\" | \"ticket\" | \"membership\" | \"pop\";\n\nexport interface AssetMarketContext {\n contract: string;\n tokenId: string;\n tokenName: string;\n tokenImage: string | null;\n tokenStandard: \"ERC721\" | \"ERC1155\" | \"UNKNOWN\";\n activeListings: ApiOrder[];\n quantityOwned?: string;\n mutateListings: () => void;\n}\n\nexport interface AssetMarketActions {\n isProcessing: boolean;\n buy: (order: ApiOrder) => void;\n list: () => void;\n offer: () => void;\n transfer: () => void;\n cancel: (order: ApiOrder) => void;\n acceptBid: (order: ApiOrder) => void;\n dialogs: ReactNode;\n}\n\ninterface KindConfig {\n namePrefix: string;\n accents: (typeof ASSET_ACCENTS)[keyof typeof ASSET_ACCENTS];\n market: boolean;\n remix: boolean;\n Panel?: ComponentType<AssetTypePanelProps>;\n}\n\nconst KINDS: Record<AssetKind, KindConfig> = {\n standard: { namePrefix: \"Token\", accents: ASSET_ACCENTS.standard, market: true, remix: true },\n edition: { namePrefix: \"Edition\", accents: ASSET_ACCENTS.edition, market: true, remix: false },\n ticket: { namePrefix: \"Ticket\", accents: ASSET_ACCENTS.ticket, market: true, remix: false, Panel: TicketPanel },\n membership: { namePrefix: \"Membership\", accents: ASSET_ACCENTS.membership, market: true, remix: false, Panel: MembershipPanel },\n pop: { namePrefix: \"POP\", accents: ASSET_ACCENTS.standard, market: false, remix: false },\n};\n\nconst PUBLICATION_TYPES = new Set([\"publications\", \"posts\"]);\n\ntype TraitList = { trait_type?: string | null; value?: string | number | boolean | null }[];\n\nfunction traitText(attributes: TraitList, trait: string): string | null {\n const value = attributes.find((a) => a.trait_type === trait)?.value;\n return typeof value === \"string\" && value.trim() !== \"\" ? value.trim() : null;\n}\n\nfunction publicationAuthor(attributes: TraitList, metadataAuthor?: string | null): string | null {\n return traitText(attributes, \"Author\") ?? metadataAuthor ?? traitText(attributes, \"Creator\");\n}\n\nconst VARIANT_KINDS: Partial<Record<string, AssetKind>> = { edition: \"edition\", ticket: \"ticket\", club: \"membership\", pop: \"pop\" };\n\nexport function detectAssetKind(service: string | null | undefined, standard: string | null | undefined): AssetKind {\n const variant = getService(service)?.uiVariant;\n if (variant) return VARIANT_KINDS[variant] ?? \"standard\";\n return standard === \"ERC1155\" ? \"edition\" : \"standard\";\n}\n\nexport function AssetPageSkeleton() {\n return (\n <PageContainer className=\"pt-20 pb-8\">\n <div className=\"grid grid-cols-1 lg:grid-cols-2 lg:gap-10 gap-6 items-start\">\n <Skeleton className=\"aspect-square w-full rounded-3xl\" />\n <div className=\"space-y-6\">\n <div className=\"space-y-3\">\n <Skeleton className=\"h-5 w-24 rounded-full\" />\n <Skeleton className=\"h-9 w-3/4\" />\n <Skeleton className=\"h-4 w-full\" />\n <Skeleton className=\"h-4 w-2/3\" />\n </div>\n <Skeleton className=\"h-[54px] w-full rounded-2xl\" />\n <div className=\"flex gap-2\">\n {Array.from({ length: 3 }).map((_, i) => <Skeleton key={i} className=\"h-[46px] flex-1 rounded-[13px]\" />)}\n </div>\n <Skeleton className=\"h-16 w-full rounded-2xl\" />\n </div>\n </div>\n </PageContainer>\n );\n}\n\nexport interface AssetPageProps {\n contract: string;\n tokenId: string;\n useMarketActions: (context: AssetMarketContext) => AssetMarketActions;\n}\n\nexport function AssetPage({ contract, tokenId, useMarketActions }: AssetPageProps) {\n const { token, isLoading, isIndexing } = useToken(contract, tokenId);\n const { collection, isLoading: collectionLoading } = useCollection(contract);\n if (isLoading || collectionLoading) return <AssetPageSkeleton />;\n if (!token) return <AssetUnavailable isIndexing={isIndexing} />;\n const kind = detectAssetKind(collection?.service, collection?.standard ?? token.standard);\n return <AssetPageView contract={contract} tokenId={tokenId} token={token} collection={collection ?? null} kind={kind} useMarketActions={useMarketActions} />;\n}\n\nfunction AssetPageView({\n contract,\n tokenId,\n token,\n collection,\n kind,\n useMarketActions,\n}: {\n contract: string;\n tokenId: string;\n token: ApiToken & { isHidden?: boolean };\n collection: ApiCollection | null;\n kind: AssetKind;\n useMarketActions: AssetPageProps[\"useMarketActions\"];\n}) {\n const resolveImage = useImageUrl();\n const config = KINDS[kind];\n const router = useRouter();\n const shouldReduce = useReducedMotion();\n const { walletAddress } = useMedialaneApp();\n\n const { listings, mutate: mutateListings, isLoading: listingsLoading } = useTokenListings(contract, tokenId);\n const { history } = useTokenHistory(contract, tokenId);\n const { tokens: collectionTokens } = useNearbyCollectionTokens(contract, tokenId);\n const { total: commentTotal } = useComments(contract, tokenId);\n const { total: remixCount } = useTokenRemixes(contract, tokenId);\n const { data: fullTokenData } = useFullTokenData(contract, tokenId);\n const { amount: walletBalance } = useTokenBalance(contract, tokenId, walletAddress);\n const market = useAssetMarketState({ token, collection, listings, history: history as ApiActivity[], walletAddress, walletBalance });\n\n const [reportOpen, setReportOpen] = useState(false);\n const [commentOpen, setCommentOpen] = useState(false);\n const [imgError, setImgError] = useState(false);\n\n const name = token.metadata?.name || `${config.namePrefix} #${token.tokenId}`;\n const image = resolveImage(token.metadata?.image);\n const tokenStandard = kind === \"standard\" || kind === \"pop\"\n ? ((token.standard ?? collection?.standard ?? \"UNKNOWN\") as AssetMarketContext[\"tokenStandard\"])\n : \"ERC1155\";\n\n const actions = useMarketActions({\n contract,\n tokenId,\n tokenName: name,\n tokenImage: image,\n tokenStandard,\n activeListings: market.activeListings,\n quantityOwned: market.quantityOwned,\n mutateListings,\n });\n\n const autoActionRef = useRef(false);\n useEffect(() => {\n if (autoActionRef.current || !config.market || !market.isOwner) return;\n const action = new URLSearchParams(window.location.search).get(\"action\");\n if (action === \"list\") actions.list();\n else if (action === \"transfer\") actions.transfer();\n else return;\n autoActionRef.current = true;\n }, [config.market, market.isOwner, actions]);\n\n const { attributes, hasTemplateData, isDisplayAttr, parentContract, parentTokenId } = assetAttributes(token.metadata?.attributes);\n const remixPolicy = resolveRemixPolicy({\n parentNoDerivatives: getDerivativesTerm(token.metadata?.attributes) === \"Not Allowed\",\n viewerIsParentOwner: market.isOwner,\n dealAvailable: !!getService(collection?.service),\n });\n const holders = token.balances ?? [];\n const ownerAddress = !market.isERC1155 ? (holders[0]?.owner ?? token.owner ?? null) : null;\n const marketCount = market.activeListings.length + market.activeBids.length;\n const { Panel } = config;\n\n const postContent = traitText(attributes, \"Content\");\n const description = token.metadata?.description?.trim() || null;\n const video = (token.metadata?.ipType ?? \"\").toLowerCase() === \"video\" ? videoEmbed(attributes) : null;\n const audio = (token.metadata?.ipType ?? \"\").toLowerCase() === \"audio\" ? audioEmbed(attributes) : null;\n const isPublication = !!description && PUBLICATION_TYPES.has((token.metadata?.ipType ?? \"\").toLowerCase());\n const publisherName = collection?.name ?? contract.slice(0, 8) + \"…\";\n const overviewAttributes = postContent ? attributes.filter((a) => a.trait_type !== \"Content\") : attributes;\n const overview = video || audio\n ? assetAttributes(overviewAttributes.filter((a) => !VIDEO_EMBED_TRAITS.has(a.trait_type ?? \"\") && !AUDIO_EMBED_TRAITS.has(a.trait_type ?? \"\")))\n : { attributes: overviewAttributes, hasTemplateData, isDisplayAttr };\n const overviewLink = isPublication || video || audio ? null : externalLink(token.metadata?.externalUrl);\n\n const marketBlock = (\n <>\n {Panel ? <Panel contract={contract} tokenId={tokenId} quantityOwned={market.quantityOwned} /> : null}\n\n {config.market ? (\n <AssetMarketplacePanel\n asset={token}\n compact={isPublication || !!video || !!audio}\n cheapest={market.cheapest}\n usdValue={market.cheapestUsd}\n isOwner={market.isOwner}\n isProcessing={actions.isProcessing}\n isERC1155={market.isERC1155}\n canListMoreEditions={market.canListMoreEditions}\n isMarketLoading={listingsLoading}\n myListing={market.myListing}\n activeBids={market.activeBids}\n remixEnabled={config.remix && remixPolicy.canRemixDirect}\n showDealOption={config.remix && remixPolicy.showDealOption}\n onCancelClick={actions.cancel}\n onAcceptBid={actions.acceptBid}\n onOpenListing={actions.list}\n onOpenTransfer={actions.transfer}\n onOpenPurchase={actions.buy}\n onOpenOffer={actions.offer}\n onOpenRemix={() => router.push(`/create/remix/${contract}/${tokenId}`)}\n />\n ) : null}\n\n {kind === \"pop\" && market.isOwner ? <PopBurnButton collectionAddress={contract} tokenId={tokenId} /> : null}\n\n {market.isERC1155 && holders.length > 0 ? (\n <AssetOwnersPanel balances={holders} total={token.holderCount} editions={Number(token.supply ?? 0)} />\n ) : null}\n </>\n );\n\n const detailsBlock = (\n <div className=\"pt-5 space-y-5\">\n <AssetOwnerRow ownerAddress={ownerAddress} ownerHref={ownerAddress ? profileHref({ address: ownerAddress }) : undefined} ipType={token.metadata?.ipType} />\n {collection?.service === \"drop-collection\" ? <DropTokenLink contract={contract} name={collection.name ?? null} /> : null}\n {kind === \"pop\" ? (\n <SoulboundCard history={history as ApiActivity[]} ownerAddress={ownerAddress} />\n ) : null}\n <AssetCollectionBar\n collectionName={publisherName}\n collectionImage={resolveImage(collection?.image)}\n collectionHref={collectionHref(\"STARKNET\", contract)}\n currentTokenId={tokenId}\n siblingTokens={collectionTokens.map((t) => ({\n tokenId: t.tokenId,\n image: resolveImage(t.metadata?.image),\n }))}\n onNavigate={(id) => router.push(assetHref(\"STARKNET\", contract, id))}\n floorPriceRaw={collection?.floorPrice}\n />\n <div className=\"-ml-3\">\n <AssetUtilityIcons\n contractExplorerHref={`${EXPLORER_URL}/contract/${token.contractAddress}`}\n shareTitle={name}\n onReportClick={() => setReportOpen(true)}\n />\n </div>\n </div>\n );\n\n return (\n <div className=\"relative z-0 min-h-screen\">\n {token.isHidden ? <HiddenContentBanner /> : null}\n <PageBackdrop image={image} />\n\n <PageContainer className={isPublication ? \"pt-20 space-y-8 pb-8 lg:px-16 xl:px-24\" : \"pt-20 space-y-8 pb-8\"}>\n {video ? (\n <div className=\"grid grid-cols-1 lg:grid-cols-[minmax(0,2fr)_minmax(0,1fr)] lg:gap-12 gap-8 items-start\">\n <AssetVideo\n name={name}\n embedSrc={video.src}\n embedLabel={video.label}\n description={token.metadata?.description}\n collectionName={publisherName}\n collectionImage={resolveImage(collection?.image)}\n collectionHref={collectionHref(\"STARKNET\", contract)}\n utilities={\n <AssetUtilityIcons\n contractExplorerHref={`${EXPLORER_URL}/contract/${token.contractAddress}`}\n shareTitle={name}\n onReportClick={() => setReportOpen(true)}\n />\n }\n />\n <aside className=\"space-y-6 min-w-0\">\n {marketBlock}\n <AssetOwnerRow ownerAddress={ownerAddress} ownerHref={ownerAddress ? profileHref({ address: ownerAddress }) : undefined} ipType={token.metadata?.ipType ?? \"Video\"} />\n <AssetRelatedList\n title={publisherName}\n titleHref={collectionHref(\"STARKNET\", contract)}\n items={collectionTokens\n .filter((t) => String(t.tokenId) !== String(tokenId))\n .map((t) => ({\n tokenId: t.tokenId,\n name: t.metadata?.name || `${config.namePrefix} #${t.tokenId}`,\n image: resolveImage(t.metadata?.image),\n href: assetHref(\"STARKNET\", contract, t.tokenId),\n }))}\n />\n </aside>\n </div>\n ) : audio ? (\n <div className=\"grid grid-cols-1 lg:grid-cols-[minmax(0,2fr)_minmax(0,1fr)] lg:gap-12 gap-8 items-start\">\n <AssetAudio\n name={name}\n image={image}\n embedSrc={audio.src}\n embedLabel={audio.label}\n description={token.metadata?.description}\n collectionName={publisherName}\n collectionImage={resolveImage(collection?.image)}\n collectionHref={collectionHref(\"STARKNET\", contract)}\n utilities={\n <AssetUtilityIcons\n contractExplorerHref={`${EXPLORER_URL}/contract/${token.contractAddress}`}\n shareTitle={name}\n onReportClick={() => setReportOpen(true)}\n />\n }\n />\n <aside className=\"space-y-6 min-w-0\">\n {marketBlock}\n <AssetOwnerRow ownerAddress={ownerAddress} ownerHref={ownerAddress ? profileHref({ address: ownerAddress }) : undefined} ipType={token.metadata?.ipType ?? \"Audio\"} />\n <AssetRelatedList\n title={publisherName}\n titleHref={collectionHref(\"STARKNET\", contract)}\n shape=\"square\"\n items={collectionTokens\n .filter((t) => String(t.tokenId) !== String(tokenId))\n .map((t) => ({\n tokenId: t.tokenId,\n name: t.metadata?.name || `${config.namePrefix} #${t.tokenId}`,\n image: resolveImage(t.metadata?.image),\n href: assetHref(\"STARKNET\", contract, t.tokenId),\n }))}\n />\n </aside>\n </div>\n ) : isPublication ? (\n <div className=\"grid grid-cols-1 lg:grid-cols-[minmax(0,2fr)_minmax(0,1fr)] lg:gap-20 gap-8 items-start\">\n <AssetPublication\n name={name}\n text={description!}\n image={image}\n imgError={imgError}\n onImageError={() => setImgError(true)}\n author={publicationAuthor(attributes, token.metadata?.author)}\n externalUrl={token.metadata?.externalUrl}\n />\n <aside className=\"space-y-6 min-w-0 lg:sticky lg:top-16\">\n {marketBlock}\n {detailsBlock}\n </aside>\n </div>\n ) : (\n <div className=\"grid grid-cols-1 lg:grid-cols-2 lg:gap-10 gap-8 items-start\">\n <AssetMediaColumn\n shouldReduce={Boolean(shouldReduce)}\n image={image}\n imageAlt={name}\n imgError={imgError}\n onImageError={() => setImgError(true)}\n animationUrl={token.metadata?.animationUrl}\n live={isLivingRenderCollection(token.chain as Chain, token.contractAddress)}\n fallback={<div className=\"aspect-square bg-muted\" />}\n />\n\n <motion.div\n initial={shouldReduce ? false : { opacity: 0, y: 16 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: 0.5, delay: 0.2 }}\n className=\"space-y-6\"\n >\n <AssetHeaderBlock\n name={name}\n description={token.metadata?.description}\n parentContract={parentContract}\n parentTokenId={parentTokenId}\n badges={kind === \"pop\" ? (\n <span className=\"inline-flex items-center gap-1 text-2xs font-semibold px-2.5 py-1 rounded-full bg-brand-purple/15 text-brand-purple dark:bg-brand-purple/25\">\n <Award className=\"h-3 w-3\" />\n POP\n </span>\n ) : null}\n />\n\n {marketBlock}\n\n {detailsBlock}\n </motion.div>\n </div>\n )}\n\n <Tabs defaultValue=\"overview\">\n <TabsList>\n <TabsTrigger value=\"overview\">Overview</TabsTrigger>\n {config.market ? <TabsTrigger value=\"markets\">Markets {marketCount > 0 && `(${marketCount})`}</TabsTrigger> : null}\n <TabsTrigger value=\"provenance\">Provenance {history.length > 0 && `(${history.length})`}</TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"overview\">\n <AssetOverviewContent attributes={overview.attributes} hasTemplateData={overview.hasTemplateData} isDisplayAttr={overview.isDisplayAttr} content={postContent} link={overviewLink} />\n </TabsContent>\n\n {config.market ? (\n <TabsContent value=\"markets\">\n <AssetMarketsTab\n activeListings={market.activeListings}\n activeBids={market.activeBids}\n walletAddress={walletAddress ?? undefined}\n isOwner={market.isOwner}\n isProcessing={actions.isProcessing}\n onBuyClick={actions.buy}\n onCancelClick={actions.cancel}\n onAcceptClick={actions.acceptBid}\n />\n </TabsContent>\n ) : null}\n\n <TabsContent value=\"provenance\">\n <AssetProvenanceTab\n history={history as ApiActivity[]}\n contract={contract}\n tokenId={tokenId}\n remixCount={remixCount}\n originalCreator={fullTokenData?.originalCreator}\n registeredAt={fullTokenData?.registeredAt}\n />\n </TabsContent>\n </Tabs>\n </PageContainer>\n\n <FloatingCommentsButton onClick={() => setCommentOpen(true)} commentTotal={commentTotal} />\n <AssetCommentsDialog\n open={commentOpen}\n onOpenChange={setCommentOpen}\n contract={contract}\n tokenId={tokenId}\n name={name}\n imageUrl={image}\n commentTotal={commentTotal}\n {...config.accents}\n />\n <ReportDialog open={reportOpen} onOpenChange={setReportOpen} target={{ type: \"TOKEN\", contract: token.contractAddress, tokenId: token.tokenId, name }} />\n {actions.dialogs}\n </div>\n );\n}\n"],"mappings":"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","names":["import_sdk"]}
|
|
@@ -9,7 +9,6 @@ import { PageContainer } from "./page-container.js";
|
|
|
9
9
|
import { PageBackdrop } from "./media-header.js";
|
|
10
10
|
import { AssetHeaderBlock, AssetMediaColumn, AssetOwnerRow } from "./asset-top-sections.js";
|
|
11
11
|
import { AssetPublication } from "./asset-publication.js";
|
|
12
|
-
import { IpTypeBadge } from "./ip-type-badge.js";
|
|
13
12
|
import { AssetRelatedList, AssetVideo, VIDEO_EMBED_TRAITS, videoEmbed } from "./asset-video.js";
|
|
14
13
|
import { AssetAudio, AUDIO_EMBED_TRAITS, audioEmbed } from "./asset-audio.js";
|
|
15
14
|
import { AssetUtilityIcons } from "./asset-utility-icons.js";
|
|
@@ -186,8 +185,9 @@ function AssetPageView({
|
|
|
186
185
|
market.isERC1155 && holders.length > 0 ? /* @__PURE__ */ jsx(AssetOwnersPanel, { balances: holders, total: token.holderCount, editions: Number(token.supply ?? 0) }) : null
|
|
187
186
|
] });
|
|
188
187
|
const detailsBlock = /* @__PURE__ */ jsxs("div", { className: "pt-5 space-y-5", children: [
|
|
189
|
-
|
|
188
|
+
/* @__PURE__ */ jsx(AssetOwnerRow, { ownerAddress, ownerHref: ownerAddress ? profileHref({ address: ownerAddress }) : void 0, ipType: token.metadata?.ipType }),
|
|
190
189
|
collection?.service === "drop-collection" ? /* @__PURE__ */ jsx(DropTokenLink, { contract, name: collection.name ?? null }) : null,
|
|
190
|
+
kind === "pop" ? /* @__PURE__ */ jsx(SoulboundCard, { history, ownerAddress }) : null,
|
|
191
191
|
/* @__PURE__ */ jsx(
|
|
192
192
|
AssetCollectionBar,
|
|
193
193
|
{
|
|
@@ -203,7 +203,6 @@ function AssetPageView({
|
|
|
203
203
|
floorPriceRaw: collection?.floorPrice
|
|
204
204
|
}
|
|
205
205
|
),
|
|
206
|
-
kind === "pop" ? /* @__PURE__ */ jsx(SoulboundCard, { history, ownerAddress }) : null,
|
|
207
206
|
/* @__PURE__ */ jsx("div", { className: "-ml-3", children: /* @__PURE__ */ jsx(
|
|
208
207
|
AssetUtilityIcons,
|
|
209
208
|
{
|
|
@@ -239,9 +238,8 @@ function AssetPageView({
|
|
|
239
238
|
}
|
|
240
239
|
),
|
|
241
240
|
/* @__PURE__ */ jsxs("aside", { className: "space-y-6 min-w-0", children: [
|
|
242
|
-
/* @__PURE__ */ jsx(IpTypeBadge, { ipType: token.metadata?.ipType ?? "Video", size: "md", showLabel: true }),
|
|
243
241
|
marketBlock,
|
|
244
|
-
|
|
242
|
+
/* @__PURE__ */ jsx(AssetOwnerRow, { ownerAddress, ownerHref: ownerAddress ? profileHref({ address: ownerAddress }) : void 0, ipType: token.metadata?.ipType ?? "Video" }),
|
|
245
243
|
/* @__PURE__ */ jsx(
|
|
246
244
|
AssetRelatedList,
|
|
247
245
|
{
|
|
@@ -279,9 +277,8 @@ function AssetPageView({
|
|
|
279
277
|
}
|
|
280
278
|
),
|
|
281
279
|
/* @__PURE__ */ jsxs("aside", { className: "space-y-6 min-w-0", children: [
|
|
282
|
-
/* @__PURE__ */ jsx(IpTypeBadge, { ipType: token.metadata?.ipType ?? "Audio", size: "md", showLabel: true }),
|
|
283
280
|
marketBlock,
|
|
284
|
-
|
|
281
|
+
/* @__PURE__ */ jsx(AssetOwnerRow, { ownerAddress, ownerHref: ownerAddress ? profileHref({ address: ownerAddress }) : void 0, ipType: token.metadata?.ipType ?? "Audio" }),
|
|
285
282
|
/* @__PURE__ */ jsx(
|
|
286
283
|
AssetRelatedList,
|
|
287
284
|
{
|
|
@@ -311,7 +308,6 @@ function AssetPageView({
|
|
|
311
308
|
}
|
|
312
309
|
),
|
|
313
310
|
/* @__PURE__ */ jsxs("aside", { className: "space-y-6 min-w-0 lg:sticky lg:top-16", children: [
|
|
314
|
-
/* @__PURE__ */ jsx(IpTypeBadge, { ipType: token.metadata?.ipType ?? "Publications", size: "md", showLabel: true }),
|
|
315
311
|
marketBlock,
|
|
316
312
|
detailsBlock
|
|
317
313
|
] })
|
|
@@ -342,7 +338,6 @@ function AssetPageView({
|
|
|
342
338
|
{
|
|
343
339
|
name,
|
|
344
340
|
description: token.metadata?.description,
|
|
345
|
-
ipType: token.metadata?.ipType,
|
|
346
341
|
parentContract,
|
|
347
342
|
parentTokenId,
|
|
348
343
|
badges: kind === "pop" ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 text-2xs font-semibold px-2.5 py-1 rounded-full bg-brand-purple/15 text-brand-purple dark:bg-brand-purple/25", children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/asset-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState, type ComponentType, type ReactNode } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { Award } from \"lucide-react\";\nimport { assetHref, collectionHref, getDerivativesTerm, getService, resolveRemixPolicy, type ApiActivity, type ApiCollection, type ApiOrder, type ApiToken, type Chain } from \"@medialane/sdk\";\nimport { useRouter } from \"./router.js\";\nimport { PageContainer } from \"./page-container.js\";\nimport { PageBackdrop } from \"./media-header.js\";\nimport { AssetHeaderBlock, AssetMediaColumn, AssetOwnerRow } from \"./asset-top-sections.js\";\nimport { AssetPublication } from \"./asset-publication.js\";\nimport { IpTypeBadge } from \"./ip-type-badge.js\";\nimport { AssetRelatedList, AssetVideo, VIDEO_EMBED_TRAITS, videoEmbed } from \"./asset-video.js\";\nimport { AssetAudio, AUDIO_EMBED_TRAITS, audioEmbed } from \"./asset-audio.js\";\nimport { AssetUtilityIcons } from \"./asset-utility-icons.js\";\nimport { AssetMarketplacePanel } from \"./asset-marketplace-panel.js\";\nimport { AssetOwnersPanel } from \"./asset-owners-panel.js\";\nimport { AssetCollectionBar } from \"./asset-collection-bar.js\";\nimport { AssetOverviewContent } from \"./asset-overview-content.js\";\nimport { AssetMarketsTab } from \"./asset-markets-tab.js\";\nimport { AssetProvenanceTab } from \"./asset-provenance-tab.js\";\nimport { AssetUnavailable } from \"./asset-unavailable.js\";\nimport { HiddenContentBanner } from \"./hidden-content-banner.js\";\nimport { DropTokenLink } from \"./drop/drop-token-link.js\";\nimport { FloatingCommentsButton } from \"./floating-comments-button.js\";\nimport { AssetCommentsDialog } from \"./asset-comments-dialog.js\";\nimport { PopBurnButton } from \"./pop-burn-button.js\";\nimport { SoulboundCard } from \"./soulbound-card.js\";\nimport { MembershipPanel, TicketPanel, type AssetTypePanelProps } from \"./asset-type-panels.js\";\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"./tabs.js\";\nimport { Skeleton } from \"./skeleton.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport { ReportDialog } from \"./report-dialog.js\";\nimport { useToken, useTokenBalance, useTokenHistory } from \"../utils/use-tokens.js\";\nimport { useCollection, useNearbyCollectionTokens } from \"../utils/use-collections.js\";\nimport { useTokenListings } from \"../utils/use-orders.js\";\nimport { useTokenRemixes } from \"../utils/use-remix-offers.js\";\nimport { useComments } from \"../utils/use-comments.js\";\nimport { useFullTokenData } from \"../utils/use-full-token-data.js\";\nimport { useAssetMarketState } from \"../utils/asset-market-state.js\";\nimport { assetAttributes } from \"../utils/asset-attributes.js\";\nimport { externalLink } from \"../utils/external-link.js\";\nimport { ASSET_ACCENTS } from \"../utils/asset-accents.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\nimport { EXPLORER_URL } from \"../utils/explorer-url.js\";\nimport { profileHref } from \"@medialane/sdk\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\nexport type AssetKind = \"standard\" | \"edition\" | \"ticket\" | \"membership\" | \"pop\";\n\nexport interface AssetMarketContext {\n contract: string;\n tokenId: string;\n tokenName: string;\n tokenImage: string | null;\n tokenStandard: \"ERC721\" | \"ERC1155\" | \"UNKNOWN\";\n activeListings: ApiOrder[];\n quantityOwned?: string;\n mutateListings: () => void;\n}\n\nexport interface AssetMarketActions {\n isProcessing: boolean;\n buy: (order: ApiOrder) => void;\n list: () => void;\n offer: () => void;\n transfer: () => void;\n cancel: (order: ApiOrder) => void;\n acceptBid: (order: ApiOrder) => void;\n dialogs: ReactNode;\n}\n\ninterface KindConfig {\n namePrefix: string;\n accents: (typeof ASSET_ACCENTS)[keyof typeof ASSET_ACCENTS];\n market: boolean;\n remix: boolean;\n Panel?: ComponentType<AssetTypePanelProps>;\n}\n\nconst KINDS: Record<AssetKind, KindConfig> = {\n standard: { namePrefix: \"Token\", accents: ASSET_ACCENTS.standard, market: true, remix: true },\n edition: { namePrefix: \"Edition\", accents: ASSET_ACCENTS.edition, market: true, remix: false },\n ticket: { namePrefix: \"Ticket\", accents: ASSET_ACCENTS.ticket, market: true, remix: false, Panel: TicketPanel },\n membership: { namePrefix: \"Membership\", accents: ASSET_ACCENTS.membership, market: true, remix: false, Panel: MembershipPanel },\n pop: { namePrefix: \"POP\", accents: ASSET_ACCENTS.standard, market: false, remix: false },\n};\n\nconst PUBLICATION_TYPES = new Set([\"publications\", \"posts\"]);\n\ntype TraitList = { trait_type?: string | null; value?: string | number | boolean | null }[];\n\nfunction traitText(attributes: TraitList, trait: string): string | null {\n const value = attributes.find((a) => a.trait_type === trait)?.value;\n return typeof value === \"string\" && value.trim() !== \"\" ? value.trim() : null;\n}\n\nfunction publicationAuthor(attributes: TraitList, metadataAuthor?: string | null): string | null {\n return traitText(attributes, \"Author\") ?? metadataAuthor ?? traitText(attributes, \"Creator\");\n}\n\nconst VARIANT_KINDS: Partial<Record<string, AssetKind>> = { edition: \"edition\", ticket: \"ticket\", club: \"membership\", pop: \"pop\" };\n\nexport function detectAssetKind(service: string | null | undefined, standard: string | null | undefined): AssetKind {\n const variant = getService(service)?.uiVariant;\n if (variant) return VARIANT_KINDS[variant] ?? \"standard\";\n return standard === \"ERC1155\" ? \"edition\" : \"standard\";\n}\n\nexport function AssetPageSkeleton() {\n return (\n <PageContainer className=\"pt-20 pb-8\">\n <div className=\"grid grid-cols-1 lg:grid-cols-2 lg:gap-10 gap-6 items-start\">\n <Skeleton className=\"aspect-square w-full rounded-3xl\" />\n <div className=\"space-y-6\">\n <div className=\"space-y-3\">\n <Skeleton className=\"h-5 w-24 rounded-full\" />\n <Skeleton className=\"h-9 w-3/4\" />\n <Skeleton className=\"h-4 w-full\" />\n <Skeleton className=\"h-4 w-2/3\" />\n </div>\n <Skeleton className=\"h-[54px] w-full rounded-2xl\" />\n <div className=\"flex gap-2\">\n {Array.from({ length: 3 }).map((_, i) => <Skeleton key={i} className=\"h-[46px] flex-1 rounded-[13px]\" />)}\n </div>\n <Skeleton className=\"h-16 w-full rounded-2xl\" />\n </div>\n </div>\n </PageContainer>\n );\n}\n\nexport interface AssetPageProps {\n contract: string;\n tokenId: string;\n useMarketActions: (context: AssetMarketContext) => AssetMarketActions;\n}\n\nexport function AssetPage({ contract, tokenId, useMarketActions }: AssetPageProps) {\n const { token, isLoading, isIndexing } = useToken(contract, tokenId);\n const { collection, isLoading: collectionLoading } = useCollection(contract);\n if (isLoading || collectionLoading) return <AssetPageSkeleton />;\n if (!token) return <AssetUnavailable isIndexing={isIndexing} />;\n const kind = detectAssetKind(collection?.service, collection?.standard ?? token.standard);\n return <AssetPageView contract={contract} tokenId={tokenId} token={token} collection={collection ?? null} kind={kind} useMarketActions={useMarketActions} />;\n}\n\nfunction AssetPageView({\n contract,\n tokenId,\n token,\n collection,\n kind,\n useMarketActions,\n}: {\n contract: string;\n tokenId: string;\n token: ApiToken & { isHidden?: boolean };\n collection: ApiCollection | null;\n kind: AssetKind;\n useMarketActions: AssetPageProps[\"useMarketActions\"];\n}) {\n const resolveImage = useImageUrl();\n const config = KINDS[kind];\n const router = useRouter();\n const shouldReduce = useReducedMotion();\n const { walletAddress } = useMedialaneApp();\n\n const { listings, mutate: mutateListings, isLoading: listingsLoading } = useTokenListings(contract, tokenId);\n const { history } = useTokenHistory(contract, tokenId);\n const { tokens: collectionTokens } = useNearbyCollectionTokens(contract, tokenId);\n const { total: commentTotal } = useComments(contract, tokenId);\n const { total: remixCount } = useTokenRemixes(contract, tokenId);\n const { data: fullTokenData } = useFullTokenData(contract, tokenId);\n const { amount: walletBalance } = useTokenBalance(contract, tokenId, walletAddress);\n const market = useAssetMarketState({ token, collection, listings, history: history as ApiActivity[], walletAddress, walletBalance });\n\n const [reportOpen, setReportOpen] = useState(false);\n const [commentOpen, setCommentOpen] = useState(false);\n const [imgError, setImgError] = useState(false);\n\n const name = token.metadata?.name || `${config.namePrefix} #${token.tokenId}`;\n const image = resolveImage(token.metadata?.image);\n const tokenStandard = kind === \"standard\" || kind === \"pop\"\n ? ((token.standard ?? collection?.standard ?? \"UNKNOWN\") as AssetMarketContext[\"tokenStandard\"])\n : \"ERC1155\";\n\n const actions = useMarketActions({\n contract,\n tokenId,\n tokenName: name,\n tokenImage: image,\n tokenStandard,\n activeListings: market.activeListings,\n quantityOwned: market.quantityOwned,\n mutateListings,\n });\n\n const autoActionRef = useRef(false);\n useEffect(() => {\n if (autoActionRef.current || !config.market || !market.isOwner) return;\n const action = new URLSearchParams(window.location.search).get(\"action\");\n if (action === \"list\") actions.list();\n else if (action === \"transfer\") actions.transfer();\n else return;\n autoActionRef.current = true;\n }, [config.market, market.isOwner, actions]);\n\n const { attributes, hasTemplateData, isDisplayAttr, parentContract, parentTokenId } = assetAttributes(token.metadata?.attributes);\n const remixPolicy = resolveRemixPolicy({\n parentNoDerivatives: getDerivativesTerm(token.metadata?.attributes) === \"Not Allowed\",\n viewerIsParentOwner: market.isOwner,\n dealAvailable: !!getService(collection?.service),\n });\n const holders = token.balances ?? [];\n const ownerAddress = !market.isERC1155 ? (holders[0]?.owner ?? token.owner ?? null) : null;\n const marketCount = market.activeListings.length + market.activeBids.length;\n const { Panel } = config;\n\n const postContent = traitText(attributes, \"Content\");\n const description = token.metadata?.description?.trim() || null;\n const video = (token.metadata?.ipType ?? \"\").toLowerCase() === \"video\" ? videoEmbed(attributes) : null;\n const audio = (token.metadata?.ipType ?? \"\").toLowerCase() === \"audio\" ? audioEmbed(attributes) : null;\n const isPublication = !!description && PUBLICATION_TYPES.has((token.metadata?.ipType ?? \"\").toLowerCase());\n const publisherName = collection?.name ?? contract.slice(0, 8) + \"…\";\n const overviewAttributes = postContent ? attributes.filter((a) => a.trait_type !== \"Content\") : attributes;\n const overview = video || audio\n ? assetAttributes(overviewAttributes.filter((a) => !VIDEO_EMBED_TRAITS.has(a.trait_type ?? \"\") && !AUDIO_EMBED_TRAITS.has(a.trait_type ?? \"\")))\n : { attributes: overviewAttributes, hasTemplateData, isDisplayAttr };\n const overviewLink = isPublication || video || audio ? null : externalLink(token.metadata?.externalUrl);\n\n const marketBlock = (\n <>\n {Panel ? <Panel contract={contract} tokenId={tokenId} quantityOwned={market.quantityOwned} /> : null}\n\n {config.market ? (\n <AssetMarketplacePanel\n asset={token}\n compact={isPublication || !!video || !!audio}\n cheapest={market.cheapest}\n usdValue={market.cheapestUsd}\n isOwner={market.isOwner}\n isProcessing={actions.isProcessing}\n isERC1155={market.isERC1155}\n canListMoreEditions={market.canListMoreEditions}\n isMarketLoading={listingsLoading}\n myListing={market.myListing}\n activeBids={market.activeBids}\n remixEnabled={config.remix && remixPolicy.canRemixDirect}\n showDealOption={config.remix && remixPolicy.showDealOption}\n onCancelClick={actions.cancel}\n onAcceptBid={actions.acceptBid}\n onOpenListing={actions.list}\n onOpenTransfer={actions.transfer}\n onOpenPurchase={actions.buy}\n onOpenOffer={actions.offer}\n onOpenRemix={() => router.push(`/create/remix/${contract}/${tokenId}`)}\n />\n ) : null}\n\n {kind === \"pop\" && market.isOwner ? <PopBurnButton collectionAddress={contract} tokenId={tokenId} /> : null}\n\n {market.isERC1155 && holders.length > 0 ? (\n <AssetOwnersPanel balances={holders} total={token.holderCount} editions={Number(token.supply ?? 0)} />\n ) : null}\n </>\n );\n\n const detailsBlock = (\n <div className=\"pt-5 space-y-5\">\n {ownerAddress ? <AssetOwnerRow ownerAddress={ownerAddress} ownerHref={profileHref({ address: ownerAddress })} /> : null}\n {collection?.service === \"drop-collection\" ? <DropTokenLink contract={contract} name={collection.name ?? null} /> : null}\n <AssetCollectionBar\n collectionName={publisherName}\n collectionImage={resolveImage(collection?.image)}\n collectionHref={collectionHref(\"STARKNET\", contract)}\n currentTokenId={tokenId}\n siblingTokens={collectionTokens.map((t) => ({\n tokenId: t.tokenId,\n image: resolveImage(t.metadata?.image),\n }))}\n onNavigate={(id) => router.push(assetHref(\"STARKNET\", contract, id))}\n floorPriceRaw={collection?.floorPrice}\n />\n {kind === \"pop\" ? (\n <SoulboundCard history={history as ApiActivity[]} ownerAddress={ownerAddress} />\n ) : null}\n <div className=\"-ml-3\">\n <AssetUtilityIcons\n contractExplorerHref={`${EXPLORER_URL}/contract/${token.contractAddress}`}\n shareTitle={name}\n onReportClick={() => setReportOpen(true)}\n />\n </div>\n </div>\n );\n\n return (\n <div className=\"relative z-0 min-h-screen\">\n {token.isHidden ? <HiddenContentBanner /> : null}\n <PageBackdrop image={image} />\n\n <PageContainer className={isPublication ? \"pt-20 space-y-8 pb-8 lg:px-16 xl:px-24\" : \"pt-20 space-y-8 pb-8\"}>\n {video ? (\n <div className=\"grid grid-cols-1 lg:grid-cols-[minmax(0,2fr)_minmax(0,1fr)] lg:gap-12 gap-8 items-start\">\n <AssetVideo\n name={name}\n embedSrc={video.src}\n embedLabel={video.label}\n description={token.metadata?.description}\n collectionName={publisherName}\n collectionImage={resolveImage(collection?.image)}\n collectionHref={collectionHref(\"STARKNET\", contract)}\n utilities={\n <AssetUtilityIcons\n contractExplorerHref={`${EXPLORER_URL}/contract/${token.contractAddress}`}\n shareTitle={name}\n onReportClick={() => setReportOpen(true)}\n />\n }\n />\n <aside className=\"space-y-6 min-w-0\">\n <IpTypeBadge ipType={token.metadata?.ipType ?? \"Video\"} size=\"md\" showLabel />\n {marketBlock}\n {ownerAddress ? <AssetOwnerRow ownerAddress={ownerAddress} ownerHref={profileHref({ address: ownerAddress })} /> : null}\n <AssetRelatedList\n title={publisherName}\n titleHref={collectionHref(\"STARKNET\", contract)}\n items={collectionTokens\n .filter((t) => String(t.tokenId) !== String(tokenId))\n .map((t) => ({\n tokenId: t.tokenId,\n name: t.metadata?.name || `${config.namePrefix} #${t.tokenId}`,\n image: resolveImage(t.metadata?.image),\n href: assetHref(\"STARKNET\", contract, t.tokenId),\n }))}\n />\n </aside>\n </div>\n ) : audio ? (\n <div className=\"grid grid-cols-1 lg:grid-cols-[minmax(0,2fr)_minmax(0,1fr)] lg:gap-12 gap-8 items-start\">\n <AssetAudio\n name={name}\n image={image}\n embedSrc={audio.src}\n embedLabel={audio.label}\n description={token.metadata?.description}\n collectionName={publisherName}\n collectionImage={resolveImage(collection?.image)}\n collectionHref={collectionHref(\"STARKNET\", contract)}\n utilities={\n <AssetUtilityIcons\n contractExplorerHref={`${EXPLORER_URL}/contract/${token.contractAddress}`}\n shareTitle={name}\n onReportClick={() => setReportOpen(true)}\n />\n }\n />\n <aside className=\"space-y-6 min-w-0\">\n <IpTypeBadge ipType={token.metadata?.ipType ?? \"Audio\"} size=\"md\" showLabel />\n {marketBlock}\n {ownerAddress ? <AssetOwnerRow ownerAddress={ownerAddress} ownerHref={profileHref({ address: ownerAddress })} /> : null}\n <AssetRelatedList\n title={publisherName}\n titleHref={collectionHref(\"STARKNET\", contract)}\n shape=\"square\"\n items={collectionTokens\n .filter((t) => String(t.tokenId) !== String(tokenId))\n .map((t) => ({\n tokenId: t.tokenId,\n name: t.metadata?.name || `${config.namePrefix} #${t.tokenId}`,\n image: resolveImage(t.metadata?.image),\n href: assetHref(\"STARKNET\", contract, t.tokenId),\n }))}\n />\n </aside>\n </div>\n ) : isPublication ? (\n <div className=\"grid grid-cols-1 lg:grid-cols-[minmax(0,2fr)_minmax(0,1fr)] lg:gap-20 gap-8 items-start\">\n <AssetPublication\n name={name}\n text={description!}\n image={image}\n imgError={imgError}\n onImageError={() => setImgError(true)}\n author={publicationAuthor(attributes, token.metadata?.author)}\n externalUrl={token.metadata?.externalUrl}\n />\n <aside className=\"space-y-6 min-w-0 lg:sticky lg:top-16\">\n <IpTypeBadge ipType={token.metadata?.ipType ?? \"Publications\"} size=\"md\" showLabel />\n {marketBlock}\n {detailsBlock}\n </aside>\n </div>\n ) : (\n <div className=\"grid grid-cols-1 lg:grid-cols-2 lg:gap-10 gap-8 items-start\">\n <AssetMediaColumn\n shouldReduce={Boolean(shouldReduce)}\n image={image}\n imageAlt={name}\n imgError={imgError}\n onImageError={() => setImgError(true)}\n animationUrl={token.metadata?.animationUrl}\n live={isLivingRenderCollection(token.chain as Chain, token.contractAddress)}\n fallback={<div className=\"aspect-square bg-muted\" />}\n />\n\n <motion.div\n initial={shouldReduce ? false : { opacity: 0, y: 16 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: 0.5, delay: 0.2 }}\n className=\"space-y-6\"\n >\n <AssetHeaderBlock\n name={name}\n description={token.metadata?.description}\n ipType={token.metadata?.ipType}\n parentContract={parentContract}\n parentTokenId={parentTokenId}\n badges={kind === \"pop\" ? (\n <span className=\"inline-flex items-center gap-1 text-2xs font-semibold px-2.5 py-1 rounded-full bg-brand-purple/15 text-brand-purple dark:bg-brand-purple/25\">\n <Award className=\"h-3 w-3\" />\n POP\n </span>\n ) : null}\n />\n\n {marketBlock}\n\n {detailsBlock}\n </motion.div>\n </div>\n )}\n\n <Tabs defaultValue=\"overview\">\n <TabsList>\n <TabsTrigger value=\"overview\">Overview</TabsTrigger>\n {config.market ? <TabsTrigger value=\"markets\">Markets {marketCount > 0 && `(${marketCount})`}</TabsTrigger> : null}\n <TabsTrigger value=\"provenance\">Provenance {history.length > 0 && `(${history.length})`}</TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"overview\">\n <AssetOverviewContent attributes={overview.attributes} hasTemplateData={overview.hasTemplateData} isDisplayAttr={overview.isDisplayAttr} content={postContent} link={overviewLink} />\n </TabsContent>\n\n {config.market ? (\n <TabsContent value=\"markets\">\n <AssetMarketsTab\n activeListings={market.activeListings}\n activeBids={market.activeBids}\n walletAddress={walletAddress ?? undefined}\n isOwner={market.isOwner}\n isProcessing={actions.isProcessing}\n onBuyClick={actions.buy}\n onCancelClick={actions.cancel}\n onAcceptClick={actions.acceptBid}\n />\n </TabsContent>\n ) : null}\n\n <TabsContent value=\"provenance\">\n <AssetProvenanceTab\n history={history as ApiActivity[]}\n contract={contract}\n tokenId={tokenId}\n remixCount={remixCount}\n originalCreator={fullTokenData?.originalCreator}\n registeredAt={fullTokenData?.registeredAt}\n />\n </TabsContent>\n </Tabs>\n </PageContainer>\n\n <FloatingCommentsButton onClick={() => setCommentOpen(true)} commentTotal={commentTotal} />\n <AssetCommentsDialog\n open={commentOpen}\n onOpenChange={setCommentOpen}\n contract={contract}\n tokenId={tokenId}\n name={name}\n imageUrl={image}\n commentTotal={commentTotal}\n {...config.accents}\n />\n <ReportDialog open={reportOpen} onOpenChange={setReportOpen} target={{ type: \"TOKEN\", contract: token.contractAddress, tokenId: token.tokenId, name }} />\n {actions.dialogs}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/asset-page.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState, type ComponentType, type ReactNode } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { Award } from \"lucide-react\";\nimport { assetHref, collectionHref, getDerivativesTerm, getService, resolveRemixPolicy, type ApiActivity, type ApiCollection, type ApiOrder, type ApiToken, type Chain } from \"@medialane/sdk\";\nimport { useRouter } from \"./router.js\";\nimport { PageContainer } from \"./page-container.js\";\nimport { PageBackdrop } from \"./media-header.js\";\nimport { AssetHeaderBlock, AssetMediaColumn, AssetOwnerRow } from \"./asset-top-sections.js\";\nimport { AssetPublication } from \"./asset-publication.js\";\nimport { AssetRelatedList, AssetVideo, VIDEO_EMBED_TRAITS, videoEmbed } from \"./asset-video.js\";\nimport { AssetAudio, AUDIO_EMBED_TRAITS, audioEmbed } from \"./asset-audio.js\";\nimport { AssetUtilityIcons } from \"./asset-utility-icons.js\";\nimport { AssetMarketplacePanel } from \"./asset-marketplace-panel.js\";\nimport { AssetOwnersPanel } from \"./asset-owners-panel.js\";\nimport { AssetCollectionBar } from \"./asset-collection-bar.js\";\nimport { AssetOverviewContent } from \"./asset-overview-content.js\";\nimport { AssetMarketsTab } from \"./asset-markets-tab.js\";\nimport { AssetProvenanceTab } from \"./asset-provenance-tab.js\";\nimport { AssetUnavailable } from \"./asset-unavailable.js\";\nimport { HiddenContentBanner } from \"./hidden-content-banner.js\";\nimport { DropTokenLink } from \"./drop/drop-token-link.js\";\nimport { FloatingCommentsButton } from \"./floating-comments-button.js\";\nimport { AssetCommentsDialog } from \"./asset-comments-dialog.js\";\nimport { PopBurnButton } from \"./pop-burn-button.js\";\nimport { SoulboundCard } from \"./soulbound-card.js\";\nimport { MembershipPanel, TicketPanel, type AssetTypePanelProps } from \"./asset-type-panels.js\";\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"./tabs.js\";\nimport { Skeleton } from \"./skeleton.js\";\nimport { useMedialaneApp } from \"./medialane-app.js\";\nimport { ReportDialog } from \"./report-dialog.js\";\nimport { useToken, useTokenBalance, useTokenHistory } from \"../utils/use-tokens.js\";\nimport { useCollection, useNearbyCollectionTokens } from \"../utils/use-collections.js\";\nimport { useTokenListings } from \"../utils/use-orders.js\";\nimport { useTokenRemixes } from \"../utils/use-remix-offers.js\";\nimport { useComments } from \"../utils/use-comments.js\";\nimport { useFullTokenData } from \"../utils/use-full-token-data.js\";\nimport { useAssetMarketState } from \"../utils/asset-market-state.js\";\nimport { assetAttributes } from \"../utils/asset-attributes.js\";\nimport { externalLink } from \"../utils/external-link.js\";\nimport { ASSET_ACCENTS } from \"../utils/asset-accents.js\";\nimport { isLivingRenderCollection } from \"../data/living-render-collections.js\";\nimport { EXPLORER_URL } from \"../utils/explorer-url.js\";\nimport { profileHref } from \"@medialane/sdk\";\nimport { useImageUrl } from \"../utils/use-image-url.js\";\n\nexport type AssetKind = \"standard\" | \"edition\" | \"ticket\" | \"membership\" | \"pop\";\n\nexport interface AssetMarketContext {\n contract: string;\n tokenId: string;\n tokenName: string;\n tokenImage: string | null;\n tokenStandard: \"ERC721\" | \"ERC1155\" | \"UNKNOWN\";\n activeListings: ApiOrder[];\n quantityOwned?: string;\n mutateListings: () => void;\n}\n\nexport interface AssetMarketActions {\n isProcessing: boolean;\n buy: (order: ApiOrder) => void;\n list: () => void;\n offer: () => void;\n transfer: () => void;\n cancel: (order: ApiOrder) => void;\n acceptBid: (order: ApiOrder) => void;\n dialogs: ReactNode;\n}\n\ninterface KindConfig {\n namePrefix: string;\n accents: (typeof ASSET_ACCENTS)[keyof typeof ASSET_ACCENTS];\n market: boolean;\n remix: boolean;\n Panel?: ComponentType<AssetTypePanelProps>;\n}\n\nconst KINDS: Record<AssetKind, KindConfig> = {\n standard: { namePrefix: \"Token\", accents: ASSET_ACCENTS.standard, market: true, remix: true },\n edition: { namePrefix: \"Edition\", accents: ASSET_ACCENTS.edition, market: true, remix: false },\n ticket: { namePrefix: \"Ticket\", accents: ASSET_ACCENTS.ticket, market: true, remix: false, Panel: TicketPanel },\n membership: { namePrefix: \"Membership\", accents: ASSET_ACCENTS.membership, market: true, remix: false, Panel: MembershipPanel },\n pop: { namePrefix: \"POP\", accents: ASSET_ACCENTS.standard, market: false, remix: false },\n};\n\nconst PUBLICATION_TYPES = new Set([\"publications\", \"posts\"]);\n\ntype TraitList = { trait_type?: string | null; value?: string | number | boolean | null }[];\n\nfunction traitText(attributes: TraitList, trait: string): string | null {\n const value = attributes.find((a) => a.trait_type === trait)?.value;\n return typeof value === \"string\" && value.trim() !== \"\" ? value.trim() : null;\n}\n\nfunction publicationAuthor(attributes: TraitList, metadataAuthor?: string | null): string | null {\n return traitText(attributes, \"Author\") ?? metadataAuthor ?? traitText(attributes, \"Creator\");\n}\n\nconst VARIANT_KINDS: Partial<Record<string, AssetKind>> = { edition: \"edition\", ticket: \"ticket\", club: \"membership\", pop: \"pop\" };\n\nexport function detectAssetKind(service: string | null | undefined, standard: string | null | undefined): AssetKind {\n const variant = getService(service)?.uiVariant;\n if (variant) return VARIANT_KINDS[variant] ?? \"standard\";\n return standard === \"ERC1155\" ? \"edition\" : \"standard\";\n}\n\nexport function AssetPageSkeleton() {\n return (\n <PageContainer className=\"pt-20 pb-8\">\n <div className=\"grid grid-cols-1 lg:grid-cols-2 lg:gap-10 gap-6 items-start\">\n <Skeleton className=\"aspect-square w-full rounded-3xl\" />\n <div className=\"space-y-6\">\n <div className=\"space-y-3\">\n <Skeleton className=\"h-5 w-24 rounded-full\" />\n <Skeleton className=\"h-9 w-3/4\" />\n <Skeleton className=\"h-4 w-full\" />\n <Skeleton className=\"h-4 w-2/3\" />\n </div>\n <Skeleton className=\"h-[54px] w-full rounded-2xl\" />\n <div className=\"flex gap-2\">\n {Array.from({ length: 3 }).map((_, i) => <Skeleton key={i} className=\"h-[46px] flex-1 rounded-[13px]\" />)}\n </div>\n <Skeleton className=\"h-16 w-full rounded-2xl\" />\n </div>\n </div>\n </PageContainer>\n );\n}\n\nexport interface AssetPageProps {\n contract: string;\n tokenId: string;\n useMarketActions: (context: AssetMarketContext) => AssetMarketActions;\n}\n\nexport function AssetPage({ contract, tokenId, useMarketActions }: AssetPageProps) {\n const { token, isLoading, isIndexing } = useToken(contract, tokenId);\n const { collection, isLoading: collectionLoading } = useCollection(contract);\n if (isLoading || collectionLoading) return <AssetPageSkeleton />;\n if (!token) return <AssetUnavailable isIndexing={isIndexing} />;\n const kind = detectAssetKind(collection?.service, collection?.standard ?? token.standard);\n return <AssetPageView contract={contract} tokenId={tokenId} token={token} collection={collection ?? null} kind={kind} useMarketActions={useMarketActions} />;\n}\n\nfunction AssetPageView({\n contract,\n tokenId,\n token,\n collection,\n kind,\n useMarketActions,\n}: {\n contract: string;\n tokenId: string;\n token: ApiToken & { isHidden?: boolean };\n collection: ApiCollection | null;\n kind: AssetKind;\n useMarketActions: AssetPageProps[\"useMarketActions\"];\n}) {\n const resolveImage = useImageUrl();\n const config = KINDS[kind];\n const router = useRouter();\n const shouldReduce = useReducedMotion();\n const { walletAddress } = useMedialaneApp();\n\n const { listings, mutate: mutateListings, isLoading: listingsLoading } = useTokenListings(contract, tokenId);\n const { history } = useTokenHistory(contract, tokenId);\n const { tokens: collectionTokens } = useNearbyCollectionTokens(contract, tokenId);\n const { total: commentTotal } = useComments(contract, tokenId);\n const { total: remixCount } = useTokenRemixes(contract, tokenId);\n const { data: fullTokenData } = useFullTokenData(contract, tokenId);\n const { amount: walletBalance } = useTokenBalance(contract, tokenId, walletAddress);\n const market = useAssetMarketState({ token, collection, listings, history: history as ApiActivity[], walletAddress, walletBalance });\n\n const [reportOpen, setReportOpen] = useState(false);\n const [commentOpen, setCommentOpen] = useState(false);\n const [imgError, setImgError] = useState(false);\n\n const name = token.metadata?.name || `${config.namePrefix} #${token.tokenId}`;\n const image = resolveImage(token.metadata?.image);\n const tokenStandard = kind === \"standard\" || kind === \"pop\"\n ? ((token.standard ?? collection?.standard ?? \"UNKNOWN\") as AssetMarketContext[\"tokenStandard\"])\n : \"ERC1155\";\n\n const actions = useMarketActions({\n contract,\n tokenId,\n tokenName: name,\n tokenImage: image,\n tokenStandard,\n activeListings: market.activeListings,\n quantityOwned: market.quantityOwned,\n mutateListings,\n });\n\n const autoActionRef = useRef(false);\n useEffect(() => {\n if (autoActionRef.current || !config.market || !market.isOwner) return;\n const action = new URLSearchParams(window.location.search).get(\"action\");\n if (action === \"list\") actions.list();\n else if (action === \"transfer\") actions.transfer();\n else return;\n autoActionRef.current = true;\n }, [config.market, market.isOwner, actions]);\n\n const { attributes, hasTemplateData, isDisplayAttr, parentContract, parentTokenId } = assetAttributes(token.metadata?.attributes);\n const remixPolicy = resolveRemixPolicy({\n parentNoDerivatives: getDerivativesTerm(token.metadata?.attributes) === \"Not Allowed\",\n viewerIsParentOwner: market.isOwner,\n dealAvailable: !!getService(collection?.service),\n });\n const holders = token.balances ?? [];\n const ownerAddress = !market.isERC1155 ? (holders[0]?.owner ?? token.owner ?? null) : null;\n const marketCount = market.activeListings.length + market.activeBids.length;\n const { Panel } = config;\n\n const postContent = traitText(attributes, \"Content\");\n const description = token.metadata?.description?.trim() || null;\n const video = (token.metadata?.ipType ?? \"\").toLowerCase() === \"video\" ? videoEmbed(attributes) : null;\n const audio = (token.metadata?.ipType ?? \"\").toLowerCase() === \"audio\" ? audioEmbed(attributes) : null;\n const isPublication = !!description && PUBLICATION_TYPES.has((token.metadata?.ipType ?? \"\").toLowerCase());\n const publisherName = collection?.name ?? contract.slice(0, 8) + \"…\";\n const overviewAttributes = postContent ? attributes.filter((a) => a.trait_type !== \"Content\") : attributes;\n const overview = video || audio\n ? assetAttributes(overviewAttributes.filter((a) => !VIDEO_EMBED_TRAITS.has(a.trait_type ?? \"\") && !AUDIO_EMBED_TRAITS.has(a.trait_type ?? \"\")))\n : { attributes: overviewAttributes, hasTemplateData, isDisplayAttr };\n const overviewLink = isPublication || video || audio ? null : externalLink(token.metadata?.externalUrl);\n\n const marketBlock = (\n <>\n {Panel ? <Panel contract={contract} tokenId={tokenId} quantityOwned={market.quantityOwned} /> : null}\n\n {config.market ? (\n <AssetMarketplacePanel\n asset={token}\n compact={isPublication || !!video || !!audio}\n cheapest={market.cheapest}\n usdValue={market.cheapestUsd}\n isOwner={market.isOwner}\n isProcessing={actions.isProcessing}\n isERC1155={market.isERC1155}\n canListMoreEditions={market.canListMoreEditions}\n isMarketLoading={listingsLoading}\n myListing={market.myListing}\n activeBids={market.activeBids}\n remixEnabled={config.remix && remixPolicy.canRemixDirect}\n showDealOption={config.remix && remixPolicy.showDealOption}\n onCancelClick={actions.cancel}\n onAcceptBid={actions.acceptBid}\n onOpenListing={actions.list}\n onOpenTransfer={actions.transfer}\n onOpenPurchase={actions.buy}\n onOpenOffer={actions.offer}\n onOpenRemix={() => router.push(`/create/remix/${contract}/${tokenId}`)}\n />\n ) : null}\n\n {kind === \"pop\" && market.isOwner ? <PopBurnButton collectionAddress={contract} tokenId={tokenId} /> : null}\n\n {market.isERC1155 && holders.length > 0 ? (\n <AssetOwnersPanel balances={holders} total={token.holderCount} editions={Number(token.supply ?? 0)} />\n ) : null}\n </>\n );\n\n const detailsBlock = (\n <div className=\"pt-5 space-y-5\">\n <AssetOwnerRow ownerAddress={ownerAddress} ownerHref={ownerAddress ? profileHref({ address: ownerAddress }) : undefined} ipType={token.metadata?.ipType} />\n {collection?.service === \"drop-collection\" ? <DropTokenLink contract={contract} name={collection.name ?? null} /> : null}\n {kind === \"pop\" ? (\n <SoulboundCard history={history as ApiActivity[]} ownerAddress={ownerAddress} />\n ) : null}\n <AssetCollectionBar\n collectionName={publisherName}\n collectionImage={resolveImage(collection?.image)}\n collectionHref={collectionHref(\"STARKNET\", contract)}\n currentTokenId={tokenId}\n siblingTokens={collectionTokens.map((t) => ({\n tokenId: t.tokenId,\n image: resolveImage(t.metadata?.image),\n }))}\n onNavigate={(id) => router.push(assetHref(\"STARKNET\", contract, id))}\n floorPriceRaw={collection?.floorPrice}\n />\n <div className=\"-ml-3\">\n <AssetUtilityIcons\n contractExplorerHref={`${EXPLORER_URL}/contract/${token.contractAddress}`}\n shareTitle={name}\n onReportClick={() => setReportOpen(true)}\n />\n </div>\n </div>\n );\n\n return (\n <div className=\"relative z-0 min-h-screen\">\n {token.isHidden ? <HiddenContentBanner /> : null}\n <PageBackdrop image={image} />\n\n <PageContainer className={isPublication ? \"pt-20 space-y-8 pb-8 lg:px-16 xl:px-24\" : \"pt-20 space-y-8 pb-8\"}>\n {video ? (\n <div className=\"grid grid-cols-1 lg:grid-cols-[minmax(0,2fr)_minmax(0,1fr)] lg:gap-12 gap-8 items-start\">\n <AssetVideo\n name={name}\n embedSrc={video.src}\n embedLabel={video.label}\n description={token.metadata?.description}\n collectionName={publisherName}\n collectionImage={resolveImage(collection?.image)}\n collectionHref={collectionHref(\"STARKNET\", contract)}\n utilities={\n <AssetUtilityIcons\n contractExplorerHref={`${EXPLORER_URL}/contract/${token.contractAddress}`}\n shareTitle={name}\n onReportClick={() => setReportOpen(true)}\n />\n }\n />\n <aside className=\"space-y-6 min-w-0\">\n {marketBlock}\n <AssetOwnerRow ownerAddress={ownerAddress} ownerHref={ownerAddress ? profileHref({ address: ownerAddress }) : undefined} ipType={token.metadata?.ipType ?? \"Video\"} />\n <AssetRelatedList\n title={publisherName}\n titleHref={collectionHref(\"STARKNET\", contract)}\n items={collectionTokens\n .filter((t) => String(t.tokenId) !== String(tokenId))\n .map((t) => ({\n tokenId: t.tokenId,\n name: t.metadata?.name || `${config.namePrefix} #${t.tokenId}`,\n image: resolveImage(t.metadata?.image),\n href: assetHref(\"STARKNET\", contract, t.tokenId),\n }))}\n />\n </aside>\n </div>\n ) : audio ? (\n <div className=\"grid grid-cols-1 lg:grid-cols-[minmax(0,2fr)_minmax(0,1fr)] lg:gap-12 gap-8 items-start\">\n <AssetAudio\n name={name}\n image={image}\n embedSrc={audio.src}\n embedLabel={audio.label}\n description={token.metadata?.description}\n collectionName={publisherName}\n collectionImage={resolveImage(collection?.image)}\n collectionHref={collectionHref(\"STARKNET\", contract)}\n utilities={\n <AssetUtilityIcons\n contractExplorerHref={`${EXPLORER_URL}/contract/${token.contractAddress}`}\n shareTitle={name}\n onReportClick={() => setReportOpen(true)}\n />\n }\n />\n <aside className=\"space-y-6 min-w-0\">\n {marketBlock}\n <AssetOwnerRow ownerAddress={ownerAddress} ownerHref={ownerAddress ? profileHref({ address: ownerAddress }) : undefined} ipType={token.metadata?.ipType ?? \"Audio\"} />\n <AssetRelatedList\n title={publisherName}\n titleHref={collectionHref(\"STARKNET\", contract)}\n shape=\"square\"\n items={collectionTokens\n .filter((t) => String(t.tokenId) !== String(tokenId))\n .map((t) => ({\n tokenId: t.tokenId,\n name: t.metadata?.name || `${config.namePrefix} #${t.tokenId}`,\n image: resolveImage(t.metadata?.image),\n href: assetHref(\"STARKNET\", contract, t.tokenId),\n }))}\n />\n </aside>\n </div>\n ) : isPublication ? (\n <div className=\"grid grid-cols-1 lg:grid-cols-[minmax(0,2fr)_minmax(0,1fr)] lg:gap-20 gap-8 items-start\">\n <AssetPublication\n name={name}\n text={description!}\n image={image}\n imgError={imgError}\n onImageError={() => setImgError(true)}\n author={publicationAuthor(attributes, token.metadata?.author)}\n externalUrl={token.metadata?.externalUrl}\n />\n <aside className=\"space-y-6 min-w-0 lg:sticky lg:top-16\">\n {marketBlock}\n {detailsBlock}\n </aside>\n </div>\n ) : (\n <div className=\"grid grid-cols-1 lg:grid-cols-2 lg:gap-10 gap-8 items-start\">\n <AssetMediaColumn\n shouldReduce={Boolean(shouldReduce)}\n image={image}\n imageAlt={name}\n imgError={imgError}\n onImageError={() => setImgError(true)}\n animationUrl={token.metadata?.animationUrl}\n live={isLivingRenderCollection(token.chain as Chain, token.contractAddress)}\n fallback={<div className=\"aspect-square bg-muted\" />}\n />\n\n <motion.div\n initial={shouldReduce ? false : { opacity: 0, y: 16 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ duration: 0.5, delay: 0.2 }}\n className=\"space-y-6\"\n >\n <AssetHeaderBlock\n name={name}\n description={token.metadata?.description}\n parentContract={parentContract}\n parentTokenId={parentTokenId}\n badges={kind === \"pop\" ? (\n <span className=\"inline-flex items-center gap-1 text-2xs font-semibold px-2.5 py-1 rounded-full bg-brand-purple/15 text-brand-purple dark:bg-brand-purple/25\">\n <Award className=\"h-3 w-3\" />\n POP\n </span>\n ) : null}\n />\n\n {marketBlock}\n\n {detailsBlock}\n </motion.div>\n </div>\n )}\n\n <Tabs defaultValue=\"overview\">\n <TabsList>\n <TabsTrigger value=\"overview\">Overview</TabsTrigger>\n {config.market ? <TabsTrigger value=\"markets\">Markets {marketCount > 0 && `(${marketCount})`}</TabsTrigger> : null}\n <TabsTrigger value=\"provenance\">Provenance {history.length > 0 && `(${history.length})`}</TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"overview\">\n <AssetOverviewContent attributes={overview.attributes} hasTemplateData={overview.hasTemplateData} isDisplayAttr={overview.isDisplayAttr} content={postContent} link={overviewLink} />\n </TabsContent>\n\n {config.market ? (\n <TabsContent value=\"markets\">\n <AssetMarketsTab\n activeListings={market.activeListings}\n activeBids={market.activeBids}\n walletAddress={walletAddress ?? undefined}\n isOwner={market.isOwner}\n isProcessing={actions.isProcessing}\n onBuyClick={actions.buy}\n onCancelClick={actions.cancel}\n onAcceptClick={actions.acceptBid}\n />\n </TabsContent>\n ) : null}\n\n <TabsContent value=\"provenance\">\n <AssetProvenanceTab\n history={history as ApiActivity[]}\n contract={contract}\n tokenId={tokenId}\n remixCount={remixCount}\n originalCreator={fullTokenData?.originalCreator}\n registeredAt={fullTokenData?.registeredAt}\n />\n </TabsContent>\n </Tabs>\n </PageContainer>\n\n <FloatingCommentsButton onClick={() => setCommentOpen(true)} commentTotal={commentTotal} />\n <AssetCommentsDialog\n open={commentOpen}\n onOpenChange={setCommentOpen}\n contract={contract}\n tokenId={tokenId}\n name={name}\n imageUrl={image}\n commentTotal={commentTotal}\n {...config.accents}\n />\n <ReportDialog open={reportOpen} onOpenChange={setReportOpen} target={{ type: \"TOKEN\", contract: token.contractAddress, tokenId: token.tokenId, name }} />\n {actions.dialogs}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -108,16 +108,12 @@ function AssetHeaderBlock({
|
|
|
108
108
|
badges,
|
|
109
109
|
utilities,
|
|
110
110
|
description,
|
|
111
|
-
ipType,
|
|
112
111
|
parentContract,
|
|
113
112
|
parentTokenId
|
|
114
113
|
}) {
|
|
115
114
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "min-w-0 flex-1", children: [
|
|
116
|
-
|
|
117
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
118
|
-
ipType ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ip_type_badge.IpTypeBadge, { ipType, size: "md", showLabel: true }) : null,
|
|
119
|
-
badges
|
|
120
|
-
] }),
|
|
115
|
+
badges || utilities ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between gap-2 mb-2", children: [
|
|
116
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex items-center gap-2 flex-wrap", children: badges }),
|
|
121
117
|
utilities
|
|
122
118
|
] }) : null,
|
|
123
119
|
parentContract && parentTokenId ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mb-3", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -132,10 +128,14 @@ function AssetHeaderBlock({
|
|
|
132
128
|
description ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_expandable_text.ExpandableText, { text: description, className: "mt-1" }) : null
|
|
133
129
|
] });
|
|
134
130
|
}
|
|
135
|
-
function AssetOwnerRow({ ownerAddress, ownerHref }) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
131
|
+
function AssetOwnerRow({ ownerAddress, ownerHref, ipType }) {
|
|
132
|
+
if (!ownerAddress && !ipType) return null;
|
|
133
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1.5 text-xs text-muted-foreground", children: [
|
|
134
|
+
ipType ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ip_type_badge.IpTypeBadge, { ipType, size: "md", showLabel: true }) : null,
|
|
135
|
+
ownerAddress && ownerHref ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
136
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "Owner" }),
|
|
137
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_link.default, { href: ownerHref, className: "hover:text-primary transition-colors font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_address_display.AddressDisplay, { address: ownerAddress }) })
|
|
138
|
+
] }) : null
|
|
139
139
|
] });
|
|
140
140
|
}
|
|
141
141
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/asset-top-sections.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport { useEffect, useState } from \"react\";\nimport { motion } from \"framer-motion\";\nimport { useIntersectionActive } from \"../utils/use-intersection-active.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { AddressDisplay } from \"./address-display.js\";\nimport { ParentAttributionBanner } from \"./parent-attribution-banner.js\";\nimport { IpTypeBadge } from \"./ip-type-badge.js\";\nimport { ExpandableText } from \"./expandable-text.js\";\n\ninterface AssetMediaColumnProps {\n shouldReduce: boolean;\n image: string | null;\n imageAlt: string;\n imgError: boolean;\n onImageError: () => void;\n fallback: React.ReactNode;\n\n\n animationUrl?: string | null;\n\n live?: boolean;\n}\n\nexport function AssetMediaColumn({\n shouldReduce,\n image,\n imageAlt,\n imgError,\n onImageError,\n fallback,\n animationUrl,\n live = false,\n}: AssetMediaColumnProps) {\n const [ref, isVisible] = useIntersectionActive<HTMLDivElement>();\n const [loaded, setLoaded] = useState(false);\n useEffect(() => setLoaded(false), [image]);\n const showLive = live && !!animationUrl && isVisible;\n\n const shimmer = !loaded && (\n <div\n className=\"absolute inset-0 min-h-80 animate-[shimmer_1.6s_ease-in-out_infinite] bg-foreground/[0.06]\"\n style={{\n backgroundImage:\n \"linear-gradient(90deg, transparent, color-mix(in srgb, var(--foreground) 8%, transparent), transparent)\",\n backgroundSize: \"200% 100%\",\n }}\n />\n );\n\n return (\n <div ref={ref} className=\"w-full lg:sticky lg:top-16\">\n {showLive ? (\n <div className=\"w-full overflow-hidden rounded-3xl aspect-square\">\n <iframe\n src={animationUrl!}\n title={imageAlt}\n sandbox=\"allow-scripts\"\n loading=\"lazy\"\n className=\"w-full h-full border-0\"\n />\n </div>\n ) : !image || imgError ? (\n <div className=\"w-full overflow-hidden rounded-3xl\">{fallback}</div>\n ) : (\n <motion.div\n initial={shouldReduce ? false : { opacity: 0, scale: 0.98 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={{ duration: 0.5 }}\n className=\"relative block w-full overflow-hidden rounded-3xl\"\n >\n {shimmer}\n <img\n src={image}\n alt={imageAlt}\n onLoad={() => setLoaded(true)}\n onError={onImageError}\n className={cn(\n \"w-full h-auto max-h-[80vh] object-contain transition-opacity duration-300\",\n loaded ? \"opacity-100\" : \"opacity-0\"\n )}\n />\n </motion.div>\n )}\n\n </div>\n );\n}\n\ninterface AssetHeaderBlockProps {\n name: string;\n badges?: React.ReactNode;\n utilities?: React.ReactNode;\n description?: string | null;\n
|
|
1
|
+
{"version":3,"sources":["../../src/components/asset-top-sections.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport { useEffect, useState } from \"react\";\nimport { motion } from \"framer-motion\";\nimport { useIntersectionActive } from \"../utils/use-intersection-active.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { AddressDisplay } from \"./address-display.js\";\nimport { ParentAttributionBanner } from \"./parent-attribution-banner.js\";\nimport { IpTypeBadge } from \"./ip-type-badge.js\";\nimport { ExpandableText } from \"./expandable-text.js\";\n\ninterface AssetMediaColumnProps {\n shouldReduce: boolean;\n image: string | null;\n imageAlt: string;\n imgError: boolean;\n onImageError: () => void;\n fallback: React.ReactNode;\n\n\n animationUrl?: string | null;\n\n live?: boolean;\n}\n\nexport function AssetMediaColumn({\n shouldReduce,\n image,\n imageAlt,\n imgError,\n onImageError,\n fallback,\n animationUrl,\n live = false,\n}: AssetMediaColumnProps) {\n const [ref, isVisible] = useIntersectionActive<HTMLDivElement>();\n const [loaded, setLoaded] = useState(false);\n useEffect(() => setLoaded(false), [image]);\n const showLive = live && !!animationUrl && isVisible;\n\n const shimmer = !loaded && (\n <div\n className=\"absolute inset-0 min-h-80 animate-[shimmer_1.6s_ease-in-out_infinite] bg-foreground/[0.06]\"\n style={{\n backgroundImage:\n \"linear-gradient(90deg, transparent, color-mix(in srgb, var(--foreground) 8%, transparent), transparent)\",\n backgroundSize: \"200% 100%\",\n }}\n />\n );\n\n return (\n <div ref={ref} className=\"w-full lg:sticky lg:top-16\">\n {showLive ? (\n <div className=\"w-full overflow-hidden rounded-3xl aspect-square\">\n <iframe\n src={animationUrl!}\n title={imageAlt}\n sandbox=\"allow-scripts\"\n loading=\"lazy\"\n className=\"w-full h-full border-0\"\n />\n </div>\n ) : !image || imgError ? (\n <div className=\"w-full overflow-hidden rounded-3xl\">{fallback}</div>\n ) : (\n <motion.div\n initial={shouldReduce ? false : { opacity: 0, scale: 0.98 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={{ duration: 0.5 }}\n className=\"relative block w-full overflow-hidden rounded-3xl\"\n >\n {shimmer}\n <img\n src={image}\n alt={imageAlt}\n onLoad={() => setLoaded(true)}\n onError={onImageError}\n className={cn(\n \"w-full h-auto max-h-[80vh] object-contain transition-opacity duration-300\",\n loaded ? \"opacity-100\" : \"opacity-0\"\n )}\n />\n </motion.div>\n )}\n\n </div>\n );\n}\n\ninterface AssetHeaderBlockProps {\n name: string;\n badges?: React.ReactNode;\n utilities?: React.ReactNode;\n description?: string | null;\n parentContract?: string | null;\n parentTokenId?: string | null;\n}\n\nexport function AssetHeaderBlock({\n name,\n badges,\n utilities,\n description,\n parentContract,\n parentTokenId,\n}: AssetHeaderBlockProps) {\n return (\n <div className=\"min-w-0 flex-1\">\n {badges || utilities ? (\n <div className=\"flex items-center justify-between gap-2 mb-2\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n {badges}\n </div>\n {utilities}\n </div>\n ) : null}\n {parentContract && parentTokenId ? (\n <div className=\"mb-3\">\n <ParentAttributionBanner\n parentContract={parentContract}\n parentTokenId={parentTokenId}\n parentName={`Token #${parentTokenId}`}\n />\n </div>\n ) : null}\n <h1 className=\"text-2xl lg:text-4xl font-bold break-words\">{name}</h1>\n {description ? <ExpandableText text={description} className=\"mt-1\" /> : null}\n </div>\n );\n}\n\nexport interface AssetOwnerRowProps {\n ownerAddress?: string | null;\n ownerHref?: string;\n ipType?: string | null;\n}\n\nexport function AssetOwnerRow({ ownerAddress, ownerHref, ipType }: AssetOwnerRowProps) {\n if (!ownerAddress && !ipType) return null;\n return (\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-1.5 text-xs text-muted-foreground\">\n {ipType ? <IpTypeBadge ipType={ipType} size=\"md\" showLabel /> : null}\n {ownerAddress && ownerHref ? (\n <div className=\"flex items-center gap-1.5\">\n <span>Owner</span>\n <Link href={ownerHref} className=\"hover:text-primary transition-colors font-medium\">\n <AddressDisplay address={ownerAddress} />\n </Link>\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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","names":["Link"]}
|
|
@@ -16,15 +16,15 @@ interface AssetHeaderBlockProps {
|
|
|
16
16
|
badges?: React.ReactNode;
|
|
17
17
|
utilities?: React.ReactNode;
|
|
18
18
|
description?: string | null;
|
|
19
|
-
ipType?: string | null;
|
|
20
19
|
parentContract?: string | null;
|
|
21
20
|
parentTokenId?: string | null;
|
|
22
21
|
}
|
|
23
|
-
declare function AssetHeaderBlock({ name, badges, utilities, description,
|
|
22
|
+
declare function AssetHeaderBlock({ name, badges, utilities, description, parentContract, parentTokenId, }: AssetHeaderBlockProps): react_jsx_runtime.JSX.Element;
|
|
24
23
|
interface AssetOwnerRowProps {
|
|
25
|
-
ownerAddress
|
|
26
|
-
ownerHref
|
|
24
|
+
ownerAddress?: string | null;
|
|
25
|
+
ownerHref?: string;
|
|
26
|
+
ipType?: string | null;
|
|
27
27
|
}
|
|
28
|
-
declare function AssetOwnerRow({ ownerAddress, ownerHref }: AssetOwnerRowProps): react_jsx_runtime.JSX.Element;
|
|
28
|
+
declare function AssetOwnerRow({ ownerAddress, ownerHref, ipType }: AssetOwnerRowProps): react_jsx_runtime.JSX.Element | null;
|
|
29
29
|
|
|
30
30
|
export { AssetHeaderBlock, AssetMediaColumn, AssetOwnerRow, type AssetOwnerRowProps };
|
|
@@ -16,15 +16,15 @@ interface AssetHeaderBlockProps {
|
|
|
16
16
|
badges?: React.ReactNode;
|
|
17
17
|
utilities?: React.ReactNode;
|
|
18
18
|
description?: string | null;
|
|
19
|
-
ipType?: string | null;
|
|
20
19
|
parentContract?: string | null;
|
|
21
20
|
parentTokenId?: string | null;
|
|
22
21
|
}
|
|
23
|
-
declare function AssetHeaderBlock({ name, badges, utilities, description,
|
|
22
|
+
declare function AssetHeaderBlock({ name, badges, utilities, description, parentContract, parentTokenId, }: AssetHeaderBlockProps): react_jsx_runtime.JSX.Element;
|
|
24
23
|
interface AssetOwnerRowProps {
|
|
25
|
-
ownerAddress
|
|
26
|
-
ownerHref
|
|
24
|
+
ownerAddress?: string | null;
|
|
25
|
+
ownerHref?: string;
|
|
26
|
+
ipType?: string | null;
|
|
27
27
|
}
|
|
28
|
-
declare function AssetOwnerRow({ ownerAddress, ownerHref }: AssetOwnerRowProps): react_jsx_runtime.JSX.Element;
|
|
28
|
+
declare function AssetOwnerRow({ ownerAddress, ownerHref, ipType }: AssetOwnerRowProps): react_jsx_runtime.JSX.Element | null;
|
|
29
29
|
|
|
30
30
|
export { AssetHeaderBlock, AssetMediaColumn, AssetOwnerRow, type AssetOwnerRowProps };
|
|
@@ -73,16 +73,12 @@ function AssetHeaderBlock({
|
|
|
73
73
|
badges,
|
|
74
74
|
utilities,
|
|
75
75
|
description,
|
|
76
|
-
ipType,
|
|
77
76
|
parentContract,
|
|
78
77
|
parentTokenId
|
|
79
78
|
}) {
|
|
80
79
|
return /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
81
|
-
|
|
82
|
-
/* @__PURE__ */
|
|
83
|
-
ipType ? /* @__PURE__ */ jsx(IpTypeBadge, { ipType, size: "md", showLabel: true }) : null,
|
|
84
|
-
badges
|
|
85
|
-
] }),
|
|
80
|
+
badges || utilities ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 mb-2", children: [
|
|
81
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 flex-wrap", children: badges }),
|
|
86
82
|
utilities
|
|
87
83
|
] }) : null,
|
|
88
84
|
parentContract && parentTokenId ? /* @__PURE__ */ jsx("div", { className: "mb-3", children: /* @__PURE__ */ jsx(
|
|
@@ -97,10 +93,14 @@ function AssetHeaderBlock({
|
|
|
97
93
|
description ? /* @__PURE__ */ jsx(ExpandableText, { text: description, className: "mt-1" }) : null
|
|
98
94
|
] });
|
|
99
95
|
}
|
|
100
|
-
function AssetOwnerRow({ ownerAddress, ownerHref }) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
/* @__PURE__ */ jsx(
|
|
96
|
+
function AssetOwnerRow({ ownerAddress, ownerHref, ipType }) {
|
|
97
|
+
if (!ownerAddress && !ipType) return null;
|
|
98
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1.5 text-xs text-muted-foreground", children: [
|
|
99
|
+
ipType ? /* @__PURE__ */ jsx(IpTypeBadge, { ipType, size: "md", showLabel: true }) : null,
|
|
100
|
+
ownerAddress && ownerHref ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
101
|
+
/* @__PURE__ */ jsx("span", { children: "Owner" }),
|
|
102
|
+
/* @__PURE__ */ jsx(Link, { href: ownerHref, className: "hover:text-primary transition-colors font-medium", children: /* @__PURE__ */ jsx(AddressDisplay, { address: ownerAddress }) })
|
|
103
|
+
] }) : null
|
|
104
104
|
] });
|
|
105
105
|
}
|
|
106
106
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/asset-top-sections.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport { useEffect, useState } from \"react\";\nimport { motion } from \"framer-motion\";\nimport { useIntersectionActive } from \"../utils/use-intersection-active.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { AddressDisplay } from \"./address-display.js\";\nimport { ParentAttributionBanner } from \"./parent-attribution-banner.js\";\nimport { IpTypeBadge } from \"./ip-type-badge.js\";\nimport { ExpandableText } from \"./expandable-text.js\";\n\ninterface AssetMediaColumnProps {\n shouldReduce: boolean;\n image: string | null;\n imageAlt: string;\n imgError: boolean;\n onImageError: () => void;\n fallback: React.ReactNode;\n\n\n animationUrl?: string | null;\n\n live?: boolean;\n}\n\nexport function AssetMediaColumn({\n shouldReduce,\n image,\n imageAlt,\n imgError,\n onImageError,\n fallback,\n animationUrl,\n live = false,\n}: AssetMediaColumnProps) {\n const [ref, isVisible] = useIntersectionActive<HTMLDivElement>();\n const [loaded, setLoaded] = useState(false);\n useEffect(() => setLoaded(false), [image]);\n const showLive = live && !!animationUrl && isVisible;\n\n const shimmer = !loaded && (\n <div\n className=\"absolute inset-0 min-h-80 animate-[shimmer_1.6s_ease-in-out_infinite] bg-foreground/[0.06]\"\n style={{\n backgroundImage:\n \"linear-gradient(90deg, transparent, color-mix(in srgb, var(--foreground) 8%, transparent), transparent)\",\n backgroundSize: \"200% 100%\",\n }}\n />\n );\n\n return (\n <div ref={ref} className=\"w-full lg:sticky lg:top-16\">\n {showLive ? (\n <div className=\"w-full overflow-hidden rounded-3xl aspect-square\">\n <iframe\n src={animationUrl!}\n title={imageAlt}\n sandbox=\"allow-scripts\"\n loading=\"lazy\"\n className=\"w-full h-full border-0\"\n />\n </div>\n ) : !image || imgError ? (\n <div className=\"w-full overflow-hidden rounded-3xl\">{fallback}</div>\n ) : (\n <motion.div\n initial={shouldReduce ? false : { opacity: 0, scale: 0.98 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={{ duration: 0.5 }}\n className=\"relative block w-full overflow-hidden rounded-3xl\"\n >\n {shimmer}\n <img\n src={image}\n alt={imageAlt}\n onLoad={() => setLoaded(true)}\n onError={onImageError}\n className={cn(\n \"w-full h-auto max-h-[80vh] object-contain transition-opacity duration-300\",\n loaded ? \"opacity-100\" : \"opacity-0\"\n )}\n />\n </motion.div>\n )}\n\n </div>\n );\n}\n\ninterface AssetHeaderBlockProps {\n name: string;\n badges?: React.ReactNode;\n utilities?: React.ReactNode;\n description?: string | null;\n
|
|
1
|
+
{"version":3,"sources":["../../src/components/asset-top-sections.tsx"],"sourcesContent":["\"use client\";\n\nimport Link from \"./link.js\";\nimport { useEffect, useState } from \"react\";\nimport { motion } from \"framer-motion\";\nimport { useIntersectionActive } from \"../utils/use-intersection-active.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { AddressDisplay } from \"./address-display.js\";\nimport { ParentAttributionBanner } from \"./parent-attribution-banner.js\";\nimport { IpTypeBadge } from \"./ip-type-badge.js\";\nimport { ExpandableText } from \"./expandable-text.js\";\n\ninterface AssetMediaColumnProps {\n shouldReduce: boolean;\n image: string | null;\n imageAlt: string;\n imgError: boolean;\n onImageError: () => void;\n fallback: React.ReactNode;\n\n\n animationUrl?: string | null;\n\n live?: boolean;\n}\n\nexport function AssetMediaColumn({\n shouldReduce,\n image,\n imageAlt,\n imgError,\n onImageError,\n fallback,\n animationUrl,\n live = false,\n}: AssetMediaColumnProps) {\n const [ref, isVisible] = useIntersectionActive<HTMLDivElement>();\n const [loaded, setLoaded] = useState(false);\n useEffect(() => setLoaded(false), [image]);\n const showLive = live && !!animationUrl && isVisible;\n\n const shimmer = !loaded && (\n <div\n className=\"absolute inset-0 min-h-80 animate-[shimmer_1.6s_ease-in-out_infinite] bg-foreground/[0.06]\"\n style={{\n backgroundImage:\n \"linear-gradient(90deg, transparent, color-mix(in srgb, var(--foreground) 8%, transparent), transparent)\",\n backgroundSize: \"200% 100%\",\n }}\n />\n );\n\n return (\n <div ref={ref} className=\"w-full lg:sticky lg:top-16\">\n {showLive ? (\n <div className=\"w-full overflow-hidden rounded-3xl aspect-square\">\n <iframe\n src={animationUrl!}\n title={imageAlt}\n sandbox=\"allow-scripts\"\n loading=\"lazy\"\n className=\"w-full h-full border-0\"\n />\n </div>\n ) : !image || imgError ? (\n <div className=\"w-full overflow-hidden rounded-3xl\">{fallback}</div>\n ) : (\n <motion.div\n initial={shouldReduce ? false : { opacity: 0, scale: 0.98 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={{ duration: 0.5 }}\n className=\"relative block w-full overflow-hidden rounded-3xl\"\n >\n {shimmer}\n <img\n src={image}\n alt={imageAlt}\n onLoad={() => setLoaded(true)}\n onError={onImageError}\n className={cn(\n \"w-full h-auto max-h-[80vh] object-contain transition-opacity duration-300\",\n loaded ? \"opacity-100\" : \"opacity-0\"\n )}\n />\n </motion.div>\n )}\n\n </div>\n );\n}\n\ninterface AssetHeaderBlockProps {\n name: string;\n badges?: React.ReactNode;\n utilities?: React.ReactNode;\n description?: string | null;\n parentContract?: string | null;\n parentTokenId?: string | null;\n}\n\nexport function AssetHeaderBlock({\n name,\n badges,\n utilities,\n description,\n parentContract,\n parentTokenId,\n}: AssetHeaderBlockProps) {\n return (\n <div className=\"min-w-0 flex-1\">\n {badges || utilities ? (\n <div className=\"flex items-center justify-between gap-2 mb-2\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n {badges}\n </div>\n {utilities}\n </div>\n ) : null}\n {parentContract && parentTokenId ? (\n <div className=\"mb-3\">\n <ParentAttributionBanner\n parentContract={parentContract}\n parentTokenId={parentTokenId}\n parentName={`Token #${parentTokenId}`}\n />\n </div>\n ) : null}\n <h1 className=\"text-2xl lg:text-4xl font-bold break-words\">{name}</h1>\n {description ? <ExpandableText text={description} className=\"mt-1\" /> : null}\n </div>\n );\n}\n\nexport interface AssetOwnerRowProps {\n ownerAddress?: string | null;\n ownerHref?: string;\n ipType?: string | null;\n}\n\nexport function AssetOwnerRow({ ownerAddress, ownerHref, ipType }: AssetOwnerRowProps) {\n if (!ownerAddress && !ipType) return null;\n return (\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-1.5 text-xs text-muted-foreground\">\n {ipType ? <IpTypeBadge ipType={ipType} size=\"md\" showLabel /> : null}\n {ownerAddress && ownerHref ? (\n <div className=\"flex items-center gap-1.5\">\n <span>Owner</span>\n <Link href={ownerHref} className=\"hover:text-primary transition-colors font-medium\">\n <AddressDisplay address={ownerAddress} />\n </Link>\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":";AA0CI,cAyBI,YAzBJ;AAxCJ,OAAO,UAAU;AACjB,SAAS,WAAW,gBAAgB;AACpC,SAAS,cAAc;AACvB,SAAS,6BAA6B;AACtC,SAAS,UAAU;AACnB,SAAS,sBAAsB;AAC/B,SAAS,+BAA+B;AACxC,SAAS,mBAAmB;AAC5B,SAAS,sBAAsB;AAgBxB,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AACT,GAA0B;AACxB,QAAM,CAAC,KAAK,SAAS,IAAI,sBAAsC;AAC/D,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,YAAU,MAAM,UAAU,KAAK,GAAG,CAAC,KAAK,CAAC;AACzC,QAAM,WAAW,QAAQ,CAAC,CAAC,gBAAgB;AAE3C,QAAM,UAAU,CAAC,UACf;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,OAAO;AAAA,QACL,iBACE;AAAA,QACF,gBAAgB;AAAA,MAClB;AAAA;AAAA,EACF;AAGF,SACE,oBAAC,SAAI,KAAU,WAAU,8BACtB,qBACC,oBAAC,SAAI,WAAU,oDACb;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,OAAO;AAAA,MACP,SAAQ;AAAA,MACR,SAAQ;AAAA,MACR,WAAU;AAAA;AAAA,EACZ,GACF,IACE,CAAC,SAAS,WACZ,oBAAC,SAAI,WAAU,sCAAsC,oBAAS,IAE9D;AAAA,IAAC,OAAO;AAAA,IAAP;AAAA,MACC,SAAS,eAAe,QAAQ,EAAE,SAAS,GAAG,OAAO,KAAK;AAAA,MAC1D,SAAS,EAAE,SAAS,GAAG,OAAO,EAAE;AAAA,MAChC,YAAY,EAAE,UAAU,IAAI;AAAA,MAC5B,WAAU;AAAA,MAET;AAAA;AAAA,QACD;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,KAAK;AAAA,YACL,QAAQ,MAAM,UAAU,IAAI;AAAA,YAC5B,SAAS;AAAA,YACT,WAAW;AAAA,cACT;AAAA,cACA,SAAS,gBAAgB;AAAA,YAC3B;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF,GAGJ;AAEJ;AAWO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0B;AACxB,SACE,qBAAC,SAAI,WAAU,kBACZ;AAAA,cAAU,YACT,qBAAC,SAAI,WAAU,gDACb;AAAA,0BAAC,SAAI,WAAU,qCACZ,kBACH;AAAA,MACC;AAAA,OACH,IACE;AAAA,IACH,kBAAkB,gBACjB,oBAAC,SAAI,WAAU,QACb;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA,YAAY,UAAU,aAAa;AAAA;AAAA,IACrC,GACF,IACE;AAAA,IACJ,oBAAC,QAAG,WAAU,8CAA8C,gBAAK;AAAA,IAChE,cAAc,oBAAC,kBAAe,MAAM,aAAa,WAAU,QAAO,IAAK;AAAA,KAC1E;AAEJ;AAQO,SAAS,cAAc,EAAE,cAAc,WAAW,OAAO,GAAuB;AACrF,MAAI,CAAC,gBAAgB,CAAC,OAAQ,QAAO;AACrC,SACE,qBAAC,SAAI,WAAU,+EACZ;AAAA,aAAS,oBAAC,eAAY,QAAgB,MAAK,MAAK,WAAS,MAAC,IAAK;AAAA,IAC/D,gBAAgB,YACf,qBAAC,SAAI,WAAU,6BACb;AAAA,0BAAC,UAAK,mBAAK;AAAA,MACX,oBAAC,QAAK,MAAM,WAAW,WAAU,oDAC/B,8BAAC,kBAAe,SAAS,cAAc,GACzC;AAAA,OACF,IACE;AAAA,KACN;AAEJ;","names":[]}
|
|
@@ -4,7 +4,7 @@ import * as React from 'react';
|
|
|
4
4
|
import { VariantProps } from 'class-variance-authority';
|
|
5
5
|
|
|
6
6
|
declare const badgeVariants: (props?: ({
|
|
7
|
-
variant?: "default" | "
|
|
7
|
+
variant?: "default" | "secondary" | "outline" | "destructive" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {
|
|
10
10
|
}
|
|
@@ -4,7 +4,7 @@ import * as React from 'react';
|
|
|
4
4
|
import { VariantProps } from 'class-variance-authority';
|
|
5
5
|
|
|
6
6
|
declare const badgeVariants: (props?: ({
|
|
7
|
-
variant?: "default" | "
|
|
7
|
+
variant?: "default" | "secondary" | "outline" | "destructive" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {
|
|
10
10
|
}
|
|
@@ -3,7 +3,7 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const buttonVariants: (props?: ({
|
|
6
|
-
variant?: "
|
|
6
|
+
variant?: "link" | "default" | "secondary" | "outline" | "destructive" | "ghost" | "premium" | "tonal" | "gradient-border" | "gradient-fill" | null | undefined;
|
|
7
7
|
size?: "default" | "icon" | "sm" | "lg" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
@@ -3,7 +3,7 @@ import * as React from 'react';
|
|
|
3
3
|
import { VariantProps } from 'class-variance-authority';
|
|
4
4
|
|
|
5
5
|
declare const buttonVariants: (props?: ({
|
|
6
|
-
variant?: "
|
|
6
|
+
variant?: "link" | "default" | "secondary" | "outline" | "destructive" | "ghost" | "premium" | "tonal" | "gradient-border" | "gradient-fill" | null | undefined;
|
|
7
7
|
size?: "default" | "icon" | "sm" | "lg" | null | undefined;
|
|
8
8
|
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
9
9
|
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
@@ -118,14 +118,15 @@ function CollectionFiltersTrigger({
|
|
|
118
118
|
"button",
|
|
119
119
|
{
|
|
120
120
|
onClick: () => onRemoveFilter(traitType, value),
|
|
121
|
-
|
|
121
|
+
title: `${traitType}: ${value}`,
|
|
122
|
+
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",
|
|
122
123
|
children: [
|
|
123
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "text-muted-foreground text-2xs", children: [
|
|
124
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "text-muted-foreground text-2xs shrink-0", children: [
|
|
124
125
|
traitType,
|
|
125
126
|
":"
|
|
126
127
|
] }),
|
|
127
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: value }),
|
|
128
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.X, { className: "h-3 w-3 text-muted-foreground ml-0.5" })
|
|
128
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate", children: value }),
|
|
129
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.X, { className: "h-3 w-3 text-muted-foreground ml-0.5 shrink-0" })
|
|
129
130
|
]
|
|
130
131
|
},
|
|
131
132
|
`${traitType}:${value}`
|
|
@@ -141,7 +142,7 @@ function CollectionFiltersTrigger({
|
|
|
141
142
|
] })
|
|
142
143
|
] });
|
|
143
144
|
}
|
|
144
|
-
const PILL_BASE = "inline-flex items-center gap-1 h-7 px-2.5 rounded-full border text-xs font-medium transition-colors";
|
|
145
|
+
const 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";
|
|
145
146
|
const PILL_ON = "border-primary bg-primary text-primary-foreground";
|
|
146
147
|
const PILL_OFF = "border-border bg-transparent text-muted-foreground hover:text-foreground hover:border-foreground/30";
|
|
147
148
|
function CollectionFiltersBody({
|
|
@@ -151,7 +152,7 @@ function CollectionFiltersBody({
|
|
|
151
152
|
selected,
|
|
152
153
|
onToggleValue
|
|
153
154
|
}) {
|
|
154
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex-1 overflow-y-auto px-5 py-3 space-y-4", children: [
|
|
155
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex-1 min-w-0 overflow-y-auto overflow-x-hidden px-5 py-3 space-y-4", children: [
|
|
155
156
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
156
157
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "mb-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-sm font-medium", children: "Sort by" }) }),
|
|
157
158
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-wrap gap-1.5", children: SORT_OPTIONS.map(({ value, label }) => {
|
|
@@ -176,9 +177,9 @@ function CollectionFiltersBody({
|
|
|
176
177
|
const activeValues = selected[section.traitType] ?? [];
|
|
177
178
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
178
179
|
i > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "h-px w-full bg-border mb-4" }),
|
|
179
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between mb-2", children: [
|
|
180
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-sm font-medium", children: section.traitType }),
|
|
181
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "text-2xs text-muted-foreground", children: [
|
|
180
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between gap-3 mb-2", children: [
|
|
181
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "min-w-0 truncate text-sm font-medium", title: section.traitType, children: section.traitType }),
|
|
182
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "shrink-0 text-2xs text-muted-foreground", children: [
|
|
182
183
|
section.values.length,
|
|
183
184
|
" values"
|
|
184
185
|
] })
|
|
@@ -189,11 +190,12 @@ function CollectionFiltersBody({
|
|
|
189
190
|
"button",
|
|
190
191
|
{
|
|
191
192
|
onClick: () => onToggleValue(section.traitType, value),
|
|
193
|
+
title: value,
|
|
192
194
|
className: (0, import_cn.cn)(PILL_BASE, isSelected ? PILL_ON : PILL_OFF),
|
|
193
195
|
children: [
|
|
194
|
-
isSelected && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Check, { className: "h-3 w-3" }),
|
|
195
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: value }),
|
|
196
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: isSelected ? "opacity-80" : "opacity-60", children: count })
|
|
196
|
+
isSelected && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Check, { className: "h-3 w-3 shrink-0" }),
|
|
197
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "truncate", children: value }),
|
|
198
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: (0, import_cn.cn)("shrink-0", isSelected ? "opacity-80" : "opacity-60"), children: count })
|
|
197
199
|
]
|
|
198
200
|
},
|
|
199
201
|
value
|
|
@@ -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 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\">{traitType}:</span>\n <span>{value}</span>\n <X className=\"h-3 w-3 text-muted-foreground ml-0.5\" />\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 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 overflow-y-auto 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 mb-2\">\n <span className=\"text-sm font-medium\">{section.traitType}</span>\n <span className=\"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 className={cn(PILL_BASE, isSelected ? PILL_ON : PILL_OFF)}\n >\n {isSelected && <Check className=\"h-3 w-3\" />}\n <span>{value}</span>\n <span className={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 <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":[]}
|
|
@@ -92,14 +92,15 @@ function CollectionFiltersTrigger({
|
|
|
92
92
|
"button",
|
|
93
93
|
{
|
|
94
94
|
onClick: () => onRemoveFilter(traitType, value),
|
|
95
|
-
|
|
95
|
+
title: `${traitType}: ${value}`,
|
|
96
|
+
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",
|
|
96
97
|
children: [
|
|
97
|
-
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-2xs", children: [
|
|
98
|
+
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground text-2xs shrink-0", children: [
|
|
98
99
|
traitType,
|
|
99
100
|
":"
|
|
100
101
|
] }),
|
|
101
|
-
/* @__PURE__ */ jsx("span", { children: value }),
|
|
102
|
-
/* @__PURE__ */ jsx(X, { className: "h-3 w-3 text-muted-foreground ml-0.5" })
|
|
102
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: value }),
|
|
103
|
+
/* @__PURE__ */ jsx(X, { className: "h-3 w-3 text-muted-foreground ml-0.5 shrink-0" })
|
|
103
104
|
]
|
|
104
105
|
},
|
|
105
106
|
`${traitType}:${value}`
|
|
@@ -115,7 +116,7 @@ function CollectionFiltersTrigger({
|
|
|
115
116
|
] })
|
|
116
117
|
] });
|
|
117
118
|
}
|
|
118
|
-
const PILL_BASE = "inline-flex items-center gap-1 h-7 px-2.5 rounded-full border text-xs font-medium transition-colors";
|
|
119
|
+
const 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";
|
|
119
120
|
const PILL_ON = "border-primary bg-primary text-primary-foreground";
|
|
120
121
|
const PILL_OFF = "border-border bg-transparent text-muted-foreground hover:text-foreground hover:border-foreground/30";
|
|
121
122
|
function CollectionFiltersBody({
|
|
@@ -125,7 +126,7 @@ function CollectionFiltersBody({
|
|
|
125
126
|
selected,
|
|
126
127
|
onToggleValue
|
|
127
128
|
}) {
|
|
128
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto px-5 py-3 space-y-4", children: [
|
|
129
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0 overflow-y-auto overflow-x-hidden px-5 py-3 space-y-4", children: [
|
|
129
130
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
130
131
|
/* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "Sort by" }) }),
|
|
131
132
|
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: SORT_OPTIONS.map(({ value, label }) => {
|
|
@@ -150,9 +151,9 @@ function CollectionFiltersBody({
|
|
|
150
151
|
const activeValues = selected[section.traitType] ?? [];
|
|
151
152
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
152
153
|
i > 0 && /* @__PURE__ */ jsx("div", { className: "h-px w-full bg-border mb-4" }),
|
|
153
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
154
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: section.traitType }),
|
|
155
|
-
/* @__PURE__ */ jsxs("span", { className: "text-2xs text-muted-foreground", children: [
|
|
154
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 mb-2", children: [
|
|
155
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate text-sm font-medium", title: section.traitType, children: section.traitType }),
|
|
156
|
+
/* @__PURE__ */ jsxs("span", { className: "shrink-0 text-2xs text-muted-foreground", children: [
|
|
156
157
|
section.values.length,
|
|
157
158
|
" values"
|
|
158
159
|
] })
|
|
@@ -163,11 +164,12 @@ function CollectionFiltersBody({
|
|
|
163
164
|
"button",
|
|
164
165
|
{
|
|
165
166
|
onClick: () => onToggleValue(section.traitType, value),
|
|
167
|
+
title: value,
|
|
166
168
|
className: cn(PILL_BASE, isSelected ? PILL_ON : PILL_OFF),
|
|
167
169
|
children: [
|
|
168
|
-
isSelected && /* @__PURE__ */ jsx(Check, { className: "h-3 w-3" }),
|
|
169
|
-
/* @__PURE__ */ jsx("span", { children: value }),
|
|
170
|
-
/* @__PURE__ */ jsx("span", { className: isSelected ? "opacity-80" : "opacity-60", children: count })
|
|
170
|
+
isSelected && /* @__PURE__ */ jsx(Check, { className: "h-3 w-3 shrink-0" }),
|
|
171
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: value }),
|
|
172
|
+
/* @__PURE__ */ jsx("span", { className: cn("shrink-0", isSelected ? "opacity-80" : "opacity-60"), children: count })
|
|
171
173
|
]
|
|
172
174
|
},
|
|
173
175
|
value
|
|
@@ -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 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\">{traitType}:</span>\n <span>{value}</span>\n <X className=\"h-3 w-3 text-muted-foreground ml-0.5\" />\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 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 overflow-y-auto 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 mb-2\">\n <span className=\"text-sm font-medium\">{section.traitType}</span>\n <span className=\"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 className={cn(PILL_BASE, isSelected ? PILL_ON : PILL_OFF)}\n >\n {isSelected && <Check className=\"h-3 w-3\" />}\n <span>{value}</span>\n <span className={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 <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":";AAsHQ,SAWA,UAVE,KADF;AApHR,SAAS,eAAe;AACxB,SAAS,mBAAmB,GAAG,aAAa;AAC5C,SAAS,UAAU;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,gBAAgC,QAAQ,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,qBAAC,SAAI,WAAU,iDACZ;AAAA,kBACC,qBAAC,YAAO,SAAS,QAAQ,WAAW,aAAa,cAAW,WAC1D;AAAA,0BAAC,qBAAkB,WAAU,eAAc;AAAA,MAC3C,oBAAC,UAAK,WAAU,oBAAmB,qBAAO;AAAA,MACzC,mBAAmB,KAClB,oBAAC,UAAK,WAAU,8HACb,4BACH;AAAA,OAEJ;AAAA,IAED,aACC,iCAED;AAAA,OAAC,iBACA;AAAA,QAAC;AAAA;AAAA,UACC,SAAS;AAAA,UACT,WAAU;AAAA,UAEV;AAAA,gCAAC,UAAK,WAAU,kCAAiC,mBAAK;AAAA,YACtD,oBAAC,UAAM,uBAAa,KAAK,CAAC,MAAM,EAAE,UAAU,IAAI,GAAG,OAAM;AAAA,YACzD,oBAAC,KAAE,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,iCAAC,UAAK,WAAU,2CAA2C;AAAA;AAAA,cAAU;AAAA,eAAC;AAAA,YACtE,oBAAC,UAAK,WAAU,YAAY,iBAAM;AAAA,YAClC,oBAAC,KAAE,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,qBAAC,SAAI,WAAU,wEAEb;AAAA,yBAAC,SACC;AAAA,0BAAC,SAAI,WAAU,QACb,8BAAC,UAAK,WAAU,uBAAsB,qBAAO,GAC/C;AAAA,MACA,oBAAC,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,WAAW,GAAG,WAAW,aAAa,UAAU,QAAQ;AAAA,YAEvD;AAAA,4BAAc,oBAAC,SAAM,WAAU,WAAU;AAAA,cAC1C,oBAAC,UAAM,iBAAM;AAAA;AAAA;AAAA,UALR;AAAA,QAMP;AAAA,MAEJ,CAAC,GACH;AAAA,OACF;AAAA,IAEC,cAAc,SAAS,KACtB,iCACE;AAAA,0BAAC,SAAI,WAAU,yBAAwB;AAAA,MACtC,cAAc,IAAI,CAAC,SAAS,MAAM;AACjC,cAAM,eAAe,SAAS,QAAQ,SAAS,KAAK,CAAC;AACrD,eACE,qBAAC,SACE;AAAA,cAAI,KAAK,oBAAC,SAAI,WAAU,8BAA6B;AAAA,UACtD,qBAAC,SAAI,WAAU,gDACb;AAAA,gCAAC,UAAK,WAAU,wCAAuC,OAAO,QAAQ,WAAY,kBAAQ,WAAU;AAAA,YACpG,qBAAC,UAAK,WAAU,2CACb;AAAA,sBAAQ,OAAO;AAAA,cAAO;AAAA,eACzB;AAAA,aACF;AAAA,UACA,oBAAC,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,WAAW,GAAG,WAAW,aAAa,UAAU,QAAQ;AAAA,gBAEvD;AAAA,gCAAc,oBAAC,SAAM,WAAU,oBAAmB;AAAA,kBACnD,oBAAC,UAAK,WAAU,YAAY,iBAAM;AAAA,kBAClC,oBAAC,UAAK,WAAW,GAAG,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":[]}
|
|
@@ -34,7 +34,7 @@ function ExpandableText({ text, className }) {
|
|
|
34
34
|
if (el) setOverflows(el.scrollHeight > el.clientHeight);
|
|
35
35
|
}, [text]);
|
|
36
36
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className, children: [
|
|
37
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { ref, className: (0, import_cn.cn)("text-
|
|
37
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { ref, className: (0, import_cn.cn)("text-base text-muted-foreground leading-relaxed", !expanded && "line-clamp-3"), children: text }),
|
|
38
38
|
overflows || expanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
39
39
|
"button",
|
|
40
40
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/expandable-text.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport function ExpandableText({ text, className }: { text: string; className?: string }) {\n const ref = useRef<HTMLParagraphElement>(null);\n const [expanded, setExpanded] = useState(false);\n const [overflows, setOverflows] = useState(false);\n\n useEffect(() => {\n const el = ref.current;\n if (el) setOverflows(el.scrollHeight > el.clientHeight);\n }, [text]);\n\n return (\n <div className={className}>\n <p ref={ref} className={cn(\"text-
|
|
1
|
+
{"version":3,"sources":["../../src/components/expandable-text.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport function ExpandableText({ text, className }: { text: string; className?: string }) {\n const ref = useRef<HTMLParagraphElement>(null);\n const [expanded, setExpanded] = useState(false);\n const [overflows, setOverflows] = useState(false);\n\n useEffect(() => {\n const el = ref.current;\n if (el) setOverflows(el.scrollHeight > el.clientHeight);\n }, [text]);\n\n return (\n <div className={className}>\n <p ref={ref} className={cn(\"text-base text-muted-foreground leading-relaxed\", !expanded && \"line-clamp-3\")}>\n {text}\n </p>\n {overflows || expanded ? (\n <button\n type=\"button\"\n onClick={() => setExpanded((e) => !e)}\n className=\"mt-1 text-xs text-muted-foreground hover:text-foreground underline-offset-2 hover:underline\"\n >\n {expanded ? \"Show less\" : \"Show more\"}\n </button>\n ) : null}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBI;AAdJ,mBAA4C;AAC5C,gBAAmB;AAEZ,SAAS,eAAe,EAAE,MAAM,UAAU,GAAyC;AACxF,QAAM,UAAM,qBAA6B,IAAI;AAC7C,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAS,KAAK;AAC9C,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAS,KAAK;AAEhD,8BAAU,MAAM;AACd,UAAM,KAAK,IAAI;AACf,QAAI,GAAI,cAAa,GAAG,eAAe,GAAG,YAAY;AAAA,EACxD,GAAG,CAAC,IAAI,CAAC;AAET,SACE,6CAAC,SAAI,WACH;AAAA,gDAAC,OAAE,KAAU,eAAW,cAAG,mDAAmD,CAAC,YAAY,cAAc,GACtG,gBACH;AAAA,IACC,aAAa,WACZ;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;AAAA,QACpC,WAAU;AAAA,QAET,qBAAW,cAAc;AAAA;AAAA,IAC5B,IACE;AAAA,KACN;AAEJ;","names":[]}
|
|
@@ -11,7 +11,7 @@ function ExpandableText({ text, className }) {
|
|
|
11
11
|
if (el) setOverflows(el.scrollHeight > el.clientHeight);
|
|
12
12
|
}, [text]);
|
|
13
13
|
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
14
|
-
/* @__PURE__ */ jsx("p", { ref, className: cn("text-
|
|
14
|
+
/* @__PURE__ */ jsx("p", { ref, className: cn("text-base text-muted-foreground leading-relaxed", !expanded && "line-clamp-3"), children: text }),
|
|
15
15
|
overflows || expanded ? /* @__PURE__ */ jsx(
|
|
16
16
|
"button",
|
|
17
17
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/expandable-text.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport function ExpandableText({ text, className }: { text: string; className?: string }) {\n const ref = useRef<HTMLParagraphElement>(null);\n const [expanded, setExpanded] = useState(false);\n const [overflows, setOverflows] = useState(false);\n\n useEffect(() => {\n const el = ref.current;\n if (el) setOverflows(el.scrollHeight > el.clientHeight);\n }, [text]);\n\n return (\n <div className={className}>\n <p ref={ref} className={cn(\"text-
|
|
1
|
+
{"version":3,"sources":["../../src/components/expandable-text.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport function ExpandableText({ text, className }: { text: string; className?: string }) {\n const ref = useRef<HTMLParagraphElement>(null);\n const [expanded, setExpanded] = useState(false);\n const [overflows, setOverflows] = useState(false);\n\n useEffect(() => {\n const el = ref.current;\n if (el) setOverflows(el.scrollHeight > el.clientHeight);\n }, [text]);\n\n return (\n <div className={className}>\n <p ref={ref} className={cn(\"text-base text-muted-foreground leading-relaxed\", !expanded && \"line-clamp-3\")}>\n {text}\n </p>\n {overflows || expanded ? (\n <button\n type=\"button\"\n onClick={() => setExpanded((e) => !e)}\n className=\"mt-1 text-xs text-muted-foreground hover:text-foreground underline-offset-2 hover:underline\"\n >\n {expanded ? \"Show less\" : \"Show more\"}\n </button>\n ) : null}\n </div>\n );\n}\n"],"mappings":";AAgBI,SACE,KADF;AAdJ,SAAS,WAAW,QAAQ,gBAAgB;AAC5C,SAAS,UAAU;AAEZ,SAAS,eAAe,EAAE,MAAM,UAAU,GAAyC;AACxF,QAAM,MAAM,OAA6B,IAAI;AAC7C,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAEhD,YAAU,MAAM;AACd,UAAM,KAAK,IAAI;AACf,QAAI,GAAI,cAAa,GAAG,eAAe,GAAG,YAAY;AAAA,EACxD,GAAG,CAAC,IAAI,CAAC;AAET,SACE,qBAAC,SAAI,WACH;AAAA,wBAAC,OAAE,KAAU,WAAW,GAAG,mDAAmD,CAAC,YAAY,cAAc,GACtG,gBACH;AAAA,IACC,aAAa,WACZ;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;AAAA,QACpC,WAAU;AAAA,QAET,qBAAW,cAAc;AAAA;AAAA,IAC5B,IACE;AAAA,KACN;AAEJ;","names":[]}
|
|
@@ -16,6 +16,7 @@ declare const editionMintSchema: z.ZodObject<{
|
|
|
16
16
|
royalty: z.ZodNumber;
|
|
17
17
|
}, "strip", z.ZodTypeAny, {
|
|
18
18
|
name: string;
|
|
19
|
+
value: string;
|
|
19
20
|
ipType: "Audio" | "Video" | "Art" | "Photography" | "NFT" | "Software" | "RWA" | "Patents" | "Posts" | "Publications" | "Documents" | "Custom";
|
|
20
21
|
licenseType: string;
|
|
21
22
|
commercialUse: "Yes" | "No";
|
|
@@ -24,12 +25,12 @@ declare const editionMintSchema: z.ZodObject<{
|
|
|
24
25
|
geographicScope: string;
|
|
25
26
|
aiPolicy: "Allowed" | "Not Allowed" | "Training Only";
|
|
26
27
|
royalty: number;
|
|
27
|
-
value: string;
|
|
28
28
|
recipient: string;
|
|
29
29
|
description?: string | undefined;
|
|
30
30
|
external_url?: string | undefined;
|
|
31
31
|
}, {
|
|
32
32
|
name: string;
|
|
33
|
+
value: string;
|
|
33
34
|
ipType: "Audio" | "Video" | "Art" | "Photography" | "NFT" | "Software" | "RWA" | "Patents" | "Posts" | "Publications" | "Documents" | "Custom";
|
|
34
35
|
licenseType: string;
|
|
35
36
|
commercialUse: "Yes" | "No";
|
|
@@ -38,7 +39,6 @@ declare const editionMintSchema: z.ZodObject<{
|
|
|
38
39
|
geographicScope: string;
|
|
39
40
|
aiPolicy: "Allowed" | "Not Allowed" | "Training Only";
|
|
40
41
|
royalty: number;
|
|
41
|
-
value: string;
|
|
42
42
|
recipient: string;
|
|
43
43
|
description?: string | undefined;
|
|
44
44
|
external_url?: string | undefined;
|
|
@@ -16,6 +16,7 @@ declare const editionMintSchema: z.ZodObject<{
|
|
|
16
16
|
royalty: z.ZodNumber;
|
|
17
17
|
}, "strip", z.ZodTypeAny, {
|
|
18
18
|
name: string;
|
|
19
|
+
value: string;
|
|
19
20
|
ipType: "Audio" | "Video" | "Art" | "Photography" | "NFT" | "Software" | "RWA" | "Patents" | "Posts" | "Publications" | "Documents" | "Custom";
|
|
20
21
|
licenseType: string;
|
|
21
22
|
commercialUse: "Yes" | "No";
|
|
@@ -24,12 +25,12 @@ declare const editionMintSchema: z.ZodObject<{
|
|
|
24
25
|
geographicScope: string;
|
|
25
26
|
aiPolicy: "Allowed" | "Not Allowed" | "Training Only";
|
|
26
27
|
royalty: number;
|
|
27
|
-
value: string;
|
|
28
28
|
recipient: string;
|
|
29
29
|
description?: string | undefined;
|
|
30
30
|
external_url?: string | undefined;
|
|
31
31
|
}, {
|
|
32
32
|
name: string;
|
|
33
|
+
value: string;
|
|
33
34
|
ipType: "Audio" | "Video" | "Art" | "Photography" | "NFT" | "Software" | "RWA" | "Patents" | "Posts" | "Publications" | "Documents" | "Custom";
|
|
34
35
|
licenseType: string;
|
|
35
36
|
commercialUse: "Yes" | "No";
|
|
@@ -38,7 +39,6 @@ declare const editionMintSchema: z.ZodObject<{
|
|
|
38
39
|
geographicScope: string;
|
|
39
40
|
aiPolicy: "Allowed" | "Not Allowed" | "Training Only";
|
|
40
41
|
royalty: number;
|
|
41
|
-
value: string;
|
|
42
42
|
recipient: string;
|
|
43
43
|
description?: string | undefined;
|
|
44
44
|
external_url?: string | undefined;
|