Commit Graph

55 Commits

Author SHA1 Message Date
Chad Curtis e00a135eb0 Merge branch 'main' of gitlab.com:soapbox-pub/agora into feat/my-square
# Conflicts:
#	src/components/TopNav.tsx
#	src/components/auth/AccountSwitcher.tsx
2026-05-24 16:27:43 -05:00
Alex Gleason 6f187d580f Merge branch 'main' of gitlab.com:soapbox-pub/agora
# Conflicts:
#	src/components/music/MusicTrackRow.tsx
#	src/pages/ActionDetailPage.tsx
2026-05-23 21:09:16 -05:00
Alex Gleason 29fd0c9a0f Remove unused exports and dead code
Aggressive cleanup of 359 exports across 153 files identified as
having zero importers outside their declaring module:

- 105 symbols deleted entirely (no internal uses either)
- 254 symbols un-exported (still referenced file-locally; dropped the
  `export` keyword to shrink the public surface)
- ~70 cascade cleanups of locals that became dead once their sole
  consumer was removed

Notable shrinkage:
- src/hooks/useShakespeare.ts: 626 \u2192 22 lines (unwired AI chat surface;
  only the ChatMessage type is consumed)
- src/hooks/useTrending.ts: only useEventStats survives; trending feed
  hooks were never wired up
- src/hooks/useTrustedCountryStats.ts: dead type re-exports removed
- src/lib/bitcoin.ts: PSBT helpers \u2014 unused wallet feature scaffolding
- src/lib/communityUtils.ts: unused NIP-72 moderation helpers
- src/lib/extraKinds.ts, src/lib/colorUtils.ts: unused helpers
- src/lib/logger.ts: bare debug/info/warn/error exports dropped;
  consumers use the `logger` object
- src/lib/aiChatSystemPrompt.ts: trimmed to the
  DEFAULT_SYSTEM_PROMPT_TEMPLATE constant
- src/components/music/MusicTrackRow.tsx: dead row component removed;
  only the skeleton is consumed

src/hooks/useNostr.ts (intentional decoy) and src/i18n.ts
(side-effect import) were preserved per their respective contracts.
2026-05-23 20:56:43 -05:00
mkfain def426b0e8 i18n: translate LoginArea + AccountSwitcher
Add auth.* namespace (join, login, signup, logout, addAccount). Wire
useTranslation into:

- LoginArea: "Join" button label
- AccountSwitcher: account menu items (Dashboard, Wallet, Notifications,
  Profile, Search, Settings, About reuse nav.* keys; logout and
  addAccount use the new auth.* keys)

AccountSwitcher header NOTE preserved.
2026-05-23 15:43:52 -05:00
filemon d0590a204b Merge branch 'main' into feat/my-square 2026-05-23 16:45:05 -03:00
filemon d192d5ac19 Rename My Square to My Dashboard and add navigation links
- Rename MySquarePage -> MyDashboardPage (file, component, default export)
- Change route from /my-square to /my-dashboard
- Update user-facing copy: SEO title, logged-out heading, JSDoc
- Add 'My Dashboard' link to AccountSwitcher dropdown
- Add 'My Dashboard' entry to TopNav mobile/profile menu
- Use LayoutDashboard icon to distinguish from the existing Dashboard
- Existing /dashboard route and EventDashboardPage are untouched
2026-05-23 16:25:15 -03:00
mkfain 4d13c79633 Rename Help to About, redesign as landing-style page, redesign Donor + Activist guides
Squashed re-application of 15 local commits onto the new route-level
layout system (refactor: replace useLayoutOptions store with route-level
layout choice). Drops the obsolete useLayoutOptions({ fullBleed: true })
calls; the About page and the two guide pages instead live under the
wide FundraiserLayout route group in AppRouter.

Routing

- /about, /about/donors, /about/activists are now the canonical paths,
  in the wide layout (no max-width cap so sections can span the
  viewport with their own backgrounds).
