From 40d889ac4ea21fc63cad0083b8a26653b7afc454 Mon Sep 17 00:00:00 2001
From: jckbtchr <77942319+jckbtchr-bot@users.noreply.github.com>
Date: Fri, 29 May 2026 16:15:31 -0500
Subject: [PATCH 1/2] Add broker contact flow to Punk marketplace status module
Rework Punk/Detail/Market.vue: move Top bid to the left cell with the
Place-bid form beneath it, Listing to the right cell with a new Contact
broker button beneath it, and surface the owner's wallet last-active time
(from the indexer) under the listing state.
New Market/BrokerContact.vue: a Contact broker popover with email capture
(client-side only for now) and a co-branded "Canon" preview, toggled via a
floating control that appears beneath the dialog while open. New
Market/BrokerLogo.vue inlines the broker wordmark.
Co-Authored-By: Claude Opus 4.8
---
.../app/components/Punk/Detail/Market.vue | 105 +++++--
.../Punk/Detail/Market/BrokerContact.vue | 280 ++++++++++++++++++
.../Punk/Detail/Market/BrokerLogo.vue | 40 +++
3 files changed, 394 insertions(+), 31 deletions(-)
create mode 100644 punks.auction/app/components/Punk/Detail/Market/BrokerContact.vue
create mode 100644 punks.auction/app/components/Punk/Detail/Market/BrokerLogo.vue
diff --git a/punks.auction/app/components/Punk/Detail/Market.vue b/punks.auction/app/components/Punk/Detail/Market.vue
index f47c75b4..4d37c27a 100644
--- a/punks.auction/app/components/Punk/Detail/Market.vue
+++ b/punks.auction/app/components/Punk/Detail/Market.vue
@@ -15,6 +15,35 @@
class="market-panel"
>
+
+
Top bid
+
+
+ by
+
+
+
+
+
+ None
+
+
+
+
+
+
+
Listing
@@ -32,23 +61,17 @@
>
Not for sale
-
-
-
Top bid
-
-
- by
-
-
-
-
-
- None
-
+ Wallet last active {{ ownerLastActiveAgo }}
+
+
+
+
+
@@ -123,20 +146,12 @@
.
-
-
-
-
+
@@ -228,6 +243,26 @@ const canBuy = computed(() => {
)
})
+// Owner's wallet last-active, sourced from the indexer's tx-from tracking, so a
+// broker can gauge how reachable the holder is. Custody set covers vault/stash;
+// the EOA drives the last-active lookup.
+const ownerAddresses = computed(() => {
+ const set = new Set()
+ if (resolvedOwner.value) set.add(resolvedOwner.value)
+ if (nativeOwner.value) set.add(nativeOwner.value)
+ return [...set]
+})
+const { stats: ownerStats } = useAccountStats({
+ addresses: ownerAddresses,
+ eoa: () => resolvedOwner.value ?? undefined,
+})
+const ownerLastActiveIso = computed(() =>
+ ownerStats.value.lastActiveAt
+ ? new Date(ownerStats.value.lastActiveAt * 1000).toISOString()
+ : undefined,
+)
+const ownerLastActiveAgo = useTimeAgo(ownerLastActiveIso)
+
let refreshToken = 0
async function refresh() {
@@ -386,6 +421,16 @@ function sameAddress(a?: Address | string | null, b?: Address | string | null) {
border: 0;
}
+.last-active {
+ margin: var(--size-1) 0 0;
+ font-size: var(--font-xs);
+ color: var(--text-dim);
+}
+
+.cell-action {
+ margin-top: var(--size-4);
+}
+
.label {
margin-bottom: var(--size-1);
color: var(--text-dim);
@@ -404,8 +449,6 @@ function sameAddress(a?: Address | string | null, b?: Address | string | null) {
align-items: center;
gap: var(--size-2);
flex-wrap: wrap;
- padding-top: var(--size-3);
- border-top: var(--border);
}
.action-group {
diff --git a/punks.auction/app/components/Punk/Detail/Market/BrokerContact.vue b/punks.auction/app/components/Punk/Detail/Market/BrokerContact.vue
new file mode 100644
index 00000000..da26aa8d
--- /dev/null
+++ b/punks.auction/app/components/Punk/Detail/Market/BrokerContact.vue
@@ -0,0 +1,280 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/punks.auction/app/components/Punk/Detail/Market/BrokerLogo.vue b/punks.auction/app/components/Punk/Detail/Market/BrokerLogo.vue
new file mode 100644
index 00000000..693fb2e2
--- /dev/null
+++ b/punks.auction/app/components/Punk/Detail/Market/BrokerLogo.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
From 3004f743e88c9d95c9461c18e00ac42ee81ec21a Mon Sep 17 00:00:00 2001
From: jckbtchr <77942319+jckbtchr-bot@users.noreply.github.com>
Date: Fri, 29 May 2026 17:05:45 -0500
Subject: [PATCH 2/2] Extract broker brand to runtime config
Move the broker name and logo SVG out of BrokerLogo.vue into
runtimeConfig.public.broker (default "Canon"), overridable per deployment via
NUXT_PUBLIC_BROKER_NAME / NUXT_PUBLIC_BROKER_LOGO. BrokerLogo.vue now renders
the configured SVG and BrokerContact.vue reads the name from config. Documented
both env vars in .env.example.
Co-Authored-By: Claude Opus 4.8
---
punks.auction/.env.example | 6 +++
.../Punk/Detail/Market/BrokerContact.vue | 6 ++-
.../Punk/Detail/Market/BrokerLogo.vue | 46 +++++++------------
punks.auction/nuxt.config.ts | 8 ++++
4 files changed, 35 insertions(+), 31 deletions(-)
diff --git a/punks.auction/.env.example b/punks.auction/.env.example
index 1e5c987f..1421a93e 100644
--- a/punks.auction/.env.example
+++ b/punks.auction/.env.example
@@ -10,3 +10,9 @@ NUXT_PUBLIC_EVM_WALLET_CONNECT_PROJECT_ID=
# Public indexer base URL (Ponder/Postgres GraphQL endpoint). Defaults to the
# shared production indexer in nuxt.config.ts; override per environment.
NUXT_PUBLIC_INDEXER_URL=https://indexer.punksmarket.app
+
+# Broker brand shown in the "branded" Contact-broker preview. Defaults to
+# "Canon" in nuxt.config.ts. NUXT_PUBLIC_BROKER_LOGO is inline SVG markup —
+# use fill="currentColor" so it inherits the surrounding text color.
+NUXT_PUBLIC_BROKER_NAME=Canon
+NUXT_PUBLIC_BROKER_LOGO=
diff --git a/punks.auction/app/components/Punk/Detail/Market/BrokerContact.vue b/punks.auction/app/components/Punk/Detail/Market/BrokerContact.vue
index da26aa8d..aa58100b 100644
--- a/punks.auction/app/components/Punk/Detail/Market/BrokerContact.vue
+++ b/punks.auction/app/components/Punk/Detail/Market/BrokerContact.vue
@@ -109,8 +109,10 @@ const submitted = ref(false)
// Demo affordance: flips the dialog to a co-branded broker preview. Persists
// across reopen so it can be shown/screen-shared without re-toggling.
const branded = ref(false)
-// Named broker in the branded preview; generic in the standard version.
-const brokerName = computed(() => (branded.value ? 'Canon' : 'a broker'))
+// Named broker (from runtime config) in the branded preview; generic in the
+// standard version.
+const broker = useRuntimeConfig().public.broker as { name: string; logo: string }
+const brokerName = computed(() => (branded.value ? broker.name : 'a broker'))
// Float the version toggle just below the dialog box: present only while the
// popover is open and anchored to the live dialog rect, so it reads as a
diff --git a/punks.auction/app/components/Punk/Detail/Market/BrokerLogo.vue b/punks.auction/app/components/Punk/Detail/Market/BrokerLogo.vue
index 693fb2e2..e39ff0e8 100644
--- a/punks.auction/app/components/Punk/Detail/Market/BrokerLogo.vue
+++ b/punks.auction/app/components/Punk/Detail/Market/BrokerLogo.vue
@@ -1,40 +1,28 @@
-
+ :aria-label="`${broker.name} logo`"
+ v-html="broker.logo"
+ />
+
+
diff --git a/punks.auction/nuxt.config.ts b/punks.auction/nuxt.config.ts
index 087902ab..d94ace1d 100644
--- a/punks.auction/nuxt.config.ts
+++ b/punks.auction/nuxt.config.ts
@@ -66,6 +66,14 @@ export default defineNuxtConfig({
// shared indexer that backs both punksmarket.app and this app.
// Override with NUXT_PUBLIC_INDEXER_URL.
indexerUrl: 'https://indexer.punksmarket.app',
+ // Broker brand shown in the "branded" Contact-broker preview. Override
+ // per deployment with NUXT_PUBLIC_BROKER_NAME / NUXT_PUBLIC_BROKER_LOGO.
+ // `logo` is inline SVG markup; use `fill="currentColor"` so it inherits
+ // the surrounding text color.
+ broker: {
+ name: 'Canon',
+ logo: '',
+ },
evm: {
walletConnectProjectId: '',
chains: {