Browse Source

feat: render npub and nprofile mentions

so that they display the inline UserHeader rather long npub terxt
master
DanConwayDev 2 years ago
parent
commit
44fb751eca
No known key found for this signature in database
GPG Key ID: 68E15486D73F75E1
  1. 1
      package.json
  2. 7
      src/lib/components/events/content/ParsedContent.svelte
  3. 56
      src/lib/components/events/content/utils.ts
  4. 36
      yarn.lock

1
package.json

@ -68,6 +68,7 @@
"daisyui": "^4.4", "daisyui": "^4.4",
"dayjs": "^1.11.10", "dayjs": "^1.11.10",
"highlight.js": "^11.9.0", "highlight.js": "^11.9.0",
"nostr-tools": "^2.5.0",
"parse-diff": "^0.11.1", "parse-diff": "^0.11.1",
"ramda": "^0.29.1", "ramda": "^0.29.1",
"svelte-markdown": "^0.4.1" "svelte-markdown": "^0.4.1"

7
src/lib/components/events/content/ParsedContent.svelte

@ -4,10 +4,13 @@
isImage, isImage,
isParsedLink, isParsedLink,
isParsedNewLine, isParsedNewLine,
isParsedNprofile,
isParsedNpub,
isParsedText, isParsedText,
parseContent, parseContent,
type ParsedPart, type ParsedPart,
} from './utils' } from './utils'
import UserHeader from '$lib/components/users/UserHeader.svelte'
export let content: string = '' export let content: string = ''
export let tags: NDKTag[] = [] export let tags: NDKTag[] = []
@ -31,6 +34,10 @@
{part.url.replace(/https?:\/\/(www\.)?/, '')} {part.url.replace(/https?:\/\/(www\.)?/, '')}
</a> </a>
{/if} {/if}
{:else if isParsedNpub(part) || isParsedNprofile(part)}
<div class="badge badge-neutral">
<UserHeader user={part.hex} inline={true} size="sm" />
</div>
{:else if isParsedText(part)} {:else if isParsedText(part)}
{part.value} {part.value}
{/if} {/if}

56
src/lib/components/events/content/utils.ts

