first commit

This commit is contained in:
2026-08-10 21:35:17 +09:00
commit 02d9d0785b
22 changed files with 3853 additions and 0 deletions
+144
View File
@@ -0,0 +1,144 @@
const DIFFICULTIES = [
{ id: 'easy', label: '쉬움' },
{ id: 'medium', label: '보통' },
{ id: 'hard', label: '어려움' },
];
const fillSelect = (select, values) => {
select.replaceChildren(
...values.map((value) => {
const option = document.createElement('option');
option.value = value;
option.textContent = value;
return option;
})
);
select.disabled = values.length === 0;
};
class OptionPage extends HTMLElement {
async connectedCallback() {
this.className = 'screen';
this.innerHTML = `
<div class="hero">
<picture>
<source srcset="/public/images/logo-dark.png"
media="(prefers-color-scheme: dark)">
<img src="/public/images/logo-light.png" alt="CogMind">
</picture>
<h1>공부의 시작은 나를 아는것</h1>
<p>문제를 풀면 AI가 여러분을 메타인지하고 피드백 해줘요.</p>
</div>
<div class="card">
<div class="field">
<label for="student">이름</label>
<input id="student" type="text" placeholder="예: 이승준" autocomplete="off"
maxlength="30">
</div>
<div class="field">
<label for="school">학교 종류</label>
<select id="school"></select>
</div>
<div class="row" style="margin-top:16px">
<div class="field" style="margin:0">
<label for="subject">과목</label>
<select id="subject"></select>
</div>
<div class="field" style="margin:0">
<label for="chapter">단원</label>
<select id="chapter"></select>
</div>
</div>
<div class="row" style="margin-top:16px">
<div class="field" style="margin:0">
<label>난이도</label>
<div id="difficulty"></div>
</div>
<div class="field" style="margin:0">
<label for="amount">문항 수 (120)</label>
<input id="amount" type="number" min="1" max="20" value="5">
</div>
</div>
<div id="error"></div>
<button class="primary block" id="start" style="margin-top:24px">
학습 진단 시작하기
</button>
<button class="block" id="history" style="margin-top:10px">
지난 기록 보기
</button>
</div>
`;
const errorBox = this.querySelector('#error');
const showMessage = (message) => {
errorBox.className = message ? 'error-box' : '';
errorBox.textContent = message ?? '';
};
if (this.dataset.error) showMessage(this.dataset.error);
this.querySelector('#history').onclick = () => showHistoryScreen();
let difficulty = 'medium';
this.querySelector('#difficulty').appendChild(
createChipGroup(DIFFICULTIES, {
selected: difficulty,
onSelect: (value) => {
difficulty = value;
},
})
);
const school = this.querySelector('#school');
const subject = this.querySelector('#subject');
const chapter = this.querySelector('#chapter');
const student = this.querySelector('#student');
const amount = this.querySelector('#amount');
const startButton = this.querySelector('#start');
let chapters = {};
const onSchoolChange = () => {
fillSelect(subject, Object.keys(chapters[school.value] ?? {}));
onSubjectChange();
};
const onSubjectChange = () => {
fillSelect(chapter, chapters[school.value]?.[subject.value] ?? []);
};
school.onchange = onSchoolChange;
subject.onchange = onSubjectChange;
startButton.disabled = true;
try {
chapters = await api.chapters();
fillSelect(school, Object.keys(chapters));
onSchoolChange();
startButton.disabled = false;
} catch (err) {
showMessage(`단원 목록을 불러오지 못했습니다. ${err.message}`);
return;
}
const submit = () => {
if (!chapter.value) {
showMessage('과목과 단원을 선택해 주세요.');
return;
}
startQuiz(
{
student: student.value.trim() || '학생',
school: school.value,
subject: subject.value,
chapter: chapter.value,
difficulty,
},
Math.min(Math.max(Number(amount.value) || 5, 1), 20)
);
};
startButton.onclick = submit;
student.addEventListener('keydown', (event) => {
if (event.key === 'Enter') submit();
});
}
}
customElements.define('option-page', OptionPage);