fix(ui): more fixing of auto-add

This commit is contained in:
psychedelicious 2023-07-21 15:00:07 +10:00
parent e10e22440d
commit 3a610e1a65
11 changed files with 197 additions and 171 deletions

View File

@ -84,6 +84,13 @@ export const addInvocationCompleteEventListener = () => {
);
}
dispatch(
imagesApi.util.invalidateTags([
{ type: 'BoardImagesTotal', id: autoAddBoardId ?? 'none' },
{ type: 'BoardAssetsTotal', id: autoAddBoardId ?? 'none' },
])
);
const { selectedBoardId, shouldAutoSwitch } = gallery;
// If auto-switch is enabled, select the new image

View File

@ -0,0 +1,19 @@
import { Flex, Icon } from '@chakra-ui/react';
import { FaPlus } from 'react-icons/fa';
const AutoAddIcon = () => {
return (
<Flex
sx={{
position: 'absolute',
insetInlineStart: 0,
top: 0,
p: 1,
}}
>
<Icon as={FaPlus} sx={{ fill: 'accent.500' }} />
</Flex>
);
};
export default AutoAddIcon;

View File

@ -52,7 +52,7 @@ const BoardAutoAddSelect = () => {
return;
}
dispatch(autoAddBoardIdChanged(v === 'none' ? null : v));
dispatch(autoAddBoardIdChanged(v === 'none' ? undefined : v));
},
[dispatch]
);

View File

