feat: panel UI'ını Tailwind v4 + shadcn/ui ile yeniden tasarla (Faz 4)

Elle yazılmış tek-dosya CSS (sabit koyu tema, ham table/button, window.confirm
ile silme onayı) yerine tutarlı bir bileşen sistemi: Card/Table/Badge/Button/
Input/Switch/AlertDialog primitifleri, Hanken Grotesk + JetBrains Mono
tipografi çifti, "broadcast/monitör" temalı özel bir renk paleti (camgöbeği
accent, ok/warn/err/live durum rengi sözlüğü). Tüm sayfalar (dashboard, kanal
detay, segmentler, ayarlar, istatistik, kullanıcılar, login) aynı oturumda
taşındı — silme onayları artık gerçek AlertDialog, native confirm() değil.

Veri akışı/server action'lar değişmedi, tamamen görsel katman.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-02 14:33:24 +03:00
co-authored by Claude Sonnet 5
parent d045b24c85
commit 7d504d1938
30 changed files with 3436 additions and 801 deletions
+63 -53
View File
@@ -1,66 +1,76 @@
import { prisma } from "@streamclipper/db";
import { getSession } from "../../lib/auth";
import { addUser, deleteUser } from "./actions";
import { DeleteButton } from "../components/DeleteButton";
import { ConfirmButton } from "../components/ConfirmButton";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent } from "@/components/ui/card";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
export const dynamic = "force-dynamic";
const fieldStyle = {
background: "var(--bg)",
border: "1px solid var(--border)",
borderRadius: "6px",
padding: "0.5rem 0.7rem",
color: "var(--text)",
fontSize: "0.9rem",
};
export default async function UsersPage() {
const [users, session] = await Promise.all([
prisma.user.findMany({ orderBy: { createdAt: "asc" } }),
getSession(),
]);
const [users, session] = await Promise.all([prisma.user.findMany({ orderBy: { createdAt: "asc" } }), getSession()]);
return (
<>
<h1>Kullanıcılar</h1>
<div className="flex flex-col gap-6">
<h1 className="text-2xl font-semibold tracking-tight">Kullanıcılar</h1>
<form
action={addUser}
className="card add-channel-form"
style={{ marginBottom: "1.5rem" }}
>
<input name="username" placeholder="Kullanıcı adı" required style={fieldStyle} />
<input name="password" type="password" placeholder="Şifre (en az 8 karakter)" required minLength={8} style={fieldStyle} />
<button type="submit">Kullanıcı Ekle</button>
</form>
<Card>
<CardContent>
<form action={addUser} className="flex flex-wrap gap-2">
<Input name="username" placeholder="Kullanıcı adı" required className="flex-1 min-w-[140px]" />
<Input
name="password"
type="password"
placeholder="Şifre (en az 8 karakter)"
required
minLength={8}
className="flex-1 min-w-[160px]"
/>
<Button type="submit">Kullanıcı Ekle</Button>
</form>
</CardContent>
</Card>
<table>
<thead>
<tr>
<th>Kullanıcı Adı</th>
<th>Oluşturulma</th>
<th></th>
</tr>
</thead>
<tbody>
{users.map((u) => (
<tr key={u.id}>
<td>
{u.username}
{u.id === session?.sub && <span className="badge muted" style={{ marginLeft: "0.5rem" }}>sen</span>}
</td>
<td className="mono">{u.createdAt.toLocaleString("tr-TR")}</td>
<td>
{u.id !== session?.sub && users.length > 1 && (
<form action={deleteUser.bind(null, u.id)}>
<DeleteButton confirmText={`${u.username} kullanıcısını silmek istediğine emin misin?`} />
</form>
)}
</td>
</tr>
))}
</tbody>
</table>
</>
<Card>
<CardContent>
<Table>
<TableHeader>
<TableRow>
<TableHead>Kullanıcı Adı</TableHead>
<TableHead>Oluşturulma</TableHead>
<TableHead className="text-right"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{users.map((u) => (
<TableRow key={u.id}>
<TableCell>
{u.username}
{u.id === session?.sub && (
<Badge variant="muted" className="ml-2">
sen
</Badge>
)}
</TableCell>
<TableCell className="font-mono-num text-xs text-muted-foreground">
{u.createdAt.toLocaleString("tr-TR")}
</TableCell>
<TableCell className="text-right">
{u.id !== session?.sub && users.length > 1 && (
<form action={deleteUser.bind(null, u.id)}>
<ConfirmButton confirmText={`${u.username} kullanıcısını silmek istediğine emin misin?`} label="Sil" />
</form>
)}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
</div>
);
}