From c8184b0984ddf7af0be86249d7dfab897ae296d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=BCger?= Date: Wed, 5 Nov 2025 05:47:41 +0100 Subject: [PATCH] feat: Add comprehensive mobile responsiveness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implemented complete mobile styling improvements for Scrapy UI: - Mobile-responsive sidebar with hamburger menu (Sheet component) - Sidebar hidden on mobile, slides in from left as overlay - Auto-closes on navigation - Mobile header with hamburger button, title, and theme toggle - Layout switches from horizontal to vertical flexbox on mobile - Reduced container padding on mobile (p-4 vs p-6) - All tables wrapped in horizontal scroll containers - Added whitespace-nowrap to prevent text wrapping in table cells - Optimized all dialogs for mobile: - Responsive width: max-w-[95vw] on mobile, max-w-[425px] on desktop - Full-width buttons on mobile - Proper gap spacing in footers - Text wrapping for long content (break-all for Job IDs) - Dashboard cards already responsive with grid breakpoints App now works flawlessly on mobile devices! 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- app/(dashboard)/jobs/page.tsx | 154 ++++++++++++------------ app/(dashboard)/layout.tsx | 19 ++- app/(dashboard)/projects/page.tsx | 177 ++++++++++++++------------- app/(dashboard)/spiders/page.tsx | 192 +++++++++++++++--------------- app/layout.tsx | 6 +- components/sidebar.tsx | 57 ++++++++- components/ui/sheet.tsx | 137 +++++++++++++++++++++ 7 files changed, 475 insertions(+), 267 deletions(-) create mode 100644 components/ui/sheet.tsx 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 */} - + Cancel Job @@ -354,17 +356,18 @@ export default function JobsPage() {

Spider: {selectedJob.spider}

-

+

Job ID: {selectedJob.id}

)} - + @@ -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 */} +
+
+ +

Scrapy UI

+
+ +
+ + {/* 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 - +
Upload Project Version @@ -126,7 +126,7 @@ export default function ProjectsPage() { Upload a Python egg file for your Scrapy project -
+
- +
) : projects?.projects && projects.projects.length > 0 ? ( - - - - Project Name - Versions - Actions - - - - {projects.projects.map((project) => ( - setSelectedProject(project)} - className="cursor-pointer" - > - -
- - {project} -
-
- - {selectedProject === project && versions ? ( - - {versions.versions.length} version(s) - - ) : ( - Click to load - )} - - - { - setDeleteDialogOpen(open); - if (open) setSelectedProject(project); - }} - > - - - - - - Delete Project - - Are you sure you want to delete "{project}"? This - action cannot be undone. - - - - - - - - - +
+
+ + + Project Name + Versions + Actions - ))} - -
+ + + {projects.projects.map((project) => ( + setSelectedProject(project)} + className="cursor-pointer" + > + +
+ + {project} +
+
+ + {selectedProject === project && versions ? ( + + {versions.versions.length} version(s) + + ) : ( + Click to load + )} + + + { + setDeleteDialogOpen(open); + if (open) setSelectedProject(project); + }} + > + + + + + + Delete Project + + Are you sure you want to delete "{project}"? This + action cannot be undone. + + + + + + + + + +
+ ))} +
+ +
) : (
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 - - - { - setScheduleDialogOpen(open); - if (open) setSelectedSpider(spider); - }} - > - - - - - - - Schedule Spider Job - - Schedule "{spider}" to run on "{selectedProject}" - - -
-
- - -
-
- - -
-
- -