Files
wehub-resource-sync 542cfa195c
CI / Frontend build (push) Failing after 9m6s
CI / Plugin validate (push) Failing after 9m27s
CI / Python lint (push) Failing after 16m1s
CI / Tests (push) Successful in 18m0s
Deploy / deploy (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:27 +08:00

95 lines
3.4 KiB
TypeScript

"use client"
import { motion } from "framer-motion"
import { X } from "lucide-react"
import { tileUrl } from "@/lib/api"
import type { Hit } from "@/lib/types"
import { Button } from "@/components/ui/button"
interface ComparePanelProps {
hits: Hit[]
allHits: Hit[]
onClose: () => void
}
export function ComparePanel({ hits, allHits, onClose }: ComparePanelProps) {
return (
<motion.div
initial={{ y: "100%" }}
animate={{ y: 0 }}
exit={{ y: "100%" }}
transition={{ type: "spring", damping: 25, stiffness: 300 }}
className="fixed inset-x-0 bottom-0 z-[90] flex max-h-[70vh] flex-col border-t border-border bg-card shadow-2xl"
>
{/* Header */}
<div className="flex items-center justify-between border-b border-border px-6 py-3">
<h3 className="text-sm font-semibold">
Comparing {hits.length} tiles
</h3>
<Button variant="ghost" size="icon" onClick={onClose}>
<X className="h-4 w-4" />
</Button>
</div>
{/* Tiles */}
<div className="flex-1 overflow-auto p-6">
<div
className="grid gap-6"
style={{
gridTemplateColumns: `repeat(${Math.min(hits.length, 4)}, 1fr)`,
}}
>
{hits.map((hit) => {
const globalRank =
allHits.findIndex((h) => h.vector_id === hit.vector_id) + 1
const slug = hit.url.split("/wiki/").pop() ?? ""
const title =
decodeURIComponent(slug).replace(/_/g, " ") ||
`Article #${hit.article_id}`
return (
<div
key={hit.vector_id}
className="flex flex-col overflow-hidden rounded-lg border border-border"
>
{/* Image */}
<div className="bg-muted">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={tileUrl(hit)}
alt={`Tile ${hit.tile_index}`}
className="w-full object-contain"
/>
</div>
{/* Metadata */}
<div className="space-y-1.5 border-t border-border p-3 text-xs">
<div className="truncate font-medium">{title}</div>
<div className="flex items-center justify-between">
<span className="text-muted-foreground">Score</span>
<span className="font-mono font-semibold text-[var(--pixelrag-score)]">
{hit.score.toFixed(3)}
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-muted-foreground">Rank</span>
<span className="font-mono">#{globalRank}</span>
</div>
<div className="flex items-center justify-between">
<span className="text-muted-foreground">Tile height</span>
<span className="font-mono">{hit.tile_height}px</span>
</div>
<div className="flex items-center justify-between">
<span className="text-muted-foreground">Vector ID</span>
<span className="font-mono">{hit.vector_id}</span>
</div>
</div>
</div>
)
})}
</div>
</div>
</motion.div>
)
}