lanna_lalala;- commited on
Commit Β·
9fd7a03
1
Parent(s): f3957b2
lesson css try
Browse files- phase/Student_view/lesson.py +72 -131
phase/Student_view/lesson.py
CHANGED
|
@@ -18,72 +18,6 @@ USE_LOCAL_DB = os.getenv("DISABLE_DB", "1") != "1"
|
|
| 18 |
|
| 19 |
FALLBACK_TAG = "<!--fallback-->"
|
| 20 |
|
| 21 |
-
|
| 22 |
-
# ---- NEW: minimal Markdown -> HTML helper (keeps cards as single HTML blocks)
|
| 23 |
-
def _md_to_html(text: str) -> str:
|
| 24 |
-
"""
|
| 25 |
-
Best-effort conversion so markdown-like lesson text can live *inside* a single HTML block.
|
| 26 |
-
Uses python-markdown if available; otherwise a tiny fallback that handles paragraphs + bullets.
|
| 27 |
-
"""
|
| 28 |
-
if not text:
|
| 29 |
-
return ""
|
| 30 |
-
try:
|
| 31 |
-
# If python-markdown is available, use it for better fidelity.
|
| 32 |
-
from markdown import markdown as _mk
|
| 33 |
-
return _mk(text, extensions=["extra", "sane_lists"])
|
| 34 |
-
except Exception:
|
| 35 |
-
# Fallback: paragraphs + simple lists
|
| 36 |
-
lines = text.strip().splitlines()
|
| 37 |
-
html_parts = []
|
| 38 |
-
in_ul = False
|
| 39 |
-
|
| 40 |
-
def close_ul():
|
| 41 |
-
nonlocal in_ul
|
| 42 |
-
if in_ul:
|
| 43 |
-
html_parts.append("</ul>")
|
| 44 |
-
in_ul = False
|
| 45 |
-
|
| 46 |
-
for ln in lines:
|
| 47 |
-
s = ln.rstrip()
|
| 48 |
-
if not s:
|
| 49 |
-
close_ul()
|
| 50 |
-
html_parts.append("<p></p>")
|
| 51 |
-
continue
|
| 52 |
-
|
| 53 |
-
# Headings (#, ##, ###) basic support
|
| 54 |
-
if s.startswith("### "):
|
| 55 |
-
close_ul()
|
| 56 |
-
html_parts.append(f"<h3>{s[4:].strip()}</h3>")
|
| 57 |
-
continue
|
| 58 |
-
if s.startswith("## "):
|
| 59 |
-
close_ul()
|
| 60 |
-
html_parts.append(f"<h2>{s[3:].strip()}</h2>")
|
| 61 |
-
continue
|
| 62 |
-
if s.startswith("# "):
|
| 63 |
-
close_ul()
|
| 64 |
-
html_parts.append(f"<h1>{s[2:].strip()}</h1>")
|
| 65 |
-
continue
|
| 66 |
-
|
| 67 |
-
# Bullet lines
|
| 68 |
-
bullet_prefixes = ("- ", "* ", "β’ ", "β ")
|
| 69 |
-
if s.startswith(bullet_prefixes):
|
| 70 |
-
if not in_ul:
|
| 71 |
-
html_parts.append("<ul>")
|
| 72 |
-
in_ul = True
|
| 73 |
-
html_parts.append(f"<li>{s[2:].strip()}</li>")
|
| 74 |
-
continue
|
| 75 |
-
|
| 76 |
-
# Regular paragraph
|
| 77 |
-
close_ul()
|
| 78 |
-
# light bold/italic
|
| 79 |
-
p = re.sub(r"\*\*(.+?)\*\*", r"<strong>\1</strong>", s)
|
| 80 |
-
p = re.sub(r"\*(.+?)\*", r"<em>\1</em>", p)
|
| 81 |
-
html_parts.append(f"<p>{p}</p>")
|
| 82 |
-
|
| 83 |
-
close_ul()
|
| 84 |
-
return "\n".join(html_parts)
|
| 85 |
-
|
| 86 |
-
|
| 87 |
# --- Load external CSS (optional) ---
|
| 88 |
def load_css(file_name: str):
|
| 89 |
try:
|
|
@@ -483,9 +417,6 @@ def _get_topics(level: str, module_id: int) -> List[Tuple[str, str]]:
|
|
| 483 |
|
| 484 |
|
| 485 |
def _render_lesson():
|
| 486 |
-
ensure_quiz_state()
|
| 487 |
-
# make sure quiz keys exist
|
| 488 |
-
|
| 489 |
"""Render the lesson interface"""
|
| 490 |
level = st.session_state.get("level", "beginner")
|
| 491 |
module_id = st.session_state.get("module_id")
|
|
@@ -638,27 +569,7 @@ def _render_lesson():
|
|
| 638 |
with col_main:
|
| 639 |
t_title, t_text = topics[topic_idx]
|
| 640 |
|
| 641 |
-
|
| 642 |
-
lesson_html_text = _md_to_html((t_text or "").strip())
|
| 643 |
-
|
| 644 |
-
takeaways_html = ""
|
| 645 |
-
if t_text:
|
| 646 |
-
takeaways = _extract_takeaways(t_text)
|
| 647 |
-
if takeaways:
|
| 648 |
-
takeaways_html = (
|
| 649 |
-
'<div class="takeaways-section" style="min-height: 150px;">'
|
| 650 |
-
' <div class="takeaways-header">'
|
| 651 |
-
' <span style="color: #10b981;">β</span>'
|
| 652 |
-
' <span>Key Takeaways</span>'
|
| 653 |
-
' </div>'
|
| 654 |
-
+ "".join(
|
| 655 |
-
f'<div class="takeaway-item"><span class="takeaway-check">β</span><span>{st.escape_markdown(x)}</span></div>'
|
| 656 |
-
for x in takeaways
|
| 657 |
-
)
|
| 658 |
-
+ "</div>"
|
| 659 |
-
)
|
| 660 |
-
|
| 661 |
-
card_html = f"""
|
| 662 |
<div class="lesson-card">
|
| 663 |
<div class="unit-header">
|
| 664 |
<span class="unit-info">Unit {topic_idx + 1} of {len(topics)}</span>
|
|
@@ -668,20 +579,46 @@ def _render_lesson():
|
|
| 668 |
</div>
|
| 669 |
</div>
|
| 670 |
<div class="lesson-content">
|
| 671 |
-
|
| 672 |
-
|
| 673 |
-
|
| 674 |
-
|
| 675 |
-
|
| 676 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 677 |
|
| 678 |
-
# Navigation buttons (stay as Streamlit widgets)
|
| 679 |
st.markdown('<div class="nav-buttons">', unsafe_allow_html=True)
|
|
|
|
| 680 |
col1, col2, col3 = st.columns([1, 1, 1])
|
| 681 |
with col1:
|
| 682 |
if st.button("β Previous", disabled=topic_idx == 0, key="prev_btn"):
|
| 683 |
st.session_state.topic_idx -= 1
|
| 684 |
st.rerun()
|
|
|
|
| 685 |
with col3:
|
| 686 |
is_last = topic_idx >= len(topics) - 1
|
| 687 |
if is_last:
|
|
@@ -695,53 +632,57 @@ def _render_lesson():
|
|
| 695 |
if st.button("Next Unit β", key="next_btn"):
|
| 696 |
st.session_state.topic_idx += 1
|
| 697 |
st.rerun()
|
|
|
|
| 698 |
st.markdown('</div>', unsafe_allow_html=True)
|
| 699 |
|
| 700 |
with col_sidebar:
|
| 701 |
-
#
|
| 702 |
-
|
| 703 |
-
progress_pct = int(progress * 100)
|
| 704 |
-
|
| 705 |
-
progress_html = f"""
|
| 706 |
<div class="sidebar-card" style="min-height: 120px;">
|
| 707 |
<h4>Module Progress</h4>
|
| 708 |
-
|
| 709 |
-
|
| 710 |
-
|
| 711 |
-
|
| 712 |
-
|
| 713 |
-
|
| 714 |
-
</div>
|
| 715 |
-
|
| 716 |
-
|
| 717 |
-
|
| 718 |
-
|
| 719 |
-
|
|
|
|
|
|
|
| 720 |
for i, (tt, _) in enumerate(topics):
|
| 721 |
-
|
| 722 |
-
|
|
|
|
|
|
|
|
|
|
| 723 |
<div class="unit-item">
|
| 724 |
-
<span style="background:#10b981;color:white;width:20px;height:20px;border-radius:50%;
|
| 725 |
-
display:flex;align-items:center;justify-content:center;font-size:0.75rem;">β</span>
|
| 726 |
<span class="unit-active">{tt}</span>
|
| 727 |
-
</div>
|
| 728 |
-
|
| 729 |
-
|
|
|
|
| 730 |
<div class="unit-item">
|
| 731 |
-
<span style="color:#10b981;font-size:1.1rem;">β</span>
|
| 732 |
-
<span style="color:#374151;">{tt}</span>
|
| 733 |
-
</div>
|
|
|
|
| 734 |
else:
|
| 735 |
-
|
| 736 |
<div class="unit-item">
|
| 737 |
-
<span style="background:#e5e7eb;color:#9ca3af;width:20px;height:20px;border-radius:50%;
|
| 738 |
-
display:flex;align-items:center;justify-content:center;font-size:0.75rem;">β</span>
|
| 739 |
<span class="unit-inactive">{tt}</span>
|
| 740 |
-
</div>
|
| 741 |
-
|
| 742 |
-
|
|
|
|
| 743 |
|
| 744 |
-
# Back to modules button
|
| 745 |
if st.button("β Back to Modules", key="back_modules"):
|
| 746 |
st.session_state.mode = "catalog"
|
| 747 |
st.session_state.module_id = None
|
|
|
|
| 18 |
|
| 19 |
FALLBACK_TAG = "<!--fallback-->"
|
| 20 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
# --- Load external CSS (optional) ---
|
| 22 |
def load_css(file_name: str):
|
| 23 |
try:
|
|
|
|
| 417 |
|
| 418 |
|
| 419 |
def _render_lesson():
|
|
|
|
|
|
|
|
|
|
| 420 |
"""Render the lesson interface"""
|
| 421 |
level = st.session_state.get("level", "beginner")
|
| 422 |
module_id = st.session_state.get("module_id")
|
|
|
|
| 569 |
with col_main:
|
| 570 |
t_title, t_text = topics[topic_idx]
|
| 571 |
|
| 572 |
+
st.markdown(f"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 573 |
<div class="lesson-card">
|
| 574 |
<div class="unit-header">
|
| 575 |
<span class="unit-info">Unit {topic_idx + 1} of {len(topics)}</span>
|
|
|
|
| 579 |
</div>
|
| 580 |
</div>
|
| 581 |
<div class="lesson-content">
|
| 582 |
+
""", unsafe_allow_html=True)
|
| 583 |
+
|
| 584 |
+
if t_text:
|
| 585 |
+
st.markdown(t_text.strip(), unsafe_allow_html=True)
|
| 586 |
+
else:
|
| 587 |
+
st.info("Content coming soon.")
|
| 588 |
+
|
| 589 |
+
st.markdown("</div>", unsafe_allow_html=True)
|
| 590 |
+
|
| 591 |
+
if t_text:
|
| 592 |
+
takeaways = _extract_takeaways(t_text)
|
| 593 |
+
if takeaways:
|
| 594 |
+
st.markdown("""
|
| 595 |
+
<div class="takeaways-section" style="min-height: 150px;">
|
| 596 |
+
<div class="takeaways-header">
|
| 597 |
+
<span style="color: #10b981;">β</span>
|
| 598 |
+
<span>Key Takeaways</span>
|
| 599 |
+
</div>
|
| 600 |
+
""", unsafe_allow_html=True)
|
| 601 |
+
|
| 602 |
+
for takeaway in takeaways:
|
| 603 |
+
st.markdown(f"""
|
| 604 |
+
<div class="takeaway-item">
|
| 605 |
+
<span class="takeaway-check">β</span>
|
| 606 |
+
<span>{takeaway}</span>
|
| 607 |
+
</div>
|
| 608 |
+
""", unsafe_allow_html=True)
|
| 609 |
+
|
| 610 |
+
st.markdown("</div>", unsafe_allow_html=True)
|
| 611 |
+
|
| 612 |
+
st.markdown("</div>", unsafe_allow_html=True)
|
| 613 |
|
|
|
|
| 614 |
st.markdown('<div class="nav-buttons">', unsafe_allow_html=True)
|
| 615 |
+
|
| 616 |
col1, col2, col3 = st.columns([1, 1, 1])
|
| 617 |
with col1:
|
| 618 |
if st.button("β Previous", disabled=topic_idx == 0, key="prev_btn"):
|
| 619 |
st.session_state.topic_idx -= 1
|
| 620 |
st.rerun()
|
| 621 |
+
|
| 622 |
with col3:
|
| 623 |
is_last = topic_idx >= len(topics) - 1
|
| 624 |
if is_last:
|
|
|
|
| 632 |
if st.button("Next Unit β", key="next_btn"):
|
| 633 |
st.session_state.topic_idx += 1
|
| 634 |
st.rerun()
|
| 635 |
+
|
| 636 |
st.markdown('</div>', unsafe_allow_html=True)
|
| 637 |
|
| 638 |
with col_sidebar:
|
| 639 |
+
# Module Progress Card
|
| 640 |
+
st.markdown("""
|
|
|
|
|
|
|
|
|
|
| 641 |
<div class="sidebar-card" style="min-height: 120px;">
|
| 642 |
<h4>Module Progress</h4>
|
| 643 |
+
""", unsafe_allow_html=True)
|
| 644 |
+
|
| 645 |
+
progress = (topic_idx + 1) / max(1, len(topics))
|
| 646 |
+
st.progress(progress)
|
| 647 |
+
st.markdown(f"<p style='color: #6b7280; font-size: 0.875rem; margin-top: 0.5rem;'>Unit {topic_idx + 1} of {len(topics)}</p>", unsafe_allow_html=True)
|
| 648 |
+
|
| 649 |
+
st.markdown("</div>", unsafe_allow_html=True)
|
| 650 |
+
|
| 651 |
+
# Module Units Card
|
| 652 |
+
st.markdown("""
|
| 653 |
+
<div class="sidebar-card" style="min-height: 300px;">
|
| 654 |
+
<h4>Module Units</h4>
|
| 655 |
+
""", unsafe_allow_html=True)
|
| 656 |
+
|
| 657 |
for i, (tt, _) in enumerate(topics):
|
| 658 |
+
is_current = i == topic_idx
|
| 659 |
+
is_completed = i < topic_idx
|
| 660 |
+
|
| 661 |
+
if is_current:
|
| 662 |
+
st.markdown(f"""
|
| 663 |
<div class="unit-item">
|
| 664 |
+
<span style="background: #10b981; color: white; width: 20px; height: 20px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 0.75rem;">β</span>
|
|
|
|
| 665 |
<span class="unit-active">{tt}</span>
|
| 666 |
+
</div>
|
| 667 |
+
""", unsafe_allow_html=True)
|
| 668 |
+
elif is_completed:
|
| 669 |
+
st.markdown(f"""
|
| 670 |
<div class="unit-item">
|
| 671 |
+
<span style="color: #10b981; font-size: 1.1rem;">β</span>
|
| 672 |
+
<span style="color: #374151;">{tt}</span>
|
| 673 |
+
</div>
|
| 674 |
+
""", unsafe_allow_html=True)
|
| 675 |
else:
|
| 676 |
+
st.markdown(f"""
|
| 677 |
<div class="unit-item">
|
| 678 |
+
<span style="background: #e5e7eb; color: #9ca3af; width: 20px; height: 20px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 0.75rem;">β</span>
|
|
|
|
| 679 |
<span class="unit-inactive">{tt}</span>
|
| 680 |
+
</div>
|
| 681 |
+
""", unsafe_allow_html=True)
|
| 682 |
+
|
| 683 |
+
st.markdown("</div>", unsafe_allow_html=True)
|
| 684 |
|
| 685 |
+
# Back to modules button
|
| 686 |
if st.button("β Back to Modules", key="back_modules"):
|
| 687 |
st.session_state.mode = "catalog"
|
| 688 |
st.session_state.module_id = None
|