diff --git a/ROADMAP.md b/ROADMAP.md
index f6a9e73c..42b90cde 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -1,5 +1,7 @@
# Current
+- [ ] Support other kinds
+ - Fix note truncation
- [ ] Feeds load forever if a modal is open
- [ ] Support other list types than 30001
- [ ] Fix connection management stuff. Have GPT help
diff --git a/src/app/shared/FeedControls.svelte b/src/app/shared/FeedControls.svelte
index 2497d21f..93cd2983 100644
--- a/src/app/shared/FeedControls.svelte
+++ b/src/app/shared/FeedControls.svelte
@@ -97,7 +97,7 @@
onChange(newFilter)
}
- const applySearch = debounce(200, applyFilter)
+ const applySearch = debounce(400, applyFilter)
const clearSearch = () => {
_filter.search = ""
diff --git a/src/app/shared/NoteContent.svelte b/src/app/shared/NoteContent.svelte
index a4a32b2c..272f8281 100644
--- a/src/app/shared/NoteContent.svelte
+++ b/src/app/shared/NoteContent.svelte
@@ -1,21 +1,20 @@
@@ -156,64 +74,34 @@
{/if}
- {#each content as { type, value }, i}
- {#if type === "newline" && i > 0}
- {#each value as _}
-
- {/each}
- {:else if type === "topic"}
- openTopic(value)}>#{value}
- {:else if type === "link"}
-
- {value.replace(/https?:\/\/(www\.)?/, "")}
-
+ {#each shortContent as { type, value }, i}
+ {#if type === NEWLINE}
+
+ {:else if type === TOPIC}
+
+ {:else if type === INVOICE}
+
+
+
+ {:else if type === LINK}
+
+ {:else if type.match(/^nostr:np(rofile|ub)$/)}
+
+ {:else if type.startsWith("nostr:") && showMedia && isStandalone(i) && value.id !== anchorId}
+
+
+
+
+
{:else if type.startsWith("nostr:")}
- {#if showMedia && value.id && isStandalone(i) && value.id !== anchorId}
- openQuote(value.id)}>
- {#await loadQuote(value)}
-
- {:then quote}
- {@const person = getPersonWithFallback(quote.pubkey)}
-
-
-
openPerson(quote.pubkey)}>
- {displayPerson(person)}
-
-
-
- {:catch}
-
- Unable to load a preview for quoted event
-
- {/await}
-
- {:else if type.match(/np(rofile|ub)$/)}
- @ openPerson(value.pubkey)}>
- {displayPerson(getPersonWithFallback(value.pubkey))}
-
- {:else}
-
- {value.entity.slice(0, 16) + "..."}
-
- {/if}
+
{:else}
{value}
{/if}
{" "}
{/each}
- {#if invoices.length > 0}
-
-
-
- {/if}
- {#if showMedia && links.length > 0}
-
-
-
+ {#if showMedia && extraLinks.length > 0}
+
{/if}
diff --git a/src/app/shared/NoteContentEntity.svelte b/src/app/shared/NoteContentEntity.svelte
new file mode 100644
index 00000000..d5c8402f
--- /dev/null
+++ b/src/app/shared/NoteContentEntity.svelte
@@ -0,0 +1,9 @@
+
+
+
+ {value.entity.slice(0, 16) + "..."}
+
diff --git a/src/app/shared/NoteContentLink.svelte b/src/app/shared/NoteContentLink.svelte
new file mode 100644
index 00000000..4854d880
--- /dev/null
+++ b/src/app/shared/NoteContentLink.svelte
@@ -0,0 +1,26 @@
+
+
+{#if showMedia && value.canDisplay}
+
+
+
+{:else}
+
+ {value.url.replace(/https?:\/\/(www\.)?/, "")}
+
+{/if}
diff --git a/src/app/shared/NoteContentNewline.svelte b/src/app/shared/NoteContentNewline.svelte
new file mode 100644
index 00000000..04078a7d
--- /dev/null
+++ b/src/app/shared/NoteContentNewline.svelte
@@ -0,0 +1,7 @@
+
+
+{#each value as _}
+
+{/each}
diff --git a/src/app/shared/NoteContentPerson.svelte b/src/app/shared/NoteContentPerson.svelte
new file mode 100644
index 00000000..3a3cdfd6
--- /dev/null
+++ b/src/app/shared/NoteContentPerson.svelte
@@ -0,0 +1,14 @@
+
+
+@
+ {displayPerson(getPersonWithFallback(value.pubkey))}
+
diff --git a/src/app/shared/NoteContentQuote.svelte b/src/app/shared/NoteContentQuote.svelte
new file mode 100644
index 00000000..f833f25d
--- /dev/null
+++ b/src/app/shared/NoteContentQuote.svelte
@@ -0,0 +1,65 @@
+
+
+
+
+ {#await loadQuote()}
+
+ {:then quote}
+ {@const person = getPersonWithFallback(quote.pubkey)}
+
+
+
openPerson(quote.pubkey)}>
+ {displayPerson(person)}
+
+
+
+ {:catch}
+
+ Unable to load a preview for quoted event
+
+ {/await}
+
+
diff --git a/src/app/shared/NoteContentTopic.svelte b/src/app/shared/NoteContentTopic.svelte
new file mode 100644
index 00000000..98aa7f68
--- /dev/null
+++ b/src/app/shared/NoteContentTopic.svelte
@@ -0,0 +1,12 @@
+
+
+ openTopic(value)}>#{value}
diff --git a/src/app/shared/PersonAbout.svelte b/src/app/shared/PersonAbout.svelte
index d8e497e5..7424b4c0 100644
--- a/src/app/shared/PersonAbout.svelte
+++ b/src/app/shared/PersonAbout.svelte
@@ -19,8 +19,8 @@
{/each}
{:else if type === "link"}
-
- {value.replace(/https?:\/\/(www\.)?/, "")}
+
+ {value.url.replace(/https?:\/\/(www\.)?/, "")}
{:else if type.startsWith("nostr:")}
diff --git a/src/app/views/Search.svelte b/src/app/views/Search.svelte
index 76b0f340..9fb24fef 100644
--- a/src/app/views/Search.svelte
+++ b/src/app/views/Search.svelte
@@ -75,13 +75,13 @@
$or: [{"kind0.name": {$type: "string"}}, {"kind0.display_name": {$type: "string"}}],
})
.map(person => {
- const {name, about, display_name} = person.kind0
+ const {name, nip05, about, display_name} = person.kind0
return {
person,
type: "person",
id: person.pubkey,
- text: "@" + [name, about, display_name].filter(identity).join(" "),
+ text: "@" + [name, about, nip05, display_name].filter(identity).join(" "),
}
})
)
@@ -116,7 +116,7 @@
camera icon to scan with your device's camera instead.
-
+
import {sortBy} from "ramda"
- import {slide} from "svelte/transition"
import {annotateMedia} from "src/util/misc"
import Media from "src/partials/Media.svelte"
+ import Anchor from "src/partials/Anchor.svelte"
import Content from "src/partials/Content.svelte"
import Modal from "src/partials/Modal.svelte"
export let links
- export let onClose = null
- let hidden = false
let showModal = false
// Put previews last since we need to load them asynchronously
- const annotated = sortBy(l => (l.type === "preview" ? 1 : 0), links.map(annotateMedia))
-
- const close = () => {
- onClose?.()
- hidden = true
- }
+ const annotated = sortBy(
+ l => (l.type === "preview" ? 1 : 0),
+ links.map(link => annotateMedia(link.url))
+ )
const openModal = () => {
showModal = true
}
+
const closeModal = () => {
showModal = false
}
-{#if !hidden}
-
-
- {#if annotated.length > 1}
-
- Show all {annotated.length} link previews
-
- {/if}
-
-{/if}
+
+
+ Show all {annotated.length} link previews
+
+
{#if showModal}
diff --git a/src/util/nostr.ts b/src/util/nostr.ts
index 020ac573..f0ed54a6 100644
--- a/src/util/nostr.ts
+++ b/src/util/nostr.ts
@@ -6,6 +6,7 @@ import {tryJson, avg} from "src/util/misc"
import {invoiceAmount} from "src/util/lightning"
export const noteKinds = [1, 1985, 30023, 30018, 10001, 1063, 9802]
+// export const noteKinds = [9802]
export const personKinds = [0, 2, 3, 10001, 10002]
export const userKinds = personKinds.concat([10000, 30001, 30078])
export const appDataKeys = [
diff --git a/src/util/notes.ts b/src/util/notes.ts
index bf26dabe..21672cd2 100644
--- a/src/util/notes.ts
+++ b/src/util/notes.ts
@@ -3,6 +3,19 @@ import {nip19} from "nostr-tools"
import {first} from "hurdak/lib/hurdak"
import {fromNostrURI} from "src/util/nostr"
+export const NEWLINE = "newline"
+export const TEXT = "text"
+export const TOPIC = "topic"
+export const LINK = "link"
+export const INVOICE = "invoice"
+export const NOSTR_NOTE = "nostr:note"
+export const NOSTR_NEVENT = "nostr:nevent"
+export const NOSTR_NPUB = "nostr:npub"
+export const NOSTR_NPROFILE = "nostr:nprofile"
+export const NOSTR_NADDR = "nostr:naddr"
+
+const canDisplayUrl = url => !url.match(/\.(apk|docx|xlsx|csv|dmg)/)
+
export const parseContent = ({content, tags = []}) => {
const result = []
let text = content.trim()
@@ -12,7 +25,7 @@ export const parseContent = ({content, tags = []}) => {
const newline = first(text.match(/^\n+/))
if (newline) {
- return ["newline", newline, newline]
+ return [NEWLINE, newline, newline]
}
}
@@ -48,7 +61,7 @@ export const parseContent = ({content, tags = []}) => {
// Skip numeric topics
if (topic && !topic.match(/^#\d+$/)) {
- return ["topic", topic, topic.slice(1)]
+ return [TOPIC, topic, topic.slice(1)]
}
}
@@ -77,11 +90,11 @@ export const parseContent = ({content, tags = []}) => {
}
}
- const parseLNUrl = () => {
- const lnurl = first(text.match(/^ln(bc|url)[\d\w]{50,1000}/i))
+ const parseInvoice = () => {
+ const invoice = first(text.match(/^ln(bc|url)[\d\w]{50,1000}/i))
- if (lnurl) {
- return ["lnurl", lnurl, lnurl]
+ if (invoice) {
+ return [INVOICE, invoice, invoice]
}
}
@@ -107,7 +120,7 @@ export const parseContent = ({content, tags = []}) => {
url = "https://" + url
}
- return ["link", raw, url]
+ return [LINK, raw, {url, canDisplay: canDisplayUrl(url)}]
}
}
@@ -118,7 +131,7 @@ export const parseContent = ({content, tags = []}) => {
parseTopic() ||
parseBech32() ||
parseUrl() ||
- parseLNUrl()
+ parseInvoice()
if (part) {
if (buffer) {
@@ -141,7 +154,42 @@ export const parseContent = ({content, tags = []}) => {
}
if (buffer) {
- result.push({type: "text", value: buffer})
+ result.push({type: TEXT, value: buffer})
+ }
+
+ return result
+}
+
+export const truncateContent = (content, {showEntire, maxLength, showMedia}) => {
+ if (showEntire) {
+ return content
+ }
+
+ let length = 0
+ const result = []
+ const truncateAt = maxLength * 0.6
+
+ for (const part of content) {
+ const isText = [TOPIC, TEXT].includes(part.type)
+ const isMedia = [LINK, INVOICE].includes(part.type) || part.type.startsWith("nostr:")
+
+ if (isText) {
+ length += part.value.length
+ }
+
+ if (isMedia) {
+ length += showMedia ? maxLength / 3 : part.value.length
+ }
+
+ result.push(part)
+
+ if (length > truncateAt) {
+ if (isText || (isMedia && !showMedia)) {
+ result.push({type: TEXT, value: "..."})
+ }
+
+ break
+ }
}
return result