Ditto is a tiny but powerful social media server for the decentralized web. https://soapbox.pub/ditto/
  • TypeScript 97%
  • Java 1.1%
  • Swift 0.9%
  • CSS 0.6%
  • JavaScript 0.3%
Find a file
Alex Gleason 480e0aa97f
Some checks are pending
Deploy to GitHub Pages / deploy (push) Waiting to run
Test / test (push) Waiting to run
Render follow lists with avatar stacks in profile recovery
The Follows tab of the profile recovery dialog previously showed only
a generic Users icon, a follow count, and a timestamp — making every
historical snapshot look identical and giving users no way to
distinguish one version from another. Now each snapshot renders an
avatar stack of the followed profiles, which makes differences between
snapshots visible at a glance.

Changes along the way:

- Extract the avatar-stack block from PeopleListContent into a shared
  PeopleAvatarStack component (sm/md/lg sizes, hover-to-pop-forward
  with display-name tooltip, "+N more" overflow).
- Reverse `p` tags in kind 3 displays so the newest follows surface
  first. Kind 3 grows by appending, so the natural order is
  oldest-first — the same early follows would otherwise dominate every
  preview. Implemented as a getDisplayPubkeys(event, pubkeys) helper
  used at display sites only; mutations and filters keep the original
  array.
- Compact the snapshot cards in ProfileRecoveryDialog by moving the
  Restore button into the top-right slot that already hosted the
  Current badge, and dropping the redundant "<icon> N follows" title
  row from the Follows card since the avatars communicate the same
  thing more clearly.
2026-04-27 15:58:07 -05:00
.agents/skills Remove direct messaging feature and skill 2026-04-26 23:21:54 -05:00
.github/workflows New project created with Shakespeare 2026-02-16 16:54:01 -06:00
.gitlab/merge_request_templates Replace screenshots table with simpler Before/After format in MR template 2026-04-10 15:15:54 -05:00
.vscode New project created with Shakespeare 2026-02-16 16:54:01 -06:00
android release: v2.10.5 2026-04-25 03:30:27 -05:00
docs Replace __DITTO_CONFIG__ global with import.meta.env.DITTO_CONFIG and remove ThemeSchemaCompat 2026-04-01 23:16:33 -05:00
eslint-rules New project created with Shakespeare 2026-02-16 16:54:01 -06:00
ios release: v2.10.5 2026-04-25 03:30:27 -05:00
public Render webxdc embeds as a tilted, color-tinted cartridge 2026-04-27 01:15:54 -05:00
scripts Add native iOS notification polling with rich metadata and grouping 2026-04-14 14:58:49 -05:00
src Render follow lists with avatar stacks in profile recovery 2026-04-27 15:58:07 -05:00
.env.example Add configurable shareOrigin to AppConfig 2026-04-17 22:39:44 -05:00
.gitignore Add .classpath to .gitignore 2026-03-16 01:43:42 -05:00
.gitlab-ci.yml Add Google Play publishing to CI release pipeline 2026-04-11 18:10:29 -05:00
.mcp.json New project created with Shakespeare 2026-02-16 16:54:01 -06:00
AGENTS.md Remove direct messaging feature and skill 2026-04-26 23:21:54 -05:00
capacitor.config.ts Fix Android WebView resize bugs caused by @capacitor/keyboard 2026-04-12 14:07:52 -05:00
CHANGELOG.md release: v2.10.5 2026-04-25 03:30:27 -05:00
components.json New project created with Shakespeare 2026-02-16 16:54:01 -06:00
CONTRIBUTING.md Document Regression-of trailer convention for commit messages 2026-04-17 16:03:51 -05:00
eslint.config.js Store nostr:login in secure storage on native platforms 2026-04-08 22:20:48 -05:00
index.html Disable global pinch-to-zoom via viewport meta 2026-04-17 16:13:40 -05:00
LICENSE Add new file 2026-02-26 21:20:15 +00:00
NIP.md feat: show tracks on playlist detail page with full playback and album support 2026-04-17 15:25:06 -05:00
NOSTR_WEBXDC.md Match NIP headers 2026-02-22 16:35:53 -06:00
opencode.json New project created with Shakespeare 2026-02-16 16:54:01 -06:00
package-lock.json Render webxdc embeds as a tilted, color-tinted cartridge 2026-04-27 01:15:54 -05:00
package.json release: v2.10.5 2026-04-25 03:30:27 -05:00
postcss.config.js New project created with Shakespeare 2026-02-16 16:54:01 -06:00
README.md Remove direct messaging feature and skill 2026-04-26 23:21:54 -05:00
tailwind.config.ts Merge branch 'fix/emoji-shortcode-autocomplete' into 'main' 2026-04-12 14:13:32 +00:00
tsconfig.json Eliminate duplicated schema by deriving DittoConfigSchema from AppConfigSchema 2026-02-26 17:57:55 -06:00
vite.config.ts Upgrade @nostrify/react to ^0.5.0 (async storage support) 2026-04-08 22:08:56 -05:00
zapstore.yaml Add release notes to Zapstore publishing 2026-03-29 15:45:52 -05:00

