Fix mention parsing

This commit is contained in:
Jonathan Staab 2023-04-03 09:46:35 -05:00
parent ce6993b214
commit 9bc5a35957
9 changed files with 38 additions and 117 deletions

View File

@ -1,5 +1,7 @@
# Current
- [ ] Fix issues
- [ ] Don't escape html in parseContent
- [ ] Look into AUTH not working for mazin
- [ ] Write NIP to support proxies. Update COUNT NIP to mention how proxies are a good use case for COUNT
- [ ] Write blog post on multiplexer
@ -11,17 +13,6 @@
- [ ] Add onError handler to subscriptions for when sockets fail to connect?
- [ ] Add bugsnag to multiplexr
# Others
- Recommendations
- Indexer/multiplexer
- relay.coracle.social for people nip-05 verified via coracle
- Improve overall design
- Stripped down easy version of coracle
- Extract library?
- Parameterize color scheme
- Deploy to special domains with relays built in
# Custom views
- [ ] Add customize icon and route with editable custom view cards using "lists" nip
@ -30,6 +21,7 @@
# More
- [ ] Build per-relay pagination, put it in paravel https://github.com/nostr-protocol/nips/pull/408
- [ ] Linkify topics
- [ ] Add suggestion list for topics on compose so people know there are suggestions
- [ ] Badges link to https://badges.page/p/97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322

View File

