feat(ui): redesign analytics page — stat cards, styled charts, git-log activity feed

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-27 00:10:46 -05:00
parent 0ea3fcfa6d
commit 8461bf788c
4 changed files with 87 additions and 44 deletions

View File

@@ -74,7 +74,7 @@ export default function ActivityFeed({ minutes, taskId }: ActivityFeedProps) {
if (eventsLoading || mappingsLoading) {
return (
<div className="flex items-center justify-center h-32 text-[#94a3b8] text-sm">
<div className="flex items-center justify-center h-32 text-[var(--color-text-secondary)] text-sm">
Loading activity...
</div>
)
@@ -82,7 +82,7 @@ export default function ActivityFeed({ minutes, taskId }: ActivityFeedProps) {
if (sortedEvents.length === 0) {
return (
<div className="flex items-center justify-center h-32 text-[#94a3b8] text-sm">
<div className="flex items-center justify-center h-32 text-[var(--color-text-secondary)] text-sm">
No activity events for this time range.
</div>
)
@@ -90,30 +90,36 @@ export default function ActivityFeed({ minutes, taskId }: ActivityFeedProps) {
return (
<div>
<div className="divide-y divide-white/5">
{visibleEvents.map((evt) => {
<div className="relative">
{visibleEvents.map((evt, idx) => {
const category = mappings ? resolveCategory(evt.appName, mappings) : 'Unknown'
const color = CATEGORY_COLORS[category] ?? CATEGORY_COLORS['Unknown']
const detail = evt.url || evt.windowTitle || ''
const isLast = idx === visibleEvents.length - 1
return (
<div key={evt.id} className="flex items-start gap-3 py-3">
{/* Category dot */}
<span
className="w-2 h-2 rounded-full mt-1.5 shrink-0"
style={{ backgroundColor: color }}
/>
<div key={evt.id} className="flex items-start gap-3 relative">
{/* Timeline connector + dot */}
<div className="flex flex-col items-center shrink-0">
<span
className="w-2 h-2 rounded-full mt-1.5 shrink-0 relative z-10"
style={{ backgroundColor: color }}
/>
{!isLast && (
<div className="w-px flex-1 bg-[var(--color-border)]" />
)}
</div>
{/* Content */}
<div className="flex-1 min-w-0">
<div className="flex-1 min-w-0 pb-3">
<div className="flex items-center gap-2">
<span className="text-xs text-[#94a3b8] shrink-0">
<span className="text-xs text-[var(--color-text-secondary)] shrink-0">
{formatTimestamp(evt.timestamp)}
</span>
<span className="text-sm text-white font-medium truncate">{evt.appName}</span>
<span className="text-sm text-[var(--color-text-primary)] font-medium truncate">{evt.appName}</span>
</div>
{detail && (
<p className="text-xs text-[#64748b] truncate mt-0.5">{detail}</p>
<p className="text-xs text-[var(--color-text-tertiary)] truncate mt-0.5">{detail}</p>
)}
</div>
</div>
@@ -124,7 +130,7 @@ export default function ActivityFeed({ minutes, taskId }: ActivityFeedProps) {
{hasMore && (
<button
onClick={() => setVisibleCount((c) => c + PAGE_SIZE)}
className="mt-3 w-full py-2 text-sm text-[#94a3b8] hover:text-white bg-white/5 hover:bg-white/10 rounded-lg transition-colors"
className="mt-3 w-full py-2 text-sm text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] bg-white/5 hover:bg-white/10 rounded-lg transition-colors"
>
Load more ({sortedEvents.length - visibleCount} remaining)
</button>