- /help, /help/donors, /help/activists become <Navigate> redirects so
  existing bookmarks and links keep working.

About page (new src/pages/AboutPage.tsx)

A landing-style document modeled on https://soapbox.pub/agora,
brought in-app to explain how the platform works. Five sections:

  1. Hero (dark navy + world-map texture + orange halos), Bebas Neue
     italic headline with an inline orange highlighter behind the
     brand name, three trust chips, and Donor / Activist Guide CTAs.
     Tilted Venezuelan sample-campaign card on lg+, hidden on mobile.
     On mobile the H1 fits on one line via text-4xl + a conditional
     <br className="hidden sm:inline" />.
  2. Three steps. No middleman. (cream) 3-up white cards with 4:3
     step images and corner 01 / 02 / 03 numerals.
  3. Two ways to get paid. (white) Bitcoin Public Payments vs.
     Bitcoin Silent Payments compare cards with gradient header
     strips. Public-Payments trade-off carries the above-ground-
     activism warning; Silent-Payments trade-off is five bold-headline
     bullets (few wallets, slow, no push notifications, buggy,
     no public counts). Below: a primary-tinted No-Custody banner
     plus a 3-column comparison grid (Unlike GoFundMe / Unlike
     GiveSendGo / Unlike other 'Bitcoin' platforms).
  4. Frequently asked. (cream) Three integrated FAQ chapters in
     page flow (Getting started / Bitcoin donations / About Nostr),
     each with a Bebas Neue numeral + Inter Bold heading + card-row
     accordion items with a left orange accent on hover/open.
  5. Pick the side you're on. (white) Two large image-led guide
     cards (Donor / Activist) using the soapbox.pub photography.
     Closes with a quiet 'Still stuck? Follow Team Soapbox' line
     linking in-app to the pack via the /:nip19 route.

Typography is Bebas Neue (font-display) italic font-normal with
WebkitTextStroke for the hero H1 and the step numerals only; every
other heading uses Inter Bold (font-sans font-bold tracking-tight).
Bebas Neue is never font-bold (synthetic bold renders as smear at
display sizes).

Em dashes have been removed throughout the page and the
HelpFAQSection component. Box-drawing chars (U+2500) in section
banner comments are not em dashes and stay.

Section backgrounds alternate dark → cream → white → cream → white.
The dark and cream sections keep their literal palette in both light
and dark mode (an editorial choice that gives the page its
landing-page identity rather than being just another themed surface).

Donor + Activist Guides (new block-based design)

Both pages now compose from a typed sequence of GuideBlock variants
defined in helpContent.ts. Each block kind is rendered by a dedicated
component under src/components/guide/:

- GuideTLDR              top-of-page summary card with lede + checklist
- GuideSteps             numbered vertical flow of short steps
- PaymentComparisonTable Public vs. Silent side-by-side. Three-column
                         grid on desktop, two stacked tinted cards on
                         mobile. Row content driven by audience flag.
- CalloutCard            tinted info / warning / danger / success blocks
- OptionGrid             two-column tile grid for privacy and cash-out
                         options
- GuideProse             plain prose escape hatch
- InlinePaymentBadge     small pill that distinguishes the two payment
                         options
- index.ts               barrel

Content is rewritten throughout to reflect current reality: campaigns
can accept Public only, Silent only, or both; the QR code carries
both endpoints when both are accepted; wallets without silent-
payments support fall back to a regular Bitcoin transaction; silent
payments are slow, scan-based, lack push notifications, are
bleeding-edge, and produce no public donation counts.

Activist Guide structure:

  TLDR
  How receiving works
  What everyone can see           (intentionally before the table)
  Public vs. Silent comparison
  A note on silent payments today (calm prose, not an alarm callout)
  Move donations promptly
  Cashing out privately           (silent-payments hop, Lightning
                                   swap, coinjoin, P2P with brokers,
                                   spend it directly)
  Avoid centralized tumblers

