From 316c9f8d76c14a1258d660df6fa1a21dd6182505 Mon Sep 17 00:00:00 2001 From: Jonathan Staab Date: Thu, 30 Mar 2023 16:02:21 -0500 Subject: [PATCH] fix line breaks in compose, add embedded nostr entities to tags --- ROADMAP.md | 8 ++-- src/agent/cmd.ts | 57 ++++++++++++++++++++++++---- src/partials/ContentEditable.svelte | 4 ++ src/views/notes/NewNoteButton.svelte | 2 +- 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 2d6d6c49..4346dacf 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -4,10 +4,9 @@ - [ ] Improve note rendering - [ ] Fix reactions and replies showing up - [x] Show all images in preview as slideshow or something - - [ ] Extract nostr: links and bech32 entities, hover - - [ ] Add nostr: links and bech32 entities in compose to tags - - [ ] Linkify topics - - [ ] Fix extra newlines when composing + - [x] Extract nostr: links and bech32 entities, hover + - [x] Add nostr: links and bech32 entities in compose to tags + - [x] Fix extra newlines when composing - [ ] Multiplexer - [ ] Announce multiplextr, paravel, coracle update w/url - [ ] Write NIP to support proxies. Update COUNT NIP to mention how proxies are a good use case for COUNT @@ -37,6 +36,7 @@ # More +- [ ] Linkify topics - [ ] Add suggestion list for topics on compose so people know there are suggestions - [ ] Badges link to https://badges.page/p/97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322 - [ ] Link/embed good chat/DM micro-apps diff --git a/src/agent/cmd.ts b/src/agent/cmd.ts index e6f0ecda..13d76885 100644 --- a/src/agent/cmd.ts +++ b/src/agent/cmd.ts @@ -1,6 +1,8 @@ import {map, pick, last, uniqBy} from "ramda" import {get} from "svelte/store" -import {roomAttrs, displayPerson, findReplyId, findRootId} from "src/util/nostr" +import {doPipe} from "hurdak/lib/hurdak" +import {parseContent} from "src/util/html" +import {Tags, roomAttrs, displayPerson, findReplyId, findRootId} from "src/util/nostr" import {getRelayForPersonHint} from "src/agent/relays" import {getPersonWithFallback} from "src/agent/tables" import pool from "src/agent/pool" @@ -47,7 +49,16 @@ const createDirectMessage = (pubkey, content) => new PublishableEvent(4, {content, tags: [["p", pubkey]]}) const createNote = (content, mentions = [], topics = []) => { - const tags = processMentions(mentions).concat(topics.map(t => ["t", t])) + // Mentions have to come first so interpolation works + const tags = doPipe( + [], + [ + tags => tags.concat(processMentions(mentions)), + tags => tags.concat(topics.map(t => ["t", t])), + tags => tagsFromContent(content, tags), + uniqTags, + ] + ) return new PublishableEvent(1, {content, tags}) } @@ -57,7 +68,18 @@ const createReaction = (note, content) => const createReply = (note, content, mentions = [], topics = []) => { // Mentions have to come first so interpolation works - const tags = tagsFromParent(note, processMentions(mentions).concat(topics.map(t => ["t", t]))) + const tags = doPipe( + [], + [ + tags => tags.concat(processMentions(mentions)), + tags => tags.concat(topics.map(t => ["t", t])), + tags => tagsFromParent(note, tags), + tags => tagsFromContent(content, tags), + uniqTags, + ] + ) + + console.log(tags) return new PublishableEvent(1, {content, tags}) } @@ -88,6 +110,27 @@ const processMentions = map(pubkey => { return ["p", pubkey, relay?.url || "", name] }) +const tagsFromContent = (content, tags) => { + const seen = new Set(Tags.wrap(tags).values().all()) + + for (const {type, value} of parseContent(content)) { + if (type.match(/nostr:(note|nevent)/) && !seen.has(value.id)) { + tags = tags.concat([["e", value.id]]) + seen.add(value.id) + } + + if (type.match(/nostr:(nprofile|npub)/) && !seen.has(value.pubkey)) { + const name = displayPerson(getPersonWithFallback(value.pubkey)) + const relay = getRelayForPersonHint(value.pubkey) + + tags = tags.concat([["p", value.pubkey, relay?.url || "", name]]) + seen.add(value.pubkey) + } + } + + return tags +} + const getReplyTags = n => { const {url} = getRelayForPersonHint(n.pubkey, n) const rootId = findRootId(n) || findReplyId(n) || n.id @@ -102,10 +145,8 @@ const getReplyTags = n => { const tagsFromParent = (n, newTags = []) => { const pubkey = get(keys.pubkey) - return uniqBy( - // Remove duplicates due to inheritance. Keep earlier ones - t => t.slice(0, 2).join(":"), - // Mentions have to come first for interpolation to work + // Mentions have to come first for interpolation to work + return ( newTags // Add standard reply tags .concat(getReplyTags(n)) @@ -122,6 +163,8 @@ const tagsFromParent = (n, newTags = []) => { ) } +const uniqTags = uniqBy(t => t.slice(0, 2).join(":")) + class PublishableEvent { event: Record constructor(kind, {content = "", tags = []}) { diff --git a/src/partials/ContentEditable.svelte b/src/partials/ContentEditable.svelte index c9b93d6c..18c137c4 100644 --- a/src/partials/ContentEditable.svelte +++ b/src/partials/ContentEditable.svelte @@ -58,6 +58,10 @@ for (const child of node.childNodes) { const lineBreaks = child.querySelectorAll?.("br") || [] + if (child.tagName === "BR") { + continue + } + // Line breaks may be bare brs or divs wrapping brs if (lineBreaks.length > 0) { content += "\n".repeat(lineBreaks.length) diff --git a/src/views/notes/NewNoteButton.svelte b/src/views/notes/NewNoteButton.svelte index 6accff8a..d95a8695 100644 --- a/src/views/notes/NewNoteButton.svelte +++ b/src/views/notes/NewNoteButton.svelte @@ -8,7 +8,7 @@ {#if $canPublish} -
+