Add scroll area to widget settings modal
Some checks failed
Build Frontend / build (push) Failing after 6s
Some checks failed
Build Frontend / build (push) Failing after 6s
Wrapped the widget settings modal content in a ScrollArea to improve usability when there are many settings, preventing overflow and keeping the modal compact.
This commit is contained in:
@@ -22,6 +22,7 @@ import {
|
||||
} from "@/components/ui/select"
|
||||
import { WidgetConfig } from "@/hooks/useWidgetLayout"
|
||||
import { Settings2 } from "lucide-react"
|
||||
import { ScrollArea } from "@/components/ui/scroll-area"
|
||||
|
||||
interface WidgetSettingsModalProps {
|
||||
widget: WidgetConfig | null
|
||||
@@ -69,213 +70,215 @@ export function WidgetSettingsModal({ widget, open, onOpenChange, onSave }: Widg
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-6 py-4">
|
||||
{/* Resize Selection */}
|
||||
<div className="space-y-3 pb-6 border-b border-border/40">
|
||||
<Label className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">Widget Display</Label>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="colSpan" className="text-sm font-medium">Widget Width</Label>
|
||||
<Select
|
||||
value={String(localColSpan)}
|
||||
onValueChange={(v) => setLocalColSpan(parseInt(v))}
|
||||
>
|
||||
<SelectTrigger className="w-40">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="1">Small (1/4)</SelectItem>
|
||||
<SelectItem value="2">Medium (1/2)</SelectItem>
|
||||
<SelectItem value="3">Large (3/4)</SelectItem>
|
||||
<SelectItem value="4">Full Width</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<ScrollArea className="max-h-[60vh] -mr-4 pr-4">
|
||||
<div className="space-y-6 py-4">
|
||||
{/* Resize Selection */}
|
||||
<div className="space-y-3 pb-6 border-b border-border/40">
|
||||
<Label className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">Widget Display</Label>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="colSpan" className="text-sm font-medium">Widget Width</Label>
|
||||
<Select
|
||||
value={String(localColSpan)}
|
||||
onValueChange={(v) => setLocalColSpan(parseInt(v))}
|
||||
>
|
||||
<SelectTrigger className="w-40">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="1">Small (1/4)</SelectItem>
|
||||
<SelectItem value="2">Medium (1/2)</SelectItem>
|
||||
<SelectItem value="3">Large (3/4)</SelectItem>
|
||||
<SelectItem value="4">Full Width</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
{/* Recent Activity Settings */}
|
||||
{widget.id === "recent-activity" && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="itemCount">Number of items</Label>
|
||||
<Select
|
||||
value={String(localSettings.itemCount || 10)}
|
||||
onValueChange={(v) => updateSetting("itemCount", parseInt(v))}
|
||||
>
|
||||
<SelectTrigger className="w-24">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="5">5</SelectItem>
|
||||
<SelectItem value="10">10</SelectItem>
|
||||
<SelectItem value="15">15</SelectItem>
|
||||
<SelectItem value="20">20</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Top Products Settings */}
|
||||
{widget.id === "top-products" && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="itemCount">Number of products</Label>
|
||||
<Select
|
||||
value={String(localSettings.itemCount || 5)}
|
||||
onValueChange={(v) => updateSetting("itemCount", parseInt(v))}
|
||||
>
|
||||
<SelectTrigger className="w-24">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="3">3</SelectItem>
|
||||
<SelectItem value="5">5</SelectItem>
|
||||
<SelectItem value="10">10</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="showRevenue">Show revenue</Label>
|
||||
<Switch
|
||||
id="showRevenue"
|
||||
checked={localSettings.showRevenue ?? true}
|
||||
onCheckedChange={(checked) => updateSetting("showRevenue", checked)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Revenue Chart Settings */}
|
||||
{widget.id === "revenue-chart" && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="days">Time period</Label>
|
||||
<Select
|
||||
value={String(localSettings.days || 7)}
|
||||
onValueChange={(v) => updateSetting("days", parseInt(v))}
|
||||
>
|
||||
<SelectTrigger className="w-32">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="7">Last 7 days</SelectItem>
|
||||
<SelectItem value="14">Last 14 days</SelectItem>
|
||||
<SelectItem value="30">Last 30 days</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="showComparison">Show comparison</Label>
|
||||
<Switch
|
||||
id="showComparison"
|
||||
checked={localSettings.showComparison ?? false}
|
||||
onCheckedChange={(checked) => updateSetting("showComparison", checked)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Low Stock Settings */}
|
||||
{widget.id === "low-stock" && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="threshold">Stock threshold</Label>
|
||||
<Input
|
||||
id="threshold"
|
||||
type="number"
|
||||
className="w-24"
|
||||
value={localSettings.threshold || 5}
|
||||
onChange={(e) => updateSetting("threshold", parseInt(e.target.value) || 5)}
|
||||
min={1}
|
||||
max={100}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="itemCount">Max items to show</Label>
|
||||
<Select
|
||||
value={String(localSettings.itemCount || 5)}
|
||||
onValueChange={(v) => updateSetting("itemCount", parseInt(v))}
|
||||
>
|
||||
<SelectTrigger className="w-24">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="3">3</SelectItem>
|
||||
<SelectItem value="5">5</SelectItem>
|
||||
<SelectItem value="10">10</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Recent Customers Settings */}
|
||||
{widget.id === "recent-customers" && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="itemCount">Number of customers</Label>
|
||||
<Select
|
||||
value={String(localSettings.itemCount || 5)}
|
||||
onValueChange={(v) => updateSetting("itemCount", parseInt(v))}
|
||||
>
|
||||
<SelectTrigger className="w-24">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="3">3</SelectItem>
|
||||
<SelectItem value="5">5</SelectItem>
|
||||
<SelectItem value="10">10</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="showSpent">Show amount spent</Label>
|
||||
<Switch
|
||||
id="showSpent"
|
||||
checked={localSettings.showSpent ?? true}
|
||||
onCheckedChange={(checked) => updateSetting("showSpent", checked)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Pending Chats Settings */}
|
||||
{widget.id === "pending-chats" && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="showPreview">Show message preview</Label>
|
||||
<Switch
|
||||
id="showPreview"
|
||||
checked={localSettings.showPreview ?? true}
|
||||
onCheckedChange={(checked) => updateSetting("showPreview", checked)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Overview Settings */}
|
||||
{widget.id === "overview" && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="showChange">Show percentage change</Label>
|
||||
<Switch
|
||||
id="showChange"
|
||||
checked={localSettings.showChange ?? false}
|
||||
onCheckedChange={(checked) => updateSetting("showChange", checked)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Quick Actions - no settings */}
|
||||
{widget.id === "quick-actions" && (
|
||||
<p className="text-sm text-muted-foreground text-center py-4">
|
||||
This widget has no customizable settings.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
{/* Recent Activity Settings */}
|
||||
{widget.id === "recent-activity" && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="itemCount">Number of items</Label>
|
||||
<Select
|
||||
value={String(localSettings.itemCount || 10)}
|
||||
onValueChange={(v) => updateSetting("itemCount", parseInt(v))}
|
||||
>
|
||||
<SelectTrigger className="w-24">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="5">5</SelectItem>
|
||||
<SelectItem value="10">10</SelectItem>
|
||||
<SelectItem value="15">15</SelectItem>
|
||||
<SelectItem value="20">20</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Top Products Settings */}
|
||||
{widget.id === "top-products" && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="itemCount">Number of products</Label>
|
||||
<Select
|
||||
value={String(localSettings.itemCount || 5)}
|
||||
onValueChange={(v) => updateSetting("itemCount", parseInt(v))}
|
||||
>
|
||||
<SelectTrigger className="w-24">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="3">3</SelectItem>
|
||||
<SelectItem value="5">5</SelectItem>
|
||||
<SelectItem value="10">10</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="showRevenue">Show revenue</Label>
|
||||
<Switch
|
||||
id="showRevenue"
|
||||
checked={localSettings.showRevenue ?? true}
|
||||
onCheckedChange={(checked) => updateSetting("showRevenue", checked)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Revenue Chart Settings */}
|
||||
{widget.id === "revenue-chart" && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="days">Time period</Label>
|
||||
<Select
|
||||
value={String(localSettings.days || 7)}
|
||||
onValueChange={(v) => updateSetting("days", parseInt(v))}
|
||||
>
|
||||
<SelectTrigger className="w-32">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="7">Last 7 days</SelectItem>
|
||||
<SelectItem value="14">Last 14 days</SelectItem>
|
||||
<SelectItem value="30">Last 30 days</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="showComparison">Show comparison</Label>
|
||||
<Switch
|
||||
id="showComparison"
|
||||
checked={localSettings.showComparison ?? false}
|
||||
onCheckedChange={(checked) => updateSetting("showComparison", checked)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Low Stock Settings */}
|
||||
{widget.id === "low-stock" && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="threshold">Stock threshold</Label>
|
||||
<Input
|
||||
id="threshold"
|
||||
type="number"
|
||||
className="w-24"
|
||||
value={localSettings.threshold || 5}
|
||||
onChange={(e) => updateSetting("threshold", parseInt(e.target.value) || 5)}
|
||||
min={1}
|
||||
max={100}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="itemCount">Max items to show</Label>
|
||||
<Select
|
||||
value={String(localSettings.itemCount || 5)}
|
||||
onValueChange={(v) => updateSetting("itemCount", parseInt(v))}
|
||||
>
|
||||
<SelectTrigger className="w-24">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="3">3</SelectItem>
|
||||
<SelectItem value="5">5</SelectItem>
|
||||
<SelectItem value="10">10</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Recent Customers Settings */}
|
||||
{widget.id === "recent-customers" && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="itemCount">Number of customers</Label>
|
||||
<Select
|
||||
value={String(localSettings.itemCount || 5)}
|
||||
onValueChange={(v) => updateSetting("itemCount", parseInt(v))}
|
||||
>
|
||||
<SelectTrigger className="w-24">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="3">3</SelectItem>
|
||||
<SelectItem value="5">5</SelectItem>
|
||||
<SelectItem value="10">10</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="showSpent">Show amount spent</Label>
|
||||
<Switch
|
||||
id="showSpent"
|
||||
checked={localSettings.showSpent ?? true}
|
||||
onCheckedChange={(checked) => updateSetting("showSpent", checked)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Pending Chats Settings */}
|
||||
{widget.id === "pending-chats" && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="showPreview">Show message preview</Label>
|
||||
<Switch
|
||||
id="showPreview"
|
||||
checked={localSettings.showPreview ?? true}
|
||||
onCheckedChange={(checked) => updateSetting("showPreview", checked)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Overview Settings */}
|
||||
{widget.id === "overview" && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label htmlFor="showChange">Show percentage change</Label>
|
||||
<Switch
|
||||
id="showChange"
|
||||
checked={localSettings.showChange ?? false}
|
||||
onCheckedChange={(checked) => updateSetting("showChange", checked)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Quick Actions - no settings */}
|
||||
{widget.id === "quick-actions" && (
|
||||
<p className="text-sm text-muted-foreground text-center py-4">
|
||||
This widget has no customizable settings.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</ScrollArea>
|
||||
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => onOpenChange(false)}>
|
||||
|
||||
Reference in New Issue
Block a user