feat(ui): fix queue item count badge positioning

Previously this badge, floating over the queue menu button next to the invoke button, was rendered within the existing layout. When I initially positioned it, the app layout interfered - it would extend into an area reserved for a flex gap, which cut off the badge.

As a (bad) workaround, I had shifted the whole app down a few pixels to make room for it. What I should have done is what I've done in this commit - render the badge in a portal to take it out of the layout so we don't need that extra vertical padding.

Sleekified some styling a bit too.
This commit is contained in:
psychedelicious 2024-08-28 16:37:50 +10:00
parent 64e60a7fde
commit ce55a96125
7 changed files with 31 additions and 17 deletions

View File

@ -19,8 +19,6 @@ export const CanvasEditor = memo(() => {
<Flex
tabIndex={-1}
ref={ref}
layerStyle="first"
p={2}
borderRadius="base"
position="relative"
flexDirection="column"

View File

@ -82,10 +82,11 @@ export const StageComponent = memo(({ asPreview = false }: Props) => {
);
return (
<Flex position="relative" w="full" h="full" bg={dynamicGrid ? 'base.850' : 'base.900'}>
<Flex position="relative" w="full" h="full" bg={dynamicGrid ? 'base.850' : 'base.900'} borderRadius="base">
{!dynamicGrid && (
<Flex
position="absolute"
borderRadius="base"
bgImage={TRANSPARENCY_CHECKER_PATTERN}
top={0}
right={0}
@ -102,9 +103,6 @@ export const StageComponent = memo(({ asPreview = false }: Props) => {
left={0}
ref={containerRef}
borderRadius="base"
border={1}
borderStyle="solid"
borderColor="base.700"
overflow="hidden"
data-testid="control-layers-canvas"
/>

View File

@ -59,7 +59,7 @@ const GalleryPanelContent = () => {
}, [boardSearchText.length, boardSearchDisclosure, boardsListPanel, dispatch]);
return (
<Flex ref={ref} position="relative" flexDirection="column" h="full" w="full" pt={2} tabIndex={-1}>
<Flex ref={ref} position="relative" flexDirection="column" h="full" w="full" tabIndex={-1}>
<Flex alignItems="center" gap={0}>
<GalleryHeader />
<Flex alignItems="center" justifyContent="space-between" w="full">

View File

@ -21,7 +21,7 @@ export const ImageViewer = memo(() => {
<Flex
ref={ref}
tabIndex={-1}
layerStyle="first"
layerStyle="body"
borderRadius="base"
position="absolute"
flexDirection="column"
@ -29,7 +29,6 @@ export const ImageViewer = memo(() => {
right={0}
bottom={0}
left={0}
p={2}
rowGap={4}
alignItems="center"
justifyContent="center"

View File

@ -7,16 +7,18 @@ import {
MenuDivider,
MenuItem,
MenuList,
Portal,
useDisclosure,
} from '@invoke-ai/ui-library';
import { useAppDispatch } from 'app/store/storeHooks';
import type { Coordinate } from 'features/controlLayers/store/types';
import { useClearQueueConfirmationAlertDialog } from 'features/queue/components/ClearQueueConfirmationAlertDialog';
import { useClearQueue } from 'features/queue/hooks/useClearQueue';
import { usePauseProcessor } from 'features/queue/hooks/usePauseProcessor';
import { useResumeProcessor } from 'features/queue/hooks/useResumeProcessor';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { setActiveTab } from 'features/ui/store/uiSlice';
import { memo, useCallback } from 'react';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { PiPauseFill, PiPlayFill, PiTrashSimpleBold } from 'react-icons/pi';
import { RiListCheck, RiPlayList2Fill } from 'react-icons/ri';
@ -26,6 +28,8 @@ export const QueueActionsMenuButton = memo(() => {
const { isOpen, onOpen, onClose } = useDisclosure();
const dispatch = useAppDispatch();
const { t } = useTranslation();
const [badgePos, setBadgePos] = useState<Coordinate | null>(null);
const menuButtonRef = useRef<HTMLButtonElement>(null);
const dialogState = useClearQueueConfirmationAlertDialog();
const isPauseEnabled = useFeatureStatus('pauseQueue');
const isResumeEnabled = useFeatureStatus('resumeQueue');
@ -49,10 +53,17 @@ export const QueueActionsMenuButton = memo(() => {
dispatch(setActiveTab('queue'));
}, [dispatch]);
useEffect(() => {
if (menuButtonRef.current) {
const { x, y } = menuButtonRef.current.getBoundingClientRect();
setBadgePos({ x: x - 10, y: y - 10 });
}
}, []);
return (
<Box pos="relative">
<Menu isOpen={isOpen} onOpen={onOpen} onClose={onClose} placement="bottom-end">
<MenuButton as={IconButton} aria-label="Queue Actions Menu" icon={<RiListCheck />} />
<MenuButton ref={menuButtonRef} as={IconButton} aria-label="Queue Actions Menu" icon={<RiListCheck />} />
<MenuList>
<MenuItem
isDestructive
@ -89,10 +100,18 @@ export const QueueActionsMenuButton = memo(() => {
</MenuItem>
</MenuList>
</Menu>
{queueSize > 0 && (
<Badge pos="absolute" insetInlineStart={-3} insetBlockStart={-1.5} colorScheme="invokeYellow" zIndex="docked">
{queueSize > 0 && badgePos !== null && (
<Portal>
<Badge
pos="absolute"
insetInlineStart={badgePos.x}
insetBlockStart={badgePos.y}
colorScheme="invokeYellow"
zIndex="docked"
>
{queueSize}
</Badge>
</Portal>
)}
</Box>
);

View File

@ -11,7 +11,7 @@ import { QueueActionsMenuButton } from './QueueActionsMenuButton';
const QueueControls = () => {
const isPrependEnabled = useFeatureStatus('prependQueue');
return (
<Flex w="full" position="relative" borderRadius="base" gap={2} pt={2} flexDir="column">
<Flex w="full" position="relative" borderRadius="base" gap={2} flexDir="column">
<ButtonGroup size="lg" isAttached={false}>
{isPrependEnabled && <QueueFrontButton />}
<InvokeQueueBackButton />

View File

@ -18,7 +18,7 @@ export const VerticalNavBar = memo(() => {
const customNavComponent = useStore($customNavComponent);
return (
<Flex flexDir="column" alignItems="center" pt={4} pb={2} gap={4}>
<Flex flexDir="column" alignItems="center" py={2} gap={4}>
<InvokeAILogoComponent />
<Flex gap={4} pt={6} h="full" flexDir="column">
<TabMountGate tab="generation">