feat(results): add video results skeleton and refresh detection summary UI
This commit is contained in:
@@ -53,7 +53,7 @@ export default function AnnotatedVideoPlayer({
|
||||
) : (
|
||||
<>
|
||||
<Loader2 className="h-7 w-7 animate-spin text-primary" />
|
||||
<p className="text-xs font-medium uppercase tracking-widest">
|
||||
<p className="text-xs">
|
||||
{isLoading ? 'Loading annotated video...' : 'Preparing video...'}
|
||||
</p>
|
||||
</>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
'use client';
|
||||
|
||||
import { MapPin } from 'lucide-react';
|
||||
import { CompletedVideoResult, DetectionResultLog } from '@/types';
|
||||
import { Activity, AlertTriangle, MapPin, SignpostBig } from 'lucide-react';
|
||||
|
||||
import type { CompletedVideoResult, DetectionResultLog } from '@/types';
|
||||
|
||||
interface CurrentDetectionBarProps {
|
||||
activeLog?: DetectionResultLog;
|
||||
@@ -17,17 +18,23 @@ export default function CurrentDetectionBar({
|
||||
{
|
||||
label: 'Potholes',
|
||||
value: currentCounts.unique_potholes || 0,
|
||||
icon: AlertTriangle,
|
||||
className: 'text-orange-500',
|
||||
iconClassName: 'bg-orange-500/10 text-orange-500',
|
||||
},
|
||||
{
|
||||
label: 'Signboards',
|
||||
value: currentCounts.unique_signboards || 0,
|
||||
icon: SignpostBig,
|
||||
className: 'text-blue-500',
|
||||
iconClassName: 'bg-blue-500/10 text-blue-500',
|
||||
},
|
||||
{
|
||||
label: 'Total',
|
||||
value: currentCounts.total_detections || 0,
|
||||
icon: Activity,
|
||||
className: 'text-green-500',
|
||||
iconClassName: 'bg-green-500/10 text-green-500',
|
||||
},
|
||||
];
|
||||
const latitude = activeLog?.latitude;
|
||||
@@ -38,33 +45,56 @@ export default function CurrentDetectionBar({
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border bg-card px-4 py-3">
|
||||
{coordinates && (
|
||||
<div className="mb-3 flex justify-end">
|
||||
<div className="flex max-w-full items-center gap-2 rounded-md border bg-muted/30 px-3 py-1.5">
|
||||
<MapPin className="size-3.5 shrink-0 text-muted-foreground" />
|
||||
<span className="truncate font-mono text-xs font-semibold text-foreground">
|
||||
<section className="overflow-hidden rounded-lg border bg-card/80">
|
||||
<div className="flex flex-col gap-3 border-b px-4 py-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<p className="text-sm font-semibold text-foreground">
|
||||
Current Detection Summary
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Counts update as the playback timeline moves.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{coordinates ? (
|
||||
<div className="flex max-w-full items-center gap-2 rounded-md bg-muted/40 px-3 py-1.5 text-xs text-muted-foreground">
|
||||
<MapPin className="size-3.5 shrink-0" />
|
||||
<span className="shrink-0 font-medium">Location</span>
|
||||
<span className="truncate font-mono font-semibold text-foreground">
|
||||
{coordinates}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
|
||||
{countItems.map((item) => (
|
||||
<div
|
||||
key={item.label}
|
||||
className="flex items-center justify-between gap-3 rounded-lg border bg-muted/20 px-4 py-2"
|
||||
>
|
||||
<p className="text-xs font-bold uppercase tracking-wide text-muted-foreground">
|
||||
{item.label}
|
||||
</p>
|
||||
<p className={`text-2xl font-bold leading-none ${item.className}`}>
|
||||
{item.value}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-2 p-3 sm:grid-cols-3">
|
||||
{countItems.map((item) => {
|
||||
const Icon = item.icon;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={item.label}
|
||||
className="flex items-center justify-between gap-3 rounded-md bg-muted/25 px-3 py-2.5 ring-1 ring-border/60"
|
||||
>
|
||||
<div className="flex min-w-0 items-center gap-3">
|
||||
<span
|
||||
className={`flex size-8 shrink-0 items-center justify-center rounded-md ${item.iconClassName}`}
|
||||
>
|
||||
<Icon className="size-4" />
|
||||
</span>
|
||||
<p className="truncate text-xs font-semibold uppercase tracking-wide text-muted-foreground">
|
||||
{item.label}
|
||||
</p>
|
||||
</div>
|
||||
<p
|
||||
className={`text-2xl font-bold leading-none ${item.className}`}
|
||||
>
|
||||
{item.value}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user