cleanup image gallery props

This commit is contained in:
hzrd149 2023-08-22 14:03:58 -05:00
parent ed0408de76
commit 6325e16cc2
4 changed files with 49 additions and 18 deletions

View File

@ -17,6 +17,7 @@ import { getMatchLink } from "../../helpers/regexp";
import { useRegisterSlide } from "../lightbox-provider";
import { isImageURL } from "../../helpers/url";
import PhotoGallery, { PhotoWithoutSize } from "../photo-gallery";
import { NostrEvent } from "../../types/nostr-event";
function useElementBlur(initBlur = false): { style: CSSProperties; onClick: MouseEventHandler } {
const [blur, setBlur] = useState(initBlur);
@ -37,7 +38,9 @@ function useElementBlur(initBlur = false): { style: CSSProperties; onClick: Mous
return { onClick, style };
}
export const TrustImage = forwardRef<HTMLImageElement, ImageProps>((props, ref) => {
export type TrustImageProps = ImageProps;
export const TrustImage = forwardRef<HTMLImageElement, TrustImageProps>((props, ref) => {
const trusted = useTrusted();
const { onClick, style } = useElementBlur(!trusted);
@ -54,7 +57,11 @@ export const TrustImage = forwardRef<HTMLImageElement, ImageProps>((props, ref)
return <Image {...props} onClick={handleClick} style={{ ...style, ...props.style }} ref={ref} />;
});
export const EmbeddedImage = forwardRef<HTMLImageElement, ImageProps>(({ src, ...props }, ref) => {
export type EmbeddedImageProps = TrustImageProps & {
event?: NostrEvent;
};
export const EmbeddedImage = forwardRef<HTMLImageElement, EmbeddedImageProps>(({ src, event, ...props }, ref) => {
const thumbnail = appSettings.value.imageProxy
? new URL(`/256,fit/${src}`, appSettings.value.imageProxy).toString()
: src;
@ -62,13 +69,13 @@ export const EmbeddedImage = forwardRef<HTMLImageElement, ImageProps>(({ src, ..
ref = ref || useRef<HTMLImageElement | null>(null);
const { show } = useRegisterSlide(
ref as MutableRefObject<HTMLImageElement | null>,
src ? { type: "image", src } : undefined,
src ? { type: "image", src, event } : undefined,
);
return <TrustImage {...props} src={thumbnail} cursor="pointer" ref={ref} onClick={show} />;
});
export function ImageGallery({ images }: { images: string[] }) {
export function ImageGallery({ images, event }: { images: string[]; event?: NostrEvent }) {
const photos = useMemo(() => {
return images.map((img) => {
const photo: PhotoWithoutSize = { src: img };
@ -89,7 +96,7 @@ export function ImageGallery({ images }: { images: string[] }) {
}
// nevent1qqs8397rp8tt60f3lm8zldt8uqljuqw9axp8z79w0qsmj3r96lmg4tgpz3mhxue69uhhyetvv9ujuerpd46hxtnfduq3zamnwvaz7tmwdaehgun4v5hxxmmd0mkwa9
export function embedImageGallery(content: EmbedableContent): EmbedableContent {
export function embedImageGallery(content: EmbedableContent, event?: NostrEvent): EmbedableContent {
return content
.map((subContent, i) => {
if (typeof subContent === "string") {
@ -104,7 +111,7 @@ export function embedImageGallery(content: EmbedableContent): EmbedableContent {
// render previous batch
const lastMatchPosition = defaultGetLocation(batch[batch.length - 1]);
const before = subContent.substring(lastBatchEnd, defaultGetLocation(batch[0]).start);
const render = <ImageGallery images={batch.map((m) => m[0])} />;
const render = <ImageGallery images={batch.map((m) => m[0])} event={event} />;
newContent.push(before, render);
lastBatchEnd = lastMatchPosition.end;

View File

@ -21,6 +21,15 @@ import Download from "yet-another-react-lightbox/plugins/download";
import "yet-another-react-lightbox/styles.css";
import "yet-another-react-lightbox/plugins/counter.css";
// extend slide type to include eventId
declare module "yet-another-react-lightbox" {
interface GenericSlide {
event?: NostrEvent;
}
}
import { NostrEvent } from "../types/nostr-event";
type RefType = MutableRefObject<HTMLElement | null>;
function getElementPath(element: HTMLElement): HTMLElement[] {
@ -85,6 +94,20 @@ function getRefPath(ref: RefType) {
return path;
}
// function EventSlideHeader({ event }: { event: NostrEvent }) {
// return (
// <Flex gap="2" alignItems="center" w="full">
// <UserAvatarLink pubkey={event.pubkey} size={["xs", "sm"]} />
// <UserLink pubkey={event.pubkey} isTruncated fontWeight="bold" fontSize="lg" />
// <UserDnsIdentityIcon pubkey={event.pubkey} onlyIcon />
// <Flex grow={1} />
// <NoteLink noteId={event.id} whiteSpace="nowrap" color="current">
// {dayjs.unix(event.created_at).fromNow()}
// </NoteLink>
// </Flex>
// );
// }
export function LightboxProvider({ children }: PropsWithChildren) {
const lightbox = useDisclosure();
const [index, setIndex] = useState(0);

View File

@ -26,7 +26,7 @@ function buildContents(event: NostrEvent | DraftNostrEvent) {
let content: EmbedableContent = [event.content.trim()];
// image gallery
content = embedImageGallery(content);
content = embedImageGallery(content, event as NostrEvent);
// common
content = embedUrls(content, [

View File

@ -1,33 +1,34 @@
import { useMemo, useRef } from "react";
import { ImageProps, useBreakpointValue } from "@chakra-ui/react";
import { useBreakpointValue } from "@chakra-ui/react";
import { TimelineLoader } from "../../../classes/timeline-loader";
import useSubject from "../../../hooks/use-subject";
import { getMatchLink } from "../../../helpers/regexp";
import { LightboxProvider } from "../../lightbox-provider";
import { isImageURL } from "../../../helpers/url";
import { EmbeddedImage } from "../../embed-types";
import { EmbeddedImage, EmbeddedImageProps } from "../../embed-types";
import { TrustProvider } from "../../../providers/trust";
import PhotoGallery, { PhotoWithoutSize } from "../../photo-gallery";
import { useRegisterIntersectionEntity } from "../../../providers/intersection-observer";
import { Photo } from "react-photo-album";
import { NostrEvent } from "../../../types/nostr-event";
function GalleryImage({ eventId, ...props }: ImageProps & { eventId: string }) {
function GalleryImage({ event, ...props }: EmbeddedImageProps & { event: NostrEvent }) {
const ref = useRef<HTMLImageElement | null>(null);
useRegisterIntersectionEntity(ref, eventId);
useRegisterIntersectionEntity(ref, event.id);
return <EmbeddedImage {...props} ref={ref} />;
return <EmbeddedImage {...props} event={event} ref={ref} />;
}
type PhotoWithEventId = PhotoWithoutSize & { eventId: string };
function ImageGallery({ images }: { images: PhotoWithEventId[] }) {
type PhotoWithEvent = PhotoWithoutSize & { event: NostrEvent };
function ImageGallery({ images }: { images: PhotoWithEvent[] }) {
const rowMultiplier = useBreakpointValue({ base: 2, sm: 3, md: 3, lg: 4, xl: 5 }) ?? 2;
return (
<PhotoGallery<Photo & { eventId: string }>
<PhotoGallery<Photo & { event: NostrEvent }>
layout="masonry"
photos={images}
renderPhoto={({ photo, imageProps }) => <GalleryImage eventId={photo.eventId} {...imageProps} />}
renderPhoto={({ photo, imageProps }) => <GalleryImage event={photo.event} {...imageProps} />}
columns={rowMultiplier}
/>
);
@ -37,14 +38,14 @@ export default function MediaTimeline({ timeline }: { timeline: TimelineLoader }
const events = useSubject(timeline.timeline);
const images = useMemo(() => {
var images: { eventId: string; src: string; index: number }[] = [];
var images: PhotoWithEvent[] = [];
for (const event of events) {
const urls = event.content.matchAll(getMatchLink());
let i = 0;
for (const match of urls) {
if (isImageURL(match[0])) images.push({ eventId: event.id, src: match[0], index: i++ });
if (isImageURL(match[0])) images.push({ event, src: match[0] });
}
}