feat: Remove Header

Remove header and incorporate everything else into the side bar and other areas
This commit is contained in:
blessedcoolant 2024-01-04 00:17:57 +05:30 committed by Kent Keirsey
parent 4ce39a5974
commit 2250bca8d9
9 changed files with 165 additions and 175 deletions

View File

@ -156,6 +156,7 @@
"save": "Save", "save": "Save",
"saveAs": "Save As", "saveAs": "Save As",
"settingsLabel": "Settings", "settingsLabel": "Settings",
"preferencesLabel": "Preferences",
"simple": "Simple", "simple": "Simple",
"somethingWentWrong": "Something went wrong", "somethingWentWrong": "Something went wrong",
"statusConnected": "Connected", "statusConnected": "Connected",

View File

@ -1,9 +1,7 @@
import { Flex, Grid } from '@chakra-ui/react'; import { Flex, Grid } from '@chakra-ui/react';
import { useStore } from '@nanostores/react';
import { useSocketIO } from 'app/hooks/useSocketIO'; import { useSocketIO } from 'app/hooks/useSocketIO';
import { useLogger } from 'app/logging/useLogger'; import { useLogger } from 'app/logging/useLogger';
import { appStarted } from 'app/store/middleware/listenerMiddleware/listeners/appStarted'; import { appStarted } from 'app/store/middleware/listenerMiddleware/listeners/appStarted';
import { $headerComponent } from 'app/store/nanostores/headerComponent';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import type { PartialAppConfig } from 'app/types/invokeai'; import type { PartialAppConfig } from 'app/types/invokeai';
import ImageUploader from 'common/components/ImageUploader'; import ImageUploader from 'common/components/ImageUploader';
@ -13,7 +11,6 @@ import { useGlobalModifiersInit } from 'common/hooks/useGlobalModifiers';
import ChangeBoardModal from 'features/changeBoardModal/components/ChangeBoardModal'; import ChangeBoardModal from 'features/changeBoardModal/components/ChangeBoardModal';
import DeleteImageModal from 'features/deleteImageModal/components/DeleteImageModal'; import DeleteImageModal from 'features/deleteImageModal/components/DeleteImageModal';
import { DynamicPromptsModal } from 'features/dynamicPrompts/components/DynamicPromptsPreviewModal'; import { DynamicPromptsModal } from 'features/dynamicPrompts/components/DynamicPromptsPreviewModal';
import SiteHeader from 'features/system/components/SiteHeader';
import { configChanged } from 'features/system/store/configSlice'; import { configChanged } from 'features/system/store/configSlice';
import { languageSelector } from 'features/system/store/systemSelectors'; import { languageSelector } from 'features/system/store/systemSelectors';
import InvokeTabs from 'features/ui/components/InvokeTabs'; import InvokeTabs from 'features/ui/components/InvokeTabs';
@ -68,8 +65,6 @@ const App = ({ config = DEFAULT_CONFIG, selectedImage }: Props) => {
dispatch(appStarted()); dispatch(appStarted());
}, [dispatch]); }, [dispatch]);
const headerComponent = useStore($headerComponent);
return ( return (
<ErrorBoundary <ErrorBoundary
onReset={handleReset} onReset={handleReset}
@ -77,12 +72,9 @@ const App = ({ config = DEFAULT_CONFIG, selectedImage }: Props) => {
> >
<Grid w="100vw" h="100vh" position="relative" overflow="hidden"> <Grid w="100vw" h="100vh" position="relative" overflow="hidden">
<ImageUploader> <ImageUploader>
<Grid p={4} gridAutoRows="min-content auto" w="full" h="full"> <Flex gap={4} p={4} w="full" h="full">
{headerComponent || <SiteHeader />} <InvokeTabs />
<Flex gap={4} w="full" h="full"> </Flex>
<InvokeTabs />
</Flex>
</Grid>
</ImageUploader> </ImageUploader>
</Grid> </Grid>
<DeleteImageModal /> <DeleteImageModal />

View File

@ -3,6 +3,7 @@ import { InvButtonGroup } from 'common/components/InvButtonGroup/InvButtonGroup'
import ClearQueueButton from 'features/queue/components/ClearQueueButton'; import ClearQueueButton from 'features/queue/components/ClearQueueButton';
import QueueFrontButton from 'features/queue/components/QueueFrontButton'; import QueueFrontButton from 'features/queue/components/QueueFrontButton';
import ProgressBar from 'features/system/components/ProgressBar'; import ProgressBar from 'features/system/components/ProgressBar';
import StatusIndicator from 'features/system/components/StatusIndicator';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus'; import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { memo } from 'react'; import { memo } from 'react';
@ -29,8 +30,9 @@ const QueueControls = () => {
{isPauseEnabled && <PauseProcessorButton asIconButton />} */} {isPauseEnabled && <PauseProcessorButton asIconButton />} */}
<ClearQueueButton asIconButton /> <ClearQueueButton asIconButton />
</InvButtonGroup> </InvButtonGroup>
<Flex h={2} w="full"> <Flex h={5} w="full" alignItems="center">
<ProgressBar /> <StatusIndicator />
<ProgressBar height={2} />
</Flex> </Flex>
</Flex> </Flex>
); );

