feat: modernize main list pages from tables to card-based rows
New shared ListItemCard component: icon avatar, title/subtitle, trailing badges/actions, chevron affordance when linked to a detail page. Applied to the 9 primary data-list pages (Bienenstaende, Voelker, Koeniginnen, Honigchargen, Aufgaben, Lager, Produkte, Inventar, Wiederkehrende Aufgaben), replacing the plain HTML tables with the same rounded-card list aesthetic already used elsewhere in the app (inspections, treatments, varroa, etc.), for a consistent look across the whole product. Admin/settings tables (Benutzer, Webhooks, Audit-Log, Import) intentionally left as tables per user's scoping choice.
This commit is contained in:
1 parent
faefd47e4b
commit
c586bff18f
10 files changed
+242
-362
No files matched your search
@@ -10,6 +10,7 @@ import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { PageHeader } from "@/components/page-header";
|
||||
import { EmptyState } from "@/components/empty-state";
|
||||
import { ListItemCard } from "@/components/list-item-card";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -17,14 +18,6 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { TaskEditDialog } from "./task-edit-dialog";
|
||||
|
||||
const STATUS_OPTIONS: TaskStatus[] = ["OPEN", "IN_PROGRESS", "DONE", "CANCELLED"];
|
||||
@@ -137,48 +130,37 @@ export default function TasksPage() {
|
||||
) : null}
|
||||
|
||||
{tasks && visibleTasks.length > 0 ? (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Titel</TableHead>
|
||||
<TableHead>Priorität</TableHead>
|
||||
<TableHead>Fällig</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
<TableHead>Aktion</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{visibleTasks.map((task) => (
|
||||
<TableRow key={task.id}>
|
||||
<TableCell>{task.title}</TableCell>
|
||||
<TableCell>{task.priority}</TableCell>
|
||||
<TableCell>
|
||||
{task.dueDate ? new Date(task.dueDate).toLocaleDateString("de-DE") : "—"}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex flex-col gap-2">
|
||||
{visibleTasks.map((task) => (
|
||||
<ListItemCard
|
||||
key={task.id}
|
||||
icon={ListTodo}
|
||||
gradient="var(--gradient-sky)"
|
||||
title={task.title}
|
||||
subtitle={`${task.priority} · Fällig: ${
|
||||
task.dueDate ? new Date(task.dueDate).toLocaleDateString("de-DE") : "—"
|
||||
}`}
|
||||
trailing={
|
||||
<>
|
||||
<Badge variant={task.status === "DONE" ? "secondary" : "default"}>
|
||||
{task.status}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="flex items-center gap-2">
|
||||
<TaskEditDialog task={task} />
|
||||
{task.status !== "DONE" && task.status !== "CANCELLED" ? (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
disabled={completeMutation.isPending}
|
||||
onClick={() => completeMutation.mutate(task.id)}
|
||||
>
|
||||
Erledigen
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TaskEditDialog task={task} />
|
||||
{task.status !== "DONE" && task.status !== "CANCELLED" ? (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
disabled={completeMutation.isPending}
|
||||
onClick={() => completeMutation.mutate(task.id)}
|
||||
>
|
||||
Erledigen
|
||||
</Button>
|
||||
) : null}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</main>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user