Files
lumina/components/searchComponents/SearchNotesBox.tsx
Silberengel 525a0850b1 Upload from url PART 2 (#139)
* add URL option to image upload

* Full NIP-68 and NIP-71 implementation

* changed deprecated note ids to nevent ids, with backward-compatability

* interim state reels implementation

* Fixed uploading from URL and added a Cancel button to the upload modal. Couldn't get rid of the errors.

* Added ability to upload kinds 20, 21, 22, along with source tags (e, a, or u). Includes validation check.

* added thumbnail support

* included kind 21 and kind 22 in the feeds and searches

* Implement inboxes/outboxes

* implemented thumbnails in the profile feed

* enhanced reels feed with #reels

* interim implementation of pins

* added pins

* fixed the pins

* tidied up the reels

* fixed the uploader

* Fixed build

* update reels feed with the one from Lumina main

* fixed the reels interactions

* Added audio controls

* Interim reelfeed state

* feed working again

* full fead

---------

Co-authored-by: Silberengel <silberengel7@proton.com>
2025-09-01 23:05:54 +02:00

108 lines
3.1 KiB
TypeScript

import React from 'react';
import { useNostrEvents, useProfile } from "nostr-react";
import {
nip19,
} from "nostr-tools";
import {
Card,
CardContent,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip"
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel"
import ReactionButton from '@/components/ReactionButton';
import { Avatar, AvatarImage } from '@/components/ui/avatar';
import ViewRawButton from '@/components/ViewRawButton';
import Link from 'next/link';
import { Event as NostrEvent } from "nostr-tools";
import ProfileInfoCard from '../ProfileInfoCard';
import NoteCard from '../NoteCard';
import KIND20Card from '../KIND20Card';
import { getImageUrl } from '@/utils/utils';
// Function to extract video URL from imeta tags
const getVideoUrl = (tags: string[][]): string | null => {
for (const tag of tags) {
if (tag[0] === 'imeta') {
for (let i = 1; i < tag.length; i++) {
if (tag[i].startsWith('url ')) {
return tag[i].substring(4);
}
}
}
}
return null;
};
interface SearchNotesBoxProps {
searchTag: string;
}
const SearchNotesBox: React.FC<SearchNotesBoxProps> = ({ searchTag }) => {
const { events: notes } = useNostrEvents({
filter: {
kinds: [1, 20, 21, 22],
search: searchTag,
limit: 10,
},
});
return (
<>
<Card>
<CardHeader>
Notes
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 gap-6">
{notes.map((event: NostrEvent) => {
const imageUrl = getImageUrl(event.tags);
const isVideo = event.kind === 21 || event.kind === 22;
if (event.kind === 1) {
return (
<NoteCard event={event} eventId={event.id} pubkey={event.pubkey} showViewNoteCardButton={true} tags={event.tags} text={event.content} key={event.id} />
);
} else if (isVideo) {
// Use NoteCard for video content
const videoUrl = getVideoUrl(event.tags);
const contentWithVideo = videoUrl ? `${event.content}\n${videoUrl}` : event.content;
return (
<NoteCard
key={event.id}
pubkey={event.pubkey}
text={contentWithVideo}
eventId={event.id}
tags={event.tags}
event={event}
showViewNoteCardButton={true}
/>
);
} else if (event.kind === 20) {
return (
<KIND20Card key={event.id} pubkey={event.pubkey} text={event.content} image={imageUrl} event={event} tags={event.tags} eventId={event.id} showViewNoteCardButton={true}/>
);
}
return null;
})}
</div>
</CardContent>
</Card>
</>
);
}
export default SearchNotesBox;