mirror of
https://github.com/coracle-social/coracle.git
synced 2024-10-06 11:43:30 +00:00
Fix mention parsing
This commit is contained in:
parent
ce6993b214
commit
9bc5a35957
14
ROADMAP.md
14
ROADMAP.md
@ -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
|
||||
|
@ -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
|
||||
|
@ -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}
|
||||
<Spinner />
|
||||
{: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}}>
|
||||
Unable to load a preview for {link.url}
|
||||
</p>
|
||||
{/if}
|
||||
<p class="mb-1 py-24 px-12 text-center text-gray-5">
|
||||
Unable to load a preview for {link.url}
|
||||
</p>
|
||||
{/await}
|
||||
{/if}
|
||||
</Anchor>
|
||||
|
@ -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\.)?/, "")}
|
||||
|
@ -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}
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}} />
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
}} />
|
||||
|
Loading…
Reference in New Issue
Block a user