From ef9bbea4654afd3218a17ac779319ece4d0603e0 Mon Sep 17 00:00:00 2001
From: "shakespeare.diy"
Date: Thu, 30 Jul 2026 13:23:55 +0700
Subject: [PATCH] feat: replace Geyser with Angor across the entire app
Remove all Geyser.fund references and replace with the SkateSpots Angor
project (angor1qtunna00uqyx52rr0nvqa059z2gknhrmn7urd6z).
- SupportersPage: remove Geyser leaderboard + API calls entirely; replace
Supporters section with an Angor CTA card including the on-chain wallet
address (bc1q2hdfyqa7utrxrd95rlr27shsdr6gtk7dzdqres)
- useGrowthStats: delete useGeyserStats hook + GEYSER_API_URL constant
- CommunityStatsPage: remove Geyser stats widget, replace with Angor CTA
- SasquatchGuide: update system prompt + FAQ (is it free, supporters)
- NewsletterPage: update both Geyser links (body + footer) to Angor
- AboutPage: remove Geyser row, update Angor entry with real project URL
- README.md: update crowdfunding section + credits
Co-authored-by: shakespeare.diy
---
README.md | 6 +-
src/components/SasquatchGuide.tsx | 6 +-
src/hooks/useGrowthStats.ts | 39 -------
src/pages/AboutPage.tsx | 3 +-
src/pages/CommunityStatsPage.tsx | 31 ++----
src/pages/NewsletterPage.tsx | 8 +-
src/pages/SupportersPage.tsx | 168 ++++++------------------------
7 files changed, 48 insertions(+), 213 deletions(-)
diff --git a/README.md b/README.md
index a1890bf..9bd5826 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@ A decentralized skateboarding community platform built on Nostr. Discover skate
- π€οΈ **Weather Integration** - Check conditions before you skate
- π **Nostr Authentication** - Decentralized login with your Nostr keys
- π± **PWA Support** - Install as a native app on any device
-- β€οΈ **Supporters** - Community funding via Geyser (Bitcoin Lightning)
+- β€οΈ **Supporters** - Community funding via Angor (decentralized Bitcoin crowdfunding)
## π οΈ Technology Stack
@@ -231,7 +231,7 @@ See `/license` in the app for the full license page.
SkateSpots is 100% free, open-source, and community-funded. No ads, no data selling, no investors.
-- **Geyser**: https://geyser.fund/project/skatespots
+- **Angor**: https://angor.io/project/angor1qtunna00uqyx52rr0nvqa059z2gknhrmn7urd6z
- **Supporters page**: https://skate-spots.org/supporters
## π Credits
@@ -239,7 +239,7 @@ SkateSpots is 100% free, open-source, and community-funded. No ads, no data sell
- **Built with**: [MKStack](https://soapbox.pub/mkstack) - Nostr client framework
- **Vibed with**: [Shakespeare](https://shakespeare.diy) - AI-powered development
- **Powered by**: [Nostr](https://nostr.com) - Decentralized protocol
-- **Funded by**: [Geyser](https://geyser.fund/project/skatespots) - Bitcoin Lightning crowdfunding
+- **Funded by**: [Angor](https://angor.io/project/angor1qtunna00uqyx52rr0nvqa059z2gknhrmn7urd6z) - Decentralized Bitcoin crowdfunding
## π Links
diff --git a/src/components/SasquatchGuide.tsx b/src/components/SasquatchGuide.tsx
index a7b192f..26b550a 100644
--- a/src/components/SasquatchGuide.tsx
+++ b/src/components/SasquatchGuide.tsx
@@ -213,7 +213,7 @@ Note: this returns a rich itinerary CARD β after calling it, add a short one-l
- Nutzaps (NIP-61) = ecash tips sent over Nostr; you can set up nutzap RECEIVING in the wallet (sending full nutzaps is rolling out β use Lightning zaps for now).
- CLINK (noffer) = an optional reusable Nostr-native payment code a shop/crew/Lab pro can add so you can pay them without a Lightning address. Shows a "Pay via CLINK" button.
- goskatespots.nostr1.com = primary community relay
-- 100% free, no ads, no tracking, community-funded via Geyser (see Supporters). πΉ`;
+- 100% free, no ads, no tracking, community-funded via Angor (see Supporters). πΉ`;
// βββ Personal tools (Sasquatch Pro) β only offered when the user is logged in β
// These read the user's OWN data client-side (Stash is decrypted locally).
@@ -418,7 +418,7 @@ const STATIC_FAQ: Record = {
'how to login': "Two ways:\n1. **Browser extension** (Desktop): Install Alby or nos2x, then click 'Log in'\n2. **New user**: Click 'Sign up' to generate keys. Download your nsec (secret key) and SAVE IT β this is your account forever!",
'what is cashu': "Built-in Bitcoin wallet! Cashu ecash tokens backed by Lightning β works offline at skate spots, privacy-focused (mints can't track payments). Go to Wallet in Settings to use it. π₯",
'what is nwc': "Nostr Wallet Connect β like USB-C for Lightning wallets. Connect Alby, Minibits, Zeus, or Coinos once, and zap with one click forever. Encrypted, you control spending limits. πβ‘",
- 'is it free': "100% free. No ads, no subscriptions, no corporate BS. Built by skaters for skaters. Community-funded via Geyser β check the Supporters page. You can also earn Bitcoin through community zaps for contributing quality spots. πΉ",
+ 'is it free': "100% free. No ads, no subscriptions, no corporate BS. Built by skaters for skaters. Community-funded via Angor β check the Supporters page. You can also earn Bitcoin through community zaps for contributing quality spots. πΉ",
'what can i do': "Discover spots worldwide on the map, hire pros in The Lab (coaches, filmers, photographers, editors, ramp builders), roll with a crew, join events, take tours, buy/sell gear, track your private Stash, zap creators, check spot weather, and build the decentralized skate community!",
'what is the lab': "The Lab is where you hire skate-scene pros: Coaches, Filmers, Photographers, Video Editors, and ramp/park/DIY Builders. Each can be a solo person or a collective (crew/studio) β members confirm with their own keys so it's legit. All on Nostr, no fake accounts. π",
'what is a crew': "Crews are your map-anchored skate family β who you skate WITH, not who you hire. Each crew has home turf on the map (teal pins), home spots, members, vibes and a manifesto. Members confirm from their own key. Start one at Crews β 'Start a Crew'. π€",
@@ -433,7 +433,7 @@ const STATIC_FAQ: Record = {
'what are tours': "Tours are guided skate trips β local sessions, national road trips, or world destruction tours. Find them on the map or the Tours section, meet up, and skate new terrain with locals. πΊοΈπΉ",
'what is a shop': "Skate Shops are local shops listed on the map. Discover and support real brick-and-mortar (or online) skate shops in your area β some even accept Bitcoin. πͺ",
'how to sell gear': "Head to Gear Swap / Marketplace and create a listing (NIP-99). Add photos, price in sats, condition, and optionally pin it to a spot so it shows on the map. Buyers zap or message you directly. πΉπΈ",
- 'supporters': "SkateSpots is community-funded via Geyser (Bitcoin Lightning crowdfunding) β no ads, no investors, no data selling. Check the Supporters page to chip in and keep the streets free. β€οΈβ‘",
+ 'supporters': "SkateSpots is community-funded via Angor (decentralized Bitcoin crowdfunding) β no ads, no investors, no data selling. Check the Supporters page to back the project and keep the streets free. β€οΈβ‘",
'trust score': "Trust scores (0-100) powered by Relatr. Analyzes your Nostr network: followers, activity, engagement, zaps. Higher = more trusted. Helps filter bots and spam. Check any profile to see their score. π‘οΈ",
'what relay': "SkateSpots uses: πΉ goskatespots.nostr1.com (primary, allowlisted for quality) + relay.ditto.pub (global) + purplepag.es (profile aggregator). Your data is replicated across all of them for redundancy.",
'trip planner': "Tell me a city and I'll build a day-by-day skate trip πΊοΈ β spots, events, coaches and local crews, weather-aware (rainy day = crew tip for covered spots). Try 'plan me 3 days in Lisbon'. I can save it all to a Collection, and hand you off to flights/stays on the real sites (no KYC, no middleman). πΉ",
diff --git a/src/hooks/useGrowthStats.ts b/src/hooks/useGrowthStats.ts
index ae2bb30..7e5d3a7 100644
--- a/src/hooks/useGrowthStats.ts
+++ b/src/hooks/useGrowthStats.ts
@@ -291,43 +291,4 @@ export function useGrowthStats() {
});
}
-// βββ Geyser supporter count ββββββββββββββββββββββββββββββββββββββββββββββββββ
-const GEYSER_API_URL = 'https://api.geyser.fund/graphql';
-
-export interface GeyserStats {
- supporterCount: number;
- totalSats: number;
-}
-
-export function useGeyserStats() {
- return useQuery({
- queryKey: ['geyser-stats'],
- queryFn: async () => {
- try {
- const res = await fetch(GEYSER_API_URL, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({
- query: `{
- projectGet(where: { name: "skatespots" }) {
- fundersCount
- balance
- }
- }`,
- }),
- });
- const json = await res.json();
- const project = json?.data?.projectGet;
- return {
- supporterCount: project?.fundersCount ?? 0,
- totalSats: project?.balance ?? 0,
- };
- } catch {
- return { supporterCount: 0, totalSats: 0 };
- }
- },
- staleTime: 15 * 60 * 1000,
- retry: false,
- });
-}
diff --git a/src/pages/AboutPage.tsx b/src/pages/AboutPage.tsx
index 5ce06c7..a1a35bf 100644
--- a/src/pages/AboutPage.tsx
+++ b/src/pages/AboutPage.tsx
@@ -263,8 +263,7 @@ Version: v0.1.0`;
{ label: 'Built with', name: 'MKStack', url: 'https://soapbox.pub/mkstack', desc: 'Nostr client framework' },
{ label: 'Vibed with', name: 'Shakespeare', url: 'https://shakespeare.diy', desc: 'AI-powered development' },
{ label: 'Powered by', name: 'Nostr', url: 'https://nostr.com', desc: 'Decentralized protocol' },
- { label: 'Crowdfunding', name: 'Geyser', url: 'https://geyser.fund/project/skatespots', desc: 'Centralized Bitcoin Lightning crowdfunding' },
- { label: 'Crowdfunding', name: 'Angor', url: 'https://angor.io/', desc: 'Bitcoin crowdfunding platform' },
+ { label: 'Crowdfunding', name: 'Angor', url: 'https://angor.io/project/angor1qtunna00uqyx52rr0nvqa059z2gknhrmn7urd6z', desc: 'Decentralized Bitcoin crowdfunding' },
{ label: 'Distributed on', name: 'Zapstore', url: 'https://zapstore.dev/apps/org.skatespots.app', desc: 'Open-source app store' },
{ label: 'AI powered by', name: 'ContextVM', url: 'https://contextvm.org/s/e3564bb877adb0c99a7e4973ccb22e516d7d9eca0027d0bd62a04174ed670530', desc: 'Nostr AI infrastructure' },
].map((item) => (
diff --git a/src/pages/CommunityStatsPage.tsx b/src/pages/CommunityStatsPage.tsx
index 62642b1..197220e 100644
--- a/src/pages/CommunityStatsPage.tsx
+++ b/src/pages/CommunityStatsPage.tsx
@@ -7,7 +7,9 @@ import { Skeleton } from '@/components/ui/skeleton';
import { useAuthor } from '@/hooks/useAuthor';
import { genUserName } from '@/lib/genUserName';
import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar';
-import { useGrowthStats, useGeyserStats } from '@/hooks/useGrowthStats';
+import { useGrowthStats } from '@/hooks/useGrowthStats';
+
+const ANGOR_PROJECT_URL = 'https://angor.io/project/angor1qtunna00uqyx52rr0nvqa059z2gknhrmn7urd6z';
import { SKATE_RELAY } from '@/lib/types';
import {
AreaChart, Area,
@@ -152,7 +154,7 @@ export default function CommunityStatsPage() {
});
const { data: stats, isLoading, isError } = useGrowthStats();
- const { data: geyser } = useGeyserStats();
+
// Content mix for donut chart
const contentMix = useMemo(() => {
@@ -460,44 +462,27 @@ export default function CommunityStatsPage() {
Funded by the Community
- Bitcoin Lightning supporters via Geyser Fund.
+ Decentralized Bitcoin crowdfunding via Angor.
No ads, no investors, no data selling.
-
- {geyser ? (
- <>
-
- {geyser.supporterCount}
-
-
supporters
- {geyser.totalSats > 0 && (
-
- β‘ {formatSats(geyser.totalSats)} sats raised
-
- )}
- >
- ) : (
-
- )}
-
diff --git a/src/pages/NewsletterPage.tsx b/src/pages/NewsletterPage.tsx
index 7f95e7a..f9711f6 100644
--- a/src/pages/NewsletterPage.tsx
+++ b/src/pages/NewsletterPage.tsx
@@ -835,16 +835,16 @@ function IssueArticle({ issue }: { issue: NewsletterIssue }) {
@@ -906,7 +906,7 @@ export default function NewsletterPage() {
Open source
{' Β· '}
-
+
Support us
diff --git a/src/pages/SupportersPage.tsx b/src/pages/SupportersPage.tsx
index b3dfd7a..507b6bc 100644
--- a/src/pages/SupportersPage.tsx
+++ b/src/pages/SupportersPage.tsx
@@ -1,12 +1,9 @@
import { useSeoMeta } from '@unhead/react';
-import { useQuery } from '@tanstack/react-query';
import { Layout } from '@/components/Layout';
import { Link } from 'react-router-dom';
import { ExternalLink, Zap, Heart, Users, Handshake, Building2, Star } from 'lucide-react';
-const GEYSER_PROJECT_URL = 'https://geyser.fund/project/skatespots?hero=satsnfacts';
-const GEYSER_LEADERBOARD_URL = 'https://geyser.fund/project/skatespots/leaderboard';
-const GEYSER_API_URL = 'https://api.geyser.fund/graphql';
+const ANGOR_PROJECT_URL = 'https://angor.io/project/angor1qtunna00uqyx52rr0nvqa059z2gknhrmn7urd6z';
// βββ Static data β edit these arrays to add/remove entries ββββββββββββββββββ
@@ -69,58 +66,6 @@ const FRIENDS: Friend[] = [
// Add more friends here
];
-// βββ Helpers βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
-
-interface GeyserContributor {
- user: {
- id: string;
- username: string;
- imageUrl?: string;
- heroLink?: string;
- };
- amount: number;
-}
-
-function formatSats(sats: number): string {
- if (sats >= 1_000_000) return `${(sats / 1_000_000).toFixed(2)}M`;
- if (sats >= 1_000) return `${Math.round(sats / 1_000).toLocaleString()}k`;
- return sats.toLocaleString();
-}
-
-function useGeyserLeaderboard() {
- return useQuery({
- queryKey: ['geyser-leaderboard'],
- queryFn: async () => {
- try {
- const res = await fetch(GEYSER_API_URL, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({
- query: `{
- projectGet(where: { name: "skatespots" }) {
- funders(input: { orderBy: { amountFunded: desc }, pagination: { take: 100 } }) {
- amountFunded
- user { id username imageUrl heroLink }
- }
- }
- }`,
- }),
- });
- const json = await res.json();
- const funders = json?.data?.projectGet?.funders ?? [];
- return funders.map((f: { amountFunded: number; user: GeyserContributor['user'] }) => ({
- user: f.user,
- amount: f.amountFunded,
- }));
- } catch {
- return [];
- }
- },
- staleTime: 5 * 60 * 1000,
- retry: false,
- });
-}
-
// βββ Section header βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
function SectionHeader({
@@ -148,43 +93,6 @@ function SectionHeader({
);
}
-// βββ Supporter card (Geyser contributors) ββββββββββββββββββββββββββββββββββββ
-
-function SupporterCard({ contributor }: { contributor: GeyserContributor }) {
- const isAnon = !contributor.user.username || contributor.user.username.toLowerCase().startsWith('anon');
- const profileUrl = contributor.user.heroLink || `https://geyser.fund/user/${contributor.user.id}`;
-
- const card = (
-
-
- {contributor.user.imageUrl ? (
-

- ) : (
-
- πΉ
-
- )}
-
-
-
-
-
- {isAnon ? 'Anon πΉ' : contributor.user.username}
-
-
- {formatSats(contributor.amount)} sats
-
-
- );
-
- if (isAnon) return card;
- return {card};
-}
-
// βββ Collaborator card ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
function CollaboratorCard({ collab }: { collab: Collaborator }) {
@@ -302,8 +210,6 @@ export default function SupportersPage() {
description: 'The community keeping SkateSpots alive β supporters, collaborators, partners and friends.',
});
- const { data: contributors = [], isLoading } = useGeyserLeaderboard();
-
return (
@@ -319,66 +225,50 @@ export default function SupportersPage() {
SkateSpots is built by and for the community. Supporters, collaborators, partners and friends keeping this free and decentralized.
- Become a Supporter
+ Back us on Angor
- {/* ββ 1. Supporters ββ */}
+ {/* ββ 1. Support ββ */}
- {isLoading ? (
-
- {Array.from({ length: 12 }).map((_, i) => (
-
- ))}
-
- ) : contributors.length > 0 ? (
-
- {contributors.map((c, i) => (
-
- ))}
-
- ) : (
-
-
πΉ
-
Be the first supporter!
-
The leaderboard updates once contributions come in.
-
- )}
-
-