mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 08:50:15 +01:00
80 lines
3.2 KiB
TypeScript
80 lines
3.2 KiB
TypeScript
|
|
import React from 'react';
|
||
|
|
import { Search } from 'lucide-react';
|
||
|
|
import { cn } from '~/utils';
|
||
|
|
|
||
|
|
const AnimatedSearchInput = ({
|
||
|
|
value,
|
||
|
|
onChange,
|
||
|
|
isSearching: searching,
|
||
|
|
placeholder,
|
||
|
|
}: {
|
||
|
|
value?: string;
|
||
|
|
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||
|
|
isSearching?: boolean;
|
||
|
|
placeholder: string;
|
||
|
|
}) => {
|
||
|
|
const isSearching = searching === true;
|
||
|
|
const hasValue = value != null && value.length > 0;
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="relative w-full">
|
||
|
|
<div className="relative rounded-lg transition-all duration-500 ease-in-out">
|
||
|
|
<div className="relative">
|
||
|
|
{/* Icon on the left */}
|
||
|
|
<div className="absolute left-3 top-1/2 z-50 -translate-y-1/2">
|
||
|
|
<Search
|
||
|
|
className={cn(
|
||
|
|
`h-4 w-4 transition-all duration-500 ease-in-out`,
|
||
|
|
isSearching && hasValue ? 'text-blue-400' : 'text-gray-400',
|
||
|
|
)}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Input field */}
|
||
|
|
<input
|
||
|
|
type="text"
|
||
|
|
value={value}
|
||
|
|
onChange={onChange}
|
||
|
|
placeholder={placeholder}
|
||
|
|
className={`peer relative z-20 w-full rounded-lg bg-surface-secondary px-10 py-2 outline-none ring-0 backdrop-blur-sm transition-all duration-500 ease-in-out placeholder:text-gray-400 focus:outline-none focus:ring-0`}
|
||
|
|
/>
|
||
|
|
|
||
|
|
{/* Gradient overlay */}
|
||
|
|
<div
|
||
|
|
className={`pointer-events-none absolute inset-0 z-20 rounded-lg bg-gradient-to-r from-blue-500/20 via-purple-500/20 to-blue-500/20 transition-all duration-500 ease-in-out ${isSearching && hasValue ? 'opacity-100 blur-sm' : 'opacity-0 blur-none'} `}
|
||
|
|
/>
|
||
|
|
|
||
|
|
{/* Animated loading indicator */}
|
||
|
|
<div
|
||
|
|
className={`absolute right-3 top-1/2 z-20 -translate-y-1/2 transition-all duration-500 ease-in-out ${isSearching && hasValue ? 'scale-100 opacity-100' : 'scale-0 opacity-0'} `}
|
||
|
|
>
|
||
|
|
<div className="relative h-2 w-2">
|
||
|
|
<div className="absolute inset-0 animate-ping rounded-full bg-blue-500/60" />
|
||
|
|
<div className="absolute inset-0 rounded-full bg-blue-500" />
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Outer glow effect */}
|
||
|
|
<div
|
||
|
|
className={`absolute -inset-8 -z-10 transition-all duration-700 ease-in-out ${isSearching && hasValue ? 'scale-105 opacity-100' : 'scale-100 opacity-0'} `}
|
||
|
|
>
|
||
|
|
<div className="absolute inset-0">
|
||
|
|
<div
|
||
|
|
className={`bg-gradient-radial absolute inset-0 from-blue-500/10 to-transparent transition-opacity duration-700 ease-in-out ${isSearching && hasValue ? 'animate-pulse-slow opacity-100' : 'opacity-0'} `}
|
||
|
|
/>
|
||
|
|
<div
|
||
|
|
className={`absolute inset-0 bg-gradient-to-r from-purple-500/5 via-blue-500/5 to-purple-500/5 blur-xl transition-all duration-700 ease-in-out ${isSearching && hasValue ? 'animate-gradient-x opacity-100' : 'opacity-0'} `}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div
|
||
|
|
className={`absolute inset-0 -z-20 scale-100 bg-gradient-to-r from-blue-500/10 via-purple-500/10 to-blue-500/10 opacity-0 blur-xl transition-all duration-500 ease-in-out peer-focus:scale-105 peer-focus:opacity-100`}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
export default AnimatedSearchInput;
|