@ -1,4 +1,5 @@
import type { NDKTag } from '@nostr-dev-kit/ndk' import type { NDKTag } from '@nostr-dev-kit/ndk'
import { nip19 } from 'nostr-tools'
import { last } from 'ramda' import { last } from 'ramda'
export const TOPIC = 'topic' export const TOPIC = 'topic'
@ -7,8 +8,6 @@ export const HTML = 'html'
export const INVOICE = 'invoice' export const INVOICE = 'invoice'
export const NOSTR_NOTE = 'nostr:note' export const NOSTR_NOTE = 'nostr:note'
export const NOSTR_NEVENT = 'nostr:nevent' export const NOSTR_NEVENT = 'nostr:nevent'
export const NOSTR_NPUB = 'nostr:npub'
export const NOSTR_NPROFILE = 'nostr:nprofile'
export const NOSTR_NADDR = 'nostr:naddr' export const NOSTR_NADDR = 'nostr:naddr'
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -53,6 +52,22 @@ type Imeta = {
blurhash: string | undefined blurhash: string | undefined
} }
export const NOSTR_NPUB = 'nostr:npub'
type PartTypeNpub = 'nostr:npub'
export type ParsedNpub = {
type: PartTypeNpub
hex: string
}
export const NOSTR_NPROFILE = 'nostr:nprofile'
type PartTypeNprofile = 'nostr:nprofile'
export type ParsedNprofile = {
type: PartTypeNprofile
hex: string
relays: string[]
}
export type ParsedNostrLink = ParsedNpub | ParsedNprofile
export const TEXT = 'text' export const TEXT = 'text'
type PartTypeText = 'text' type PartTypeText = 'text'
export type ParsedText = { export type ParsedText = {
@ -60,7 +75,11 @@ export type ParsedText = {
value: string value: string
} }
export type ParsedPart = ParsedNewLine | ParsedText | ParsedLink export type ParsedPart =
| ParsedNewLine
| ParsedText
| ParsedNostrLink
| ParsedLink
export const isParsedNewLine = (part: ParsedPart): part is ParsedNewLine => export const isParsedNewLine = (part: ParsedPart): part is ParsedNewLine =>
part.type == NEWLINE part.type == NEWLINE
@ -68,6 +87,15 @@ export const isParsedNewLine = (part: ParsedPart): part is ParsedNewLine =>
export const isParsedLink = (part: ParsedPart): part is ParsedLink => export const isParsedLink = (part: ParsedPart): part is ParsedLink =>
part.type == LINK part.type == LINK
export const isParsedNostrLink = (part: ParsedPart): part is ParsedNostrLink =>
part.type == NOSTR_NPUB || part.type == NOSTR_NPROFILE
export const isParsedNpub = (part: ParsedPart): part is ParsedNpub =>
part.type == NOSTR_NPUB
export const isParsedNprofile = (part: ParsedPart): part is ParsedNprofile =>
part.type == NOSTR_NPROFILE
export const isParsedText = (part: ParsedPart): part is ParsedText => export const isParsedText = (part: ParsedPart): part is ParsedText =>
part.type == TEXT part.type == TEXT
@ -140,9 +168,29 @@ export const parseContent = (content: string, tags: NDKTag[]): ParsedPart[] => {
] ]
} }
const parseNostrLinks = (): undefined | [string, ParsedNostrLink] => {
const bech32: string = first(
text.match(
/^(web\+)?(nostr:)?\/?\/?n(event|ote|profile|pub|addr)1[\d\w]+/i
)
)
if (bech32) {
try {
const entity = fromNostrURI(bech32)
const decoded = nip19.decode(entity)
if (decoded.type === 'npub') {
return [bech32, { type: NOSTR_NPUB, hex: decoded.data }]
}
if (decoded.type === 'nprofile') {
return [bech32, { type: NOSTR_NPUB, hex: decoded.data.pubkey }]
}
} catch {}
}
}
while (text) { while (text) {
// The order that this runs matters // The order that this runs matters
const part = parseNewline() || parseUrl() const part = parseNewline() || parseUrl() || parseNostrLinks()
if (part) { if (part) {
if (buffer) { if (buffer) {

36
yarn.lock

@ -1971,6 +1971,11 @@
resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-0.2.0.tgz#a12cda60f3cf1ab5d7c77068c3711d2366649ed7" resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-0.2.0.tgz#a12cda60f3cf1ab5d7c77068c3711d2366649ed7"
integrity sha512-6YBxJDAapHSdd3bLDv6x2wRPwq4QFMUaB3HvljNBUTThDd12eSm7/3F+2lnfzx2jvM+S6Nsy0jEt9QbPqSwqRw== integrity sha512-6YBxJDAapHSdd3bLDv6x2wRPwq4QFMUaB3HvljNBUTThDd12eSm7/3F+2lnfzx2jvM+S6Nsy0jEt9QbPqSwqRw==
"@noble/ciphers@^0.5.1":
version "0.5.2"
resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-0.5.2.tgz#879367fd51d59185259eb844d5b9a78f408b4a12"
integrity sha512-GADtQmZCdgbnNp+daPLc3OY3ibEtGGDV/+CzeM3MFnhiQ7ELQKlsHWYq0YbYUXx4jU3/Y1erAxU6r+hwpewqmQ==
"@noble/curves@1.1.0", "@noble/curves@~1.1.0": "@noble/curves@1.1.0", "@noble/curves@~1.1.0":
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d"
@ -1978,11 +1983,23 @@
dependencies: dependencies:
"@noble/hashes" "1.3.1" "@noble/hashes" "1.3.1"
"@noble/curves@1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35"
integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==
dependencies:
"@noble/hashes" "1.3.2"
"@noble/hashes@1.3.1": "@noble/hashes@1.3.1":
version "1.3.1" version "1.3.1"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9"
integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==
"@noble/hashes@1.3.2":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39"
integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==
"@noble/hashes@^1.3.1": "@noble/hashes@^1.3.1":
version "1.4.0" version "1.4.0"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426"
@ -8606,6 +8623,25 @@ nostr-tools@^1.15.0:
"@scure/bip32" "1.3.1" "@scure/bip32" "1.3.1"
"@scure/bip39" "1.2.1" "@scure/bip39" "1.2.1"
nostr-tools@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/nostr-tools/-/nostr-tools-2.5.0.tgz#083c8a22eb88c65f30d88a25e200ea2274348663"
integrity sha512-G02O3JYNCfhx9NDjd3NOCw/5ck8PX5hiOIhHKpsXyu49ZtZbxGH3OLP9tf0fpUZ+EVWdjIYFR689sV0i7+TOng==
dependencies:
"@noble/ciphers" "^0.5.1"
"@noble/curves" "1.2.0"
"@noble/hashes" "1.3.1"
"@scure/base" "1.1.1"
"@scure/bip32" "1.3.1"
"@scure/bip39" "1.2.1"
optionalDependencies:
nostr-wasm v0.1.0
nostr-wasm@v0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/nostr-wasm/-/nostr-wasm-0.1.0.tgz#17af486745feb2b7dd29503fdd81613a24058d94"
integrity sha512-78BTryCLcLYv96ONU8Ws3Q1JzjlAt+43pWQhIl86xZmWeegYCNLPml7yQ+gG3vR6V5h4XGj+TxO+SS5dsThQIA==
npm-run-path@^4.0.1: npm-run-path@^4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"

Loading…
Cancel
Save