reorganize the gallery - move board name to top of image grid, add hide/view boards button for toggle

This commit is contained in:
Mary Hipp 2024-07-23 18:51:48 -04:00 committed by psychedelicious
parent 0d40a7d865
commit bd73b6b2af
4 changed files with 67 additions and 50 deletions

View File

@ -32,6 +32,7 @@
"deleteBoardAndImages": "Delete Board and Images",
"deleteBoardOnly": "Delete Board Only",
"deletedBoardsCannotbeRestored": "Deleted boards cannot be restored",
"hideBoards": "Hide Boards",
"loading": "Loading...",
"menuItemAutoAdd": "Auto-add to this Board",
"move": "Move",
@ -47,6 +48,7 @@
"topMessage": "This board contains images used in the following features:",
"unarchiveBoard": "Unarchive Board",
"uncategorized": "Uncategorized",
"viewBoards": "View Boards",
"downloadBoard": "Download Board",
"imagesWithCount_one": "{{count}} image",
"imagesWithCount_other": "{{count}} images",

View File

@ -1,10 +1,11 @@
import type { ChakraProps } from '@invoke-ai/ui-library';
import { Box, Collapse, Flex, IconButton, Spacer, Tab, TabList, Tabs, useDisclosure } from '@invoke-ai/ui-library';
import { Box, Collapse, Flex, IconButton, Tab, TabList, Tabs, Text, useDisclosure } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { galleryViewChanged, searchTermChanged } from 'features/gallery/store/gallerySlice';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { MdSearch, MdSearchOff } from 'react-icons/md';
import { useBoardName } from 'services/api/hooks/useBoardName';
import { COLLAPSE_STYLES } from './ImageGalleryContent';
import GalleryImageGrid from './ImageGrid/GalleryImageGrid';
@ -47,17 +48,26 @@ export const Gallery = () => {
}
}, [searchTerm, dispatch, searchDisclosure]);
const selectedBoardId = useAppSelector((s) => s.gallery.selectedBoardId);
const boardName = useBoardName(selectedBoardId);
return (
<Flex flexDirection="column" alignItems="center" justifyContent="space-between" h="full" w="full">
<Tabs index={galleryView === 'images' ? 0 : 1} variant="enclosed" display="flex" flexDir="column" w="full">
<TabList gap={2} fontSize="sm" borderColor="base.800">
<Tab sx={BASE_STYLES} _selected={SELECTED_STYLES} onClick={handleClickImages} data-testid="images-tab">
{t('parameters.images')}
</Tab>
<Tab sx={BASE_STYLES} _selected={SELECTED_STYLES} onClick={handleClickAssets} data-testid="assets-tab">
{t('gallery.assets')}
</Tab>
<Spacer />
<Flex alignItems="center" justifyContent="space-between" w="full">
<Text fontSize="sm" fontWeight="semibold" noOfLines={1} px="2">
{boardName}
</Text>
<Flex alignItems="center" justifyContent="space-between">
<Tabs index={galleryView === 'images' ? 0 : 1} variant="enclosed" display="flex" flexDir="column">
<TabList gap={2} fontSize="sm" borderColor="base.800">
<Tab sx={BASE_STYLES} _selected={SELECTED_STYLES} onClick={handleClickImages} data-testid="images-tab">
{t('parameters.images')}
</Tab>
<Tab sx={BASE_STYLES} _selected={SELECTED_STYLES} onClick={handleClickAssets} data-testid="assets-tab">
{t('gallery.assets')}
</Tab>
</TabList>
</Tabs>
<Box position="relative">
<IconButton
w="full"
@ -69,8 +79,9 @@ export const Gallery = () => {
variant="link"
/>
</Box>
</TabList>
</Tabs>
</Flex>
</Flex>
<Box w="full">
<Collapse in={searchDisclosure.isOpen} style={COLLAPSE_STYLES}>
<Box w="full" pt={2}>

View File

@ -3,13 +3,7 @@ import { useStore } from '@nanostores/react';
import { $projectName, $projectUrl } from 'app/store/nanostores/projectId';
import { memo } from 'react';
import GalleryBoardName from './GalleryBoardName';
type Props = {
onClickBoardName: () => void;
};
export const GalleryHeader = memo((props: Props) => {
export const GalleryHeader = memo(() => {
const projectName = useStore($projectName);
const projectUrl = useStore($projectUrl);
@ -19,16 +13,11 @@ export const GalleryHeader = memo((props: Props) => {
<Text fontSize="md" fontWeight="semibold" noOfLines={1} w="full" textAlign="center">
<Link href={projectUrl}>{projectName}</Link>
</Text>
<GalleryBoardName onClick={props.onClickBoardName} />
</Flex>
);
}
return (
<Flex w="full" pe={2}>
<GalleryBoardName onClick={props.onClickBoardName} />
</Flex>
);
return <></>;
});
GalleryHeader.displayName = 'GalleryHeader';

View File

@ -1,13 +1,14 @@
import { Box, Collapse, Divider, Flex, IconButton, useDisclosure } from '@invoke-ai/ui-library';
import { Button, Collapse, Divider, Flex, IconButton, useDisclosure } from '@invoke-ai/ui-library';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { GalleryHeader } from 'features/gallery/components/GalleryHeader';
import { boardSearchTextChanged } from 'features/gallery/store/gallerySlice';
import ResizeHandle from 'features/ui/components/tabs/ResizeHandle';
import { usePanel, type UsePanelOptions } from 'features/ui/hooks/usePanel';
import type { CSSProperties } from 'react';
import { memo, useCallback, useEffect, useMemo, useRef } from 'react';
import { memo, useCallback, useMemo, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { MdSearch, MdSearchOff } from 'react-icons/md';
import { PiCaretDownBold, PiCaretUpBold } from 'react-icons/pi';
import type { ImperativePanelGroupHandle } from 'react-resizable-panels';
import { Panel, PanelGroup } from 'react-resizable-panels';
@ -41,36 +42,50 @@ const ImageGalleryContent = () => {
const handleClickBoardSearch = useCallback(() => {
if (boardSearchText.length) {
dispatch(boardSearchTextChanged(''));
boardSearchDisclosure.onToggle();
} else {
boardSearchDisclosure.onToggle();
}
boardSearchDisclosure.onToggle();
}, [boardSearchText, dispatch, boardSearchDisclosure]);
useEffect(() => {
if (boardSearchDisclosure.isOpen) {
boardsListPanel.expand();
const handleToggleBoardPanel = useCallback(() => {
if (boardSearchText.length) {
dispatch(boardSearchTextChanged(''));
}
}, [boardSearchDisclosure, boardsListPanel]);
boardsListPanel.toggle();
}, [boardSearchText, dispatch, boardsListPanel]);
return (
<Flex position="relative" flexDirection="column" h="full" w="full" pt={2}>
<Flex alignItems="center" gap={2}>
<GalleryHeader onClickBoardName={boardsListPanel.toggle} />
<GallerySettingsPopover />
<Box position="relative" h="full">
<IconButton
w="full"
h="full"
onClick={handleClickBoardSearch}
tooltip={
boardSearchDisclosure.isOpen ? `${t('gallery.exitBoardSearch')}` : `${t('gallery.displayBoardSearch')}`
}
aria-label={t('gallery.displayBoardSearch')}
icon={boardSearchText.length ? <MdSearchOff /> : <MdSearch />}
variant="link"
/>
</Box>
<Flex alignItems="center" gap={0}>
<GalleryHeader />
<Flex alignItems="center" justifyContent="space-between" w="full">
<Button
size="sm"
variant="ghost"
onClick={handleToggleBoardPanel}
rightIcon={boardsListPanel.isCollapsed ? <PiCaretDownBold /> : <PiCaretUpBold />}
>
{boardsListPanel.isCollapsed ? t('boards.viewBoards') : t('boards.hideBoards')}
</Button>
<Flex alignItems="center" justifyContent="space-between">
<GallerySettingsPopover />
<Flex>
<IconButton
w="full"
h="full"
onClick={handleClickBoardSearch}
tooltip={
boardSearchDisclosure.isOpen
? `${t('gallery.exitBoardSearch')}`
: `${t('gallery.displayBoardSearch')}`
}
aria-label={t('gallery.displayBoardSearch')}
icon={boardSearchText.length ? <MdSearchOff /> : <MdSearch />}
variant="link"
/>
</Flex>
</Flex>
</Flex>
</Flex>
<PanelGroup ref={panelGroupRef} direction="vertical">