mirror of
https://github.com/lumina-rocks/lumina.git
synced 2026-04-09 23:16:47 +02:00
* 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>
110 lines
4.0 KiB
TypeScript
110 lines
4.0 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { useProfile } from "nostr-react";
|
|
import {
|
|
nip19,
|
|
} from "nostr-tools";
|
|
import {
|
|
Card,
|
|
SmallCardContent,
|
|
} from "@/components/ui/card"
|
|
import Image from 'next/image';
|
|
import Link from 'next/link';
|
|
import { PlayIcon, StackIcon, VideoIcon } from '@radix-ui/react-icons';
|
|
|
|
interface NoteCardProps {
|
|
pubkey: string;
|
|
text: string;
|
|
eventId: string;
|
|
tags: string[][];
|
|
event: any;
|
|
linkToNote: boolean;
|
|
}
|
|
|
|
const QuickViewNoteCard: React.FC<NoteCardProps> = ({ pubkey, text, eventId, tags, event, linkToNote }) => {
|
|
const { data: userData } = useProfile({
|
|
pubkey,
|
|
});
|
|
const [imageError, setImageError] = useState(false);
|
|
|
|
const title = userData?.username || userData?.display_name || userData?.name || userData?.npub || nip19.npubEncode(pubkey);
|
|
text = text.replaceAll('\n', ' ');
|
|
const imageSrc = text.match(/https?:\/\/[^ ]*\.(png|jpg|gif|jpeg)/g);
|
|
const videoSrc = text.match(/https?:\/\/[^ ]*\.(mp4|webm|mov)/g);
|
|
const textWithoutImage = text.replace(/https?:\/\/.*\.(?:png|jpg|gif|mp4|webm|mov|jpeg)/g, '');
|
|
const createdAt = new Date(event.created_at * 1000);
|
|
const hrefProfile = `/profile/${nip19.npubEncode(pubkey)}`;
|
|
const profileImageSrc = userData?.picture || "https://robohash.org/" + pubkey;
|
|
// Create nevent with relay hints
|
|
const nevent = nip19.neventEncode({
|
|
id: event.id,
|
|
relays: event.relays || []
|
|
})
|
|
|
|
const card = (
|
|
<Card>
|
|
<SmallCardContent>
|
|
<div>
|
|
<div className='d-flex justify-content-center align-items-center'>
|
|
{imageSrc && imageSrc.length > 1 && !videoSrc ? (
|
|
<div style={{ position: 'relative' }}>
|
|
<div className="absolute top-2 right-2 w-7 h-7 lg:w-12 lg:h-12 bg-black bg-opacity-40 rounded-lg flex items-center justify-center">
|
|
<StackIcon className='absolute w-7 h-7 lg:w-12 lg:h-12'/>
|
|
</div>
|
|
<img src={imageSrc[0]}
|
|
className='rounded lg:rounded-lg w-full h-auto object-cover'
|
|
style={{ maxHeight: '75vh', margin: 'auto' }}
|
|
alt={text}
|
|
loading="lazy"
|
|
onError={() => setImageError(true)}
|
|
/>
|
|
</div>
|
|
) : imageSrc && imageSrc.length > 0 ? (
|
|
<div style={{ position: 'relative' }}>
|
|
{videoSrc && videoSrc.length > 0 &&
|
|
<div className="absolute top-2 right-2 w-7 h-7 lg:w-12 lg:h-12 bg-black bg-opacity-40 rounded-lg flex items-center justify-center">
|
|
<PlayIcon className='absolute w-7 h-7 lg:w-12 lg:h-12' />
|
|
</div>
|
|
}
|
|
<img src={imageSrc[0]}
|
|
className='rounded lg:rounded-lg w-full h-auto object-cover'
|
|
style={{ maxHeight: '75vh', margin: 'auto' }}
|
|
alt={text}
|
|
loading="lazy"
|
|
onError={() => setImageError(true)}
|
|
/>
|
|
</div>
|
|
) : videoSrc && videoSrc.length > 0 ? (
|
|
<div style={{ position: 'relative' }}>
|
|
<div className="absolute top-2 right-2 w-7 h-7 lg:w-12 lg:h-12 bg-black bg-opacity-40 rounded-lg flex items-center justify-center">
|
|
<PlayIcon className='absolute w-7 h-7 lg:w-12 lg:h-12' />
|
|
</div>
|
|
<video src={videoSrc[0] + "#t=0.5"} className='rounded lg:rounded-lg' style={{ maxWidth: '100%', maxHeight: '75vh', objectFit: 'contain', margin: 'auto' }} />
|
|
</div>
|
|
) : imageError ? (
|
|
// Fallback for failed images
|
|
<div className="w-full h-32 bg-gray-800 rounded-lg flex items-center justify-center">
|
|
<div className="text-center text-gray-400">
|
|
<p className="text-sm">Image unavailable</p>
|
|
</div>
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
</SmallCardContent>
|
|
</Card>
|
|
);
|
|
|
|
return (
|
|
<>
|
|
{linkToNote ? (
|
|
<Link href={`/note/${nevent}`}>
|
|
{card}
|
|
</Link>
|
|
) : (
|
|
card
|
|
)}
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default QuickViewNoteCard; |