# ───────────────────────────────────────────── # app/components.py # Reusable Streamlit UI building blocks. # Keeps main.py clean and focused on flow logic. # ───────────────────────────────────────────── import streamlit as st from src.mcq_builder import MCQ def render_question_card(mcq: MCQ, index: int) -> str | None: """ Render a question with labelled radio button options. Returns the selected option label ("A"/"B"/"C"/"D") or None. """ st.markdown(f"### Q{index + 1}. {mcq.question}") # Build labelled options: ["A. Paris", "B. London", ...] labelled_options = [f"{chr(65+i)}. {opt}" for i, opt in enumerate(mcq.options)] # Restore previous selection if user came back to this question prev_index = st.session_state.user_answers[index] default = prev_index if prev_index >= 0 else 0 selected = st.radio( label = "Select your answer:", options = labelled_options, index = default, key = f"q_{index}", label_visibility = "collapsed", ) # Return just the letter ("A", "B", etc.) return selected[0] if selected else None def render_result_card(result: dict, question_num: int): """ Render a single question's result with colour coding. Green = correct, Red = wrong. """ is_correct = result["is_correct"] icon = "✅" if is_correct else "❌" color = "#d4edda" if is_correct else "#f8d7da" border = "#28a745" if is_correct else "#dc3545" with st.container(): st.markdown( f"""
{icon} Q{question_num}: {result['question']}
""", unsafe_allow_html=True, ) col1, col2 = st.columns(2) with col1: st.write(f"**Your answer:** {result['your_answer']}") with col2: if not is_correct: st.write(f"**Correct answer:** {result['correct_answer']}") else: st.write("**Correct!**") with st.expander("See explanation"): st.info(result["explanation"]) def render_score_summary(result: dict): """ Render the score banner at the top of the results screen. """ score = result["score"] total = result["total"] percentage = result["percentage"] feedback = result["feedback"] # Choose colour based on score if percentage >= 80: color = "#d4edda"; border = "#28a745" elif percentage >= 60: color = "#fff3cd"; border = "#ffc107" else: color = "#f8d7da"; border = "#dc3545" st.markdown( f"""

{score} / {total}

{percentage}%

{feedback}

""", unsafe_allow_html=True, ) # Metric columns for quick glance st.markdown("
", unsafe_allow_html=True) c1, c2, c3 = st.columns(3) c1.metric("Correct", score) c2.metric("Wrong", total - score) c3.metric("Score", f"{percentage}%")