Add src/components/Header.tsx

This commit is contained in:
2026-05-02 18:03:47 -04:00
parent 24e94c050c
commit fcadd2d8b5

111
src/components/Header.tsx Normal file
View File

@@ -0,0 +1,111 @@
'use client';
import { useApp } from './AppProvider';
import { useState, useEffect, useRef } from 'react';
export default function Header() {
const {
view, selectedProject, projects, searchQuery, setSearchQuery,
showNewTaskModal, setShowNewTaskModal,
filterStatus, setFilterStatus, filterPriority, setFilterPriority,
filterDueBefore, setFilterDueBefore, filterDueAfter, setFilterDueAfter,
filterCompleted, setFilterCompleted,
refreshTasks,
} = useApp();
const [showFilters, setShowFilters] = useState(false);
const searchRef = useRef<HTMLInputElement>(null);
useEffect(() => {
const handler = (e: KeyboardEvent) => {
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
e.preventDefault();
searchRef.current?.focus();
}
if (e.key === 'n' && (e.metaKey || e.ctrlKey)) {
e.preventDefault();
setShowNewTaskModal(true);
}
};
window.addEventListener('keydown', handler);
return () => window.removeEventListener('keydown', handler);
}, [setShowNewTaskModal]);
const selectedProjectName = projects.find(p => p.id === selectedProject)?.name || 'All Projects';
const handleSearch = (e: React.FormEvent) => {
e.preventDefault();
refreshTasks();
};
const handleClearFilters = () => {
setFilterStatus('');
setFilterPriority('');
setFilterDueBefore('');
setFilterDueAfter('');
setFilterCompleted('');
setSearchQuery('');
refreshTasks();
};
const hasActiveFilters = filterStatus || filterPriority || filterDueBefore || filterDueAfter || filterCompleted || searchQuery;
return (
<header className="bg-card border-b border-border px-4 py-3 flex items-center gap-4">
{/* Search */}
<form onSubmit={handleSearch} className="flex-1 max-w-md">
<div className="relative">
<span className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 text-sm">🔍</span>
<input
ref={searchRef}
type="text"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="Search tasks... (⌘K)"
className="w-full bg-content border border-border rounded-lg pl-9 pr-4 py-2 text-sm focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent/20 transition-colors"
/>
</div>
</form>
{/* Project name */}
<div className="flex items-center gap-2 text-sm text-text-secondary">
<span>📋</span>
<span className="font-medium">{selectedProjectName}</span>
</div>
{/* Filter toggle */}
<button
onClick={() => setShowFilters(!showFilters)}
className={`flex items-center gap-1.5 px-3 py-2 rounded-lg text-sm transition-colors ${
showFilters || hasActiveFilters
? 'bg-accent/10 text-accent'
: 'text-text-secondary hover:bg-content'
}`}
>
<span></span>
Filters
{hasActiveFilters && (
<span className="w-2 h-2 bg-accent rounded-full" />
)}
</button>
{/* Clear filters */}
{hasActiveFilters && (
<button
onClick={handleClearFilters}
className="text-xs text-text-secondary hover:text-red-500 transition-colors"
>
Clear all
</button>
)}
{/* New task button (mobile) */}
<button
onClick={() => setShowNewTaskModal(true)}
className="bg-accent hover:bg-accent-hover text-white px-4 py-2 rounded-lg text-sm font-medium transition-colors"
>
+ New Task
</button>
</header>
);
}