The wallet step previously stacked two generic dropdowns (source + accept) on top of two custom-address inputs that the user had to expand explicitly. Every donation flow starts the same way: pick "my wallet" and accept everything. The redesign treats that path as the default view, not one of two dropdown options. What changed: * The Source dropdown becomes an inline identity card — avatar + display name on the left, live USD/BTC balance on the right (modeled on the wallet-page treatment), pencil affordance on the far right. Tapping anywhere on the card swaps the view into the custom-wallet inputs; a quieter "Use a custom wallet instead" sub-link beneath it offers the same swap. From custom mode a small "← Use my Agora wallet" mirror-link snaps back. * The Accept dropdown becomes a three-pill segmented ToggleGroup — All / Public / Private — with icons (sparkles / bitcoin / radar) and a one-line caption beneath that explains the current selection. The All and Private buttons disable when silent payments aren't supported by the current login. Default stays 'all' (HD wallet with SP); empty toggle deselects are coerced back to the previous value since the field is required. * Balance comes from the parent's existing useHdWallet hook (passed in via new `totalBalance` + `balanceLoading` props) plus an in-component useBtcPrice call. Loading state shows a small Skeleton in place of the price line; missing price falls back to BTC-only. * When no HD wallet is available (extension / bunker logins) the picker collapses to just the two custom inputs with the existing intro copy — no card, no toggle. Existing locale keys are reused where the strings still fit; new ones cover the toggle short labels, the captions, and the swap affordances. The wider "Custom" label widens to "Custom wallet" so the segmented header reads cleanly. Other locales fall back to English on the new keys until the copy settles.
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.
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
- Node.js 22+
- npm 10.9.4+
Development
git clone https://gitlab.com/soapbox-pub/agora-3.git
cd agora-3
npm install
npm run dev
Development server: http://localhost:8080
Docker Getting Started
Use Docker Compose when you want the nginx reverse-proxy stack (necessary if you want decryptable media in messages - kind 15s of NIP 17):
git clone https://gitlab.com/soapbox-pub/agora-3.git
cd agora-3
cp .env.example .env
docker compose up --build
Proxy URL: http://localhost:8083
This starts:
viteservice on the internal Docker network (vite:8080)webservice (nginx) on host port8082, proxying to Vite with websocket support
Stop stack:
docker compose down
Production-style container build:
docker compose -f docker-compose.prod.yml up --build
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):
- User settings (local storage)
- Build config (
agora.json) - 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.