Add course outline sidebar to the lesson page
Shows every section and lesson in the course - videos and standalone documents alike - so jumping to a different section no longer means backing out to the course page first. Current lesson is highlighted, its section auto-expands and scrolls into view; sticky on desktop, stacks below the player on narrow viewports. Replaces the old "Lessons in this section" list, which only showed the current section. The tree-rendering markup (shared with the loaded-course dashboard view) is now a single macro in templates/_course_tree.html instead of being duplicated, so both views stay in sync going forward. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+10
-33
@@ -4554,8 +4554,16 @@ def view_lesson(lesson_path: str):
|
||||
if not current_course:
|
||||
return redirect(url_for('index'))
|
||||
|
||||
# Find the lesson in the tree, and the section (DirectoryNode) it belongs to
|
||||
lesson, section_node = find_lesson_in_tree(current_course.root_node, lesson_path)
|
||||
# Populates the whole tree's Lesson objects (completed/progress_seconds/
|
||||
# duration_seconds) from disk - needed for the course-outline sidebar,
|
||||
# which (like the dashboard's tree) reads those fields directly rather
|
||||
# than loading progress per-row.
|
||||
ProgressTracker.apply_progress_to_tree(current_course)
|
||||
|
||||
# Find the lesson in the tree (the section/DirectoryNode it belongs to
|
||||
# isn't needed here anymore - the sidebar shows the whole course, not
|
||||
# just this lesson's own section)
|
||||
lesson, _ = find_lesson_in_tree(current_course.root_node, lesson_path)
|
||||
|
||||
if not lesson:
|
||||
return redirect(url_for('index'))
|
||||
@@ -4603,7 +4611,6 @@ def view_lesson(lesson_path: str):
|
||||
initial_seek_seconds=seek_seconds,
|
||||
outline_topic_id=lesson_progress.get('outline_topic_id', ''),
|
||||
outline_topic_name=lesson_progress.get('outline_topic_name', ''),
|
||||
section_lessons=get_section_lessons(current_course, section_node, lesson),
|
||||
prev_lesson=prev_lesson,
|
||||
next_lesson=next_lesson)
|
||||
|
||||
@@ -4656,36 +4663,6 @@ def find_lesson_in_tree(node: DirectoryNode, target_path: str) -> Tuple[Optional
|
||||
return None, None
|
||||
|
||||
|
||||
def get_section_lessons(course: Course, section_node: DirectoryNode, current_lesson: Lesson) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
The sibling lessons in current_lesson's own section, for the lesson
|
||||
page's "up next in this section" list. view_lesson() isn't on the
|
||||
apply_progress_to_tree() code path, so - like that route already does
|
||||
for the current lesson's own notes/progress - this reads progress
|
||||
directly from the progress file rather than relying on Lesson fields.
|
||||
"""
|
||||
progress = ProgressTracker.load_progress(course)
|
||||
siblings = []
|
||||
for sibling in section_node.lessons:
|
||||
key = _resolve_lesson_progress_key(course, sibling, progress)
|
||||
entry = progress.get(key, {}) if key else {}
|
||||
completed = entry.get('completed', False)
|
||||
progress_seconds = entry.get('progress_seconds', 0)
|
||||
duration_seconds = entry.get('duration_seconds', 0)
|
||||
percent_watched = 100 if completed else (
|
||||
round(100 * progress_seconds / duration_seconds) if duration_seconds and progress_seconds else 0
|
||||
)
|
||||
siblings.append({
|
||||
'title': sibling.title,
|
||||
'url': get_lesson_url(sibling, course.path),
|
||||
'lesson_type': sibling.lesson_type,
|
||||
'completed': completed,
|
||||
'percent_watched': percent_watched,
|
||||
'is_current': sibling is current_lesson,
|
||||
})
|
||||
return siblings
|
||||
|
||||
|
||||
def get_all_lessons(node: DirectoryNode) -> List[Tuple[str, Lesson]]:
|
||||
"""Get all lessons from the tree with their paths"""
|
||||
lessons = []
|
||||
|
||||
Reference in New Issue
Block a user