feat: add imeta tags
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
|||||||
createPictureNoteDraftEvent,
|
createPictureNoteDraftEvent,
|
||||||
createShortTextNoteDraftEvent
|
createShortTextNoteDraftEvent
|
||||||
} from '@/lib/draft-event'
|
} from '@/lib/draft-event'
|
||||||
|
import { extractImagesFromContent } from '@/lib/event'
|
||||||
import { useNostr } from '@/providers/NostrProvider'
|
import { useNostr } from '@/providers/NostrProvider'
|
||||||
import client from '@/services/client.service'
|
import client from '@/services/client.service'
|
||||||
import { ChevronDown, LoaderCircle } from 'lucide-react'
|
import { ChevronDown, LoaderCircle } from 'lucide-react'
|
||||||
@@ -18,7 +19,6 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import Mentions from './Mentions'
|
import Mentions from './Mentions'
|
||||||
import Preview from './Preview'
|
import Preview from './Preview'
|
||||||
import Uploader from './Uploader'
|
import Uploader from './Uploader'
|
||||||
import { extractImagesFromContent } from '@/lib/event'
|
|
||||||
|
|
||||||
export default function PostContent({
|
export default function PostContent({
|
||||||
defaultContent = '',
|
defaultContent = '',
|
||||||
@@ -33,6 +33,7 @@ export default function PostContent({
|
|||||||
const { toast } = useToast()
|
const { toast } = useToast()
|
||||||
const { publish, checkLogin } = useNostr()
|
const { publish, checkLogin } = useNostr()
|
||||||
const [content, setContent] = useState(defaultContent)
|
const [content, setContent] = useState(defaultContent)
|
||||||
|
const [pictureInfos, setPictureInfos] = useState<{ url: string; tags: string[][] }[]>([])
|
||||||
const [posting, setPosting] = useState(false)
|
const [posting, setPosting] = useState(false)
|
||||||
const [showMoreOptions, setShowMoreOptions] = useState(false)
|
const [showMoreOptions, setShowMoreOptions] = useState(false)
|
||||||
const [addClientTag, setAddClientTag] = useState(false)
|
const [addClientTag, setAddClientTag] = useState(false)
|
||||||
@@ -73,10 +74,10 @@ export default function PostContent({
|
|||||||
}
|
}
|
||||||
const draftEvent =
|
const draftEvent =
|
||||||
isPictureNote && !parentEvent && hasImages
|
isPictureNote && !parentEvent && hasImages
|
||||||
? await createPictureNoteDraftEvent(content, { addClientTag })
|
? await createPictureNoteDraftEvent(content, pictureInfos, { addClientTag })
|
||||||
: parentEvent && parentEvent.kind !== kinds.ShortTextNote
|
: parentEvent && parentEvent.kind !== kinds.ShortTextNote
|
||||||
? await createCommentDraftEvent(content, parentEvent, { addClientTag })
|
? await createCommentDraftEvent(content, parentEvent, pictureInfos, { addClientTag })
|
||||||
: await createShortTextNoteDraftEvent(content, {
|
: await createShortTextNoteDraftEvent(content, pictureInfos, {
|
||||||
parentEvent,
|
parentEvent,
|
||||||
addClientTag
|
addClientTag
|
||||||
})
|
})
|
||||||
@@ -127,7 +128,12 @@ export default function PostContent({
|
|||||||
{content && <Preview content={content} />}
|
{content && <Preview content={content} />}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex gap-2 items-center">
|
<div className="flex gap-2 items-center">
|
||||||
<Uploader setContent={setContent} />
|
<Uploader
|
||||||
|
onUploadSuccess={({ url, tags }) => {
|
||||||
|
setPictureInfos((prev) => [...prev, { url, tags }])
|
||||||
|
setContent((prev) => `${prev}\n${url}`)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<Button
|
<Button
|
||||||
variant="link"
|
variant="link"
|
||||||
className="text-foreground gap-0 px-0"
|
className="text-foreground gap-0 px-0"
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import { useRef, useState } from 'react'
|
|||||||
import { z } from 'zod'
|
import { z } from 'zod'
|
||||||
|
|
||||||
export default function Uploader({
|
export default function Uploader({
|
||||||
setContent
|
onUploadSuccess
|
||||||
}: {
|
}: {
|
||||||
setContent: React.Dispatch<React.SetStateAction<string>>
|
onUploadSuccess: ({ url, tags }: { url: string; tags: string[][] }) => void
|
||||||
}) {
|
}) {
|
||||||
const [uploading, setUploading] = useState(false)
|
const [uploading, setUploading] = useState(false)
|
||||||
const { signHttpAuth } = useNostr()
|
const { signHttpAuth } = useNostr()
|
||||||
@@ -42,7 +42,7 @@ export default function Uploader({
|
|||||||
const tags = z.array(z.array(z.string())).parse(data.nip94_event?.tags ?? [])
|
const tags = z.array(z.array(z.string())).parse(data.nip94_event?.tags ?? [])
|
||||||
const imageUrl = tags.find(([tagName]) => tagName === 'url')?.[1]
|
const imageUrl = tags.find(([tagName]) => tagName === 'url')?.[1]
|
||||||
if (imageUrl) {
|
if (imageUrl) {
|
||||||
setContent((prevContent) => `${prevContent}\n${imageUrl}`)
|
onUploadSuccess({ url: imageUrl, tags })
|
||||||
} else {
|
} else {
|
||||||
throw new Error('No image url found')
|
throw new Error('No image url found')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ export function createRepostDraftEvent(event: Event): TDraftEvent {
|
|||||||
|
|
||||||
export async function createShortTextNoteDraftEvent(
|
export async function createShortTextNoteDraftEvent(
|
||||||
content: string,
|
content: string,
|
||||||
|
pictureInfos: { url: string; tags: string[][] }[],
|
||||||
options: {
|
options: {
|
||||||
parentEvent?: Event
|
parentEvent?: Event
|
||||||
addClientTag?: boolean
|
addClientTag?: boolean
|
||||||
@@ -70,6 +71,11 @@ export async function createShortTextNoteDraftEvent(
|
|||||||
tags.push(['e', parentEventId, '', 'reply'])
|
tags.push(['e', parentEventId, '', 'reply'])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { images } = extractImagesFromContent(content)
|
||||||
|
if (images && images.length) {
|
||||||
|
tags.push(...generateImetaTags(images, pictureInfos))
|
||||||
|
}
|
||||||
|
|
||||||
if (options.addClientTag) {
|
if (options.addClientTag) {
|
||||||
tags.push(['client', 'jumble'])
|
tags.push(['client', 'jumble'])
|
||||||
}
|
}
|
||||||
@@ -98,6 +104,7 @@ export function createRelaySetDraftEvent(relaySet: TRelaySet): TDraftEvent {
|
|||||||
|
|
||||||
export async function createPictureNoteDraftEvent(
|
export async function createPictureNoteDraftEvent(
|
||||||
content: string,
|
content: string,
|
||||||
|
pictureInfos: { url: string; tags: string[][] }[],
|
||||||
options: {
|
options: {
|
||||||
addClientTag?: boolean
|
addClientTag?: boolean
|
||||||
} = {}
|
} = {}
|
||||||
@@ -109,8 +116,7 @@ export async function createPictureNoteDraftEvent(
|
|||||||
throw new Error('No images found in content')
|
throw new Error('No images found in content')
|
||||||
}
|
}
|
||||||
|
|
||||||
const tags = images
|
const tags = generateImetaTags(images, pictureInfos)
|
||||||
.map((image) => ['imeta', `url ${image}`])
|
|
||||||
.concat(pubkeys.map((pubkey) => ['p', pubkey]))
|
.concat(pubkeys.map((pubkey) => ['p', pubkey]))
|
||||||
.concat(quoteEventIds.map((eventId) => ['q', eventId]))
|
.concat(quoteEventIds.map((eventId) => ['q', eventId]))
|
||||||
.concat(hashtags.map((hashtag) => ['t', hashtag]))
|
.concat(hashtags.map((hashtag) => ['t', hashtag]))
|
||||||
@@ -130,6 +136,7 @@ export async function createPictureNoteDraftEvent(
|
|||||||
export async function createCommentDraftEvent(
|
export async function createCommentDraftEvent(
|
||||||
content: string,
|
content: string,
|
||||||
parentEvent: Event,
|
parentEvent: Event,
|
||||||
|
pictureInfos: { url: string; tags: string[][] }[],
|
||||||
options: {
|
options: {
|
||||||
addClientTag?: boolean
|
addClientTag?: boolean
|
||||||
} = {}
|
} = {}
|
||||||
@@ -153,12 +160,15 @@ export async function createCommentDraftEvent(
|
|||||||
['e', parentEventId],
|
['e', parentEventId],
|
||||||
['k', parentEventKind.toString()],
|
['k', parentEventKind.toString()],
|
||||||
['p', parentEventPubkey]
|
['p', parentEventPubkey]
|
||||||
].concat(
|
]
|
||||||
pubkeys
|
.concat(pubkeys.map((pubkey) => ['p', pubkey]))
|
||||||
.map((pubkey) => ['p', pubkey])
|
.concat(quoteEventIds.map((eventId) => ['q', eventId]))
|
||||||
.concat(quoteEventIds.map((eventId) => ['q', eventId]))
|
.concat(hashtags.map((hashtag) => ['t', hashtag]))
|
||||||
.concat(hashtags.map((hashtag) => ['t', hashtag]))
|
|
||||||
)
|
const { images } = extractImagesFromContent(content)
|
||||||
|
if (images && images.length) {
|
||||||
|
tags.push(...generateImetaTags(images, pictureInfos))
|
||||||
|
}
|
||||||
|
|
||||||
if (options.addClientTag) {
|
if (options.addClientTag) {
|
||||||
tags.push(['client', 'jumble'])
|
tags.push(['client', 'jumble'])
|
||||||
@@ -171,3 +181,12 @@ export async function createCommentDraftEvent(
|
|||||||
created_at: dayjs().unix()
|
created_at: dayjs().unix()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generateImetaTags(imageUrls: string[], pictureInfos: { url: string; tags: string[][] }[]) {
|
||||||
|
return imageUrls.map((imageUrl) => {
|
||||||
|
const pictureInfo = pictureInfos.find((info) => info.url === imageUrl)
|
||||||
|
return pictureInfo
|
||||||
|
? ['imeta', ...pictureInfo.tags.map(([n, v]) => `${n} ${v}`)]
|
||||||
|
: ['imeta', `url ${imageUrl}`]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user