|
|
|
|
@@ -917,43 +917,65 @@ export function formatTimeAgo(timestamp) {
|
|
|
|
|
// Store timestamps for real-time updates
|
|
|
|
|
const timeAgoElements = new Map(); // element -> { timestamp, eventId }
|
|
|
|
|
|
|
|
|
|
// Track relay publish counts per event ID from broadcastProgress events.
|
|
|
|
|
// Keyed by event ID → number of successful relay publishes.
|
|
|
|
|
const relayCountByEventId = new Map();
|
|
|
|
|
// Track relay publish info per event ID from broadcastProgress events.
|
|
|
|
|
// Keyed by event ID → { count, urls } where urls is an array of relay URLs.
|
|
|
|
|
const relayInfoByEventId = new Map();
|
|
|
|
|
|
|
|
|
|
// Listen for broadcast progress events to capture final relay counts.
|
|
|
|
|
// Listen for broadcast progress events to capture final relay counts and URLs.
|
|
|
|
|
// The worker emits ndkBroadcastProgress with phase 'done' containing the
|
|
|
|
|
// total successful count. We store it so post cards can show "21r - 1h".
|
|
|
|
|
// total successful count and the list of relay URLs. We store it so post
|
|
|
|
|
// cards can show "21r - 1h" with a hover tooltip listing the relays.
|
|
|
|
|
if (typeof window !== 'undefined') {
|
|
|
|
|
window.addEventListener('ndkBroadcastProgress', (event) => {
|
|
|
|
|
const d = event.detail;
|
|
|
|
|
if (!d || d.phase !== 'done') return;
|
|
|
|
|
const eventId = d.eventId;
|
|
|
|
|
if (!eventId) return;
|
|
|
|
|
relayCountByEventId.set(eventId, d.successful || 0);
|
|
|
|
|
relayInfoByEventId.set(eventId, {
|
|
|
|
|
count: d.successful || 0,
|
|
|
|
|
urls: Array.isArray(d.relayUrls) ? d.relayUrls : [],
|
|
|
|
|
});
|
|
|
|
|
// Update any already-rendered time elements for this event.
|
|
|
|
|
timeAgoElements.forEach((info, element) => {
|
|
|
|
|
if (info.eventId === eventId && element.isConnected) {
|
|
|
|
|
element.textContent = formatTimeAgoWithRelays(info.timestamp, info.eventId);
|
|
|
|
|
updateTimeAgoElement(element, info);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Format time ago with optional relay count prefix.
|
|
|
|
|
* Shows "21r - 1h" when a relay count is available, else just "1h".
|
|
|
|
|
* @param {number} timestamp - Unix timestamp in seconds
|
|
|
|
|
* @param {string} [eventId] - Optional event ID to look up relay count
|
|
|
|
|
* Build the hover tooltip text for a relay list.
|
|
|
|
|
* Shows "Published to N relays:" followed by the URL list, truncated.
|
|
|
|
|
* @param {number} count - Number of successful relays
|
|
|
|
|
* @param {string[]} urls - Array of relay URLs
|
|
|
|
|
* @returns {string}
|
|
|
|
|
*/
|
|
|
|
|
function formatTimeAgoWithRelays(timestamp, eventId) {
|
|
|
|
|
const timeStr = formatTimeAgo(timestamp);
|
|
|
|
|
if (eventId && relayCountByEventId.has(eventId)) {
|
|
|
|
|
const count = relayCountByEventId.get(eventId);
|
|
|
|
|
return `${count}r - ${timeStr}`;
|
|
|
|
|
function buildRelayTooltip(count, urls) {
|
|
|
|
|
if (!count || count === 0) return '';
|
|
|
|
|
const header = `Published to ${count} relay${count === 1 ? '' : 's'}:`;
|
|
|
|
|
if (!urls || urls.length === 0) return header;
|
|
|
|
|
// Show up to 50 relay URLs in the tooltip; beyond that, show a summary.
|
|
|
|
|
if (urls.length <= 50) {
|
|
|
|
|
return header + '\n' + urls.join('\n');
|
|
|
|
|
}
|
|
|
|
|
return header + '\n' + urls.slice(0, 50).join('\n') + `\n… and ${urls.length - 50} more`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Update a time-ago element's text and tooltip from its stored info.
|
|
|
|
|
* @param {HTMLElement} element - The element to update
|
|
|
|
|
* @param {{timestamp: number, eventId: string}} info - Stored info
|
|
|
|
|
*/
|
|
|
|
|
function updateTimeAgoElement(element, info) {
|
|
|
|
|
const timeStr = formatTimeAgo(info.timestamp);
|
|
|
|
|
if (info.eventId && relayInfoByEventId.has(info.eventId)) {
|
|
|
|
|
const relayInfo = relayInfoByEventId.get(info.eventId);
|
|
|
|
|
element.textContent = `${relayInfo.count}r - ${timeStr}`;
|
|
|
|
|
element.title = buildRelayTooltip(relayInfo.count, relayInfo.urls);
|
|
|
|
|
} else {
|
|
|
|
|
element.textContent = timeStr;
|
|
|
|
|
}
|
|
|
|
|
return timeStr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -964,7 +986,7 @@ function formatTimeAgoWithRelays(timestamp, eventId) {
|
|
|
|
|
*/
|
|
|
|
|
export function registerTimeAgo(element, timestamp, eventId) {
|
|
|
|
|
timeAgoElements.set(element, { timestamp, eventId });
|
|
|
|
|
element.textContent = formatTimeAgoWithRelays(timestamp, eventId);
|
|
|
|
|
updateTimeAgoElement(element, { timestamp, eventId });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -974,7 +996,7 @@ export function registerTimeAgo(element, timestamp, eventId) {
|
|
|
|
|
export function updateTimeAgos() {
|
|
|
|
|
timeAgoElements.forEach((info, element) => {
|
|
|
|
|
if (element.isConnected) {
|
|
|
|
|
element.textContent = formatTimeAgoWithRelays(info.timestamp, info.eventId);
|
|
|
|
|
updateTimeAgoElement(element, info);
|
|
|
|
|
} else {
|
|
|
|
|
// Clean up detached elements
|
|
|
|
|
timeAgoElements.delete(element);
|
|
|
|
|
|