filemon c48079406d Remove localStorage as source of truth for daily missions
Replace localStorage with an in-memory session store. Kind 11125
content JSON is now the ONLY persistent source of truth for daily
missions.

Architecture:
- On page load / account switch, useDailyMissions hydrates from
  profile.content.dailyMissions (parsed from the kind 11125 event)
- During the session, progress/rerolls update an in-memory Map
- Claims persist to kind 11125 via updateDailyMissionsContent()
- On page refresh the Map is empty → re-hydrates from kind 11125
- Unclaimed progress is lost on refresh (intentional tradeoff vs
  cross-account leakage)

What changed:
- daily-missions.ts: replaced localStorage helpers with in-memory
  Map<pubkey, DailyMissionsState> (sessionStore). readDailyMissionsState
  and writeDailyMissionsState now operate on the Map, not localStorage.
  Added clearDailyMissionsState. Removed getDailyMissionsStorageKey.
- useDailyMissions.ts: accepts persistedDailyMissions option (from
  profile.content.dailyMissions). Hydrates from kind 11125 when the
  session store is empty. Uses persistedMissionToMission() (previously
  defined but never called).
- useClaimMissionReward.ts: reads from session store instead of
  localStorage. Still persists to kind 11125 on claim.
- useRerollMission.ts: reads/writes session store only.
- daily-mission-tracker.ts: reads/writes session store only. Removed
  ensureCurrentState (no longer creates state — the hook handles init).
- BlobbiPage.tsx: passes profile?.content.dailyMissions to useDailyMissions
- BlobbiMissionsModal.tsx: passes profile?.content.dailyMissions to
  useDailyMissions

localStorage usage for daily missions: ZERO
- No localStorage.getItem calls for blobbi:daily-missions
- No localStorage.setItem calls for blobbi:daily-missions
- No blobbi:daily-missions key referenced anywhere in the codebase

Remaining risks:
- Unclaimed progress (feed counts, rerolls) is lost on page refresh
  since only claims persist to kind 11125. A future enhancement could
  persist intermediate state on a debounce, but this is out of scope
  for the foundation phase.
2026-04-06 19:07:34 -03:00
2026-04-06 00:58:23 -05:00
2026-04-06 00:58:23 -05:00
2026-04-06 00:58:23 -05:00
2026-03-16 01:43:42 -05:00
2026-02-16 16:54:01 -06:00
2026-04-06 00:58:23 -05:00
2026-02-26 21:20:15 +00:00
2026-02-22 16:35:53 -06:00
2026-04-06 00:58:23 -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
  • Private Messaging -- End-to-end encrypted DMs (NIP-04 and NIP-17)
  • 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

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%