feat: initial commit - Scrapyd UI web interface
- Next.js 16.0.1 + React 19.2.0 + Tailwind CSS 4.1.16 - Complete Scrapyd API integration (all 12 endpoints) - Dashboard with real-time job monitoring - Projects management (upload, list, delete) - Spiders management with scheduling - Jobs monitoring with filtering and cancellation - System status monitoring - Dark/light theme toggle with next-themes - Server-side authentication via environment variables - Docker deployment with multi-stage builds - GitHub Actions CI/CD workflow 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
83
components/sidebar.tsx
Normal file
83
components/sidebar.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
LayoutDashboard,
|
||||
FolderKanban,
|
||||
Bug,
|
||||
BriefcaseBusiness,
|
||||
Activity,
|
||||
} from "lucide-react";
|
||||
import { ThemeToggle } from "./theme-toggle";
|
||||
|
||||
const routes = [
|
||||
{
|
||||
label: "Dashboard",
|
||||
icon: LayoutDashboard,
|
||||
href: "/",
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
label: "Projects",
|
||||
icon: FolderKanban,
|
||||
href: "/projects",
|
||||
},
|
||||
{
|
||||
label: "Spiders",
|
||||
icon: Bug,
|
||||
href: "/spiders",
|
||||
},
|
||||
{
|
||||
label: "Jobs",
|
||||
icon: BriefcaseBusiness,
|
||||
href: "/jobs",
|
||||
},
|
||||
{
|
||||
label: "System",
|
||||
icon: Activity,
|
||||
href: "/system",
|
||||
},
|
||||
];
|
||||
|
||||
export function Sidebar() {
|
||||
const pathname = usePathname();
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-64 flex-col border-r bg-card">
|
||||
<div className="flex h-16 items-center border-b px-6">
|
||||
<h1 className="text-xl font-bold">Scrapy UI</h1>
|
||||
</div>
|
||||
<nav className="flex-1 gap-1 p-4">
|
||||
{routes.map((route) => {
|
||||
const isActive = route.exact
|
||||
? pathname === route.href
|
||||
: pathname?.startsWith(route.href);
|
||||
|
||||
return (
|
||||
<Link
|
||||
key={route.href}
|
||||
href={route.href}
|
||||
className={cn(
|
||||
"flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors",
|
||||
isActive
|
||||
? "bg-primary text-primary-foreground"
|
||||
: "text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
||||
)}
|
||||
>
|
||||
<route.icon className="h-5 w-5" />
|
||||
{route.label}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
<div className="border-t p-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-muted-foreground">Theme</span>
|
||||
<ThemeToggle />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user