diff --git a/src/components/Tutorial/TutorialOverlay.tsx b/src/components/Tutorial/TutorialOverlay.tsx index 26d89fa..450c5ac 100644 --- a/src/components/Tutorial/TutorialOverlay.tsx +++ b/src/components/Tutorial/TutorialOverlay.tsx @@ -238,9 +238,11 @@ const TutorialOverlay: React.FC = ({ {t('tutorial.prev')} )} - + {(hint.clickToAdvance !== true || isLast) && ( + + )} diff --git a/src/components/Tutorial/tutorialSteps.ts b/src/components/Tutorial/tutorialSteps.ts index c453bb0..48e8dbc 100644 --- a/src/components/Tutorial/tutorialSteps.ts +++ b/src/components/Tutorial/tutorialSteps.ts @@ -155,6 +155,7 @@ export const tutorialSteps: TutorialStepDef[] = [ titleKey: 'tutorial.asset.ratio.title', descriptionKey: 'tutorial.asset.ratio.desc', position: 'left', + clickToAdvance: false, }, { targetSelector: '.asset-next-button', @@ -201,6 +202,13 @@ export const tutorialSteps: TutorialStepDef[] = [ position: 'left', clickToAdvance: false, }, + { + targetSelector: '.status-message-new', + titleKey: 'tutorial.sound.lyricsWait.title', + descriptionKey: 'tutorial.sound.lyricsWait.desc', + position: 'right', + clickToAdvance: false, + }, ], }, { @@ -230,12 +238,14 @@ export const tutorialSteps: TutorialStepDef[] = [ titleKey: 'tutorial.myInfo.connect.title', descriptionKey: 'tutorial.myInfo.connect.desc', position: 'top', + clickToAdvance: false, }, { - targetSelector: '.myinfo-social-btn.connected', + targetSelector: '.myinfo-social-buttons', titleKey: 'tutorial.myInfo.button.title', descriptionKey: 'tutorial.myInfo.button.desc', position: 'top', + clickToAdvance: true, }, { targetSelector: '.myinfo-connected-accounts', diff --git a/src/components/Tutorial/useTutorial.ts b/src/components/Tutorial/useTutorial.ts index 55131f4..e229d4a 100644 --- a/src/components/Tutorial/useTutorial.ts +++ b/src/components/Tutorial/useTutorial.ts @@ -104,6 +104,7 @@ export function useTutorial(): UseTutorialReturn { // 마지막 힌트 완료 → seen 기록 + 진행 상태 삭제 setIsActive(false); if (tutorialKey) markSeen(tutorialKey); + globalSkip = null; // 완료된 튜토리얼은 globalSkip 해제 onCompleteRef.current?.(); onCompleteRef.current = undefined; return 0; @@ -127,7 +128,7 @@ export function useTutorial(): UseTutorialReturn { setIsRestartPopupVisible(true); }, []); - // 팝업에서 확인 → seen 초기화 후 튜토리얼 시작 + // 팝업에서 확인 → seen/progress 초기화 후 튜토리얼 시작 const confirmRestart = useCallback(() => { setIsRestartPopupVisible(false); if (pendingRestartKey) { diff --git a/src/locales/en.json b/src/locales/en.json index b55e588..374a3bc 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -46,14 +46,15 @@ "language": { "title": "Select Language", "desc": "You can choose the language for the sound.\nWant to continue with Korean?" }, "generate": { "title": "Generate Sound", "desc": "AI will generate music in your chosen genre and language." }, "lyrics": { "title": "Lyrics Complete", "desc": "AI wrote lyrics in your selected language.\nCheck the generated lyrics." }, + "lyricsWait": { "title": "Generating Music", "desc": "AI is composing music based on the lyrics.\nPlease wait a moment." }, "audioPlayer": { "title": "Preview the Music", "desc": "Music generation is complete.\nPress play to listen to the generated music." }, "video": { "title": "Generate Video", "desc": "Click the button to start generating your video." } }, "myInfo": { "connect": { "title": "Connect Social Account", "desc": "You need to link a social account to upload videos." }, - "button": { "title": "Connect Now", "desc": "Click the social media button you want to connect." }, - "connected": { "title": "Connected Accounts", "desc": "Your linked social accounts appear here. Check after connecting." }, - "ado2": { "title": "Check My Contents", "desc": "After connecting, go to My Contents in the sidebar to view and upload your videos. Click to navigate." } + "button": { "title": "Connect Now", "desc": "Click the YouTube connect button.\n(Instagram connection is under development.)" }, + "connected": { "title": "Connected Accounts", "desc": "Your linked social accounts appear here.\nCheck after connecting." }, + "ado2": { "title": "ADO2 Contents", "desc": "You can now upload the generated video.\nClick to navigate." } }, "ado2": { "list": { "title": "Generated Videos", "desc": "View all AI-created videos here." }, @@ -61,12 +62,12 @@ }, "completion": { "contentInfo": { "title": "Content Info", "desc": "Check the title, genre, resolution, and lyrics of the generated content." }, - "generating": { "title": "Generating Video", "desc": "AI is creating your video. Please wait a moment." }, + "generating": { "title": "Generating Video", "desc": "AI is creating your video.\nPlease wait a moment." }, "completion": { "title": "Video Complete!", "desc": "Your video is ready. Want to take a look?" }, "myInfo": { "title": "Connect Social Account", "desc": "To upload your video to YouTube, connect your social account in My Info. Click to go there." } }, "upload": { - "seo": { "title": "Title & Description", "desc": "AI is generating the title and description for your video.\nPlease wait a moment." }, + "seo": { "title": "Title & Description", "desc": "AI is generating the title and description for your video. \nPlease wait a moment." }, "required": { "title": "Required Fields", "desc": "Fields marked with * are required. Please fill them in before uploading." }, "schedule": { "title": "Schedule Upload", "desc": "Post now or schedule for a specific time." }, "submit": { "title": "Start Upload", "desc": "Click the Post button to start uploading." } diff --git a/src/locales/ko.json b/src/locales/ko.json index 0f607c7..33777c6 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -46,14 +46,15 @@ "language": { "title": "언어 선택", "desc": "사운드의 언어를 선택할 수 있어요. \n이미 선택된 한국어로 진행해볼까요?" }, "generate": { "title": "사운드 생성", "desc": "AI가 선택한 장르와 언어로 음악을 생성해요." }, "lyrics": { "title": "가사 생성 완료", "desc": "AI가 선택한 언어로 가사를 만들었어요.\n생성된 가사를 확인하세요." }, + "lyricsWait": { "title": "음악 생성 중", "desc": "가사를 바탕으로 AI가 음악을 만들고 있어요.\n잠시만 기다려 주세요." }, "audioPlayer": { "title": "음악 미리 듣기", "desc": "음악 생성이 완료되었어요.\n재생 버튼을 눌러 생성된 음악을 미리 들어보세요." }, "video": { "title": "영상 생성", "desc": "버튼을 클릭해서 영상 생성을 시작하세요." } }, "myInfo": { "connect": { "title": "소셜 연결", "desc": "영상을 업로드하려면 소셜 계정을 연동해야 해요." }, - "button": { "title": "연결하기", "desc": "원하는 소셜미디어 버튼을 클릭해서 연동하세요. \n(Instaram연결은 개발 중입니다.)" }, + "button": { "title": "연결하기", "desc": "YouTube 연결 버튼을 클릭하세요. \n(Instaram연결은 개발 중입니다.)" }, "connected": { "title": "연결 계정", "desc": "연결된 소셜 계정 목록이에요. \n연결 후 여기서 확인할 수 있어요." }, - "ado2": { "title": "ADO2 콘텐츠", "desc": "이제 생성된 영상을 업로드할 수 있어요. 클릭해서 이동하세요." } + "ado2": { "title": "ADO2 콘텐츠", "desc": "이제 생성된 영상을 업로드할 수 있어요. \n클릭해서 이동하세요." } }, "ado2": { "list": { "title": "생성된 영상 목록", "desc": "ADO2에서 만든 영상들을 확인할 수 있어요." }, @@ -61,7 +62,7 @@ }, "completion": { "contentInfo": { "title": "콘텐츠 정보", "desc": "생성된 콘텐츠의 제목, 장르, 규격, 가사 정보를 확인하세요." }, - "generating": { "title": "영상 제작 중", "desc": "AI가 영상을 만들고 있어요. 잠시만 기다려 주세요." }, + "generating": { "title": "영상 제작 중", "desc": "AI가 영상을 만들고 있어요. \n잠시만 기다려 주세요." }, "completion": { "title": "영상 완성!", "desc": "영상 제작이 완료되었어요. \n영상을 확인해 볼까요?" }, "myInfo": { "title": "소셜 계정 연동", "desc": "영상을 유튜브에 업로드하려면 내 정보에서 소셜 계정을 연동해야 해요. 클릭해서 이동하세요." } }, diff --git a/src/pages/Dashboard/GenerationFlow.tsx b/src/pages/Dashboard/GenerationFlow.tsx index f750bca..6299e39 100755 --- a/src/pages/Dashboard/GenerationFlow.tsx +++ b/src/pages/Dashboard/GenerationFlow.tsx @@ -323,6 +323,7 @@ const GenerationFlow: React.FC = ({ // wizardStep 변경 시 튜토리얼 트리거 (사이드바 메뉴 화면에서는 제외) const SIDEBAR_ITEMS = ['대시보드', 'ADO2 콘텐츠', '내 정보', '콘텐츠 캘린더']; useEffect(() => { + if (tutorial.isActive) tutorial.skipTutorial(); if (SIDEBAR_ITEMS.includes(activeItem)) return; const timer = setTimeout(() => { if (wizardStep === 1 && !tutorial.hasSeen(TUTORIAL_KEYS.ASSET)) { @@ -336,6 +337,7 @@ const GenerationFlow: React.FC = ({ // activeItem 변경 시 튜토리얼 트리거 useEffect(() => { + if (tutorial.isActive) tutorial.skipTutorial(); if (activeItem === '내 정보' && !tutorial.hasSeen(TUTORIAL_KEYS.MY_INFO)) { tutorial.startTutorial(TUTORIAL_KEYS.MY_INFO); } else if (activeItem === 'ADO2 콘텐츠' && !tutorial.hasSeen(TUTORIAL_KEYS.ADO2_CONTENTS)) { @@ -509,6 +511,7 @@ const GenerationFlow: React.FC = ({ if (activeItem === '내 정보') return TUTORIAL_KEYS.MY_INFO; if (activeItem === 'ADO2 콘텐츠') return TUTORIAL_KEYS.ADO2_CONTENTS; if (activeItem === '대시보드') return TUTORIAL_KEYS.DASHBOARD; + if (activeItem === '콘텐츠 캘린더') return TUTORIAL_KEYS.CONTENT_CALENDAR; if (activeItem === '새 프로젝트 만들기') { if (wizardStep === 1) return TUTORIAL_KEYS.ASSET; if (wizardStep === 2) return TUTORIAL_KEYS.SOUND;