clone of repo on github
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

167 lines
4.5 KiB

/**
* Utility functions for highlight management
*/
import type { NDKEvent } from "@nostr-dev-kit/ndk";
import { nip19 } from "nostr-tools";
export interface GroupedHighlight {
pubkey: string;
highlights: NDKEvent[];
count: number;
}
/**
* Groups highlights by author pubkey
* Returns a Map with pubkey as key and array of highlights as value
*/
export function groupHighlightsByAuthor(
highlights: NDKEvent[],
): Map<string, NDKEvent[]> {
const grouped = new Map<string, NDKEvent[]>();
for (const highlight of highlights) {
const pubkey = highlight.pubkey;
const existing = grouped.get(pubkey) || [];
existing.push(highlight);
grouped.set(pubkey, existing);
}
return grouped;
}
/**
* Truncates highlight text to specified length, breaking at word boundaries
* @param text - The text to truncate
* @param maxLength - Maximum length (default: 50)
* @returns Truncated text with ellipsis if needed
*/
export function truncateHighlight(
text: string,
maxLength: number = 50,
): string {
if (!text || text.length <= maxLength) {
return text;
}
// Find the last space before maxLength
const truncated = text.slice(0, maxLength);
const lastSpace = truncated.lastIndexOf(" ");
// If there's a space, break there; otherwise use the full maxLength
if (lastSpace > 0) {
return truncated.slice(0, lastSpace) + "...";
}
return truncated + "...";
}
/**
* Encodes a highlight event as an naddr with relay hints
* @param event - The highlight event (kind 9802)
* @param relays - Array of relay URLs to include as hints
* @returns naddr string
*/
export function encodeHighlightNaddr(
event: NDKEvent,
relays: string[] = [],
): string {
try {
// For kind 9802 highlights, we need the event's unique identifier
// Since highlights don't have a d-tag, we'll use the event id as nevent instead
// But per NIP-19, naddr is for addressable events (with d-tag)
// For non-addressable events like kind 9802, we should use nevent
const nevent = nip19.neventEncode({
id: event.id,
relays: relays.length > 0 ? relays : undefined,
author: event.pubkey,
kind: event.kind,
});
return nevent;
} catch (error) {
console.error("Error encoding highlight naddr:", error);
// Fallback to just the event id
return event.id;
}
}
/**
* Creates a shortened npub for display
* @param pubkey - The hex pubkey
* @param length - Number of characters to show from start (default: 8)
* @returns Shortened npub like "npub1abc...xyz"
*/
export function shortenNpub(pubkey: string, length: number = 8): string {
try {
const npub = nip19.npubEncode(pubkey);
// npub format: "npub1" + bech32 encoded data
// Show first part and last part
if (npub.length <= length + 10) {
return npub;
}
const start = npub.slice(0, length + 5); // "npub1" + first chars
const end = npub.slice(-4); // last chars
return `${start}...${end}`;
} catch (error) {
console.error("Error creating shortened npub:", error);
// Fallback to shortened hex
return `${pubkey.slice(0, 8)}...${pubkey.slice(-4)}`;
}
}
/**
* Extracts relay URLs from a highlight event's tags or metadata
* @param event - The highlight event
* @returns Array of relay URLs
*/
export function getRelaysFromHighlight(event: NDKEvent): string[] {
const relays: string[] = [];
// Check for relay hints in tags (e.g., ["a", "30041:pubkey:id", "relay-url"])
for (const tag of event.tags) {
if ((tag[0] === "a" || tag[0] === "e" || tag[0] === "p") && tag[2]) {
relays.push(tag[2]);
}
}
// Also include relay from the event if available
if (event.relay?.url) {
relays.push(event.relay.url);
}
// Deduplicate
return [...new Set(relays)];
}
/**
* Sorts highlights within a group by creation time (newest first)
* @param highlights - Array of highlight events
* @returns Sorted array
*/
export function sortHighlightsByTime(highlights: NDKEvent[]): NDKEvent[] {
return [...highlights].sort((a, b) => {
const timeA = a.created_at || 0;
const timeB = b.created_at || 0;
return timeB - timeA; // Newest first
});
}
/**
* Gets the display name for a highlight author
* Priority: displayName > name > shortened npub
*/
export function getAuthorDisplayName(
profile:
| { name?: string; displayName?: string; display_name?: string }
| null,
pubkey: string,
): string {
if (profile) {
return profile.displayName || profile.display_name || profile.name ||
shortenNpub(pubkey);
}
return shortenNpub(pubkey);
}