Spaces:
Sleeping
Sleeping
| # utils/ui_components.py | |
| import streamlit as st | |
| import plotly.graph_objects as go | |
| from config.settings import BADGES | |
| from config.themes import THEMES | |
| def apply_custom_theme(theme_name: str): | |
| """Applies a custom theme using CSS variables.""" | |
| theme = THEMES.get(theme_name, THEMES["default"]) | |
| css = f""" | |
| <style> | |
| :root {{ | |
| --primary-color: {theme["primary_color"]}; | |
| --background-color: {theme["background_color"]}; | |
| --secondary-background-color: {theme["secondary_background_color"]}; | |
| --text-color: {theme["text_color"]}; | |
| --font: {theme["font"]}; | |
| }} | |
| /* Apply background color to the main Streamlit elements */ | |
| .stApp {{ | |
| background-color: var(--background-color); | |
| color: var(--text-color); | |
| }} | |
| .stSidebar {{ | |
| background-color: var(--secondary-background-color); | |
| }} | |
| </style> | |
| """ | |
| st.markdown(css, unsafe_allow_html=True) | |
| def display_user_stats(stats: dict): | |
| """Displays user statistics in a dashboard format.""" | |
| cols = st.columns(4) | |
| with cols[0]: | |
| st.metric("Total Score", f"{stats.get('total_score', 0):,}") | |
| with cols[1]: | |
| st.metric("Quizzes Played", stats.get("quizzes_completed", 0)) | |
| with cols[2]: | |
| st.metric("Current Streak", f"🔥 {stats.get('current_streak', 0)}") | |
| with cols[3]: | |
| st.metric("Best Streak", f"⭐ {stats.get('best_streak', 0)}") | |
| def display_badges(earned_badges: list): | |
| """Displays earned badges.""" | |
| if not earned_badges: | |
| return | |
| st.markdown("### 🏆 Your Badges") | |
| cols = st.columns(len(BADGES)) | |
| for i, badge_id in enumerate(earned_badges): | |
| badge = BADGES.get(badge_id) | |
| if badge: | |
| with cols[i]: | |
| st.markdown( | |
| f"<div style='text-align: center; padding: 10px; border-radius: 10px; background-color: var(--secondary-background-color);'>", | |
| unsafe_allow_html=True, | |
| ) | |
| st.markdown( | |
| f"<span style='font-size: 50px;'>{badge['icon']}</span>", | |
| unsafe_allow_html=True, | |
| ) | |
| st.markdown(f"**{badge['name']}**") | |
| st.markdown(f"</div>", unsafe_allow_html=True) | |
| def create_progress_chart(stats: dict) -> go.Figure: | |
| """Creates a progress chart for the user.""" | |
| history = stats.get("quiz_history", []) | |
| if not history: | |
| return go.Figure() | |
| dates = [item["timestamp"] for item in history] | |
| scores = [item["percentage"] for item in history] | |
| fig = go.Figure() | |
| fig.add_trace(go.Scatter(x=dates, y=scores, mode="lines+markers", name="Score %")) | |
| fig.update_layout( | |
| title="Quiz Performance Over Time", | |
| xaxis_title="Date", | |
| yaxis_title="Score (%)", | |
| yaxis_range=[0, 100], | |
| ) | |
| return fig | |
| def animated_success(message: str): | |
| """Displays an animated success message.""" | |
| st.success(message) | |
| def create_quiz_card(question: str, options: list): | |
| """Creates a card for a multiple-choice question.""" | |
| st.subheader(question) | |
| answer = st.radio( | |
| "Select your answer:", options, index=None, label_visibility="collapsed" | |
| ) | |
| return answer | |
| def render_flashcard(front_content: str, back_content: str, is_flipped: bool): | |
| """Renders a flippable flashcard.""" | |
| card_style = """ | |
| width: 100%; | |
| height: 300px; | |
| perspective: 1000px; | |
| """ | |
| flipper_style = f""" | |
| position: relative; | |
| width: 100%; | |
| height: 100%; | |
| transition: transform 0.6s; | |
| transform-style: preserve-3d; | |
| transform: {"rotateY(180deg)" if is_flipped else "none"}; | |
| """ | |
| face_style = """ | |
| position: absolute; | |
| width: 100%; | |
| height: 100%; | |
| -webkit-backface-visibility: hidden; | |
| backface-visibility: hidden; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| padding: 20px; | |
| border-radius: 10px; | |
| box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); | |
| """ | |
| front_style = ( | |
| f"{{face_style}} background-color: var(--primary-color); color: white;" | |
| ) | |
| back_style = f"{{face_style}} background-color: var(--secondary-background-color); color: var(--text-color); transform: rotateY(180deg);" | |
| st.markdown( | |
| f"<div style='{{card_style}}'><div style='{{flipper_style}}'> \ | |
| <div style='{{front_style}}'><div>{front_content}</div></div> \ | |
| <div style='{{back_style}}'><div>{back_content}</div></div> \ | |
| </div></div>", | |
| unsafe_allow_html=True, | |
| ) | |