@medialane/ui 0.34.2 → 0.35.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/asset-collection-bar.cjs +3 -33
- package/dist/components/asset-collection-bar.cjs.map +1 -1
- package/dist/components/asset-collection-bar.d.cts +4 -7
- package/dist/components/asset-collection-bar.d.ts +4 -7
- package/dist/components/asset-collection-bar.js +4 -34
- package/dist/components/asset-collection-bar.js.map +1 -1
- package/dist/components/asset-utility-icons.cjs +62 -0
- package/dist/components/asset-utility-icons.cjs.map +1 -0
- package/dist/components/asset-utility-icons.d.cts +15 -0
- package/dist/components/asset-utility-icons.d.ts +15 -0
- package/dist/components/asset-utility-icons.js +38 -0
- package/dist/components/asset-utility-icons.js.map +1 -0
- package/dist/components/launchpad-filter-bar.cjs +88 -0
- package/dist/components/launchpad-filter-bar.cjs.map +1 -0
- package/dist/components/launchpad-filter-bar.d.cts +21 -0
- package/dist/components/launchpad-filter-bar.d.ts +21 -0
- package/dist/components/launchpad-filter-bar.js +64 -0
- package/dist/components/launchpad-filter-bar.js.map +1 -0
- package/dist/components/launchpad-services.cjs +103 -40
- package/dist/components/launchpad-services.cjs.map +1 -1
- package/dist/components/launchpad-services.d.cts +2 -1
- package/dist/components/launchpad-services.d.ts +2 -1
- package/dist/components/launchpad-services.js +104 -41
- package/dist/components/launchpad-services.js.map +1 -1
- package/dist/data/launchpad-services.cjs +18 -43
- package/dist/data/launchpad-services.cjs.map +1 -1
- package/dist/data/launchpad-services.d.cts +1 -1
- package/dist/data/launchpad-services.d.ts +1 -1
- package/dist/data/launchpad-services.js +18 -43
- package/dist/data/launchpad-services.js.map +1 -1
- package/dist/index.cjs +6 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -36,15 +36,11 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
36
36
|
var import_image = __toESM(require("next/image"), 1);
|
|
37
37
|
var import_link = __toESM(require("next/link"), 1);
|
|
38
38
|
var import_lucide_react = require("lucide-react");
|
|
39
|
-
var import_share_button = require("./share-button.js");
|
|
40
39
|
var import_cn = require("../utils/cn.js");
|
|
41
40
|
function AssetCollectionBar({
|
|
42
41
|
collectionName,
|
|
43
42
|
collectionImage,
|
|
44
43
|
collectionHref,
|
|
45
|
-
contractExplorerHref,
|
|
46
|
-
shareTitle,
|
|
47
|
-
onReportClick,
|
|
48
44
|
currentTokenId,
|
|
49
45
|
siblingTokens,
|
|
50
46
|
onNavigate
|
|
@@ -54,35 +50,9 @@ function AssetCollectionBar({
|
|
|
54
50
|
const nextToken = currentIndex >= 0 && currentIndex < siblingTokens.length - 1 ? siblingTokens[currentIndex + 1] : null;
|
|
55
51
|
const showFilmstrip = siblingTokens.length > 1;
|
|
56
52
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rounded-2xl bg-card/40 px-4 py-3 space-y-3", children: [
|
|
57
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
58
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
59
|
-
|
|
60
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm font-semibold truncate group-hover:text-primary transition-colors", children: collectionName })
|
|
61
|
-
] }),
|
|
62
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-1 shrink-0 text-muted-foreground", children: [
|
|
63
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
64
|
-
"a",
|
|
65
|
-
{
|
|
66
|
-
href: contractExplorerHref,
|
|
67
|
-
target: "_blank",
|
|
68
|
-
rel: "noopener noreferrer",
|
|
69
|
-
title: "View contract",
|
|
70
|
-
className: "inline-flex h-9 w-9 items-center justify-center rounded-lg hover:bg-muted/50 hover:text-foreground transition-colors",
|
|
71
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ExternalLink, { className: "h-4 w-4" })
|
|
72
|
-
}
|
|
73
|
-
),
|
|
74
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_share_button.ShareButton, { title: shareTitle, variant: "ghost", size: "icon" }),
|
|
75
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
76
|
-
"button",
|
|
77
|
-
{
|
|
78
|
-
type: "button",
|
|
79
|
-
title: "Report this asset",
|
|
80
|
-
onClick: onReportClick,
|
|
81
|
-
className: "inline-flex h-9 w-9 items-center justify-center rounded-lg hover:bg-muted/50 hover:text-foreground transition-colors",
|
|
82
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Flag, { className: "h-4 w-4" })
|
|
83
|
-
}
|
|
84
|
-
)
|
|
85
|
-
] })
|
|
53
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_link.default, { href: collectionHref, className: "flex items-center justify-center gap-3 min-w-0 group", children: [
|
|
54
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "relative h-10 w-10 rounded-xl overflow-hidden shrink-0 bg-gradient-to-br from-primary/20 to-purple-500/20 ring-1 ring-border/60 group-hover:ring-primary/40 transition", children: collectionImage ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_image.default, { src: collectionImage, alt: "", fill: true, className: "object-cover", unoptimized: true }) : null }),
|
|
55
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-sm font-semibold truncate group-hover:text-primary transition-colors", children: collectionName })
|
|
86
56
|
] }),
|
|
87
57
|
showFilmstrip ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
88
58
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/asset-collection-bar.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"next/image\";\nimport Link from \"next/link\";\nimport { ChevronLeft, ChevronRight
|
|
1
|
+
{"version":3,"sources":["../../src/components/asset-collection-bar.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"next/image\";\nimport Link from \"next/link\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface AssetCollectionBarSibling {\n tokenId: string;\n /** Already-resolved, ready-to-render src (e.g. via the caller's ipfsToHttp). `null` renders a placeholder. */\n image: string | null;\n}\n\nexport interface AssetCollectionBarProps {\n collectionName: string;\n /** Already-resolved, ready-to-render src (e.g. via the caller's ipfsToHttp). */\n collectionImage?: string | null;\n collectionHref: string;\n currentTokenId: string;\n siblingTokens: AssetCollectionBarSibling[];\n onNavigate: (tokenId: string) => void;\n}\n\n/**\n * Collection identity bar: centered avatar+name, with a filmstrip of\n * collection siblings on a second row for browsing (replaces plain-text\n * Prev/Next). Soft `bg-card/40` surface, no hard border — matches the\n * aurora-glow design language instead of an OpenSea-style boxed panel.\n * Asset-level concerns (IP-type, explorer/share/report) live elsewhere\n * (`AssetHeaderBlock`, `AssetUtilityIcons`) — this bar is collection-only.\n */\nexport function AssetCollectionBar({\n collectionName,\n collectionImage,\n collectionHref,\n currentTokenId,\n siblingTokens,\n onNavigate,\n}: AssetCollectionBarProps) {\n const currentIndex = siblingTokens.findIndex((t) => String(t.tokenId) === String(currentTokenId));\n const prevToken = currentIndex > 0 ? siblingTokens[currentIndex - 1] : null;\n const nextToken =\n currentIndex >= 0 && currentIndex < siblingTokens.length - 1 ? siblingTokens[currentIndex + 1] : null;\n const showFilmstrip = siblingTokens.length > 1;\n\n return (\n <div className=\"rounded-2xl bg-card/40 px-4 py-3 space-y-3\">\n <Link href={collectionHref} className=\"flex items-center justify-center gap-3 min-w-0 group\">\n <div className=\"relative h-10 w-10 rounded-xl overflow-hidden shrink-0 bg-gradient-to-br from-primary/20 to-purple-500/20 ring-1 ring-border/60 group-hover:ring-primary/40 transition\">\n {collectionImage ? (\n <Image src={collectionImage} alt=\"\" fill className=\"object-cover\" unoptimized />\n ) : null}\n </div>\n <p className=\"text-sm font-semibold truncate group-hover:text-primary transition-colors\">\n {collectionName}\n </p>\n </Link>\n\n {showFilmstrip ? (\n <div className=\"flex items-center gap-1.5\">\n <button\n type=\"button\"\n disabled={!prevToken}\n onClick={() => prevToken && onNavigate(prevToken.tokenId)}\n className=\"shrink-0 inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition hover:text-foreground active:scale-95 disabled:opacity-30 disabled:pointer-events-none\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n </button>\n <div className=\"flex items-center gap-2 overflow-x-auto scroll-smooth [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\">\n {siblingTokens.map((sibling) => {\n const isCurrent = String(sibling.tokenId) === String(currentTokenId);\n return (\n <button\n key={sibling.tokenId}\n type=\"button\"\n onClick={() => onNavigate(sibling.tokenId)}\n className={cn(\n \"relative h-11 w-11 shrink-0 rounded-lg overflow-hidden ring-2 transition\",\n isCurrent ? \"ring-primary\" : \"ring-transparent hover:ring-border\"\n )}\n >\n {sibling.image ? (\n <Image src={sibling.image} alt=\"\" fill className=\"object-cover\" unoptimized />\n ) : (\n <div className=\"h-full w-full bg-muted\" />\n )}\n </button>\n );\n })}\n </div>\n <button\n type=\"button\"\n disabled={!nextToken}\n onClick={() => nextToken && onNavigate(nextToken.tokenId)}\n className=\"shrink-0 inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition hover:text-foreground active:scale-95 disabled:opacity-30 disabled:pointer-events-none\"\n >\n <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+CM;AA7CN,mBAAkB;AAClB,kBAAiB;AACjB,0BAA0C;AAC1C,gBAAmB;AA0BZ,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,eAAe,cAAc,UAAU,CAAC,MAAM,OAAO,EAAE,OAAO,MAAM,OAAO,cAAc,CAAC;AAChG,QAAM,YAAY,eAAe,IAAI,cAAc,eAAe,CAAC,IAAI;AACvE,QAAM,YACJ,gBAAgB,KAAK,eAAe,cAAc,SAAS,IAAI,cAAc,eAAe,CAAC,IAAI;AACnG,QAAM,gBAAgB,cAAc,SAAS;AAE7C,SACE,6CAAC,SAAI,WAAU,8CACb;AAAA,iDAAC,YAAAA,SAAA,EAAK,MAAM,gBAAgB,WAAU,wDACpC;AAAA,kDAAC,SAAI,WAAU,0KACZ,4BACC,4CAAC,aAAAC,SAAA,EAAM,KAAK,iBAAiB,KAAI,IAAG,MAAI,MAAC,WAAU,gBAAe,aAAW,MAAC,IAC5E,MACN;AAAA,MACA,4CAAC,OAAE,WAAU,6EACV,0BACH;AAAA,OACF;AAAA,IAEC,gBACC,6CAAC,SAAI,WAAU,6BACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU,CAAC;AAAA,UACX,SAAS,MAAM,aAAa,WAAW,UAAU,OAAO;AAAA,UACxD,WAAU;AAAA,UAEV,sDAAC,mCAAY,WAAU,WAAU;AAAA;AAAA,MACnC;AAAA,MACA,4CAAC,SAAI,WAAU,8GACZ,wBAAc,IAAI,CAAC,YAAY;AAC9B,cAAM,YAAY,OAAO,QAAQ,OAAO,MAAM,OAAO,cAAc;AACnE,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,MAAK;AAAA,YACL,SAAS,MAAM,WAAW,QAAQ,OAAO;AAAA,YACzC,eAAW;AAAA,cACT;AAAA,cACA,YAAY,iBAAiB;AAAA,YAC/B;AAAA,YAEC,kBAAQ,QACP,4CAAC,aAAAA,SAAA,EAAM,KAAK,QAAQ,OAAO,KAAI,IAAG,MAAI,MAAC,WAAU,gBAAe,aAAW,MAAC,IAE5E,4CAAC,SAAI,WAAU,0BAAyB;AAAA;AAAA,UAXrC,QAAQ;AAAA,QAaf;AAAA,MAEJ,CAAC,GACH;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU,CAAC;AAAA,UACX,SAAS,MAAM,aAAa,WAAW,UAAU,OAAO;AAAA,UACxD,WAAU;AAAA,UAEV,sDAAC,oCAAa,WAAU,WAAU;AAAA;AAAA,MACpC;AAAA,OACF,IACE;AAAA,KACN;AAEJ;","names":["Link","Image"]}
|
|
@@ -10,21 +10,18 @@ interface AssetCollectionBarProps {
|
|
|
10
10
|
/** Already-resolved, ready-to-render src (e.g. via the caller's ipfsToHttp). */
|
|
11
11
|
collectionImage?: string | null;
|
|
12
12
|
collectionHref: string;
|
|
13
|
-
contractExplorerHref: string;
|
|
14
|
-
shareTitle: string;
|
|
15
|
-
onReportClick: () => void;
|
|
16
13
|
currentTokenId: string;
|
|
17
14
|
siblingTokens: AssetCollectionBarSibling[];
|
|
18
15
|
onNavigate: (tokenId: string) => void;
|
|
19
16
|
}
|
|
20
17
|
/**
|
|
21
|
-
*
|
|
22
|
-
* explorer/share/report utility icons on one row, with a filmstrip of
|
|
18
|
+
* Collection identity bar: centered avatar+name, with a filmstrip of
|
|
23
19
|
* collection siblings on a second row for browsing (replaces plain-text
|
|
24
20
|
* Prev/Next). Soft `bg-card/40` surface, no hard border — matches the
|
|
25
21
|
* aurora-glow design language instead of an OpenSea-style boxed panel.
|
|
26
|
-
*
|
|
22
|
+
* Asset-level concerns (IP-type, explorer/share/report) live elsewhere
|
|
23
|
+
* (`AssetHeaderBlock`, `AssetUtilityIcons`) — this bar is collection-only.
|
|
27
24
|
*/
|
|
28
|
-
declare function AssetCollectionBar({ collectionName, collectionImage, collectionHref,
|
|
25
|
+
declare function AssetCollectionBar({ collectionName, collectionImage, collectionHref, currentTokenId, siblingTokens, onNavigate, }: AssetCollectionBarProps): react_jsx_runtime.JSX.Element;
|
|
29
26
|
|
|
30
27
|
export { AssetCollectionBar, type AssetCollectionBarProps, type AssetCollectionBarSibling };
|
|
@@ -10,21 +10,18 @@ interface AssetCollectionBarProps {
|
|
|
10
10
|
/** Already-resolved, ready-to-render src (e.g. via the caller's ipfsToHttp). */
|
|
11
11
|
collectionImage?: string | null;
|
|
12
12
|
collectionHref: string;
|
|
13
|
-
contractExplorerHref: string;
|
|
14
|
-
shareTitle: string;
|
|
15
|
-
onReportClick: () => void;
|
|
16
13
|
currentTokenId: string;
|
|
17
14
|
siblingTokens: AssetCollectionBarSibling[];
|
|
18
15
|
onNavigate: (tokenId: string) => void;
|
|
19
16
|
}
|
|
20
17
|
/**
|
|
21
|
-
*
|
|
22
|
-
* explorer/share/report utility icons on one row, with a filmstrip of
|
|
18
|
+
* Collection identity bar: centered avatar+name, with a filmstrip of
|
|
23
19
|
* collection siblings on a second row for browsing (replaces plain-text
|
|
24
20
|
* Prev/Next). Soft `bg-card/40` surface, no hard border — matches the
|
|
25
21
|
* aurora-glow design language instead of an OpenSea-style boxed panel.
|
|
26
|
-
*
|
|
22
|
+
* Asset-level concerns (IP-type, explorer/share/report) live elsewhere
|
|
23
|
+
* (`AssetHeaderBlock`, `AssetUtilityIcons`) — this bar is collection-only.
|
|
27
24
|
*/
|
|
28
|
-
declare function AssetCollectionBar({ collectionName, collectionImage, collectionHref,
|
|
25
|
+
declare function AssetCollectionBar({ collectionName, collectionImage, collectionHref, currentTokenId, siblingTokens, onNavigate, }: AssetCollectionBarProps): react_jsx_runtime.JSX.Element;
|
|
29
26
|
|
|
30
27
|
export { AssetCollectionBar, type AssetCollectionBarProps, type AssetCollectionBarSibling };
|
|
@@ -2,16 +2,12 @@
|
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import Image from "next/image";
|
|
4
4
|
import Link from "next/link";
|
|
5
|
-
import { ChevronLeft, ChevronRight
|
|
6
|
-
import { ShareButton } from "./share-button.js";
|
|
5
|
+
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
7
6
|
import { cn } from "../utils/cn.js";
|
|
8
7
|
function AssetCollectionBar({
|
|
9
8
|
collectionName,
|
|
10
9
|
collectionImage,
|
|
11
10
|
collectionHref,
|
|
12
|
-
contractExplorerHref,
|
|
13
|
-
shareTitle,
|
|
14
|
-
onReportClick,
|
|
15
11
|
currentTokenId,
|
|
16
12
|
siblingTokens,
|
|
17
13
|
onNavigate
|
|
@@ -21,35 +17,9 @@ function AssetCollectionBar({
|
|
|
21
17
|
const nextToken = currentIndex >= 0 && currentIndex < siblingTokens.length - 1 ? siblingTokens[currentIndex + 1] : null;
|
|
22
18
|
const showFilmstrip = siblingTokens.length > 1;
|
|
23
19
|
return /* @__PURE__ */ jsxs("div", { className: "rounded-2xl bg-card/40 px-4 py-3 space-y-3", children: [
|
|
24
|
-
/* @__PURE__ */ jsxs(
|
|
25
|
-
/* @__PURE__ */
|
|
26
|
-
|
|
27
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold truncate group-hover:text-primary transition-colors", children: collectionName })
|
|
28
|
-
] }),
|
|
29
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 shrink-0 text-muted-foreground", children: [
|
|
30
|
-
/* @__PURE__ */ jsx(
|
|
31
|
-
"a",
|
|
32
|
-
{
|
|
33
|
-
href: contractExplorerHref,
|
|
34
|
-
target: "_blank",
|
|
35
|
-
rel: "noopener noreferrer",
|
|
36
|
-
title: "View contract",
|
|
37
|
-
className: "inline-flex h-9 w-9 items-center justify-center rounded-lg hover:bg-muted/50 hover:text-foreground transition-colors",
|
|
38
|
-
children: /* @__PURE__ */ jsx(ExternalLink, { className: "h-4 w-4" })
|
|
39
|
-
}
|
|
40
|
-
),
|
|
41
|
-
/* @__PURE__ */ jsx(ShareButton, { title: shareTitle, variant: "ghost", size: "icon" }),
|
|
42
|
-
/* @__PURE__ */ jsx(
|
|
43
|
-
"button",
|
|
44
|
-
{
|
|
45
|
-
type: "button",
|
|
46
|
-
title: "Report this asset",
|
|
47
|
-
onClick: onReportClick,
|
|
48
|
-
className: "inline-flex h-9 w-9 items-center justify-center rounded-lg hover:bg-muted/50 hover:text-foreground transition-colors",
|
|
49
|
-
children: /* @__PURE__ */ jsx(Flag, { className: "h-4 w-4" })
|
|
50
|
-
}
|
|
51
|
-
)
|
|
52
|
-
] })
|
|
20
|
+
/* @__PURE__ */ jsxs(Link, { href: collectionHref, className: "flex items-center justify-center gap-3 min-w-0 group", children: [
|
|
21
|
+
/* @__PURE__ */ jsx("div", { className: "relative h-10 w-10 rounded-xl overflow-hidden shrink-0 bg-gradient-to-br from-primary/20 to-purple-500/20 ring-1 ring-border/60 group-hover:ring-primary/40 transition", children: collectionImage ? /* @__PURE__ */ jsx(Image, { src: collectionImage, alt: "", fill: true, className: "object-cover", unoptimized: true }) : null }),
|
|
22
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold truncate group-hover:text-primary transition-colors", children: collectionName })
|
|
53
23
|
] }),
|
|
54
24
|
showFilmstrip ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
55
25
|
/* @__PURE__ */ jsx(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/asset-collection-bar.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"next/image\";\nimport Link from \"next/link\";\nimport { ChevronLeft, ChevronRight
|
|
1
|
+
{"version":3,"sources":["../../src/components/asset-collection-bar.tsx"],"sourcesContent":["\"use client\";\n\nimport Image from \"next/image\";\nimport Link from \"next/link\";\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\n\nexport interface AssetCollectionBarSibling {\n tokenId: string;\n /** Already-resolved, ready-to-render src (e.g. via the caller's ipfsToHttp). `null` renders a placeholder. */\n image: string | null;\n}\n\nexport interface AssetCollectionBarProps {\n collectionName: string;\n /** Already-resolved, ready-to-render src (e.g. via the caller's ipfsToHttp). */\n collectionImage?: string | null;\n collectionHref: string;\n currentTokenId: string;\n siblingTokens: AssetCollectionBarSibling[];\n onNavigate: (tokenId: string) => void;\n}\n\n/**\n * Collection identity bar: centered avatar+name, with a filmstrip of\n * collection siblings on a second row for browsing (replaces plain-text\n * Prev/Next). Soft `bg-card/40` surface, no hard border — matches the\n * aurora-glow design language instead of an OpenSea-style boxed panel.\n * Asset-level concerns (IP-type, explorer/share/report) live elsewhere\n * (`AssetHeaderBlock`, `AssetUtilityIcons`) — this bar is collection-only.\n */\nexport function AssetCollectionBar({\n collectionName,\n collectionImage,\n collectionHref,\n currentTokenId,\n siblingTokens,\n onNavigate,\n}: AssetCollectionBarProps) {\n const currentIndex = siblingTokens.findIndex((t) => String(t.tokenId) === String(currentTokenId));\n const prevToken = currentIndex > 0 ? siblingTokens[currentIndex - 1] : null;\n const nextToken =\n currentIndex >= 0 && currentIndex < siblingTokens.length - 1 ? siblingTokens[currentIndex + 1] : null;\n const showFilmstrip = siblingTokens.length > 1;\n\n return (\n <div className=\"rounded-2xl bg-card/40 px-4 py-3 space-y-3\">\n <Link href={collectionHref} className=\"flex items-center justify-center gap-3 min-w-0 group\">\n <div className=\"relative h-10 w-10 rounded-xl overflow-hidden shrink-0 bg-gradient-to-br from-primary/20 to-purple-500/20 ring-1 ring-border/60 group-hover:ring-primary/40 transition\">\n {collectionImage ? (\n <Image src={collectionImage} alt=\"\" fill className=\"object-cover\" unoptimized />\n ) : null}\n </div>\n <p className=\"text-sm font-semibold truncate group-hover:text-primary transition-colors\">\n {collectionName}\n </p>\n </Link>\n\n {showFilmstrip ? (\n <div className=\"flex items-center gap-1.5\">\n <button\n type=\"button\"\n disabled={!prevToken}\n onClick={() => prevToken && onNavigate(prevToken.tokenId)}\n className=\"shrink-0 inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition hover:text-foreground active:scale-95 disabled:opacity-30 disabled:pointer-events-none\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n </button>\n <div className=\"flex items-center gap-2 overflow-x-auto scroll-smooth [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\">\n {siblingTokens.map((sibling) => {\n const isCurrent = String(sibling.tokenId) === String(currentTokenId);\n return (\n <button\n key={sibling.tokenId}\n type=\"button\"\n onClick={() => onNavigate(sibling.tokenId)}\n className={cn(\n \"relative h-11 w-11 shrink-0 rounded-lg overflow-hidden ring-2 transition\",\n isCurrent ? \"ring-primary\" : \"ring-transparent hover:ring-border\"\n )}\n >\n {sibling.image ? (\n <Image src={sibling.image} alt=\"\" fill className=\"object-cover\" unoptimized />\n ) : (\n <div className=\"h-full w-full bg-muted\" />\n )}\n </button>\n );\n })}\n </div>\n <button\n type=\"button\"\n disabled={!nextToken}\n onClick={() => nextToken && onNavigate(nextToken.tokenId)}\n className=\"shrink-0 inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground transition hover:text-foreground active:scale-95 disabled:opacity-30 disabled:pointer-events-none\"\n >\n <ChevronRight className=\"h-4 w-4\" />\n </button>\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":";AA+CM,SAGM,KAHN;AA7CN,OAAO,WAAW;AAClB,OAAO,UAAU;AACjB,SAAS,aAAa,oBAAoB;AAC1C,SAAS,UAAU;AA0BZ,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,eAAe,cAAc,UAAU,CAAC,MAAM,OAAO,EAAE,OAAO,MAAM,OAAO,cAAc,CAAC;AAChG,QAAM,YAAY,eAAe,IAAI,cAAc,eAAe,CAAC,IAAI;AACvE,QAAM,YACJ,gBAAgB,KAAK,eAAe,cAAc,SAAS,IAAI,cAAc,eAAe,CAAC,IAAI;AACnG,QAAM,gBAAgB,cAAc,SAAS;AAE7C,SACE,qBAAC,SAAI,WAAU,8CACb;AAAA,yBAAC,QAAK,MAAM,gBAAgB,WAAU,wDACpC;AAAA,0BAAC,SAAI,WAAU,0KACZ,4BACC,oBAAC,SAAM,KAAK,iBAAiB,KAAI,IAAG,MAAI,MAAC,WAAU,gBAAe,aAAW,MAAC,IAC5E,MACN;AAAA,MACA,oBAAC,OAAE,WAAU,6EACV,0BACH;AAAA,OACF;AAAA,IAEC,gBACC,qBAAC,SAAI,WAAU,6BACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU,CAAC;AAAA,UACX,SAAS,MAAM,aAAa,WAAW,UAAU,OAAO;AAAA,UACxD,WAAU;AAAA,UAEV,8BAAC,eAAY,WAAU,WAAU;AAAA;AAAA,MACnC;AAAA,MACA,oBAAC,SAAI,WAAU,8GACZ,wBAAc,IAAI,CAAC,YAAY;AAC9B,cAAM,YAAY,OAAO,QAAQ,OAAO,MAAM,OAAO,cAAc;AACnE,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,MAAK;AAAA,YACL,SAAS,MAAM,WAAW,QAAQ,OAAO;AAAA,YACzC,WAAW;AAAA,cACT;AAAA,cACA,YAAY,iBAAiB;AAAA,YAC/B;AAAA,YAEC,kBAAQ,QACP,oBAAC,SAAM,KAAK,QAAQ,OAAO,KAAI,IAAG,MAAI,MAAC,WAAU,gBAAe,aAAW,MAAC,IAE5E,oBAAC,SAAI,WAAU,0BAAyB;AAAA;AAAA,UAXrC,QAAQ;AAAA,QAaf;AAAA,MAEJ,CAAC,GACH;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU,CAAC;AAAA,UACX,SAAS,MAAM,aAAa,WAAW,UAAU,OAAO;AAAA,UACxD,WAAU;AAAA,UAEV,8BAAC,gBAAa,WAAU,WAAU;AAAA;AAAA,MACpC;AAAA,OACF,IACE;AAAA,KACN;AAEJ;","names":[]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
var asset_utility_icons_exports = {};
|
|
21
|
+
__export(asset_utility_icons_exports, {
|
|
22
|
+
AssetUtilityIcons: () => AssetUtilityIcons
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(asset_utility_icons_exports);
|
|
25
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
26
|
+
var import_lucide_react = require("lucide-react");
|
|
27
|
+
var import_share_button = require("./share-button.js");
|
|
28
|
+
function AssetUtilityIcons({
|
|
29
|
+
contractExplorerHref,
|
|
30
|
+
shareTitle,
|
|
31
|
+
onReportClick
|
|
32
|
+
}) {
|
|
33
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-1 text-muted-foreground", children: [
|
|
34
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
35
|
+
"a",
|
|
36
|
+
{
|
|
37
|
+
href: contractExplorerHref,
|
|
38
|
+
target: "_blank",
|
|
39
|
+
rel: "noopener noreferrer",
|
|
40
|
+
title: "View contract",
|
|
41
|
+
className: "inline-flex h-9 w-9 items-center justify-center rounded-lg hover:bg-muted/50 hover:text-foreground transition-colors",
|
|
42
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ExternalLink, { className: "h-4 w-4" })
|
|
43
|
+
}
|
|
44
|
+
),
|
|
45
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_share_button.ShareButton, { title: shareTitle, variant: "ghost", size: "icon" }),
|
|
46
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
47
|
+
"button",
|
|
48
|
+
{
|
|
49
|
+
type: "button",
|
|
50
|
+
title: "Report this asset",
|
|
51
|
+
onClick: onReportClick,
|
|
52
|
+
className: "inline-flex h-9 w-9 items-center justify-center rounded-lg hover:bg-muted/50 hover:text-foreground transition-colors",
|
|
53
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Flag, { className: "h-4 w-4" })
|
|
54
|
+
}
|
|
55
|
+
)
|
|
56
|
+
] });
|
|
57
|
+
}
|
|
58
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
59
|
+
0 && (module.exports = {
|
|
60
|
+
AssetUtilityIcons
|
|
61
|
+
});
|
|
62
|
+
//# sourceMappingURL=asset-utility-icons.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/asset-utility-icons.tsx"],"sourcesContent":["\"use client\";\n\nimport { ExternalLink, Flag } from \"lucide-react\";\nimport { ShareButton } from \"./share-button.js\";\n\nexport interface AssetUtilityIconsProps {\n contractExplorerHref: string;\n shareTitle: string;\n onReportClick: () => void;\n}\n\n/**\n * Asset-level utility row: view-on-explorer / share / report. Lives next to\n * the asset's own identity (name/owner), not inside `AssetCollectionBar` —\n * these actions are about the asset, not the collection it belongs to.\n */\nexport function AssetUtilityIcons({\n contractExplorerHref,\n shareTitle,\n onReportClick,\n}: AssetUtilityIconsProps) {\n return (\n <div className=\"flex items-center gap-1 text-muted-foreground\">\n <a\n href={contractExplorerHref}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n title=\"View contract\"\n className=\"inline-flex h-9 w-9 items-center justify-center rounded-lg hover:bg-muted/50 hover:text-foreground transition-colors\"\n >\n <ExternalLink className=\"h-4 w-4\" />\n </a>\n <ShareButton title={shareTitle} variant=\"ghost\" size=\"icon\" />\n <button\n type=\"button\"\n title=\"Report this asset\"\n onClick={onReportClick}\n className=\"inline-flex h-9 w-9 items-center justify-center rounded-lg hover:bg-muted/50 hover:text-foreground transition-colors\"\n >\n <Flag className=\"h-4 w-4\" />\n </button>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBI;AApBJ,0BAAmC;AACnC,0BAA4B;AAarB,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AACF,GAA2B;AACzB,SACE,6CAAC,SAAI,WAAU,iDACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,QAAO;AAAA,QACP,KAAI;AAAA,QACJ,OAAM;AAAA,QACN,WAAU;AAAA,QAEV,sDAAC,oCAAa,WAAU,WAAU;AAAA;AAAA,IACpC;AAAA,IACA,4CAAC,mCAAY,OAAO,YAAY,SAAQ,SAAQ,MAAK,QAAO;AAAA,IAC5D;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,OAAM;AAAA,QACN,SAAS;AAAA,QACT,WAAU;AAAA,QAEV,sDAAC,4BAAK,WAAU,WAAU;AAAA;AAAA,IAC5B;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface AssetUtilityIconsProps {
|
|
4
|
+
contractExplorerHref: string;
|
|
5
|
+
shareTitle: string;
|
|
6
|
+
onReportClick: () => void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Asset-level utility row: view-on-explorer / share / report. Lives next to
|
|
10
|
+
* the asset's own identity (name/owner), not inside `AssetCollectionBar` —
|
|
11
|
+
* these actions are about the asset, not the collection it belongs to.
|
|
12
|
+
*/
|
|
13
|
+
declare function AssetUtilityIcons({ contractExplorerHref, shareTitle, onReportClick, }: AssetUtilityIconsProps): react_jsx_runtime.JSX.Element;
|
|
14
|
+
|
|
15
|
+
export { AssetUtilityIcons, type AssetUtilityIconsProps };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface AssetUtilityIconsProps {
|
|
4
|
+
contractExplorerHref: string;
|
|
5
|
+
shareTitle: string;
|
|
6
|
+
onReportClick: () => void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Asset-level utility row: view-on-explorer / share / report. Lives next to
|
|
10
|
+
* the asset's own identity (name/owner), not inside `AssetCollectionBar` —
|
|
11
|
+
* these actions are about the asset, not the collection it belongs to.
|
|
12
|
+
*/
|
|
13
|
+
declare function AssetUtilityIcons({ contractExplorerHref, shareTitle, onReportClick, }: AssetUtilityIconsProps): react_jsx_runtime.JSX.Element;
|
|
14
|
+
|
|
15
|
+
export { AssetUtilityIcons, type AssetUtilityIconsProps };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { ExternalLink, Flag } from "lucide-react";
|
|
4
|
+
import { ShareButton } from "./share-button.js";
|
|
5
|
+
function AssetUtilityIcons({
|
|
6
|
+
contractExplorerHref,
|
|
7
|
+
shareTitle,
|
|
8
|
+
onReportClick
|
|
9
|
+
}) {
|
|
10
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-muted-foreground", children: [
|
|
11
|
+
/* @__PURE__ */ jsx(
|
|
12
|
+
"a",
|
|
13
|
+
{
|
|
14
|
+
href: contractExplorerHref,
|
|
15
|
+
target: "_blank",
|
|
16
|
+
rel: "noopener noreferrer",
|
|
17
|
+
title: "View contract",
|
|
18
|
+
className: "inline-flex h-9 w-9 items-center justify-center rounded-lg hover:bg-muted/50 hover:text-foreground transition-colors",
|
|
19
|
+
children: /* @__PURE__ */ jsx(ExternalLink, { className: "h-4 w-4" })
|
|
20
|
+
}
|
|
21
|
+
),
|
|
22
|
+
/* @__PURE__ */ jsx(ShareButton, { title: shareTitle, variant: "ghost", size: "icon" }),
|
|
23
|
+
/* @__PURE__ */ jsx(
|
|
24
|
+
"button",
|
|
25
|
+
{
|
|
26
|
+
type: "button",
|
|
27
|
+
title: "Report this asset",
|
|
28
|
+
onClick: onReportClick,
|
|
29
|
+
className: "inline-flex h-9 w-9 items-center justify-center rounded-lg hover:bg-muted/50 hover:text-foreground transition-colors",
|
|
30
|
+
children: /* @__PURE__ */ jsx(Flag, { className: "h-4 w-4" })
|
|
31
|
+
}
|
|
32
|
+
)
|
|
33
|
+
] });
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
AssetUtilityIcons
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=asset-utility-icons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/asset-utility-icons.tsx"],"sourcesContent":["\"use client\";\n\nimport { ExternalLink, Flag } from \"lucide-react\";\nimport { ShareButton } from \"./share-button.js\";\n\nexport interface AssetUtilityIconsProps {\n contractExplorerHref: string;\n shareTitle: string;\n onReportClick: () => void;\n}\n\n/**\n * Asset-level utility row: view-on-explorer / share / report. Lives next to\n * the asset's own identity (name/owner), not inside `AssetCollectionBar` —\n * these actions are about the asset, not the collection it belongs to.\n */\nexport function AssetUtilityIcons({\n contractExplorerHref,\n shareTitle,\n onReportClick,\n}: AssetUtilityIconsProps) {\n return (\n <div className=\"flex items-center gap-1 text-muted-foreground\">\n <a\n href={contractExplorerHref}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n title=\"View contract\"\n className=\"inline-flex h-9 w-9 items-center justify-center rounded-lg hover:bg-muted/50 hover:text-foreground transition-colors\"\n >\n <ExternalLink className=\"h-4 w-4\" />\n </a>\n <ShareButton title={shareTitle} variant=\"ghost\" size=\"icon\" />\n <button\n type=\"button\"\n title=\"Report this asset\"\n onClick={onReportClick}\n className=\"inline-flex h-9 w-9 items-center justify-center rounded-lg hover:bg-muted/50 hover:text-foreground transition-colors\"\n >\n <Flag className=\"h-4 w-4\" />\n </button>\n </div>\n );\n}\n"],"mappings":";AAsBI,SAQI,KARJ;AApBJ,SAAS,cAAc,YAAY;AACnC,SAAS,mBAAmB;AAarB,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AACF,GAA2B;AACzB,SACE,qBAAC,SAAI,WAAU,iDACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,QAAO;AAAA,QACP,KAAI;AAAA,QACJ,OAAM;AAAA,QACN,WAAU;AAAA,QAEV,8BAAC,gBAAa,WAAU,WAAU;AAAA;AAAA,IACpC;AAAA,IACA,oBAAC,eAAY,OAAO,YAAY,SAAQ,SAAQ,MAAK,QAAO;AAAA,IAC5D;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,OAAM;AAAA,QACN,SAAS;AAAA,QACT,WAAU;AAAA,QAEV,8BAAC,QAAK,WAAU,WAAU;AAAA;AAAA,IAC5B;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
var launchpad_filter_bar_exports = {};
|
|
21
|
+
__export(launchpad_filter_bar_exports, {
|
|
22
|
+
LaunchpadFilterBar: () => LaunchpadFilterBar
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(launchpad_filter_bar_exports);
|
|
25
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
26
|
+
var import_lucide_react = require("lucide-react");
|
|
27
|
+
var import_cn = require("../utils/cn.js");
|
|
28
|
+
function LaunchpadFilterBar({
|
|
29
|
+
query,
|
|
30
|
+
onQueryChange,
|
|
31
|
+
groups,
|
|
32
|
+
activeGroups,
|
|
33
|
+
onToggleGroup,
|
|
34
|
+
resultCount
|
|
35
|
+
}) {
|
|
36
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col sm:flex-row gap-3 sm:items-center", children: [
|
|
37
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "relative flex-1 sm:max-w-xs", children: [
|
|
38
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground pointer-events-none" }),
|
|
39
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
40
|
+
"input",
|
|
41
|
+
{
|
|
42
|
+
type: "text",
|
|
43
|
+
value: query,
|
|
44
|
+
onChange: (e) => onQueryChange(e.target.value),
|
|
45
|
+
placeholder: "Search services",
|
|
46
|
+
className: "w-full h-10 rounded-full border border-border bg-card pl-9 pr-9 text-sm placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-brand-purple/40 focus:border-brand-purple/40"
|
|
47
|
+
}
|
|
48
|
+
),
|
|
49
|
+
query && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
50
|
+
"button",
|
|
51
|
+
{
|
|
52
|
+
type: "button",
|
|
53
|
+
onClick: () => onQueryChange(""),
|
|
54
|
+
"aria-label": "Clear search",
|
|
55
|
+
className: "absolute right-2.5 top-1/2 -translate-y-1/2 h-5 w-5 flex items-center justify-center rounded-full text-muted-foreground hover:text-foreground transition-colors",
|
|
56
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.X, { className: "h-3.5 w-3.5" })
|
|
57
|
+
}
|
|
58
|
+
)
|
|
59
|
+
] }),
|
|
60
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex flex-wrap gap-2 flex-1", children: groups.map((group) => {
|
|
61
|
+
const active = activeGroups.has(group.key);
|
|
62
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
63
|
+
"button",
|
|
64
|
+
{
|
|
65
|
+
type: "button",
|
|
66
|
+
onClick: () => onToggleGroup(group.key),
|
|
67
|
+
"aria-pressed": active,
|
|
68
|
+
className: (0, import_cn.cn)(
|
|
69
|
+
"h-8 px-3.5 rounded-full text-xs font-semibold transition-colors border",
|
|
70
|
+
active ? "bg-gradient-to-r from-brand-purple to-brand-blue text-white border-transparent shadow-sm" : "bg-card text-muted-foreground border-border active:bg-muted/60 sm:hover:bg-muted/40"
|
|
71
|
+
),
|
|
72
|
+
children: group.title
|
|
73
|
+
},
|
|
74
|
+
group.key
|
|
75
|
+
);
|
|
76
|
+
}) }),
|
|
77
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "text-xs text-muted-foreground whitespace-nowrap sm:pl-2", children: [
|
|
78
|
+
resultCount,
|
|
79
|
+
" ",
|
|
80
|
+
resultCount === 1 ? "service" : "services"
|
|
81
|
+
] })
|
|
82
|
+
] });
|
|
83
|
+
}
|
|
84
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
85
|
+
0 && (module.exports = {
|
|
86
|
+
LaunchpadFilterBar
|
|
87
|
+
});
|
|
88
|
+
//# sourceMappingURL=launchpad-filter-bar.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/launchpad-filter-bar.tsx"],"sourcesContent":["\"use client\";\n\nimport { Search, X } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport type { ServiceGroup, ServiceGroupDefinition } from \"../data/launchpad-services.js\";\n\nexport interface LaunchpadFilterBarProps {\n query: string;\n onQueryChange: (value: string) => void;\n groups: ServiceGroupDefinition[];\n activeGroups: Set<ServiceGroup>;\n onToggleGroup: (key: ServiceGroup) => void;\n resultCount: number;\n}\n\n/**\n * Search + group-filter bar sitting above the grouped launchpad sections.\n * Fully controlled — all state (query, active groups) lives in the caller\n * (`LaunchpadGroupedSections`) so the grid below can react to the same\n * state without prop-drilling through this component.\n */\nexport function LaunchpadFilterBar({\n query,\n onQueryChange,\n groups,\n activeGroups,\n onToggleGroup,\n resultCount,\n}: LaunchpadFilterBarProps) {\n return (\n <div className=\"flex flex-col sm:flex-row gap-3 sm:items-center\">\n <div className=\"relative flex-1 sm:max-w-xs\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground pointer-events-none\" />\n <input\n type=\"text\"\n value={query}\n onChange={(e) => onQueryChange(e.target.value)}\n placeholder=\"Search services\"\n className=\"w-full h-10 rounded-full border border-border bg-card pl-9 pr-9 text-sm placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-brand-purple/40 focus:border-brand-purple/40\"\n />\n {query && (\n <button\n type=\"button\"\n onClick={() => onQueryChange(\"\")}\n aria-label=\"Clear search\"\n className=\"absolute right-2.5 top-1/2 -translate-y-1/2 h-5 w-5 flex items-center justify-center rounded-full text-muted-foreground hover:text-foreground transition-colors\"\n >\n <X className=\"h-3.5 w-3.5\" />\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap gap-2 flex-1\">\n {groups.map((group) => {\n const active = activeGroups.has(group.key);\n return (\n <button\n key={group.key}\n type=\"button\"\n onClick={() => onToggleGroup(group.key)}\n aria-pressed={active}\n className={cn(\n \"h-8 px-3.5 rounded-full text-xs font-semibold transition-colors border\",\n active\n ? \"bg-gradient-to-r from-brand-purple to-brand-blue text-white border-transparent shadow-sm\"\n : \"bg-card text-muted-foreground border-border active:bg-muted/60 sm:hover:bg-muted/40\",\n )}\n >\n {group.title}\n </button>\n );\n })}\n </div>\n\n <p className=\"text-xs text-muted-foreground whitespace-nowrap sm:pl-2\">\n {resultCount} {resultCount === 1 ? \"service\" : \"services\"}\n </p>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+BM;AA7BN,0BAA0B;AAC1B,gBAAmB;AAkBZ,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,SACE,6CAAC,SAAI,WAAU,mDACb;AAAA,iDAAC,SAAI,WAAU,+BACb;AAAA,kDAAC,8BAAO,WAAU,8FAA6F;AAAA,MAC/G;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,cAAc,EAAE,OAAO,KAAK;AAAA,UAC7C,aAAY;AAAA,UACZ,WAAU;AAAA;AAAA,MACZ;AAAA,MACC,SACC;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,cAAc,EAAE;AAAA,UAC/B,cAAW;AAAA,UACX,WAAU;AAAA,UAEV,sDAAC,yBAAE,WAAU,eAAc;AAAA;AAAA,MAC7B;AAAA,OAEJ;AAAA,IAEA,4CAAC,SAAI,WAAU,+BACZ,iBAAO,IAAI,CAAC,UAAU;AACrB,YAAM,SAAS,aAAa,IAAI,MAAM,GAAG;AACzC,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,MAAK;AAAA,UACL,SAAS,MAAM,cAAc,MAAM,GAAG;AAAA,UACtC,gBAAc;AAAA,UACd,eAAW;AAAA,YACT;AAAA,YACA,SACI,6FACA;AAAA,UACN;AAAA,UAEC,gBAAM;AAAA;AAAA,QAXF,MAAM;AAAA,MAYb;AAAA,IAEJ,CAAC,GACH;AAAA,IAEA,6CAAC,OAAE,WAAU,2DACV;AAAA;AAAA,MAAY;AAAA,MAAE,gBAAgB,IAAI,YAAY;AAAA,OACjD;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ServiceGroupDefinition, ServiceGroup } from '../data/launchpad-services.cjs';
|
|
3
|
+
import 'lucide-react';
|
|
4
|
+
|
|
5
|
+
interface LaunchpadFilterBarProps {
|
|
6
|
+
query: string;
|
|
7
|
+
onQueryChange: (value: string) => void;
|
|
8
|
+
groups: ServiceGroupDefinition[];
|
|
9
|
+
activeGroups: Set<ServiceGroup>;
|
|
10
|
+
onToggleGroup: (key: ServiceGroup) => void;
|
|
11
|
+
resultCount: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Search + group-filter bar sitting above the grouped launchpad sections.
|
|
15
|
+
* Fully controlled — all state (query, active groups) lives in the caller
|
|
16
|
+
* (`LaunchpadGroupedSections`) so the grid below can react to the same
|
|
17
|
+
* state without prop-drilling through this component.
|
|
18
|
+
*/
|
|
19
|
+
declare function LaunchpadFilterBar({ query, onQueryChange, groups, activeGroups, onToggleGroup, resultCount, }: LaunchpadFilterBarProps): react_jsx_runtime.JSX.Element;
|
|
20
|
+
|
|
21
|
+
export { LaunchpadFilterBar, type LaunchpadFilterBarProps };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ServiceGroupDefinition, ServiceGroup } from '../data/launchpad-services.js';
|
|
3
|
+
import 'lucide-react';
|
|
4
|
+
|
|
5
|
+
interface LaunchpadFilterBarProps {
|
|
6
|
+
query: string;
|
|
7
|
+
onQueryChange: (value: string) => void;
|
|
8
|
+
groups: ServiceGroupDefinition[];
|
|
9
|
+
activeGroups: Set<ServiceGroup>;
|
|
10
|
+
onToggleGroup: (key: ServiceGroup) => void;
|
|
11
|
+
resultCount: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Search + group-filter bar sitting above the grouped launchpad sections.
|
|
15
|
+
* Fully controlled — all state (query, active groups) lives in the caller
|
|
16
|
+
* (`LaunchpadGroupedSections`) so the grid below can react to the same
|
|
17
|
+
* state without prop-drilling through this component.
|
|
18
|
+
*/
|
|
19
|
+
declare function LaunchpadFilterBar({ query, onQueryChange, groups, activeGroups, onToggleGroup, resultCount, }: LaunchpadFilterBarProps): react_jsx_runtime.JSX.Element;
|
|
20
|
+
|
|
21
|
+
export { LaunchpadFilterBar, type LaunchpadFilterBarProps };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Search, X } from "lucide-react";
|
|
4
|
+
import { cn } from "../utils/cn.js";
|
|
5
|
+
function LaunchpadFilterBar({
|
|
6
|
+
query,
|
|
7
|
+
onQueryChange,
|
|
8
|
+
groups,
|
|
9
|
+
activeGroups,
|
|
10
|
+
onToggleGroup,
|
|
11
|
+
resultCount
|
|
12
|
+
}) {
|
|
13
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row gap-3 sm:items-center", children: [
|
|
14
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex-1 sm:max-w-xs", children: [
|
|
15
|
+
/* @__PURE__ */ jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground pointer-events-none" }),
|
|
16
|
+
/* @__PURE__ */ jsx(
|
|
17
|
+
"input",
|
|
18
|
+
{
|
|
19
|
+
type: "text",
|
|
20
|
+
value: query,
|
|
21
|
+
onChange: (e) => onQueryChange(e.target.value),
|
|
22
|
+
placeholder: "Search services",
|
|
23
|
+
className: "w-full h-10 rounded-full border border-border bg-card pl-9 pr-9 text-sm placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-brand-purple/40 focus:border-brand-purple/40"
|
|
24
|
+
}
|
|
25
|
+
),
|
|
26
|
+
query && /* @__PURE__ */ jsx(
|
|
27
|
+
"button",
|
|
28
|
+
{
|
|
29
|
+
type: "button",
|
|
30
|
+
onClick: () => onQueryChange(""),
|
|
31
|
+
"aria-label": "Clear search",
|
|
32
|
+
className: "absolute right-2.5 top-1/2 -translate-y-1/2 h-5 w-5 flex items-center justify-center rounded-full text-muted-foreground hover:text-foreground transition-colors",
|
|
33
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" })
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
] }),
|
|
37
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 flex-1", children: groups.map((group) => {
|
|
38
|
+
const active = activeGroups.has(group.key);
|
|
39
|
+
return /* @__PURE__ */ jsx(
|
|
40
|
+
"button",
|
|
41
|
+
{
|
|
42
|
+
type: "button",
|
|
43
|
+
onClick: () => onToggleGroup(group.key),
|
|
44
|
+
"aria-pressed": active,
|
|
45
|
+
className: cn(
|
|
46
|
+
"h-8 px-3.5 rounded-full text-xs font-semibold transition-colors border",
|
|
47
|
+
active ? "bg-gradient-to-r from-brand-purple to-brand-blue text-white border-transparent shadow-sm" : "bg-card text-muted-foreground border-border active:bg-muted/60 sm:hover:bg-muted/40"
|
|
48
|
+
),
|
|
49
|
+
children: group.title
|
|
50
|
+
},
|
|
51
|
+
group.key
|
|
52
|
+
);
|
|
53
|
+
}) }),
|
|
54
|
+
/* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground whitespace-nowrap sm:pl-2", children: [
|
|
55
|
+
resultCount,
|
|
56
|
+
" ",
|
|
57
|
+
resultCount === 1 ? "service" : "services"
|
|
58
|
+
] })
|
|
59
|
+
] });
|
|
60
|
+
}
|
|
61
|
+
export {
|
|
62
|
+
LaunchpadFilterBar
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=launchpad-filter-bar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/launchpad-filter-bar.tsx"],"sourcesContent":["\"use client\";\n\nimport { Search, X } from \"lucide-react\";\nimport { cn } from \"../utils/cn.js\";\nimport type { ServiceGroup, ServiceGroupDefinition } from \"../data/launchpad-services.js\";\n\nexport interface LaunchpadFilterBarProps {\n query: string;\n onQueryChange: (value: string) => void;\n groups: ServiceGroupDefinition[];\n activeGroups: Set<ServiceGroup>;\n onToggleGroup: (key: ServiceGroup) => void;\n resultCount: number;\n}\n\n/**\n * Search + group-filter bar sitting above the grouped launchpad sections.\n * Fully controlled — all state (query, active groups) lives in the caller\n * (`LaunchpadGroupedSections`) so the grid below can react to the same\n * state without prop-drilling through this component.\n */\nexport function LaunchpadFilterBar({\n query,\n onQueryChange,\n groups,\n activeGroups,\n onToggleGroup,\n resultCount,\n}: LaunchpadFilterBarProps) {\n return (\n <div className=\"flex flex-col sm:flex-row gap-3 sm:items-center\">\n <div className=\"relative flex-1 sm:max-w-xs\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground pointer-events-none\" />\n <input\n type=\"text\"\n value={query}\n onChange={(e) => onQueryChange(e.target.value)}\n placeholder=\"Search services\"\n className=\"w-full h-10 rounded-full border border-border bg-card pl-9 pr-9 text-sm placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-brand-purple/40 focus:border-brand-purple/40\"\n />\n {query && (\n <button\n type=\"button\"\n onClick={() => onQueryChange(\"\")}\n aria-label=\"Clear search\"\n className=\"absolute right-2.5 top-1/2 -translate-y-1/2 h-5 w-5 flex items-center justify-center rounded-full text-muted-foreground hover:text-foreground transition-colors\"\n >\n <X className=\"h-3.5 w-3.5\" />\n </button>\n )}\n </div>\n\n <div className=\"flex flex-wrap gap-2 flex-1\">\n {groups.map((group) => {\n const active = activeGroups.has(group.key);\n return (\n <button\n key={group.key}\n type=\"button\"\n onClick={() => onToggleGroup(group.key)}\n aria-pressed={active}\n className={cn(\n \"h-8 px-3.5 rounded-full text-xs font-semibold transition-colors border\",\n active\n ? \"bg-gradient-to-r from-brand-purple to-brand-blue text-white border-transparent shadow-sm\"\n : \"bg-card text-muted-foreground border-border active:bg-muted/60 sm:hover:bg-muted/40\",\n )}\n >\n {group.title}\n </button>\n );\n })}\n </div>\n\n <p className=\"text-xs text-muted-foreground whitespace-nowrap sm:pl-2\">\n {resultCount} {resultCount === 1 ? \"service\" : \"services\"}\n </p>\n </div>\n );\n}\n"],"mappings":";AA+BM,SACE,KADF;AA7BN,SAAS,QAAQ,SAAS;AAC1B,SAAS,UAAU;AAkBZ,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,SACE,qBAAC,SAAI,WAAU,mDACb;AAAA,yBAAC,SAAI,WAAU,+BACb;AAAA,0BAAC,UAAO,WAAU,8FAA6F;AAAA,MAC/G;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,cAAc,EAAE,OAAO,KAAK;AAAA,UAC7C,aAAY;AAAA,UACZ,WAAU;AAAA;AAAA,MACZ;AAAA,MACC,SACC;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,cAAc,EAAE;AAAA,UAC/B,cAAW;AAAA,UACX,WAAU;AAAA,UAEV,8BAAC,KAAE,WAAU,eAAc;AAAA;AAAA,MAC7B;AAAA,OAEJ;AAAA,IAEA,oBAAC,SAAI,WAAU,+BACZ,iBAAO,IAAI,CAAC,UAAU;AACrB,YAAM,SAAS,aAAa,IAAI,MAAM,GAAG;AACzC,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,MAAK;AAAA,UACL,SAAS,MAAM,cAAc,MAAM,GAAG;AAAA,UACtC,gBAAc;AAAA,UACd,WAAW;AAAA,YACT;AAAA,YACA,SACI,6FACA;AAAA,UACN;AAAA,UAEC,gBAAM;AAAA;AAAA,QAXF,MAAM;AAAA,MAYb;AAAA,IAEJ,CAAC,GACH;AAAA,IAEA,qBAAC,OAAE,WAAU,2DACV;AAAA;AAAA,MAAY;AAAA,MAAE,gBAAgB,IAAI,YAAY;AAAA,OACjD;AAAA,KACF;AAEJ;","names":[]}
|