@readerseye2/cr_type 1.0.92 → 1.0.93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ast/ast.types.d.ts +7 -112
- package/dist/book/book-api.type.d.ts +15 -0
- package/dist/book/book-api.type.js +2 -0
- package/dist/book/book-log.type.d.ts +14 -0
- package/dist/book/book-log.type.js +2 -0
- package/dist/book/book-sections.type.d.ts +34 -0
- package/dist/book/book-sections.type.js +2 -0
- package/dist/book/book.const.d.ts +274 -0
- package/dist/book/book.const.js +119 -0
- package/dist/book/book.type.d.ts +56 -184
- package/dist/book/book.type.js +50 -82
- package/dist/book/index.d.ts +3 -0
- package/dist/book/index.js +3 -0
- package/dist/book/legacy.book.type.d.ts +164 -0
- package/dist/book/legacy.book.type.js +41 -0
- package/dist/book/tag.type.d.ts +10 -0
- package/dist/book/tag.type.js +2 -0
- package/dist/index.js +2 -3
- package/dist/store/index.d.ts +1 -0
- package/dist/store/index.js +17 -0
- package/dist/store/store.types.d.ts +42 -0
- package/dist/store/store.types.js +2 -0
- package/package.json +1 -1
package/dist/ast/ast.types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AudioMeta } from '../book/book-sections.type';
|
|
1
2
|
export type SectionId = string;
|
|
2
3
|
export type InlineRun = {
|
|
3
4
|
text: string;
|
|
@@ -43,15 +44,11 @@ export interface AudioMark {
|
|
|
43
44
|
end: number;
|
|
44
45
|
value: string;
|
|
45
46
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
TTS_engine: string;
|
|
49
|
-
language: string;
|
|
50
|
-
speaker: string;
|
|
47
|
+
/** 개별 오디오 클립 메타 (AudioMeta 확장 + 결과 데이터) */
|
|
48
|
+
export type AudioClipMeta = AudioMeta & {
|
|
51
49
|
durationMs: number;
|
|
52
50
|
wordCount: number;
|
|
53
|
-
|
|
54
|
-
}
|
|
51
|
+
};
|
|
55
52
|
type SectionAudioBase = {
|
|
56
53
|
chunkIndex: number;
|
|
57
54
|
marks?: AudioMark[];
|
|
@@ -89,7 +86,7 @@ export type SectionQuiz = {
|
|
|
89
86
|
qid: string;
|
|
90
87
|
kind: 'saved';
|
|
91
88
|
index: number;
|
|
92
|
-
|
|
89
|
+
image_cdn_url: string;
|
|
93
90
|
question: string;
|
|
94
91
|
options: string[];
|
|
95
92
|
answers: string[];
|
|
@@ -99,7 +96,7 @@ export type SectionQuiz = {
|
|
|
99
96
|
qid: string;
|
|
100
97
|
kind: 'temp';
|
|
101
98
|
index: number;
|
|
102
|
-
|
|
99
|
+
image_blob_url: string;
|
|
103
100
|
question: string;
|
|
104
101
|
options: string[];
|
|
105
102
|
answers: string[];
|
|
@@ -109,114 +106,12 @@ export type SectionQuiz = {
|
|
|
109
106
|
export type SectionAST = {
|
|
110
107
|
title: string;
|
|
111
108
|
blocks: Block[];
|
|
112
|
-
isAddedSplit?: boolean;
|
|
113
|
-
isAddedAudio?: boolean;
|
|
114
109
|
};
|
|
115
110
|
export type SectionData = {
|
|
116
111
|
section_id: SectionId;
|
|
117
112
|
ast: SectionAST;
|
|
118
113
|
images?: SectionImage[];
|
|
119
114
|
audios?: SectionAudio[];
|
|
120
|
-
|
|
121
|
-
};
|
|
122
|
-
/** 드래프트 책 메타 정보 (cr.erd.json CR.draft_book 테이블 기준)
|
|
123
|
-
* - user_idx는 백엔드 세션에서 확인하므로 프론트에서 전송하지 않음
|
|
124
|
-
* - isdeleted는 백엔드 내부용이므로 프론트에 노출하지 않음
|
|
125
|
-
*/
|
|
126
|
-
export interface DraftMeta {
|
|
127
|
-
/** PK */
|
|
128
|
-
draft_book_idx: number;
|
|
129
|
-
/** 책 제목 (default: 'untitled') */
|
|
130
|
-
draft_book_title: string;
|
|
131
|
-
/** 언어 코드 */
|
|
132
|
-
draft_book_language: 'ko' | 'en';
|
|
133
|
-
/** 난이도 레벨 (권장 연령, default: 5) */
|
|
134
|
-
draft_book_level: number;
|
|
135
|
-
/** 표지 이미지 URL (nullable) */
|
|
136
|
-
draft_book_cover_url: string | null;
|
|
137
|
-
/** 책 길이 (short/medium/long) */
|
|
138
|
-
draft_book_length: string | null;
|
|
139
|
-
/** 책 종류/장르 (fiction/non-fiction/other) */
|
|
140
|
-
draft_book_genre: string | null;
|
|
141
|
-
/** 영어레벨 (영어책 전용) */
|
|
142
|
-
draft_book_en_level: string | null;
|
|
143
|
-
/** 시리즈명 */
|
|
144
|
-
draft_book_series: string | null;
|
|
145
|
-
/** 원작자 */
|
|
146
|
-
draft_book_author: string | null;
|
|
147
|
-
/** 태그 배열 */
|
|
148
|
-
draft_book_tags: string[] | null;
|
|
149
|
-
/** 설명 */
|
|
150
|
-
draft_book_description: string | null;
|
|
151
|
-
/** 원출판일 (YYYY-MM-DD) */
|
|
152
|
-
draft_book_original_publish_date: string | null;
|
|
153
|
-
/** 원출판사 */
|
|
154
|
-
draft_book_original_publisher: string | null;
|
|
155
|
-
/** ISBN */
|
|
156
|
-
draft_book_isbn: string | null;
|
|
157
|
-
/** 총 어절 수 (자동 계산) */
|
|
158
|
-
draft_book_word_count: number | null;
|
|
159
|
-
/** AR 지수 (0.0 ~ 12.0, 소수점 1자리) */
|
|
160
|
-
draft_book_ar_index: number | null;
|
|
161
|
-
/** Lexile 지수 (0 ~ 2000, 정수) */
|
|
162
|
-
draft_book_lexile_index: number | null;
|
|
163
|
-
/** QUIZ 다시풀기 허용 여부 */
|
|
164
|
-
draft_book_quiz_retry_allowed: boolean;
|
|
165
|
-
/** 생성일 (ISO) */
|
|
166
|
-
draft_book_create_date: string;
|
|
167
|
-
/** 수정일 (ISO) */
|
|
168
|
-
draft_book_update_date: string;
|
|
169
|
-
/** 출판 상태 */
|
|
170
|
-
draft_book_publish_status?: 'draft' | 'pending' | 'rejected';
|
|
171
|
-
}
|
|
172
|
-
import { SectionSummary } from '../book/book.type';
|
|
173
|
-
export type DraftSummary = {
|
|
174
|
-
sectionOrder: SectionId[];
|
|
175
|
-
sections?: SectionSummary[];
|
|
115
|
+
quizzes?: SectionQuiz[];
|
|
176
116
|
};
|
|
177
|
-
export type BookDraftDTO = {
|
|
178
|
-
meta: DraftMeta;
|
|
179
|
-
summary: DraftSummary;
|
|
180
|
-
content: SectionData[];
|
|
181
|
-
};
|
|
182
|
-
export type SectionMap = Record<SectionId, SectionData>;
|
|
183
|
-
export type RuntimeTemp = {
|
|
184
|
-
/** 오디오 blobUrl (런타임 전용): sectionId -> clipIndex -> blobUrl */
|
|
185
|
-
audioBlobUrlBySection: Record<SectionId, Record<number, string>>;
|
|
186
|
-
/** 이미지 blobUrl (런타임 전용): sectionId -> imageIndex -> blobUrl */
|
|
187
|
-
imageBlobUrlBySection: Record<SectionId, Record<number, string>>;
|
|
188
|
-
};
|
|
189
|
-
export type SaveStatus = 'unsaved' | 'saving' | 'saved' | 'error';
|
|
190
|
-
export type SectionSaveState = {
|
|
191
|
-
status: SaveStatus;
|
|
192
|
-
savedAt?: string;
|
|
193
|
-
errorMessage?: string;
|
|
194
|
-
};
|
|
195
|
-
export type DraftSaveState = {
|
|
196
|
-
/** 메타 저장 상태 */
|
|
197
|
-
meta: SaveStatus;
|
|
198
|
-
/** 섹션 순서 저장 상태 */
|
|
199
|
-
order: SaveStatus;
|
|
200
|
-
/** 섹션별 저장 상태 */
|
|
201
|
-
sections: Record<SectionId, SectionSaveState>;
|
|
202
|
-
/** 저장 진행률 */
|
|
203
|
-
progress?: {
|
|
204
|
-
current: number;
|
|
205
|
-
total: number;
|
|
206
|
-
jobId?: string;
|
|
207
|
-
};
|
|
208
|
-
};
|
|
209
|
-
export interface MakeBookState {
|
|
210
|
-
meta: DraftMeta | null;
|
|
211
|
-
/** 정규화된 섹션 맵 */
|
|
212
|
-
sectionsById: SectionMap;
|
|
213
|
-
/** 섹션 순서(목차) */
|
|
214
|
-
sectionOrder: SectionId[];
|
|
215
|
-
/** 리스트 캐시(선택) */
|
|
216
|
-
sectionSummaries?: SectionSummary[];
|
|
217
|
-
/** 런타임 전용(blobUrl 등) */
|
|
218
|
-
temp: RuntimeTemp;
|
|
219
|
-
/** 저장 상태 (클라이언트 전용) */
|
|
220
|
-
saveState: DraftSaveState;
|
|
221
|
-
}
|
|
222
117
|
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Book, SectionSummary } from './book.type';
|
|
2
|
+
import type { SectionData } from '../ast/ast.types';
|
|
3
|
+
/** 책 목록 조회용 (간략) */
|
|
4
|
+
export type BookListItem = Pick<Book, 'book_idx' | 'creator_idx' | 'status' | 'book_title' | 'book_language' | 'book_level' | 'book_cover_url' | 'genre' | 'word_count' | 'section_count' | 'created_at' | 'updated_at'> & {
|
|
5
|
+
creator_name?: string;
|
|
6
|
+
};
|
|
7
|
+
/** 책 상세 응답 (메타 + 요약 + 콘텐츠) */
|
|
8
|
+
export type BookDTO = {
|
|
9
|
+
meta: Book;
|
|
10
|
+
summary: {
|
|
11
|
+
sectionOrder: string[];
|
|
12
|
+
sections: SectionSummary[];
|
|
13
|
+
};
|
|
14
|
+
content: SectionData[];
|
|
15
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** book_log.action ENUM */
|
|
2
|
+
export type BookLogAction = 'request' | 'approve' | 'reject' | 'cancel' | 'suspend' | 'unsuspend';
|
|
3
|
+
/** book_log.acted_by_type ENUM */
|
|
4
|
+
export type BookLogActorType = 'admin' | 'creator';
|
|
5
|
+
/** MySQL book_log 테이블 1:1 */
|
|
6
|
+
export interface BookLog {
|
|
7
|
+
book_log_idx: number;
|
|
8
|
+
book_idx: number;
|
|
9
|
+
action: BookLogAction;
|
|
10
|
+
acted_by_type: BookLogActorType;
|
|
11
|
+
acted_by_idx: number;
|
|
12
|
+
reason: string | null;
|
|
13
|
+
created_at: string;
|
|
14
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** TTS 설정 (섹션 레벨) */
|
|
2
|
+
export type AudioMeta = {
|
|
3
|
+
provider: 'AWS' | 'GCP';
|
|
4
|
+
language: string;
|
|
5
|
+
engine: string;
|
|
6
|
+
voiceName: string;
|
|
7
|
+
voiceGender?: 'Male' | 'Female';
|
|
8
|
+
};
|
|
9
|
+
/** 섹션 요약 (snake_case — MongoDB/API 공용) */
|
|
10
|
+
export interface SectionSummary {
|
|
11
|
+
section_id: string;
|
|
12
|
+
title: string;
|
|
13
|
+
order: number;
|
|
14
|
+
audio_count: number;
|
|
15
|
+
image_count: number;
|
|
16
|
+
quiz_count: number;
|
|
17
|
+
word_count: number;
|
|
18
|
+
sound_minutes?: number;
|
|
19
|
+
is_added_split?: boolean;
|
|
20
|
+
is_added_audio?: boolean;
|
|
21
|
+
is_added_quiz?: boolean;
|
|
22
|
+
updated_at?: string;
|
|
23
|
+
ast_cdn_url?: string;
|
|
24
|
+
audio_meta?: AudioMeta;
|
|
25
|
+
}
|
|
26
|
+
/** MongoDB book_sections 문서 1:1 */
|
|
27
|
+
export interface BookSectionsDoc {
|
|
28
|
+
book_idx: number;
|
|
29
|
+
section_order: string[];
|
|
30
|
+
sections: SectionSummary[];
|
|
31
|
+
free_section_ids: string[] | null;
|
|
32
|
+
created_at: string;
|
|
33
|
+
updated_at: string;
|
|
34
|
+
}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/** 언어 */
|
|
2
|
+
export type BookLanguage = 'ko' | 'en';
|
|
3
|
+
/** 길이 */
|
|
4
|
+
export type BookLength = 'short' | 'medium' | 'long';
|
|
5
|
+
/** 종류 */
|
|
6
|
+
export type BookGenre = 'fiction' | 'non-fiction' | 'other';
|
|
7
|
+
/** 영어레벨 (영어책 전용) */
|
|
8
|
+
export type BookEnLevel = 'story' | 'readers' | 'early-chapter' | 'middle-chapter' | 'chapter' | 'novel';
|
|
9
|
+
/** 출판 연령등급 */
|
|
10
|
+
export type PublishAgeRating = 'all' | '12' | '15' | '19';
|
|
11
|
+
/** 책 상태 (라이프사이클) */
|
|
12
|
+
export type BookStatus = 'draft' | 'pending' | 'published' | 'suspended';
|
|
13
|
+
export declare const BookLanguageLabel: {
|
|
14
|
+
readonly ko: "한국어";
|
|
15
|
+
readonly en: "English";
|
|
16
|
+
};
|
|
17
|
+
export declare const BookLengthLabel: {
|
|
18
|
+
readonly short: "단편";
|
|
19
|
+
readonly medium: "중편";
|
|
20
|
+
readonly long: "장편";
|
|
21
|
+
};
|
|
22
|
+
export declare const BookGenreLabel: {
|
|
23
|
+
readonly fiction: "문학";
|
|
24
|
+
readonly 'non-fiction': "비문학";
|
|
25
|
+
readonly other: "기타";
|
|
26
|
+
};
|
|
27
|
+
export declare const BookEnLevelLabel: {
|
|
28
|
+
readonly story: "스토리";
|
|
29
|
+
readonly readers: "리더스";
|
|
30
|
+
readonly 'early-chapter': "얼리챕터";
|
|
31
|
+
readonly 'middle-chapter': "미들챕터";
|
|
32
|
+
readonly chapter: "챕터";
|
|
33
|
+
readonly novel: "노블";
|
|
34
|
+
};
|
|
35
|
+
export declare const PublishAgeRatingLabel: {
|
|
36
|
+
readonly all: "전체이용가";
|
|
37
|
+
readonly '12': "12세 이용가";
|
|
38
|
+
readonly '15': "15세 이용가";
|
|
39
|
+
readonly '19': "19세 이용가";
|
|
40
|
+
};
|
|
41
|
+
/** 권장 연령 범위 (5~19세) */
|
|
42
|
+
export declare const BOOK_AGE_MIN = 5;
|
|
43
|
+
export declare const BOOK_AGE_MAX = 19;
|
|
44
|
+
/** 새 책 생성 시 기본값 */
|
|
45
|
+
export declare const DEFAULT_BOOK_META: {
|
|
46
|
+
readonly title: "나의 책";
|
|
47
|
+
readonly language: BookLanguage;
|
|
48
|
+
readonly age: 5;
|
|
49
|
+
readonly length: BookLength;
|
|
50
|
+
readonly genre: BookGenre;
|
|
51
|
+
readonly quiz_retry_allowed: true;
|
|
52
|
+
readonly ar_index: 3;
|
|
53
|
+
readonly lexile_index: 600;
|
|
54
|
+
};
|
|
55
|
+
/** AR 지수 범위별 설명 (소수점 1자리 기준) */
|
|
56
|
+
export declare const AR_INDEX_RANGES: readonly [{
|
|
57
|
+
readonly min: 0;
|
|
58
|
+
readonly max: 1.9;
|
|
59
|
+
readonly level: "유아 ~ 초1";
|
|
60
|
+
readonly description: "그림책, 아주 짧은 문장";
|
|
61
|
+
}, {
|
|
62
|
+
readonly min: 2;
|
|
63
|
+
readonly max: 2.9;
|
|
64
|
+
readonly level: "초2";
|
|
65
|
+
readonly description: "기초 리더북";
|
|
66
|
+
}, {
|
|
67
|
+
readonly min: 3;
|
|
68
|
+
readonly max: 3.9;
|
|
69
|
+
readonly level: "초3";
|
|
70
|
+
readonly description: "챕터북 시작";
|
|
71
|
+
}, {
|
|
72
|
+
readonly min: 4;
|
|
73
|
+
readonly max: 4.9;
|
|
74
|
+
readonly level: "초4";
|
|
75
|
+
readonly description: "본격적인 이야기 구조";
|
|
76
|
+
}, {
|
|
77
|
+
readonly min: 5;
|
|
78
|
+
readonly max: 5.9;
|
|
79
|
+
readonly level: "초5";
|
|
80
|
+
readonly description: "어휘·문장 길이 증가";
|
|
81
|
+
}, {
|
|
82
|
+
readonly min: 6;
|
|
83
|
+
readonly max: 6.9;
|
|
84
|
+
readonly level: "초6";
|
|
85
|
+
readonly description: "논픽션 비중 증가";
|
|
86
|
+
}, {
|
|
87
|
+
readonly min: 7;
|
|
88
|
+
readonly max: 8.9;
|
|
89
|
+
readonly level: "중학생";
|
|
90
|
+
readonly description: "복합 문장, 추론 필요";
|
|
91
|
+
}, {
|
|
92
|
+
readonly min: 9;
|
|
93
|
+
readonly max: 10.9;
|
|
94
|
+
readonly level: "고등학생";
|
|
95
|
+
readonly description: "문학 작품, 추상 개념";
|
|
96
|
+
}, {
|
|
97
|
+
readonly min: 11;
|
|
98
|
+
readonly max: 12;
|
|
99
|
+
readonly level: "고급";
|
|
100
|
+
readonly description: "성인 소설·고전";
|
|
101
|
+
}];
|
|
102
|
+
/** Lexile 지수 범위별 설명 */
|
|
103
|
+
export declare const LEXILE_INDEX_RANGES: readonly [{
|
|
104
|
+
readonly min: 0;
|
|
105
|
+
readonly max: 200;
|
|
106
|
+
readonly level: "유아";
|
|
107
|
+
readonly description: "알파벳·기초 단어";
|
|
108
|
+
}, {
|
|
109
|
+
readonly min: 200;
|
|
110
|
+
readonly max: 400;
|
|
111
|
+
readonly level: "초1";
|
|
112
|
+
readonly description: "아주 쉬운 문장";
|
|
113
|
+
}, {
|
|
114
|
+
readonly min: 400;
|
|
115
|
+
readonly max: 600;
|
|
116
|
+
readonly level: "초2";
|
|
117
|
+
readonly description: "간단한 스토리";
|
|
118
|
+
}, {
|
|
119
|
+
readonly min: 600;
|
|
120
|
+
readonly max: 800;
|
|
121
|
+
readonly level: "초3";
|
|
122
|
+
readonly description: "챕터북";
|
|
123
|
+
}, {
|
|
124
|
+
readonly min: 800;
|
|
125
|
+
readonly max: 1000;
|
|
126
|
+
readonly level: "초4";
|
|
127
|
+
readonly description: "정보량 증가";
|
|
128
|
+
}, {
|
|
129
|
+
readonly min: 1000;
|
|
130
|
+
readonly max: 1200;
|
|
131
|
+
readonly level: "초5~6";
|
|
132
|
+
readonly description: "교과서 수준";
|
|
133
|
+
}, {
|
|
134
|
+
readonly min: 1200;
|
|
135
|
+
readonly max: 1400;
|
|
136
|
+
readonly level: "중학생";
|
|
137
|
+
readonly description: "추론·비판적 읽기";
|
|
138
|
+
}, {
|
|
139
|
+
readonly min: 1400;
|
|
140
|
+
readonly max: 1600;
|
|
141
|
+
readonly level: "고등학생";
|
|
142
|
+
readonly description: "문학·비문학 혼합";
|
|
143
|
+
}, {
|
|
144
|
+
readonly min: 1600;
|
|
145
|
+
readonly max: 2000;
|
|
146
|
+
readonly level: "성인";
|
|
147
|
+
readonly description: "학술·고전 문학";
|
|
148
|
+
}];
|
|
149
|
+
/** AR 지수로 해당 범위 설명 조회 */
|
|
150
|
+
export declare const getARDescription: (ar: number) => {
|
|
151
|
+
readonly min: 0;
|
|
152
|
+
readonly max: 1.9;
|
|
153
|
+
readonly level: "유아 ~ 초1";
|
|
154
|
+
readonly description: "그림책, 아주 짧은 문장";
|
|
155
|
+
} | {
|
|
156
|
+
readonly min: 2;
|
|
157
|
+
readonly max: 2.9;
|
|
158
|
+
readonly level: "초2";
|
|
159
|
+
readonly description: "기초 리더북";
|
|
160
|
+
} | {
|
|
161
|
+
readonly min: 3;
|
|
162
|
+
readonly max: 3.9;
|
|
163
|
+
readonly level: "초3";
|
|
164
|
+
readonly description: "챕터북 시작";
|
|
165
|
+
} | {
|
|
166
|
+
readonly min: 4;
|
|
167
|
+
readonly max: 4.9;
|
|
168
|
+
readonly level: "초4";
|
|
169
|
+
readonly description: "본격적인 이야기 구조";
|
|
170
|
+
} | {
|
|
171
|
+
readonly min: 5;
|
|
172
|
+
readonly max: 5.9;
|
|
173
|
+
readonly level: "초5";
|
|
174
|
+
readonly description: "어휘·문장 길이 증가";
|
|
175
|
+
} | {
|
|
176
|
+
readonly min: 6;
|
|
177
|
+
readonly max: 6.9;
|
|
178
|
+
readonly level: "초6";
|
|
179
|
+
readonly description: "논픽션 비중 증가";
|
|
180
|
+
} | {
|
|
181
|
+
readonly min: 7;
|
|
182
|
+
readonly max: 8.9;
|
|
183
|
+
readonly level: "중학생";
|
|
184
|
+
readonly description: "복합 문장, 추론 필요";
|
|
185
|
+
} | {
|
|
186
|
+
readonly min: 9;
|
|
187
|
+
readonly max: 10.9;
|
|
188
|
+
readonly level: "고등학생";
|
|
189
|
+
readonly description: "문학 작품, 추상 개념";
|
|
190
|
+
} | {
|
|
191
|
+
readonly min: 11;
|
|
192
|
+
readonly max: 12;
|
|
193
|
+
readonly level: "고급";
|
|
194
|
+
readonly description: "성인 소설·고전";
|
|
195
|
+
} | undefined;
|
|
196
|
+
/** Lexile 지수로 해당 범위 설명 조회 */
|
|
197
|
+
export declare const getLexileDescription: (lexile: number) => {
|
|
198
|
+
readonly min: 0;
|
|
199
|
+
readonly max: 200;
|
|
200
|
+
readonly level: "유아";
|
|
201
|
+
readonly description: "알파벳·기초 단어";
|
|
202
|
+
} | {
|
|
203
|
+
readonly min: 200;
|
|
204
|
+
readonly max: 400;
|
|
205
|
+
readonly level: "초1";
|
|
206
|
+
readonly description: "아주 쉬운 문장";
|
|
207
|
+
} | {
|
|
208
|
+
readonly min: 400;
|
|
209
|
+
readonly max: 600;
|
|
210
|
+
readonly level: "초2";
|
|
211
|
+
readonly description: "간단한 스토리";
|
|
212
|
+
} | {
|
|
213
|
+
readonly min: 600;
|
|
214
|
+
readonly max: 800;
|
|
215
|
+
readonly level: "초3";
|
|
216
|
+
readonly description: "챕터북";
|
|
217
|
+
} | {
|
|
218
|
+
readonly min: 800;
|
|
219
|
+
readonly max: 1000;
|
|
220
|
+
readonly level: "초4";
|
|
221
|
+
readonly description: "정보량 증가";
|
|
222
|
+
} | {
|
|
223
|
+
readonly min: 1000;
|
|
224
|
+
readonly max: 1200;
|
|
225
|
+
readonly level: "초5~6";
|
|
226
|
+
readonly description: "교과서 수준";
|
|
227
|
+
} | {
|
|
228
|
+
readonly min: 1200;
|
|
229
|
+
readonly max: 1400;
|
|
230
|
+
readonly level: "중학생";
|
|
231
|
+
readonly description: "추론·비판적 읽기";
|
|
232
|
+
} | {
|
|
233
|
+
readonly min: 1400;
|
|
234
|
+
readonly max: 1600;
|
|
235
|
+
readonly level: "고등학생";
|
|
236
|
+
readonly description: "문학·비문학 혼합";
|
|
237
|
+
} | {
|
|
238
|
+
readonly min: 1600;
|
|
239
|
+
readonly max: 2000;
|
|
240
|
+
readonly level: "성인";
|
|
241
|
+
readonly description: "학술·고전 문학";
|
|
242
|
+
} | undefined;
|
|
243
|
+
/** 어절 수 → 재생 분수 계산 (200 WPM 기준) */
|
|
244
|
+
export declare const calcSoundMinutes: (wordCount: number) => number;
|
|
245
|
+
/** 언어 옵션 (UI Select용) */
|
|
246
|
+
export declare const getLanguageOptions: () => {
|
|
247
|
+
value: BookLanguage;
|
|
248
|
+
label: "한국어" | "English";
|
|
249
|
+
}[];
|
|
250
|
+
/** 길이 옵션 (UI Select용) */
|
|
251
|
+
export declare const getLengthOptions: () => {
|
|
252
|
+
value: BookLength;
|
|
253
|
+
label: "단편" | "중편" | "장편";
|
|
254
|
+
}[];
|
|
255
|
+
/** 장르 옵션 (UI Select용) */
|
|
256
|
+
export declare const getGenreOptions: () => {
|
|
257
|
+
value: BookGenre;
|
|
258
|
+
label: "문학" | "비문학" | "기타";
|
|
259
|
+
}[];
|
|
260
|
+
/** 영어레벨 옵션 (UI Select용) */
|
|
261
|
+
export declare const getEnLevelOptions: () => {
|
|
262
|
+
value: BookEnLevel;
|
|
263
|
+
label: "스토리" | "리더스" | "얼리챕터" | "미들챕터" | "챕터" | "노블";
|
|
264
|
+
}[];
|
|
265
|
+
/** 출판 연령등급 옵션 (UI Select용) */
|
|
266
|
+
export declare const getAgeRatingOptions: () => {
|
|
267
|
+
value: PublishAgeRating;
|
|
268
|
+
label: "전체이용가" | "12세 이용가" | "15세 이용가" | "19세 이용가";
|
|
269
|
+
}[];
|
|
270
|
+
/** 권장 연령 옵션 (5~19세) */
|
|
271
|
+
export declare const getAgeOptions: () => {
|
|
272
|
+
value: number;
|
|
273
|
+
label: string;
|
|
274
|
+
}[];
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ========== 리터럴 유니온 타입 ==========
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.getAgeOptions = exports.getAgeRatingOptions = exports.getEnLevelOptions = exports.getGenreOptions = exports.getLengthOptions = exports.getLanguageOptions = exports.calcSoundMinutes = exports.getLexileDescription = exports.getARDescription = exports.LEXILE_INDEX_RANGES = exports.AR_INDEX_RANGES = exports.DEFAULT_BOOK_META = exports.BOOK_AGE_MAX = exports.BOOK_AGE_MIN = exports.PublishAgeRatingLabel = exports.BookEnLevelLabel = exports.BookGenreLabel = exports.BookLengthLabel = exports.BookLanguageLabel = void 0;
|
|
5
|
+
// ========== 라벨 (UI 표시용) ==========
|
|
6
|
+
exports.BookLanguageLabel = {
|
|
7
|
+
ko: '한국어',
|
|
8
|
+
en: 'English',
|
|
9
|
+
};
|
|
10
|
+
exports.BookLengthLabel = {
|
|
11
|
+
short: '단편',
|
|
12
|
+
medium: '중편',
|
|
13
|
+
long: '장편',
|
|
14
|
+
};
|
|
15
|
+
exports.BookGenreLabel = {
|
|
16
|
+
fiction: '문학',
|
|
17
|
+
'non-fiction': '비문학',
|
|
18
|
+
other: '기타',
|
|
19
|
+
};
|
|
20
|
+
exports.BookEnLevelLabel = {
|
|
21
|
+
story: '스토리',
|
|
22
|
+
readers: '리더스',
|
|
23
|
+
'early-chapter': '얼리챕터',
|
|
24
|
+
'middle-chapter': '미들챕터',
|
|
25
|
+
chapter: '챕터',
|
|
26
|
+
novel: '노블',
|
|
27
|
+
};
|
|
28
|
+
exports.PublishAgeRatingLabel = {
|
|
29
|
+
all: '전체이용가',
|
|
30
|
+
'12': '12세 이용가',
|
|
31
|
+
'15': '15세 이용가',
|
|
32
|
+
'19': '19세 이용가',
|
|
33
|
+
};
|
|
34
|
+
// ========== 상수 ==========
|
|
35
|
+
/** 권장 연령 범위 (5~19세) */
|
|
36
|
+
exports.BOOK_AGE_MIN = 5;
|
|
37
|
+
exports.BOOK_AGE_MAX = 19;
|
|
38
|
+
/** 새 책 생성 시 기본값 */
|
|
39
|
+
exports.DEFAULT_BOOK_META = {
|
|
40
|
+
title: '나의 책',
|
|
41
|
+
language: 'en',
|
|
42
|
+
age: 5,
|
|
43
|
+
length: 'short',
|
|
44
|
+
genre: 'fiction',
|
|
45
|
+
quiz_retry_allowed: true,
|
|
46
|
+
ar_index: 3.0,
|
|
47
|
+
lexile_index: 600,
|
|
48
|
+
};
|
|
49
|
+
// ========== AR / Lexile 지수 ==========
|
|
50
|
+
/** AR 지수 범위별 설명 (소수점 1자리 기준) */
|
|
51
|
+
exports.AR_INDEX_RANGES = [
|
|
52
|
+
{ min: 0.0, max: 1.9, level: '유아 ~ 초1', description: '그림책, 아주 짧은 문장' },
|
|
53
|
+
{ min: 2.0, max: 2.9, level: '초2', description: '기초 리더북' },
|
|
54
|
+
{ min: 3.0, max: 3.9, level: '초3', description: '챕터북 시작' },
|
|
55
|
+
{ min: 4.0, max: 4.9, level: '초4', description: '본격적인 이야기 구조' },
|
|
56
|
+
{ min: 5.0, max: 5.9, level: '초5', description: '어휘·문장 길이 증가' },
|
|
57
|
+
{ min: 6.0, max: 6.9, level: '초6', description: '논픽션 비중 증가' },
|
|
58
|
+
{ min: 7.0, max: 8.9, level: '중학생', description: '복합 문장, 추론 필요' },
|
|
59
|
+
{ min: 9.0, max: 10.9, level: '고등학생', description: '문학 작품, 추상 개념' },
|
|
60
|
+
{ min: 11.0, max: 12.0, level: '고급', description: '성인 소설·고전' },
|
|
61
|
+
];
|
|
62
|
+
/** Lexile 지수 범위별 설명 */
|
|
63
|
+
exports.LEXILE_INDEX_RANGES = [
|
|
64
|
+
{ min: 0, max: 200, level: '유아', description: '알파벳·기초 단어' },
|
|
65
|
+
{ min: 200, max: 400, level: '초1', description: '아주 쉬운 문장' },
|
|
66
|
+
{ min: 400, max: 600, level: '초2', description: '간단한 스토리' },
|
|
67
|
+
{ min: 600, max: 800, level: '초3', description: '챕터북' },
|
|
68
|
+
{ min: 800, max: 1000, level: '초4', description: '정보량 증가' },
|
|
69
|
+
{ min: 1000, max: 1200, level: '초5~6', description: '교과서 수준' },
|
|
70
|
+
{ min: 1200, max: 1400, level: '중학생', description: '추론·비판적 읽기' },
|
|
71
|
+
{ min: 1400, max: 1600, level: '고등학생', description: '문학·비문학 혼합' },
|
|
72
|
+
{ min: 1600, max: 2000, level: '성인', description: '학술·고전 문학' },
|
|
73
|
+
];
|
|
74
|
+
/** AR 지수로 해당 범위 설명 조회 */
|
|
75
|
+
const getARDescription = (ar) => exports.AR_INDEX_RANGES.find(r => ar >= r.min && ar <= r.max);
|
|
76
|
+
exports.getARDescription = getARDescription;
|
|
77
|
+
/** Lexile 지수로 해당 범위 설명 조회 */
|
|
78
|
+
const getLexileDescription = (lexile) => exports.LEXILE_INDEX_RANGES.find(r => lexile >= r.min && lexile <= r.max);
|
|
79
|
+
exports.getLexileDescription = getLexileDescription;
|
|
80
|
+
// ========== 헬퍼 함수 ==========
|
|
81
|
+
/** 어절 수 → 재생 분수 계산 (200 WPM 기준) */
|
|
82
|
+
const calcSoundMinutes = (wordCount) => Math.ceil(wordCount / 200);
|
|
83
|
+
exports.calcSoundMinutes = calcSoundMinutes;
|
|
84
|
+
/** 언어 옵션 (UI Select용) */
|
|
85
|
+
const getLanguageOptions = () => Object.entries(exports.BookLanguageLabel).map(([value, label]) => ({
|
|
86
|
+
value: value,
|
|
87
|
+
label,
|
|
88
|
+
}));
|
|
89
|
+
exports.getLanguageOptions = getLanguageOptions;
|
|
90
|
+
/** 길이 옵션 (UI Select용) */
|
|
91
|
+
const getLengthOptions = () => Object.entries(exports.BookLengthLabel).map(([value, label]) => ({
|
|
92
|
+
value: value,
|
|
93
|
+
label,
|
|
94
|
+
}));
|
|
95
|
+
exports.getLengthOptions = getLengthOptions;
|
|
96
|
+
/** 장르 옵션 (UI Select용) */
|
|
97
|
+
const getGenreOptions = () => Object.entries(exports.BookGenreLabel).map(([value, label]) => ({
|
|
98
|
+
value: value,
|
|
99
|
+
label,
|
|
100
|
+
}));
|
|
101
|
+
exports.getGenreOptions = getGenreOptions;
|
|
102
|
+
/** 영어레벨 옵션 (UI Select용) */
|
|
103
|
+
const getEnLevelOptions = () => Object.entries(exports.BookEnLevelLabel).map(([value, label]) => ({
|
|
104
|
+
value: value,
|
|
105
|
+
label,
|
|
106
|
+
}));
|
|
107
|
+
exports.getEnLevelOptions = getEnLevelOptions;
|
|
108
|
+
/** 출판 연령등급 옵션 (UI Select용) */
|
|
109
|
+
const getAgeRatingOptions = () => Object.entries(exports.PublishAgeRatingLabel).map(([value, label]) => ({
|
|
110
|
+
value: value,
|
|
111
|
+
label,
|
|
112
|
+
}));
|
|
113
|
+
exports.getAgeRatingOptions = getAgeRatingOptions;
|
|
114
|
+
/** 권장 연령 옵션 (5~19세) */
|
|
115
|
+
const getAgeOptions = () => Array.from({ length: exports.BOOK_AGE_MAX - exports.BOOK_AGE_MIN + 1 }, (_, i) => ({
|
|
116
|
+
value: exports.BOOK_AGE_MIN + i,
|
|
117
|
+
label: `만 ${exports.BOOK_AGE_MIN + i}세`,
|
|
118
|
+
}));
|
|
119
|
+
exports.getAgeOptions = getAgeOptions;
|