diff --git a/frontend/src/components/DataTable.tsx b/frontend/src/components/DataTable.tsx index fbaa712..e34b8d9 100644 --- a/frontend/src/components/DataTable.tsx +++ b/frontend/src/components/DataTable.tsx @@ -32,14 +32,14 @@ export function DataTable({ }) return ( -
+
- + {table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => { return ( - + {header.isPlaceholder ? null : flexRender( @@ -58,6 +58,7 @@ export function DataTable({ {row.getVisibleCells().map((cell) => ( @@ -68,8 +69,13 @@ export function DataTable({ )) ) : ( - - No results. + +
+
+ +
+

未找到匹配的仓库

+
)} diff --git a/frontend/src/components/RepositoryManager.tsx b/frontend/src/components/RepositoryManager.tsx index 57c609a..1298bb0 100644 --- a/frontend/src/components/RepositoryManager.tsx +++ b/frontend/src/components/RepositoryManager.tsx @@ -13,21 +13,21 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@ function DataTableSkeleton() { return ( -
+
- - - - - + + + + + {Array.from({ length: 10 }).map((_, i) => ( - - - - + + + + ))} @@ -61,16 +61,15 @@ export function RepositoryManager() { return (
-
-

仓库 Webhook 管理

-
- +
+
+ setSearchTerm(e.target.value)} - className="pl-8 sm:w-[300px] md:w-[200px] lg:w-[300px]" + className="pl-9 w-full sm:w-[300px] md:w-[250px] lg:w-[300px] bg-zinc-900/50 border-border/50 text-zinc-200 placeholder:text-zinc-600 focus-visible:ring-1 focus-visible:ring-primary/50 focus-visible:border-primary transition-all font-mono text-sm" />
@@ -78,20 +77,27 @@ export function RepositoryManager() { {isLoading ? ( ) : isError ? ( -
- {/* The original Alert component was removed, so this will now just show the error message */} -

加载仓库列表失败: {error.message}

+
+
+
+ +
+
+

System Error_

+

加载仓库列表失败: {error.message}

+
+
) : ( <> {totalPages > 1 && ( -
-
- 第 {page} 页 / 共 {totalPages} 页 (共 {totalCount} 个仓库) +
+
+ 第 {page} 页 / 共 {totalPages}|{totalCount} 个仓库
- - + + Math.max(1, p - 1)); }} - className={page <= 1 ? "pointer-events-none opacity-50" : ""} + className={`border border-border/50 hover:bg-zinc-800 hover:text-primary hover:border-primary/50 font-mono text-xs transition-colors ${page <= 1 ? "pointer-events-none opacity-30 bg-zinc-900/30" : "bg-zinc-900 text-zinc-400"}`} /> @@ -109,7 +115,7 @@ export function RepositoryManager() { e.preventDefault(); setPage(p => Math.min(totalPages, p + 1)); }} - className={page >= totalPages ? "pointer-events-none opacity-50" : ""} + className={`border border-border/50 hover:bg-zinc-800 hover:text-primary hover:border-primary/50 font-mono text-xs transition-colors ${page >= totalPages ? "pointer-events-none opacity-30 bg-zinc-900/30" : "bg-zinc-900 text-zinc-400"}`} /> diff --git a/frontend/src/components/RepositoryTableColumns.tsx b/frontend/src/components/RepositoryTableColumns.tsx index c4170ad..bd0913f 100644 --- a/frontend/src/components/RepositoryTableColumns.tsx +++ b/frontend/src/components/RepositoryTableColumns.tsx @@ -2,14 +2,13 @@ import type { ColumnDef } from "@tanstack/react-table" import type { Repository } from "@/services/repositoryService" -import { Badge } from "@/components/ui/badge" import { WebhookToggleButton } from "@/components/WebhookToggleButton" export const columns: ColumnDef[] = [ { accessorKey: "name", header: "仓库名称", - cell: ({ row }) =>
{row.getValue("name")}
, + cell: ({ row }) =>
{row.getValue("name")}
, }, { accessorKey: "webhook_status", @@ -18,15 +17,16 @@ export const columns: ColumnDef[] = [ const status = row.getValue("webhook_status") as Repository["webhook_status"] const isActive = status === 'active' return ( - +
+ {isActive && } {isActive ? '已启用' : '未启用'} - +
) }, }, { id: "actions", - header: () =>
操作
, + header: () =>
操作
, cell: ({ row }) => { const repo = row.original return ( diff --git a/frontend/src/components/WebhookToggleButton.tsx b/frontend/src/components/WebhookToggleButton.tsx index 9c8ca90..3b5f261 100644 --- a/frontend/src/components/WebhookToggleButton.tsx +++ b/frontend/src/components/WebhookToggleButton.tsx @@ -1,5 +1,6 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; import api from '@/lib/api'; +import { Loader2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { toast } from "sonner"; @@ -32,14 +33,26 @@ export function WebhookToggleButton({ repoName, status, hookId }: WebhookToggleB return ( ); } diff --git a/frontend/src/index.css b/frontend/src/index.css index 5eec7f3..d858db0 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -1,51 +1,53 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap'); + @tailwind base; @tailwind components; @tailwind utilities; @layer base { :root { - --background: 0 0% 100%; + --background: 240 10% 98%; --foreground: 240 10% 3.9%; --card: 0 0% 100%; --card-foreground: 240 10% 3.9%; --popover: 0 0% 100%; --popover-foreground: 240 10% 3.9%; - --primary: 240 5.9% 10%; - --primary-foreground: 0 0% 98%; + --primary: 180 100% 35%; + --primary-foreground: 0 0% 100%; --secondary: 240 4.8% 95.9%; --secondary-foreground: 240 5.9% 10%; --muted: 240 4.8% 95.9%; --muted-foreground: 240 3.8% 46.1%; - --accent: 240 4.8% 95.9%; - --accent-foreground: 240 5.9% 10%; + --accent: 180 100% 35%; + --accent-foreground: 0 0% 100%; --destructive: 0 84.2% 60.2%; --destructive-foreground: 0 0% 98%; --border: 240 5.9% 90%; --input: 240 5.9% 90%; - --ring: 240 10% 3.9%; + --ring: 180 100% 35%; --radius: 0.5rem; } .dark { - --background: 240 10% 3.9%; + --background: 240 10% 4%; --foreground: 0 0% 98%; - --card: 240 10% 3.9%; + --card: 240 10% 6%; --card-foreground: 0 0% 98%; - --popover: 240 10% 3.9%; + --popover: 240 10% 6%; --popover-foreground: 0 0% 98%; - --primary: 0 0% 98%; - --primary-foreground: 240 5.9% 10%; - --secondary: 240 3.7% 15.9%; + --primary: 175 90% 45%; + --primary-foreground: 240 10% 4%; + --secondary: 240 5% 15%; --secondary-foreground: 0 0% 98%; - --muted: 240 3.7% 15.9%; - --muted-foreground: 240 5% 64.9%; - --accent: 240 3.7% 15.9%; - --accent-foreground: 0 0% 98%; + --muted: 240 5% 15%; + --muted-foreground: 240 5% 65%; + --accent: 175 90% 45%; + --accent-foreground: 240 10% 4%; --destructive: 0 62.8% 30.6%; --destructive-foreground: 0 0% 98%; - --border: 240 3.7% 15.9%; - --input: 240 3.7% 15.9%; - --ring: 240 4.9% 83.9%; + --border: 240 5% 15%; + --input: 240 5% 15%; + --ring: 175 90% 45%; } } @@ -54,6 +56,32 @@ @apply border-border; } body { - @apply bg-background text-foreground; + @apply bg-background text-foreground font-sans antialiased selection:bg-primary/30 selection:text-primary; + } + h1, h2, h3, h4, h5, h6 { + @apply tracking-tight; + } + code, pre, .font-mono { + font-family: 'JetBrains Mono', monospace; + } +} + +@layer utilities { + .font-sans { + font-family: 'Inter', sans-serif; + } + .bg-grid-pattern { + background-size: 40px 40px; + background-image: linear-gradient(to right, rgba(255, 255, 255, 0.05) 1px, transparent 1px), + linear-gradient(to bottom, rgba(255, 255, 255, 0.05) 1px, transparent 1px); + } + .glass-panel { + @apply bg-zinc-950/50 backdrop-blur-xl border border-white/10 shadow-2xl; + } + .tech-glow { + box-shadow: 0 0 20px -5px hsl(var(--primary) / 0.5); + } + .tech-glow:hover { + box-shadow: 0 0 30px -5px hsl(var(--primary) / 0.7); } } diff --git a/frontend/src/pages/LoginPage.tsx b/frontend/src/pages/LoginPage.tsx index 28a4521..8246ac9 100644 --- a/frontend/src/pages/LoginPage.tsx +++ b/frontend/src/pages/LoginPage.tsx @@ -2,8 +2,7 @@ import { useState } from 'react'; import api from '@/lib/api'; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { Bot } from 'lucide-react'; +import { Bot, Terminal, ShieldCheck, ArrowRight, Activity } from 'lucide-react'; export function LoginPage() { const [password, setPassword] = useState(''); @@ -30,37 +29,87 @@ export function LoginPage() { }; return ( -
-
-
- -

Gitea AI Assistant

-

智能代码审查,自动化您的工作流

-
-
-
-
-
-

登录

-

- 请输入您的管理员密码以继续 -

+
+ {/* Background grid and gradient effects */} +
+
+
+ +
+
+ {/* Decorative terminal dots */} +
+
+
+
-
-
- - setPassword(e.target.value)} - onKeyDown={(e) => e.key === 'Enter' && !isLoading && handleLogin()} - required - /> + +
+
+
+
- {error &&

{error}

} -
+ +
+
+
+ +
+
+ setPassword(e.target.value)} + onKeyDown={(e) => e.key === 'Enter' && !isLoading && handleLogin()} + required + placeholder="••••••••" + className="h-12 border-zinc-800 bg-zinc-900/50 font-mono text-zinc-100 placeholder:text-zinc-700 focus-visible:border-primary/50 focus-visible:ring-primary/20 transition-all duration-300" + /> + +
+
+ + {error && ( +
+ +

{error}

+
+ )} + +