Make all title bars sticky and improve mobile calendar display
The `CalendarView`, `KanbanBoard`, and `TasksWithCalendar` components now have sticky header elements. The `CalendarView` and `KanbanBoard` headers are applied with `sticky top-16` for proper placement within the app's layout. Additionally, for mobile views, the calendar display in `TasksWithCalendar` has been adjusted for better readability. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ceced2fc-aa46-458d-ba87-ddd4b7bb1518 Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/659922a9-0087-461c-90dd-6d9a58b81d4d/ceced2fc-aa46-458d-ba87-ddd4b7bb1518/7CG7dga
This commit is contained in:
@@ -66,34 +66,36 @@ export default function CalendarView({ tasks, onTaskDrop, onTaskClick, onDateSel
|
|||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="sticky top-16 z-40 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 border-b pb-3 mb-4">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center justify-between">
|
||||||
<Calendar className="w-5 h-5 text-primary" />
|
<div className="flex items-center gap-2">
|
||||||
<h2 className="text-lg font-semibold" data-testid="text-calendar-title">
|
<Calendar className="w-5 h-5 text-primary" />
|
||||||
5-Week Calendar View
|
<h2 className="text-lg font-semibold" data-testid="text-calendar-title">
|
||||||
</h2>
|
5-Week Calendar View
|
||||||
</div>
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="icon"
|
size="icon"
|
||||||
onClick={() => navigateWeek('prev')}
|
onClick={() => navigateWeek('prev')}
|
||||||
data-testid="button-prev-week"
|
data-testid="button-prev-week"
|
||||||
className="w-8 h-8"
|
className="w-8 h-8"
|
||||||
>
|
>
|
||||||
<ChevronLeft className="w-4 h-4" />
|
<ChevronLeft className="w-4 h-4" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="icon"
|
size="icon"
|
||||||
onClick={() => navigateWeek('next')}
|
onClick={() => navigateWeek('next')}
|
||||||
data-testid="button-next-week"
|
data-testid="button-next-week"
|
||||||
className="w-8 h-8"
|
className="w-8 h-8"
|
||||||
>
|
>
|
||||||
<ChevronRight className="w-4 h-4" />
|
<ChevronRight className="w-4 h-4" />
|
||||||
</Button>
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -169,45 +169,46 @@ export default function KanbanBoard({ tasks, onTaskStatusChange, onTaskUpdate, o
|
|||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="sticky top-16 z-40 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 border-b pb-3 mb-4">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center justify-between mb-4">
|
||||||
<LayoutGrid className="w-5 h-5 text-primary" />
|
<div className="flex items-center gap-2">
|
||||||
<h2 className="text-lg font-semibold" data-testid="text-kanban-title">
|
<LayoutGrid className="w-5 h-5 text-primary" />
|
||||||
Task Board
|
<h2 className="text-lg font-semibold" data-testid="text-kanban-title">
|
||||||
</h2>
|
Task Board
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{viewMode !== 'traditional' && (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="icon"
|
||||||
|
onClick={() => navigatePeriod('prev')}
|
||||||
|
data-testid="button-prev-period"
|
||||||
|
className="w-8 h-8"
|
||||||
|
>
|
||||||
|
<ChevronLeft className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<span className="text-sm font-medium min-w-[120px] text-center">
|
||||||
|
{getPeriodTitle()}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="icon"
|
||||||
|
onClick={() => navigatePeriod('next')}
|
||||||
|
data-testid="button-next-period"
|
||||||
|
className="w-8 h-8"
|
||||||
|
>
|
||||||
|
<ChevronRight className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{viewMode !== 'traditional' && (
|
{/* Filter Bar */}
|
||||||
<div className="flex items-center gap-2">
|
<Card className="p-4">
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="icon"
|
|
||||||
onClick={() => navigatePeriod('prev')}
|
|
||||||
data-testid="button-prev-period"
|
|
||||||
className="w-8 h-8"
|
|
||||||
>
|
|
||||||
<ChevronLeft className="w-4 h-4" />
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<span className="text-sm font-medium min-w-[120px] text-center">
|
|
||||||
{getPeriodTitle()}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
size="icon"
|
|
||||||
onClick={() => navigatePeriod('next')}
|
|
||||||
data-testid="button-next-period"
|
|
||||||
className="w-8 h-8"
|
|
||||||
>
|
|
||||||
<ChevronRight className="w-4 h-4" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Filter Bar */}
|
|
||||||
<Card className="p-4">
|
|
||||||
<div className="flex items-center justify-between flex-wrap gap-4">
|
<div className="flex items-center justify-between flex-wrap gap-4">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Filter className="w-4 h-4 text-muted-foreground" />
|
<Filter className="w-4 h-4 text-muted-foreground" />
|
||||||
@@ -394,6 +395,7 @@ export default function KanbanBoard({ tasks, onTaskStatusChange, onTaskUpdate, o
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* View Mode Tabs */}
|
{/* View Mode Tabs */}
|
||||||
<Tabs value={viewMode} onValueChange={(value) => setViewMode(value as ViewMode)}>
|
<Tabs value={viewMode} onValueChange={(value) => setViewMode(value as ViewMode)}>
|
||||||
|
|||||||
@@ -181,69 +181,70 @@ export default function TasksWithCalendar({ tasks, onTaskUpdate, onTaskEdit, onS
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{/* Header */}
|
{/* Header and Search Filters - Sticky */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="sticky top-16 z-40 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 border-b pb-3 mb-4">
|
||||||
<h2 className="text-lg font-semibold" data-testid="text-task-list-title">
|
<div className="space-y-3">
|
||||||
My Tasks
|
{/* Title Bar */}
|
||||||
</h2>
|
<div className="flex items-center justify-between">
|
||||||
<Badge variant="secondary" data-testid="badge-task-count">
|
<h2 className="text-lg font-semibold" data-testid="text-task-list-title">
|
||||||
{filteredAndSortedTasks.length} tasks
|
My Tasks
|
||||||
</Badge>
|
</h2>
|
||||||
</div>
|
<Badge variant="secondary" data-testid="badge-task-count">
|
||||||
|
{filteredAndSortedTasks.length} tasks
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
<div className="relative">
|
||||||
|
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-muted-foreground" />
|
||||||
|
<Input
|
||||||
|
placeholder="Search tasks..."
|
||||||
|
value={searchQuery}
|
||||||
|
onChange={(e) => {
|
||||||
|
setSearchQuery(e.target.value);
|
||||||
|
console.log('Search query:', e.target.value);
|
||||||
|
}}
|
||||||
|
className="pl-10"
|
||||||
|
data-testid="input-search-tasks"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Search and Filters */}
|
<div className="flex gap-3">
|
||||||
<div className="space-y-3">
|
<Select value={filterBy} onValueChange={(value: FilterOption) => {
|
||||||
<div className="relative">
|
setFilterBy(value);
|
||||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-muted-foreground" />
|
console.log('Filter changed to:', value);
|
||||||
<Input
|
}}>
|
||||||
placeholder="Search tasks..."
|
<SelectTrigger className="flex-1" data-testid="select-filter">
|
||||||
value={searchQuery}
|
<div className="flex items-center gap-2">
|
||||||
onChange={(e) => {
|
<Filter className="w-4 h-4" />
|
||||||
setSearchQuery(e.target.value);
|
<SelectValue />
|
||||||
console.log('Search query:', e.target.value);
|
</div>
|
||||||
}}
|
</SelectTrigger>
|
||||||
className="pl-10"
|
<SelectContent>
|
||||||
data-testid="input-search-tasks"
|
<SelectItem value="all">All ({getFilterCount('all')})</SelectItem>
|
||||||
/>
|
<SelectItem value="todo">To Do ({getFilterCount('todo')})</SelectItem>
|
||||||
</div>
|
<SelectItem value="inProgress">In Progress ({getFilterCount('inProgress')})</SelectItem>
|
||||||
|
<SelectItem value="done">Done ({getFilterCount('done')})</SelectItem>
|
||||||
|
<SelectItem value="overdue">Overdue ({getFilterCount('overdue')})</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
|
||||||
<div className="flex gap-3">
|
<Select value={sortBy} onValueChange={(value: SortOption) => {
|
||||||
<Select value={filterBy} onValueChange={(value: FilterOption) => {
|
setSortBy(value);
|
||||||
setFilterBy(value);
|
console.log('Sort changed to:', value);
|
||||||
console.log('Filter changed to:', value);
|
}}>
|
||||||
}}>
|
<SelectTrigger className="flex-1" data-testid="select-sort">
|
||||||
<SelectTrigger className="flex-1" data-testid="select-filter">
|
<div className="flex items-center gap-2">
|
||||||
<div className="flex items-center gap-2">
|
<SortAsc className="w-4 h-4" />
|
||||||
<Filter className="w-4 h-4" />
|
<SelectValue />
|
||||||
<SelectValue />
|
</div>
|
||||||
</div>
|
</SelectTrigger>
|
||||||
</SelectTrigger>
|
<SelectContent>
|
||||||
<SelectContent>
|
<SelectItem value="dueDate">Due Date</SelectItem>
|
||||||
<SelectItem value="all">All ({getFilterCount('all')})</SelectItem>
|
<SelectItem value="priority">Priority</SelectItem>
|
||||||
<SelectItem value="todo">To Do ({getFilterCount('todo')})</SelectItem>
|
<SelectItem value="title">Title</SelectItem>
|
||||||
<SelectItem value="inProgress">In Progress ({getFilterCount('inProgress')})</SelectItem>
|
<SelectItem value="status">Status</SelectItem>
|
||||||
<SelectItem value="done">Done ({getFilterCount('done')})</SelectItem>
|
</SelectContent>
|
||||||
<SelectItem value="overdue">Overdue ({getFilterCount('overdue')})</SelectItem>
|
</Select>
|
||||||
</SelectContent>
|
</div>
|
||||||
</Select>
|
|
||||||
|
|
||||||
<Select value={sortBy} onValueChange={(value: SortOption) => {
|
|
||||||
setSortBy(value);
|
|
||||||
console.log('Sort changed to:', value);
|
|
||||||
}}>
|
|
||||||
<SelectTrigger className="flex-1" data-testid="select-sort">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<SortAsc className="w-4 h-4" />
|
|
||||||
<SelectValue />
|
|
||||||
</div>
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="dueDate">Due Date</SelectItem>
|
|
||||||
<SelectItem value="priority">Priority</SelectItem>
|
|
||||||
<SelectItem value="title">Title</SelectItem>
|
|
||||||
<SelectItem value="status">Status</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user