@ -1,9 +1,15 @@
import { Box, MenuItem, MenuList } from '@chakra-ui/react';
import { useAppDispatch } from 'app/store/storeHooks';
import { MenuItem, MenuList } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { ContextMenu, ContextMenuProps } from 'chakra-ui-contextmenu';
import { boardIdSelected } from 'features/gallery/store/gallerySlice';
import { memo, useCallback } from 'react';
import { FaFolder } from 'react-icons/fa';
import {
autoAddBoardIdChanged,
boardIdSelected,
} from 'features/gallery/store/gallerySlice';
import { memo, useCallback, useMemo } from 'react';
import { FaFolder, FaMinus, FaPlus } from 'react-icons/fa';
import { BoardDTO } from 'services/api/types';
import { menuListMotionProps } from 'theme/components/menu';
import GalleryBoardContextMenuItems from './GalleryBoardContextMenuItems';
@ -11,7 +17,7 @@ import SystemBoardContextMenuItems from './SystemBoardContextMenuItems';
type Props = {
board?: BoardDTO;
board_id: string;
board_id?: string;
children: ContextMenuProps<HTMLDivElement>['children'];
setBoardToDelete?: (board?: BoardDTO) => void;
};
@ -19,9 +25,30 @@ type Props = {
const BoardContextMenu = memo(
({ board, board_id, setBoardToDelete, children }: Props) => {
const dispatch = useAppDispatch();
const selector = useMemo(
() =>
createSelector(
stateSelector,
({ gallery }) => {
const isSelectedForAutoAdd = board_id === gallery.autoAddBoardId;
return { isSelectedForAutoAdd };
},
defaultSelectorOptions
),
[board_id]
);
const { isSelectedForAutoAdd } = useAppSelector(selector);
const handleSelectBoard = useCallback(() => {
dispatch(boardIdSelected(board?.board_id ?? board_id));
}, [board?.board_id, board_id, dispatch]);
const handleAutoAdd = useCallback(() => {
dispatch(autoAddBoardIdChanged(board_id));
}, [board_id, dispatch]);
return (
<ContextMenu<HTMLDivElement>
menuProps={{ size: 'sm', isLazy: true }}
@ -37,6 +64,14 @@ const BoardContextMenu = memo(
<MenuItem icon={<FaFolder />} onClickCapture={handleSelectBoard}>
Select Board
</MenuItem>
<MenuItem
icon={isSelectedForAutoAdd ? <FaMinus /> : <FaPlus />}
onClickCapture={handleAutoAdd}
>
{isSelectedForAutoAdd
? 'Disable Auto-Add'
: 'Auto-Add to this Board'}
</MenuItem>
{!board && <SystemBoardContextMenuItems board_id={board_id} />}
{board && (
<GalleryBoardContextMenuItems

View File

@ -24,13 +24,9 @@ import { useUpdateBoardMutation } from 'services/api/endpoints/boards';
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
import { useBoardTotal } from 'services/api/hooks/useBoardTotal';
import { BoardDTO } from 'services/api/types';
import AutoAddIcon from '../AutoAddIcon';
import BoardContextMenu from '../BoardContextMenu';
const AUTO_ADD_BADGE_STYLES: ChakraProps['sx'] = {
bg: 'accent.200',
color: 'blackAlpha.900',
};
const BASE_BADGE_STYLES: ChakraProps['sx'] = {
bg: 'base.500',
color: 'whiteAlpha.900',
@ -200,6 +196,7 @@ const GalleryBoard = memo(
{totalImages}/{totalAssets}
</Badge>
</Flex>
{isSelectedForAutoAdd && <AutoAddIcon />}
<Box
className="selection-box"
sx={{

View File

@ -1,11 +1,16 @@
import { Badge, Box, ChakraProps, Flex, Icon, Text } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { MoveBoardDropData } from 'app/components/ImageDnd/typesafeDnd';
import { useAppDispatch } from 'app/store/storeHooks';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAIDroppable from 'common/components/IAIDroppable';
import { boardIdSelected } from 'features/gallery/store/gallerySlice';
import { memo, useCallback, useMemo } from 'react';
import { FaFolder } from 'react-icons/fa';
import { FaFolder, FaPlus } from 'react-icons/fa';
import { useBoardTotal } from 'services/api/hooks/useBoardTotal';
import AutoAddIcon from '../AutoAddIcon';
import BoardContextMenu from '../BoardContextMenu';
const BASE_BADGE_STYLES: ChakraProps['sx'] = {
bg: 'base.500',
@ -15,9 +20,19 @@ interface Props {
isSelected: boolean;
}
const selector = createSelector(
stateSelector,
({ gallery }) => {
const { autoAddBoardId } = gallery;
return { autoAddBoardId };
},
defaultSelectorOptions
);
const NoBoardBoard = memo(({ isSelected }: Props) => {
const dispatch = useAppDispatch();
const { totalImages, totalAssets } = useBoardTotal(undefined);
const { autoAddBoardId } = useAppSelector(selector);
const handleSelectBoard = useCallback(() => {
dispatch(boardIdSelected(undefined));
}, [dispatch]);
@ -34,85 +49,92 @@ const NoBoardBoard = memo(({ isSelected }: Props) => {
return (
<Box sx={{ w: 'full', h: 'full', touchAction: 'none', userSelect: 'none' }}>
<Flex
onClick={handleSelectBoard}
sx={{
position: 'relative',
justifyContent: 'center',
alignItems: 'center',
aspectRatio: '1/1',
borderRadius: 'base',
cursor: 'pointer',
w: 'full',
h: 'full',
}}
>
<Flex
sx={{
w: 'full',
h: 'full',
justifyContent: 'center',
alignItems: 'center',
borderRadius: 'base',
bg: 'base.200',
_dark: {
bg: 'base.800',
},
}}
>
<Flex
sx={{
w: 'full',
h: 'full',
justifyContent: 'center',
alignItems: 'center',
}}
>
<Icon
boxSize={12}
as={FaFolder}
<BoardContextMenu>
{(ref) => (
<Flex
ref={ref}
onClick={handleSelectBoard}
sx={{
opacity: 0.7,
color: 'base.500',
w: 'full',
h: 'full',
position: 'relative',
justifyContent: 'center',
alignItems: 'center',
borderRadius: 'base',
cursor: 'pointer',
bg: 'base.200',
_dark: {
color: 'base.500',
bg: 'base.800',
},
}}
/>
</Flex>
</Flex>
<Flex
sx={{
position: 'absolute',
insetInlineEnd: 0,
top: 0,
p: 1,
}}
>
<Badge variant="solid" sx={BASE_BADGE_STYLES}>
{totalImages}/{totalAssets}
</Badge>
</Flex>
<Box
className="selection-box"
sx={{
position: 'absolute',
top: 0,
insetInlineEnd: 0,
bottom: 0,
insetInlineStart: 0,
borderRadius: 'base',
transitionProperty: 'common',
transitionDuration: 'common',
shadow: isSelected ? 'selected.light' : undefined,
_dark: {
shadow: isSelected ? 'selected.dark' : undefined,
},
}}
/>
<IAIDroppable
data={droppableData}
dropLabel={<Text fontSize="md">Move</Text>}
/>
>
<Flex
sx={{
w: 'full',
h: 'full',
justifyContent: 'center',
alignItems: 'center',
}}
>
<Icon
boxSize={12}
as={FaFolder}
sx={{
opacity: 0.7,
color: 'base.500',
_dark: {
color: 'base.500',
},
}}
/>
</Flex>
<Flex
sx={{
position: 'absolute',
insetInlineEnd: 0,
top: 0,
p: 1,
}}
>
<Badge variant="solid" sx={BASE_BADGE_STYLES}>
{totalImages}/{totalAssets}
</Badge>
</Flex>
{!autoAddBoardId && <AutoAddIcon />}
<Box
className="selection-box"
sx={{
position: 'absolute',
top: 0,
insetInlineEnd: 0,
bottom: 0,
insetInlineStart: 0,
borderRadius: 'base',
transitionProperty: 'common',
transitionDuration: 'common',
shadow: isSelected ? 'selected.light' : undefined,
_dark: {
shadow: isSelected ? 'selected.dark' : undefined,
},
}}
/>
<IAIDroppable
data={droppableData}
dropLabel={<Text fontSize="md">Move</Text>}
/>
</Flex>
)}
</BoardContextMenu>
</Flex>
</Box>
);

View File

@ -1,11 +1,6 @@
import { MenuItem } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { autoAddBoardIdChanged } from 'features/gallery/store/gallerySlice';
import { memo, useCallback, useMemo } from 'react';
import { FaMinus, FaPlus, FaTrash } from 'react-icons/fa';
import { memo, useCallback } from 'react';
import { FaTrash } from 'react-icons/fa';
import { BoardDTO } from 'services/api/types';
type Props = {
@ -14,25 +9,6 @@ type Props = {
};
const GalleryBoardContextMenuItems = ({ board, setBoardToDelete }: Props) => {
const dispatch = useAppDispatch();
const selector = useMemo(
() =>
createSelector(
stateSelector,
({ gallery }) => {
const isSelectedForAutoAdd =
board.board_id === gallery.autoAddBoardId;
return { isSelectedForAutoAdd };
},
defaultSelectorOptions
),
[board.board_id]
);
const { isSelectedForAutoAdd } = useAppSelector(selector);
const handleDelete = useCallback(() => {
if (!setBoardToDelete) {
return;
@ -40,31 +16,8 @@ const GalleryBoardContextMenuItems = ({ board, setBoardToDelete }: Props) => {
setBoardToDelete(board);
}, [board, setBoardToDelete]);
const handleToggleAutoAdd = useCallback(() => {
dispatch(
autoAddBoardIdChanged(isSelectedForAutoAdd ? null : board.board_id)
);
}, [board.board_id, dispatch, isSelectedForAutoAdd]);
return (
<>
{board.image_count > 0 && (
<>
{/* <MenuItem
isDisabled={!board.image_count}
icon={<FaImages />}
onClickCapture={handleAddBoardToBatch}
>
Add Board to Batch
</MenuItem> */}
</>
)}
<MenuItem
icon={isSelectedForAutoAdd ? <FaMinus /> : <FaPlus />}
onClickCapture={handleToggleAutoAdd}
>
{isSelectedForAutoAdd ? 'Disable Auto-Add' : 'Auto-Add to this Board'}
</MenuItem>
<MenuItem
sx={{ color: 'error.600', _dark: { color: 'error.300' } }}
icon={<FaTrash />}

View File

@ -51,7 +51,7 @@ const GalleryBoardName = (props: Props) => {
as={Button}
onClick={onToggle}
size="sm"
variant="ghost"
// variant="ghost"
sx={{
position: 'relative',
gap: 2,
@ -59,12 +59,12 @@ const GalleryBoardName = (props: Props) => {
justifyContent: 'center',
alignItems: 'center',
px: 2,
bg: 'base.100',
_dark: { bg: 'base.800' },
_hover: {
bg: 'base.200',
_dark: { bg: 'base.700' },
},
// bg: 'base.100',
// _dark: { bg: 'base.800' },
// _hover: {
// bg: 'base.200',
// _dark: { bg: 'base.700' },
// },
}}
>
<Spacer />

View File

@ -3,6 +3,9 @@ import {
ButtonGroup,
Flex,
Spacer,
Tab,
TabList,
Tabs,
VStack,
useDisclosure,
} from '@chakra-ui/react';
@ -87,30 +90,22 @@ const ImageGalleryContent = () => {
gap: 2,
}}
>
<ButtonGroup isAttached sx={{ w: 'full' }}>
<IAIButton
leftIcon={<FaImages />}
size="sm"
isChecked={galleryView === 'images'}
onClick={handleClickImages}
sx={{
w: 'full',
}}
>
Images
</IAIButton>
<IAIButton
leftIcon={<FaServer />}
size="sm"
isChecked={galleryView === 'assets'}
onClick={handleClickAssets}
sx={{
w: 'full',
}}
>
Assets
</IAIButton>
</ButtonGroup>
<Tabs variant="line" size="sm" sx={{ w: 'full' }}>
<TabList>
<Tab
onClick={handleClickImages}
sx={{ borderTopRadius: 'base', w: 'full' }}
>
Images
</Tab>
<Tab
onClick={handleClickAssets}
sx={{ borderTopRadius: 'base', w: 'full' }}
>
Assets
</Tab>
</TabList>
</Tabs>
</Flex>
{selectedBoardId === 'batch' ? (

View File

@ -21,7 +21,7 @@ export type BoardId = string | undefined;
type GalleryState = {
selection: string[];
shouldAutoSwitch: boolean;
autoAddBoardId: string | null;
autoAddBoardId: string | undefined;
galleryImageMinimumWidth: number;
selectedBoardId: BoardId;
galleryView: GalleryView;
@ -32,7 +32,7 @@ type GalleryState = {
export const initialGalleryState: GalleryState = {
selection: [],
shouldAutoSwitch: true,
autoAddBoardId: null,
autoAddBoardId: undefined,
galleryImageMinimumWidth: 96,
selectedBoardId: undefined,
galleryView: 'images',
@ -124,7 +124,10 @@ export const gallerySlice = createSlice({
state.batchImageNames = [];
state.selection = [];
},
autoAddBoardIdChanged: (state, action: PayloadAction<string | null>) => {
autoAddBoardIdChanged: (
state,
action: PayloadAction<string | undefined>
) => {
state.autoAddBoardId = action.payload;
},
galleryViewChanged: (state, action: PayloadAction<GalleryView>) => {
@ -137,10 +140,11 @@ export const gallerySlice = createSlice({
(state, action) => {
const deletedBoardId = action.meta.arg.originalArgs;
if (deletedBoardId === state.selectedBoardId) {
state.selectedBoardId = 'images';
state.selectedBoardId = undefined;
state.galleryView = 'images';
}
if (deletedBoardId === state.autoAddBoardId) {
state.autoAddBoardId = null;
state.autoAddBoardId = undefined;
}
}
);
@ -153,7 +157,7 @@ export const gallerySlice = createSlice({
}
if (!boards.map((b) => b.board_id).includes(state.autoAddBoardId)) {
state.autoAddBoardId = null;
state.autoAddBoardId = undefined;
}
}
);

View File

@ -190,9 +190,6 @@ export const boardsApi = api.injectEndpoints({
)
);
});
// after deleting a board, select the 'All Images' board
dispatch(boardIdSelected('images'));
} catch {
//no-op
}
@ -265,9 +262,6 @@ export const boardsApi = api.injectEndpoints({
)
);
});
// after deleting a board, select the 'All Images' board
dispatch(boardIdSelected('images'));
} catch {
//no-op
}