Changed tab order to show Community before Global:
- Follows (always first when logged in)
- Community (when enabled - e.g., "Ditto")
- Global (when enabled)
Rationale: Community is more curated/relevant than Global, so it should appear before the global firehose.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
When downloading a community:
- Extract label from hostname (ditto.pub → "Ditto")
- Capitalize first letter of hostname
- Store label in community object
- Auto-enable Community Feed toggle
- Display label in feed tab instead of generic "Community"
Community card display:
- Show label as primary text (e.g., "Ditto")
- Show domain + user count in secondary text
- Format: "Ditto" with "ditto.pub • 247 users"
Feed tab:
- Load community label from localStorage
- Display as tab name (e.g., "Ditto" instead of "Community")
- Falls back to "Community" if no label found
Removing community:
- Auto-disables Community Feed toggle
- Clears all community data
- Returns to input state
Examples:
- ditto.pub → "Ditto" tab
- spinster.xyz → "Spinster" tab
- bitcoinhackers.org → "Bitcoinhackers" tab
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Added proper repost handling to Community feed (was missing):
- Process kind 6 (repost) events same as Follows feed
- Parse embedded JSON content from repost
- Fetch missing reposted events in batch query
- Deduplicate events (prefer original over repost)
- Sort by repost timestamp when displaying reposts
- Maintain repostedBy context for UI display
Community feed now handles:
- Direct posts (kind 1)
- Reposts (kind 6) with embedded content
- Reposts (kind 6) with e-tag reference
- Extra content types (vines, polls, etc.)
- All with NIP-05 domain verification
Fixes the broken repost display showing raw JSON instead of parsed content.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Now only shows posts from users with matching NIP-05 domain in their profile:
1. Query events from all pubkeys in the community NIP-05 JSON
2. Fetch kind 0 metadata for all authors in the results
3. Extract nip05 field from each author's profile
4. Filter events to only include authors whose nip05 ends with @domain
5. Example: ditto.pub community only shows users with nip05 ending in "@ditto.pub"
This ensures the Community feed respects current NIP-05 verification status:
- Users must have the matching domain in their current profile
- If a user changes their NIP-05 to a different domain, they're filtered out
- Prevents showing posts from users who left the community
- Maintains trust model based on current verification state
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Changes to support only one community at a time:
Settings (ContentSettings):
- Changed from communities array to single community object
- Storage: mew:community (single object) instead of mew:communities (array)
- Storage: mew:communityData (NIP-05 JSON) instead of mew:community:{domain}
- Changed "Communities Feed" → "Community Feed" in UI
- Changed showCommunitiesFeed → showCommunityFeed in localStorage
- Show input when no community set, show card when community exists
- Remove button clears the single community
- Updated placeholder to "ditto.pub"
Feed component:
- Changed showCommunitiesFeed → showCommunityFeed
- Changed tab label "Communities" → "Community"
useFeed hook:
- Simplified to load single community data from mew:communityData
- Extracts pubkeys directly from NIP-05 names object
- No longer loops through multiple communities
Benefits:
- Simpler UX - one community at a time
- Cleaner data model
- Less storage complexity
- Clear visual state (input vs community card)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Feed component changes:
- Added "communities" as a feed tab type
- Load showGlobalFeed and showCommunitiesFeed from localStorage
- Conditionally render Global tab based on setting
- Conditionally render Communities tab based on setting
- Tab buttons dynamically appear/disappear based on user preferences
useFeed hook changes:
- Extended to support 'communities' tab type
- Loads community list from localStorage (mew:communities)
- Fetches NIP-05 JSON data for each community
- Extracts all pubkeys from community NIP-05 data
- Queries posts from all community members
- Returns feed filtered to community pubkeys
- Includes all enabled content types (vines, polls, etc.)
How it works:
1. User adds communities in Settings > Content > Feed Tabs
2. User enables "Communities Feed" toggle
3. Communities tab appears in main feed navigation
4. Shows posts from all users in added communities
5. Respects NIP-05 verification (only shows users in the JSON)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Added toggle to enable/disable Communities feed tab
- Stored in localStorage (mew:showCommunitiesFeed)
- Defaults to disabled (false)
- Toggle is disabled when no communities are added
- Description updates dynamically showing community count
- Toast notifications on toggle
- Positioned next to Global feed toggle for consistency
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Moved border-b-2 from wrapping div to CollapsibleTrigger button
- Border now appears at section title instead of bottom of content
- Consistent with Other Stuff section styling
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Added back the feed-intro.png image
- Added back "Other Stuff" heading and description inside collapsible
- Matches styling of Feed Tabs and Muted Content sections
- Consistent visual presentation across all collapsible sections
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Major additions to Content settings:
1. Renamed "Content Types" → "Other Stuff" (now collapsible)
- Moved intro image and description into collapsible section
- Defaults to OPEN for easy access
2. Added new "Feed Tabs" section (collapsible, defaults to CLOSED)
- Community management feature
- Download NIP-05 JSON from any domain
- Fetches https://domain/.well-known/nostr.json
- Parses user list and stores locally
- Shows user count for each community
- Remove communities with X button
- Communities stored in localStorage (mew:communities + mew:community:{domain})
- Placeholder for feed tab toggles (Global, Communities, etc.)
Community feature details:
- Input validates and cleans domain (removes protocol, trailing slash)
- Prevents duplicate communities
- Shows loading state during fetch
- Error handling for invalid domains or JSON format
- Stores both community list and raw JSON data for feed filtering
- Clean, consistent UI matching existing patterns
Structure:
- Feed Tabs (new)
- Other Stuff (renamed from Content Types)
- Muted Content (existing)
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Changed section headers from text-sm to text-base font-semibold
- Changed border-bottom from border-border to border-b-2 border-primary (thicker accent color)
- Increased vertical padding on collapsible triggers (py-3.5 instead of py-3)
- Added "Other Stuff" as a static section header above Content Types
- Moved "Other Stuff" description to static section instead of collapsible content
- Removed duplicate description from Muted Content internals
Visual improvements:
- Section headers now stand out more with larger, bolder text
- Accent-colored borders create clearer visual hierarchy
- Static "Other Stuff" section provides context before collapsible sections
- More consistent with modern settings UI patterns
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Major restructure to improve UX for less technical users:
- Consolidated "Feed" + "Mutes" → "Content" tab
- Moved "Wallet" + "Relays" → "Advanced" tab
- Reduced from 5 tabs to 3 tabs with collapsible sections
New structure:
- Profile: Identity settings (unchanged)
- Content: Content Types, Muted Content (with placeholders for Communities, Sensitive Content)
- Advanced: Wallet, Network (relays)
Implementation details:
- Created ContentSettings component with collapsible sections
- Created AdvancedSettings component with collapsible sections
- Content Types section defaults to OPEN
- Muted Content section defaults to CLOSED
- Wallet/Network sections default to CLOSED
- All sections use consistent collapsible UI pattern
- Updated settings page description
- Maintains all existing functionality
Benefits:
- Cleaner mental model for new users
- Power user features hidden but accessible
- Room to grow (Communities, Sensitive Content placeholders)
- Reduced cognitive load with fewer top-level tabs
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Added intro section with relay-intro.png image and description
- Reorganized layout with cleaner visual hierarchy and border separators
- Reduced font sizes for consistency (text-xs, text-sm labels)
- Removed rounded borders and card-style backgrounds
- Added hover states to relay rows (hover:bg-muted/20)
- Improved spacing and padding throughout
- Smaller icon sizes (h-4 w-4 for relays, h-5 w-5 for section headers)
- Reduced button sizes and input heights (h-9) to match other tabs
- Simplified "Add Relay" button text and styling
- Updated popover label sizes to text-xs for consistency
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Added intro section with profile-intro.png image and description
- Reorganized form layout with cleaner visual hierarchy and border separators
- Reduced font sizes and spacing to match feed tab style (text-xs labels)
- Moved "Bot Account" setting under collapsible "Advanced Settings" section
- Improved input heights (h-9) and button sizes for consistency
- Enhanced image upload field styling with smaller previews and buttons
- Updated form descriptions to be more concise
- Added proper spacing with border-b separators between sections
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Changed from my-4 to mt-4 mb-1 for tighter spacing with description text
- Reduces bottom margin to bring header closer to tabs
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Added "Manage your profile, feed, and preferences" subtitle
- Restructured header layout to accommodate description text
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Renamed formatClientName to formatClientInfo, returns { name, url? }
- Client names derived from URLs/hostnames are now clickable links
- Links open in new tab with noopener/noreferrer for security
- Plaintext client names remain as non-linked text
- Added stopPropagation to prevent navigation when clicking client link
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Use flex with items-center to properly vertically center the dot
- Separate each element (client name, dot, date) into individual spans
- Use gap-1.5 for consistent spacing between elements
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Updated formatClientName() to handle three formats:
1. Full URLs (https://example.com)
2. Hostnames (example.com, mew.shakespeare.wtf)
3. Plaintext client names (Amethyst, Primal, etc.)
- Check known client map before and after URL parsing
- Return plaintext client names as-is if no mapping found
- Capitalize hostname-based clients for unknown sources
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Created formatClientName() helper function to extract and format client names from client tags
- Maps known hostnames (gleasonator.dev, ditto.pub, mew.shakespeare.wtf) to friendly names
- Falls back to capitalizing unknown hostnames
- Display client name to the left of date with dot separator in both stats and date-only rows
- Extracted client tag from event.tags using useMemo for performance
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This reverts the codebase back to the state at commit da5835b.
Reverted 1 commit(s):
- e905087: Change client tag to 'Mew' instead of hostname
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Use 'Mew' as the client name for encrypted metadata events instead of the deployment hostname, providing consistent client identification across all deployments.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Changed from 'mew-settings' to 'mew-metadata' to better reflect that this event stores various types of app state including settings, notification cursor, and other metadata.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
The useMutation hook creates a new object on every render, causing markAsRead to be recreated constantly. Removed updateSettings from the dependency array and only depend on stable values. Also changed the effect to only trigger when there are NEW notifications, not all notifications.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
The markAsRead function was being recreated on every render, causing the NotificationsPage effect to run continuously and trigger a signature request every second. Now properly memoized with useCallback.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
The markAsRead function now checks if the cursor would actually change before calling updateSettings. This prevents unnecessary signature requests when notifications are already marked as read. The NotificationsPage was triggering markAsRead every 60 seconds when the query refetched, even though nothing changed.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Set staleTime and gcTime to Infinity for encrypted settings queries to prevent constant refetching and decryption requests. Queries only run once on mount and when explicitly invalidated after writes. This fixes the spam of kind 30078 signature requests.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Users can now paste images directly from clipboard into the compose box. Images are automatically uploaded to Blossom and the URL is inserted into the content.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Move image/video extraction before hasPreviewableContent check to avoid accessing variables before initialization.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
The Edit/Preview segmented control now appears when content contains images or videos, not just link previews. Previously it only showed for non-media URLs, so pasting image URLs wouldn't trigger the preview mode.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
Preview mode now properly renders images (including SVGs) and videos inline, matching the behavior of PostDetailPage and NoteCard. Previously NoteContent was skipping media URLs expecting the parent to render them, but preview mode wasn't extracting and displaying media.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Include SVG URLs in link preview detection (LinkPreview checks content-type to handle both images and OG pages)
- Add proper imeta tags (NIP-92) for all media URLs in posts
- Store uploaded file metadata and use full NIP-94 tags in imeta
- Reduce encrypted settings decryption spam by disabling refetchOnWindowFocus and refetchOnReconnect
- Replace Switch with modern segmented control for Edit/Preview toggle
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Preview switch only appears when there are embeds to preview
- Hidden when content is just plain text
- Shows when detecting: URLs, nevent1, note1, naddr1, nostr: URIs
- Prevents unnecessary preview mode for text-only posts
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Replace Toggle with animated Switch component
- Sliding toggle animation like a settings switch
- "Preview" label next to switch
- Smooth transition when toggling on/off
- Proper on/off state with sliding thumb
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Replace button with proper Toggle component
- Shows on/off state visually with background change
- Eye icon with "Preview" label
- Toggles between edit and preview mode
- Uses shadcn/ui Toggle component with proper pressed state
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Preview toggle is now plain text link without pill/border
- Remove border and background from preview area
- Clean, minimal preview that blends with compose area
- Just shows text label "Preview" / "Edit" with hover effect
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Replace embed preview toggle with full post preview mode
- Preview button positioned in center of toolbar with label
- Shows "Preview" in edit mode, "Edit" in preview mode
- Preview displays how the post will actually render with NoteContent
- Renders all embeds, hashtags, and URLs as they would appear
- Mock event created for preview with current content
- Bordered preview area with subtle background
- Only shows toggle when content exists
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Remove complex inline rendering and hidden text approach
- Add simple eye/eye-off toggle button to show/hide embed previews
- Previews now render cleanly below textarea when enabled
- Toggle button only appears when embeds are detected
- Identifiers remain visible in textarea (no hiding complexity)
- Much simpler implementation that doesn't break rendering
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- NIP-19 identifier strings are now hidden in the composer textarea
- Embedded cards render inline at the position of the identifier
- Cursor automatically moves to newline after pasting identifier
- Textarea uses dual-layer approach: hidden input + visual display overlay
- Each line is rendered separately to support inline embed positioning
- Link previews still render at bottom (not inline)
- X button removes both the identifier and the preview
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- NIP-19 identifiers (nevent1, note1, naddr1) are now hidden in the composer
- Textarea shows cleaned text via overlay while preserving actual content
- Identifiers still included in posted event content
- Visual feedback through inline embedded previews with X button
- Maintains proper caret positioning and text selection
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Detect raw nevent1, note1, and naddr1 identifiers without nostr: prefix
- Render inline embedded preview with X button for removal
- Maintains existing nostr: URI support
- Still stores as literal string in posted event content
- Provides instant preview feedback during composition
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Desktop: size-2.5 (10px)
- Mobile: size-2 (8px)
- Both positioned at top-right corner of bell icon
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
- Wrap icon in relative container
- Position indicator at top-right corner of bell icon
- Increase size to 2.5 (10px) to match desktop
- Remove unnecessary relative class from parent link
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>