@medialane/ui 0.152.0 → 0.154.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/components/collection-hero-banner.cjs.map +1 -1
  2. package/dist/components/collection-hero-banner.d.cts +0 -2
  3. package/dist/components/collection-hero-banner.d.ts +0 -2
  4. package/dist/components/collection-hero-banner.js.map +1 -1
  5. package/dist/components/drop-preview-card.test.d.cts +3 -2
  6. package/dist/components/drop-preview-card.test.d.ts +3 -2
  7. package/dist/components/dual-price.cjs +0 -2
  8. package/dist/components/dual-price.cjs.map +1 -1
  9. package/dist/components/dual-price.d.cts +0 -2
  10. package/dist/components/dual-price.d.ts +0 -2
  11. package/dist/components/dual-price.js +0 -2
  12. package/dist/components/dual-price.js.map +1 -1
  13. package/dist/components/fast-mint/fast-mint.d.cts +2 -2
  14. package/dist/components/fast-mint/fast-mint.d.ts +2 -2
  15. package/dist/components/image.cjs.map +1 -1
  16. package/dist/components/image.js.map +1 -1
  17. package/dist/components/ip-type-fields.cjs.map +1 -1
  18. package/dist/components/ip-type-fields.d.cts +0 -6
  19. package/dist/components/ip-type-fields.d.ts +0 -6
  20. package/dist/components/ip-type-fields.js.map +1 -1
  21. package/dist/components/launchpad-cta-banner.cjs.map +1 -1
  22. package/dist/components/launchpad-cta-banner.d.cts +0 -4
  23. package/dist/components/launchpad-cta-banner.d.ts +0 -4
  24. package/dist/components/launchpad-cta-banner.js.map +1 -1
  25. package/dist/components/launchpad-services.cjs.map +1 -1
  26. package/dist/components/launchpad-services.d.cts +0 -3
  27. package/dist/components/launchpad-services.d.ts +0 -3
  28. package/dist/components/launchpad-services.js.map +1 -1
  29. package/dist/components/link.cjs.map +1 -1
  30. package/dist/components/link.d.cts +0 -2
  31. package/dist/components/link.d.ts +0 -2
  32. package/dist/components/link.js.map +1 -1
  33. package/dist/components/medialane-collection-card.cjs.map +1 -1
  34. package/dist/components/medialane-collection-card.d.cts +0 -1
  35. package/dist/components/medialane-collection-card.d.ts +0 -1
  36. package/dist/components/medialane-collection-card.js.map +1 -1
  37. package/dist/components/portfolio-section.cjs.map +1 -1
  38. package/dist/components/portfolio-section.d.cts +0 -4
  39. package/dist/components/portfolio-section.d.ts +0 -4
  40. package/dist/components/portfolio-section.js.map +1 -1
  41. package/dist/components/router.cjs.map +1 -1
  42. package/dist/components/router.js.map +1 -1
  43. package/dist/data/coins.cjs.map +1 -1
  44. package/dist/data/coins.d.cts +0 -2
  45. package/dist/data/coins.d.ts +0 -2
  46. package/dist/data/coins.js.map +1 -1
  47. package/dist/medialane.css +1 -47
  48. package/dist/utils/ipfs.cjs.map +1 -1
  49. package/dist/utils/ipfs.d.cts +0 -7
  50. package/dist/utils/ipfs.d.ts +0 -7
  51. package/dist/utils/ipfs.js.map +1 -1
  52. package/dist/utils/profile-identity.cjs +1 -1
  53. package/dist/utils/profile-identity.cjs.map +1 -1
  54. package/dist/utils/profile-identity.d.cts +1 -13
  55. package/dist/utils/profile-identity.d.ts +1 -13
  56. package/dist/utils/profile-identity.js +1 -1
  57. package/dist/utils/profile-identity.js.map +1 -1
  58. package/dist/utils/use-usd-prices.cjs.map +1 -1
  59. package/dist/utils/use-usd-prices.d.cts +0 -2
  60. package/dist/utils/use-usd-prices.d.ts +0 -2
  61. package/dist/utils/use-usd-prices.js.map +1 -1
  62. package/package.json +1 -1
@@ -1,9 +1,3 @@
1
- /* Medialane Design System — shared CSS
2
- Imported by apps via: import "@medialane/ui/styles"
3
- Do NOT import @tailwind directives here — apps handle that.
4
- All classes here are pure CSS, no @apply. */
5
-
6
- /* ── Scrollbars ───────────────────────────────────────────────────────── */
7
1
  ::-webkit-scrollbar { width: 4px; height: 4px; }
8
2
  ::-webkit-scrollbar-track { background: transparent; }
9
3
  ::-webkit-scrollbar-thumb { background: hsl(var(--border)); border-radius: 4px; }
@@ -12,33 +6,24 @@
12
6
  .scrollbar-hide { scrollbar-width: none; }
13
7
  .scrollbar-hide::-webkit-scrollbar { display: none; }
14
8
 
15
- /* ── Safe-area insets (notched/home-indicator devices) ──────────────────── */
16
9
  .pb-safe { padding-bottom: max(env(safe-area-inset-bottom), 0px); }
17
10
  .pt-safe { padding-top: max(env(safe-area-inset-top), 0px); }
18
11
 
19
- /* ── Glass ────────────────────────────────────────────────────────────── */
20
12
  .glass {
21
13
  background: rgba(10, 14, 30, 0.60);
22
14
  backdrop-filter: blur(16px);
23
- -webkit-backdrop-filter: blur(16px);
24
15
  border: 1px solid rgba(255, 255, 255, 0.06);
25
16
  }
26
17
  .glass-light {
27
18
  background: rgba(255, 255, 255, 0.80);
28
19
  backdrop-filter: blur(16px);
29
- -webkit-backdrop-filter: blur(16px);
30
20
  border: 1px solid rgba(255, 255, 255, 0.5);
31
21
  }
32
22
 
33
- /* ── Display face ─────────────────────────────────────────────────────── */
34
- /* Only the page main header renders in the brand display face (Urbanist);
35
- everything else stays on the body face. Apps set --font-display via
36
- next/font; unset, h1 inherits the body face. */
37
23
  h1 {
38
24
  font-family: var(--font-display, inherit);
39
25
  }
40
26
 
