|
import { Box, Button, Collapse, Divider, Flex, IconButton, useDisclosure } from '@invoke-ai/ui-library'; |
|
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; |
|
import { useFocusRegion } from 'common/hooks/focus'; |
|
import { GalleryHeader } from 'features/gallery/components/GalleryHeader'; |
|
import { selectBoardSearchText } from 'features/gallery/store/gallerySelectors'; |
|
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, useMemo, useRef } from 'react'; |
|
import { useTranslation } from 'react-i18next'; |
|
import { PiCaretDownBold, PiCaretUpBold, PiMagnifyingGlassBold } from 'react-icons/pi'; |
|
import type { ImperativePanelGroupHandle } from 'react-resizable-panels'; |
|
import { Panel, PanelGroup } from 'react-resizable-panels'; |
|
|
|
import BoardsListWrapper from './Boards/BoardsList/BoardsListWrapper'; |
|
import BoardsSearch from './Boards/BoardsList/BoardsSearch'; |
|
import BoardsSettingsPopover from './Boards/BoardsSettingsPopover'; |
|
import { Gallery } from './Gallery'; |
|
|
|
const COLLAPSE_STYLES: CSSProperties = { flexShrink: 0, minHeight: 0 }; |
|
|
|
const GalleryPanelContent = () => { |
|
const { t } = useTranslation(); |
|
const boardSearchText = useAppSelector(selectBoardSearchText); |
|
const dispatch = useAppDispatch(); |
|
const boardSearchDisclosure = useDisclosure({ defaultIsOpen: !!boardSearchText.length }); |
|
const imperativePanelGroupRef = useRef<ImperativePanelGroupHandle>(null); |
|
const galleryPanelFocusRef = useRef<HTMLDivElement>(null); |
|
useFocusRegion('gallery', galleryPanelFocusRef); |
|
|
|
const boardsListPanelOptions = useMemo<UsePanelOptions>( |
|
() => ({ |
|
id: 'boards-list-panel', |
|
minSizePx: 128, |
|
defaultSizePx: 256, |
|
imperativePanelGroupRef, |
|
panelGroupDirection: 'vertical', |
|
}), |
|
[] |
|
); |
|
const boardsListPanel = usePanel(boardsListPanelOptions); |
|
|
|
const handleClickBoardSearch = useCallback(() => { |
|
if (boardSearchText.length) { |
|
dispatch(boardSearchTextChanged('')); |
|
} |
|
boardSearchDisclosure.onToggle(); |
|
boardsListPanel.expand(); |
|
}, [boardSearchText.length, boardSearchDisclosure, boardsListPanel, dispatch]); |
|
|
|
return ( |
|
<Flex ref={galleryPanelFocusRef} position="relative" flexDirection="column" h="full" w="full" tabIndex={-1}> |
|
<Flex alignItems="center" justifyContent="space-between" w="full"> |
|
<Flex flexGrow={1} flexBasis={0}> |
|
<Button |
|
size="sm" |
|
variant="ghost" |
|
onClick={boardsListPanel.toggle} |
|
rightIcon={boardsListPanel.isCollapsed ? <PiCaretDownBold /> : <PiCaretUpBold />} |
|
> |
|
{boardsListPanel.isCollapsed ? t('boards.viewBoards') : t('boards.hideBoards')} |
|
</Button> |
|
</Flex> |
|
<Flex> |
|
<GalleryHeader /> |
|
</Flex> |
|
<Flex flexGrow={1} flexBasis={0} justifyContent="flex-end"> |
|
<BoardsSettingsPopover /> |
|
<IconButton |
|
size="sm" |
|
variant="link" |
|
alignSelf="stretch" |
|
onClick={handleClickBoardSearch} |
|
tooltip={ |
|
boardSearchDisclosure.isOpen ? `${t('gallery.exitBoardSearch')}` : `${t('gallery.displayBoardSearch')}` |
|
} |
|
aria-label={t('gallery.displayBoardSearch')} |
|
icon={<PiMagnifyingGlassBold />} |
|
colorScheme={boardSearchDisclosure.isOpen ? 'invokeBlue' : 'base'} |
|
/> |
|
</Flex> |
|
</Flex> |
|
|
|
<PanelGroup ref={imperativePanelGroupRef} direction="vertical" autoSaveId="boards-list-panel"> |
|
<Panel collapsible {...boardsListPanel.panelProps}> |
|
<Flex flexDir="column" w="full" h="full"> |
|
<Collapse in={boardSearchDisclosure.isOpen} style={COLLAPSE_STYLES}> |
|
<Box w="full" pt={2}> |
|
<BoardsSearch /> |
|
</Box> |
|
</Collapse> |
|
<Divider pt={2} /> |
|
<BoardsListWrapper /> |
|
</Flex> |
|
</Panel> |
|
<ResizeHandle id="gallery-panel-handle" {...boardsListPanel.resizeHandleProps} /> |
|
<Panel id="gallery-wrapper-panel" minSize={20}> |
|
<Gallery /> |
|
</Panel> |
|
</PanelGroup> |
|
</Flex> |
|
); |
|
}; |
|
|
|
export default memo(GalleryPanelContent); |
|
|