Some checks failed
Profile Linker Docker Build / Build and push Docker image (push) Failing after 3s
- Integrated Cloudflare R2 for template storage and converted file management - Added Google Gemini AI for resume parsing and HTML generation - Created backend API endpoints for templates, conversion, and history - Refactored frontend to use real API instead of mock data - Fixed Docker networking issues (IPv6/IPv4) for R2 connectivity - Added resumeService.ts for frontend API integration - Updated Vite configuration for proper asset serving in Docker - Successfully tested with 13 templates from R2 bucket
91 lines
3.9 KiB
TypeScript
91 lines
3.9 KiB
TypeScript
import React, { useState, FormEvent } from 'react';
|
|
// FIX: Import Sparkles icon for AI feature button
|
|
import { Search, RefreshCw, X, FolderPlus, Sparkles } from 'lucide-react';
|
|
|
|
interface HeaderBarProps {
|
|
onSearch: (term: string) => void;
|
|
onRefresh: () => void;
|
|
onCreateFolder: () => void;
|
|
// FIX: Add prop for new AI feature
|
|
onAnalyzeImage: () => void;
|
|
isLoading: boolean;
|
|
}
|
|
|
|
const HeaderBar: React.FC<HeaderBarProps> = ({ onSearch, onRefresh, onCreateFolder, onAnalyzeImage, isLoading }) => {
|
|
const [inputValue, setInputValue] = useState('');
|
|
|
|
const handleSearch = (e: FormEvent) => {
|
|
e.preventDefault();
|
|
onSearch(inputValue);
|
|
};
|
|
|
|
const handleClear = () => {
|
|
setInputValue('');
|
|
onSearch('');
|
|
};
|
|
|
|
return (
|
|
<div className="bg-white/80 dark:bg-slate-800/80 backdrop-blur-sm p-4 rounded-lg shadow-lg mb-8 sticky top-4 z-10 border border-slate-200 dark:border-slate-700">
|
|
<form onSubmit={handleSearch} className="flex flex-col md:flex-row items-center gap-4">
|
|
<div className="relative w-full">
|
|
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-400 pointer-events-none" />
|
|
<input
|
|
type="text"
|
|
placeholder="Search files by name..."
|
|
value={inputValue}
|
|
onChange={(e) => setInputValue(e.target.value)}
|
|
className="w-full pl-10 pr-10 py-2 border border-slate-300 dark:border-slate-600 rounded-md bg-slate-50 dark:bg-slate-700 text-slate-800 dark:text-slate-200 focus:ring-2 focus:ring-primary focus:border-primary outline-none transition"
|
|
/>
|
|
{inputValue && (
|
|
<button
|
|
type="button"
|
|
onClick={handleClear}
|
|
className="absolute right-3 top-1/2 -translate-y-1/2 p-1 text-slate-500 hover:text-slate-800 dark:hover:text-slate-200"
|
|
aria-label="Clear search"
|
|
>
|
|
<X className="w-4 h-4" />
|
|
</button>
|
|
)}
|
|
</div>
|
|
<div className="flex items-center gap-2 w-full md:w-auto flex-shrink-0">
|
|
<button
|
|
type="button"
|
|
onClick={onCreateFolder}
|
|
className="flex items-center justify-center gap-2 w-full md:w-auto px-4 py-2 bg-green-500 text-white font-semibold rounded-md hover:bg-green-600 dark:bg-green-600 dark:hover:bg-green-500 transition-colors"
|
|
>
|
|
<FolderPlus className="w-5 h-5" />
|
|
<span>New Folder</span>
|
|
</button>
|
|
{/* FIX: Add new button for AI Vision feature */}
|
|
<button
|
|
type="button"
|
|
onClick={onAnalyzeImage}
|
|
className="flex items-center justify-center gap-2 w-full md:w-auto px-4 py-2 bg-purple-500 text-white font-semibold rounded-md hover:bg-purple-600 dark:bg-purple-600 dark:hover:bg-purple-500 transition-colors"
|
|
>
|
|
<Sparkles className="w-5 h-5" />
|
|
<span>Analyze Image</span>
|
|
</button>
|
|
<button
|
|
type="submit"
|
|
className="flex items-center justify-center gap-2 w-full md:w-auto px-4 py-2 bg-slate-700 text-white font-semibold rounded-md hover:bg-slate-800 dark:bg-slate-600 dark:hover:bg-slate-500 transition-colors"
|
|
>
|
|
<Search className="w-5 h-5" />
|
|
<span>Search</span>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={onRefresh}
|
|
disabled={isLoading}
|
|
className="flex items-center justify-center gap-2 w-full md:w-auto px-4 py-2 bg-primary text-white font-semibold rounded-md hover:bg-blue-600 transition-colors disabled:bg-slate-400 disabled:cursor-not-allowed"
|
|
>
|
|
<RefreshCw className={`w-5 h-5 ${isLoading ? 'animate-spin' : ''}`} />
|
|
<span>Refresh</span>
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default HeaderBar;
|