41
- /* ── Typography gradients ─────────────────────────────────────────────── */
42
27
  .gradient-text {
43
28
  background: linear-gradient(135deg, #8a5cf6 0%, #5b4ce6 40%, #3b7bff 100%);
44
29
  -webkit-background-clip: text;
@@ -64,14 +49,12 @@ h1 {
64
49
  background-clip: text;
65
50
  }
66
51
 
67
- /* ── Price ────────────────────────────────────────────────────────────── */
68
52
  .price-value {
69
53
  color: hsl(var(--price));
70
54
  font-weight: 700;
71
55
  font-variant-numeric: tabular-nums;
72
56
  }
73
57
 
74
- /* ── Section label ────────────────────────────────────────────────────── */
75
58
  .section-label {
76
59
  font-size: 0.625rem;
77
60
  font-weight: 700;
@@ -80,7 +63,6 @@ h1 {
80
63
  color: hsl(var(--muted-foreground));
81
64
  }
82
65
 
83
- /* ── Pill badge ───────────────────────────────────────────────────────── */
84
66
  .pill-badge {
85
67
  display: inline-flex;
86
68
  align-items: center;
@@ -96,15 +78,13 @@ h1 {
96
78
  color: hsl(var(--primary));
97
79
  }
98
80
 
99
- /* Navigation canvas */
100
81
  .nav-canvas-overlay {
101
82
  position: fixed;
102
83
  inset: 0;
103
84
  z-index: 100;
104
85
  backdrop-filter: blur(48px) saturate(1.5);
105
- -webkit-backdrop-filter: blur(48px) saturate(1.5);
106
86
  }
107
- /* ── Card primitives ──────────────────────────────────────────────────── */
87
+
108
88
  .card-base {
109
89
  border-radius: calc(var(--radius) * 1.25);
110
90
  border: 1px solid hsl(var(--border));
@@ -120,7 +100,6 @@ h1 {
120
100
  position: relative;
121
101
  }
122
102
 
123
- /* ── Background grid ──────────────────────────────────────────────────── */
124
103
  .bg-grid {
125
104
  background-image:
126
105
  linear-gradient(hsl(var(--border) / 0.4) 1px, transparent 1px),
@@ -128,11 +107,9 @@ h1 {
128
107
  background-size: 48px 48px;
129
108
  }
130
109
 
131
- /* ── Snap scroll ──────────────────────────────────────────────────────── */
132
110
  .snap-x-mandatory { scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch; }
133
111
  .snap-start { scroll-snap-align: start; }
134
112
 
135
- /* ── Keyframes ────────────────────────────────────────────────────────── */
136
113
  @keyframes float {
137
114
  0%, 100% { transform: translateY(0px); }
138
115
  50% { transform: translateY(-10px); }
@@ -163,39 +140,32 @@ h1 {
163
140
  50% { background-position: 100% 50%; }
164
141
  }
165
142
 
166
- /* ── Animation utilities ──────────────────────────────────────────────── */
167
143
  .animate-float { animation: float 5s ease-in-out infinite; }
168
144
  .animate-pulse-glow { animation: pulse-glow 2s ease-in-out infinite; }
169
145
  .animate-spin-slow { animation: spin-slow 24s linear infinite; }
170
146
  .animate-sparkle { animation: pulse-glow 2.5s ease-in-out infinite; }
171
147
  .animate-kenburns { animation: kenburns 8s ease-in-out infinite alternate; transform-origin: center center; }
172
148
 
173
- /* ── Reduced motion ───────────────────────────────────────────────────── */
174
149
  @media (prefers-reduced-motion: reduce) {
175
150
  .animate-float, .animate-pulse-glow, .animate-spin-slow,
176
151
  .animate-sparkle, .animate-kenburns { animation: none; }
177
152
  }
178
153
 
179
- /* ── Input spinners (price inputs use custom suffix) ──────────────────── */
180
154
  input[type="number"]::-webkit-outer-spin-button,
181
155
  input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
182
156
  input[type="number"] { -moz-appearance: textfield; }
183
157
 
184
- /* ── Wrapper that adds a 2px animated gradient border around a .card-base card ── */
185
158
  .card-exclusive-wrapper {
186
159
  padding: 2px;
187
160
  border-radius: calc(var(--radius) * 1.25 + 2px);
188
161
  }
189
162
 
190
- /* ── Animated gradient border (marketplace buy button) ────────────────── */
191
163
  .btn-border-animated {
192
164
  background: linear-gradient(270deg, #3b7bff, #8a5cf6, #f6608f, #fb8b46, #3b7bff);
193
165
  background-size: 300% 300%;
194
166
  animation: border-flow 5s ease infinite;
195
167
  }
196
168
 
197
- /* ── Action button — animated gradient border via ::before mask ────────── */
198
- /* Set --ml-grad on the element to choose the border gradient. */
199
169
  .ml-gbtn { position: relative; }
200
170
  .ml-gbtn::before {
201
171
  content: '';
@@ -213,10 +183,6 @@ input[type="number"] { -moz-appearance: textfield; }
213
183
  }
214
184
  .ml-gbtn:hover::before { padding: 2px; animation-duration: 1.6s; }
215
185
 
216
- /* ── Nav wallet trigger — rotating brand-gradient ring ──────────────────── */
217
- /* Not connected: the ring rotates continuously (ambient "connect here" cue, */
218
- /* no icon inside). Connected: the ring stops and settles to a quiet static */
219
- /* accent, the trigger's own User glyph renders in the center instead. */
220
186
  .ml-nav-wallet-ring {
221
187
  position: absolute;
222
188
  inset: 0;
@@ -233,10 +199,6 @@ input[type="number"] { -moz-appearance: textfield; }
233
199
  animation: none;
234
200
  }
235
201
 
236
- /* ── Static two-stop signature ring — Collections/Creators surfaces ────── */
237
- /* Same masked-ring technique as .ml-nav-wallet-ring, but static (no spin) and
238
- scoped to the two colors this section owns (brand-blue -> brand-purple) —
239
- see medialane-core reference_brand_colors_and_gradients section-theming map. */
240
202
  .ml-collection-ring {
241
203
  position: absolute;
242
204
  inset: 0;
@@ -249,10 +211,6 @@ input[type="number"] { -moz-appearance: textfield; }
249
211
  pointer-events: none;
250
212
  }
251
213
 
252
- /* ── Hover-only branded gradient border (launchpad cards) ───────────────── */
253
- /* The resting state keeps the card's own hairline; on hover-capable devices */
254
- /* the full-spectrum ring fades in over it. Decoration only — never carries */
255
- /* information (mobile users lose nothing). */
256
214
  .ml-grad-hover-border { position: relative; }
257
215
  .ml-grad-hover-border::before {
258
216
  content: '';
@@ -276,9 +234,6 @@ input[type="number"] { -moz-appearance: textfield; }
276
234
  100% { background-position: 220% 50%; }
277
235
  }
278
236
 
279
- /* ── Collector card material (MedialaneCollectionCard) ────────────────── */
280
- /* Light by default (matches the app's light-theme root, no .dark ancestor);
281
- .dark overrides restore the original always-dark foil-on-navy look. */
282
237
  .ml-card-material {
283
238
  background:
284
239
  radial-gradient(120% 90% at 0% 0%, rgba(59,123,255,0.07), transparent 55%),
@@ -292,7 +247,6 @@ input[type="number"] { -moz-appearance: textfield; }
292
247
  #0a0e1f;
293
248
  }
294
249
 
295
- /* ── Action dialog keyframes ──────────────────────────────────────────── */
296
250
  @keyframes mlFade {
297
251
  from { opacity: 0; }
298
252
  to { opacity: 1; }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/ipfs.ts"],"sourcesContent":["export const DEFAULT_GATEWAY = \"https://gateway.pinata.cloud/ipfs/\";\n\nconst ALLOWED_PROTOCOLS = new Set([\"http:\", \"https:\", \"ipfs:\"]);\n\nconst KNOWN_IPFS_GATEWAY_HOSTS = /(^|\\.)(mypinata\\.cloud|pinata\\.cloud|ipfs\\.io|dweb\\.link|cloudflare-ipfs\\.com|nftstorage\\.link|w3s\\.link)$/i;\n\nconst DEFAULT_WIDTH = 1200;\n\nfunction withSize(url: string, gateway: string, width: number | null): string {\n if (!width || !url.startsWith(gateway)) return url;\n const sep = url.includes(\"?\") ? \"&\" : \"?\";\n return `${url}${sep}img-width=${width}&img-format=webp&img-quality=80`;\n}\n\nexport function ipfsToHttp(\n uri: string | null | undefined,\n opts: { gateway?: string; width?: number | null } = {}\n): string {\n const gateway = opts.gateway ?? DEFAULT_GATEWAY;\n const width = opts.width === undefined ? DEFAULT_WIDTH : opts.width;\n\n if (!uri) return \"\";\n if (uri.startsWith(\"ipfs://\")) {\n return withSize(uri.replace(\"ipfs://\", gateway), gateway, width);\n }\n if (uri.startsWith(\"data:image/\")) {\n return uri;\n }\n try {\n const parsed = new URL(uri);\n if (!ALLOWED_PROTOCOLS.has(parsed.protocol)) return \"\";\n\n if (KNOWN_IPFS_GATEWAY_HOSTS.test(parsed.hostname)) {\n const match = parsed.pathname.match(/\\/ipfs\\/(.+)$/);\n if (match) return withSize(`${gateway}${match[1]}`, gateway, width);\n }\n } catch {\n return \"\";\n }\n return uri;\n}\n\nexport interface DisplayUrlOptions {\n gateway?: string;\n proxyPath?: string;\n placeholder?: string;\n}\n\nexport function toDisplayUrl(\n uri: string | null | undefined,\n opts: DisplayUrlOptions = {},\n): string {\n const gateway = opts.gateway ?? DEFAULT_GATEWAY;\n const placeholder = opts.placeholder ?? \"/placeholder.svg\";\n const proxyPath = opts.proxyPath ?? \"/api/img\";\n\n if (!uri) return placeholder;\n if (uri.startsWith(\"data:image/\")) return uri;\n\n const resolved = ipfsToHttp(uri, { gateway });\n if (resolved.startsWith(gateway)) return resolved;\n\n if (uri.startsWith(\"https://\") || uri.startsWith(\"http://\")) {\n return `${proxyPath}?url=${encodeURIComponent(uri)}`;\n }\n\n return placeholder;\n}\n\nexport function toDisplayUrlOrNull(\n raw: string | null | undefined,\n opts: DisplayUrlOptions = {},\n): string | null {\n if (!raw) return null;\n if (raw.startsWith(\"/\")) return raw;\n return toDisplayUrl(raw, opts);\n}\n\n/**\n * Absolute URL for a crawler: og:image and twitter:image are fetched by\n * Facebook, X and Slack with our app nowhere in the path, so the result must\n * resolve on its own. Pointing these at an app route is how every social\n * preview once 404'd. Empty string means \"no image\", which is what the\n * metadata APIs expect in place of a broken URL.\n */\nexport function toAbsoluteImageUrl(uri: string | null | undefined): string {\n if (!uri) return \"\";\n return ipfsToHttp(uri) || \"\";\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,MAAM,kBAAkB;AAE/B,MAAM,oBAAoB,oBAAI,IAAI,CAAC,SAAS,UAAU,OAAO,CAAC;AAE9D,MAAM,2BAA2B;AAEjC,MAAM,gBAAgB;AAEtB,SAAS,SAAS,KAAa,SAAiB,OAA8B;AAC5E,MAAI,CAAC,SAAS,CAAC,IAAI,WAAW,OAAO,EAAG,QAAO;AAC/C,QAAM,MAAM,IAAI,SAAS,GAAG,IAAI,MAAM;AACtC,SAAO,GAAG,GAAG,GAAG,GAAG,aAAa,KAAK;AACvC;AAEO,SAAS,WACd,KACA,OAAoD,CAAC,GAC7C;AACR,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,QAAQ,KAAK,UAAU,SAAY,gBAAgB,KAAK;AAE9D,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,IAAI,WAAW,SAAS,GAAG;AAC7B,WAAO,SAAS,IAAI,QAAQ,WAAW,OAAO,GAAG,SAAS,KAAK;AAAA,EACjE;AACA,MAAI,IAAI,WAAW,aAAa,GAAG;AACjC,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,QAAI,CAAC,kBAAkB,IAAI,OAAO,QAAQ,EAAG,QAAO;AAEpD,QAAI,yBAAyB,KAAK,OAAO,QAAQ,GAAG;AAClD,YAAM,QAAQ,OAAO,SAAS,MAAM,eAAe;AACnD,UAAI,MAAO,QAAO,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC,IAAI,SAAS,KAAK;AAAA,IACpE;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAQO,SAAS,aACd,KACA,OAA0B,CAAC,GACnB;AACR,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,cAAc,KAAK,eAAe;AACxC,QAAM,YAAY,KAAK,aAAa;AAEpC,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,IAAI,WAAW,aAAa,EAAG,QAAO;AAE1C,QAAM,WAAW,WAAW,KAAK,EAAE,QAAQ,CAAC;AAC5C,MAAI,SAAS,WAAW,OAAO,EAAG,QAAO;AAEzC,MAAI,IAAI,WAAW,UAAU,KAAK,IAAI,WAAW,SAAS,GAAG;AAC3D,WAAO,GAAG,SAAS,QAAQ,mBAAmB,GAAG,CAAC;AAAA,EACpD;AAEA,SAAO;AACT;AAEO,SAAS,mBACd,KACA,OAA0B,CAAC,GACZ;AACf,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,IAAI,WAAW,GAAG,EAAG,QAAO;AAChC,SAAO,aAAa,KAAK,IAAI;AAC/B;AASO,SAAS,mBAAmB,KAAwC;AACzE,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,WAAW,GAAG,KAAK;AAC5B;","names":[]}
1
+ {"version":3,"sources":["../../src/utils/ipfs.ts"],"sourcesContent":["export const DEFAULT_GATEWAY = \"https://gateway.pinata.cloud/ipfs/\";\n\nconst ALLOWED_PROTOCOLS = new Set([\"http:\", \"https:\", \"ipfs:\"]);\n\nconst KNOWN_IPFS_GATEWAY_HOSTS = /(^|\\.)(mypinata\\.cloud|pinata\\.cloud|ipfs\\.io|dweb\\.link|cloudflare-ipfs\\.com|nftstorage\\.link|w3s\\.link)$/i;\n\nconst DEFAULT_WIDTH = 1200;\n\nfunction withSize(url: string, gateway: string, width: number | null): string {\n if (!width || !url.startsWith(gateway)) return url;\n const sep = url.includes(\"?\") ? \"&\" : \"?\";\n return `${url}${sep}img-width=${width}&img-format=webp&img-quality=80`;\n}\n\nexport function ipfsToHttp(\n uri: string | null | undefined,\n opts: { gateway?: string; width?: number | null } = {}\n): string {\n const gateway = opts.gateway ?? DEFAULT_GATEWAY;\n const width = opts.width === undefined ? DEFAULT_WIDTH : opts.width;\n\n if (!uri) return \"\";\n if (uri.startsWith(\"ipfs://\")) {\n return withSize(uri.replace(\"ipfs://\", gateway), gateway, width);\n }\n if (uri.startsWith(\"data:image/\")) {\n return uri;\n }\n try {\n const parsed = new URL(uri);\n if (!ALLOWED_PROTOCOLS.has(parsed.protocol)) return \"\";\n\n if (KNOWN_IPFS_GATEWAY_HOSTS.test(parsed.hostname)) {\n const match = parsed.pathname.match(/\\/ipfs\\/(.+)$/);\n if (match) return withSize(`${gateway}${match[1]}`, gateway, width);\n }\n } catch {\n return \"\";\n }\n return uri;\n}\n\nexport interface DisplayUrlOptions {\n gateway?: string;\n proxyPath?: string;\n placeholder?: string;\n}\n\nexport function toDisplayUrl(\n uri: string | null | undefined,\n opts: DisplayUrlOptions = {},\n): string {\n const gateway = opts.gateway ?? DEFAULT_GATEWAY;\n const placeholder = opts.placeholder ?? \"/placeholder.svg\";\n const proxyPath = opts.proxyPath ?? \"/api/img\";\n\n if (!uri) return placeholder;\n if (uri.startsWith(\"data:image/\")) return uri;\n\n const resolved = ipfsToHttp(uri, { gateway });\n if (resolved.startsWith(gateway)) return resolved;\n\n if (uri.startsWith(\"https://\") || uri.startsWith(\"http://\")) {\n return `${proxyPath}?url=${encodeURIComponent(uri)}`;\n }\n\n return placeholder;\n}\n\nexport function toDisplayUrlOrNull(\n raw: string | null | undefined,\n opts: DisplayUrlOptions = {},\n): string | null {\n if (!raw) return null;\n if (raw.startsWith(\"/\")) return raw;\n return toDisplayUrl(raw, opts);\n}\n\nexport function toAbsoluteImageUrl(uri: string | null | undefined): string {\n if (!uri) return \"\";\n return ipfsToHttp(uri) || \"\";\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,MAAM,kBAAkB;AAE/B,MAAM,oBAAoB,oBAAI,IAAI,CAAC,SAAS,UAAU,OAAO,CAAC;AAE9D,MAAM,2BAA2B;AAEjC,MAAM,gBAAgB;AAEtB,SAAS,SAAS,KAAa,SAAiB,OAA8B;AAC5E,MAAI,CAAC,SAAS,CAAC,IAAI,WAAW,OAAO,EAAG,QAAO;AAC/C,QAAM,MAAM,IAAI,SAAS,GAAG,IAAI,MAAM;AACtC,SAAO,GAAG,GAAG,GAAG,GAAG,aAAa,KAAK;AACvC;AAEO,SAAS,WACd,KACA,OAAoD,CAAC,GAC7C;AACR,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,QAAQ,KAAK,UAAU,SAAY,gBAAgB,KAAK;AAE9D,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,IAAI,WAAW,SAAS,GAAG;AAC7B,WAAO,SAAS,IAAI,QAAQ,WAAW,OAAO,GAAG,SAAS,KAAK;AAAA,EACjE;AACA,MAAI,IAAI,WAAW,aAAa,GAAG;AACjC,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,QAAI,CAAC,kBAAkB,IAAI,OAAO,QAAQ,EAAG,QAAO;AAEpD,QAAI,yBAAyB,KAAK,OAAO,QAAQ,GAAG;AAClD,YAAM,QAAQ,OAAO,SAAS,MAAM,eAAe;AACnD,UAAI,MAAO,QAAO,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC,IAAI,SAAS,KAAK;AAAA,IACpE;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAQO,SAAS,aACd,KACA,OAA0B,CAAC,GACnB;AACR,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,cAAc,KAAK,eAAe;AACxC,QAAM,YAAY,KAAK,aAAa;AAEpC,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,IAAI,WAAW,aAAa,EAAG,QAAO;AAE1C,QAAM,WAAW,WAAW,KAAK,EAAE,QAAQ,CAAC;AAC5C,MAAI,SAAS,WAAW,OAAO,EAAG,QAAO;AAEzC,MAAI,IAAI,WAAW,UAAU,KAAK,IAAI,WAAW,SAAS,GAAG;AAC3D,WAAO,GAAG,SAAS,QAAQ,mBAAmB,GAAG,CAAC;AAAA,EACpD;AAEA,SAAO;AACT;AAEO,SAAS,mBACd,KACA,OAA0B,CAAC,GACZ;AACf,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,IAAI,WAAW,GAAG,EAAG,QAAO;AAChC,SAAO,aAAa,KAAK,IAAI;AAC/B;AAEO,SAAS,mBAAmB,KAAwC;AACzE,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,WAAW,GAAG,KAAK;AAC5B;","names":[]}
@@ -10,13 +10,6 @@ interface DisplayUrlOptions {
10
10
  }
11
11
  declare function toDisplayUrl(uri: string | null | undefined, opts?: DisplayUrlOptions): string;
12
12
  declare function toDisplayUrlOrNull(raw: string | null | undefined, opts?: DisplayUrlOptions): string | null;
13
- /**
14
- * Absolute URL for a crawler: og:image and twitter:image are fetched by
15
- * Facebook, X and Slack with our app nowhere in the path, so the result must
16
- * resolve on its own. Pointing these at an app route is how every social
17
- * preview once 404'd. Empty string means "no image", which is what the
18
- * metadata APIs expect in place of a broken URL.
19
- */
20
13
  declare function toAbsoluteImageUrl(uri: string | null | undefined): string;
21
14
 
22
15
  export { DEFAULT_GATEWAY, type DisplayUrlOptions, ipfsToHttp, toAbsoluteImageUrl, toDisplayUrl, toDisplayUrlOrNull };
@@ -10,13 +10,6 @@ interface DisplayUrlOptions {
10
10
  }
11
11
  declare function toDisplayUrl(uri: string | null | undefined, opts?: DisplayUrlOptions): string;
12
12
  declare function toDisplayUrlOrNull(raw: string | null | undefined, opts?: DisplayUrlOptions): string | null;
13
- /**
14
- * Absolute URL for a crawler: og:image and twitter:image are fetched by
15
- * Facebook, X and Slack with our app nowhere in the path, so the result must
16
- * resolve on its own. Pointing these at an app route is how every social
17
- * preview once 404'd. Empty string means "no image", which is what the
18
- * metadata APIs expect in place of a broken URL.
19
- */
20
13
  declare function toAbsoluteImageUrl(uri: string | null | undefined): string;
21
14
 
22
15
  export { DEFAULT_GATEWAY, type DisplayUrlOptions, ipfsToHttp, toAbsoluteImageUrl, toDisplayUrl, toDisplayUrlOrNull };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/ipfs.ts"],"sourcesContent":["export const DEFAULT_GATEWAY = \"https://gateway.pinata.cloud/ipfs/\";\n\nconst ALLOWED_PROTOCOLS = new Set([\"http:\", \"https:\", \"ipfs:\"]);\n\nconst KNOWN_IPFS_GATEWAY_HOSTS = /(^|\\.)(mypinata\\.cloud|pinata\\.cloud|ipfs\\.io|dweb\\.link|cloudflare-ipfs\\.com|nftstorage\\.link|w3s\\.link)$/i;\n\nconst DEFAULT_WIDTH = 1200;\n\nfunction withSize(url: string, gateway: string, width: number | null): string {\n if (!width || !url.startsWith(gateway)) return url;\n const sep = url.includes(\"?\") ? \"&\" : \"?\";\n return `${url}${sep}img-width=${width}&img-format=webp&img-quality=80`;\n}\n\nexport function ipfsToHttp(\n uri: string | null | undefined,\n opts: { gateway?: string; width?: number | null } = {}\n): string {\n const gateway = opts.gateway ?? DEFAULT_GATEWAY;\n const width = opts.width === undefined ? DEFAULT_WIDTH : opts.width;\n\n if (!uri) return \"\";\n if (uri.startsWith(\"ipfs://\")) {\n return withSize(uri.replace(\"ipfs://\", gateway), gateway, width);\n }\n if (uri.startsWith(\"data:image/\")) {\n return uri;\n }\n try {\n const parsed = new URL(uri);\n if (!ALLOWED_PROTOCOLS.has(parsed.protocol)) return \"\";\n\n if (KNOWN_IPFS_GATEWAY_HOSTS.test(parsed.hostname)) {\n const match = parsed.pathname.match(/\\/ipfs\\/(.+)$/);\n if (match) return withSize(`${gateway}${match[1]}`, gateway, width);\n }\n } catch {\n return \"\";\n }\n return uri;\n}\n\nexport interface DisplayUrlOptions {\n gateway?: string;\n proxyPath?: string;\n placeholder?: string;\n}\n\nexport function toDisplayUrl(\n uri: string | null | undefined,\n opts: DisplayUrlOptions = {},\n): string {\n const gateway = opts.gateway ?? DEFAULT_GATEWAY;\n const placeholder = opts.placeholder ?? \"/placeholder.svg\";\n const proxyPath = opts.proxyPath ?? \"/api/img\";\n\n if (!uri) return placeholder;\n if (uri.startsWith(\"data:image/\")) return uri;\n\n const resolved = ipfsToHttp(uri, { gateway });\n if (resolved.startsWith(gateway)) return resolved;\n\n if (uri.startsWith(\"https://\") || uri.startsWith(\"http://\")) {\n return `${proxyPath}?url=${encodeURIComponent(uri)}`;\n }\n\n return placeholder;\n}\n\nexport function toDisplayUrlOrNull(\n raw: string | null | undefined,\n opts: DisplayUrlOptions = {},\n): string | null {\n if (!raw) return null;\n if (raw.startsWith(\"/\")) return raw;\n return toDisplayUrl(raw, opts);\n}\n\n/**\n * Absolute URL for a crawler: og:image and twitter:image are fetched by\n * Facebook, X and Slack with our app nowhere in the path, so the result must\n * resolve on its own. Pointing these at an app route is how every social\n * preview once 404'd. Empty string means \"no image\", which is what the\n * metadata APIs expect in place of a broken URL.\n */\nexport function toAbsoluteImageUrl(uri: string | null | undefined): string {\n if (!uri) return \"\";\n return ipfsToHttp(uri) || \"\";\n}\n"],"mappings":"AAAO,MAAM,kBAAkB;AAE/B,MAAM,oBAAoB,oBAAI,IAAI,CAAC,SAAS,UAAU,OAAO,CAAC;AAE9D,MAAM,2BAA2B;AAEjC,MAAM,gBAAgB;AAEtB,SAAS,SAAS,KAAa,SAAiB,OAA8B;AAC5E,MAAI,CAAC,SAAS,CAAC,IAAI,WAAW,OAAO,EAAG,QAAO;AAC/C,QAAM,MAAM,IAAI,SAAS,GAAG,IAAI,MAAM;AACtC,SAAO,GAAG,GAAG,GAAG,GAAG,aAAa,KAAK;AACvC;AAEO,SAAS,WACd,KACA,OAAoD,CAAC,GAC7C;AACR,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,QAAQ,KAAK,UAAU,SAAY,gBAAgB,KAAK;AAE9D,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,IAAI,WAAW,SAAS,GAAG;AAC7B,WAAO,SAAS,IAAI,QAAQ,WAAW,OAAO,GAAG,SAAS,KAAK;AAAA,EACjE;AACA,MAAI,IAAI,WAAW,aAAa,GAAG;AACjC,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,QAAI,CAAC,kBAAkB,IAAI,OAAO,QAAQ,EAAG,QAAO;AAEpD,QAAI,yBAAyB,KAAK,OAAO,QAAQ,GAAG;AAClD,YAAM,QAAQ,OAAO,SAAS,MAAM,eAAe;AACnD,UAAI,MAAO,QAAO,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC,IAAI,SAAS,KAAK;AAAA,IACpE;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAQO,SAAS,aACd,KACA,OAA0B,CAAC,GACnB;AACR,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,cAAc,KAAK,eAAe;AACxC,QAAM,YAAY,KAAK,aAAa;AAEpC,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,IAAI,WAAW,aAAa,EAAG,QAAO;AAE1C,QAAM,WAAW,WAAW,KAAK,EAAE,QAAQ,CAAC;AAC5C,MAAI,SAAS,WAAW,OAAO,EAAG,QAAO;AAEzC,MAAI,IAAI,WAAW,UAAU,KAAK,IAAI,WAAW,SAAS,GAAG;AAC3D,WAAO,GAAG,SAAS,QAAQ,mBAAmB,GAAG,CAAC;AAAA,EACpD;AAEA,SAAO;AACT;AAEO,SAAS,mBACd,KACA,OAA0B,CAAC,GACZ;AACf,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,IAAI,WAAW,GAAG,EAAG,QAAO;AAChC,SAAO,aAAa,KAAK,IAAI;AAC/B;AASO,SAAS,mBAAmB,KAAwC;AACzE,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,WAAW,GAAG,KAAK;AAC5B;","names":[]}
1
+ {"version":3,"sources":["../../src/utils/ipfs.ts"],"sourcesContent":["export const DEFAULT_GATEWAY = \"https://gateway.pinata.cloud/ipfs/\";\n\nconst ALLOWED_PROTOCOLS = new Set([\"http:\", \"https:\", \"ipfs:\"]);\n\nconst KNOWN_IPFS_GATEWAY_HOSTS = /(^|\\.)(mypinata\\.cloud|pinata\\.cloud|ipfs\\.io|dweb\\.link|cloudflare-ipfs\\.com|nftstorage\\.link|w3s\\.link)$/i;\n\nconst DEFAULT_WIDTH = 1200;\n\nfunction withSize(url: string, gateway: string, width: number | null): string {\n if (!width || !url.startsWith(gateway)) return url;\n const sep = url.includes(\"?\") ? \"&\" : \"?\";\n return `${url}${sep}img-width=${width}&img-format=webp&img-quality=80`;\n}\n\nexport function ipfsToHttp(\n uri: string | null | undefined,\n opts: { gateway?: string; width?: number | null } = {}\n): string {\n const gateway = opts.gateway ?? DEFAULT_GATEWAY;\n const width = opts.width === undefined ? DEFAULT_WIDTH : opts.width;\n\n if (!uri) return \"\";\n if (uri.startsWith(\"ipfs://\")) {\n return withSize(uri.replace(\"ipfs://\", gateway), gateway, width);\n }\n if (uri.startsWith(\"data:image/\")) {\n return uri;\n }\n try {\n const parsed = new URL(uri);\n if (!ALLOWED_PROTOCOLS.has(parsed.protocol)) return \"\";\n\n if (KNOWN_IPFS_GATEWAY_HOSTS.test(parsed.hostname)) {\n const match = parsed.pathname.match(/\\/ipfs\\/(.+)$/);\n if (match) return withSize(`${gateway}${match[1]}`, gateway, width);\n }\n } catch {\n return \"\";\n }\n return uri;\n}\n\nexport interface DisplayUrlOptions {\n gateway?: string;\n proxyPath?: string;\n placeholder?: string;\n}\n\nexport function toDisplayUrl(\n uri: string | null | undefined,\n opts: DisplayUrlOptions = {},\n): string {\n const gateway = opts.gateway ?? DEFAULT_GATEWAY;\n const placeholder = opts.placeholder ?? \"/placeholder.svg\";\n const proxyPath = opts.proxyPath ?? \"/api/img\";\n\n if (!uri) return placeholder;\n if (uri.startsWith(\"data:image/\")) return uri;\n\n const resolved = ipfsToHttp(uri, { gateway });\n if (resolved.startsWith(gateway)) return resolved;\n\n if (uri.startsWith(\"https://\") || uri.startsWith(\"http://\")) {\n return `${proxyPath}?url=${encodeURIComponent(uri)}`;\n }\n\n return placeholder;\n}\n\nexport function toDisplayUrlOrNull(\n raw: string | null | undefined,\n opts: DisplayUrlOptions = {},\n): string | null {\n if (!raw) return null;\n if (raw.startsWith(\"/\")) return raw;\n return toDisplayUrl(raw, opts);\n}\n\nexport function toAbsoluteImageUrl(uri: string | null | undefined): string {\n if (!uri) return \"\";\n return ipfsToHttp(uri) || \"\";\n}\n"],"mappings":"AAAO,MAAM,kBAAkB;AAE/B,MAAM,oBAAoB,oBAAI,IAAI,CAAC,SAAS,UAAU,OAAO,CAAC;AAE9D,MAAM,2BAA2B;AAEjC,MAAM,gBAAgB;AAEtB,SAAS,SAAS,KAAa,SAAiB,OAA8B;AAC5E,MAAI,CAAC,SAAS,CAAC,IAAI,WAAW,OAAO,EAAG,QAAO;AAC/C,QAAM,MAAM,IAAI,SAAS,GAAG,IAAI,MAAM;AACtC,SAAO,GAAG,GAAG,GAAG,GAAG,aAAa,KAAK;AACvC;AAEO,SAAS,WACd,KACA,OAAoD,CAAC,GAC7C;AACR,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,QAAQ,KAAK,UAAU,SAAY,gBAAgB,KAAK;AAE9D,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,IAAI,WAAW,SAAS,GAAG;AAC7B,WAAO,SAAS,IAAI,QAAQ,WAAW,OAAO,GAAG,SAAS,KAAK;AAAA,EACjE;AACA,MAAI,IAAI,WAAW,aAAa,GAAG;AACjC,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,QAAI,CAAC,kBAAkB,IAAI,OAAO,QAAQ,EAAG,QAAO;AAEpD,QAAI,yBAAyB,KAAK,OAAO,QAAQ,GAAG;AAClD,YAAM,QAAQ,OAAO,SAAS,MAAM,eAAe;AACnD,UAAI,MAAO,QAAO,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC,IAAI,SAAS,KAAK;AAAA,IACpE;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAQO,SAAS,aACd,KACA,OAA0B,CAAC,GACnB;AACR,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,cAAc,KAAK,eAAe;AACxC,QAAM,YAAY,KAAK,aAAa;AAEpC,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,IAAI,WAAW,aAAa,EAAG,QAAO;AAE1C,QAAM,WAAW,WAAW,KAAK,EAAE,QAAQ,CAAC;AAC5C,MAAI,SAAS,WAAW,OAAO,EAAG,QAAO;AAEzC,MAAI,IAAI,WAAW,UAAU,KAAK,IAAI,WAAW,SAAS,GAAG;AAC3D,WAAO,GAAG,SAAS,QAAQ,mBAAmB,GAAG,CAAC;AAAA,EACpD;AAEA,SAAO;AACT;AAEO,SAAS,mBACd,KACA,OAA0B,CAAC,GACZ;AACf,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,IAAI,WAAW,GAAG,EAAG,QAAO;AAChC,SAAO,aAAa,KAAK,IAAI;AAC/B;AAEO,SAAS,mBAAmB,KAAwC;AACzE,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,WAAW,GAAG,KAAK;AAC5B;","names":[]}
@@ -24,7 +24,7 @@ module.exports = __toCommonJS(profile_identity_exports);
24
24
  var import_address = require("./address.js");
25
25
  function profileIdentity(source) {
26
26
  const username = source.username?.trim() || null;
27
- const name = source.displayName?.trim() || null;
27
+ const name = source.name?.trim() || null;
28
28
  const address = source.walletAddress?.trim() || null;
29
29
  return {
30
30
  identity: username ? `@${username}` : address ? (0, import_address.shortenAddress)(address) : "Unknown account",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/profile-identity.ts"],"sourcesContent":["import { shortenAddress } from \"./address.js\";\n\nexport interface ProfileIdentitySource {\n username?: string | null;\n displayName?: string | null;\n walletAddress?: string | null;\n}\n\nexport interface ProfileIdentity {\n identity: string;\n name: string | null;\n hasUsername: boolean;\n}\n\n/**\n * Splits a profile into what identifies an account and what merely labels it.\n *\n * `identity` only ever comes from a claimed username or the wallet address.\n * Both are governed: a username is unique, charset-restricted, blocked against\n * a reserved list and reviewed before approval; an address is the account\n * itself. `name` is free text the account typed, so it can say anything and\n * cannot identify anyone.\n *\n * Keeping them apart is the point. A profile that set its name to a platform\n * or a rival's handle rendered as that handle everywhere the two were merged.\n */\nexport function profileIdentity(source: ProfileIdentitySource): ProfileIdentity {\n const username = source.username?.trim() || null;\n const name = source.displayName?.trim() || null;\n const address = source.walletAddress?.trim() || null;\n\n return {\n identity: username ? `@${username}` : address ? shortenAddress(address) : \"Unknown account\",\n name,\n hasUsername: Boolean(username),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA+B;AA0BxB,SAAS,gBAAgB,QAAgD;AAC9E,QAAM,WAAW,OAAO,UAAU,KAAK,KAAK;AAC5C,QAAM,OAAO,OAAO,aAAa,KAAK,KAAK;AAC3C,QAAM,UAAU,OAAO,eAAe,KAAK,KAAK;AAEhD,SAAO;AAAA,IACL,UAAU,WAAW,IAAI,QAAQ,KAAK,cAAU,+BAAe,OAAO,IAAI;AAAA,IAC1E;AAAA,IACA,aAAa,QAAQ,QAAQ;AAAA,EAC/B;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/utils/profile-identity.ts"],"sourcesContent":["import { shortenAddress } from \"./address.js\";\n\nexport interface ProfileIdentitySource {\n username?: string | null;\n name?: string | null;\n walletAddress?: string | null;\n}\n\nexport interface ProfileIdentity {\n identity: string;\n name: string | null;\n hasUsername: boolean;\n}\n\nexport function profileIdentity(source: ProfileIdentitySource): ProfileIdentity {\n const username = source.username?.trim() || null;\n const name = source.name?.trim() || null;\n const address = source.walletAddress?.trim() || null;\n\n return {\n identity: username ? `@${username}` : address ? shortenAddress(address) : \"Unknown account\",\n name,\n hasUsername: Boolean(username),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA+B;AAcxB,SAAS,gBAAgB,QAAgD;AAC9E,QAAM,WAAW,OAAO,UAAU,KAAK,KAAK;AAC5C,QAAM,OAAO,OAAO,MAAM,KAAK,KAAK;AACpC,QAAM,UAAU,OAAO,eAAe,KAAK,KAAK;AAEhD,SAAO;AAAA,IACL,UAAU,WAAW,IAAI,QAAQ,KAAK,cAAU,+BAAe,OAAO,IAAI;AAAA,IAC1E;AAAA,IACA,aAAa,QAAQ,QAAQ;AAAA,EAC/B;AACF;","names":[]}
@@ -1,6 +1,6 @@
1
1
  interface ProfileIdentitySource {
2
2
  username?: string | null;
3
- displayName?: string | null;
3
+ name?: string | null;
4
4
  walletAddress?: string | null;
5
5
  }
6
6
  interface ProfileIdentity {
@@ -8,18 +8,6 @@ interface ProfileIdentity {
8
8
  name: string | null;
9
9
  hasUsername: boolean;
10
10
  }
11
- /**
12
- * Splits a profile into what identifies an account and what merely labels it.
13
- *
14
- * `identity` only ever comes from a claimed username or the wallet address.
15
- * Both are governed: a username is unique, charset-restricted, blocked against
16
- * a reserved list and reviewed before approval; an address is the account
17
- * itself. `name` is free text the account typed, so it can say anything and
18
- * cannot identify anyone.
19
- *
20
- * Keeping them apart is the point. A profile that set its name to a platform
21
- * or a rival's handle rendered as that handle everywhere the two were merged.
22
- */
23
11
  declare function profileIdentity(source: ProfileIdentitySource): ProfileIdentity;
24
12
 
25
13
  export { type ProfileIdentity, type ProfileIdentitySource, profileIdentity };
@@ -1,6 +1,6 @@
1
1
  interface ProfileIdentitySource {
2
2
  username?: string | null;
3
- displayName?: string | null;
3
+ name?: string | null;
4
4
  walletAddress?: string | null;
5
5
  }
6
6
  interface ProfileIdentity {
@@ -8,18 +8,6 @@ interface ProfileIdentity {
8
8
  name: string | null;
9
9
  hasUsername: boolean;
10
10
  }
11
- /**
12
- * Splits a profile into what identifies an account and what merely labels it.
13
- *
14
- * `identity` only ever comes from a claimed username or the wallet address.
15
- * Both are governed: a username is unique, charset-restricted, blocked against
16
- * a reserved list and reviewed before approval; an address is the account
17
- * itself. `name` is free text the account typed, so it can say anything and
18
- * cannot identify anyone.
19
- *
20
- * Keeping them apart is the point. A profile that set its name to a platform
21
- * or a rival's handle rendered as that handle everywhere the two were merged.
22
- */
23
11
  declare function profileIdentity(source: ProfileIdentitySource): ProfileIdentity;
24
12
 
25
13
  export { type ProfileIdentity, type ProfileIdentitySource, profileIdentity };
@@ -1,7 +1,7 @@
1
1
  import { shortenAddress } from "./address.js";
2
2
  function profileIdentity(source) {
3
3
  const username = source.username?.trim() || null;
4
- const name = source.displayName?.trim() || null;
4
+ const name = source.name?.trim() || null;
5
5
  const address = source.walletAddress?.trim() || null;
6
6
  return {
7
7
  identity: username ? `@${username}` : address ? shortenAddress(address) : "Unknown account",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/profile-identity.ts"],"sourcesContent":["import { shortenAddress } from \"./address.js\";\n\nexport interface ProfileIdentitySource {\n username?: string | null;\n displayName?: string | null;\n walletAddress?: string | null;\n}\n\nexport interface ProfileIdentity {\n identity: string;\n name: string | null;\n hasUsername: boolean;\n}\n\n/**\n * Splits a profile into what identifies an account and what merely labels it.\n *\n * `identity` only ever comes from a claimed username or the wallet address.\n * Both are governed: a username is unique, charset-restricted, blocked against\n * a reserved list and reviewed before approval; an address is the account\n * itself. `name` is free text the account typed, so it can say anything and\n * cannot identify anyone.\n *\n * Keeping them apart is the point. A profile that set its name to a platform\n * or a rival's handle rendered as that handle everywhere the two were merged.\n */\nexport function profileIdentity(source: ProfileIdentitySource): ProfileIdentity {\n const username = source.username?.trim() || null;\n const name = source.displayName?.trim() || null;\n const address = source.walletAddress?.trim() || null;\n\n return {\n identity: username ? `@${username}` : address ? shortenAddress(address) : \"Unknown account\",\n name,\n hasUsername: Boolean(username),\n };\n}\n"],"mappings":"AAAA,SAAS,sBAAsB;AA0BxB,SAAS,gBAAgB,QAAgD;AAC9E,QAAM,WAAW,OAAO,UAAU,KAAK,KAAK;AAC5C,QAAM,OAAO,OAAO,aAAa,KAAK,KAAK;AAC3C,QAAM,UAAU,OAAO,eAAe,KAAK,KAAK;AAEhD,SAAO;AAAA,IACL,UAAU,WAAW,IAAI,QAAQ,KAAK,UAAU,eAAe,OAAO,IAAI;AAAA,IAC1E;AAAA,IACA,aAAa,QAAQ,QAAQ;AAAA,EAC/B;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/utils/profile-identity.ts"],"sourcesContent":["import { shortenAddress } from \"./address.js\";\n\nexport interface ProfileIdentitySource {\n username?: string | null;\n name?: string | null;\n walletAddress?: string | null;\n}\n\nexport interface ProfileIdentity {\n identity: string;\n name: string | null;\n hasUsername: boolean;\n}\n\nexport function profileIdentity(source: ProfileIdentitySource): ProfileIdentity {\n const username = source.username?.trim() || null;\n const name = source.name?.trim() || null;\n const address = source.walletAddress?.trim() || null;\n\n return {\n identity: username ? `@${username}` : address ? shortenAddress(address) : \"Unknown account\",\n name,\n hasUsername: Boolean(username),\n };\n}\n"],"mappings":"AAAA,SAAS,sBAAsB;AAcxB,SAAS,gBAAgB,QAAgD;AAC9E,QAAM,WAAW,OAAO,UAAU,KAAK,KAAK;AAC5C,QAAM,OAAO,OAAO,MAAM,KAAK,KAAK;AACpC,QAAM,UAAU,OAAO,eAAe,KAAK,KAAK;AAEhD,SAAO;AAAA,IACL,UAAU,WAAW,IAAI,QAAQ,KAAK,UAAU,eAAe,OAAO,IAAI;AAAA,IAC1E;AAAA,IACA,aAAa,QAAQ,QAAQ;AAAA,EAC/B;AACF;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/use-usd-prices.ts"],"sourcesContent":["\"use client\";\n\nimport useSWR from \"swr\";\n\nexport type UsdPrices = Partial<Record<\"STRK\" | \"ETH\" | \"USDC\" | \"USDT\" | \"WBTC\", number>>;\n\n/** Looks up a USD price by an arbitrary token symbol (not just the pinned\n * set UsdPrices is keyed on) — a coin/memecoin symbol simply has no entry. */\nexport function usdPriceFor(prices: UsdPrices | null, symbol: string): number | undefined {\n return (prices as Record<string, number | undefined> | null)?.[symbol];\n}\n\nconst REFRESH_MS = 60_000;\nconst PRICES_KEY = \"usd-prices\";\nconst PRICES_URL = \"/api/proxy/v1/prices\";\n\nasync function fetchUsdPrices(): Promise<UsdPrices | null> {\n const res = await fetch(PRICES_URL);\n const body = (await res.json()) as { data?: { usd?: UsdPrices } };\n return body.data?.usd ?? null;\n}\n\nexport function useUsdPrices(): UsdPrices | null {\n const { data } = useSWR(PRICES_KEY, fetchUsdPrices, {\n refreshInterval: REFRESH_MS,\n dedupingInterval: REFRESH_MS,\n revalidateOnFocus: false,\n revalidateOnReconnect: true,\n keepPreviousData: true,\n onError: () => {},\n });\n return data ?? null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,iBAAmB;AAMZ,SAAS,YAAY,QAA0B,QAAoC;AACxF,SAAQ,SAAuD,MAAM;AACvE;AAEA,MAAM,aAAa;AACnB,MAAM,aAAa;AACnB,MAAM,aAAa;AAEnB,eAAe,iBAA4C;AACzD,QAAM,MAAM,MAAM,MAAM,UAAU;AAClC,QAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,SAAO,KAAK,MAAM,OAAO;AAC3B;AAEO,SAAS,eAAiC;AAC/C,QAAM,EAAE,KAAK,QAAI,WAAAA,SAAO,YAAY,gBAAgB;AAAA,IAClD,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,mBAAmB;AAAA,IACnB,uBAAuB;AAAA,IACvB,kBAAkB;AAAA,IAClB,SAAS,MAAM;AAAA,IAAC;AAAA,EAClB,CAAC;AACD,SAAO,QAAQ;AACjB;","names":["useSWR"]}
1
+ {"version":3,"sources":["../../src/utils/use-usd-prices.ts"],"sourcesContent":["\"use client\";\n\nimport useSWR from \"swr\";\n\nexport type UsdPrices = Partial<Record<\"STRK\" | \"ETH\" | \"USDC\" | \"USDT\" | \"WBTC\", number>>;\n\nexport function usdPriceFor(prices: UsdPrices | null, symbol: string): number | undefined {\n return (prices as Record<string, number | undefined> | null)?.[symbol];\n}\n\nconst REFRESH_MS = 60_000;\nconst PRICES_KEY = \"usd-prices\";\nconst PRICES_URL = \"/api/proxy/v1/prices\";\n\nasync function fetchUsdPrices(): Promise<UsdPrices | null> {\n const res = await fetch(PRICES_URL);\n const body = (await res.json()) as { data?: { usd?: UsdPrices } };\n return body.data?.usd ?? null;\n}\n\nexport function useUsdPrices(): UsdPrices | null {\n const { data } = useSWR(PRICES_KEY, fetchUsdPrices, {\n refreshInterval: REFRESH_MS,\n dedupingInterval: REFRESH_MS,\n revalidateOnFocus: false,\n revalidateOnReconnect: true,\n keepPreviousData: true,\n onError: () => {},\n });\n return data ?? null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,iBAAmB;AAIZ,SAAS,YAAY,QAA0B,QAAoC;AACxF,SAAQ,SAAuD,MAAM;AACvE;AAEA,MAAM,aAAa;AACnB,MAAM,aAAa;AACnB,MAAM,aAAa;AAEnB,eAAe,iBAA4C;AACzD,QAAM,MAAM,MAAM,MAAM,UAAU;AAClC,QAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,SAAO,KAAK,MAAM,OAAO;AAC3B;AAEO,SAAS,eAAiC;AAC/C,QAAM,EAAE,KAAK,QAAI,WAAAA,SAAO,YAAY,gBAAgB;AAAA,IAClD,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,mBAAmB;AAAA,IACnB,uBAAuB;AAAA,IACvB,kBAAkB;AAAA,IAClB,SAAS,MAAM;AAAA,IAAC;AAAA,EAClB,CAAC;AACD,SAAO,QAAQ;AACjB;","names":["useSWR"]}
@@ -1,6 +1,4 @@
1
1
  type UsdPrices = Partial<Record<"STRK" | "ETH" | "USDC" | "USDT" | "WBTC", number>>;
2
- /** Looks up a USD price by an arbitrary token symbol (not just the pinned
3
- * set UsdPrices is keyed on) — a coin/memecoin symbol simply has no entry. */
4
2
  declare function usdPriceFor(prices: UsdPrices | null, symbol: string): number | undefined;
5
3
  declare function useUsdPrices(): UsdPrices | null;
6
4
 
@@ -1,6 +1,4 @@
1
1
  type UsdPrices = Partial<Record<"STRK" | "ETH" | "USDC" | "USDT" | "WBTC", number>>;
2
- /** Looks up a USD price by an arbitrary token symbol (not just the pinned
3
- * set UsdPrices is keyed on) — a coin/memecoin symbol simply has no entry. */
4
2
  declare function usdPriceFor(prices: UsdPrices | null, symbol: string): number | undefined;
5
3
  declare function useUsdPrices(): UsdPrices | null;
6
4
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/use-usd-prices.ts"],"sourcesContent":["\"use client\";\n\nimport useSWR from \"swr\";\n\nexport type UsdPrices = Partial<Record<\"STRK\" | \"ETH\" | \"USDC\" | \"USDT\" | \"WBTC\", number>>;\n\n/** Looks up a USD price by an arbitrary token symbol (not just the pinned\n * set UsdPrices is keyed on) — a coin/memecoin symbol simply has no entry. */\nexport function usdPriceFor(prices: UsdPrices | null, symbol: string): number | undefined {\n return (prices as Record<string, number | undefined> | null)?.[symbol];\n}\n\nconst REFRESH_MS = 60_000;\nconst PRICES_KEY = \"usd-prices\";\nconst PRICES_URL = \"/api/proxy/v1/prices\";\n\nasync function fetchUsdPrices(): Promise<UsdPrices | null> {\n const res = await fetch(PRICES_URL);\n const body = (await res.json()) as { data?: { usd?: UsdPrices } };\n return body.data?.usd ?? null;\n}\n\nexport function useUsdPrices(): UsdPrices | null {\n const { data } = useSWR(PRICES_KEY, fetchUsdPrices, {\n refreshInterval: REFRESH_MS,\n dedupingInterval: REFRESH_MS,\n revalidateOnFocus: false,\n revalidateOnReconnect: true,\n keepPreviousData: true,\n onError: () => {},\n });\n return data ?? null;\n}\n"],"mappings":";AAEA,OAAO,YAAY;AAMZ,SAAS,YAAY,QAA0B,QAAoC;AACxF,SAAQ,SAAuD,MAAM;AACvE;AAEA,MAAM,aAAa;AACnB,MAAM,aAAa;AACnB,MAAM,aAAa;AAEnB,eAAe,iBAA4C;AACzD,QAAM,MAAM,MAAM,MAAM,UAAU;AAClC,QAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,SAAO,KAAK,MAAM,OAAO;AAC3B;AAEO,SAAS,eAAiC;AAC/C,QAAM,EAAE,KAAK,IAAI,OAAO,YAAY,gBAAgB;AAAA,IAClD,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,mBAAmB;AAAA,IACnB,uBAAuB;AAAA,IACvB,kBAAkB;AAAA,IAClB,SAAS,MAAM;AAAA,IAAC;AAAA,EAClB,CAAC;AACD,SAAO,QAAQ;AACjB;","names":[]}
1
+ {"version":3,"sources":["../../src/utils/use-usd-prices.ts"],"sourcesContent":["\"use client\";\n\nimport useSWR from \"swr\";\n\nexport type UsdPrices = Partial<Record<\"STRK\" | \"ETH\" | \"USDC\" | \"USDT\" | \"WBTC\", number>>;\n\nexport function usdPriceFor(prices: UsdPrices | null, symbol: string): number | undefined {\n return (prices as Record<string, number | undefined> | null)?.[symbol];\n}\n\nconst REFRESH_MS = 60_000;\nconst PRICES_KEY = \"usd-prices\";\nconst PRICES_URL = \"/api/proxy/v1/prices\";\n\nasync function fetchUsdPrices(): Promise<UsdPrices | null> {\n const res = await fetch(PRICES_URL);\n const body = (await res.json()) as { data?: { usd?: UsdPrices } };\n return body.data?.usd ?? null;\n}\n\nexport function useUsdPrices(): UsdPrices | null {\n const { data } = useSWR(PRICES_KEY, fetchUsdPrices, {\n refreshInterval: REFRESH_MS,\n dedupingInterval: REFRESH_MS,\n revalidateOnFocus: false,\n revalidateOnReconnect: true,\n keepPreviousData: true,\n onError: () => {},\n });\n return data ?? null;\n}\n"],"mappings":";AAEA,OAAO,YAAY;AAIZ,SAAS,YAAY,QAA0B,QAAoC;AACxF,SAAQ,SAAuD,MAAM;AACvE;AAEA,MAAM,aAAa;AACnB,MAAM,aAAa;AACnB,MAAM,aAAa;AAEnB,eAAe,iBAA4C;AACzD,QAAM,MAAM,MAAM,MAAM,UAAU;AAClC,QAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,SAAO,KAAK,MAAM,OAAO;AAC3B;AAEO,SAAS,eAAiC;AAC/C,QAAM,EAAE,KAAK,IAAI,OAAO,YAAY,gBAAgB;AAAA,IAClD,iBAAiB;AAAA,IACjB,kBAAkB;AAAA,IAClB,mBAAmB;AAAA,IACnB,uBAAuB;AAAA,IACvB,kBAAkB;AAAA,IAClB,SAAS,MAAM;AAAA,IAAC;AAAA,EAClB,CAAC;AACD,SAAO,QAAQ;AACjB;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@medialane/ui",
3
- "version": "0.152.0",
3
+ "version": "0.154.0",
4
4
  "description": "Shared UI components for Medialane apps",
5
5
  "type": "module",
6
6
  "sideEffects": false,