From c9d4e2b761c8232963959ad91ca081be5738f616 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 7 Jul 2025 16:36:53 +0000 Subject: [PATCH] Refactor support videos modal to simplify video and playlist handling Co-authored-by: kent --- invokeai/frontend/web/public/locales/en.json | 62 +----------- .../components/VideosModal/PlaylistCard.tsx | 33 ------- .../VideosModal/PlaylistCardList.tsx | 20 ---- .../components/VideosModal/VideosModal.tsx | 10 +- .../system/components/VideosModal/data.ts | 96 ++----------------- 5 files changed, 12 insertions(+), 209 deletions(-) delete mode 100644 invokeai/frontend/web/src/features/system/components/VideosModal/PlaylistCard.tsx delete mode 100644 invokeai/frontend/web/src/features/system/components/VideosModal/PlaylistCardList.tsx diff --git a/invokeai/frontend/web/public/locales/en.json b/invokeai/frontend/web/public/locales/en.json index 84eef9d6b2..9af94fa945 100644 --- a/invokeai/frontend/web/public/locales/en.json +++ b/invokeai/frontend/web/public/locales/en.json @@ -2564,17 +2564,11 @@ }, "supportVideos": { "supportVideos": "Support Videos", - "supportPlaylists": "Video Playlists", "gettingStarted": "Getting Started", - "controlCanvas": "Control Canvas", "watch": "Watch", - "watchPlaylist": "Watch Playlist", - "videoCount": "{{count}} videos", - "videoCount_one": "{{count}} video", - "videoCount_other": "{{count}} videos", "studioSessionsDesc1": "Check out the for Invoke deep dives.", "studioSessionsDesc2": "Join our to participate in the live sessions and ask questions. Sessions are uploaded to the playlist the following week.", - "playlists": { + "videos": { "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." @@ -2583,60 +2577,6 @@ "title": "Studio Sessions", "description": "Deep dive sessions exploring advanced Invoke features, creative workflows, and community discussions." } - }, - "videos": { - "creatingYourFirstImage": { - "title": "Creating Your First Image", - "description": "Introduction to creating an image from scratch using Invoke's tools." - }, - "usingControlLayersAndReferenceGuides": { - "title": "Using Control Layers and Reference Guides", - "description": "Learn how to guide your image creation with control layers and reference images." - }, - "understandingImageToImageAndDenoising": { - "title": "Understanding Image-to-Image and Denoising", - "description": "Overview of image-to-image transformations and denoising in Invoke." - }, - "exploringAIModelsAndConceptAdapters": { - "title": "Exploring AI Models and Concept Adapters", - "description": "Dive into AI models and how to use concept adapters for creative control." - }, - "creatingAndComposingOnInvokesControlCanvas": { - "title": "Creating and Composing on Invoke's Control Canvas", - "description": "Learn to compose images using Invoke's control canvas." - }, - "upscaling": { - "title": "Upscaling", - "description": "How to upscale images with Invoke's tools to enhance resolution." - }, - "howDoIGenerateAndSaveToTheGallery": { - "title": "How Do I Generate and Save to the Gallery?", - "description": "Steps to generate and save images to the gallery." - }, - "howDoIEditOnTheCanvas": { - "title": "How Do I Edit on the Canvas?", - "description": "Guide to editing images directly on the canvas." - }, - "howDoIDoImageToImageTransformation": { - "title": "How Do I Do Image-to-Image Transformation?", - "description": "Tutorial on performing image-to-image transformations in Invoke." - }, - "howDoIUseControlNetsAndControlLayers": { - "title": "How Do I Use Control Nets and Control Layers?", - "description": "Learn to apply control layers and controlnets to your images." - }, - "howDoIUseGlobalIPAdaptersAndReferenceImages": { - "title": "How Do I Use Global IP Adapters and Reference Images?", - "description": "Introduction to adding reference images and global IP adapters." - }, - "howDoIUseInpaintMasks": { - "title": "How Do I Use Inpaint Masks?", - "description": "How to apply inpaint masks for image correction and variation." - }, - "howDoIOutpaint": { - "title": "How Do I Outpaint?", - "description": "Guide to outpainting beyond the original image borders." - } } } } diff --git a/invokeai/frontend/web/src/features/system/components/VideosModal/PlaylistCard.tsx b/invokeai/frontend/web/src/features/system/components/VideosModal/PlaylistCard.tsx deleted file mode 100644 index 4c361fb3bd..0000000000 --- a/invokeai/frontend/web/src/features/system/components/VideosModal/PlaylistCard.tsx +++ /dev/null @@ -1,33 +0,0 @@ -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 ( - - - - {t(`supportVideos.playlists.${tKey}.title`)} - - - {t('supportVideos.videoCount', { count: videoCount })} - - - - {t(`supportVideos.playlists.${tKey}.description`)} - - - ); -}); - -PlaylistCard.displayName = 'PlaylistCard'; diff --git a/invokeai/frontend/web/src/features/system/components/VideosModal/PlaylistCardList.tsx b/invokeai/frontend/web/src/features/system/components/VideosModal/PlaylistCardList.tsx deleted file mode 100644 index d29f4bb206..0000000000 --- a/invokeai/frontend/web/src/features/system/components/VideosModal/PlaylistCardList.tsx +++ /dev/null @@ -1,20 +0,0 @@ -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 ( - - {playlists.map((playlist, i) => ( - - - {i < playlists.length - 1 && } - - ))} - - ); -}); - -PlaylistCardList.displayName = 'PlaylistCardList'; diff --git a/invokeai/frontend/web/src/features/system/components/VideosModal/VideosModal.tsx b/invokeai/frontend/web/src/features/system/components/VideosModal/VideosModal.tsx index 8ba63e2a33..cf0c0fb81f 100644 --- a/invokeai/frontend/web/src/features/system/components/VideosModal/VideosModal.tsx +++ b/invokeai/frontend/web/src/features/system/components/VideosModal/VideosModal.tsx @@ -13,12 +13,7 @@ import { import { useAppDispatch } from 'app/store/storeHooks'; import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent'; import { buildUseDisclosure } from 'common/hooks/useBoolean'; -import { - controlCanvasVideos, - studioSessionsPlaylistLink, - supportPlaylists, -} from 'features/system/components/VideosModal/data'; -import { PlaylistCardList } from 'features/system/components/VideosModal/PlaylistCardList'; +import { studioSessionsPlaylistLink, supportVideos } from 'features/system/components/VideosModal/data'; import { VideoCardList } from 'features/system/components/VideosModal/VideoCardList'; import { videoModalLinkClicked } from 'features/system/store/actions'; import { discordLink } from 'features/system/store/constants'; @@ -87,8 +82,7 @@ export const VideosModal = memo(() => { - - + diff --git a/invokeai/frontend/web/src/features/system/components/VideosModal/data.ts b/invokeai/frontend/web/src/features/system/components/VideosModal/data.ts index 3e7864779e..107c7bd5a6 100644 --- a/invokeai/frontend/web/src/features/system/components/VideosModal/data.ts +++ b/invokeai/frontend/web/src/features/system/components/VideosModal/data.ts @@ -1,30 +1,10 @@ /** - * To add a support video playlist, you'll need to add the playlist to the list below. + * To add a support video, you'll need to add the video to the list below. * * The `tKey` is a sub-key in the translation file `invokeai/frontend/web/public/locales/en.json`. - * Add the title and description under `supportVideos.playlists`, following the existing format. + * Add the title and description under `supportVideos.videos`, 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 = { tKey: string; link: string; @@ -34,74 +14,16 @@ export type VideoData = { }; }; -export const gettingStartedVideos: VideoData[] = [ +export const supportVideos: VideoData[] = [ { - tKey: 'creatingYourFirstImage', - link: 'https://www.youtube.com/watch?v=jVi2XgSGrfY&list=PLvWK1Kc8iXGrQy8r9TYg6QdUuJ5MMx-ZO&index=1&t=29s&pp=iAQB', - length: { minutes: 6, seconds: 0 }, + tKey: 'gettingStarted', + link: 'https://www.youtube.com/watch?v=jVi2XgSGrfY&list=PLvWK1Kc8iXGrQy8r9TYg6QdUuJ5MMx-ZO&pp=gAQB0gcJCV8EOCosWNin', + length: { minutes: 0, seconds: 0 }, // Playlist doesn't have a single duration }, { - tKey: 'usingControlLayersAndReferenceGuides', - link: 'https://www.youtube.com/watch?v=crgw6bEgyrw&list=PLvWK1Kc8iXGrQy8r9TYg6QdUuJ5MMx-ZO&index=2&t=70s&pp=iAQB', - length: { minutes: 5, seconds: 30 }, - }, - { - tKey: 'understandingImageToImageAndDenoising', - link: 'https://www.youtube.com/watch?v=tvj8-0s6S2U&list=PLvWK1Kc8iXGrQy8r9TYg6QdUuJ5MMx-ZO&index=3&t=1s&pp=iAQB', - length: { minutes: 2, seconds: 37 }, - }, - { - tKey: 'exploringAIModelsAndConceptAdapters', - link: 'https://www.youtube.com/watch?v=iwBmBQMZ0UA&list=PLvWK1Kc8iXGrQy8r9TYg6QdUuJ5MMx-ZO&index=4&pp=iAQB', - length: { minutes: 8, seconds: 52 }, - }, - { - tKey: 'creatingAndComposingOnInvokesControlCanvas', - link: 'https://www.youtube.com/watch?v=O4LaFcYFxlA', - length: { minutes: 2, seconds: 52 }, - }, - { - tKey: 'upscaling', - link: 'https://www.youtube.com/watch?v=OCb19_P0nro&list=PLvWK1Kc8iXGrQy8r9TYg6QdUuJ5MMx-ZO&index=6&t=2s&pp=iAQB', - length: { minutes: 4, seconds: 0 }, - }, -]; - -export const controlCanvasVideos: VideoData[] = [ - { - tKey: 'howDoIGenerateAndSaveToTheGallery', - link: 'https://youtu.be/Tl-69JvwJ2s?si=dbjmBc1iDAUpE1k5&t=26', - length: { minutes: 0, seconds: 49 }, - }, - { - tKey: 'howDoIEditOnTheCanvas', - link: 'https://youtu.be/Tl-69JvwJ2s?si=U_bFl9HsvSuejbxp&t=76', - length: { minutes: 0, seconds: 58 }, - }, - { - tKey: 'howDoIDoImageToImageTransformation', - link: 'https://youtu.be/Tl-69JvwJ2s?si=fjhTeY-yZ3qsEzEM&t=138', - length: { minutes: 0, seconds: 51 }, - }, - { - tKey: 'howDoIUseControlNetsAndControlLayers', - link: 'https://youtu.be/Tl-69JvwJ2s?si=x5KcYvkHbvR9ifsX&t=192', - length: { minutes: 1, seconds: 41 }, - }, - { - tKey: 'howDoIUseGlobalIPAdaptersAndReferenceImages', - link: 'https://youtu.be/Tl-69JvwJ2s?si=O940rNHiHGKXknK2&t=297', - length: { minutes: 0, seconds: 43 }, - }, - { - tKey: 'howDoIUseInpaintMasks', - link: 'https://youtu.be/Tl-69JvwJ2s?si=3DZhmerkzUmvJJSn&t=345', - length: { minutes: 1, seconds: 9 }, - }, - { - tKey: 'howDoIOutpaint', - link: 'https://youtu.be/Tl-69JvwJ2s?si=IIwkGZLq1PfLf80Q&t=420', - length: { minutes: 0, seconds: 48 }, + tKey: 'studioSessions', + link: 'https://www.youtube.com/watch?v=91ZgeeqL7Bo&list=PLvWK1Kc8iXGq_8tWZqnwDVaf9uhlDC09U&pp=gAQB', + length: { minutes: 0, seconds: 0 }, // Playlist doesn't have a single duration }, ];