diff --git a/src/components/HighlightItem.tsx b/src/components/HighlightItem.tsx index dc783a15..9d3d9013 100644 --- a/src/components/HighlightItem.tsx +++ b/src/components/HighlightItem.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useRef } from 'react' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { faQuoteLeft, faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons' +import { faQuoteLeft, faExternalLinkAlt, faHouseSignal } from '@fortawesome/free-solid-svg-icons' import { Highlight } from '../types/highlights' import { formatDistanceToNow } from 'date-fns' import { useEventModel } from 'applesauce-react/hooks' @@ -91,6 +91,16 @@ export const HighlightItem: React.FC = ({ highlight, onSelec {formatDistanceToNow(new Date(highlight.created_at * 1000), { addSuffix: true })} + {highlight.isLocalOnly && ( + <> + + + + Local + + + )} + {sourceLink && ( { +): Promise { if (!selectedText || !source) { throw new Error('Missing required data to create highlight') } @@ -104,13 +105,34 @@ export async function createHighlight( // Sign the event const signedEvent = await factory.sign(highlightEvent) + // Get list of currently connected relays from the pool + const connectedRelays = Array.from(relayPool.relays.values()).map(relay => relay.url) + + // Determine which relays we're publishing to (intersection of RELAYS and connected relays) + const publishingRelays = RELAYS.filter(url => connectedRelays.includes(url)) + + // If no relays are connected, fallback to just local relay if available + const targetRelays = publishingRelays.length > 0 ? publishingRelays : RELAYS.filter(r => r.includes('localhost') || r.includes('127.0.0.1')) + // Publish to relays (including local relay) - await relayPool.publish(RELAYS, signedEvent) + await relayPool.publish(targetRelays, signedEvent) - console.log('✅ Highlight published to', RELAYS.length, 'relays (including local):', signedEvent) + // Check if we're only publishing to local relays + const isLocalOnly = areAllRelaysLocal(targetRelays) - // Return the signed event for immediate UI updates - return signedEvent + console.log('✅ Highlight published to', targetRelays.length, 'relays:', { + relays: targetRelays, + isLocalOnly, + event: signedEvent + }) + + // Convert to Highlight with relay tracking info + const highlight = eventToHighlight(signedEvent) + highlight.publishedRelays = targetRelays + highlight.isLocalOnly = isLocalOnly + + // Return the highlight for immediate UI updates + return highlight } /** diff --git a/src/types/highlights.ts b/src/types/highlights.ts index 7e0744ab..09dc4a1b 100644 --- a/src/types/highlights.ts +++ b/src/types/highlights.ts @@ -15,5 +15,8 @@ export interface Highlight { comment?: string // optional comment about the highlight // Level classification (computed based on user's context) level?: HighlightLevel + // Relay tracking for offline/local-only highlights + publishedRelays?: string[] // URLs of relays that acknowledged this event + isLocalOnly?: boolean // true if only published to local relays } diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts index 85f9a97b..da3c12ef 100644 --- a/src/utils/helpers.ts +++ b/src/utils/helpers.ts @@ -40,3 +40,26 @@ export const classifyUrl = (url: string | undefined): UrlClassification => { return { type: 'article', buttonText: 'READ NOW' } } +/** + * Checks if a relay URL is a local relay (localhost or 127.0.0.1) + */ +export const isLocalRelay = (relayUrl: string): boolean => { + return relayUrl.includes('localhost') || relayUrl.includes('127.0.0.1') +} + +/** + * Checks if all relays in the list are local relays + */ +export const areAllRelaysLocal = (relayUrls: string[]): boolean => { + if (!relayUrls || relayUrls.length === 0) return false + return relayUrls.every(isLocalRelay) +} + +/** + * Checks if at least one relay is a remote (non-local) relay + */ +export const hasRemoteRelay = (relayUrls: string[]): boolean => { + if (!relayUrls || relayUrls.length === 0) return false + return relayUrls.some(url => !isLocalRelay(url)) +} +