feat(ui): Dashboard mit Board, Filtern und direktem Statuswechsel

- Fuenf Kennzahlen ueber dem Board: Projektzahl mit Durchschnittsfortschritt,
  Ideen, aktive Entwicklungen, fertige Projekte, verknuepfte Repos
- Volltextsuche ueber Name, Beschreibung, Tags und Repo-Pfad
- Statusfilter als Chips mit Trefferzaehler, mehrfach kombinierbar
- Sortierung nach Aenderung, Anlage, Name, Fortschritt oder Prioritaet;
  Favoriten stehen immer oben
- Zwei Ansichten: freies Raster oder nach Status gruppiert
- Archiv standardmaessig ausgeblendet, per Schalter sichtbar

Die Projektkarte zeigt Fortschritt, Provider, Default-Branch, letzten Tag,
Alter des letzten Commits, Notizzahl und Sync-Fehler. Status und Favorit sind
direkt auf der Karte aenderbar - beides optimistisch, mit Rollback wenn der
Server ablehnt. Die Karte ist ein "stretched link", damit die Schaltflaechen
darin nicht in einem Anker verschachtelt sind.

Der Anlege-Dialog verlangt nur einen Namen; neue Projekte starten als Idee.
Ist eine Git-Verbindung gewaehlt, laesst sich das Repository aus einer
durchsuchbaren Liste uebernehmen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-25 19:34:29 +02:00
co-authored by Claude Opus 5
parent 6fcbc04110
commit 62b5c5bfa6
7 changed files with 1297 additions and 0 deletions
+36
View File
@@ -0,0 +1,36 @@
import type { LucideIcon } from "lucide-react";
interface StatCardProps {
label: string;
value: number | string;
hint?: string;
icon: LucideIcon;
color: string;
}
export function StatCard({ label, value, hint, icon: Icon, color }: StatCardProps) {
return (
<div className="glass relative overflow-hidden p-4">
<div
className="pointer-events-none absolute -right-6 -top-8 h-24 w-24 rounded-full opacity-25 blur-2xl"
style={{ backgroundColor: color }}
aria-hidden="true"
/>
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<p className="text-[11px] font-semibold uppercase tracking-[0.14em] text-slate-500">
{label}
</p>
<p className="mt-2 text-3xl font-semibold tabular-nums text-white">{value}</p>
{hint ? <p className="mt-1 truncate text-xs text-slate-500">{hint}</p> : null}
</div>
<span
className="grid h-9 w-9 shrink-0 place-items-center rounded-xl"
style={{ backgroundColor: `${color}1f`, color }}
>
<Icon className="h-4 w-4" />
</span>
</div>
</div>
);
}