feat(ui): mini metadata viewer

This commit is contained in:
psychedelicious
2025-06-20 17:39:31 +10:00
parent cf30d1d476
commit c01f8f595f
3 changed files with 97 additions and 12 deletions

View File

@@ -10,6 +10,7 @@ import { AnimatePresence, motion } from 'framer-motion';
import { memo, useCallback, useRef, useState } from 'react';
import type { ImageDTO } from 'services/api/types';
import { ImageMetadataMini } from './ImageMetadataMini';
import { NoContentForViewer } from './NoContentForViewer';
export const CurrentImagePreview = memo(({ imageDTO }: { imageDTO?: ImageDTO }) => {
@@ -39,16 +40,9 @@ export const CurrentImagePreview = memo(({ imageDTO }: { imageDTO?: ImageDTO })
position="relative"
>
<ImageContent imageDTO={imageDTO} />
<Flex
flexDir="column"
gap={2}
position="absolute"
top={0}
insetInlineStart={0}
pointerEvents="none"
alignItems="flex-start"
>
<Flex flexDir="column" gap={2} position="absolute" top={0} insetInlineStart={0} alignItems="flex-start">
<CanvasAlertsInvocationProgress />
{imageDTO && <ImageMetadataMini imageName={imageDTO.image_name} />}
</Flex>
{shouldShowImageDetails && imageDTO && (
<Box position="absolute" opacity={0.8} top={0} width="full" height="full" borderRadius="base">

View File

@@ -0,0 +1,92 @@
import { Alert, AlertIcon, AlertTitle, Grid, GridItem, Text } from '@invoke-ai/ui-library';
import { useMetadataItem } from 'features/metadata/hooks/useMetadataItem';
import { handlers } from 'features/metadata/util/handlers';
import { useDebouncedMetadata } from 'services/api/hooks/useDebouncedMetadata';
export const ImageMetadataMini = ({ imageName }: { imageName: string }) => {
const { metadata, isLoading } = useDebouncedMetadata(imageName);
const createdBy = useMetadataItem(metadata, handlers.createdBy);
const positivePrompt = useMetadataItem(metadata, handlers.positivePrompt);
const negativePrompt = useMetadataItem(metadata, handlers.negativePrompt);
const seed = useMetadataItem(metadata, handlers.seed);
const model = useMetadataItem(metadata, handlers.model);
const strength = useMetadataItem(metadata, handlers.strength);
if (isLoading) {
return (
<Alert status="loading" borderRadius="base" fontSize="sm" shadow="md" w="fit-content">
<AlertIcon />
<AlertTitle>Loading metadata...</AlertTitle>
</Alert>
);
}
if (
!createdBy.valueOrNull &&
!positivePrompt.valueOrNull &&
!negativePrompt.valueOrNull &&
!seed.valueOrNull &&
!model.valueOrNull &&
!strength.valueOrNull
) {
return (
<Alert status="warning" borderRadius="base" fontSize="sm" shadow="md" w="fit-content">
<AlertTitle>No metadata found</AlertTitle>
</Alert>
);
}
return (
<Alert borderRadius="base" fontSize="sm" shadow="md" w="fit-content">
<Grid gridTemplateColumns="auto 1fr" columnGap={2} maxW={420}>
{createdBy.valueOrNull && (
<>
<GridItem textAlign="end">
<Text fontWeight="semibold">{createdBy.label}:</Text>
</GridItem>
<GridItem>{createdBy.renderedValue}</GridItem>
</>
)}
{positivePrompt.valueOrNull && (
<>
<GridItem textAlign="end">
<Text fontWeight="semibold">{positivePrompt.label}:</Text>
</GridItem>
<GridItem>{positivePrompt.renderedValue}</GridItem>
</>
)}
{negativePrompt.valueOrNull && (
<>
<GridItem textAlign="end">
<Text fontWeight="semibold">{negativePrompt.label}:</Text>
</GridItem>
<GridItem>{negativePrompt.renderedValue}</GridItem>
</>
)}
{model.valueOrNull !== null && (
<>
<GridItem textAlign="end">
<Text fontWeight="semibold">{model.label}:</Text>
</GridItem>
<GridItem>{model.renderedValue}</GridItem>
</>
)}
{strength.valueOrNull !== null && (
<>
<GridItem textAlign="end">
<Text fontWeight="semibold">{strength.label}:</Text>
</GridItem>
<GridItem>{strength.renderedValue}</GridItem>
</>
)}
{seed.valueOrNull !== null && (
<>
<GridItem textAlign="end">
<Text fontWeight="semibold">{seed.label}:</Text>
</GridItem>
<GridItem>{seed.renderedValue}</GridItem>
</>
)}
</Grid>
</Alert>
);
};
ImageMetadataMini.displayName = 'ImageMetadataMini';

View File

@@ -8,8 +8,7 @@ export const useDebouncedMetadata = (imageName?: string | null) => {
const metadataFetchDebounce = useAppSelector(selectMetadataFetchDebounce);
const [debouncedImageName] = useDebounce(imageName, metadataFetchDebounce);
const { data, isFetching } = useGetImageMetadataQuery(debouncedImageName ?? skipToken);
const { data: metadata, isLoading } = useGetImageMetadataQuery(debouncedImageName ?? skipToken);
return { metadata, isLoading };
return { metadata: data, isLoading: isFetching || imageName !== debouncedImageName };
};