frontend: dashboard recent-activities widget no longer scrolls
Build and push images / validate (push) Successful in 3s
Build and push images / build-backend (push) Successful in 6s
Build and push images / build-worker (push) Successful in 5s
Build and push images / build-frontend (push) Successful in 10s

Rows now flex to fill the card height so the list always fits exactly,
removing the vertical scrollbar that appeared once rows carried a route
line, and the spurious horizontal scrollbar caused by overflow-auto +
the -mx-2 hover bleed. Empty state preserved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-18 22:00:42 +01:00
co-authored by Claude Opus 4.8
parent c14f3d60fa
commit a0912fd09a
+26 -22
View File
@@ -459,28 +459,32 @@ function RecentActivities({ activities }) {
const unit = useUnit()
return (
<Card title="Recent activities" viewHref="/activities">
<div className="space-y-2 overflow-auto h-full">
{activities?.slice(0, 6).map(activity => (
<Link key={activity.id} to={`/activities/${activity.id}`}
className="flex items-center gap-3 py-2 border-b border-gray-800/50 hover:bg-gray-800/30 rounded-lg px-2 -mx-2 transition-colors">
<span className="text-lg">{sportIcon(activity.sport_type)}</span>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-white truncate">{activity.name}</p>
{activity.named_route_name && (
<p className="text-xs text-blue-400 truncate">📍 {activity.named_route_name}</p>
)}
<p className="text-xs text-gray-500">{formatDate(activity.start_time)}</p>
</div>
<div className="text-right text-sm">
<p className="text-gray-200">{formatDistance(activity.distance_m, unit)}</p>
<p className="text-xs text-red-400">{formatHeartRate(activity.avg_heart_rate)}</p>
</div>
</Link>
))}
{!activities?.length && (
<p className="text-gray-600 text-sm text-center py-8">No activities yet <Link to="/upload" className="text-blue-400 hover:underline">import some data</Link></p>
)}
</div>
{activities?.length ? (
// Rows flex to fill the card height so the list always fits exactly —
// no scrollbars (and never a spurious horizontal one). The visible count
// adapts to the widget's height rather than a fixed slice overflowing.
<div className="h-full flex flex-col overflow-hidden">
{activities.slice(0, 6).map(activity => (
<Link key={activity.id} to={`/activities/${activity.id}`}
className="flex items-center gap-3 flex-1 min-h-0 overflow-hidden px-2 border-b border-gray-800/50 last:border-0 hover:bg-gray-800/30 rounded-lg transition-colors">
<span className="text-lg shrink-0">{sportIcon(activity.sport_type)}</span>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-white truncate">{activity.name}</p>
{activity.named_route_name && (
<p className="text-xs text-blue-400 truncate">📍 {activity.named_route_name}</p>
)}
<p className="text-xs text-gray-500">{formatDate(activity.start_time)}</p>
</div>
<div className="text-right text-sm shrink-0">
<p className="text-gray-200">{formatDistance(activity.distance_m, unit)}</p>
<p className="text-xs text-red-400">{formatHeartRate(activity.avg_heart_rate)}</p>
</div>
</Link>
))}
</div>
) : (
<p className="text-gray-600 text-sm text-center py-8">No activities yet <Link to="/upload" className="text-blue-400 hover:underline">import some data</Link></p>
)}
</Card>
)
}