first commit
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
class TestPage extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this.className = 'screen';
|
||||
this.renderQuestion();
|
||||
}
|
||||
|
||||
renderHeader(step) {
|
||||
const wrapper = document.createElement('div');
|
||||
const counter = document.createElement('span');
|
||||
counter.className = 'muted';
|
||||
counter.textContent = `${step} / ${state.questions.length}`;
|
||||
|
||||
const topbar = createTopbar([counter]);
|
||||
topbar.querySelector('.brand').onclick = () => {
|
||||
if (confirm('처음 화면으로 돌아갈까요? 지금까지의 응답은 사라집니다.')) {
|
||||
showStartScreen();
|
||||
}
|
||||
};
|
||||
|
||||
const track = document.createElement('div');
|
||||
track.className = 'progress-track';
|
||||
const fill = document.createElement('div');
|
||||
fill.className = 'progress-fill';
|
||||
fill.style.width = `${(step / state.questions.length) * 100}%`;
|
||||
track.appendChild(fill);
|
||||
|
||||
wrapper.append(topbar, track);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
renderQuestion() {
|
||||
const index = state.current;
|
||||
const question = state.questions[index];
|
||||
let selected = state.answers[index] ?? null;
|
||||
let confidence = state.confidences[index] ?? null;
|
||||
|
||||
this.replaceChildren(this.renderHeader(index + 1));
|
||||
|
||||
const card = document.createElement('div');
|
||||
card.className = 'card';
|
||||
|
||||
const title = document.createElement('p');
|
||||
title.className = 'question-text';
|
||||
title.textContent = `${index + 1}. ${question.question}`;
|
||||
card.appendChild(title);
|
||||
|
||||
const list = document.createElement('ul');
|
||||
list.className = 'options';
|
||||
const optionButtons = question.options.map((option, i) => {
|
||||
const item = document.createElement('li');
|
||||
const button = document.createElement('button');
|
||||
button.type = 'button';
|
||||
button.className = 'option';
|
||||
button.setAttribute('aria-pressed', String(option === selected));
|
||||
|
||||
const key = document.createElement('span');
|
||||
key.className = 'key';
|
||||
key.textContent = String.fromCharCode(65 + i);
|
||||
const text = document.createElement('span');
|
||||
text.textContent = option;
|
||||
|
||||
button.append(key, text);
|
||||
button.onclick = () => {
|
||||
selected = option;
|
||||
optionButtons.forEach((b) => b.setAttribute('aria-pressed', 'false'));
|
||||
button.setAttribute('aria-pressed', 'true');
|
||||
updateSubmitState();
|
||||
};
|
||||
|
||||
item.appendChild(button);
|
||||
list.appendChild(item);
|
||||
return button;
|
||||
});
|
||||
card.appendChild(list);
|
||||
|
||||
const confidenceBox = document.createElement('div');
|
||||
confidenceBox.className = 'confidence';
|
||||
const confidenceLabel = document.createElement('label');
|
||||
confidenceLabel.textContent = '이 답에 얼마나 확신하나요?';
|
||||
confidenceBox.append(
|
||||
confidenceLabel,
|
||||
createChipGroup(CONFIDENCE, {
|
||||
selected: confidence,
|
||||
onSelect: (value) => {
|
||||
confidence = value;
|
||||
updateSubmitState();
|
||||
},
|
||||
})
|
||||
);
|
||||
card.appendChild(confidenceBox);
|
||||
|
||||
const actions = document.createElement('div');
|
||||
actions.className = 'actions';
|
||||
if (index > 0) {
|
||||
actions.appendChild(createButton('이전 문제', () => history.back(), 'ghost'));
|
||||
}
|
||||
|
||||
const isLast = index === state.questions.length - 1;
|
||||
const submitButton = document.createElement('button');
|
||||
submitButton.className = 'primary';
|
||||
submitButton.textContent = isLast ? '결과 보기' : '다음 문제';
|
||||
submitButton.onclick = () => {
|
||||
state.answers[index] = selected;
|
||||
state.confidences[index] = confidence;
|
||||
if (isLast) {
|
||||
finishQuiz();
|
||||
} else {
|
||||
goToQuestion(index + 1);
|
||||
}
|
||||
};
|
||||
actions.appendChild(submitButton);
|
||||
card.appendChild(actions);
|
||||
|
||||
const updateSubmitState = () => {
|
||||
submitButton.disabled = !(selected && confidence);
|
||||
};
|
||||
updateSubmitState();
|
||||
|
||||
this.appendChild(card);
|
||||
|
||||
this.onkeydown = (event) => {
|
||||
if (event.target.tagName === 'INPUT') return;
|
||||
const fromLetter = event.key.toUpperCase().charCodeAt(0) - 65;
|
||||
const fromNumber = Number(event.key) - 1;
|
||||
const at = optionButtons[fromLetter] ?? optionButtons[fromNumber];
|
||||
if (event.key.length === 1 && at) {
|
||||
at.click();
|
||||
at.focus();
|
||||
}
|
||||
};
|
||||
this.tabIndex = -1;
|
||||
this.focus({ preventScroll: true });
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('test-page', TestPage);
|
||||
Reference in New Issue
Block a user