Move sidebar left, add collapse toggle and remembered sections
- Course outline sidebar now sits on the left of the player instead of the right (mobile stacking order unchanged - video still first). - Collapsible to a slim rail via a toggle button, remembered per device, for a full-width player when wanted. - Which sections a user has manually expanded is now remembered (keyed by the section's path) and shared between the lesson-page sidebar and the dashboard's course view, so re-opening a course doesn't reset everything back to collapsed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+109
-11
@@ -166,9 +166,43 @@
|
||||
top: 20px;
|
||||
max-height: calc(100vh - 40px);
|
||||
overflow-y: auto;
|
||||
order: -1;
|
||||
}
|
||||
.lesson-sidebar h3 {
|
||||
margin-top: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.lesson-sidebar-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
}
|
||||
.sidebar-toggle-btn {
|
||||
background: var(--bg-tertiary);
|
||||
border: none;
|
||||
color: var(--text-primary);
|
||||
border-radius: var(--radius);
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
flex-shrink: 0;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.9em;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
.sidebar-toggle-btn:hover {
|
||||
background: var(--bg-tertiary-hover);
|
||||
}
|
||||
.lesson-sidebar.collapsed {
|
||||
flex: 0 0 auto;
|
||||
padding: 20px 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.lesson-sidebar.collapsed .lesson-sidebar-header h3,
|
||||
.lesson-sidebar.collapsed .tree-container {
|
||||
display: none;
|
||||
}
|
||||
@media (max-width: 900px) {
|
||||
.lesson-layout {
|
||||
@@ -179,6 +213,10 @@
|
||||
width: 100%;
|
||||
position: static;
|
||||
max-height: 420px;
|
||||
order: 0;
|
||||
}
|
||||
.lesson-sidebar.collapsed {
|
||||
max-height: none;
|
||||
}
|
||||
}
|
||||
/* Course-outline sidebar tree - scoped under .lesson-sidebar so
|
||||
@@ -796,8 +834,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container lesson-sidebar">
|
||||
<h3>Course Outline</h3>
|
||||
<div class="container lesson-sidebar" id="lesson-sidebar">
|
||||
<div class="lesson-sidebar-header">
|
||||
<h3>Course Outline</h3>
|
||||
<button type="button" class="sidebar-toggle-btn" id="sidebar-toggle-btn" onclick="toggleSidebar()" title="Collapse sidebar">◀</button>
|
||||
</div>
|
||||
<div class="tree-container">
|
||||
{{ tree.render_tree_node(course.root_node, course.path, lesson) }}
|
||||
</div>
|
||||
@@ -1199,27 +1240,84 @@
|
||||
if (content && content.classList.contains('tree-content')) {
|
||||
const isExpanded = content.classList.toggle('expanded');
|
||||
if (toggleBtn) toggleBtn.textContent = isExpanded ? '▼' : '▶';
|
||||
if (content.dataset.sectionPath) saveSectionExpanded(content.dataset.sectionPath, isExpanded);
|
||||
}
|
||||
}
|
||||
|
||||
// Sections default collapsed (same as the dashboard) - expand
|
||||
// just the ancestor chain down to the current lesson so it's
|
||||
// visible without the user having to hunt for it, and scroll
|
||||
// it into view within the sidebar's own scroll area.
|
||||
// Remembers which course sections a user has manually expanded
|
||||
// (keyed by the section's absolute path, shared with the
|
||||
// dashboard's own tree - see _course_tree.html) so re-opening
|
||||
// a course doesn't reset every section back to collapsed.
|
||||
function getExpandedSectionPaths() {
|
||||
try {
|
||||
return new Set(JSON.parse(localStorage.getItem('offlineu-expanded-sections') || '[]'));
|
||||
} catch (e) {
|
||||
return new Set();
|
||||
}
|
||||
}
|
||||
|
||||
function saveSectionExpanded(path, expanded) {
|
||||
const paths = getExpandedSectionPaths();
|
||||
if (expanded) paths.add(path); else paths.delete(path);
|
||||
localStorage.setItem('offlineu-expanded-sections', JSON.stringify([...paths]));
|
||||
}
|
||||
|
||||
function expandSection(content) {
|
||||
content.classList.add('expanded');
|
||||
const header = content.previousElementSibling;
|
||||
const toggleBtn = header ? header.querySelector('.tree-toggle') : null;
|
||||
if (toggleBtn) toggleBtn.textContent = '▼';
|
||||
}
|
||||
|
||||
(function restoreExpandedSections() {
|
||||
const saved = getExpandedSectionPaths();
|
||||
if (!saved.size) return;
|
||||
document.querySelectorAll('.lesson-sidebar .tree-content[data-section-path]').forEach(function(content) {
|
||||
if (saved.has(content.dataset.sectionPath)) expandSection(content);
|
||||
});
|
||||
})();
|
||||
|
||||
// Sections default collapsed - additionally expand the ancestor
|
||||
// chain down to the current lesson (even if not previously
|
||||
// remembered) so it's visible without hunting for it, and
|
||||
// scroll it into view within the sidebar's own scroll area.
|
||||
// Persisted the same as a manual expand, so it stays open on
|
||||
// later visits too.
|
||||
(function revealCurrentLessonInSidebar() {
|
||||
const current = document.querySelector('.lesson-sidebar .lesson-item.current');
|
||||
if (!current) return;
|
||||
let content = current.closest('.tree-content');
|
||||
while (content) {
|
||||
content.classList.add('expanded');
|
||||
const header = content.previousElementSibling;
|
||||
const toggleBtn = header ? header.querySelector('.tree-toggle') : null;
|
||||
if (toggleBtn) toggleBtn.textContent = '▼';
|
||||
expandSection(content);
|
||||
if (content.dataset.sectionPath) saveSectionExpanded(content.dataset.sectionPath, true);
|
||||
content = content.parentElement ? content.parentElement.closest('.tree-content') : null;
|
||||
}
|
||||
current.scrollIntoView({ block: 'center' });
|
||||
})();
|
||||
|
||||
// ---- Sidebar collapse (client-only, remembered per device) ----
|
||||
function toggleSidebar() {
|
||||
const sidebar = document.getElementById('lesson-sidebar');
|
||||
const btn = document.getElementById('sidebar-toggle-btn');
|
||||
const collapsed = sidebar.classList.toggle('collapsed');
|
||||
if (btn) {
|
||||
btn.textContent = collapsed ? '▶' : '◀';
|
||||
btn.title = collapsed ? 'Expand sidebar' : 'Collapse sidebar';
|
||||
}
|
||||
localStorage.setItem('offlineu-lesson-sidebar-collapsed', collapsed ? '1' : '0');
|
||||
}
|
||||
|
||||
(function restoreSidebarCollapsed() {
|
||||
if (localStorage.getItem('offlineu-lesson-sidebar-collapsed') !== '1') return;
|
||||
const sidebar = document.getElementById('lesson-sidebar');
|
||||
const btn = document.getElementById('sidebar-toggle-btn');
|
||||
if (sidebar) sidebar.classList.add('collapsed');
|
||||
if (btn) {
|
||||
btn.textContent = '▶';
|
||||
btn.title = 'Expand sidebar';
|
||||
}
|
||||
})();
|
||||
|
||||
renderNotes();
|
||||
|
||||
// Seek once metadata is available (activeMedia.duration is NaN
|
||||
|
||||
Reference in New Issue
Block a user