View File

@ -2,6 +2,7 @@
import { Flex, Image } from '@chakra-ui/react'; import { Flex, Image } from '@chakra-ui/react';
import InvokeLogoYellow from 'assets/images/invoke-key-ylw-sm.svg'; import InvokeLogoYellow from 'assets/images/invoke-key-ylw-sm.svg';
import { InvText } from 'common/components/InvText/wrapper'; import { InvText } from 'common/components/InvText/wrapper';
import { InvTooltip } from 'common/components/InvTooltip/InvTooltip';
import type { AnimationProps } from 'framer-motion'; import type { AnimationProps } from 'framer-motion';
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
import { memo, useRef } from 'react'; import { memo, useRef } from 'react';
@ -14,8 +15,29 @@ const InvokeAILogoComponent = () => {
const isHovered = useHoverDirty(ref); const isHovered = useHoverDirty(ref);
return ( return (
<Flex alignItems="center" gap={5} ps={1} ref={ref}> <InvTooltip
placement="right"
label={
<Flex gap={3} alignItems="center">
<AnimatePresence>
{isHovered && appVersion && (
<motion.div
key="statusText"
initial={initial}
animate={animate}
exit={exit}
>
<InvText fontWeight="semibold" marginTop={1} color="base.900">
v{appVersion.version}
</InvText>
</motion.div>
)}
</AnimatePresence>
</Flex>
}
>
<Image <Image
ref={ref}
src={InvokeLogoYellow} src={InvokeLogoYellow}
alt="invoke-logo" alt="invoke-logo"
w="24px" w="24px"
@ -24,23 +46,7 @@ const InvokeAILogoComponent = () => {
minH="24px" minH="24px"
userSelect="none" userSelect="none"
/> />
<Flex gap={3} alignItems="center"> </InvTooltip>
<AnimatePresence>
{isHovered && appVersion && (
<motion.div
key="statusText"
initial={initial}
animate={animate}
exit={exit}
>
<InvText fontWeight="semibold" marginTop={1} color="base.300">
v{appVersion.version}
</InvText>
</motion.div>
)}
</AnimatePresence>
</Flex>
</Flex>
); );
}; };

View File

