@@ -211,94 +151,31 @@ const Feed = ({ showDisplayAs, filterOptions, emptyMessage }: Props) => {
const renderGrid = () => {
return (
- {imagesAndVideos.map((item, index) => renderGridItem(item, index))}
+ {imagesAndVideos.map((item, index) => (
+
+ ))}
);
};
- const renderGridItem = (item: { url: string; type: 'image' | 'video' }, index: number) => {
- const url =
- item.type === 'video' ? `https://imgproxy.iris.to/thumbnail/638/${item.url}` : item.url;
- return (
-
{
- setModalImageIndex(index);
- }}
- >
-
- {item.type === 'video' && (
-
{VideoIcon}
- )}
-
- );
- };
-
- const renderImageModal = () => {
- return modalItemIndex !== null ? (
-
setModalImageIndex(null)}>
-
- {imagesAndVideos[modalItemIndex].type === 'video' ? (
-
- ) : (
-
- )}
-
-
{
- e.stopPropagation();
- goToPrevImage();
- }}
- >
-
-
-
{
- e.stopPropagation();
- goToNextImage();
- }}
- >
-
-
-
-
-
- ) : (
- ''
- );
- };
-
return (
<>
- {filterOptions.length > 1 && renderFilterOptions()}
+
1}>{renderFilterOptions()}
{renderDisplayAsSelector()}
- {renderImageModal()}
- {isEmpty &&
{emptyMessage || 'No Posts'}
}
+
+
+ {emptyMessage || 'No Posts'}
+
{displayAs === 'grid'
? renderGrid()
diff --git a/src/js/components/feed/ImageGridItem.tsx b/src/js/components/feed/ImageGridItem.tsx
new file mode 100644
index 00000000..d8563720
--- /dev/null
+++ b/src/js/components/feed/ImageGridItem.tsx
@@ -0,0 +1,41 @@
+import { ImageOrVideo } from '@/components/feed/types';
+import SafeImg from '@/components/SafeImg';
+import Icons from '@/Icons';
+
+type ImageGridItemProps = {
+ item: ImageOrVideo;
+ index: number;
+ setModalImageIndex: (index: number) => void;
+ imagesAndVideosLength: number;
+ lastElementRef?: React.MutableRefObject
;
+};
+
+export const ImageGridItem = ({
+ item,
+ index,
+ setModalImageIndex,
+ imagesAndVideosLength,
+ lastElementRef,
+}: ImageGridItemProps) => {
+ const url =
+ item.type === 'video' ? `https://imgproxy.iris.to/thumbnail/638/${item.url}` : item.url;
+ const isLast = index === imagesAndVideosLength - 1;
+
+ return (
+ {
+ setModalImageIndex(index);
+ }}
+ >
+
+ {item.type === 'video' && (
+
{Icons.video}
+ )}
+
+ );
+};
+
+export default ImageGridItem;
diff --git a/src/js/components/feed/ImageModal.tsx b/src/js/components/feed/ImageModal.tsx
new file mode 100644
index 00000000..9afcb4fe
--- /dev/null
+++ b/src/js/components/feed/ImageModal.tsx
@@ -0,0 +1,94 @@
+import { useEffect } from 'react';
+import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/20/solid';
+
+import Modal from '@/components/modal/Modal';
+import SafeImg from '@/components/SafeImg';
+
+type ImageModalProps = {
+ imagesAndVideos: Array<{
+ type: 'image' | 'video';
+ url: string;
+ }>;
+ modalItemIndex: number | null;
+ setModalImageIndex: (index: number | null) => void;
+};
+
+const ImageModal = ({ imagesAndVideos, modalItemIndex, setModalImageIndex }: ImageModalProps) => {
+ const goToPrevImage = () => {
+ if (modalItemIndex === null) return;
+ const prevImageIndex = (modalItemIndex - 1 + imagesAndVideos.length) % imagesAndVideos.length;
+ setModalImageIndex(prevImageIndex);
+ };
+
+ const goToNextImage = () => {
+ if (modalItemIndex === null) return;
+ const nextImageIndex = (modalItemIndex + 1) % imagesAndVideos.length;
+ setModalImageIndex(nextImageIndex);
+ };
+
+ useEffect(() => {
+ const handleKeyDown = (e: KeyboardEvent) => {
+ if (e.key === 'ArrowRight') {
+ goToNextImage();
+ } else if (e.key === 'ArrowLeft') {
+ goToPrevImage();
+ }
+ };
+
+ window.addEventListener('keydown', handleKeyDown);
+
+ return () => {
+ window.removeEventListener('keydown', handleKeyDown);
+ };
+ }, [modalItemIndex, imagesAndVideos]);
+
+ return modalItemIndex !== null ? (
+ setModalImageIndex(null)}>
+
+ {imagesAndVideos[modalItemIndex].type === 'video' ? (
+
+ ) : (
+
+ )}
+
+
{
+ e.stopPropagation();
+ goToPrevImage();
+ }}
+ >
+
+
+
{
+ e.stopPropagation();
+ goToNextImage();
+ }}
+ >
+
+
+
+
+
+ ) : null;
+};
+
+export default ImageModal;
diff --git a/src/js/components/feed/types.ts b/src/js/components/feed/types.ts
new file mode 100644
index 00000000..f0c4db9c
--- /dev/null
+++ b/src/js/components/feed/types.ts
@@ -0,0 +1,24 @@
+import { Filter } from 'nostr-tools';
+
+import { EventComponentProps } from '@/components/events/EventComponent';
+
+export type FeedProps = {
+ filterOptions: FilterOption[];
+ showDisplayAs?: boolean;
+ filterFn?: (event: any) => boolean;
+ emptyMessage?: string;
+};
+
+export type DisplayAs = 'feed' | 'grid';
+
+export type ImageOrVideo = {
+ type: 'image' | 'video';
+ url: string;
+};
+
+export type FilterOption = {
+ name: string;
+ filter: Filter;
+ filterFn?: (event: any) => boolean;
+ eventProps?: Partial;
+};
diff --git a/src/js/views/EditProfile.tsx b/src/js/views/EditProfile.tsx
index 1843aff1..a6539321 100644
--- a/src/js/views/EditProfile.tsx
+++ b/src/js/views/EditProfile.tsx
@@ -124,7 +124,7 @@ export default class EditProfile extends Component {
{val && (
-
+
)}
>