Derek Ross a7df27c754 port Agora Wallet (Spark) from Ditto's feat/spark-wallet
Bring in the Signal-style wallet redesign and settings refactor from
Ditto's feat/spark-wallet branch, rebranded as "Agora Wallet" throughout
the UI. The underlying SDK stays the Breez SDK Spark variant — internal
identifiers keep the 'spark' name.

Dashboard (/wallet)
- Signal-style layout: centered balance, three circular SEND / SCAN /
  RECEIVE actions, flat date-grouped transaction history with
  category-coloured rows.
- Tap-to-toggle between sats and USD on the balance, persisted in
  localStorage (agora:wallet:balance-mode).
- Pre-flight "Wallet not available" state when VITE_BREEZ_API_KEY is
  missing, so self-hosted builds without a key surface the problem
  before setup.

Send dialog
- Three sub-tabs: Recipient (new useNostrRecipientSearch hook backed by
  useSearchProfiles — NIP-50 + cached author fallback + debounce), Scan
  (camera QR via @capacitor/barcode-scanner), Keyboard (paste / type any
  LN address, invoice, or on-chain address).
- Recipient rows truncate display names at 32 chars + middle-ellipsis
  the LN address so pathologically long values can't push the row past
  the modal edge.

Receive dialog
- Two sub-tabs (Lightning / Bitcoin), rounded QR cards, COPY + ADD
  DETAILS pills, inline sheet for amount-specific bolt11 invoice
  generation. Lightning tab prefers the registered Lightning Address
  over a one-shot invoice.

Settings (/settings/wallet)
- Split the monolithic WalletSettings/WalletSettingsContent into three
  self-contained sections: SparkWalletSettings, WebLNSettings,
  NWCSettings.
- One-tap "Use <addr> on my Nostr profile" button publishes the wallet's
  Lightning Address to kind 0 lud16. Already-applied state shows a
  confirmation chip.
- "Change my Lightning Address" collapses behind a toggle when the user
  already has one; the claim form is primary otherwise.
- Hide-transactions-below threshold, Backup wallet sheet (relay sync /
  file export / view recovery phrase / delete relay backup), Restore
  existing wallet (with ?setup=restore URL deep-linking), CSV
  transaction export, Remove wallet (typed-DELETE confirmation).

Onboarding
- Insert a "wallet" step into InitialSyncGate's signup flow between
  Profile and Follows, with WASM-unsupported (iOS Lockdown Mode) and
  feature-disabled (no API key) fallbacks plus one-tap relay backup of
  the recovery phrase.

Zap integration
- useZaps tries the Agora Wallet first (when balance >= invoice amount)
  before falling back to NWC -> WebLN -> manual QR.

Dead code removal
- Drop WalletLockScreen + LockTimeoutSettings components and all lock
  state from SparkWalletContext (isLocked, lockWallet, unlockWallet,
  lockTimeout, shouldAutoLock, updateLastActivity, LockTimeoutMinutes).
- Existing users with lockTimeout in their persisted config blob have
  the field silently ignored on load (parseSparkWalletConfig does a
  JSON.parse + cast, unknown fields are dropped).

Library code
- Reusable presentational primitives in
  src/components/SparkWallet/primitives/: CircleAction, DateSeparator,
  TransactionRow, WalletTabBar, SettingsRow.
- src/lib/spark/{exportCsv,formatDateBucket,walletAvailability}.ts
- src/hooks/useNostrRecipientSearch.ts
- docs/SPARK-WALLET.md documenting architecture, backup formats,
  payment priority, onboarding placement, and the SDK upgrade-ceiling
  diagnostic.

Dependencies
- @breeztech/breez-sdk-spark pinned to 0.13.1 (exact, no caret). Bumped
  from the prior 0.13.2-dev1.
- @scure/bip32 ^2.0.1 and html5-qrcode ^2.3.8 added to match Ditto's
  dependency set.
- One SDK breaking change handled: prepareLnurlPay's amount_sats was
  renamed to amount and widened to bigint — breezService.ts:719 now
  calls BigInt(amountSats).