@ -42,7 +42,7 @@
{#if !hidden}
<div in:slide class="relative">
<CarouselItem link={annotated[0]} showLoading={false} onClose={close} />
<CarouselItem link={annotated[0]} onClose={close} />
{#if annotated.length > 1}
<p class="text-gray-500 py-4 text-center underline" on:click={openModal}>
<i class="fa fa-plus" /> Show {annotated.length} link previews

View File

@ -1,7 +1,7 @@
<script>
import cx from "classnames"
import {ellipsize} from "hurdak/lib/hurdak"
import {fly} from "svelte/transition"
import {fly, slide} from "svelte/transition"
import Anchor from "src/partials/Anchor.svelte"
import Spinner from "src/partials/Spinner.svelte"
import user from "src/agent/user"
@ -9,7 +9,6 @@
export let link
export let onClick = null
export let onClose = null
export let showLoading = true
const loadPreview = async () => {
const res = await fetch(user.dufflepud("/link/preview"), {
@ -36,18 +35,14 @@
href={onClick ? null : link.url}
on:click={onClick}
style="background-color: rgba(15, 15, 14, 0.5)"
class={cx("relative flex flex-col overflow-hidden rounded border-solid border-gray-6", {
border: showLoading || link.type !== "preview",
})}>
class={cx("relative flex flex-col overflow-hidden rounded border border-solid border-gray-6")}>
{#if link.type === "image"}
<img alt="Link preview" src={link.url} class="max-h-96 object-contain object-center" />
{:else if link.type === "video"}
<video controls src={link.url} class="max-h-96 object-contain object-center" />
{:else}
{#await loadPreview()}
{#if showLoading}
<Spinner />
{/if}
{:then { title, description, image }}
{#if image}
<img alt="Link preview" src={image} class="max-h-96 object-contain object-center" />
@ -68,11 +63,9 @@
</div>
{/if}
{:catch}
{#if showLoading}
<p class="mb-1 py-24 px-12 text-center text-gray-5" in:fly={{y: 20}}>
<p class="mb-1 py-24 px-12 text-center text-gray-5">
Unable to load a preview for {link.url}
</p>
{/if}
{/await}
{/if}
</Anchor>

View File

@ -14,8 +14,10 @@
<p class="overflow-hidden text-ellipsis">
{#each content as { type, value }}
{#if type === "br"}
{@html value}
{#if type === "newline"}
{#each value as _}
<br />
{/each}
{:else if type === "link"}
<Anchor external href={value}>
{value.replace(/https?:\/\/(www\.)?/, "")}

View File

@ -1,72 +0,0 @@
<script>
import {onMount} from "svelte"
import {slide} from "svelte/transition"
import Anchor from "src/partials/Anchor.svelte"
import user from "src/agent/user"
export let url
export let onClose = null
let preview
const close = () => {
onClose?.()
preview = null
}
onMount(async () => {
if (url.match(".(jpg|jpeg|png|gif)")) {
preview = {image: url}
} else if (url.match(".(mov|mp4)")) {
preview = {video: url}
} else {
try {
const res = await fetch(user.dufflepud("/link/preview"), {
method: "POST",
body: JSON.stringify({url}),
headers: {
"Content-Type": "application/json",
},
})
const json = await res.json()
if (json.title || json.image) {
preview = json
}
} catch (e) {
return
}
}
})
</script>
{#if preview}
<div in:slide>
<Anchor
external
href={url}
style="background-color: rgba(15, 15, 14, 0.5)"
class="relative flex flex-col overflow-hidden rounded border border-solid border-gray-6">
{#if preview.image}
<img alt="Link preview" src={preview.image} class="max-h-96 object-contain object-center" />
{/if}
{#if preview.video}
<video controls src={preview.video} class="max-h-96 object-contain object-center" />
{/if}
<div class="h-px bg-gray-6" />
{#if preview.title}
<div class="flex flex-col bg-white px-4 py-2 text-black">
<strong class="overflow-hidden text-ellipsis whitespace-nowrap">{preview.title}</strong>
<small>{preview.description}</small>
</div>
{/if}
<div
on:click|preventDefault={close}
class="absolute top-0 right-0 m-1 flex h-6 w-6 items-center justify-center
rounded-full border border-solid border-gray-6 bg-white text-black opacity-50 shadow">
<i class="fa fa-times" />
</div>
</Anchor>
</div>
{/if}

View File

@ -103,7 +103,7 @@ export const noEvent = f => e => {
}
export const parseContent = content => {
const text = escapeHtml(content.trim())
const text = content.trim()
const result = []
let buffer = "",
i = 0
@ -121,10 +121,10 @@ export const parseContent = content => {
for (; i < text.length; ) {
const tail = text.slice(i)
const brMatch = tail.match(/^(<br>)+/)
const newLine = tail.match(/^\n+/)
if (brMatch) {
push("br", brMatch[0])
if (newLine) {
push("newline", newLine[0])
continue
}

View File

@ -20,7 +20,7 @@
import PersonCircle from "src/partials/PersonCircle.svelte"
import RelayCard from "src/views/relays/RelayCard.svelte"
import Modal from "src/partials/Modal.svelte"
import Preview from "src/partials/Preview.svelte"
import CarouselItem from "src/partials/CarouselItem.svelte"
import Anchor from "src/partials/Anchor.svelte"
import {toast, modal} from "src/app/ui"
import Compose from "src/partials/Compose.svelte"
@ -512,8 +512,8 @@
</div>
{#if image}
<div class="bg-gray-7 p-2">
<Preview
url={image}
<CarouselItem
link={{type: 'image', url: image}}
onClose={() => {
image = null
}} />

View File

@ -24,6 +24,7 @@
const entities = []
const shouldTruncate = !showEntire && note.content.length > 500
const content = parseContent(note.content)
const showMedia = user.getSetting("showMedia")
let l = 0
for (let i = 0; i < content.length; i++) {
@ -42,11 +43,11 @@
// If the link is surrounded by line breaks (or content start/end), remove
// the link along with trailing whitespace
if ((!prev || prev.type === "br") && (!next || next.type === "br")) {
if (showMedia && (!prev || prev.type === "newline") && (!next || next.type === "newline")) {
let n = 0
for (let j = i + 1; j < content.length; j++) {
if (content[j].type !== "br") {
if (content[j].type !== "newline") {
break
}
@ -59,10 +60,10 @@
}
// Keep track of total characters, if we're not dealing with a string just guess
if (value instanceof String) {
if (typeof value === 'string') {
l += value.length
if (shouldTruncate && l > 350 && type !== "br") {
if (shouldTruncate && l > 350 && type !== "newline") {
content[i].value = value.trim()
content.splice(i + 1, content.length, {type: "text", value: "..."})
break
@ -75,9 +76,12 @@
const getMentionPubkey = text => {
const i = parseInt(first(text.match(/\d+/)))
// Some implementations count only p tags when calculating index
// Some implementations count only p tags when calculating index, and some
// implementations are 1-indexed
if (note.tags[i]?.[0] === "p") {
return note.tags[i][1]
} else if (note.tags[i-1]?.[0] === "p") {
return note.tags[i-1][1]
} else {
return Tags.from(note).type("p").values().nth(i)
}
@ -104,8 +108,10 @@
<div class="flex flex-col gap-2 overflow-hidden text-ellipsis">
<p>
{#each content as { type, value }}
{#if type === "br"}
{@html value}
{#if type === "newline"}
{#each value as _}
<br />
{/each}
{:else if type === "link"}
<Anchor external href={value}>
{value.replace(/https?:\/\/(www\.)?/, "")}
@ -132,7 +138,7 @@
{/if}
{/each}
</p>
{#if user.getSetting("showMedia") && links.length > 0}
{#if showMedia && links.length > 0}
<div on:click={e => e.stopPropagation()}>
<Carousel {links} />
</div>

View File

@ -8,7 +8,7 @@
import Button from "src/partials/Button.svelte"
import Compose from "src/partials/Compose.svelte"
import ImageInput from "src/partials/ImageInput.svelte"
import Preview from "src/partials/Preview.svelte"
import CarouselItem from "src/partials/CarouselItem.svelte"
import Input from "src/partials/Input.svelte"
import RelayCardSimple from "src/partials/RelayCardSimple.svelte"
import Content from "src/partials/Content.svelte"
@ -113,8 +113,8 @@
</div>
</div>
{#if image}
<Preview
url={image}
<CarouselItem
link={{type: 'image', url: image}}
onClose={() => {
image = null
}} />