@ -16,7 +16,12 @@ const progressBarSelector = createMemoizedSelector(
} }
); );
const ProgressBar = () => { type ProgressBarProps = {
height?: number | string;
};
const ProgressBar = (props: ProgressBarProps) => {
const { height = 'full' } = props;
const { t } = useTranslation(); const { t } = useTranslation();
const { data: queueStatus } = useGetQueueStatusQuery(); const { data: queueStatus } = useGetQueueStatusQuery();
const { hasSteps, value, isConnected } = useAppSelector(progressBarSelector); const { hasSteps, value, isConnected } = useAppSelector(progressBarSelector);
@ -29,7 +34,7 @@ const ProgressBar = () => {
isIndeterminate={ isIndeterminate={
isConnected && Boolean(queueStatus?.queue.in_progress) && !hasSteps isConnected && Boolean(queueStatus?.queue.in_progress) && !hasSteps
} }
h="full" h={height}
w="full" w="full"
colorScheme="invokeYellow" colorScheme="invokeYellow"
/> />

View File

@ -0,0 +1,101 @@
import { useDisclosure } from '@chakra-ui/react';
import { InvIconButton } from 'common/components/InvIconButton/InvIconButton';
import { InvMenuItem } from 'common/components/InvMenu/InvMenuItem';
import { InvMenuList } from 'common/components/InvMenu/InvMenuList';
import {
InvMenu,
InvMenuButton,
InvMenuGroup,
} from 'common/components/InvMenu/wrapper';
import { InvTooltip } from 'common/components/InvTooltip/InvTooltip';
import { useGlobalMenuCloseTrigger } from 'common/hooks/useGlobalMenuCloseTrigger';
import HotkeysModal from 'features/system/components/HotkeysModal/HotkeysModal';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import {
FaBars,
FaBug,
FaCog,
FaDiscord,
FaGithub,
FaKeyboard,
} from 'react-icons/fa';
import SettingsModal from './SettingsModal';
const SettingsMenu = () => {
const { t } = useTranslation();
const { isOpen, onOpen, onClose } = useDisclosure();
useGlobalMenuCloseTrigger(onClose);
const isBugLinkEnabled = useFeatureStatus('bugLink').isFeatureEnabled;
const isDiscordLinkEnabled = useFeatureStatus('discordLink').isFeatureEnabled;
const isGithubLinkEnabled = useFeatureStatus('githubLink').isFeatureEnabled;
const githubLink = 'http://github.com/invoke-ai/InvokeAI';
const discordLink = 'https://discord.gg/ZmtBAhwWhy';
return (
<InvMenu isOpen={isOpen} onOpen={onOpen} onClose={onClose}>
<InvTooltip label={t('common.preferencesLabel')} placement="right">
<InvMenuButton
as={InvIconButton}
variant="link"
aria-label={t('accessibility.menu')}
icon={<FaCog fontSize={20} />}
boxSize={8}
/>
</InvTooltip>
<InvMenuList>
<InvMenuGroup title={t('common.communityLabel')}>
{isGithubLinkEnabled && (
<InvMenuItem
as="a"
href={githubLink}
target="_blank"
icon={<FaGithub />}
>
{t('common.githubLabel')}
</InvMenuItem>
)}
{isBugLinkEnabled && (
<InvMenuItem
as="a"
href={`${githubLink}/issues`}
target="_blank"
icon={<FaBug />}
>
{t('common.reportBugLabel')}
</InvMenuItem>
)}
{isDiscordLinkEnabled && (
<InvMenuItem
as="a"
href={discordLink}
target="_blank"
icon={<FaDiscord />}
>
{t('common.discordLabel')}
</InvMenuItem>
)}
</InvMenuGroup>
<InvMenuGroup title={t('common.settingsLabel')}>
<HotkeysModal>
<InvMenuItem as="button" icon={<FaKeyboard />}>
{t('common.hotkeysLabel')}
</InvMenuItem>
</HotkeysModal>
<SettingsModal>
<InvMenuItem as="button" icon={<FaBars />}>
{t('common.settingsLabel')}
</InvMenuItem>
</SettingsModal>
</InvMenuGroup>
</InvMenuList>
</InvMenu>
);
};
export default memo(SettingsMenu);

View File

@ -1,105 +0,0 @@
import { Flex, Spacer, useDisclosure } from '@chakra-ui/react';
import { InvIconButton } from 'common/components/InvIconButton/InvIconButton';
import { InvMenuItem } from 'common/components/InvMenu/InvMenuItem';
import { InvMenuList } from 'common/components/InvMenu/InvMenuList';
import {
InvMenu,
InvMenuButton,
InvMenuGroup,
} from 'common/components/InvMenu/wrapper';
import { useGlobalMenuCloseTrigger } from 'common/hooks/useGlobalMenuCloseTrigger';
import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import {
FaBars,
FaBug,
FaCog,
FaDiscord,
FaGithub,
FaKeyboard,
} from 'react-icons/fa';
import HotkeysModal from './HotkeysModal/HotkeysModal';
import InvokeAILogoComponent from './InvokeAILogoComponent';
import SettingsModal from './SettingsModal/SettingsModal';
import StatusIndicator from './StatusIndicator';
const SiteHeader = () => {
const { t } = useTranslation();
const { isOpen, onOpen, onClose } = useDisclosure();
useGlobalMenuCloseTrigger(onClose);
const isBugLinkEnabled = useFeatureStatus('bugLink').isFeatureEnabled;
const isDiscordLinkEnabled = useFeatureStatus('discordLink').isFeatureEnabled;
const isGithubLinkEnabled = useFeatureStatus('githubLink').isFeatureEnabled;
const githubLink = 'http://github.com/invoke-ai/InvokeAI';
const discordLink = 'https://discord.gg/ZmtBAhwWhy';
return (
<Flex gap={2} alignItems="center">
<InvokeAILogoComponent />
<Spacer />
<StatusIndicator />
<InvMenu isOpen={isOpen} onOpen={onOpen} onClose={onClose}>
<InvMenuButton
as={InvIconButton}
variant="link"
aria-label={t('accessibility.menu')}
icon={<FaBars />}
boxSize={8}
/>
<InvMenuList>
<InvMenuGroup title={t('common.communityLabel')}>
{isGithubLinkEnabled && (
<InvMenuItem
as="a"
href={githubLink}
target="_blank"
icon={<FaGithub />}
>
{t('common.githubLabel')}
</InvMenuItem>
)}
{isBugLinkEnabled && (
<InvMenuItem
as="a"
href={`${githubLink}/issues`}
target="_blank"
icon={<FaBug />}
>
{t('common.reportBugLabel')}
</InvMenuItem>
)}
{isDiscordLinkEnabled && (
<InvMenuItem
as="a"
href={discordLink}
target="_blank"
icon={<FaDiscord />}
>
{t('common.discordLabel')}
</InvMenuItem>
)}
</InvMenuGroup>
<InvMenuGroup title={t('common.settingsLabel')}>
<HotkeysModal>
<InvMenuItem as="button" icon={<FaKeyboard />}>
{t('common.hotkeysLabel')}
</InvMenuItem>
</HotkeysModal>
<SettingsModal>
<InvMenuItem as="button" icon={<FaCog />}>
{t('common.settingsLabel')}
</InvMenuItem>
</SettingsModal>
</InvMenuGroup>
</InvMenuList>
</InvMenu>
</Flex>
);
};
export default memo(SiteHeader);

View File

@ -3,9 +3,8 @@ import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store'; import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { InvText } from 'common/components/InvText/wrapper'; import { InvText } from 'common/components/InvText/wrapper';
import { InvTooltip } from 'common/components/InvTooltip/InvTooltip';
import { STATUS_TRANSLATION_KEYS } from 'features/system/store/types'; import { STATUS_TRANSLATION_KEYS } from 'features/system/store/types';
import type { AnimationProps } from 'framer-motion';
import { AnimatePresence, motion } from 'framer-motion';
import type { ResourceKey } from 'i18next'; import type { ResourceKey } from 'i18next';
import { memo, useMemo, useRef } from 'react'; import { memo, useMemo, useRef } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -54,15 +53,13 @@ const StatusIndicator = () => {
const isHovered = useHoverDirty(ref); const isHovered = useHoverDirty(ref);
return ( return (
<Flex ref={ref} h="full" px={2} alignItems="center" gap={5}> <Flex ref={ref} alignItems="center" p={2} pl={0}>
<AnimatePresence> <InvTooltip
{isHovered && ( left={10}
<motion.div bottom={-24}
key="statusText" background="base.800"
initial={initial} label={
animate={animate} isHovered && (
exit={exit}
>
<InvText <InvText
fontSize="sm" fontSize="sm"
fontWeight="semibold" fontWeight="semibold"
@ -72,24 +69,13 @@ const StatusIndicator = () => {
> >
{t(statusTranslationKey as ResourceKey)} {t(statusTranslationKey as ResourceKey)}
</InvText> </InvText>
</motion.div> )
)} }
</AnimatePresence> >
<Icon as={FaCircle} boxSize="0.5rem" color={COLOR_MAP[statusColor]} /> <Icon as={FaCircle} boxSize="0.6rem" color={COLOR_MAP[statusColor]} />
</InvTooltip>
</Flex> </Flex>
); );
}; };
export default memo(StatusIndicator); export default memo(StatusIndicator);
const initial: AnimationProps['initial'] = {
opacity: 0,
};
const animate: AnimationProps['animate'] = {
opacity: 1,
transition: { duration: 0.1 },
};
const exit: AnimationProps['exit'] = {
opacity: 0,
transition: { delay: 0.8 },
};

View File

@ -1,4 +1,4 @@
import { Spacer } from '@chakra-ui/react'; import { Flex, Spacer } from '@chakra-ui/react';
import { createMemoizedSelector } from 'app/store/createMemoizedSelector'; import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
import { stateSelector } from 'app/store/store'; import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
@ -13,6 +13,8 @@ import {
import { InvTooltip } from 'common/components/InvTooltip/InvTooltip'; import { InvTooltip } from 'common/components/InvTooltip/InvTooltip';
import ImageGalleryContent from 'features/gallery/components/ImageGalleryContent'; import ImageGalleryContent from 'features/gallery/components/ImageGalleryContent';
import NodeEditorPanelGroup from 'features/nodes/components/sidePanel/NodeEditorPanelGroup'; import NodeEditorPanelGroup from 'features/nodes/components/sidePanel/NodeEditorPanelGroup';
import InvokeAILogoComponent from 'features/system/components/InvokeAILogoComponent';
import SettingsMenu from 'features/system/components/SettingsModal/SettingsMenu';
import type { UsePanelOptions } from 'features/ui/hooks/usePanel'; import type { UsePanelOptions } from 'features/ui/hooks/usePanel';
import { usePanel } from 'features/ui/hooks/usePanel'; import { usePanel } from 'features/ui/hooks/usePanel';
import { usePanelStorage } from 'features/ui/hooks/usePanelStorage'; import { usePanelStorage } from 'features/ui/hooks/usePanelStorage';
@ -249,10 +251,14 @@ const InvokeTabs = () => {
gap={4} gap={4}
isLazy isLazy
> >
<InvTabList gap={4} pt={4} flexDir="column"> <Flex flexDir="column" alignItems="center" pt={2}>
{tabs} <InvokeAILogoComponent />
<Spacer /> <InvTabList gap={4} pt={8} pb={4} h="full" flexDir="column">
</InvTabList> {tabs}
<Spacer />
<SettingsMenu />
</InvTabList>
</Flex>
<PanelGroup <PanelGroup
ref={panelGroupRef} ref={panelGroupRef}
id={appPanelGroupId} id={appPanelGroupId}
@ -272,7 +278,6 @@ const InvokeTabs = () => {
onCollapse={onCollapseOptionsPanel} onCollapse={onCollapseOptionsPanel}
onExpand={onExpandOptionsPanel} onExpand={onExpandOptionsPanel}
collapsible collapsible
style={paddingTop4}
> >
{activeTabName === 'nodes' ? ( {activeTabName === 'nodes' ? (
<NodeEditorPanelGroup /> <NodeEditorPanelGroup />
@ -287,7 +292,7 @@ const InvokeTabs = () => {
/> />
</> </>
)} )}
<Panel id="main-panel" order={1} minSize={20} style={paddingTop4}> <Panel id="main-panel" order={1} minSize={20}>
<InvTabPanels w="full" h="full"> <InvTabPanels w="full" h="full">
{tabPanels} {tabPanels}
</InvTabPanels> </InvTabPanels>
@ -308,7 +313,6 @@ const InvokeTabs = () => {
onCollapse={onCollapseGalleryPanel} onCollapse={onCollapseGalleryPanel}
onExpand={onExpandGalleryPanel} onExpand={onExpandGalleryPanel}
collapsible collapsible
style={paddingTop4}
> >
<ImageGalleryContent /> <ImageGalleryContent />
</Panel> </Panel>
@ -320,5 +324,3 @@ const InvokeTabs = () => {
}; };
export default memo(InvokeTabs); export default memo(InvokeTabs);
const paddingTop4: CSSProperties = { paddingTop: '8px' };