refactor: post editor

This commit is contained in:
codytseng
2025-05-23 22:47:31 +08:00
parent 3d06421acb
commit 78725d1e88
31 changed files with 1603 additions and 766 deletions

View File

@@ -1,5 +1,6 @@
import { ApplicationDataKey, ExtendedKind } from '@/constants'
import client from '@/services/client.service'
import mediaUpload from '@/services/media-upload.service'
import { TDraftEvent, TEmoji, TMailboxRelay, TRelaySet } from '@/types'
import dayjs from 'dayjs'
import { Event, kinds } from 'nostr-tools'
@@ -61,7 +62,6 @@ export function createRepostDraftEvent(event: Event): TDraftEvent {
export async function createShortTextNoteDraftEvent(
content: string,
pictureInfos: { url: string; tags: string[][] }[],
mentions: string[],
options: {
parentEvent?: Event
@@ -80,7 +80,7 @@ export async function createShortTextNoteDraftEvent(
// imeta tags
const { images } = extractImagesFromContent(content)
if (images && images.length) {
tags.push(...generateImetaTags(images, pictureInfos))
tags.push(...generateImetaTags(images))
}
// q tags
@@ -168,7 +168,6 @@ export async function createPictureNoteDraftEvent(
export async function createCommentDraftEvent(
content: string,
parentEvent: Event,
pictureInfos: { url: string; tags: string[][] }[],
mentions: string[],
options: {
addClientTag?: boolean
@@ -192,7 +191,7 @@ export async function createCommentDraftEvent(
const { images } = extractImagesFromContent(content)
if (images && images.length) {
tags.push(...generateImetaTags(images, pictureInfos))
tags.push(...generateImetaTags(images))
}
tags.push(
@@ -300,11 +299,11 @@ export function createBookmarkDraftEvent(tags: string[][], content = ''): TDraft
}
}
function generateImetaTags(imageUrls: string[], pictureInfos: { url: string; tags: string[][] }[]) {
function generateImetaTags(imageUrls: string[]) {
return imageUrls
.map((imageUrl) => {
const pictureInfo = pictureInfos.find((info) => info.url === imageUrl)
return pictureInfo ? ['imeta', ...pictureInfo.tags.map(([n, v]) => `${n} ${v}`)] : null
const tag = mediaUpload.getImetaTagByUrl(imageUrl)
return tag ?? null
})
.filter(Boolean) as string[][]
}

View File

@@ -4,7 +4,7 @@ import { TEmoji, TImageInfo, TRelayList, TRelaySet } from '@/types'
import { LRUCache } from 'lru-cache'
import { Event, kinds, nip19 } from 'nostr-tools'
import { getAmountFromInvoice, getLightningAddressFromProfile } from './lightning'
import { formatPubkey } from './pubkey'
import { formatPubkey, pubkeyToNpub } from './pubkey'
import {
extractImageInfoFromTag,
generateEventIdFromETag,
@@ -180,6 +180,7 @@ export function getProfileFromProfileEvent(event: Event) {
profileObj.nip05?.split('@')[0]?.trim()
return {
pubkey: event.pubkey,
npub: pubkeyToNpub(event.pubkey) ?? '',
banner: profileObj.banner,
avatar: profileObj.picture,
username: username || formatPubkey(event.pubkey),
@@ -196,6 +197,7 @@ export function getProfileFromProfileEvent(event: Event) {
console.error(err)
return {
pubkey: event.pubkey,
npub: pubkeyToNpub(event.pubkey) ?? '',
username: formatPubkey(event.pubkey)
}
}

View File

@@ -23,6 +23,13 @@ export function formatNpub(npub: string, length = 12) {
return npub.slice(0, prefixLength) + '...' + npub.slice(-suffixLength)
}
export function formatUserId(userId: string) {
if (userId.startsWith('npub1')) {
return formatNpub(userId)
}
return formatPubkey(userId)
}
export function pubkeyToNpub(pubkey: string) {
try {
return nip19.npubEncode(pubkey)

40
src/lib/tiptap.ts Normal file
View File

@@ -0,0 +1,40 @@
import { JSONContent } from '@tiptap/react'
import { nip19 } from 'nostr-tools'
export function parseEditorJsonToText(node?: JSONContent) {
const text = _parseEditorJsonToText(node).trim()
const regex = /(?<=^|\s)(nevent|naddr|nprofile|npub)[a-zA-Z0-9]+/g
return text.replace(regex, (match) => {
try {
nip19.decode(match)
return `nostr:${match}`
} catch {
return match
}
})
}
function _parseEditorJsonToText(node?: JSONContent): string {
if (!node) return ''
if (typeof node === 'string') return node
if (node.type === 'text') {
return node.text || ''
}
if (Array.isArray(node.content)) {
return (
node.content.map(_parseEditorJsonToText).join('') + (node.type === 'paragraph' ? '\n' : '')
)
}
switch (node.type) {
case 'paragraph':
return '\n'
case 'mention':
return node.attrs ? `nostr:${node.attrs.id}` : ''
default:
return ''
}
}