Ditto

Your content. Your vibe. Your rules. A fun, customizable Nostr client that puts you in control.

ditto.pub | Docs | Source

About

Ditto is an open-source, decentralized social media client built on the Nostr protocol. It's designed for people who want to have fun online without feeding the Big Tech machine. Express yourself with custom themes, Lightning payments, and an ever-growing set of content types -- all while owning your identity and data.

Made by Soapbox.

Features

  • Theming -- 9 built-in theme presets, 19 CSS token properties for full customization, and the ability to publish and share themes as Nostr events
  • Infinite Content Types -- Text notes, articles, short-form videos (Divines), live streams, polls, follow packs, color moments, magic decks, geocaching, and Webxdc mini-apps
  • Lightning Payments -- Zap posts and profiles with sats via Nostr Wallet Connect (NWC) or WebLN
  • Comments -- Comment on anything: posts, URLs, profiles, hashtags, books, and more (NIP-22)
  • Self-Hosting -- Builds to static HTML/JS/CSS. Deploy anywhere -- GitHub Pages, Netlify, Vercel, a VPS, or a Raspberry Pi
  • Mobile -- Android native app via Capacitor, responsive design for all screen sizes

Getting Started

Prerequisites

Development

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

The dev server starts at http://localhost:8080.

Build

npm run build

The built site is output to dist/.

Test

Runs type-checking, linting, unit tests, and a production build:

npm test

Configuration

Ditto is configured through a ditto.json file at the project root, read at build time. This file is gitignored so each deployment can have its own configuration.

{
  "theme": "dark",
  "relayMetadata": {
    "relays": [
      { "url": "wss://relay.ditto.pub", "read": true, "write": true }
    ]
  },
  "blossomServers": ["https://blossom.ditto.pub"],
  "feedSettings": {
    "showPosts": true,
    "showReposts": true,
    "showArticles": true
    // ...and more content type toggles
  }
}

Configuration is resolved in three layers (highest priority first):

  1. User settings stored in localStorage
  2. Build config from ditto.json
  3. Hardcoded defaults

Use an alternate config file path with: CONFIG_FILE=./my-config.json npm run build

Custom Branding

For self-hosted instances:

  • Replace public/logo.svg and public/logo.png with your logo
  • Update the app name in index.html and public/manifest.webmanifest
  • Replace public/og-image.jpg for social sharing previews
  • Set default relays and upload servers in ditto.json

Deployment

Ditto builds to static files and can be deployed anywhere that serves HTML.

  • GitHub Pages / GitLab Pages -- Push to main and CI auto-deploys
  • Netlify / Vercel -- Connect your fork and deploy. A _redirects file is included for SPA routing
  • VPS / Any web server -- Build and copy dist/ to your server. Configure SPA routing (e.g., Nginx try_files $uri $uri/ /index.html)

Android

Build a native Android app with Capacitor:

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 6
Data TanStack Query
Nostr Nostrify + nostr-tools
Mobile Capacitor
Testing Vitest + React Testing Library

Project Structure

src/
  components/     UI components (100+), including shadcn/ui primitives
  hooks/          Custom React hooks (65+)
  pages/          Page components for each route (30+)
  contexts/       React context providers
  lib/            Utilities and shared logic
  test/           Test setup and helpers
public/           Static assets, icons, manifest

Contributing

We welcome contributions but have high standards. Please read the full Contributing Guide before submitting a merge request. The short version:

  • Bug fixes: One bug, one MR. Keep it small and focused.
  • New features: Must link to an existing issue and align with the Ditto Philosophy.
  • Required: Live preview URL, before/after screenshots, completed self-review checklist.
  • Required tools: Claude Opus 4.6 (or latest frontier model), an AI coding agent with plan mode.

Read the Ditto Philosophy to understand what Ditto is and isn't.

License

AGPL-3.0