videofolxtv/client/src/components/search-header.tsx
sebastjanartic 38274ff979 Improve visibility and appearance of background logos
Refactor the positioning, sizing, opacity, and blur of go4.video logos and triangle decorations across multiple components to enhance visual presence and adhere to geometric design principles.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: d7424866-83d1-4486-a212-ac12b4c7becf
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/d7424866-83d1-4486-a212-ac12b4c7becf/u1XGT5E
2025-08-28 15:41:54 +00:00

168 lines
6.3 KiB
TypeScript

import { useState, useCallback } from "react";
import { Search, Play, Menu, Grid3X3, List } from "lucide-react";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import go4LogoPath from "@assets/go4_1756394900352.png";
interface SearchHeaderProps {
onSearch: (query: string) => void;
onViewChange: (view: "grid" | "list") => void;
currentView: "grid" | "list";
}
export default function SearchHeader({
onSearch,
onViewChange,
currentView
}: SearchHeaderProps) {
const [searchQuery, setSearchQuery] = useState("");
// Debounce function to delay search API calls
const debounce = useCallback((func: Function, delay: number) => {
let timeoutId: NodeJS.Timeout;
return (...args: any[]) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func(...args), delay);
};
}, []);
// Optimized debounced search - waits 300ms and filters short queries
const debouncedSearch = useCallback(
debounce((query: string) => {
// Only search if query is meaningful (2+ characters or empty for reset)
if (query.length === 0 || query.length >= 2) {
onSearch(query);
}
}, 300),
[onSearch, debounce]
);
const handleSearchChange = (value: string) => {
setSearchQuery(value);
debouncedSearch(value);
};
return (
<div className="bunny-gray border-b border-white/20 sticky top-0 z-50 backdrop-blur-md relative overflow-hidden">
{/* go4.video logoti v headerju - bolj vidni */}
<div
style={{
position: 'absolute',
top: '5px',
right: '8%',
transform: 'rotate(-15deg)',
width: '140px',
height: '70px',
backgroundImage: `url(${go4LogoPath})`,
backgroundSize: 'contain',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center',
pointerEvents: 'none',
zIndex: 1,
opacity: 0.4,
filter: 'blur(0.3px)'
}}
/>
<div
style={{
position: 'absolute',
top: '8px',
left: '12%',
transform: 'rotate(25deg)',
width: '120px',
height: '60px',
backgroundImage: `url(${go4LogoPath})`,
backgroundSize: 'contain',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'center',
pointerEvents: 'none',
zIndex: 1,
opacity: 0.35,
filter: 'blur(0.3px)'
}}
/>
{/* Triangle decorations v headerju - z nižjim z-index da ne zakrivajo besedila */}
<div className="absolute top-2 right-[25%] w-0 h-0 border-l-[25px] border-l-transparent border-r-[25px] border-r-transparent border-b-[35px] border-b-blue-400/8 rotate-12 z-0"></div>
<div className="absolute top-3 left-[40%] w-0 h-0 border-l-[20px] border-l-transparent border-r-[20px] border-r-transparent border-b-[25px] border-b-purple-400/6 -rotate-6 z-0"></div>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
<div className="flex items-center justify-between h-20">
<div className="flex items-center space-x-4">
<a href="/" className="flex items-center space-x-2 hover:opacity-80 transition-opacity">
<div className="w-9 h-9 gradient-primary rounded-lg flex items-center justify-center shadow-lg">
<div className="w-0 h-0 border-l-[10px] border-l-white border-y-[7px] border-y-transparent ml-1"></div>
</div>
<h1 className="text-2xl font-bold text-white tracking-wide">go4.video</h1>
</a>
</div>
<div className="hidden md:flex items-center space-x-6">
<nav className="flex space-x-6">
<a href="/" className="text-bunny-light hover:text-bunny-blue transition-colors" data-testid="link-home">
Home
</a>
</nav>
<div className="relative">
<Input
type="search"
placeholder="Search videos..."
value={searchQuery}
onChange={(e) => handleSearchChange(e.target.value)}
className="bg-white border border-gray-300 rounded-lg px-4 py-2 pl-10 text-sm text-gray-900 placeholder-gray-500 focus:outline-none focus:border-bunny-blue transition-colors w-64"
data-testid="input-search"
/>
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
</div>
</div>
<Button variant="ghost" className="md:hidden text-bunny-light" data-testid="button-mobile-menu">
<Menu className="text-xl" />
</Button>
</div>
</div>
{/* Filter Bar */}
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<div>
<h2 className="text-2xl font-bold mb-2 text-bunny-light">Video Library</h2>
<p className="text-bunny-muted">Video streaming platform</p>
</div>
<div className="flex bg-bunny-gray rounded-lg p-1">
<Button
variant={currentView === "grid" ? "default" : "ghost"}
size="sm"
onClick={() => onViewChange("grid")}
className={`px-3 py-1 rounded text-sm ${
currentView === "grid"
? "bg-bunny-blue text-white"
: "text-bunny-muted hover:text-white"
}`}
data-testid="button-grid-view"
>
<Grid3X3 className="w-4 h-4" />
</Button>
<Button
variant={currentView === "list" ? "default" : "ghost"}
size="sm"
onClick={() => onViewChange("list")}
className={`px-3 py-1 rounded text-sm ${
currentView === "list"
? "bg-bunny-blue text-white"
: "text-bunny-muted hover:text-white"
}`}
data-testid="button-list-view"
>
<List className="w-4 h-4" />
</Button>
</div>
</div>
</div>
</div>
);
}