feat: implement room and space mentions (#130) #154
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import {call, ellipsize, displayUrl, postJson} from "@welshman/lib"
|
||||
import {isRelayUrl, getTagValue, normalizeRelayUrl} from "@welshman/util"
|
||||
import {isRelayUrl, getTagValue, normalizeRelayUrl, displayRelayUrl} from "@welshman/util"
|
||||
import {Capacitor} from "@capacitor/core"
|
||||
import {preventDefault, stopPropagation} from "@lib/html"
|
||||
import LinkRound from "@assets/icons/link-round.svg?dataurl"
|
||||
@@ -15,6 +15,9 @@
|
||||
IMAGE_CONTENT_TYPES,
|
||||
VIDEO_CONTENT_TYPES,
|
||||
THUMBNAIL_URL,
|
||||
displayRoom,
|
||||
isRoomId,
|
||||
splitRoomId,
|
||||
} from "@app/core/state"
|
||||
import {makeRoomPath, makeSpacePath} from "@app/util/routes"
|
||||
|
||||
@@ -23,25 +26,43 @@
|
||||
let hideImage = $state(false)
|
||||
|
||||
const url = value.url.toString()
|
||||
const splitRoomReference = (input: string) => {
|
||||
const separatorIndex = input.indexOf("'")
|
||||
|
||||
if (separatorIndex === -1) {
|
||||
const roomReference = call(() => {
|
||||
if (!isRoomId(url)) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const roomUrl = input.slice(0, separatorIndex)
|
||||
const h = input.slice(separatorIndex + 1)
|
||||
const [roomUrl, h] = splitRoomId(url)
|
||||
|
Khushvendra marked this conversation as resolved
Outdated
|
||||
|
||||
if (!h || !isRelayUrl(roomUrl)) {
|
||||
if (!roomUrl || !h || !isRelayUrl(roomUrl)) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return {url: normalizeRelayUrl(roomUrl), h}
|
||||
}
|
||||
})
|
||||
|
||||
const relayReference = call(() => {
|
||||
if (roomReference || !isRelayUrl(url)) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return normalizeRelayUrl(url)
|
||||
})
|
||||
|
||||
const label = call(() => {
|
||||
if (roomReference) {
|
||||
const spaceName = displayRelayUrl(roomReference.url)
|
||||
const roomName = displayRoom(roomReference.url, roomReference.h)
|
||||
|
||||
return `~${spaceName} / ${roomName}`
|
||||
}
|
||||
|
||||
if (relayReference) {
|
||||
|
hodlbod marked this conversation as resolved
hodlbod
commented
It doesn't make sense to use ContentLinkUrl in this case since because we're providing our own content, it's doing basically nothing. Remove the children and showIcon props from ContentLinkUrl. You can might be able to remove the labelClass as well, not sure. It doesn't make sense to use ContentLinkUrl in this case since because we're providing our own content, it's doing basically nothing. Remove the children and showIcon props from ContentLinkUrl. You can might be able to remove the labelClass as well, not sure.
|
||||
return `~${displayRelayUrl(relayReference)}`
|
||||
}
|
||||
|
||||
return displayUrl(url)
|
||||
})
|
||||
|
||||
const roomReference = splitRoomReference(url)
|
||||
const relayReference = !roomReference && isRelayUrl(url) ? normalizeRelayUrl(url) : undefined
|
||||
const fileType = getTagValue("file-type", event.tags) || ""
|
||||
const [href, external] = call(() => {
|
||||
if (roomReference) return [makeRoomPath(roomReference.url, roomReference.h), false]
|
||||
@@ -94,7 +115,7 @@
|
||||
{:else if roomReference || relayReference}
|
||||
<div class="bg-alt p-4 leading-normal">
|
||||
<Icon icon={LinkRound} size={3} class="inline-block" />
|
||||
<span class="ml-2">{displayUrl(url)}</span>
|
||||
<span class="ml-2">{label}</span>
|
||||
</div>
|
||||
{:else}
|
||||
{#await loadPreview()}
|
||||
|
||||
@@ -1,40 +1,65 @@
|
||||
<script lang="ts">
|
||||
import {call, displayUrl} from "@welshman/lib"
|
||||
import {isRelayUrl, getTagValue, normalizeRelayUrl} from "@welshman/util"
|
||||
import {isRelayUrl, getTagValue, normalizeRelayUrl, displayRelayUrl} from "@welshman/util"
|
||||
import {preventDefault, stopPropagation} from "@lib/html"
|
||||
import LinkRound from "@assets/icons/link-round.svg?dataurl"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Link from "@lib/components/Link.svelte"
|
||||
import ContentLinkDetail from "@app/components/ContentLinkDetail.svelte"
|
||||
import {pushModal} from "@app/util/modal"
|
||||
import {PLATFORM_URL, IMAGE_CONTENT_TYPES} from "@app/core/state"
|
||||
import {
|
||||
PLATFORM_URL,
|
||||
IMAGE_CONTENT_TYPES,
|
||||
displayRoom,
|
||||
isRoomId,
|
||||
splitRoomId,
|
||||
} from "@app/core/state"
|
||||
import {makeRoomPath, makeSpacePath} from "@app/util/routes"
|
||||
|
||||
const {value, event} = $props()
|
||||
|
||||
const url = value.url.toString()
|
||||
const splitRoomReference = (input: string) => {
|
||||
const separatorIndex = input.indexOf("'")
|
||||
|
||||
if (separatorIndex === -1) {
|
||||
const roomReference = call(() => {
|
||||
if (!isRoomId(url)) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const roomUrl = input.slice(0, separatorIndex)
|
||||
const h = input.slice(separatorIndex + 1)
|
||||
const [roomUrl, h] = splitRoomId(url)
|
||||
|
||||
if (!h || !isRelayUrl(roomUrl)) {
|
||||
if (!roomUrl || !h || !isRelayUrl(roomUrl)) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return {url: normalizeRelayUrl(roomUrl), h}
|
||||
}
|
||||
})
|
||||
|
||||
const relayReference = call(() => {
|
||||
if (roomReference || !isRelayUrl(url)) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return normalizeRelayUrl(url)
|
||||
})
|
||||
|
||||
const label = call(() => {
|
||||
if (roomReference) {
|
||||
const spaceName = displayRelayUrl(roomReference.url)
|
||||
const roomName = displayRoom(roomReference.url, roomReference.h)
|
||||
|
||||
return `~${spaceName} / ${roomName}`
|
||||
}
|
||||
|
||||
if (relayReference) {
|
||||
return `~${displayRelayUrl(relayReference)}`
|
||||
}
|
||||
|
||||
return displayUrl(url)
|
||||
})
|
||||
|
Khushvendra marked this conversation as resolved
Outdated
hodlbod
commented
Let's refactor this a bit. Go ahead and add a new component called Let's refactor this a bit. Go ahead and add a new component called `ContentLinkUrl` that encapsulates this logic and is used in both inline and block contexts. In the block case you'll still need to detect whether the url is a room or relay, but that should be as simple as `isRoomId(url) || isRelayUrl(url)`
|
||||
|
||||
const roomReference = splitRoomReference(url)
|
||||
const fileType = getTagValue("file-type", event.tags) || ""
|
||||
const [href, external] = call(() => {
|
||||
if (roomReference) return [makeRoomPath(roomReference.url, roomReference.h), false]
|
||||
if (isRelayUrl(url)) return [makeSpacePath(normalizeRelayUrl(url)), false]
|
||||
if (relayReference) return [makeSpacePath(relayReference), false]
|
||||
if (url.startsWith(PLATFORM_URL)) return [url.replace(PLATFORM_URL, ""), false]
|
||||
|
||||
return [url, true]
|
||||
@@ -55,6 +80,6 @@
|
||||
{:else}
|
||||
<Link {external} {href} class="link-content whitespace-nowrap">
|
||||
<Icon icon={LinkRound} size={3} class="inline-block" />
|
||||
{displayUrl(url)}
|
||||
{label}
|
||||
</Link>
|
||||
{/if}
|
||||
|
||||
@@ -596,6 +596,8 @@ export const getRoomType = (room: RoomMeta): RoomType =>
|
||||
|
||||
export const makeRoomId = (url: string, h: string) => `${url}'${h}`
|
||||
|
||||
export const isRoomId = (id: string) => id.includes("'")
|
||||
|
||||
export const splitRoomId = (id: string) => id.split("'")
|
||||
|
||||
export const hasNip29 = (relay?: RelayProfile) =>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type {NodeViewRendererProps} from "@tiptap/core"
|
||||
import {displayRelayUrl} from "@welshman/util"
|
||||
import {deriveRoom} from "@app/core/state"
|
||||
|
||||
export const RoomReferenceNodeView = ({node}: NodeViewRendererProps) => {
|
||||
@@ -10,7 +11,7 @@ export const RoomReferenceNodeView = ({node}: NodeViewRendererProps) => {
|
||||
dom.classList.add("tiptap-object")
|
||||
|
||||
const unsubRoom = room.subscribe($room => {
|
||||
dom.textContent = `~${$room.name || h}`
|
||||
dom.textContent = `~${displayRelayUrl(url)} / ${$room.name || h}`
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
@@ -9,9 +9,10 @@
|
||||
const {value}: Props = $props()
|
||||
const [url = "", h = ""] = splitRoomId(value)
|
||||
const room = deriveRoom(url, h)
|
||||
|
||||
const label = $derived(`~${displayRelayUrl(url)} / ${$room.name || h}`)
|
||||
</script>
|
||||
|
||||
<div class="flex max-w-full flex-col gap-1">
|
||||
<div class="overflow-hidden text-ellipsis text-base font-semibold">~{$room.name || h}</div>
|
||||
<div class="overflow-hidden text-ellipsis text-sm opacity-75">{displayRelayUrl(url)}'{h}</div>
|
||||
<div class="max-w-full overflow-hidden text-ellipsis text-base font-semibold">
|
||||
|
Khushvendra marked this conversation as resolved
Outdated
hodlbod
commented
This should be displayed the same way we'll ultimately render it, as This should be displayed the same way we'll ultimately render it, as `~Space Name / Room Name`
|
||||
{label}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user
I think we can live dangerously here by adding
isRoomIdto core/state which just checks for an apostrophe, and usesplitRoomIdfrom that same file.