471 lines
14 KiB
Markdown
471 lines
14 KiB
Markdown
# 레슨 콘텐츠 타입별 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
|
|
<LessonViewer lessonId={lessonId}>
|
|
{/* 헤더 */}
|
|
<LessonHeader
|
|
title="1강. 소리를 글로 표현하기"
|
|
progress={currentIndex / totalContents}
|
|
/>
|
|
|
|
{/* 현재 콘텐츠 블록 */}
|
|
<ContentRenderer
|
|
content={lesson.contents[currentIndex]}
|
|
onComplete={() => handleComplete()}
|
|
/>
|
|
|
|
{/* 네비게이션 */}
|
|
<LessonNavigation
|
|
onNext={() => nextContent()}
|
|
onPrevious={() => previousContent()}
|
|
canNext={currentContentCompleted}
|
|
isLastContent={currentIndex === totalContents - 1}
|
|
/>
|
|
</LessonViewer>
|
|
```
|
|
|
|
### 진행 상태 관리
|
|
|
|
**로컬 상태**:
|
|
- `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.
|