diff --git a/invokeai/frontend/web/src/app/components/GlobalHotkeys.ts b/invokeai/frontend/web/src/app/components/GlobalHotkeys.ts index c4660416bf..9827e7f2b3 100644 --- a/invokeai/frontend/web/src/app/components/GlobalHotkeys.ts +++ b/invokeai/frontend/web/src/app/components/GlobalHotkeys.ts @@ -1,7 +1,9 @@ import { createSelector } from '@reduxjs/toolkit'; import { RootState } from 'app/store/store'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; +import { requestCanvasRescale } from 'features/canvas/store/thunks/requestCanvasScale'; import { shiftKeyPressed } from 'features/ui/store/hotkeysSlice'; +import { activeTabNameSelector } from 'features/ui/store/uiSelectors'; import { setActiveTab, toggleGalleryPanel, @@ -14,10 +16,11 @@ import React, { memo } from 'react'; import { isHotkeyPressed, useHotkeys } from 'react-hotkeys-hook'; const globalHotkeysSelector = createSelector( - (state: RootState) => state.hotkeys, - (hotkeys) => { + [(state: RootState) => state.hotkeys, (state: RootState) => state.ui], + (hotkeys, ui) => { const { shift } = hotkeys; - return { shift }; + const { shouldPinParametersPanel, shouldPinGallery } = ui; + return { shift, shouldPinGallery, shouldPinParametersPanel }; }, { memoizeOptions: { @@ -34,7 +37,10 @@ const globalHotkeysSelector = createSelector( */ const GlobalHotkeys: React.FC = () => { const dispatch = useAppDispatch(); - const { shift } = useAppSelector(globalHotkeysSelector); + const { shift, shouldPinParametersPanel, shouldPinGallery } = useAppSelector( + globalHotkeysSelector + ); + const activeTabName = useAppSelector(activeTabNameSelector); useHotkeys( '*', @@ -51,18 +57,30 @@ const GlobalHotkeys: React.FC = () => { useHotkeys('o', () => { dispatch(toggleParametersPanel()); + if (activeTabName === 'unifiedCanvas' && shouldPinParametersPanel) { + dispatch(requestCanvasRescale()); + } }); useHotkeys(['shift+o'], () => { dispatch(togglePinParametersPanel()); + if (activeTabName === 'unifiedCanvas') { + dispatch(requestCanvasRescale()); + } }); useHotkeys('g', () => { dispatch(toggleGalleryPanel()); + if (activeTabName === 'unifiedCanvas' && shouldPinGallery) { + dispatch(requestCanvasRescale()); + } }); useHotkeys(['shift+g'], () => { dispatch(togglePinGalleryPanel()); + if (activeTabName === 'unifiedCanvas') { + dispatch(requestCanvasRescale()); + } }); useHotkeys('1', () => { diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasBoundingBox.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasBoundingBox.tsx index 3421749658..3086e001c2 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasBoundingBox.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasBoundingBox.tsx @@ -11,6 +11,7 @@ import { setIsMouseOverBoundingBox, setIsMovingBoundingBox, setIsTransformingBoundingBox, + setShouldSnapToGrid, } from 'features/canvas/store/canvasSlice'; import { uiSelector } from 'features/ui/store/uiSelectors'; import Konva from 'konva'; @@ -20,6 +21,7 @@ import { Vector2d } from 'konva/lib/types'; import { isEqual } from 'lodash-es'; import { useCallback, useEffect, useRef, useState } from 'react'; +import { useHotkeys } from 'react-hotkeys-hook'; import { Group, Rect, Transformer } from 'react-konva'; const boundingBoxPreviewSelector = createSelector( @@ -91,6 +93,10 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => { const scaledStep = 64 * stageScale; + useHotkeys('N', () => { + dispatch(setShouldSnapToGrid(!shouldSnapToGrid)); + }); + const handleOnDragMove = useCallback( (e: KonvaEventObject) => { if (!shouldSnapToGrid) { diff --git a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx index 794b8ba795..158e2954af 100644 --- a/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx +++ b/invokeai/frontend/web/src/features/canvas/components/IAICanvasToolbar/IAICanvasToolChooserOptions.tsx @@ -139,7 +139,7 @@ const IAICanvasToolChooserOptions = () => { ); useHotkeys( - ['shift+BracketLeft'], + ['Shift+BracketLeft'], () => { dispatch( setBrushColor({ @@ -156,7 +156,7 @@ const IAICanvasToolChooserOptions = () => { ); useHotkeys( - ['shift+BracketRight'], + ['Shift+BracketRight'], () => { dispatch( setBrushColor({ diff --git a/invokeai/frontend/web/src/features/nodes/components/AddNodeMenu.tsx b/invokeai/frontend/web/src/features/nodes/components/AddNodeMenu.tsx index 4e44c4c077..408bf74eed 100644 --- a/invokeai/frontend/web/src/features/nodes/components/AddNodeMenu.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/AddNodeMenu.tsx @@ -110,8 +110,11 @@ const SelectItem = forwardRef( return (
- {label} - + {label} + {description}
diff --git a/invokeai/frontend/web/src/features/nodes/components/IAINode/IAINodeHeader.tsx b/invokeai/frontend/web/src/features/nodes/components/IAINode/IAINodeHeader.tsx index 226aaed7be..7b56bc95b4 100644 --- a/invokeai/frontend/web/src/features/nodes/components/IAINode/IAINodeHeader.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/IAINode/IAINodeHeader.tsx @@ -20,8 +20,8 @@ const IAINodeHeader = (props: IAINodeHeaderProps) => { justifyContent: 'space-between', px: 2, py: 1, - bg: 'base.300', - _dark: { bg: 'base.700' }, + bg: 'base.100', + _dark: { bg: 'base.900' }, }} > @@ -30,7 +30,7 @@ const IAINodeHeader = (props: IAINodeHeaderProps) => { sx={{ fontWeight: 600, color: 'base.900', - _dark: { color: 'base.100' }, + _dark: { color: 'base.200' }, }} > {title} diff --git a/invokeai/frontend/web/src/features/nodes/components/InvocationComponent.tsx b/invokeai/frontend/web/src/features/nodes/components/InvocationComponent.tsx index 608f98d6d2..4c031afaff 100644 --- a/invokeai/frontend/web/src/features/nodes/components/InvocationComponent.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/InvocationComponent.tsx @@ -59,7 +59,7 @@ export const InvocationComponent = memo((props: NodeProps) => { flexDirection: 'column', borderBottomRadius: 'md', py: 2, - bg: 'base.200', + bg: 'base.150', _dark: { bg: 'base.800' }, }} > diff --git a/invokeai/frontend/web/src/features/nodes/components/NodeEditor.tsx b/invokeai/frontend/web/src/features/nodes/components/NodeEditor.tsx index 2be98b1cb9..8c0480774c 100644 --- a/invokeai/frontend/web/src/features/nodes/components/NodeEditor.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/NodeEditor.tsx @@ -1,9 +1,9 @@ -import 'reactflow/dist/style.css'; import { Box } from '@chakra-ui/react'; import { ReactFlowProvider } from 'reactflow'; +import 'reactflow/dist/style.css'; -import { Flow } from './Flow'; import { memo } from 'react'; +import { Flow } from './Flow'; const NodeEditor = () => { return ( diff --git a/invokeai/frontend/web/src/features/nodes/components/NodeWrapper.tsx b/invokeai/frontend/web/src/features/nodes/components/NodeWrapper.tsx index dc5a94c267..882c6efd69 100644 --- a/invokeai/frontend/web/src/features/nodes/components/NodeWrapper.tsx +++ b/invokeai/frontend/web/src/features/nodes/components/NodeWrapper.tsx @@ -1,9 +1,9 @@ import { Box, useToken } from '@chakra-ui/react'; import { NODE_MIN_WIDTH } from 'app/constants'; +import { useAppSelector } from 'app/store/storeHooks'; import { PropsWithChildren } from 'react'; import { DRAG_HANDLE_CLASSNAME } from '../hooks/useBuildInvocation'; -import { useAppSelector } from 'app/store/storeHooks'; type NodeWrapperProps = PropsWithChildren & { selected: boolean; diff --git a/invokeai/frontend/web/src/features/system/components/HotkeysModal/HotkeysModal.tsx b/invokeai/frontend/web/src/features/system/components/HotkeysModal/HotkeysModal.tsx index 4a7f4292eb..4da46fdac9 100644 --- a/invokeai/frontend/web/src/features/system/components/HotkeysModal/HotkeysModal.tsx +++ b/invokeai/frontend/web/src/features/system/components/HotkeysModal/HotkeysModal.tsx @@ -15,7 +15,7 @@ import { ModalOverlay, useDisclosure, } from '@chakra-ui/react'; -import { cloneElement, ReactElement } from 'react'; +import { ReactElement, cloneElement } from 'react'; import { useTranslation } from 'react-i18next'; import HotkeysModalItem from './HotkeysModalItem'; @@ -65,11 +65,6 @@ export default function HotkeysModal({ children }: HotkeysModalProps) { desc: t('hotkeys.pinOptions.desc'), hotkey: 'Shift+O', }, - { - title: t('hotkeys.toggleViewer.title'), - desc: t('hotkeys.toggleViewer.desc'), - hotkey: 'Z', - }, { title: t('hotkeys.toggleGallery.title'), desc: t('hotkeys.toggleGallery.desc'), @@ -85,12 +80,6 @@ export default function HotkeysModal({ children }: HotkeysModalProps) { desc: t('hotkeys.changeTabs.desc'), hotkey: '1-5', }, - - { - title: t('hotkeys.consoleToggle.title'), - desc: t('hotkeys.consoleToggle.desc'), - hotkey: '`', - }, ]; const generalHotkeys = [ @@ -109,11 +98,6 @@ export default function HotkeysModal({ children }: HotkeysModalProps) { desc: t('hotkeys.setParameters.desc'), hotkey: 'A', }, - { - title: t('hotkeys.restoreFaces.title'), - desc: t('hotkeys.restoreFaces.desc'), - hotkey: 'Shift+R', - }, { title: t('hotkeys.upscale.title'), desc: t('hotkeys.upscale.desc'), diff --git a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx index 43a487ba5a..890ceb1f48 100644 --- a/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx +++ b/invokeai/frontend/web/src/features/system/components/SettingsModal/SettingsModal.tsx @@ -183,7 +183,7 @@ const SettingsModal = ({ children, config }: SettingsModalProps) => { > - {t('common.settingsLabel')} + {t('common.settingsLabel')} @@ -331,12 +331,15 @@ export default SettingsModal; const StyledFlex = (props: PropsWithChildren) => { return ( {props.children} diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerPanel/ModelList.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerPanel/ModelList.tsx index 4a12aad0bf..93cef98f80 100644 --- a/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerPanel/ModelList.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerPanel/ModelList.tsx @@ -3,7 +3,7 @@ import { EntityState } from '@reduxjs/toolkit'; import IAIButton from 'common/components/IAIButton'; import IAIInput from 'common/components/IAIInput'; import { forEach } from 'lodash-es'; -import type { ChangeEvent } from 'react'; +import type { ChangeEvent, PropsWithChildren } from 'react'; import { useCallback, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { @@ -44,13 +44,7 @@ const ModelList = (props: ModelListProps) => { return ( - + setModelFormatFilter('all')} @@ -83,35 +77,39 @@ const ModelList = (props: ModelListProps) => { {['all', 'diffusers'].includes(modelFormatFilter) && filteredDiffusersModels.length > 0 && ( - - - Diffusers - - {filteredDiffusersModels.map((model) => ( - - ))} - + + + + Diffusers + + {filteredDiffusersModels.map((model) => ( + + ))} + + )} {['all', 'checkpoint'].includes(modelFormatFilter) && filteredCheckpointModels.length > 0 && ( - - - Checkpoint - - {filteredCheckpointModels.map((model) => ( - - ))} - + + + + Checkpoint + + {filteredCheckpointModels.map((model) => ( + + ))} + + )} @@ -143,3 +141,24 @@ const modelsFilter = ( }); return filteredModels; }; + +const StyledModelContainer = (props: PropsWithChildren) => { + return ( + + {props.children} + + ); +}; diff --git a/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerPanel/ModelListItem.tsx b/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerPanel/ModelListItem.tsx index 3d2126dce7..224b0ac003 100644 --- a/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerPanel/ModelListItem.tsx +++ b/invokeai/frontend/web/src/features/ui/components/tabs/ModelManager/subpanels/ModelManagerPanel/ModelListItem.tsx @@ -1,5 +1,5 @@ import { DeleteIcon } from '@chakra-ui/icons'; -import { Flex, Text, Tooltip } from '@chakra-ui/react'; +import { Badge, Flex, Text, Tooltip } from '@chakra-ui/react'; import { makeToast } from 'app/components/Toaster'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import IAIAlertDialog from 'common/components/IAIAlertDialog'; @@ -20,6 +20,13 @@ type ModelListItemProps = { setSelectedModelId: (v: string | undefined) => void; }; +const modelBaseTypeMap = { + 'sd-1': 'SD1', + 'sd-2': 'SD2', + sdxl: 'SDXL', + 'sdxl-refiner': 'SDXLR', +}; + export default function ModelListItem(props: ModelListItemProps) { const isBusy = useAppSelector(selectIsBusy); const { t } = useTranslation(); @@ -76,7 +83,7 @@ export default function ModelListItem(props: ModelListItemProps) { bg: isSelected ? 'accent.400' : 'base.100', color: isSelected ? 'base.50' : 'base.800', _hover: { - bg: isSelected ? 'accent.500' : 'base.200', + bg: isSelected ? 'accent.500' : 'base.300', color: isSelected ? 'base.50' : 'base.800', }, _dark: { @@ -84,15 +91,33 @@ export default function ModelListItem(props: ModelListItemProps) { bg: isSelected ? 'accent.600' : 'base.850', _hover: { color: isSelected ? 'base.50' : 'base.100', - bg: isSelected ? 'accent.550' : 'base.800', + bg: isSelected ? 'accent.550' : 'base.700', }, }, }} onClick={handleSelectModel} > - - {model.model_name} - + + + { + modelBaseTypeMap[ + model.base_model as keyof typeof modelBaseTypeMap + ] + } + + + {model.model_name} + + =0.0.6", "timm==0.6.13", # needed to override timm latest in controlnet_aux, see https://github.com/isl-org/ZoeDepth/issues/26 "datasets",