Files
nebula/src/app/tasks/page.tsx
T
florian.wildeandClaude Opus 5 6a7365946b fix(ui): Dialoge weichen der Bildschirmtastatur aus
Auf dem Telefon verdeckte die Tastatur den halben Dialog – bei der
Schnellerfassung genau das Eingabefeld, um das es geht.

Ursache ist der Unterschied zwischen Layout- und Sichtfenster: die Tastatur
schiebt sich darueber, ohne dass sich fuer die Seite etwas aendert.
"position: fixed" und "100vh" beziehen sich weiter auf das volle Fenster,
ein mittig stehender Dialog liegt damit zur Haelfte darunter.

Der Dialog richtet sich jetzt nach window.visualViewport – Hoehe und oberer
Rand kommen von dort und werden bei jeder Aenderung nachgefuehrt. Weil der
Behaelter scrollbar ist, holt der Browser das fokussierte Feld dann von
selbst ins Bild. Das gilt fuer alle Dialoge, nicht nur die Schnellerfassung.

Dazu, weil es beim Nachsehen auffiel: Aufgaben lassen sich in der
Uebersicht direkt bearbeiten. Bisher fuehrte von dort nur der Weg ins
Projekt, und wer eine Faelligkeit aendern wollte, musste die Aufgabe im
Brett wiederfinden. Der Dialog nimmt dafuer eine schlankere Form entgegen
als den vollstaendigen Prisma-Datensatz.

Geprueft mit einem nachgestellten Sichtfenster: Eingabefeld und Absende-
knopf liegen bei 375x667 und aufgeklappter Tastatur vollstaendig im freien
Bereich. Vorher lagen beide darunter.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-15 00:34:56 +02:00

53 lines
1.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { Metadata } from "next";
import { TaskOverview } from "@/components/tasks/TaskOverview";
import { requireUserPage } from "@/lib/auth/guard";
import { prisma } from "@/lib/db";
import { dueBucket } from "@/lib/tasks";
import type { TaskOverviewItem } from "@/types";
export const dynamic = "force-dynamic";
export const metadata: Metadata = { title: "Aufgaben" };
export default async function TasksPage() {
const user = await requireUserPage();
/**
* Die Aufgabe kennt keinen Besitzer – die Trennung laeuft ueber das
* Projekt. Die Bedingung steht deshalb als einzige und erste in der
* where-Klausel; eine fremde Aufgabe kann hier gar nicht auftauchen.
*/
const tasks = await prisma.task.findMany({
where: { project: { ownerId: user.id } },
include: {
project: { select: { id: true, name: true, accent: true, status: true } },
},
// NULL-Termine sortiert Postgres bei ASC ans Ende – genau richtig,
// Aufgaben ohne Termin gehoeren nicht nach oben.
orderBy: [{ dueDate: "asc" }, { position: "asc" }],
});
/**
* Das Fach wird auf dem Server bestimmt, nicht im Browser. "Heute" haengt
* an der Uhr, und zwei verschiedene Antworten zwischen Server-Render und
* Hydration waeren genau der Fehler, den die feste Zeitzone in lib/utils
* sonst vermeidet.
*/
const jetzt = new Date();
const items: TaskOverviewItem[] = tasks.map((task) => ({
id: task.id,
title: task.title,
description: task.description,
status: task.status,
dueDate: task.dueDate ? task.dueDate.toISOString() : null,
labels: task.labels,
recurrence: task.recurrence,
sourceIssue: task.sourceIssue,
sourceUrl: task.sourceUrl,
bucket: dueBucket(task.dueDate, jetzt),
project: task.project,
}));
return <TaskOverview tasks={items} />;
}