Stop resetting lesson progress on view, and add Notes Hub search
view_lesson() called update_lesson_progress() with no arguments on every page load, which defaults completed=False and progress_seconds=0 and silently overwrote whatever was already saved - just opening an already-watched lesson reset its progress/completed state unless the client happened to report real values within the next 15 seconds. Replaced with touch_lesson_accessed(), which only bumps last_accessed. Also fixes the "Resume from Xs" feature this fed into: it read a value that was never populated on this route, and even when given a real one, checked activeMedia.duration synchronously before metadata had loaded, so it silently never applied. Now waits for loadedmetadata (or resolves immediately if already available) and defers to an explicit note-timestamp jump (?t=) when both are present. Notes Hub gets a live search box filtering by note text, lesson title, or course name (client-side, no reload), with a "no notes match" state - useful now that a single category folder can hold dozens of courses' worth of timestamped notes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -117,6 +117,17 @@
|
||||
text-align: center;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
.notes-search-input {
|
||||
width: 100%;
|
||||
background: var(--bg-tertiary);
|
||||
color: var(--text-primary);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius);
|
||||
padding: 10px 14px;
|
||||
font-size: 0.95em;
|
||||
font-family: var(--font-family);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.note-card {
|
||||
background: var(--bg-secondary);
|
||||
border-radius: var(--radius);
|
||||
@@ -213,10 +224,14 @@
|
||||
|
||||
{% if not notes %}
|
||||
<div class="empty-hint">No notes yet - jot something down on a lesson page and it'll show up here.</div>
|
||||
{% else %}
|
||||
<input type="text" id="notes-search-input" class="notes-search-input"
|
||||
placeholder="Search notes, lessons, or courses…" oninput="filterNotes(this.value)">
|
||||
<div id="notes-no-results-hint" class="empty-hint" style="display: none;">No notes match your search.</div>
|
||||
{% endif %}
|
||||
|
||||
{% for note in notes %}
|
||||
<div class="note-card">
|
||||
<div class="note-card" data-search="{{ (note.lesson_title ~ ' ' ~ note.course_name ~ ' ' ~ note.text) | lower }}">
|
||||
<div class="note-card-header">
|
||||
<span class="note-card-icon">📝</span>
|
||||
<div class="note-card-titles">
|
||||
@@ -251,6 +266,22 @@
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
function filterNotes(query) {
|
||||
const q = query.trim().toLowerCase();
|
||||
const cards = document.querySelectorAll('.note-card');
|
||||
let visibleCount = 0;
|
||||
cards.forEach(function(card) {
|
||||
const match = !q || card.dataset.search.includes(q);
|
||||
card.style.display = match ? '' : 'none';
|
||||
if (match) visibleCount++;
|
||||
});
|
||||
const noResultsHint = document.getElementById('notes-no-results-hint');
|
||||
if (noResultsHint) {
|
||||
noResultsHint.style.display = (visibleCount === 0 && cards.length > 0) ? 'block' : 'none';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="/static/theme.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user