diff --git a/AGENTS.md b/AGENTS.md index a593df0..1beeba0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1777,6 +1777,11 @@ Nostr events signed by a **project identity** (derived from the founder's wallet `angor:members`, `angor:media`). Live: displayName "Skate Spots", NIP-05 `owner@skate-spots.org`, lud16 `skatespots@minibits.cash` (single-sourced in `src/lib/platform.ts`), picture on `blossom.angor.io`. +- **In-app display:** `/supporters` has a **Supporters** section (curated) fed by + **`src/lib/backers.ts`** — `{ npub, amount (sats), note }` or `{ name, logo, url }`. + Amounts come from the investment txs' Taproot stage outputs. Discovery helper: + `~/.config/skatespots/angor/angor-backers.mjs` (decrypts the founder's investment DMs → + `work/backers.json`). ⚠️ Don't list a backer without consent. ### Tooling — machine-local, deliberately NOT in the repo `~/.config/skatespots/angor/` → `angor-metadata.mjs` + `blossom-upload.mjs` (own diff --git a/src/i18n/en.ts b/src/i18n/en.ts index 5ff599b..d5a7e2f 100644 --- a/src/i18n/en.ts +++ b/src/i18n/en.ts @@ -6495,6 +6495,11 @@ walletUi: { community: 'COMMUNITY', heroDesc: 'SkateSpots is built by and for the community. Supporters, collaborators, partners and friends keeping this free and decentralized.', backAngor: 'Back us on Angor', + backers: 'Supporters', + backersDesc: 'People who backed SkateSpots on Angor — decentralized, on-chain Bitcoin. Thank you.', + anonymousBacker: 'Anonymous supporter', + beFirstBacker: 'No public supporters yet — be the first.', + backersTotal: '{{count}} supporters · {{amount}} sats raised', support: 'Support', supportDesc: 'Fund SkateSpots on Angor — decentralized, on-chain Bitcoin crowdfunding. No middleman, no KYC.', collaborators: 'Collaborators', diff --git a/src/i18n/es.ts b/src/i18n/es.ts index f714073..cce3d7e 100644 --- a/src/i18n/es.ts +++ b/src/i18n/es.ts @@ -6495,6 +6495,11 @@ walletUi: { community: 'COMUNIDAD', heroDesc: 'SkateSpots lo construye y lo mantiene la comunidad. Patrocinadores, colaboradores, socios y amigos que lo mantienen libre y descentralizado.', backAngor: 'Apóyanos en Angor', + backers: 'Patrocinadores', + backersDesc: 'Personas que han apoyado SkateSpots en Angor — Bitcoin descentralizado on-chain. Gracias.', + anonymousBacker: 'Patrocinador anónimo', + beFirstBacker: 'Aún no hay patrocinadores públicos — sé el primero.', + backersTotal: '{{count}} patrocinadores · {{amount}} sats recaudados', support: 'Apoyo', supportDesc: 'Financia SkateSpots en Angor — crowdfunding descentralizado on-chain en Bitcoin. Sin intermediarios, sin KYC.', collaborators: 'Colaboradores', diff --git a/src/lib/backers.ts b/src/lib/backers.ts new file mode 100644 index 0000000..0e64a56 --- /dev/null +++ b/src/lib/backers.ts @@ -0,0 +1,48 @@ +/** + * Curated list of Angor supporters shown on /supporters. + * + * Deliberately opt-in: only list people/organisations who are happy to be + * shown. Discover the raw list (privately) with: + * node ~/.config/skatespots/angor/angor-backers.mjs + * → writes ~/.config/skatespots/angor/work/backers.json (npub + txid). + * The amount = the sum of the investment transaction's Taproot stage outputs + * (per-backer `amount` = 99,000 sats here; total matches the app's "0.00198 BTC"). + * + * Entries: + * - people: { npub, amount } → links to their profile; add `name` to override + * - shops / orgs: { name, logo, url, amount } (logo: PNG/WebP, transparent, ≥200px) + * - hide identity: { anonymous: true, note } + * + * ⚠️ Don't add someone without their consent — a backer's npub + "backed this + * project" is new, linkable information even though the key is public. + */ +export interface Backer { + /** Display name; falls back to "Anonymous supporter". */ + name?: string; + /** Nostr profile — renders a skate placeholder + links to /. */ + npub?: string; + /** Logo for a shop/brand/org (shown instead of the placeholder). */ + logo?: string; + /** External link (used when there is no npub). */ + url?: string; + /** Amount contributed, in satoshis. */ + amount?: number; + /** Small line under the name, e.g. "Founding backer". */ + note?: string; +} + +export const BACKERS: Backer[] = [ + { + npub: 'npub15q3ekfxdvzuc9nhhyh2yv7lwtnfagurllc9rkkrypt40d303jsjsdfujeu', + amount: 99000, + note: 'Founding supporter', + }, + { + npub: 'npub1t5yjluyvxatlmmcxccv7tdppmp4ae0j850k63323t7j0fe4lsqlsp7mfyl', + amount: 99000, + note: 'Founding supporter', + }, +]; + +/** Total raised across the listed supporters, in satoshis. */ +export const BACKERS_TOTAL_SATS = BACKERS.reduce((sum, b) => sum + (b.amount ?? 0), 0); diff --git a/src/pages/SupportersPage.tsx b/src/pages/SupportersPage.tsx index a99e8db..e32bf4b 100644 --- a/src/pages/SupportersPage.tsx +++ b/src/pages/SupportersPage.tsx @@ -2,6 +2,7 @@ import { useSeoMeta } from '@unhead/react'; import { Link } from 'react-router-dom'; import { ExternalLink, Zap, Heart, Users, Handshake, Building2, Star } from 'lucide-react'; import { SupportSkateSpots } from '@/components/SupportSkateSpots'; +import { BACKERS, BACKERS_TOTAL_SATS, type Backer } from '@/lib/backers'; import { useTranslation } from '@/contexts/language'; const ANGOR_PROJECT_URL = 'https://angor.io/project/angor1qtunna00uqyx52rr0nvqa059z2gknhrmn7urd6z'; @@ -202,6 +203,43 @@ function FriendCard({ friend }: { friend: Friend }) { ); } +// ─── Backer card (Angor backers) ───────────────────────────────────────────── + +function BackerCard({ backer }: { backer: Backer }) { + const { t } = useTranslation(); + const href = backer.npub ? `/${backer.npub}` : backer.url; + + const inner = ( +
+
+ {backer.logo ? ( + {backer.name { (e.target as HTMLImageElement).style.display = 'none'; }} + /> + ) : ( + 🛹 + )} +
+
+

+ {backer.name || t('walletUi.supporters.anonymousBacker')} +

+ {typeof backer.amount === 'number' && ( +

{backer.amount.toLocaleString()} sats

+ )} + {backer.note &&

{backer.note}

} +
+
+ ); + + if (!href) return inner; + if (backer.npub) return {inner}; + return {inner}; +} + // ─── Placeholder card (empty slot) ─────────────────────────────────────────── function PlaceholderCard({ label }: { label: string }) { @@ -288,7 +326,47 @@ export default function SupportersPage() { - {/* ── 2. Collaborators ── */} + {/* ── 2. Backers (Angor) ── */} +
+ + + {BACKERS.length > 0 ? ( + <> +
+ {BACKERS.map((b) => ( + + ))} +
+

+ {t('walletUi.supporters.backersTotal', { + count: BACKERS.length, + amount: BACKERS_TOTAL_SATS.toLocaleString(), + })} +

+ + ) : ( +
+ +

{t('walletUi.supporters.beFirstBacker')}

+ + + {t('walletUi.supporters.backAngor')} + +
+ )} +
+ + {/* ── 3. Collaborators ── */}