Files
pdf/frontend/src/viewer/SearchOverlayLayer.tsx
T
2026-06-08 11:22:15 +05:30

63 lines
1.8 KiB
TypeScript

import React from 'react';
import type { SearchResult } from '../lib/gatewayService';
interface SearchOverlayLayerProps {
pageIndex: number;
width: number;
height: number;
zoom: number;
searchQuery: string;
searchResults?: SearchResult[];
searchCurrentMatch?: number;
}
export const SearchOverlayLayer: React.FC<SearchOverlayLayerProps> = ({
pageIndex,
width,
height,
zoom,
searchQuery,
searchResults = [],
searchCurrentMatch = 0,
}) => {
if (!searchQuery || searchResults.length === 0) return null;
// Filter results for this specific page and keep track of global index
const pageMatches = searchResults
.map((result, globalIndex) => ({ ...result, globalIndex }))
.filter((result) => result.pageIndex === pageIndex);
if (pageMatches.length === 0) return null;
return (
<div
className="absolute top-0 left-0 pointer-events-none z-20"
style={{ width: `${width}px`, height: `${height}px` }}
>
{pageMatches.map((match) => (
<React.Fragment key={match.globalIndex}>
{match.rects.map((rect, rectIdx) => {
const isActive = match.globalIndex === searchCurrentMatch;
return (
<div
key={rectIdx}
className={`absolute rounded-sm border ${
isActive
? 'bg-orange-500/50 border-orange-600/80 shadow-[0_0_8px_rgba(249,115,22,0.6)] z-30'
: 'bg-yellow-400/40 border-yellow-500/60'
}`}
style={{
left: `${rect.x * zoom}px`,
top: `${rect.y * zoom}px`,
width: `${rect.w * zoom}px`,
height: `${rect.h * zoom}px`,
}}
/>
);
})}
</React.Fragment>
))}
</div>
);
};