Donor Guide structure:

  TLDR
  How a donation flows
  Public vs. Silent comparison
  Public donations are visible on-chain forever callout
  Donating privately option grid
  Consumer apps can't make you anonymous callout
  A note on silent payments today

Other touchpoints

- Sidebar (sidebarItems.tsx): Help label → About, icon LifeBuoy → Info,
  path /help → /about.
- Top nav profile menu (TopNav.tsx): Help → About.
- Site footer (AppRouter.tsx inline): Help → About.
- AccountSwitcher dropdown: Help → About.
- LandingHero FAQ button → /about#faq.
- HelpTip popover footer link → /about#faq.
- GuideHero back link → /about, label 'Back to About', wider
  max-w-5xl on lg+ container so it sits well on the now-full-bleed
  hero. Inner overlay min-height bumped to 320px on lg+.
- CampaignsPage 'How it works' button → /about.

New assets in /public/about/ pulled from soapbox.pub:

- world-map-bg.png (hero + textures)
- venezuela-libertad-presos-politicos.png (hero sample-card image)
- donor-guide-freedom-libertad.jpeg
- activist-guide-unity.png

Step photos in /public/help/ (step-1-account.jpg, step-2-send.jpg,
step-3-spend.jpg) for the Three Steps section.

HelpFAQSection gains:

- variant: 'list' | 'cards' (default 'list')
- tabs: boolean (only meaningful with variant='cards')
- listTone: 'default' | 'reference' (quieter category labels and more
  breathable accordion items for the About page; existing inline
  callers keep the default pill style)

In 'reference' mode each accordion item gets a card-row treatment
(rounded white card, subtle border, hover lifts to primary/40 border,
left orange accent rule driven off data-state=open).

