import {Event, nip19} from 'nostr-tools'; import {Children, elem, elemArticle, parseTextContent} from './utils/dom'; import {dateTime, formatTime} from './utils/time'; import {/*validatePow,*/ sortByCreatedAt} from './events'; import {setViewElem} from './view'; import {config} from './settings'; import {getReactions, getReactionContents} from './reactions'; import {openWriteInput} from './write'; // import {linkPreview} from './media'; import {getMetadata} from './profiles'; import {EventWithNip19, replyList} from './notes'; import {parseJSON} from './media'; setInterval(() => { document.querySelectorAll('time[datetime]').forEach((timeElem: HTMLTimeElement) => { timeElem.textContent = formatTime(new Date(timeElem.dateTime)); }); }, 10000); export const createTextNote = ( evt: EventWithNip19, relay: string, ) => { const {img, name, userName} = getMetadata(evt.pubkey); const replies = replyList.filter(({replyTo}) => replyTo === evt.id) .sort(sortByCreatedAt) .reverse(); // const isLongContent = evt.content.trimRight().length > 280; // const content = isLongContent ? evt.content.slice(0, 280) : evt.content; const reactions = getReactions(evt.id); const didReact = reactions.length && !!reactions.find(reaction => reaction.pubkey === config.pubkey); const [content, {firstLink}] = parseTextContent(evt.content); const time = new Date(evt.created_at * 1000); const buttons = elem('div', {className: 'buttons'}, [ elem('button', {name: 'reply', type: 'button'}, [ elem('img', {height: 24, width: 24, src: '/assets/comment.svg'}) ]), elem('button', {name: 'star', type: 'button'}, [ elem('img', { alt: didReact ? '✭' : '✩', // ♥ height: 24, width: 24, src: `/assets/${didReact ? 'star-fill' : 'star'}.svg`, title: getReactionContents(evt.id).join(' '), }), elem('small', {data: {reactions: ''}}, reactions.length || ''), ]), ]); if (localStorage.getItem('reply_to') === evt.id) { openWriteInput(buttons, evt.id); } const replyFeed: Array = replies[0] ? replies.map(e => setViewElem(e.id, createTextNote(e, relay))) : []; return elemArticle([ elem('a', {className: 'mbox-img', href: `/${evt.nip19.npub}`, tabIndex: -1}, img), elem('div', {className: 'mbox-body'}, [ elem('header', { className: 'mbox-header', title: `User: ${userName}\n${time}\n\nUser pubkey: ${evt.pubkey}\n\nRelay: ${relay}\n\nEvent-id: ${evt.id} ${evt.tags.length ? `\nTags ${JSON.stringify(evt.tags)}\n` : ''} ${evt.content}` }, [ elem('a', { className: `mbox-username${name ? ' mbox-kind0-name' : ''}`, data: {profile: evt.pubkey}, href: `/${evt.nip19.npub}`, }, name || userName), ' ', elem('a', {href: `/${evt.nip19.note}`}, elem('time', {dateTime: time.toISOString()}, formatTime(time))), ]), elem('div', {className: 'mbox-content'/* data: isLongContent ? {append: evt.content.slice(280)} : null*/}, content /*[ ...content, (firstLink && validatePow(evt)) ? linkPreview(firstLink, evt.id, relay) : null, ]*/), buttons, ]), ...(replies[0] ? [elem('div', {className: 'mbox-replies'}, replyFeed)] : []), ], { className: replies.length ? 'mbox-has-replies' : '', data: {kind: evt.kind, id: evt.id, pubkey: evt.pubkey, relay} }); }; type EventWithContent = Omit & { content: Children } export const renderUpdateContact = ( evt: EventWithContent, relay: string, ) => { const {img, name, userName} = getMetadata(evt.pubkey); const time = new Date(evt.created_at * 1000); return elemArticle([ elem('div', {className: 'mbox-img'}, img), elem('div', {className: 'mbox-body'}, [ elem('header', {className: 'mbox-header'}, [ elem('span', { className: `mbox-username${name ? ' mbox-kind0-name' : ''}`, data: {profile: evt.pubkey}, }, name || userName), ' ', elem('span', {data: {contacts: evt.id}, title: time.toISOString()}, evt.content), ]), elem('div', {className: 'mbox-content'}, [ ]), ]), ], { className: 'mbox-updated-contact', data: {kind: evt.kind, id: evt.id, pubkey: evt.pubkey, relay} } ); }; export const renderRecommendServer = (evt: Event, relay: string) => { const {img, userName} = getMetadata(evt.pubkey); const time = new Date(evt.created_at * 1000); const body = elem('div', {className: 'mbox-body', title: dateTime.format(time)}, [ elem('header', {className: 'mbox-header'}, [ elem('small', {}, [ elem('strong', {}, userName) ]), ]), ` recommends server: ${evt.content}`, ]); return elemArticle([ elem('div', {className: 'mbox-img'}, [img]), body ], { className: 'mbox-recommend-server', data: {kind: evt.kind, id: evt.id, pubkey: evt.pubkey} }); }; export const renderEventDetails = (evt: Event, relay: string) => { const {img, name, userName} = getMetadata(evt.pubkey); const time = new Date(evt.created_at * 1000); const npub = nip19.npubEncode(evt.pubkey); let content = parseJSON(evt.content) switch (typeof content) { case 'object': content = JSON.stringify(content, null, 2); break; default: content = `${evt.content}`; } const body = elem('div', {className: 'mbox-body', title: dateTime.format(time)}, [ elem('header', {className: 'mbox-header'}, [ elem('a', { className: `mbox-username${name ? ' mbox-kind0-name' : ''}`, data: {profile: evt.pubkey}, href: `/${npub}`, }, name || userName), ]), elem('dl', {}, [ elem('dt', {}, 'npub'), elem('dd', {}, npub), elem('dt', {}, 'created at'), elem('dd', {}, dateTime.format(evt.created_at * 1000)), elem('dt', {}, 'relay'), elem('dd', {}, relay), ]), elem('h2', {}, 'Event'), elem('dl', {}, [ elem('dt', {}, 'id'), elem('dd', {}, evt.id), elem('dt', {}, 'kind'), elem('dd', {}, evt.kind), elem('dt', {}, 'pubkey'), elem('dd', {}, evt.pubkey), elem('dt', {}, 'tags count'), elem('dd', {}, evt.tags.length), elem('dt', {}, 'tags'), elem('dd', {}, JSON.stringify(evt.tags)), elem('dt', {}, 'content'), elem('dd', {}, elem('pre', {}, content as string)), ]), ]); return elemArticle([ elem('a', {className: 'mbox-img', href: `/${npub}`, tabIndex: -1}, img), body, ], { className: 'mbox-recommend-server', data: {kind: evt.kind, id: evt.id, pubkey: evt.pubkey} }); };