first commit
This commit is contained in:
@@ -0,0 +1,326 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { CheckCircle2, DollarSign, Package, Plus, ShoppingCart, Users } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
import { RecentOrdersTable } from "@/components/dashboard/recent-orders-table"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { DatePicker, DateRangePicker } from "@/components/ui/date-picker"
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog"
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogContent,
|
||||
AlertDialogTrigger,
|
||||
} from "@/components/ui/alert-dialog"
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbEllipsis,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
BreadcrumbSeparator,
|
||||
} from "@/components/ui/breadcrumb"
|
||||
import { StatCard } from "@/components/ui/stat-card"
|
||||
import { toast } from "@/components/ui/toast"
|
||||
import LineChart from "@/components/ui/line-chart"
|
||||
import BarChart from "@/components/ui/bar-chart"
|
||||
import PieChart from "@/components/ui/pie-chart"
|
||||
|
||||
const indigoButton =
|
||||
"rounded-full bg-indigo-50 text-indigo-700 hover:bg-indigo-100 focus-visible:ring-indigo-300/40"
|
||||
|
||||
export default function DashboardPage() {
|
||||
const [date, setDate] = React.useState<Date>()
|
||||
const [range, setRange] = React.useState<{ from: Date | undefined; to?: Date | undefined }>()
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex flex-col gap-5 rounded-2xl bg-white p-4 shadow-sm ring-1 ring-black/5 sm:p-5">
|
||||
<div>
|
||||
<p className="mb-2 text-sm font-semibold text-slate-500">Breadcrumb</p>
|
||||
<div className="flex flex-col gap-3">
|
||||
{/* Basic */}
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="/dashboard">Home</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="/dashboard/products">Products</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Product Detail</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
|
||||
{/* With ellipsis */}
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="/dashboard">Home</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbEllipsis />
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="/dashboard/products">Products</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Edit</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="mb-2 text-sm font-semibold text-slate-500">Variants</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button variant="default">Default</Button>
|
||||
<Button variant="outline">Outline</Button>
|
||||
<Button variant="secondary">Secondary</Button>
|
||||
<Button variant="ghost">Ghost</Button>
|
||||
<Button variant="destructive">Destructive</Button>
|
||||
<Button variant="success">Success</Button>
|
||||
<Button variant="warning">Warning</Button>
|
||||
<Button variant="info">Info</Button>
|
||||
<Button variant="link">Link</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="mb-2 text-sm font-semibold text-slate-500">Sizes</p>
|
||||
<div className="flex flex-wrap items-center gap-3">
|
||||
<Button size="xs" className={indigoButton}>
|
||||
Extra Small
|
||||
</Button>
|
||||
<Button size="sm" className={indigoButton}>
|
||||
Small
|
||||
</Button>
|
||||
<Button size="default" className={indigoButton}>
|
||||
Default
|
||||
</Button>
|
||||
<Button size="lg" className={indigoButton}>
|
||||
Large
|
||||
</Button>
|
||||
<Button size="lg" className={cn(indigoButton, "h-13 px-8 text-base")}>
|
||||
Extra Large
|
||||
</Button>
|
||||
<Button size="icon-sm" className={indigoButton} aria-label="Add (small)">
|
||||
<Plus />
|
||||
</Button>
|
||||
<Button size="icon" className={indigoButton} aria-label="Add">
|
||||
<Plus />
|
||||
</Button>
|
||||
<Button size="icon-lg" className={indigoButton} aria-label="Add (large)">
|
||||
<Plus />
|
||||
</Button>
|
||||
<Button
|
||||
size="icon-lg"
|
||||
className={cn(indigoButton, "size-13")}
|
||||
aria-label="Add (extra large)"
|
||||
>
|
||||
<Plus className="size-6" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="mb-2 text-sm font-semibold text-slate-500">Date Picker</p>
|
||||
<div className="flex flex-col gap-3 sm:flex-row sm:flex-wrap sm:items-center">
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="text-xs text-slate-400">Single date</span>
|
||||
<DatePicker
|
||||
value={date}
|
||||
onChange={setDate}
|
||||
placeholder="Select a date"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="text-xs text-slate-400">Date range</span>
|
||||
<DateRangePicker
|
||||
value={range}
|
||||
onChange={setRange}
|
||||
placeholder="Select date range"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{(date || range?.from) && (
|
||||
<p className="mt-2 text-xs text-slate-500">
|
||||
{date && <>Selected: <span className="font-medium text-slate-700">{date.toLocaleDateString()}</span></>}
|
||||
{range?.from && (
|
||||
<>
|
||||
{date && " · "}
|
||||
Range: <span className="font-medium text-slate-700">{range.from.toLocaleDateString()}</span>
|
||||
{range.to && <> – <span className="font-medium text-slate-700">{range.to.toLocaleDateString()}</span></>}
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="mb-2 text-sm font-semibold text-slate-500">Modal</p>
|
||||
<Dialog>
|
||||
<DialogTrigger render={<Button variant="outline">Open Modal</Button>} />
|
||||
<DialogContent className="w-[calc(100%-2rem)] sm:max-w-md">
|
||||
<DialogHeader className="items-center gap-3 px-2 pt-4 text-center sm:px-4">
|
||||
<div className="flex size-14 items-center justify-center rounded-full bg-emerald-50">
|
||||
<CheckCircle2 className="size-7 text-emerald-600" />
|
||||
</div>
|
||||
<DialogTitle className="text-lg font-bold">Order confirmed</DialogTitle>
|
||||
<DialogDescription>
|
||||
Your order has been placed successfully and is now being processed.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="flex justify-center px-2 pb-2 sm:px-4">
|
||||
<Button size="lg" className="w-full rounded-full sm:w-auto sm:px-10">
|
||||
Continue
|
||||
</Button>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="mb-2 text-sm font-semibold text-slate-500">Toast</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button variant="outline" onClick={() => toast({ title: "Default toast message" })}>
|
||||
Default
|
||||
</Button>
|
||||
<Button variant="success" onClick={() => toast.success("Success!", "Your changes have been saved.")}>
|
||||
Success
|
||||
</Button>
|
||||
<Button variant="destructive" onClick={() => toast.error("Error", "Something went wrong. Please try again.")}>
|
||||
Error
|
||||
</Button>
|
||||
<Button variant="warning" onClick={() => toast.warning("Warning", "This action cannot be undone.")}>
|
||||
Warning
|
||||
</Button>
|
||||
<Button variant="info" onClick={() => toast.info("Info", "Your session will expire in 5 minutes.")}>
|
||||
Info
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() =>
|
||||
toast({
|
||||
title: "With Action",
|
||||
description: "Do you want to undo this change?",
|
||||
actionLabel: "Undo",
|
||||
onAction: () => toast.success("Undone!", "Change has been reverted."),
|
||||
})
|
||||
}
|
||||
>
|
||||
With Action
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-5 rounded-2xl bg-white p-4 shadow-sm ring-1 ring-black/5 sm:p-5">
|
||||
<div>
|
||||
<p className="mb-2 text-sm font-semibold text-slate-500">Alert Dialogs</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger render={<Button variant="info">Info</Button>} />
|
||||
<AlertDialogContent
|
||||
variant="info"
|
||||
title="Update available"
|
||||
description="A new version is ready. Reload the page to apply the latest changes."
|
||||
confirmLabel="Reload"
|
||||
onConfirm={() => toast.info("Reloading...", "Applying the latest update.")}
|
||||
/>
|
||||
</AlertDialog>
|
||||
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger render={<Button variant="success">Success</Button>} />
|
||||
<AlertDialogContent
|
||||
variant="success"
|
||||
title="Order confirmed"
|
||||
description="Your order has been placed successfully and is now being processed."
|
||||
confirmLabel="Continue"
|
||||
cancelLabel="View order"
|
||||
onConfirm={() => toast.success("Done!", "Redirecting to dashboard.")}
|
||||
/>
|
||||
</AlertDialog>
|
||||
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger render={<Button variant="warning">Warning</Button>} />
|
||||
<AlertDialogContent
|
||||
variant="warning"
|
||||
title="Unsaved changes"
|
||||
description="You have unsaved changes. Leaving this page will discard them."
|
||||
confirmLabel="Leave anyway"
|
||||
onConfirm={() => toast.warning("Changes discarded")}
|
||||
/>
|
||||
</AlertDialog>
|
||||
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger render={<Button variant="destructive">Delete</Button>} />
|
||||
<AlertDialogContent
|
||||
variant="destructive"
|
||||
title="Delete record?"
|
||||
description="This action is permanent and cannot be undone. All associated data will be removed."
|
||||
confirmLabel="Delete"
|
||||
onConfirm={() => toast.error("Deleted", "The record has been permanently removed.")}
|
||||
/>
|
||||
</AlertDialog>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4">
|
||||
<StatCard label="Total Revenue" value={45231.89} icon={DollarSign} />
|
||||
<StatCard label="Orders" value={1284} icon={ShoppingCart} />
|
||||
<StatCard label="Customers" value={892} icon={Users} />
|
||||
<StatCard label="Low Stock Items" value={16} icon={Package} />
|
||||
</div>
|
||||
|
||||
<RecentOrdersTable />
|
||||
|
||||
<div className="mt-6 grid grid-cols-1 gap-4 lg:grid-cols-3">
|
||||
<div className="rounded-2xl bg-white p-4 shadow-sm ring-1 ring-black/5">
|
||||
<h3 className="mb-2 text-sm font-semibold text-slate-600">Sales (Line)</h3>
|
||||
<div className="h-56">
|
||||
<LineChart
|
||||
labels={["Jan", "Feb", "Mar", "Apr", "May", "Jun"]}
|
||||
datasets={[{ label: "Sales", data: [120, 200, 150, 220, 180, 260] }]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-2xl bg-white p-4 shadow-sm ring-1 ring-black/5">
|
||||
<h3 className="mb-2 text-sm font-semibold text-slate-600">Revenue (Bar)</h3>
|
||||
<div className="h-56">
|
||||
<BarChart
|
||||
labels={["Q1", "Q2", "Q3", "Q4"]}
|
||||
datasets={[{ label: "Revenue", data: [30000, 42000, 36000, 48000], backgroundColor: "#60a5fa" }]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-2xl bg-white p-4 shadow-sm ring-1 ring-black/5">
|
||||
<h3 className="mb-2 text-sm font-semibold text-slate-600">Product Mix (Pie)</h3>
|
||||
<div className="h-56">
|
||||
<PieChart labels={["A","B","C"]} data={[45, 30, 25]} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user