Build / native
- vite.config.ts: worker.format 'es' + optimizeDeps exclude for
  @breeztech/breez-sdk-spark (wasm loader).
- Android: CAMERA permission + uses-feature android.hardware.camera
  required=false.
- iOS: broaden NSCameraUsageDescription to mention scanning Lightning
  invoices / Bitcoin addresses.
- cap sync registers @capacitor/barcode-scanner for both platforms.

AppConfig
- New optional walletHideBelowSats?: number field (interface + Zod
  schema) controls the per-transaction hide threshold in the wallet
  history.

Help content
- "How do I connect a wallet?" FAQ leads with the built-in Agora Wallet
  and its one-tap profile setup before mentioning external NWC / WebLN
  options.

Settings page
- Add top-level Wallet entry, drop wallet description from Advanced
  (wallet settings are no longer nested under Advanced).
2026-04-21 13:45:40 -04:00
2026-04-17 12:15:51 +05:45
2026-04-17 12:10:11 +05:45
2026-03-16 01:43:42 -05:00
2026-02-16 16:54:01 -06:00
2026-04-16 18:05:50 -05:00
2026-04-17 12:10:11 +05:45
2026-02-26 21:20:15 +00:00
2026-02-22 16:35:53 -06:00
2026-04-17 12:29:00 +05:45
2026-04-18 17:17:22 +05:45

Agora

Power to the people.

Agora is a Nostr client focused on community ownership, expressive identity, and censorship resistance. This repository (agora-3) is the Agora-branded app built from the Ditto codebase.

agora.spot | Source

What This Repo Is

  • Agora product identity (name, theme, assets, native IDs)
  • Ditto-derived implementation with broad Nostr feature coverage
  • Configurable deployment defaults via agora.json

Features

  • Community-first social client: notes, articles, comments, reposts, reactions, and rich event rendering
  • Theming system: built-in presets + custom color/font/background themes that can be shared as events
  • Lightning support: zaps with Nostr Wallet Connect and WebLN
  • Private messaging: NIP-04 and NIP-17 direct messages
  • Mobile app shell: Capacitor-powered Android/iOS wrappers
  • Self-hostable: static web build + configurable relay and upload infrastructure

Getting Started

Prerequisites

Development

git clone https://gitlab.com/soapbox-pub/agora-3.git
cd agora-3
npm install
npm run dev

Development server: http://localhost:8080

Build

npm run build

Build output: dist/

Validate

npm test

This runs type-checking, linting, unit tests, and production build checks.

Configuration

Build-time config is read from agora.json (gitignored by default so each deployment can provide its own values).

{
  "theme": "dark",
  "relayMetadata": {
    "relays": [
      { "url": "wss://relay.ditto.pub", "read": true, "write": true },
      { "url": "wss://relay.primal.net", "read": true, "write": true },
      { "url": "wss://relay.damus.io", "read": true, "write": true }
    ]
  },
  "blossomServers": [
    "https://blossom.ditto.pub",
    "https://blossom.primal.net/"
  ]
}

Configuration priority (highest first):

  1. User settings (local storage)
  2. Build config (agora.json)
  3. Hardcoded app defaults

Use a custom config path:

CONFIG_FILE=./my-config.json npm run build

Deployment

Agora builds to static files and can be deployed to any static host.

  • GitLab/GitHub Pages
  • Netlify/Vercel
  • VPS or any web server with SPA routing fallback

For Android:

npm run build
npx cap sync
npx cap open android

Tech Stack

Layer Technology
Framework React 18
Build Vite
Language TypeScript
Styling TailwindCSS 3 + shadcn/ui
Routing React Router
Data TanStack Query
Nostr Nostrify + nostr-tools
Mobile Capacitor
Testing Vitest + React Testing Library

Contributing

Read CONTRIBUTING.md before opening a merge request.

License

AGPL-3.0

S
Description
Activist social network and fundraising platform on Nostr
Readme AGPL-3.0 43 MiB
Languages
TypeScript 95.7%
Java 1.5%
JavaScript 0.9%
Swift 0.9%
CSS 0.5%
Other 0.4%