From 68f1f87c6fe7ad3f4a54b18f573559c6d55dac76 Mon Sep 17 00:00:00 2001
From: psychedelicious <4822129+psychedelicious@users.noreply.github.com>
Date: Fri, 21 Jul 2023 20:02:54 +1000
Subject: [PATCH] feat(ui): board styles
---
.../listeners/boardIdSelected.ts | 2 +-
.../web/src/common/components/IAICollapse.tsx | 5 +-
.../web/src/common/components/IAIDndImage.tsx | 29 ++++++--
.../common/components/SelectionOverlay.tsx | 42 +++++++++++
.../gallery/components/Boards/AutoAddIcon.tsx | 2 +-
.../components/Boards/BoardContextMenu.tsx | 68 +++++++++++++-----
.../Boards/BoardsList/BoardsList.tsx | 2 +-
.../Boards/BoardsList/GalleryBoard.tsx | 68 +++++++++---------
.../Boards/BoardsList/NoBoardBoard.tsx | 70 ++++++++++++++-----
.../Boards/GalleryBoardContextMenuItems.tsx | 4 +-
.../Boards/NoBoardContextMenuItems.tsx | 4 +-
.../gallery/components/GalleryBoardName.tsx | 33 +++++----
.../components/ImageGalleryContent.tsx | 44 ++++++++----
.../components/ImageGrid/GalleryImage.tsx | 1 +
.../components/ImageGrid/GalleryImageGrid.tsx | 34 ++++++---
.../ui/components/ParametersDrawer.tsx | 1 -
.../ResizableDrawer/ResizableDrawer.tsx | 2 +-
.../web/src/theme/components/button.ts | 14 ++++
invokeai/frontend/web/src/theme/theme.ts | 6 +-
19 files changed, 306 insertions(+), 125 deletions(-)
create mode 100644 invokeai/frontend/web/src/common/components/SelectionOverlay.tsx
diff --git a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/boardIdSelected.ts b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/boardIdSelected.ts
index a2ac34969f..b44f87a081 100644
--- a/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/boardIdSelected.ts
+++ b/invokeai/frontend/web/src/app/store/middleware/listenerMiddleware/listeners/boardIdSelected.ts
@@ -44,7 +44,7 @@ export const addBoardIdSelectedListener = () => {
() =>
imagesApi.endpoints.listImages.select(queryArgs)(getState())
.isSuccess,
- 1000
+ 5000
);
if (isSuccess) {
diff --git a/invokeai/frontend/web/src/common/components/IAICollapse.tsx b/invokeai/frontend/web/src/common/components/IAICollapse.tsx
index 09dc1392e2..0ce767ed9d 100644
--- a/invokeai/frontend/web/src/common/components/IAICollapse.tsx
+++ b/invokeai/frontend/web/src/common/components/IAICollapse.tsx
@@ -92,7 +92,10 @@ const IAICollapse = (props: IAIToggleCollapseProps) => {
sx={{
p: 4,
borderBottomRadius: 'base',
- bg: mode('base.100', 'base.800')(colorMode),
+ bg: 'base.100',
+ _dark: {
+ bg: 'base.800',
+ },
}}
>
{children}
diff --git a/invokeai/frontend/web/src/common/components/IAIDndImage.tsx b/invokeai/frontend/web/src/common/components/IAIDndImage.tsx
index 57d54e155e..cf01a93197 100644
--- a/invokeai/frontend/web/src/common/components/IAIDndImage.tsx
+++ b/invokeai/frontend/web/src/common/components/IAIDndImage.tsx
@@ -18,12 +18,20 @@ import {
import ImageMetadataOverlay from 'common/components/ImageMetadataOverlay';
import { useImageUploadButton } from 'common/hooks/useImageUploadButton';
import ImageContextMenu from 'features/gallery/components/ImageContextMenu/ImageContextMenu';
-import { MouseEvent, ReactElement, SyntheticEvent, memo } from 'react';
+import {
+ MouseEvent,
+ ReactElement,
+ SyntheticEvent,
+ memo,
+ useCallback,
+ useState,
+} from 'react';
import { FaImage, FaUndo, FaUpload } from 'react-icons/fa';
import { ImageDTO, PostUploadAction } from 'services/api/types';
import { mode } from 'theme/util/mode';
import IAIDraggable from './IAIDraggable';
import IAIDroppable from './IAIDroppable';
+import SelectionOverlay from './SelectionOverlay';
type IAIDndImageProps = {
imageDTO: ImageDTO | undefined;
@@ -49,6 +57,7 @@ type IAIDndImageProps = {
thumbnail?: boolean;
noContentFallback?: ReactElement;
useThumbailFallback?: boolean;
+ withHoverOverlay?: boolean;
};
const IAIDndImage = (props: IAIDndImageProps) => {
@@ -75,9 +84,17 @@ const IAIDndImage = (props: IAIDndImageProps) => {
resetIcon = ,
noContentFallback = ,
useThumbailFallback,
+ withHoverOverlay = false,
} = props;
const { colorMode } = useColorMode();
+ const [isHovered, setIsHovered] = useState(false);
+ const handleMouseOver = useCallback(() => {
+ setIsHovered(true);
+ }, []);
+ const handleMouseOut = useCallback(() => {
+ setIsHovered(false);
+ }, []);
const { getUploadButtonProps, getUploadInputProps } = useImageUploadButton({
postUploadAction,
@@ -105,6 +122,8 @@ const IAIDndImage = (props: IAIDndImageProps) => {
{(ref) => (
{
maxW: 'full',
maxH: 'full',
borderRadius: 'base',
- shadow: isSelected ? 'selected.light' : undefined,
- _dark: {
- shadow: isSelected ? 'selected.dark' : undefined,
- },
...imageSx,
}}
/>
{withMetadataOverlay && }
+
)}
{!imageDTO && !isUploadDisabled && (
diff --git a/invokeai/frontend/web/src/common/components/SelectionOverlay.tsx b/invokeai/frontend/web/src/common/components/SelectionOverlay.tsx
new file mode 100644
index 0000000000..9ff6cd341b
--- /dev/null
+++ b/invokeai/frontend/web/src/common/components/SelectionOverlay.tsx
@@ -0,0 +1,42 @@
+import { Box } from '@chakra-ui/react';
+
+type Props = {
+ isSelected: boolean;
+ isHovered: boolean;
+};
+const SelectionOverlay = ({ isSelected, isHovered }: Props) => {
+ return (
+
+ );
+};
+
+export default SelectionOverlay;
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/AutoAddIcon.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/AutoAddIcon.tsx
index 53f0293afa..ffdde04ef5 100644
--- a/invokeai/frontend/web/src/features/gallery/components/Boards/AutoAddIcon.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/Boards/AutoAddIcon.tsx
@@ -5,7 +5,7 @@ const AutoAddIcon = () => {
{
const dispatch = useAppDispatch();
+ const selector = useMemo(
+ () =>
+ createSelector(stateSelector, ({ gallery }) => {
+ const isSelected = gallery.selectedBoardId === board_id;
+ const isAutoAdd = gallery.autoAddBoardId === board_id;
+ return { isSelected, isAutoAdd };
+ }),
+ [board_id]
+ );
+
+ const { isSelected, isAutoAdd } = useAppSelector(selector);
+ const boardName = useBoardName(board_id);
+
const handleSelectBoard = useCallback(() => {
- dispatch(boardIdSelected(board?.board_id ?? board_id));
- }, [board?.board_id, board_id, dispatch]);
+ dispatch(boardIdSelected(board_id));
+ }, [board_id, dispatch]);
+
+ const handleSetAutoAdd = useCallback(() => {
+ dispatch(autoAddBoardIdChanged(board_id));
+ }, [board_id, dispatch]);
+
+ const skipEvent = useCallback((e: MouseEvent) => {
+ e.preventDefault();
+ }, []);
return (
@@ -35,17 +62,24 @@ const BoardContextMenu = memo(
- } onClickCapture={handleSelectBoard}>
- Select Board
-
- {!board && }
- {board && (
-
- )}
+
+ }
+ isDisabled={isAutoAdd}
+ onClick={handleSetAutoAdd}
+ >
+ Auto-add to this Board
+
+ {!board && }
+ {board && (
+
+ )}
+
)}
>
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardsList.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardsList.tsx
index 1cd32f93b0..f20bb5a245 100644
--- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardsList.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/BoardsList.tsx
@@ -76,7 +76,7 @@ const BoardsList = (props: Props) => {
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/GalleryBoard.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/GalleryBoard.tsx
index 8b5d871799..dc484ec230 100644
--- a/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/GalleryBoard.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/Boards/BoardsList/GalleryBoard.tsx
@@ -26,6 +26,7 @@ import { useBoardTotal } from 'services/api/hooks/useBoardTotal';
import { BoardDTO } from 'services/api/types';
import AutoAddIcon from '../AutoAddIcon';
import BoardContextMenu from '../BoardContextMenu';
+import SelectionOverlay from 'common/components/SelectionOverlay';
const BASE_BADGE_STYLES: ChakraProps['sx'] = {
bg: 'base.500',
@@ -56,7 +57,13 @@ const GalleryBoard = memo(
);
const { isSelectedForAutoAdd } = useAppSelector(selector);
-
+ const [isHovered, setIsHovered] = useState(false);
+ const handleMouseOver = useCallback(() => {
+ setIsHovered(true);
+ }, []);
+ const handleMouseOut = useCallback(() => {
+ setIsHovered(false);
+ }, []);
const { currentData: coverImage } = useGetImageDTOQuery(
board.cover_image_name ?? skipToken
);
@@ -83,26 +90,30 @@ const GalleryBoard = memo(
);
const handleSubmit = useCallback(
- (newBoardName: string) => {
- if (!newBoardName) {
- // empty strings are not allowed
+ async (newBoardName: string) => {
+ // empty strings are not allowed
+ if (!newBoardName.trim()) {
setLocalBoardName(board_name);
return;
}
+
+ // don't updated the board name if it hasn't changed
if (newBoardName === board_name) {
- // don't updated the board name if it hasn't changed
return;
}
- updateBoard({ board_id, changes: { board_name: newBoardName } })
- .unwrap()
- .then((response) => {
- // update local state
- setLocalBoardName(response.board_name);
- })
- .catch(() => {
- // revert on error
- setLocalBoardName(board_name);
- });
+
+ try {
+ const { board_name } = await updateBoard({
+ board_id,
+ changes: { board_name: newBoardName },
+ }).unwrap();
+
+ // update local state
+ setLocalBoardName(board_name);
+ } catch {
+ // revert on error
+ setLocalBoardName(board_name);
+ }
},
[board_id, board_name, updateBoard]
);
@@ -116,6 +127,8 @@ const GalleryBoard = memo(
sx={{ w: 'full', h: 'full', touchAction: 'none', userSelect: 'none' }}
>
)}
-
{totalImages}/{totalAssets}
-
+ */}
{isSelectedForAutoAdd && }
-
{
const dispatch = useAppDispatch();
const { totalImages, totalAssets } = useBoardTotal(undefined);
const { autoAddBoardId } = useAppSelector(selector);
+ const boardName = useBoardName(undefined);
const handleSelectBoard = useCallback(() => {
dispatch(boardIdSelected(undefined));
}, [dispatch]);
+ const [isHovered, setIsHovered] = useState(false);
+ const handleMouseOver = useCallback(() => {
+ setIsHovered(true);
+ }, []);
+ const handleMouseOut = useCallback(() => {
+ setIsHovered(false);
+ }, []);
const droppableData: MoveBoardDropData = useMemo(
() => ({
@@ -49,6 +59,8 @@ const NoBoardBoard = memo(({ isSelected }: Props) => {
return (
{
alignItems: 'center',
}}
>
- {
color: 'base.500',
},
}}
+ /> */}
+
- {
{totalImages}/{totalAssets}
-
+ */}
{!autoAddBoardId && }
-
+ >
+ {boardName}
+
+
Move}
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/GalleryBoardContextMenuItems.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/GalleryBoardContextMenuItems.tsx
index e8bd1be992..4b036bfe7c 100644
--- a/invokeai/frontend/web/src/features/gallery/components/Boards/GalleryBoardContextMenuItems.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/Boards/GalleryBoardContextMenuItems.tsx
@@ -59,11 +59,11 @@ const GalleryBoardContextMenuItems = ({ board, setBoardToDelete }: Props) => {
*/}
>
)}
- {!isSelectedForAutoAdd && (
+ {/* {!isSelectedForAutoAdd && (
} onClick={handleToggleAutoAdd}>
Auto-add to this Board
- )}
+ )} */}
}
diff --git a/invokeai/frontend/web/src/features/gallery/components/Boards/NoBoardContextMenuItems.tsx b/invokeai/frontend/web/src/features/gallery/components/Boards/NoBoardContextMenuItems.tsx
index 34b4c5f790..31366f6e6a 100644
--- a/invokeai/frontend/web/src/features/gallery/components/Boards/NoBoardContextMenuItems.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/Boards/NoBoardContextMenuItems.tsx
@@ -16,11 +16,11 @@ const NoBoardContextMenuItems = () => {
return (
<>
- {autoAddBoardId && (
+ {/* {autoAddBoardId && (
} onClick={handleDisableAutoAdd}>
Auto-add to this Board
- )}
+ )} */}
>
);
};
diff --git a/invokeai/frontend/web/src/features/gallery/components/GalleryBoardName.tsx b/invokeai/frontend/web/src/features/gallery/components/GalleryBoardName.tsx
index 7e2048e628..4667723e23 100644
--- a/invokeai/frontend/web/src/features/gallery/components/GalleryBoardName.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/GalleryBoardName.tsx
@@ -6,7 +6,6 @@ import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { memo, useMemo } from 'react';
import { useBoardName } from 'services/api/hooks/useBoardName';
-import { useBoardTotal } from 'services/api/hooks/useBoardTotal';
const selector = createSelector(
[stateSelector],
@@ -27,24 +26,28 @@ const GalleryBoardName = (props: Props) => {
const { isOpen, onToggle } = props;
const { selectedBoardId } = useAppSelector(selector);
const boardName = useBoardName(selectedBoardId);
- const { totalImages, totalAssets } = useBoardTotal(selectedBoardId);
+ // const { totalImages, totalAssets } = useBoardTotal(selectedBoardId);
const formattedBoardName = useMemo(() => {
- if (!boardName) {
- return '';
- }
-
- if (boardName && (totalImages === undefined || totalAssets === undefined)) {
- return boardName;
- }
-
- const count = `${totalImages}/${totalAssets}`;
-
if (boardName.length > 20) {
- return `${boardName.substring(0, 20)}... (${count})`;
+ return `${boardName.substring(0, 20)}...`;
}
- return `${boardName} (${count})`;
- }, [boardName, totalAssets, totalImages]);
+ return boardName;
+ // if (!boardName) {
+ // return '';
+ // }
+
+ // if (boardName && (totalImages === undefined || totalAssets === undefined)) {
+ // return boardName;
+ // }
+
+ // const count = `${totalImages}/${totalAssets}`;
+
+ // if (boardName.length > 20) {
+ // return `${boardName.substring(0, 20)}... (${count})`;
+ // }
+ // return `${boardName} (${count})`;
+ }, [boardName]);
return (
{
>
-
- Images
-
-
- Assets
-
+ }
+ >
+ Images
+
+ }
+ >
+ Assets
+
+
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx
index bf627b9591..866b1579bd 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImage.tsx
@@ -106,6 +106,7 @@ const GalleryImage = (props: HoverableImageProps) => {
isDropDisabled={true}
isUploadDisabled={true}
thumbnail={true}
+ withHoverOverlay
// resetIcon={}
// resetTooltip="Delete image"
// withResetIcon // removed bc it's too easy to accidentally delete images
diff --git a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImageGrid.tsx b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImageGrid.tsx
index e4b996fc96..285327a971 100644
--- a/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImageGrid.tsx
+++ b/invokeai/frontend/web/src/features/gallery/components/ImageGrid/GalleryImageGrid.tsx
@@ -1,8 +1,9 @@
-import { Box, Spinner } from '@chakra-ui/react';
+import { Box, Flex } from '@chakra-ui/react';
import { useAppSelector } from 'app/store/storeHooks';
import IAIButton from 'common/components/IAIButton';
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
import { IMAGE_LIMIT } from 'features/gallery//store/gallerySlice';
+import { selectListImagesBaseQueryArgs } from 'features/gallery/store/gallerySelectors';
import {
UseOverlayScrollbarsParams,
useOverlayScrollbars,
@@ -15,11 +16,10 @@ import {
useLazyListImagesQuery,
useListImagesQuery,
} from 'services/api/endpoints/images';
+import { useBoardTotal } from 'services/api/hooks/useBoardTotal';
import GalleryImage from './GalleryImage';
import ImageGridItemContainer from './ImageGridItemContainer';
import ImageGridListContainer from './ImageGridListContainer';
-import { selectListImagesBaseQueryArgs } from 'features/gallery/store/gallerySelectors';
-import { useBoardTotal } from 'services/api/hooks/useBoardTotal';
const overlayScrollbarsConfig: UseOverlayScrollbarsParams = {
defer: true,
@@ -87,20 +87,34 @@ const GalleryImageGrid = () => {
if (!currentData) {
return (
-
-
-
+
+
+
);
}
if (isSuccess && currentData?.ids.length === 0) {
return (
-
+
-
+
);
}
@@ -129,9 +143,7 @@ const GalleryImageGrid = () => {
loadingText="Loading"
flexShrink={0}
>
- {areMoreAvailable
- ? t('gallery.loadMore')
- : t('gallery.allImagesLoaded')}
+ {`Load More (${currentData.ids.length} of ${currentViewTotal})`}
>
);
diff --git a/invokeai/frontend/web/src/features/ui/components/ParametersDrawer.tsx b/invokeai/frontend/web/src/features/ui/components/ParametersDrawer.tsx
index ee9cc4bbb8..89400c09e5 100644
--- a/invokeai/frontend/web/src/features/ui/components/ParametersDrawer.tsx
+++ b/invokeai/frontend/web/src/features/ui/components/ParametersDrawer.tsx
@@ -78,7 +78,6 @@ const ParametersDrawer = () => {
}}
>
{
};
});
+const invokeAIOutline = defineStyle((props) => {
+ const { colorScheme: c } = props;
+ const borderColor = mode(`gray.200`, `whiteAlpha.300`)(props);
+ return {
+ border: '1px solid',
+ borderColor: c === 'gray' ? borderColor : 'currentColor',
+ '.chakra-button__group[data-attached][data-orientation=horizontal] > &:not(:last-of-type)':
+ { marginEnd: '-1px' },
+ '.chakra-button__group[data-attached][data-orientation=vertical] > &:not(:last-of-type)':
+ { marginBottom: '-1px' },
+ };
+});
+
export const buttonTheme = defineStyleConfig({
variants: {
invokeAI,
+ invokeAIOutline,
},
defaultProps: {
variant: 'invokeAI',
diff --git a/invokeai/frontend/web/src/theme/theme.ts b/invokeai/frontend/web/src/theme/theme.ts
index 6f7a719e85..afed8688ee 100644
--- a/invokeai/frontend/web/src/theme/theme.ts
+++ b/invokeai/frontend/web/src/theme/theme.ts
@@ -78,12 +78,12 @@ export const theme: ThemeOverride = {
hoverSelected: {
light:
'0px 0px 0px 1px var(--invokeai-colors-base-150), 0px 0px 0px 4px var(--invokeai-colors-accent-500)',
- dark: '0px 0px 0px 1px var(--invokeai-colors-base-900), 0px 0px 0px 4px var(--invokeai-colors-accent-300)',
+ dark: '0px 0px 0px 1px var(--invokeai-colors-base-900), 0px 0px 0px 4px var(--invokeai-colors-accent-400)',
},
hoverUnselected: {
light:
- '0px 0px 0px 1px var(--invokeai-colors-base-150), 0px 0px 0px 4px var(--invokeai-colors-accent-200)',
- dark: '0px 0px 0px 1px var(--invokeai-colors-base-900), 0px 0px 0px 4px var(--invokeai-colors-accent-600)',
+ '0px 0px 0px 1px var(--invokeai-colors-base-150), 0px 0px 0px 3px var(--invokeai-colors-accent-500)',
+ dark: '0px 0px 0px 1px var(--invokeai-colors-base-900), 0px 0px 0px 3px var(--invokeai-colors-accent-400)',
},
nodeSelectedOutline: `0 0 0 2px var(--invokeai-colors-accent-450)`,
},