feat: Add comprehensive mobile responsiveness
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 <noreply@anthropic.com>
This commit is contained in:
@@ -158,101 +158,105 @@ export default function SpidersPage() {
|
||||
))}
|
||||
</div>
|
||||
) : spiders?.spiders && spiders.spiders.length > 0 ? (
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Spider Name</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
<TableHead className="text-right">Actions</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{spiders.spiders.map((spider) => (
|
||||
<TableRow key={spider}>
|
||||
<TableCell>
|
||||
<div className="flex items-center gap-2">
|
||||
<Bug className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="font-medium">{spider}</span>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant="secondary">Available</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<Dialog
|
||||
open={scheduleDialogOpen && selectedSpider === spider}
|
||||
onOpenChange={(open) => {
|
||||
setScheduleDialogOpen(open);
|
||||
if (open) setSelectedSpider(spider);
|
||||
}}
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => setSelectedSpider(spider)}
|
||||
>
|
||||
<PlayCircle className="mr-2 h-4 w-4" />
|
||||
Schedule
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<form onSubmit={handleSchedule}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Schedule Spider Job</DialogTitle>
|
||||
<DialogDescription>
|
||||
Schedule "{spider}" to run on "{selectedProject}"
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="gap-4 py-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="project-name">Project</Label>
|
||||
<Input
|
||||
id="project-name"
|
||||
value={selectedProject}
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="spider-name">Spider</Label>
|
||||
<Input
|
||||
id="spider-name"
|
||||
value={spider}
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="args">
|
||||
Arguments (JSON)
|
||||
</Label>
|
||||
<Textarea
|
||||
id="args"
|
||||
name="args"
|
||||
placeholder='{"url": "https://example.com", "pages": 10}'
|
||||
className="font-mono text-sm"
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Optional: Provide spider arguments in JSON format
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={scheduleJobMutation.isPending}
|
||||
>
|
||||
{scheduleJobMutation.isPending
|
||||
? "Scheduling..."
|
||||
: "Schedule Job"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</TableCell>
|
||||
<div className="overflow-x-auto">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Spider Name</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
<TableHead className="text-right">Actions</TableHead>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{spiders.spiders.map((spider) => (
|
||||
<TableRow key={spider}>
|
||||
<TableCell>
|
||||
<div className="flex items-center gap-2 whitespace-nowrap">
|
||||
<Bug className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="font-medium">{spider}</span>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant="secondary" className="whitespace-nowrap">Available</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<Dialog
|
||||
open={scheduleDialogOpen && selectedSpider === spider}
|
||||
onOpenChange={(open) => {
|
||||
setScheduleDialogOpen(open);
|
||||
if (open) setSelectedSpider(spider);
|
||||
}}
|
||||
>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => setSelectedSpider(spider)}
|
||||
className="whitespace-nowrap"
|
||||
>
|
||||
<PlayCircle className="mr-2 h-4 w-4" />
|
||||
Schedule
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-[95vw] sm:max-w-[425px]">
|
||||
<form onSubmit={handleSchedule}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Schedule Spider Job</DialogTitle>
|
||||
<DialogDescription>
|
||||
Schedule "{spider}" to run on "{selectedProject}"
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-4 py-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="project-name">Project</Label>
|
||||
<Input
|
||||
id="project-name"
|
||||
value={selectedProject}
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="spider-name">Spider</Label>
|
||||
<Input
|
||||
id="spider-name"
|
||||
value={spider}
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="args">
|
||||
Arguments (JSON)
|
||||
</Label>
|
||||
<Textarea
|
||||
id="args"
|
||||
name="args"
|
||||
placeholder='{"url": "https://example.com", "pages": 10}'
|
||||
className="font-mono text-sm"
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Optional: Provide spider arguments in JSON format
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter className="gap-2 sm:gap-0">
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={scheduleJobMutation.isPending}
|
||||
className="w-full sm:w-auto"
|
||||
>
|
||||
{scheduleJobMutation.isPending
|
||||
? "Scheduling..."
|
||||
: "Schedule Job"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center py-12 text-center">
|
||||
<AlertCircle className="mb-4 h-12 w-12 text-muted-foreground" />
|
||||
|
||||
Reference in New Issue
Block a user