문제 풀이 화면의 입력 항 진행 상태 표시 방법 개선

This commit is contained in:
2026-05-30 18:39:22 +09:00
parent 282e4d64cf
commit 33e065301f
4 changed files with 151 additions and 104 deletions
+43 -35
View File
@@ -9,31 +9,33 @@ interface VariableChoiceAnswerFormProps {
choices: [VariableTermChoice[], VariableTermChoice[]];
selectedChoiceIds: [string | null, string | null];
activeTermIndex: 0 | 1;
pendingChoiceLabels: [string, string];
onSelectChoice: (termIndex: 0 | 1, choiceId: string) => void;
onSubmit: () => void;
}
export default function VariableChoiceAnswerForm({
choices,
selectedChoiceIds,
activeTermIndex,
pendingChoiceLabels,
onSelectChoice,
onSubmit,
}: VariableChoiceAnswerFormProps) {
const firstChoiceRef = useRef<HTMLButtonElement>(null);
const submitButtonRef = useRef<HTMLButtonElement>(null);
const canSubmit = selectedChoiceIds[0] !== null && selectedChoiceIds[1] !== null;
const activeChoices = choices[activeTermIndex];
const activeChoices = [...choices[activeTermIndex]].sort(
(a, b) => a.coefficient - b.coefficient,
);
useEffect(() => {
firstChoiceRef.current?.focus();
}, [activeTermIndex]);
useEffect(() => {
if (canSubmit) {
submitButtonRef.current?.focus();
}
}, [canSubmit]);
function getSelectedChoice(index: 0 | 1) {
const selectedChoiceId = selectedChoiceIds[index];
if (!selectedChoiceId) return null;
return choices[index].find((choice) => choice.id === selectedChoiceId) ?? null;
}
return (
<div className="rounded-md bg-white p-6 shadow-sm ring-1 ring-slate-200">
@@ -42,32 +44,48 @@ export default function VariableChoiceAnswerForm({
<p className="text-sm font-semibold text-slate-500">
{activeTermIndex === 0 ? "첫째 항" : "둘째 항"} .
</p>
<p className="mt-1 text-base text-slate-700">
.
</p>
</div>
<div
className="inline-flex gap-1 rounded-md border border-slate-300 bg-slate-50 p-1"
role="group"
<ol
className="flex min-w-40 items-center gap-1"
aria-label="입력 항 진행 상태"
>
{selectedChoiceIds.map((choiceId, index) => {
const selected = activeTermIndex === index;
const selectedChoice = getSelectedChoice(index as 0 | 1);
const completed = choiceId !== null && selectedChoice !== null;
return (
<span
<li
key={index}
className={`inline-flex h-9 min-w-16 items-center justify-center rounded px-3 text-sm font-bold ${
selected
? "bg-emerald-700 text-white"
: "bg-white text-slate-700"
}`}
className="min-w-0 flex-1"
aria-label={`${index + 1}${
completed ? "선택 완료" : "미선택"
}${selected ? ", 현재 선택 중" : ""}`}
>
{choiceId ? `${index + 1}항 완료` : `${index + 1}`}
</span>
<span
className={`block truncate text-center text-xs font-bold ${
selected || completed ? "text-emerald-800" : "text-slate-500"
}`}
>
{completed ? (
<KatexRenderer latex={selectedChoice.latex} />
) : (
<KatexRenderer latex={pendingChoiceLabels[index]} />
)}
</span>
<span
className={`mt-1 block h-1.5 rounded-full ${
completed
? "bg-emerald-700"
: selected
? "bg-emerald-300 ring-1 ring-emerald-700"
: "bg-slate-200"
}`}
/>
</li>
);
})}
</div>
</ol>
</div>
<div
@@ -96,16 +114,6 @@ export default function VariableChoiceAnswerForm({
);
})}
</div>
<button
ref={submitButtonRef}
type="button"
onClick={onSubmit}
disabled={!canSubmit}
className="mt-5 inline-flex h-11 items-center justify-center rounded-md bg-slate-950 px-5 text-base font-semibold text-white transition hover:bg-slate-800 focus:outline-none focus:ring-2 focus:ring-slate-500 focus:ring-offset-2 disabled:cursor-not-allowed disabled:bg-slate-300"
>
</button>
</div>
);
}