Replace Vite 6 (esbuild + Rollup) with Vite 8 (Rolldown), reducing
build times from ~12s to ~3.5s. Switch from the archived
@vitejs/plugin-react-swc to @vitejs/plugin-react v6 which uses Oxc
for React Refresh transforms.
Dynamically imports and initializes Plausible when the
VITE_PLAUSIBLE_DOMAIN env variable is set at build time.
When unset, the tracker code is never loaded.
Install Cinzel, Nunito, Quicksand, Courier Prime, and Comic Neue as
bundled fonts and register them in the font registry. Add Unsplash
background images to every new preset (Gothic, Cottage, Candy Heart,
Midnight, Hologram, Floret, Win 95, Plush).
Sentry SDK is loaded via dynamic import() only when a DSN is configured
and error reporting is enabled, keeping it out of the initial bundle.
Users can control error reporting via a toggle and DSN field in
Advanced Settings, with the DSN synced across devices via encrypted
NIP-78 settings. The ErrorBoundary now reports fatal crashes to Sentry
with component stack context, and a beforeSend hook censors nsec
private keys before any data leaves the browser.
Fixes race condition where NBrowserSigner would throw 'Browser extension
not available' when app code accessed signer.nip44 before the extension's
content script had injected window.nostr on page reload.
Add Skater, Kawaii, Grunge, MS Paint, Retro Pop, Bubblegum, and Gamer
theme presets derived from the ditto-1 aesthetic designs. Each preset
includes tailored CoreThemeColors, a display font, and a Blossom-hosted
background image.
Install and register 7 new fontsource display fonts (Permanent Marker,
Cherry Bomb One, Creepster, Silkscreen, Bungee Shade, Luckiest Guy,
Press Start 2P) in the bundled font registry so they appear in the
FontPicker for custom theme building as well.
- Add ThemeConfig wrapper type (colors + fonts + background) replacing bare CoreThemeColors
- Sync theme event parsing/building with NIP.md spec: colors in c tags (hex), fonts in f tags, background in bg tags (imeta-style), empty content field
- Legacy backward compat: parse old JSON-in-content format and bare CoreThemeColors in localStorage/encrypted settings
- Bundle 10 curated fonts via fontsource (Inter, DM Sans, Outfit, Montserrat, Lora, Merriweather, Playfair Display, JetBrains Mono, Comfortaa, Comic Neue) with lazy dynamic imports
- Create font loader (src/lib/fontLoader.ts) for @font-face injection from remote URLs and CSS override application for title/body roles
- Rewrite FontPicker as dual title/body picker using bundled fonts instead of Google Fonts CDN
- Remove Google Fonts integration (useGoogleFont.ts, GoogleFontLoader.tsx)
- Resolve bundled font family names to CDN URLs when publishing to Nostr
- Apply profile theme fonts when visiting other users' profiles
- Update all consumers: AppProvider, useTheme, usePublishTheme, useEncryptedSettings, ThemeSelector, ThemeBuilderPage, ProfilePage, EditProfileForm, InitialSyncGate, NostrSync
- Desktop: Remove redundant Home/Search nav items (logo serves as Home, inline
search covers both quick lookup and full search page navigation)
- Add visual section grouping with labeled separators (Explore, You, Settings)
- Replace ugly dashed 'Add' button with subtle 'More...' inline link
- Add edit mode with drag-and-drop reordering (@dnd-kit) and remove buttons
for content-type items in the Explore section
- Hover-to-remove on desktop content-type items outside edit mode
- Mobile: Replace avatar menu trigger with standard hamburger icon
- Mobile: Add search icon to top bar right side
- Mobile: Redesign bottom nav as 4-tab layout (Home, Explore, Notifications, You)
- Mobile: Explore tab opens bottom sheet with content type links (vaul Drawer)
- Mobile drawer: Replace profile header with logo, restructure to match desktop
sections, add 'Manage...' link for settings, remove redundant Profile link
- Add sidebarOrder to AppConfig for persisting custom item order
- Extend useFeedSettings hook with orderedRoutes, addToSidebar, removeFromSidebar
- Parse NIP-94 dim and blurhash fields in parseImetaMap (NoteCard + PostDetailPage)
- ImageGallery/GridImage: use dim for correct aspect-ratio skeleton sizing; render Blurhash canvas placeholder when available
- VideoPlayer: set aspect-ratio container from dim; show Blurhash canvas before first frame/poster loads
- Install react-blurhash (+ blurhash) for canvas rendering
The old DomainFavicon component had a multi-step fallback chain (HTML scraping,
direct URL guessing, then the configured provider) which meant the configurable
setting was almost never reached. The new ExternalFavicon component uses the
configured favicon URL template directly via RFC 6570 URI templates.
- Rename config field faviconProvider -> faviconUrl
- Add faviconUrl() utility with uri-templates for RFC 6570 support
- Remove local Favicon component from ProfileRightSidebar
- Update all consumers to use ExternalFavicon
- Add webxdcMeta.ts utility to extract name from manifest.toml and
icon (icon.png/icon.jpg) from the .xdc ZIP using fflate
- Upload extracted icon to Blossom during file attach
- Add webxdc_name and webxdc_icon properties to imeta tags
- Parse webxdc_name/webxdc_icon in NoteCard and PostDetailPage
- Show app icon and name in WebxdcEmbed launch card, remove filename
and 'Stateful · shared session' text
- Create useWebxdc hook bridging the Webxdc API with Nostr kind 4079 state updates
- Create WebxdcEmbed component with launch-on-click UX for sandboxed iframe rendering
- Update ComposeBox to accept .xdc files and generate imeta tags with webxdc UUID
- Update NoteCard and PostDetailPage to detect and render webxdc attachments
- Skip .xdc URLs in NoteContent to avoid rendering them as raw links
Implement kind 30311 live streaming events: HLS video player (hls.js),
kind 1311 live chat with real-time subscriptions, stream detail page with
collapsible description on mobile, desktop sidebar chat, streams feed page,
and full extra-kinds integration with sidebar nav and settings.
- Implement Signal-like local-only notifications via direct WebSocket relay polling
- Poll every 60s foreground, 15min background, no external push server
- Resolve NIP-05 display names for notification body (e.g. 'alice@nostr.com reacted to your post')
- Add Capacitor LocalNotifications plugin with POST_NOTIFICATIONS permission
- Replace default Capacitor splash with Mew logo PNG on dark background using Android 12 Theme.SplashScreen
- Add ic_stat_mew vector drawable for notification small icon
- Regenerate splash PNGs with #14161f background
- Install @capacitor/app and @capacitor/status-bar as dependencies
- Initialize StatusBar in App.tsx with dark style and overlay mode
- Add safe-area-top utility class to index.css
- Apply safe-area-top to MobileTopBar component
- Apply safe-area-top to toast notifications on mobile
- Ensures content is not hidden behind device notches/status bars
This reverts the codebase back to the state at commit e693589.
Reverted 1 commit(s):
- 052aca5: Add support for Articles and Recipes (kind 30023)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Added ArticleCard component for displaying long-form content in feeds
- Added ArticleDetail component with markdown rendering for article detail pages
- Created ArticlesFeedPage with optional tag filtering for recipes
- Added /articles and /recipes routes
- Updated PostDetailPage to use ArticleDetail for kind 30023 events
- Added Articles and Recipes to settings toggles (sidebar & feed visibility)
- Integrated articles into Feed component - kind 30023 events now use ArticleCard
- Added react-markdown and remark-gfm for proper markdown rendering
- Articles and Recipes now visible by default in sidebar navigation
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This reverts the codebase back to the state at commit 9ca82c3.
Reverted 4 commit(s):
- 94b43ac: Skip already-cached pubkeys in useAuthors batch query
- ee69816: Adopt Agora's faster feed loading pattern
- 0f630fc: Use Agora's useAuthor pattern: pool race + losers bracket fallback
- 7eafd14: Batch useAuthor and useEventStats to reduce concurrent REQs
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Add useInfiniteScroll hook using native IntersectionObserver (400px rootMargin)
instead of react-intersection-observer library
- Rewrite useFeed: 5s timeout (was 8s), AbortSignal.any pattern, placeholderData
to prevent flicker, cleaner filter construction with spread
- Rewrite Feed.tsx to use useInfiniteScroll ref instead of useInView
- Update ProfilePage.tsx to use useInfiniteScroll for both feed and likes tabs
- Update useProfileFeed: 5s timeout, placeholderData, cleaner filter construction
- Remove react-intersection-observer dependency (replaced by native hook)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>