infinite grid

This commit is contained in:
psychedelicious
2024-09-26 05:53:19 +10:00
parent 10ca09a5b2
commit affdca4316
4 changed files with 80 additions and 56 deletions

View File

@@ -166,8 +166,8 @@ export const createStore = (uniqueStoreKey?: string, persist = true) =>
reducer: rememberedRootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: import.meta.env.MODE === 'development',
immutableCheck: import.meta.env.MODE === 'development',
serializableCheck: false, // import.meta.env.MODE === 'development',
immutableCheck: false, // import.meta.env.MODE === 'development',
})
.concat(api.middleware)
.concat(dynamicMiddlewares)

View File

@@ -4,7 +4,6 @@ import { IAILoadingImageFallback, IAINoContentFallback } from 'common/components
import ImageMetadataOverlay from 'common/components/ImageMetadataOverlay';
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
import type { TypesafeDraggableData, TypesafeDroppableData } from 'features/dnd/types';
import ImageContextMenu from 'features/gallery/components/ImageContextMenu/ImageContextMenu';
import type { MouseEvent, ReactElement, ReactNode, SyntheticEvent } from 'react';
import { memo, useCallback, useMemo } from 'react';
import { PiImageBold, PiUploadSimpleBold } from 'react-icons/pi';
@@ -125,36 +124,6 @@ const IAIDndImage = (props: IAIDndImageProps) => {
[onMouseOut]
);
const { getUploadButtonProps, getUploadInputProps } = useImageUploadButton({
postUploadAction,
isDisabled: isUploadDisabled,
});
const uploadButtonStyles = useMemo<SystemStyleObject>(() => {
const styles: SystemStyleObject = {
minH: minSize,
w: 'full',
h: 'full',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 'base',
transitionProperty: 'common',
transitionDuration: '0.1s',
color: 'base.500',
};
if (!isUploadDisabled) {
Object.assign(styles, {
cursor: 'pointer',
bg: 'base.700',
_hover: {
bg: 'base.650',
color: 'base.300',
},
});
}
return styles;
}, [isUploadDisabled, minSize]);
const openInNewTab = useCallback(
(e: MouseEvent) => {
if (!imageDTO) {
@@ -169,10 +138,10 @@ const IAIDndImage = (props: IAIDndImageProps) => {
);
return (
<ImageContextMenu imageDTO={imageDTO}>
{(ref) => (
// <ImageContextMenu imageDTO={imageDTO}>
// {(ref) => (
<Flex
ref={ref}
// ref={ref}
onMouseOver={handleMouseOver}
onMouseOut={handleMouseOut}
width="full"
@@ -216,12 +185,12 @@ const IAIDndImage = (props: IAIDndImageProps) => {
</Flex>
)}
{!imageDTO && !isUploadDisabled && (
<>
<Flex sx={uploadButtonStyles} {...getUploadButtonProps()}>
<input {...getUploadInputProps()} />
{uploadElement}
</Flex>
</>
<UploadButton
isUploadDisabled={isUploadDisabled}
postUploadAction={postUploadAction}
uploadElement={uploadElement}
minSize={minSize}
/>
)}
{!imageDTO && isUploadDisabled && noContentFallback}
{imageDTO && !isDragDisabled && (
@@ -235,9 +204,58 @@ const IAIDndImage = (props: IAIDndImageProps) => {
{children}
{!isDropDisabled && <IAIDroppable data={droppableData} disabled={isDropDisabled} dropLabel={dropLabel} />}
</Flex>
)}
</ImageContextMenu>
// )}
// </ImageContextMenu>
);
};
export default memo(IAIDndImage);
const UploadButton = ({
isUploadDisabled,
postUploadAction,
uploadElement,
minSize,
}: {
isUploadDisabled: boolean;
postUploadAction?: PostUploadAction;
uploadElement: ReactNode;
minSize: number;
}) => {
const { getUploadButtonProps, getUploadInputProps } = useImageUploadButton({
postUploadAction,
isDisabled: isUploadDisabled,
});
const uploadButtonStyles = useMemo<SystemStyleObject>(() => {
const styles: SystemStyleObject = {
minH: minSize,
w: 'full',
h: 'full',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 'base',
transitionProperty: 'common',
transitionDuration: '0.1s',
color: 'base.500',
};
if (!isUploadDisabled) {
Object.assign(styles, {
cursor: 'pointer',
bg: 'base.700',
_hover: {
bg: 'base.650',
color: 'base.300',
},
});
}
return styles;
}, [isUploadDisabled, minSize]);
return (
<Flex sx={uploadButtonStyles} {...getUploadButtonProps()}>
<input {...getUploadInputProps()} />
{uploadElement}
</Flex>
);
};

View File

@@ -161,10 +161,6 @@ const GalleryImageContent = memo(({ index, imageDTO }: GalleryImageContentProps)
const dataTestId = useMemo(() => getGalleryImageDataTestId(imageDTO.image_name), [imageDTO.image_name]);
if (!imageDTO) {
return <IAIFillSkeleton />;
}
return (
<Box w="full" h="full" className={GALLERY_IMAGE_CLASS_NAME} data-testid={dataTestId} sx={boxSx}>
<Flex
@@ -228,7 +224,7 @@ const GalleryImageContent = memo(({ index, imageDTO }: GalleryImageContentProps)
GalleryImageContent.displayName = 'GalleryImageContent';
const DeleteIcon = ({ imageDTO }: { imageDTO: ImageDTO }) => {
const DeleteIcon = memo(({ imageDTO }: { imageDTO: ImageDTO }) => {
const shift = useShiftModifier();
const { t } = useTranslation();
const dispatch = useAppDispatch();
@@ -257,9 +253,9 @@ const DeleteIcon = ({ imageDTO }: { imageDTO: ImageDTO }) => {
insetInlineEnd={2}
/>
);
};
});
const OpenInViewerIconButton = ({ imageDTO }: { imageDTO: ImageDTO }) => {
const OpenInViewerIconButton = memo(({ imageDTO }: { imageDTO: ImageDTO }) => {
const imageViewer = useImageViewer();
const { t } = useTranslation();
@@ -277,4 +273,4 @@ const OpenInViewerIconButton = ({ imageDTO }: { imageDTO: ImageDTO }) => {
insetInlineStart={2}
/>
);
};
});

View File

@@ -14,6 +14,16 @@ import type { ImageDTO } from 'services/api/types';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type TableVirtuosoScrollerRef = (ref: HTMLElement | Window | null) => any;
const selectors = new Map<string, ReturnType<typeof imagesApi.endpoints.getImageDTO.select>>();
const getSelector = (name: string) => {
let selector = selectors.get(name);
if (!selector) {
selector = imagesApi.endpoints.getImageDTO.select(name);
selectors.set(name, selector);
}
return selector;
};
export const GalleryImageListExperiment = memo(() => {
const store = useAppStore();
const { data } = useGetImageNamesQuery({ starred_first: false });
@@ -35,10 +45,10 @@ export const GalleryImageListExperiment = memo(() => {
if (imageNames) {
// optimisation: we may have already loaded some of these images, so filter out the ones we already have
const imageNamesToFetch: string[] = [];
const state = store.getState();
for (const name of imageNames) {
// check if we have this image cached already
const { data } = imagesApi.endpoints.getImageDTO.select(name)(store.getState());
if (!data) {
if (!getSelector(name)(state).data) {
// nope, we need to fetch it
imageNamesToFetch.push(name);
}
@@ -89,7 +99,7 @@ export const GalleryImageListExperiment = memo(() => {
components={components}
itemContent={itemContent}
rangeChanged={debouncedOnRangeChanged}
overscan={10}
overscan={50}
// increases teh virual viewport by 200px in each direction, so we fetch a few more images than required
scrollerRef={setScroller as TableVirtuosoScrollerRef}
/>
@@ -115,7 +125,7 @@ const useGetImageDTOCache = (imageName: string): ImageDTO | undefined => {
const HEIGHT = 24;
const ListItem = ({ index, data }: { index: number; data: string }) => {
const imageDTO = useGetImageDTOCache(data);
const imageDTO = useAppSelector(getSelector(data)).data;
if (!imageDTO) {
return <Skeleton w="full" h={HEIGHT} />;