# 레슨 콘텐츠 타입별 UX 정의 이 문서는 레슨(Lesson) 시스템의 4가지 콘텐츠 타입이 **어떻게 보이고 어떻게 동작해야 하는지** 명확하게 정의합니다. --- ## 1. Theory (이론 설명) ### 목적 개념이나 지식을 가르치는 읽기 전용 콘텐츠 ### 데이터 구조 ```typescript interface TheoryBlock { markdown: string; imageUrl?: string; } ``` ### 렌더링 방법 **컴포넌트**: `TheoryRenderer.tsx` **UI 구성**: - 마크다운을 HTML로 렌더링 (제목, 굵은 글씨, 목록 등 지원) - 이미지가 있으면 하단에 표시 - 읽기 전용 (사용자 입력 없음) **사용자 액션**: - 읽기만 함 - 스크롤 가능 - 액션 없음 → 자동으로 "완료" 처리 **예시**: ```markdown ## 의성어란? 소리를 흉내 낸 말이에요. **예시:** - 강아지: 멍멍, 왈왈 - 비: 주룩주룩, 후두둑 의성어를 사용하면 글을 읽는 사람이 소리를 상상할 수 있어요! ``` **렌더링 결과**: ``` ┌─────────────────────────────────┐ │ 의성어란? │ │ │ │ 소리를 흉내 낸 말이에요. │ │ │ │ 예시: │ │ • 강아지: 멍멍, 왈왈 │ │ • 비: 주룩주룩, 후두둑 │ │ │ │ 의성어를 사용하면... │ │ │ │ [이미지가 있으면 여기에 표시] │ └─────────────────────────────────┘ ``` --- ## 2. Quiz (퀴즈) ### 목적 이해도를 확인하는 문제 (객관식 또는 주관식) ### 데이터 구조 ```typescript interface QuizBlock { question: string; type: 'multiple_choice' | 'short_answer'; options?: string[]; // 객관식인 경우 answer: string | number; // 주관식: string, 객관식: 선택지 인덱스 (0부터) explanation: string; } ``` ### 렌더링 방법 **컴포넌트**: `QuizRenderer.tsx` **UI 구성**: 1. **문제 표시** 2. **답변 입력 영역** (타입에 따라) - **객관식**: 라디오 버튼 - **주관식**: 텍스트 입력 3. **제출 버튼** 4. **결과 표시** (제출 후) - 정답/오답 표시 - 해설 표시 ### 사용자 액션 **객관식 플로우**: 1. 문제 읽기 2. 선택지 중 하나 선택 (Radio button) 3. "정답 확인" 버튼 클릭 4. 결과 표시: - ✅ **정답**: "정답입니다!" + 해설 - ❌ **오답**: "아쉬워요! 정답은 X번입니다" + 해설 5. 다음으로 진행 가능 **주관식 플로우**: 1. 문제 읽기 2. 텍스트 입력 3. "정답 확인" 버튼 클릭 4. 정답과 비교 (대소문자 무시, 공백 제거 후 비교) 5. 결과 표시 6. 다음으로 진행 가능 ### UI 예시 **객관식 (제출 전)**: ``` ┌─────────────────────────────────┐ │ 📝 퀴즈 │ │ │ │ 다음 중 의성어가 아닌 것은? │ │ │ │ ○ 졸졸 │ │ ○ 빨갛다 │ │ ○ 윙윙 │ │ ○ 톡톡 │ │ │ │ [정답 확인] │ └─────────────────────────────────┘ ``` **객관식 (정답 제출 후)**: ``` ┌─────────────────────────────────┐ │ 📝 퀴즈 │ │ │ │ 다음 중 의성어가 아닌 것은? │ │ │ │ ○ 졸졸 │ │ ● 빨갛다 ❌ (선택) │ │ ○ 윙윙 │ │ ○ 톡톡 │ │ │ │ ❌ 아쉬워요! │ │ 정답은 2번 "빨갛다" 입니다. │ │ │ │ 💡 '빨갛다'는 색깔을 나타내는 │ │ 말이에요. │ └─────────────────────────────────┘ ``` **주관식**: ``` ┌─────────────────────────────────┐ │ 📝 퀴즈 │ │ │ │ 비유란 무엇일까요? │ │ │ │ ┌─────────────────────────────┐ │ │ │ │ │ │ └─────────────────────────────┘ │ │ │ │ [정답 확인] │ └─────────────────────────────────┘ ``` --- ## 3. Mission (미션) ### 목적 학생이 직접 찾거나 수행해야 할 체크리스트 ### 데이터 구조 ```typescript interface MissionBlock { description: string; items: string[]; // 체크할 항목들 } ``` ### 렌더링 방법 **컴포넌트**: `MissionRenderer.tsx` **UI 구성**: 1. 미션 설명 2. 체크박스 리스트 3. 완료 상태 표시 ### 사용자 액션 1. 미션 설명 읽기 2. 각 항목 수행 후 체크 3. 모든 항목 체크 시 자동 완료 **중요**: 실제로 "수행했는지"는 검증 불가능 → 신뢰 기반 체크 ### UI 예시 **초기 상태**: ``` ┌─────────────────────────────────┐ │ 🎯 미션 │ │ │ │ 소리 탐정이 되어보자! │ │ │ │ ☐ 지금 주변에서 들리는 │ │ 소리 3가지 찾기 │ │ │ │ ☐ 각 소리를 의성어로 │ │ 표현해보기 │ │ │ │ 진행률: 0 / 2 │ └─────────────────────────────────┘ ``` **일부 완료**: ``` ┌─────────────────────────────────┐ │ 🎯 미션 │ │ │ │ 소리 탐정이 되어보자! │ │ │ │ ☑ 지금 주변에서 들리는 │ │ 소리 3가지 찾기 │ │ │ │ ☐ 각 소리를 의성어로 │ │ 표현해보기 │ │ │ │ 진행률: 1 / 2 │ └─────────────────────────────────┘ ``` **전체 완료**: ``` ┌─────────────────────────────────┐ │ 🎯 미션 │ │ │ │ 소리 탐정이 되어보자! │ │ │ │ ☑ 지금 주변에서 들리는 │ │ 소리 3가지 찾기 │ │ │ │ ☑ 각 소리를 의성어로 │ │ 표현해보기 │ │ │ │ ✅ 완료했어요! │ └─────────────────────────────────┘ ``` --- ## 4. WritingPrompt (글쓰기 프롬프트) ### 목적 레슨 안에서 간단하게 글을 써보는 연습 **주의**: 본격적인 글쓰기는 `/write` 페이지의 Topic 사용. WritingPrompt는 배운 내용을 바로 적용해보는 **짧은 연습**용. ### 데이터 구조 ```typescript interface WritingPromptBlock { prompt: string; guideLines: string[]; minLength?: number; // 최소 글자 수 } ``` ### 렌더링 방법 **컴포넌트**: `WritingPromptRenderer.tsx` **UI 구성**: 1. 글쓰기 주제 2. 가이드라인 목록 3. 텍스트 에디터 (간단한 Textarea) 4. 글자 수 카운터 5. 제출 버튼 ### 사용자 액션 1. 주제와 가이드라인 읽기 2. 텍스트 에디터에 글 작성 3. 최소 글자 수 도달 확인 4. "제출" 버튼 클릭 5. 완료 처리 **저장 위치**: - LocalStorage 또는 Realtime DB에 임시 저장 - 나중에 `/write` 페이지에서 이어 쓸 수 있도록 연동 가능 (선택) ### UI 예시 **초기 상태**: ``` ┌─────────────────────────────────┐ │ ✍️ 글쓰기 │ │ │ │ 소리가 가득한 아침 │ │ │ │ 가이드라인: │ │ • 오늘 아침에 들은 소리들을 │ │ 떠올려보세요 │ │ • 의성어를 3개 이상 사용해보세요 │ │ │ │ ┌─────────────────────────────┐ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─────────────────────────────┘ │ │ │ │ 0 / 100자 (최소 100자) │ │ │ │ [제출] (비활성화) │ └─────────────────────────────────┘ ``` **작성 중**: ``` ┌─────────────────────────────────┐ │ ✍️ 글쓰기 │ │ │ │ 소리가 가득한 아침 │ │ │ │ 가이드라인: │ │ • 오늘 아침에 들은 소리들을... │ │ • 의성어를 3개 이상... │ │ │ │ ┌─────────────────────────────┐ │ │ │ 아침에 일어나니 새들이 │ │ │ │ 짹짹거리는 소리가 들렸다. │ │ │ │ 부엌에서는 엄마가 후라이팬에 │ │ │ │ 계란을 지글지글 굽고 계셨다. │ │ │ │ │ │ │ └─────────────────────────────┘ │ │ │ │ 78 / 100자 (거의 다 왔어요!) │ │ │ │ [제출] (비활성화) │ └─────────────────────────────────┘ ``` **제출 가능**: ``` ┌─────────────────────────────────┐ │ ✍️ 글쓰기 │ │ │ │ 소리가 가득한 아침 │ │ │ │ ┌─────────────────────────────┐ │ │ │ 아침에 일어나니 새들이 │ │ │ │ 짹짹거리는 소리가 들렸다... │ │ │ │ (글 내용 계속) │ │ │ └─────────────────────────────┘ │ │ │ │ 125 / 100자 ✅ │ │ │ │ [제출] │ └─────────────────────────────────┘ ``` --- ## 레슨 전체 플로우 ### LessonViewer 컴포넌트 구조 ```typescript {/* 헤더 */} {/* 현재 콘텐츠 블록 */} handleComplete()} /> {/* 네비게이션 */} nextContent()} onPrevious={() => previousContent()} canNext={currentContentCompleted} isLastContent={currentIndex === totalContents - 1} /> ``` ### 진행 상태 관리 **로컬 상태**: - `currentIndex`: 현재 보고 있는 콘텐츠 인덱스 - `completedBlocks`: 완료한 블록들의 Set **서버 저장** (나중에 구현): - UserLessonProgress 모델 - 레슨 완료 시 경험치 및 스티커 보상 ### 완료 조건 | 타입 | 완료 조건 | |------|-----------| | Theory | 자동 완료 (읽기만) | | Quiz | 정답 확인 후 | | Mission | 모든 항목 체크 | | WritingPrompt | 최소 글자 수 이상 + 제출 | --- ## 구현 우선순위 ### Phase 1: 기본 렌더러 1. TheoryRenderer (가장 간단) 2. MissionRenderer 3. QuizRenderer (주관식만) 4. WritingPromptRenderer ### Phase 2: 고급 기능 1. QuizRenderer 객관식 지원 2. 마크다운 렌더링 (react-markdown) 3. 진행 상태 저장 ### Phase 3: UX 개선 1. 애니메이션 (콘텐츠 전환) 2. 로딩 상태 3. 에러 처리 --- ## 디자인 토큰 **색상**: - Theory: `blue` (파란색) - Quiz: `purple` (보라색) - Mission: `orange` (주황색) - WritingPrompt: `green` (초록색) **아이콘**: - Theory: `HiOutlineDocumentText` - Quiz: `HiOutlineQuestionMarkCircle` - Mission: `HiOutlineFlag` - WritingPrompt: `HiOutlinePencilAlt` --- ## 참고 사항 ### 접근성 - 모든 인터랙티브 요소에 키보드 접근 가능 - 스크린 리더 지원 (aria-label) - 명확한 포커스 표시 ### 반응형 - 모바일 우선 디자인 - 터치 친화적 버튼 크기 (최소 44x44px) ### 성능 - 마크다운 렌더링은 메모이제이션 - 긴 콘텐츠는 가상화 고려 --- © 2024 BlueNovaLab. All rights reserved.