helpContent.ts FAQ content (FAQItem / FAQCategory and templates) is
left untouched. Only the donor/activist guide section was rewritten
into GuideBlock[] arrays.
2026-05-23 13:38:13 -05:00
lemon 11a51509ae Improve save key warning contrast 2026-05-22 23:37:32 -07:00
Alex Gleason 93108bc00e AuthDialog: mark nsec login form with data-nsec-allowed
The nsec paste guard (useNsecPasteGuard) bails out when the paste
target has id="nsec" or sits inside [data-nsec-allowed], but the
login form had neither marker, so pasting an nsec into the login
field triggered the "Secret key detected" toast and was blocked.
2026-05-22 16:45:38 -05:00
Alex Gleason d4590a9340 Brighten the account switcher chevron on hover 2026-05-20 14:00:21 -05:00
Alex Gleason 3c330efaa9 Compact the top-nav account switcher trigger 2026-05-20 13:58:54 -05:00
Alex Gleason 89c392fa63 Remove Start Campaign button from top nav; brighten Join contrast 2026-05-20 13:49:36 -05:00
Alex Gleason aa5f5d7640 Brand the auth dialog with the Agora bolt mark
Replaces the generic key emoji / lucide Key icons on the welcome,
generate, and secure steps with AgoraBoltIcon (matching the rest of
the app's onboarding chrome). Personalizes the dialog title with the
app name and clarifies the welcome buttons to 'Create a new Nostr
account' / 'Log in to an existing account'.
2026-05-18 20:57:29 -05:00
Alex Gleason 0b1caeffa7 Unify auth into a single Join button using MKStack AuthDialog
Replaces the separate Log in / Sign up entry points with one Join
button that opens AuthDialog (welcome -> create-account or log-in).
Drops the full-screen SetupQuestionnaire signup flow, LoginDialog,
SignupDialog, and the useOnboarding context.

Removes InitialSyncGate so the app no longer blocks on initial
encrypted-settings / relay-list / mute-list sync. The same side
effects now run via InitialSyncRunner, mounted alongside NostrSync
at the top of the tree, so settings still get pulled and seeded
into the query cache on login \u2014 just in the background.
2026-05-18 20:53:15 -05:00
lemon 58bb3046e7 Reorganize sidebar navigation 2026-05-18 10:43:49 -07:00
lemon ef9adb29e8 Update primary navigation 2026-05-18 10:30:15 -07:00
lemon e91f4a2c63 Move help to account menu 2026-05-18 09:55:18 -07:00
lemon 77b35995eb Align top nav controls 2026-05-18 09:41:59 -07:00
lemon 94bcf23b68 Improve account menu 2026-05-18 09:37:46 -07:00
Alex Gleason 740fc1c63c Merge ditto/main into agora
Pulls in 387 commits from ditto/main while preserving Agora-specific
features. Where the two codebases diverged on the same concept, kept
the Agora side per project direction.

Kept Agora-specific:
- SparkWallet stack (over Ditto's nostr-derived Bitcoin wallet)
- Communities (NIP-72 + chat + members), Messages, Organizers,
  Actions, Verified, Appearance settings
- DMProviderWrapper, country/organizer moderation in NoteMoreMenu
- 'Agora' branding, pub.agora.app bundle ID, version 2.8.0
- Built-in theme system (src/themes.ts) only

Rejected from Ditto:
- All Blobbi virtual pet code (80+ files, route, provider, sidebar,
  kind labels, feed setting, NIP.md entries, CSS animations)
- Custom theme events (kinds 36767/16767) — ThemesPage, ThemeContent,
  active profile themes, theme snapshot recovery
- On-chain zaps (kind 8333) and the entire Bitcoin wallet implementation
  (useBitcoinWallet, bitcoin-signers, BitcoinContentHeader,
  bitcoinjs-lib / @bitcoinerlab/secp256k1 / ecpair / tiny-secp256k1)
- ZapSuccessScreen (depended on dropped bitcoin lib)

Pulled in from Ditto:
- .agents/skills/* (12 new specialized skills, slim AGENTS.md)
- @nostrify bumps to 0.52 / 0.6 / 0.37
- New routes/pages: Music, Podcasts, Videos, Vines, Wikipedia, Books,
  Bluesky, Archive, AIChat, Trends, Webxdc, Highlights, Decks, Emojis,
  Development, Treasures, Colors, Packs
- Birdstar feed integration (kinds 2473, 12473, 30621)
- Wikipedia/Wikidata/Scryfall lookup in ExternalContentPage
- release-notes CI job + extract-release-notes.mjs script
- nsite:// URI handling in feed/sidebar
- iOS fastlane setup
- src/lib/avatarShape.ts + Avatar shape prop (kept for new Music/People
  components that depend on it)

Preserved Agora's ABSOLUTE 'NEVER COMMIT' rule at the top of AGENTS.md
and dropped Ditto's contradicting 'Commit at the end of every task'
section.

Validation: npm run test passes (tsc, eslint, 40/40 vitest, vite build).
2026-05-13 18:35:03 -05:00
sam e12716722a remove shape stuff 2026-05-11 14:49:11 +07:00
Alex Gleason 0497aa33c9 Show live progress during the nostrconnect login handshake
When a user tapped "Open Signer App", the dialog previously stayed
frozen on the same screen — same button, same copy-URI fallback, no
feedback — until the login either succeeded (and the dialog dismissed)
or timed out after two minutes. With slow or flaky signers (Amber's
current listening-REQ bug being the immediate trigger, but any NIP-46
signer that takes more than a second or two to respond hits the same
hole) this looked indistinguishable from a hang. Users retapped the
button, closed the dialog, gave up.

Now the dialog swaps the QR / Open Signer App area for a centered
spinner with a live status line as the handshake advances:

- "Waiting for signer connection…" while the signer app has the user
  and we're listening on kind 24133 for the connect-ack.
- "Getting public key…" once the connect-ack arrives and we're
  issuing the NIP-46 get_public_key RPC.

On mobile the swap happens synchronously when the user taps "Open
Signer App" so they see the progress state the moment they return
from the signer — this is the most important window, since that's
exactly when the original UI left them staring at a button they
were worried they needed to re-tap. On desktop the QR stays visible
through the awaiting-connect phase (they may still be scanning with
a different device) and only swaps in once the signer has
acknowledged.

The progress view includes a Cancel link (primary color, matches the
"Create account" affordance) that aborts the in-flight subscription
and regenerates fresh connect params — equivalent to the existing
Retry path, but reachable while the handshake is live instead of
only after a failure.

The handshake phases are surfaced via the new `onStatus` callback
on `NLogin.fromNostrConnect` in @nostrify/react 0.6.0. Bumps
@nostrify/react to ^0.6.0 and @nostrify/nostrify / @nostrify/types
to their matching versions (^0.52.0 / ^0.37.0) to avoid duplicate
nested package copies that would otherwise split type identity.

Incidental cleanup while editing the dialog: the Copy URI button and
the "Tap to open your signer app" / "Scan with your signer app"
status lines are removed. The primary Open Signer App button is
self-explanatory on mobile, and the QR on desktop doesn't need a
caption.
2026-05-04 21:42:45 -05:00
Alex Gleason 0d1fe7bbca Fix nostrconnect listen effect losing successful logins on re-render
The nostrconnect listening effect depended on `login`, `onLogin`,
`onClose`, and `isWaitingForConnect`. `login` is a fresh object from
useLoginActions on every render, and every call site passes inline
arrow functions for onLogin/onClose, so the effect re-ran on every
parent render. Each re-run fired the cleanup and flipped a local
`cancelled = true` flag, and when the signer's NIP-46 response
eventually arrived, the success branch saw `cancelled === true` and
silently skipped `onLogin()` / `onClose()` — the user was logged in on
the backend but the dialog never closed.

Stabilize onLogin/onClose/login via latest-value refs, narrow the
effect deps to `[nostrConnectParams]` only, and gate the success
branch on `controller.signal.aborted` (which is only true when the
dialog was explicitly closed or handleRetry fired). Drop the unused
`isWaitingForConnect` state. Also abort the in-flight controller from
handleRetry before regenerating params, so the prior subscription
doesn't linger.

The bug was masked by most signers responding fast enough (<1s) that
parent re-renders didn't happen during the wait. It surfaced during
an upstream Amber bug that delays its listening REQ by ~8+ seconds,
giving render cycles time to fire (https://github.com/greenart7c3/Amber/pull/420).
The Amber bug is getting fixed separately; this Ditto fix stands on
its own — any signer that takes a few seconds to respond could trip
the same race.
2026-05-04 21:16:38 -05:00
Alex Gleason 981e4f0726 Prefer metadata.name, fall back to metadata.display_name everywhere
Previously getDisplayName() and ~50 inline sites only consulted
metadata.name, ignoring display_name. A handful of other sites used the
opposite priority (display_name || name), so the same user could render
under different names across the UI.

Standardize on `name || display_name || genUserName(pubkey)` in the
helper and at every call site, and widen two local inline metadata types
in RightSidebar and SearchPage that did not declare display_name.
2026-04-30 01:30:07 -05:00
Alex Gleason a2f2d9ff89 Add configurable shareOrigin to AppConfig
window.location.origin resolves to capacitor://localhost on iOS and
https://localhost on Android, which produces broken QR codes, broken
copy-link actions, and a broken remote-login callback URL on native
builds.

Add an optional shareOrigin field to AppConfig and a useShareOrigin
hook that falls back to window.location.origin when unset. Replace
all 13 call sites that build shareable URLs.

The origin can be configured three ways, in order of precedence:
user localStorage > ditto.json > VITE_SHARE_ORIGIN env var. Native
deployments can set VITE_SHARE_ORIGIN=https://ditto.pub at build time
so that shared URLs resolve correctly when opened on another device
(and get caught by DeepLinkHandler when opened on the same app via
Universal/App Links).

Regression-of: a12d5db5
2026-04-17 22:39:44 -05:00
Alex Gleason dabe3c1687 Fix avatar shape not saving during signup
The signup and onboarding profile steps rendered ProfileCard without
passing onAvatarShape, so emoji shape selections were silent no-ops and
never made it into the published kind 0 event.
2026-04-16 17:06:27 -05:00
Alex Gleason 0fca39a1bd Remove androidResume utility and its foreground-resume retry logic
The visibility-change-based Android resume detection was causing more
problems than it solved. Remove the module and simplify LoginDialog and
signerWithNudge to operate without retry-on-resume behavior.
2026-04-12 11:37:10 -05:00
Alex Gleason 207ca6893a Add iCloud Keychain credential saving/restoring on iOS via @capgo/capacitor-autofill-save-password
- Use SecAddSharedWebCredential to prompt 'Save Password?' on signup
- Use ASAuthorizationPasswordProvider to restore credentials on login
- Add webcredentials:ditto.pub Associated Domains entitlement
- Deploy apple-app-site-association for domain validation
- Keep existing Chromium PasswordCredential flow as web fallback
- Add saveNsec() helper: native credential manager on iOS/Android,
  file download + bonus PasswordCredential on web
- Single 'Continue' button triggers the appropriate save method per platform
2026-04-11 14:01:34 -05:00
Alex Gleason 874010c4fe Store nsec in browser password manager via Credential Management API
Progressive enhancement using PasswordCredential (Chromium-only).
On sign-up, the nsec is offered to the browser's password manager
alongside the existing file download. The prompt appears while the
user is looking at their key on the download step. On login, stored
credentials are retrieved for one-tap login on supported browsers.

Safari/Firefox/iOS silently skip — existing flows are unchanged.
2026-04-10 21:49:14 -05:00
Alex Gleason adadb6ed53 Fix native file downloads: save directly to Documents on iOS/Android 2026-04-08 22:54:46 -05:00
Alex Gleason c77c098843 Add NIP-24 published_at to useNostrPublish for replaceable/addressable events
Extend useNostrPublish with an optional `prev` property on the event
template. For replaceable and addressable kinds, the hook automatically
manages published_at:

- First publish (no prev): set published_at equal to created_at
- Update (prev provided): preserve published_at from the old event
- Old event lacks published_at: don't fabricate one
- Caller already set published_at in tags: leave it alone

Callers pass `prev` when they have the old event from fetchFreshEvent,
giving the hook everything it needs without extra network requests.
Updated all 11 call sites that publish replaceable or addressable events.
Documents the prev convention in AGENTS.md.
2026-04-05 14:23:58 -05:00
Chad Curtis 08e26e28d0 Fix key download path: save to Download/ instead of Documents/ 2026-03-28 21:58:53 -05:00
Chad Curtis b1c61a7888 Fix Amber login on Android: retry nostrconnect subscription on foreground resume 2026-03-28 21:51:17 -05:00
Chad Curtis e951a3b00a Fix key download on Android: save to Documents instead of share sheet 2026-03-28 21:47:47 -05:00
Alex Gleason da27054a9b Fix file downloads and URL opening on Capacitor iOS
The <a download> and <a target="_blank"> patterns don't work in
WKWebView. Add downloadTextFile() and openUrl() utilities in
src/lib/downloadFile.ts that use @capacitor/filesystem and
@capacitor/share on native platforms, falling back to standard
browser behavior on web.

Update all call sites: onboarding key download (InitialSyncGate,
SignupDialog), image lightbox buttons (ImageGallery, ProfilePage).

Document Capacitor compatibility constraints in AGENTS.md.
2026-03-27 16:42:36 -05:00
Alex Gleason 0666278a58 refactor: use @nostrify/react@0.3.0 for client-initiated NIP-46
Replace inline nostrconnect:// protocol logic with NLogin.fromNostrConnect(),
generateNostrConnectParams(), and generateNostrConnectURI() from upstream
@nostrify/react. Removes ~130 lines of code that is now in the library.
2026-03-24 16:21:00 -05:00
Lemon f91a37914c fix: prevent iOS Safari auto-zoom on input focus 2026-03-17 19:55:18 +00:00
Alex Gleason 10bb16abfb Clean up avatar shape code: remove magic strings, type casts, and inconsistencies
- avatar.tsx: consolidate to single isEmojiShape boolean, fix AvatarFallback using same logic as Avatar
- avatarShape.ts: accept NostrMetadata directly in getAvatarShape (no cast needed)
- Remove 'as Record<string, unknown>' casts from all ~50 call sites
- Replace 'circle' magic string with empty string in form defaults and parseShape
- Use isValidAvatarShape instead of string comparison in save logic
- ProfileCard: extract IIFE overlay style into useMemo, use isEmojiShape throughout
2026-03-13 21:14:03 -05:00
Alex Gleason 3b79b384e5 Add avatar shapes: users can set a shape (circle, triangle, hexagon, star, etc.) for their avatar via kind 0 metadata
- New 'shape' property on kind 0 profile metadata with 7 predefined shapes:
  circle, triangle, inverted-triangle, hexagon, star, inverted-star, hexagram
- Avatar component updated with clip-path support for non-circle shapes
- Visual shape picker added to both EditProfileForm and ProfileSettings
- Shape applied across all 49 avatar render sites in the app
- New UserAvatar wrapper component for future simplified avatar rendering
- Unknown shape values gracefully fall back to circle (forward compatible)
2026-03-13 16:14:40 -05:00
Alex Gleason bed84c6285 Fix iOS Safari auto-zoom on input focus by ensuring 16px minimum font size on mobile 2026-03-07 11:42:54 -06:00
Chad Curtis 7aaa3e2587 Add interactive profile editor with live card, image crop, and onboarding integration 2026-03-03 07:31:06 -06:00
Alex Gleason fad790be16 Extract non-component exports to separate modules to fix react-refresh warnings
Move helper functions, types, and constants out of component files into
dedicated lib/hooks modules so each component file only exports components:

- getContentWarning -> src/lib/contentWarning.ts
- isCustomEmoji, getCustomEmojiUrl, buildEmojiMap, ResolvedEmoji, resolveReactionEmoji -> src/lib/customEmoji.ts
- ExternalContent, parseExternalUri, formatIsbn, headerLabel, seoTitle -> src/lib/externalContent.ts
- extractYouTubeId, extractTweetId, and other URL helpers -> src/lib/linkEmbed.ts
- isSingleImagePost -> src/lib/noteContent.ts
- useOnboarding, OnboardingContext -> src/hooks/useOnboarding.ts

Also un-exported module-private symbols in VinesFeedPage and SettingsPage.
2026-03-01 22:15:47 -06:00
Alex Gleason d147a25590 Fix all ESLint errors and warnings across 15 files 2026-03-01 21:59:19 -06:00
Alex Gleason 713bf52cfb Add configurable appName to AppConfig, replacing hardcoded 'Ditto' in page titles and UI text
All runtime references to 'Ditto' now use config.appName, which defaults
to 'Ditto' and can be overridden at build-time via ditto.json. This
covers useSeoMeta titles across all pages, the welcome screen, feed CTA,
Nostr Connect app name, encrypted settings event title, and the
AdvancedSettings zap comment placeholder.
2026-02-28 17:09:37 -06:00
Alex Gleason a87b6c3c02 Show skeleton loading states for avatars and names while profile is fetching
Replace the '?' avatar fallback and 'Anonymous' name placeholder with skeleton
loaders in ComposeBox and LeftSidebar during initial profile load. Expose
isLoading from useCurrentUser and useLoggedInAccounts to support this.
2026-02-23 13:37:44 -06:00
Alex Gleason 1f035f4a6e Rename Mew to Ditto across entire codebase
- Update all branding: titles, meta tags, OG tags, manifest
- Rename MewLogo component to DittoLogo
- Update Capacitor config: appId to pub.ditto.app, hostname to ditto.pub
- Migrate Android Java package from com.mew.app to pub.ditto.app
- Rename MewNotificationPlugin to DittoNotificationPlugin
- Update all localStorage keys from mew: to ditto: prefix
- Update Nostr encrypted settings d-tag from mew-metadata to ditto-metadata
- Update all page titles, zap comments, and UI strings
- Rename ic_stat_mew.xml drawable to ic_stat_ditto.xml
- Update build script references (mew.apk -> ditto.apk)
- Update all domain references (mew.shakespeare.wtf -> ditto.pub)
2026-02-23 11:50:00 -06:00
Chad Curtis 43e501ad74 Improve onboarding: add profile fields, fix sync gate for logged-out users, update profile cache
- Move 'New here?' link above extension login button
- Use profile-intro.png instead of MewLogo on profile step
- Add 'More details' collapsible with banner, website, and custom fields
- Skip sync/onboarding when logged out (guard in InitialSyncGate)
- Persist sync completion in localStorage instead of sessionStorage
- Initialize sync phase synchronously to prevent flash on refresh
- Invalidate author cache after profile publish for immediate updates
2026-02-21 03:42:02 -06:00
Chad Curtis 1d967b98d0 Integrate signup into onboarding flow, replace SignupDialog
Sign up now triggers the full onboarding overlay instead of a dialog.
The flow starts with keygen -> download key (logs in) -> profile setup
(kind 0) -> then continues with the existing settings questionnaire
(theme, content, safety, follows, outro).

Added OnboardingContext with useOnboarding().startSignup() hook so any
component can trigger the signup flow. Updated LoginArea, Feed,
LeftSidebar, and FloatingComposeButton to use it instead of
SignupDialog. SignupDialog is no longer imported by any component.
2026-02-20 22:18:51 -06:00
Chad Curtis 3e7ba143f9 Add user-configurable settings for Blossom servers, zap comment, favicon provider, CORS proxy, and NIP-46 relays
- Add blossomServers (array), defaultZapComment, faviconProvider, corsProxy to AppConfig
- Blossom servers: multi-server support with add/remove UI matching relay list pattern
- Default zap comment changed from 'Zapped with MKStack!' to 'Zapped with Mew!'
- NIP-46 nostrconnect now uses the user's write relay list instead of hardcoded relay
- CORS proxy and favicon provider use {href} URI template pattern
- New 'System' section in Advanced Settings for zap comment, favicon provider, CORS proxy
- Fix ghost button hover text color on light/pink themes across settings panels
- Fix pre-existing TSC errors: appRelays array typing, muteHelpers dead code, ProfilePage FeedItem type, EditProfileForm useFieldArray, FeedSettingsForm/ContentSettings feedKey narrowing, LeftSidebar icon type
2026-02-19 17:51:51 -06:00
shakespeare.diy bc95237b7c Fix React error #300 when logging out
The error occurred because the AccountSwitcher component was returning null while the DropdownMenu was still mounted and open. This caused React to throw a minified error #300 about invalid elements.

The fix ensures the dropdown menu is closed before removing the login, preventing the component from being unmounted while still rendering its dropdown content.

Changes:
- Added controlled state for dropdown menu (isOpen/setIsOpen)
- Created handleLogout function that closes dropdown before removing login
- Used setTimeout to ensure dropdown closes before state update

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
2026-02-18 20:12:35 -06:00