Add custom Launchpad tab with dynamic icon based on active tab

Co-authored-by: kent <kent@invoke.ai>
This commit is contained in:
Cursor Agent
2025-06-30 22:16:02 +00:00
committed by psychedelicious
parent 7566d0d6c6
commit 19b6dc1c1f
6 changed files with 72 additions and 4 deletions

View File

@@ -0,0 +1,55 @@
import { Flex, Text } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import { useCallbackOnDragEnter } from 'common/hooks/useCallbackOnDragEnter';
import type { IDockviewPanelHeaderProps } from 'dockview';
import { selectActiveTab } from 'features/ui/store/uiSelectors';
import type { TabName } from 'features/ui/store/uiTypes';
import { memo, useCallback, useRef } from 'react';
import {
PiBoundingBoxBold,
PiCubeBold,
PiFlowArrowBold,
PiFrameCornersBold,
PiQueueBold,
PiTextAaBold,
} from 'react-icons/pi';
const TAB_ICONS: Record<TabName, React.ReactElement> = {
generate: <PiTextAaBold />,
canvas: <PiBoundingBoxBold />,
upscaling: <PiFrameCornersBold />,
workflows: <PiFlowArrowBold />,
models: <PiCubeBold />,
queue: <PiQueueBold />,
};
export const TabWithLaunchpadIcon = memo((props: IDockviewPanelHeaderProps) => {
const ref = useRef<HTMLDivElement>(null);
const activeTab = useAppSelector(selectActiveTab);
const setActive = useCallback(() => {
if (!props.api.isActive) {
props.api.setActive();
}
}, [props.api]);
useCallbackOnDragEnter(setActive, ref, 300);
// Show icon only for Launchpad panel
const isLaunchpadPanel = props.api.id === 'launchpad';
const currentTabIcon = TAB_ICONS[activeTab];
return (
<Flex ref={ref} alignItems="center" h="full">
{isLaunchpadPanel && currentTabIcon && (
<Flex alignItems="center" px={2}>
{currentTabIcon}
</Flex>
)}
<Text userSelect="none" px={isLaunchpadPanel ? 2 : 4}>
{props.api.title ?? props.api.id}
</Text>
</Flex>
);
});
TabWithLaunchpadIcon.displayName = 'TabWithLaunchpadIcon';

View File

