diff --git a/app/(dashboard)/jobs/page.tsx b/app/(dashboard)/jobs/page.tsx
index 97bd759..e80e1fe 100644
--- a/app/(dashboard)/jobs/page.tsx
+++ b/app/(dashboard)/jobs/page.tsx
@@ -242,79 +242,81 @@ export default function JobsPage() {
))}
) : filteredJobs.length > 0 ? (
-
-
-
- Job ID
- Spider
- Status
- Start Time
- PID
- Actions
-
-
-
- {filteredJobs.map((job) => (
-
-
-
- {job.id.substring(0, 8)}...
-
-
-
-
-
- {job.spider}
-
-
- {getStatusBadge(job.status)}
-
-
- {format(new Date(job.start_time), "PPp")}
-
-
-
- {job.pid ? (
- {job.pid}
- ) : (
- -
- )}
-
-
-
- {job.log_url && (
-
- )}
- {(job.status === "pending" || job.status === "running") && (
-
- )}
-
-
+
+
+
+
+ Job ID
+ Spider
+ Status
+ Start Time
+ PID
+ Actions
- ))}
-
-
+
+
+ {filteredJobs.map((job) => (
+
+
+
+ {job.id.substring(0, 8)}...
+
+
+
+
+
+ {job.spider}
+
+
+ {getStatusBadge(job.status)}
+
+
+ {format(new Date(job.start_time), "PPp")}
+
+
+
+ {job.pid ? (
+ {job.pid}
+ ) : (
+ -
+ )}
+
+
+
+ {job.log_url && (
+
+ )}
+ {(job.status === "pending" || job.status === "running") && (
+
+ )}
+
+
+
+ ))}
+
+
+
) : (
@@ -344,7 +346,7 @@ export default function JobsPage() {
{/* Cancel Job Dialog */}
)}
-
+
@@ -372,6 +375,7 @@ export default function JobsPage() {
variant="destructive"
onClick={handleCancelJob}
disabled={cancelJobMutation.isPending}
+ className="w-full sm:w-auto"
>
{cancelJobMutation.isPending ? "Canceling..." : "Yes, cancel job"}
diff --git a/app/(dashboard)/layout.tsx b/app/(dashboard)/layout.tsx
index 003d7c0..5e36643 100644
--- a/app/(dashboard)/layout.tsx
+++ b/app/(dashboard)/layout.tsx
@@ -1,5 +1,6 @@
-import { Sidebar } from "@/components/sidebar";
+import { Sidebar, MobileSidebar } from "@/components/sidebar";
import { Providers } from "@/components/providers";
+import { ThemeToggle } from "@/components/theme-toggle";
export default function DashboardLayout({
children,
@@ -8,10 +9,22 @@ export default function DashboardLayout({
}) {
return (
-
+
+ {/* Mobile Header */}
+
+
+ {/* Desktop Sidebar */}
+
+ {/* Main Content */}
- {children}
+ {children}
diff --git a/app/(dashboard)/projects/page.tsx b/app/(dashboard)/projects/page.tsx
index c1af170..2846bde 100644
--- a/app/(dashboard)/projects/page.tsx
+++ b/app/(dashboard)/projects/page.tsx
@@ -118,7 +118,7 @@ export default function ProjectsPage() {
Upload Project
-
+
) : (
diff --git a/app/(dashboard)/spiders/page.tsx b/app/(dashboard)/spiders/page.tsx
index b65ede8..c50cb7c 100644
--- a/app/(dashboard)/spiders/page.tsx
+++ b/app/(dashboard)/spiders/page.tsx
@@ -158,101 +158,105 @@ export default function SpidersPage() {
))}
) : spiders?.spiders && spiders.spiders.length > 0 ? (
-
-
-
- Spider Name
- Status
- Actions
-
-
-
- {spiders.spiders.map((spider) => (
-
-
-
-
- {spider}
-
-
-
- Available
-
-
-
-
+
+
+
+
+ Spider Name
+ Status
+ Actions
- ))}
-
-
+
+
+ {spiders.spiders.map((spider) => (
+
+
+
+
+ {spider}
+
+
+
+ Available
+
+
+
+
+
+ ))}
+
+
+
) : (
diff --git a/app/layout.tsx b/app/layout.tsx
index 6049d46..1c2d39a 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -24,10 +24,8 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
-
-
+
+
void }) {
const pathname = usePathname();
return (
-
-
-
Scrapy UI
-
+ <>
+ >
+ );
+}
+
+export function Sidebar() {
+ return (
+
);
}
+
+export function MobileSidebar() {
+ const [open, setOpen] = useState(false);
+
+ return (
+ <>
+
+
+
+
+
+
+ Scrapy UI
+
+ setOpen(false)} />
+
+
+
+ >
+ );
+}
diff --git a/components/ui/sheet.tsx b/components/ui/sheet.tsx
new file mode 100644
index 0000000..fd2906c
--- /dev/null
+++ b/components/ui/sheet.tsx
@@ -0,0 +1,137 @@
+"use client"
+
+import * as React from "react"
+import * as SheetPrimitive from "@radix-ui/react-dialog"
+import { Cross2Icon } from "@radix-ui/react-icons"
+import { cva, type VariantProps } from "class-variance-authority"
+
+import { cn } from "@/lib/utils"
+
+const Sheet = SheetPrimitive.Root
+
+const SheetTrigger = SheetPrimitive.Trigger
+
+const SheetClose = SheetPrimitive.Close
+
+const SheetPortal = SheetPrimitive.Portal
+
+const SheetOverlay = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
+
+const sheetVariants = cva(
+ "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out",
+ {
+ variants: {
+ side: {
+ top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
+ bottom:
+ "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
+ left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
+ right:
+ "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
+ },
+ },
+ defaultVariants: {
+ side: "right",
+ },
+ }
+)
+
+interface SheetContentProps
+ extends React.ComponentPropsWithoutRef,
+ VariantProps {}
+
+const SheetContent = React.forwardRef<
+ React.ElementRef,
+ SheetContentProps
+>(({ side = "right", className, children, ...props }, ref) => (
+
+
+
+ {children}
+
+
+ Close
+
+
+
+))
+SheetContent.displayName = SheetPrimitive.Content.displayName
+
+const SheetHeader = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+)
+SheetHeader.displayName = "SheetHeader"
+
+const SheetFooter = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+)
+SheetFooter.displayName = "SheetFooter"
+
+const SheetTitle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+SheetTitle.displayName = SheetPrimitive.Title.displayName
+
+const SheetDescription = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+SheetDescription.displayName = SheetPrimitive.Description.displayName
+
+export {
+ Sheet,
+ SheetPortal,
+ SheetOverlay,
+ SheetTrigger,
+ SheetClose,
+ SheetContent,
+ SheetHeader,
+ SheetFooter,
+ SheetTitle,
+ SheetDescription,
+}