workflow library UI updates: scrollbar to make obvious its overflowing, move deselecet all tags to be next to browse button

This commit is contained in:
Mary Hipp
2025-03-19 11:10:17 -04:00
committed by psychedelicious
parent 9cc2232b6f
commit 05de3b7a84
10 changed files with 71 additions and 42 deletions

View File

@@ -20,12 +20,22 @@ export const overlayScrollbarsParams: UseOverlayScrollbarsParams = {
},
};
export const getOverlayScrollbarsParams = (
overflowX: 'hidden' | 'scroll' = 'hidden',
overflowY: 'hidden' | 'scroll' = 'scroll'
) => {
export const getOverlayScrollbarsParams = ({
overflowX = 'hidden',
overflowY = 'scroll',
visibility = 'auto',
}: {
overflowX?: 'hidden' | 'scroll';
overflowY?: 'hidden' | 'scroll';
visibility?: 'auto' | 'hidden' | 'visible';
}) => {
const params = deepClone(overlayScrollbarsParams);
merge(params, { options: { overflow: { y: overflowY, x: overflowX } } });
merge(params, {
options: {
overflow: { y: overflowY, x: overflowX },
scrollbars: { visibility, autoHide: visibility === 'visible' ? 'never' : 'scroll' },
},
});
return params;
};

View File

@@ -24,7 +24,7 @@ import { PiXBold } from 'react-icons/pi';
import type { FieldComponentProps } from './types';
const overlayscrollbarsOptions = getOverlayScrollbarsParams().options;
const overlayscrollbarsOptions = getOverlayScrollbarsParams({}).options;
const sx = {
borderWidth: 1,

View File

@@ -24,7 +24,7 @@ import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useDebounce } from 'use-debounce';
const overlayscrollbarsOptions = getOverlayScrollbarsParams().options;
const overlayscrollbarsOptions = getOverlayScrollbarsParams({}).options;
export const FloatGeneratorFieldInputComponent = memo(
(props: FieldComponentProps<FloatGeneratorFieldInputInstance, FloatGeneratorFieldInputTemplate>) => {

View File

@@ -24,7 +24,7 @@ import type { ImageDTO } from 'services/api/types';
import type { FieldComponentProps } from './types';
const overlayscrollbarsOptions = getOverlayScrollbarsParams().options;
const overlayscrollbarsOptions = getOverlayScrollbarsParams({}).options;
const sx = {
borderWidth: 1,

View File

@@ -17,7 +17,7 @@ import type { ChangeEvent } from 'react';
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
const overlayscrollbarsOptions = getOverlayScrollbarsParams().options;
const overlayscrollbarsOptions = getOverlayScrollbarsParams({}).options;
export const ImageGeneratorFieldInputComponent = memo(
(props: FieldComponentProps<ImageGeneratorFieldInputInstance, ImageGeneratorFieldInputTemplate>) => {

View File

@@ -27,7 +27,7 @@ import { PiXBold } from 'react-icons/pi';
import type { FieldComponentProps } from './types';
const overlayscrollbarsOptions = getOverlayScrollbarsParams().options;
const overlayscrollbarsOptions = getOverlayScrollbarsParams({}).options;
const sx = {
borderWidth: 1,

View File

@@ -27,7 +27,7 @@ import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useDebounce } from 'use-debounce';
const overlayscrollbarsOptions = getOverlayScrollbarsParams().options;
const overlayscrollbarsOptions = getOverlayScrollbarsParams({}).options;
export const IntegerGeneratorFieldInputComponent = memo(
(props: FieldComponentProps<IntegerGeneratorFieldInputInstance, IntegerGeneratorFieldInputTemplate>) => {

View File

@@ -17,7 +17,7 @@ import { PiXBold } from 'react-icons/pi';
import type { FieldComponentProps } from './types';
const overlayscrollbarsOptions = getOverlayScrollbarsParams().options;
const overlayscrollbarsOptions = getOverlayScrollbarsParams({}).options;
const sx = {
borderWidth: 1,

View File

@@ -21,7 +21,7 @@ import type { ChangeEvent } from 'react';
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
const overlayscrollbarsOptions = getOverlayScrollbarsParams().options;
const overlayscrollbarsOptions = getOverlayScrollbarsParams({}).options;
export const StringGeneratorFieldInputComponent = memo(
(props: FieldComponentProps<StringGeneratorFieldInputInstance, StringGeneratorFieldInputTemplate>) => {

View File

@@ -1,7 +1,18 @@
import type { ButtonProps, CheckboxProps } from '@invoke-ai/ui-library';
import { Button, Checkbox, Collapse, Flex, Spacer, Text } from '@invoke-ai/ui-library';
import {
Button,
ButtonGroup,
Checkbox,
Collapse,
Flex,
IconButton,
Spacer,
Text,
Tooltip,
} from '@invoke-ai/ui-library';
import { useStore } from '@nanostores/react';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { getOverlayScrollbarsParams, overlayScrollbarsStyles } from 'common/components/OverlayScrollbars/constants';
import type { WorkflowLibraryView, WorkflowTagCategory } from 'features/nodes/store/workflowLibrarySlice';
import {
$workflowLibraryCategoriesOptions,
@@ -15,6 +26,7 @@ import {
} from 'features/nodes/store/workflowLibrarySlice';
import { NewWorkflowButton } from 'features/workflowLibrary/components/NewWorkflowButton';
import { UploadWorkflowButton } from 'features/workflowLibrary/components/UploadWorkflowButton';
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { PiArrowCounterClockwiseBold, PiUsersBold } from 'react-icons/pi';
@@ -25,9 +37,14 @@ export const WorkflowLibrarySideNav = () => {
const { t } = useTranslation();
const categoryOptions = useStore($workflowLibraryCategoriesOptions);
const view = useAppSelector(selectWorkflowLibraryView);
const dispatch = useAppDispatch();
const selectedTags = useAppSelector(selectWorkflowLibrarySelectedTags);
const resetTags = useCallback(() => {
dispatch(workflowLibraryTagsReset());
}, [dispatch]);
return (
<Flex h="full" minH={0} overflow="hidden" flexDir="column" w={64} gap={1}>
<Flex h="full" minH={0} overflow="hidden" flexDir="column" w={64} gap={0}>
<Flex flexDir="column" w="full" pb={2}>
<WorkflowLibraryViewButton view="recent">{t('workflows.recentlyOpened')}</WorkflowLibraryViewButton>
</Flex>
@@ -48,7 +65,26 @@ export const WorkflowLibrarySideNav = () => {
)}
</Flex>
<Flex h="full" minH={0} overflow="hidden" flexDir="column">
<WorkflowLibraryViewButton view="defaults">{t('workflows.browseWorkflows')}</WorkflowLibraryViewButton>
{view === 'defaults' && selectedTags.length > 0 ? (
<ButtonGroup>
<WorkflowLibraryViewButton view="defaults" w="auto">
{t('workflows.browseWorkflows')}
</WorkflowLibraryViewButton>
<Tooltip label={t('workflows.deselectAll')}>
<IconButton
onClick={resetTags}
size="md"
aria-label={t('workflows.deselectAll')}
icon={<PiArrowCounterClockwiseBold size={12} />}
variant="ghost"
bg="base.700"
color="base.50"
/>
</Tooltip>
</ButtonGroup>
) : (
<WorkflowLibraryViewButton view="defaults">{t('workflows.browseWorkflows')}</WorkflowLibraryViewButton>
)}
<DefaultsViewCheckboxesCollapsible />
</Flex>
<Spacer />
@@ -58,39 +94,22 @@ export const WorkflowLibrarySideNav = () => {
);
};
const overlayscrollbarsOptions = getOverlayScrollbarsParams({ visibility: 'visible' }).options;
const DefaultsViewCheckboxesCollapsible = memo(() => {
const { t } = useTranslation();
const dispatch = useDispatch();
const tags = useAppSelector(selectWorkflowLibrarySelectedTags);
const tagCategoryOptions = useStore($workflowLibraryTagCategoriesOptions);
const view = useAppSelector(selectWorkflowLibraryView);
const resetTags = useCallback(() => {
dispatch(workflowLibraryTagsReset());
}, [dispatch]);
return (
<Collapse in={view === 'defaults'}>
<Flex flexDir="column" gap={2} pl={4} py={2} overflow="hidden" h="100%" minH={0}>
<Button
isDisabled={tags.length === 0}
onClick={resetTags}
size="sm"
variant="link"
fontWeight="bold"
justifyContent="flex-start"
flexGrow={0}
flexShrink={0}
leftIcon={<PiArrowCounterClockwiseBold />}
h={8}
>
{t('workflows.deselectAll')}
</Button>
<Flex flexDir="column" gap={2} overflow="auto">
{tagCategoryOptions.map((tagCategory) => (
<TagCategory key={tagCategory.categoryTKey} tagCategory={tagCategory} />
))}
</Flex>
<OverlayScrollbarsComponent style={overlayScrollbarsStyles} options={overlayscrollbarsOptions}>
<Flex flexDir="column" gap={2} overflow="auto">
{tagCategoryOptions.map((tagCategory) => (
<TagCategory key={tagCategory.categoryTKey} tagCategory={tagCategory} />
))}
</Flex>
</OverlayScrollbarsComponent>
</Flex>
</Collapse>
);