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_vars = { | |
| "--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"], | |
| "--card-background": theme.get("card_background", "#FFFFFF"), | |
| "--shadow-light": theme.get("shadow_light", "0 4px 15px rgba(0, 0, 0, 0.05)"), | |
| "--shadow-medium": theme.get("shadow_medium", "0 8px 30px rgba(0, 0, 0, 0.1)"), | |
| "--highlight-color": theme.get("highlight_color", theme["primary_color"]), | |
| } | |
| css_vars_str = "\n".join([f"{key}: {value};" for key, value in css_vars.items()]) | |
| css = f""" | |
| <style> | |
| :root {{ {css_vars_str} }} | |
| .stApp {{ background-color: var(--background-color); color: var(--text-color); }} | |
| .stSidebar {{ background-color: var(--secondary-background-color); }} | |
| .stButton>button {{ background-color: var(--primary-color); color: white; box-shadow: var(--shadow-light); }} | |
| .stButton>button:hover {{ background-color: var(--secondary-color); box-shadow: var(--shadow-medium); }} | |
| /* Add other theme styles here */ | |
| </style> | |
| """ | |
| st.markdown(css, unsafe_allow_html=True) | |
| def display_user_stats(stats: dict, ui: dict): | |
| """Displays user statistics in a dashboard format.""" | |
| cols = st.columns(4) | |
| with cols[0]: | |
| st.metric(ui.get("total_score", "Total Score"), f"{stats.get('total_score', 0):,}") | |
| with cols[1]: | |
| st.metric(ui.get("quizzes", "Quizzes Played"), stats.get("quizzes_completed", 0)) | |
| with cols[2]: | |
| st.metric(ui.get("current_streak", "Current Streak"), f"π₯ {stats.get('current_streak', 0)}") | |
| with cols[3]: | |
| st.metric(ui.get("best_streak", "Best Streak"), f"β {stats.get('best_streak', 0)}") | |
| def display_badges(earned_badges: list, ui: dict): | |
| """Displays earned badges.""" | |
| if not earned_badges: | |
| return | |
| st.markdown(f"### π {ui.get('your_badges', 'Your Badges')}") | |
| cols = st.columns(len(earned_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;'><span style='font-size: 50px;'>{badge['icon']}</span><br><b>{ui.get(badge['name'].lower(), badge['name'])}</b></div>", unsafe_allow_html=True) | |
| def create_progress_chart(stats: dict, ui: 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=ui.get("score", "Score") + " %")) | |
| fig.update_layout( | |
| title=ui.get("quiz_performance_over_time", "Quiz Performance Over Time"), | |
| xaxis_title=ui.get("date", "Date"), | |
| yaxis_title=f"{ui.get('score', 'Score')} (%)", | |
| yaxis_range=[0, 100], | |
| ) | |
| return fig | |
| def animated_success(message: str): | |
| """Displays an animated success message.""" | |
| st.markdown(f"<div class='pop-in'>{st.success(message)}</div>", unsafe_allow_html=True) | |
| def create_quiz_card(question: str, options: list, key: str): | |
| """Creates a card for a multiple-choice question.""" | |
| st.markdown(f"<div style='background-color: var(--card-background); padding: 20px; border-radius: 10px; box-shadow: var(--shadow-light);'>", unsafe_allow_html=True) | |
| st.subheader(question) | |
| st.session_state[key] = st.radio( | |
| "Select your answer:", | |
| options, | |
| index=None, | |
| key=f"{key}_radio", | |
| label_visibility="collapsed", | |
| ) | |
| st.markdown("</div>", unsafe_allow_html=True) | |
| 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: var(--shadow-light);" | |
| front_style = f"{face_style} background-color: var(--primary-color); color: white;" | |
| back_style = f"{face_style} background-color: var(--card-background); color: var(--text-color); transform: rotateY(180deg);" | |
| st.markdown( | |
| f"<div style='{card_style}'><div style='{flipper_style}'>" | |
| f"<div style='{front_style}'><div>{front_content}</div></div>" | |
| f"<div style='{back_style}'><div>{back_content}</div></div>" | |
| f"</div></div>", | |
| unsafe_allow_html=True, | |
| ) | |