mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-02-02 03:25:14 -05:00
feat: more updates to first run view
This commit is contained in:
@@ -2133,10 +2133,8 @@
|
||||
"toGetStartedLocal": "To get started, make sure to download or import models needed to run Invoke. Then, enter a prompt in the box and click <StrongComponent>Invoke</StrongComponent> to generate your first image. Select a prompt template to improve results. You can choose to save your images directly to the <StrongComponent>Gallery</StrongComponent> or edit them to the <StrongComponent>Canvas</StrongComponent>.",
|
||||
"toGetStarted": "To get started, enter a prompt in the box and click <StrongComponent>Invoke</StrongComponent> to generate your first image. Select a prompt template to improve results. You can choose to save your images directly to the <StrongComponent>Gallery</StrongComponent> or edit them to the <StrongComponent>Canvas</StrongComponent>.",
|
||||
"gettingStartedSeries": "Want more guidance? Check out our <LinkComponent>Getting Started Series</LinkComponent> for tips on unlocking the full potential of the Invoke Studio.",
|
||||
"lowVRAMMode": "For best performance, follow the <LinkComponent>Low VRAM mode guide</LinkComponent>.",
|
||||
"downloadStarterModels": "Download Starter Models",
|
||||
"importModels": "Import Models",
|
||||
"noModelsInstalled": "It looks like you don't have any models installed"
|
||||
"lowVRAMMode": "For best performance, follow our <LinkComponent>Low VRAM mode guide</LinkComponent>.",
|
||||
"noModelsInstalled": "It looks like you don't have any models installed! You can <DownloadStarterModelsButton>download a starter model bundle</DownloadStarterModelsButton> or <ImportModelsButton>import models</ImportModelsButton>."
|
||||
},
|
||||
"whatsNew": {
|
||||
"whatsNewInInvoke": "What's New in Invoke",
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
import { Button, Divider, Flex, Icon, Link, Spinner, Text } from '@invoke-ai/ui-library';
|
||||
import {
|
||||
Alert,
|
||||
AlertDescription,
|
||||
AlertIcon,
|
||||
Button,
|
||||
Divider,
|
||||
Flex,
|
||||
Icon,
|
||||
Link,
|
||||
Spinner,
|
||||
Text,
|
||||
} from '@invoke-ai/ui-library';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||
import { InvokeLogoIcon } from 'common/components/InvokeLogoIcon';
|
||||
@@ -13,21 +24,112 @@ import { Trans, useTranslation } from 'react-i18next';
|
||||
import { PiArrowSquareOutBold, PiImageBold } from 'react-icons/pi';
|
||||
import { useMainModels } from 'services/api/hooks/modelsByType';
|
||||
|
||||
const ExternalLink = (props: PropsWithChildren<{ href: string }>) => {
|
||||
return (
|
||||
<Link isExternal display="inline-flex" alignItems="center" href={props.href} color="base.50">
|
||||
{props.children}
|
||||
<Icon display="inline" verticalAlign="middle" marginInlineStart={2} as={PiArrowSquareOutBold} />
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export const NoContentForViewer = memo(() => {
|
||||
const hasImages = useHasImages();
|
||||
const [mainModels, { data }] = useMainModels();
|
||||
const isLocal = useAppSelector(selectIsLocal);
|
||||
const isEnabled = useFeatureStatus('starterModels');
|
||||
const { t } = useTranslation();
|
||||
|
||||
const showStarterBundles = useMemo(() => {
|
||||
return isEnabled && data && mainModels.length === 0;
|
||||
}, [mainModels.length, data, isEnabled]);
|
||||
|
||||
if (hasImages === LOADING_SYMBOL) {
|
||||
// Blank bg w/ a spinner. The new user experience components below have an invoke logo, but it's not centered.
|
||||
// If we show the logo while loading, there is an awkward layout shift where the invoke logo moves a bit. Less
|
||||
// jarring to show a blank bg with a spinner - it will only be shown for a moment as we do the initial images
|
||||
// fetching.
|
||||
return <LoadingSpinner />;
|
||||
}
|
||||
|
||||
if (hasImages) {
|
||||
return <IAINoContentFallback icon={PiImageBold} label={t('gallery.noImageSelected')} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex flexDir="column" gap={8} alignItems="center" textAlign="center" maxW="600px">
|
||||
<InvokeLogoIcon w={32} h={32} />
|
||||
<Flex flexDir="column" gap={4} alignItems="center" textAlign="center">
|
||||
{isLocal ? <GetStartedLocal /> : <GetStartedCommercial />}
|
||||
{showStarterBundles && <StarterBundlesCallout />}
|
||||
<Divider />
|
||||
<GettingStartedVideosCallout />
|
||||
{isLocal && <LowVRAMAlert />}
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
});
|
||||
|
||||
NoContentForViewer.displayName = 'NoContentForViewer';
|
||||
|
||||
const LoadingSpinner = () => {
|
||||
return (
|
||||
<Flex position="relative" width="full" height="full" alignItems="center" justifyContent="center">
|
||||
<Spinner label="Loading" color="grey" position="absolute" size="sm" width={8} height={8} right={4} bottom={4} />
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
const ExternalLink = (props: PropsWithChildren<{ href: string }>) => {
|
||||
return (
|
||||
<Button
|
||||
as={Link}
|
||||
variant="link"
|
||||
isExternal
|
||||
display="inline-flex"
|
||||
alignItems="center"
|
||||
href={props.href}
|
||||
color="base.50"
|
||||
>
|
||||
{props.children}
|
||||
<Icon display="inline" verticalAlign="middle" marginInlineStart={2} as={PiArrowSquareOutBold} />
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
const InlineButton = (props: PropsWithChildren<{ onClick: () => void }>) => {
|
||||
return (
|
||||
<Button variant="link" size="md" onClick={props.onClick} color="base.50">
|
||||
{props.children}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
const StrongComponent = <Text as="span" color="base.50" fontSize="md" />;
|
||||
|
||||
const GetStartedLocal = () => {
|
||||
return (
|
||||
<Text fontSize="md" color="base.200">
|
||||
<Trans i18nKey="newUserExperience.toGetStartedLocal" components={{ StrongComponent }} />
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
const GetStartedCommercial = () => {
|
||||
return (
|
||||
<Text fontSize="md" color="base.200">
|
||||
<Trans i18nKey="newUserExperience.toGetStarted" components={{ StrongComponent }} />
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
const GettingStartedVideosCallout = () => {
|
||||
return (
|
||||
<Text fontSize="md" color="base.200">
|
||||
<Trans
|
||||
i18nKey="newUserExperience.gettingStartedSeries"
|
||||
components={{
|
||||
LinkComponent: (
|
||||
<ExternalLink href="https://www.youtube.com/playlist?list=PLvWK1Kc8iXGrQy8r9TYg6QdUuJ5MMx-ZO" />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
const StarterBundlesCallout = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const handleClickDownloadStarterModels = useCallback(() => {
|
||||
@@ -40,94 +142,31 @@ export const NoContentForViewer = memo(() => {
|
||||
$installModelsTab.set(0);
|
||||
}, [dispatch]);
|
||||
|
||||
const showStarterBundles = useMemo(() => {
|
||||
return isEnabled && data && mainModels.length === 0;
|
||||
}, [mainModels.length, data, isEnabled]);
|
||||
|
||||
if (hasImages === LOADING_SYMBOL) {
|
||||
return (
|
||||
// Blank bg w/ a spinner. The new user experience components below have an invoke logo, but it's not centered.
|
||||
// If we show the logo while loading, there is an awkward layout shift where the invoke logo moves a bit. Less
|
||||
// jarring to show a blank bg with a spinner - it will only be shown for a moment as we do the initial images
|
||||
// fetching.
|
||||
<Flex position="relative" width="full" height="full" alignItems="center" justifyContent="center">
|
||||
<Spinner label="Loading" color="grey" position="absolute" size="sm" width={8} height={8} right={4} bottom={4} />
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
if (hasImages) {
|
||||
return <IAINoContentFallback icon={PiImageBold} label={t('gallery.noImageSelected')} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex flexDir="column" gap={8} alignItems="center" textAlign="center" maxW="600px">
|
||||
<InvokeLogoIcon w={32} h={32} />
|
||||
<Flex flexDir="column" gap={8} alignItems="center" textAlign="center">
|
||||
{isLocal ? (
|
||||
<>
|
||||
<Text fontSize="md" color="base.200">
|
||||
<Trans
|
||||
i18nKey="newUserExperience.toGetStartedLocal"
|
||||
components={{
|
||||
StrongComponent: <Text as="span" color="white" fontSize="md" fontWeight="semibold" />,
|
||||
}}
|
||||
/>
|
||||
</Text>
|
||||
<Text fontSize="md" color="base.200">
|
||||
<Trans
|
||||
i18nKey="newUserExperience.lowVRAMMode"
|
||||
components={{
|
||||
LinkComponent: <ExternalLink href="https://invoke-ai.github.io/InvokeAI/features/low-vram/" />,
|
||||
}}
|
||||
/>
|
||||
</Text>
|
||||
</>
|
||||
) : (
|
||||
<Text fontSize="md" color="base.200">
|
||||
<Trans
|
||||
i18nKey="newUserExperience.toGetStarted"
|
||||
components={{
|
||||
StrongComponent: <Text as="span" color="white" fontSize="md" fontWeight="semibold" />,
|
||||
}}
|
||||
/>
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{showStarterBundles && (
|
||||
<Flex flexDir="column" gap={2} alignItems="center">
|
||||
<Text fontSize="md" color="base.200">
|
||||
{t('newUserExperience.noModelsInstalled')}
|
||||
</Text>
|
||||
<Flex gap={3} alignItems="center">
|
||||
<Button size="sm" onClick={handleClickDownloadStarterModels}>
|
||||
{t('newUserExperience.downloadStarterModels')}
|
||||
</Button>
|
||||
<Text fontSize="sm" color="base.200">
|
||||
{t('common.or')}
|
||||
</Text>
|
||||
<Button size="sm" onClick={handleClickImportModels}>
|
||||
{t('newUserExperience.importModels')}
|
||||
</Button>
|
||||
</Flex>
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
<Divider />
|
||||
|
||||
<Text fontSize="md" color="base.200">
|
||||
<Trans
|
||||
i18nKey="newUserExperience.gettingStartedSeries"
|
||||
components={{
|
||||
LinkComponent: (
|
||||
<ExternalLink href="https://www.youtube.com/playlist?list=PLvWK1Kc8iXGrQy8r9TYg6QdUuJ5MMx-ZO" />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Text>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Text fontSize="md" color="base.200">
|
||||
<Trans
|
||||
i18nKey="newUserExperience.noModelsInstalled"
|
||||
components={{
|
||||
DownloadStarterModelsButton: <InlineButton onClick={handleClickDownloadStarterModels} />,
|
||||
ImportModelsButton: <InlineButton onClick={handleClickImportModels} />,
|
||||
}}
|
||||
/>
|
||||
</Text>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
NoContentForViewer.displayName = 'NoContentForViewer';
|
||||
const LowVRAMAlert = () => {
|
||||
return (
|
||||
<Alert status="warning" borderRadius="base" fontSize="md" shadow="md" w="fit-content">
|
||||
<AlertIcon />
|
||||
<AlertDescription>
|
||||
<Trans
|
||||
i18nKey="newUserExperience.lowVRAMMode"
|
||||
components={{
|
||||
LinkComponent: <ExternalLink href="https://invoke-ai.github.io/InvokeAI/features/low-vram/" />,
|
||||
}}
|
||||
/>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user