@@ -33,16 +33,19 @@ import {
RIGHT_PANEL_ID,
RIGHT_PANEL_MIN_SIZE_PX,
SETTINGS_PANEL_ID,
TAB_WITH_LAUNCHPAD_ICON_ID,
TAB_WITH_PROGRESS_INDICATOR_ID,
VIEWER_PANEL_ID,
WORKSPACE_PANEL_ID,
} from './shared';
import { TabWithLaunchpadIcon } from './TabWithLaunchpadIcon';
import { TabWithoutCloseButtonAndWithProgressIndicator } from './TabWithoutCloseButtonAndWithProgressIndicator';
import { useResizeMainPanelOnFirstVisit } from './use-on-first-visible';
const tabComponents = {
[DEFAULT_TAB_ID]: TabWithoutCloseButton,
[TAB_WITH_PROGRESS_INDICATOR_ID]: TabWithoutCloseButtonAndWithProgressIndicator,
[TAB_WITH_LAUNCHPAD_ICON_ID]: TabWithLaunchpadIcon,
};
const centerPanelComponents: IDockviewReactProps['components'] = {
@@ -57,7 +60,7 @@ const initializeCenterPanelLayout = (api: DockviewApi) => {
id: LAUNCHPAD_PANEL_ID,
component: LAUNCHPAD_PANEL_ID,
title: 'Launchpad',
tabComponent: DEFAULT_TAB_ID,
tabComponent: TAB_WITH_LAUNCHPAD_ICON_ID,
});
api.addPanel({
id: WORKSPACE_PANEL_ID,

View File

@@ -29,15 +29,18 @@ import {
RIGHT_PANEL_ID,
RIGHT_PANEL_MIN_SIZE_PX,
SETTINGS_PANEL_ID,
TAB_WITH_LAUNCHPAD_ICON_ID,
TAB_WITH_PROGRESS_INDICATOR_ID,
VIEWER_PANEL_ID,
} from './shared';
import { TabWithLaunchpadIcon } from './TabWithLaunchpadIcon';
import { TabWithoutCloseButtonAndWithProgressIndicator } from './TabWithoutCloseButtonAndWithProgressIndicator';
import { useResizeMainPanelOnFirstVisit } from './use-on-first-visible';
const tabComponents = {
[DEFAULT_TAB_ID]: TabWithoutCloseButton,
[TAB_WITH_PROGRESS_INDICATOR_ID]: TabWithoutCloseButtonAndWithProgressIndicator,
[TAB_WITH_LAUNCHPAD_ICON_ID]: TabWithLaunchpadIcon,
};
const centerPanelComponents: IDockviewReactProps['components'] = {
@@ -51,7 +54,7 @@ const initializeCenterPanelLayout = (api: DockviewApi) => {
id: LAUNCHPAD_PANEL_ID,
component: LAUNCHPAD_PANEL_ID,
title: 'Launchpad',
tabComponent: DEFAULT_TAB_ID,
tabComponent: TAB_WITH_LAUNCHPAD_ICON_ID,
});
api.addPanel({
id: VIEWER_PANEL_ID,

View File

@@ -15,6 +15,7 @@ export const SETTINGS_PANEL_ID = 'settings';
export const DEFAULT_TAB_ID = 'default-tab';
export const TAB_WITH_PROGRESS_INDICATOR_ID = 'tab-with-progress-indicator';
export const TAB_WITH_LAUNCHPAD_ICON_ID = 'tab-with-launchpad-icon';
export const LEFT_PANEL_MIN_SIZE_PX = 420;
export const RIGHT_PANEL_MIN_SIZE_PX = 420;

View File

@@ -28,9 +28,11 @@ import {
RIGHT_PANEL_ID,
RIGHT_PANEL_MIN_SIZE_PX,
SETTINGS_PANEL_ID,
TAB_WITH_LAUNCHPAD_ICON_ID,
TAB_WITH_PROGRESS_INDICATOR_ID,
VIEWER_PANEL_ID,
} from './shared';
import { TabWithLaunchpadIcon } from './TabWithLaunchpadIcon';
import { TabWithoutCloseButtonAndWithProgressIndicator } from './TabWithoutCloseButtonAndWithProgressIndicator';
import { UpscalingTabLeftPanel } from './UpscalingTabLeftPanel';
import { useResizeMainPanelOnFirstVisit } from './use-on-first-visible';
@@ -38,6 +40,7 @@ import { useResizeMainPanelOnFirstVisit } from './use-on-first-visible';
const tabComponents = {
[DEFAULT_TAB_ID]: TabWithoutCloseButton,
[TAB_WITH_PROGRESS_INDICATOR_ID]: TabWithoutCloseButtonAndWithProgressIndicator,
[TAB_WITH_LAUNCHPAD_ICON_ID]: TabWithLaunchpadIcon,
};
const centerComponents: IDockviewReactProps['components'] = {
@@ -51,7 +54,7 @@ const initializeCenterLayout = (api: DockviewApi) => {
id: LAUNCHPAD_PANEL_ID,
component: LAUNCHPAD_PANEL_ID,
title: 'Launchpad',
tabComponent: DEFAULT_TAB_ID,
tabComponent: TAB_WITH_LAUNCHPAD_ICON_ID,
});
api.addPanel({
id: VIEWER_PANEL_ID,

View File

@@ -30,16 +30,19 @@ import {
RIGHT_PANEL_ID,
RIGHT_PANEL_MIN_SIZE_PX,
SETTINGS_PANEL_ID,
TAB_WITH_LAUNCHPAD_ICON_ID,
TAB_WITH_PROGRESS_INDICATOR_ID,
VIEWER_PANEL_ID,
WORKSPACE_PANEL_ID,
} from './shared';
import { TabWithLaunchpadIcon } from './TabWithLaunchpadIcon';
import { TabWithoutCloseButtonAndWithProgressIndicator } from './TabWithoutCloseButtonAndWithProgressIndicator';
import { useResizeMainPanelOnFirstVisit } from './use-on-first-visible';
const tabComponents = {
[DEFAULT_TAB_ID]: TabWithoutCloseButton,
[TAB_WITH_PROGRESS_INDICATOR_ID]: TabWithoutCloseButtonAndWithProgressIndicator,
[TAB_WITH_LAUNCHPAD_ICON_ID]: TabWithLaunchpadIcon,
};
const centerPanelComponents: IDockviewReactProps['components'] = {
@@ -54,7 +57,7 @@ const initializeCenterPanelLayout = (api: DockviewApi) => {
id: LAUNCHPAD_PANEL_ID,
component: LAUNCHPAD_PANEL_ID,
title: 'Launchpad',
tabComponent: DEFAULT_TAB_ID,
tabComponent: TAB_WITH_LAUNCHPAD_ICON_ID,
});
api.addPanel({
id: WORKSPACE_PANEL_ID,