mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
Add support for video playlists in support videos modal
Co-authored-by: kent <kent@invoke.ai>
This commit is contained in:
committed by
psychedelicious
parent
e81a115169
commit
9ff6ada15b
@@ -2564,11 +2564,26 @@
|
|||||||
},
|
},
|
||||||
"supportVideos": {
|
"supportVideos": {
|
||||||
"supportVideos": "Support Videos",
|
"supportVideos": "Support Videos",
|
||||||
|
"supportPlaylists": "Video Playlists",
|
||||||
"gettingStarted": "Getting Started",
|
"gettingStarted": "Getting Started",
|
||||||
"controlCanvas": "Control Canvas",
|
"controlCanvas": "Control Canvas",
|
||||||
"watch": "Watch",
|
"watch": "Watch",
|
||||||
|
"watchPlaylist": "Watch Playlist",
|
||||||
|
"videoCount": "{{count}} videos",
|
||||||
|
"videoCount_one": "{{count}} video",
|
||||||
|
"videoCount_other": "{{count}} videos",
|
||||||
"studioSessionsDesc1": "Check out the <StudioSessionsPlaylistLink /> for Invoke deep dives.",
|
"studioSessionsDesc1": "Check out the <StudioSessionsPlaylistLink /> for Invoke deep dives.",
|
||||||
"studioSessionsDesc2": "Join our <DiscordLink /> to participate in the live sessions and ask questions. Sessions are uploaded to the playlist the following week.",
|
"studioSessionsDesc2": "Join our <DiscordLink /> to participate in the live sessions and ask questions. Sessions are uploaded to the playlist the following week.",
|
||||||
|
"playlists": {
|
||||||
|
"gettingStarted": {
|
||||||
|
"title": "Getting Started with Invoke",
|
||||||
|
"description": "Complete video series covering everything you need to know to get started with Invoke, from creating your first image to advanced techniques."
|
||||||
|
},
|
||||||
|
"studioSessions": {
|
||||||
|
"title": "Studio Sessions",
|
||||||
|
"description": "Deep dive sessions exploring advanced Invoke features, creative workflows, and community discussions."
|
||||||
|
}
|
||||||
|
},
|
||||||
"videos": {
|
"videos": {
|
||||||
"creatingYourFirstImage": {
|
"creatingYourFirstImage": {
|
||||||
"title": "Creating Your First Image",
|
"title": "Creating Your First Image",
|
||||||
|
|||||||
@@ -55,9 +55,7 @@ export const ModelInstallQueue = memo(() => {
|
|||||||
<Box layerStyle="first" p={3} borderRadius="base" w="full" h="full">
|
<Box layerStyle="first" p={3} borderRadius="base" w="full" h="full">
|
||||||
<ScrollableContent>
|
<ScrollableContent>
|
||||||
<Flex flexDir="column-reverse" gap="2" w="full">
|
<Flex flexDir="column-reverse" gap="2" w="full">
|
||||||
{data?.map((model) => (
|
{data?.map((model) => <ModelInstallQueueItem key={model.id} installJob={model} />)}
|
||||||
<ModelInstallQueueItem key={model.id} installJob={model} />
|
|
||||||
))}
|
|
||||||
</Flex>
|
</Flex>
|
||||||
</ScrollableContent>
|
</ScrollableContent>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { ExternalLink, Flex, Spacer, Text } from '@invoke-ai/ui-library';
|
||||||
|
import { useAppDispatch } from 'app/store/storeHooks';
|
||||||
|
import type { PlaylistData } from 'features/system/components/VideosModal/data';
|
||||||
|
import { videoModalLinkClicked } from 'features/system/store/actions';
|
||||||
|
import { memo, useCallback } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
export const PlaylistCard = memo(({ playlist }: { playlist: PlaylistData }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const { tKey, link, videoCount } = playlist;
|
||||||
|
const handleLinkClick = useCallback(() => {
|
||||||
|
dispatch(videoModalLinkClicked(t(`supportVideos.playlists.${tKey}.title`)));
|
||||||
|
}, [dispatch, t, tKey]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex flexDir="column" gap={1}>
|
||||||
|
<Flex alignItems="center" gap={2}>
|
||||||
|
<Text fontSize="md" fontWeight="semibold">
|
||||||
|
{t(`supportVideos.playlists.${tKey}.title`)}
|
||||||
|
</Text>
|
||||||
|
<Spacer />
|
||||||
|
<Text variant="subtext">{t('supportVideos.videoCount', { count: videoCount })}</Text>
|
||||||
|
<ExternalLink fontSize="sm" href={link} label={t('supportVideos.watchPlaylist')} onClick={handleLinkClick} />
|
||||||
|
</Flex>
|
||||||
|
<Text fontSize="md" variant="subtext">
|
||||||
|
{t(`supportVideos.playlists.${tKey}.description`)}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
PlaylistCard.displayName = 'PlaylistCard';
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { Divider } from '@invoke-ai/ui-library';
|
||||||
|
import { StickyScrollable } from 'features/system/components/StickyScrollable';
|
||||||
|
import type { PlaylistData } from 'features/system/components/VideosModal/data';
|
||||||
|
import { PlaylistCard } from 'features/system/components/VideosModal/PlaylistCard';
|
||||||
|
import { Fragment, memo } from 'react';
|
||||||
|
|
||||||
|
export const PlaylistCardList = memo(({ category, playlists }: { category: string; playlists: PlaylistData[] }) => {
|
||||||
|
return (
|
||||||
|
<StickyScrollable title={category}>
|
||||||
|
{playlists.map((playlist, i) => (
|
||||||
|
<Fragment key={`${playlist.tKey}-${i}`}>
|
||||||
|
<PlaylistCard playlist={playlist} />
|
||||||
|
{i < playlists.length - 1 && <Divider />}
|
||||||
|
</Fragment>
|
||||||
|
))}
|
||||||
|
</StickyScrollable>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
PlaylistCardList.displayName = 'PlaylistCardList';
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Divider } from '@invoke-ai/ui-library';
|
import { Divider } from '@invoke-ai/ui-library';
|
||||||
import { StickyScrollable } from 'features/system/components/StickyScrollable';
|
import { StickyScrollable } from 'features/system/components/StickyScrollable';
|
||||||
import { gettingStartedVideos, type VideoData } from 'features/system/components/VideosModal/data';
|
import type { VideoData } from 'features/system/components/VideosModal/data';
|
||||||
import { VideoCard } from 'features/system/components/VideosModal/VideoCard';
|
import { VideoCard } from 'features/system/components/VideosModal/VideoCard';
|
||||||
import { Fragment, memo } from 'react';
|
import { Fragment, memo } from 'react';
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ export const VideoCardList = memo(({ category, videos }: { category: string; vid
|
|||||||
{videos.map((video, i) => (
|
{videos.map((video, i) => (
|
||||||
<Fragment key={`${video.tKey}-${i}`}>
|
<Fragment key={`${video.tKey}-${i}`}>
|
||||||
<VideoCard video={video} />
|
<VideoCard video={video} />
|
||||||
{i < gettingStartedVideos.length - 1 && <Divider />}
|
{i < videos.length - 1 && <Divider />}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
))}
|
))}
|
||||||
</StickyScrollable>
|
</StickyScrollable>
|
||||||
|
|||||||
@@ -15,9 +15,10 @@ import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableCon
|
|||||||
import { buildUseDisclosure } from 'common/hooks/useBoolean';
|
import { buildUseDisclosure } from 'common/hooks/useBoolean';
|
||||||
import {
|
import {
|
||||||
controlCanvasVideos,
|
controlCanvasVideos,
|
||||||
gettingStartedVideos,
|
|
||||||
studioSessionsPlaylistLink,
|
studioSessionsPlaylistLink,
|
||||||
|
supportPlaylists,
|
||||||
} from 'features/system/components/VideosModal/data';
|
} from 'features/system/components/VideosModal/data';
|
||||||
|
import { PlaylistCardList } from 'features/system/components/VideosModal/PlaylistCardList';
|
||||||
import { VideoCardList } from 'features/system/components/VideosModal/VideoCardList';
|
import { VideoCardList } from 'features/system/components/VideosModal/VideoCardList';
|
||||||
import { videoModalLinkClicked } from 'features/system/store/actions';
|
import { videoModalLinkClicked } from 'features/system/store/actions';
|
||||||
import { discordLink } from 'features/system/store/constants';
|
import { discordLink } from 'features/system/store/constants';
|
||||||
@@ -86,7 +87,7 @@ export const VideosModal = memo(() => {
|
|||||||
<Trans i18nKey="supportVideos.studioSessionsDesc2" components={components} />
|
<Trans i18nKey="supportVideos.studioSessionsDesc2" components={components} />
|
||||||
</Text>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
<VideoCardList category={t('supportVideos.gettingStarted')} videos={gettingStartedVideos} />
|
<PlaylistCardList category={t('supportVideos.supportPlaylists')} playlists={supportPlaylists} />
|
||||||
<VideoCardList category={t('supportVideos.controlCanvas')} videos={controlCanvasVideos} />
|
<VideoCardList category={t('supportVideos.controlCanvas')} videos={controlCanvasVideos} />
|
||||||
</Flex>
|
</Flex>
|
||||||
</ScrollableContent>
|
</ScrollableContent>
|
||||||
|
|||||||
@@ -1,10 +1,30 @@
|
|||||||
/**
|
/**
|
||||||
* To add a support video, you'll need to add the video to the list below.
|
* To add a support video playlist, you'll need to add the playlist to the list below.
|
||||||
*
|
*
|
||||||
* The `tKey` is a sub-key in the translation file `invokeai/frontend/web/public/locales/en.json`.
|
* The `tKey` is a sub-key in the translation file `invokeai/frontend/web/public/locales/en.json`.
|
||||||
* Add the title and description under `supportVideos.videos`, following the existing format.
|
* Add the title and description under `supportVideos.playlists`, following the existing format.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
export type PlaylistData = {
|
||||||
|
tKey: string;
|
||||||
|
link: string;
|
||||||
|
videoCount: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const supportPlaylists: PlaylistData[] = [
|
||||||
|
{
|
||||||
|
tKey: 'gettingStarted',
|
||||||
|
link: 'https://www.youtube.com/watch?v=jVi2XgSGrfY&list=PLvWK1Kc8iXGrQy8r9TYg6QdUuJ5MMx-ZO&pp=gAQB0gcJCV8EOCosWNin',
|
||||||
|
videoCount: 6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tKey: 'studioSessions',
|
||||||
|
link: 'https://www.youtube.com/watch?v=91ZgeeqL7Bo&list=PLvWK1Kc8iXGq_8tWZqnwDVaf9uhlDC09U&pp=gAQB',
|
||||||
|
videoCount: 10,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// Legacy video data - keeping for backward compatibility if needed
|
||||||
export type VideoData = {
|
export type VideoData = {
|
||||||
tKey: string;
|
tKey: string;
|
||||||
link: string;
|
link: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user