feat(learner): search results show lesson matches cleanly; contract notes for the browser entry and LessonView; plan marked done

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Lucas Winther
2026-10-30 04:54:53 +01:00
co-authored by Claude Opus 5.5
parent 89c51f013d
commit 061ae7a2d9
3 changed files with 46 additions and 24 deletions
@@ -5,6 +5,7 @@ import type { CourseCard, ContinueItem, Format, LibraryPayload, SearchHit } from
import { api, courseHref, ensureStyles, fmtMinutes, lessonHref, refreshLibrary, useLibrary, useSearch } from "../api";
import { HeaderExtras } from "../shell/HeaderExtras";
import { accentStyle } from "../shell/CourseFrame";
import { TitleText } from "../lesson/TitleText";
const FORMAT_LABEL: Record<Format, string> = { text: "Text", video: "Video", slides: "Slides", exercises: "Exercises" };
type LengthFilter = "any" | "short" | "medium" | "long";
@@ -104,16 +105,18 @@ export function LibraryView({ lib, initialQuery }: { lib: LibraryPayload; initia
</>
) : (
<>
<h2 className="sec-h">{q ? `Courses matching “${q}”` : "Courses"}</h2>
{q && hits === null ? <p className="lr-nohit">Searching…</p> : results.length ? <CourseTable courses={results} signedIn={lib.signedIn} /> : <p className="lr-nohit">No courses match.</p>}
{results.length || !lessonHits.length ? <h2 className="sec-h">{q ? `Courses matching “${q}”` : "Courses"}</h2> : null}
{q && hits === null ? <p className="lr-nohit">Searching…</p>
: results.length ? <CourseTable courses={results} signedIn={lib.signedIn} />
: !lessonHits.length ? <p className="lr-nohit">Nothing matches. Try fewer words, or clear the filters.</p> : null}
{lessonHits.length ? (
<>
<h2 className="sec-h" style={{ marginTop: 36 }}>Lessons</h2>
<h2 className="sec-h" style={{ marginTop: results.length ? 36 : 0 }}>{q ? `Lessons matching “${q}”` : "Lessons"}</h2>
<ul className="hits">
{lessonHits.flatMap((h) => h.lessons.map((l) => (
<li key={`${h.courseId}/${l.id}`}>
<Link to={lessonHref(h.courseId, l.id)}>
<span><span className="h1">{l.title}</span><span className="h2" style={{ display: "block" }}>{h.courseTitle} · {l.moduleTitle}</span></span>
<span><span className="h1"><TitleText text={l.title} /></span><span className="h2" style={{ display: "block" }}>{h.courseTitle} · {l.moduleTitle}</span></span>
</Link>
</li>
)))}