Polish dashboard: consistent icon set, flatter cards, merged activity card
Replace card-header emoji with a matching stroke-style SVG icon set that inherits theme color via currentColor. Drop the accent-stripe border from every card and keep it only on the Your Courses card, the one primary action. Merge Continue Watching and Recently Viewed into a single true-recency list so an old completed item can no longer outrank a newer in-progress one across two separately-capped lists. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+1
-20
@@ -1790,23 +1790,6 @@ def build_study_guide_markdown(course: Course) -> str:
|
||||
current_course = None
|
||||
|
||||
|
||||
def _split_continue_watching(all_views: List[Dict[str, Any]]) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]]]:
|
||||
"""
|
||||
Split the recent-views list (already carrying percent_watched/completed,
|
||||
see get_recent_views_for_display) into 'Continue Watching' - genuinely
|
||||
in-progress lessons - and the remaining 'Recently Viewed' entries, each
|
||||
capped at 5 for the dashboard. Reuses the same underlying history rather
|
||||
than a separate library-wide progress index (see plan notes).
|
||||
"""
|
||||
continue_watching = [v for v in all_views if 0 < v['percent_watched'] < 100][:5]
|
||||
continue_ids = {(v.get('course_path'), v.get('lesson_path')) for v in continue_watching}
|
||||
recent_views = [
|
||||
v for v in all_views
|
||||
if (v.get('course_path'), v.get('lesson_path')) not in continue_ids
|
||||
][:5]
|
||||
return continue_watching, recent_views
|
||||
|
||||
|
||||
def format_duration(seconds: int) -> str:
|
||||
"""Render a duration in seconds as e.g. '3h 24m' or '45m' (under an hour)."""
|
||||
total_minutes = max(0, int(seconds)) // 60
|
||||
@@ -1819,7 +1802,7 @@ def index():
|
||||
"""Main dashboard"""
|
||||
global current_course
|
||||
|
||||
continue_watching, recent_views = _split_continue_watching(get_recent_views_for_display())
|
||||
recent_views = get_recent_views_for_display()[:8]
|
||||
|
||||
if current_course is None:
|
||||
# One scan covers stats/stale-courses/heatmap - see _scan_library_activity.
|
||||
@@ -1827,7 +1810,6 @@ def index():
|
||||
return render_template('course_dashboard.html',
|
||||
course=None,
|
||||
stats={'total_lessons': 0, 'completed_lessons': 0, 'completion_percentage': 0},
|
||||
continue_watching=continue_watching,
|
||||
recent_views=recent_views,
|
||||
recently_added=get_recently_added_courses(),
|
||||
library_stats=format_library_stats(scan),
|
||||
@@ -1851,7 +1833,6 @@ def index():
|
||||
return render_template('course_dashboard.html',
|
||||
course=current_course,
|
||||
stats=stats,
|
||||
continue_watching=continue_watching,
|
||||
recent_views=recent_views,
|
||||
has_note=bool(course_has_any_notes(current_course)),
|
||||
is_queued=os.path.abspath(current_course.path) in get_next_up_paths(),
|
||||
|
||||
@@ -206,6 +206,12 @@
|
||||
border-radius: var(--radius);
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#library-card {
|
||||
/* the one card that's a primary action (browse/search/load a
|
||||
course) rather than a passive info/list card - every other
|
||||
card getting the same accent stripe made nothing stand out */
|
||||
border-left: 4px solid var(--accent);
|
||||
}
|
||||
|
||||
@@ -380,6 +386,16 @@
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.card-header-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.card-icon {
|
||||
flex-shrink: 0;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.card-body {
|
||||
overflow: hidden;
|
||||
max-height: 3000px;
|
||||
@@ -1088,7 +1104,7 @@
|
||||
|
||||
<div class="container">
|
||||
<div class="card" id="library-card">
|
||||
<h2>Your Courses</h2>
|
||||
<h2><span class="card-header-label"><svg class="card-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="8" height="8" rx="1.5"></rect><rect x="13" y="3" width="8" height="8" rx="1.5"></rect><rect x="3" y="13" width="8" height="8" rx="1.5"></rect><rect x="13" y="13" width="8" height="8" rx="1.5"></rect></svg>Your Courses</span></h2>
|
||||
<div class="library-toolbar">
|
||||
<input type="text" id="library-search-input" class="library-search-input"
|
||||
placeholder="Search courses…" oninput="handleLibrarySearchInput(this.value)">
|
||||
@@ -1124,7 +1140,7 @@
|
||||
{% if library_stats and library_stats.total_courses %}
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<h2 class="collapsible-header" data-card-id="library-stats">📊 Library Stats</h2>
|
||||
<h2 class="collapsible-header" data-card-id="library-stats"><span class="card-header-label"><svg class="card-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="6" y1="20" x2="6" y2="14"></line><line x1="12" y1="20" x2="12" y2="8"></line><line x1="18" y1="20" x2="18" y2="11"></line></svg>Library Stats</span></h2>
|
||||
<div class="card-body">
|
||||
<div class="stats-grid">
|
||||
<div class="stats-tile">
|
||||
@@ -1166,7 +1182,7 @@
|
||||
{% if next_up %}
|
||||
<div class="container">
|
||||
<div class="card" id="next-up-card">
|
||||
<h2 class="collapsible-header" data-card-id="next-up">📌 Next Up</h2>
|
||||
<h2 class="collapsible-header" data-card-id="next-up"><span class="card-header-label"><svg class="card-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="8" y1="6" x2="20" y2="6"></line><line x1="8" y1="12" x2="20" y2="12"></line><line x1="8" y1="18" x2="20" y2="18"></line><circle cx="4" cy="6" r="1"></circle><circle cx="4" cy="12" r="1"></circle><circle cx="4" cy="18" r="1"></circle></svg>Next Up</span></h2>
|
||||
<div class="card-body" id="next-up-list">
|
||||
{% for item in next_up %}
|
||||
<div class="lesson-item" data-path="{{ item.path }}">
|
||||
@@ -1193,7 +1209,7 @@
|
||||
{% if stale_courses %}
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<h2 class="collapsible-header" data-card-id="pick-back-up">⏰ Pick Back Up</h2>
|
||||
<h2 class="collapsible-header" data-card-id="pick-back-up"><span class="card-header-label"><svg class="card-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7"></path><polyline points="3 4 3 9 8 9"></polyline></svg>Pick Back Up</span></h2>
|
||||
<div class="card-body">
|
||||
{% for item in stale_courses %}
|
||||
{{ render_course_row(item, 'Last touched ' + item.last_touched_display) }}
|
||||
@@ -1205,7 +1221,7 @@
|
||||
{% if recently_added %}
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<h2 class="collapsible-header" data-card-id="recently-added">🆕 Recently Added</h2>
|
||||
<h2 class="collapsible-header" data-card-id="recently-added"><span class="card-header-label"><svg class="card-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"></circle><line x1="12" y1="8" x2="12" y2="16"></line><line x1="8" y1="12" x2="16" y2="12"></line></svg>Recently Added</span></h2>
|
||||
<div class="card-body">
|
||||
{% for item in recently_added %}
|
||||
{{ render_course_row(item, item.added_display) }}
|
||||
@@ -1214,22 +1230,10 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if continue_watching %}
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<h2 class="collapsible-header" data-card-id="continue-watching">▶ Continue Watching</h2>
|
||||
<div class="card-body">
|
||||
{% for view in continue_watching %}
|
||||
{{ render_view_row(view) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if recent_views %}
|
||||
<div class="container">
|
||||
<div class="card">
|
||||
<h2 class="collapsible-header" data-card-id="recently-viewed">🕐 Recently Viewed</h2>
|
||||
<h2 class="collapsible-header" data-card-id="recently-viewed"><span class="card-header-label"><svg class="card-icon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"></circle><polygon points="10 8 16 12 10 16 10 8"></polygon></svg>Recently Viewed</span></h2>
|
||||
<div class="card-body">
|
||||
{% for view in recent_views %}
|
||||
{{ render_view_row(view) }}
|
||||
|
||||
Reference in New Issue
Block a user