Seed: dashboard template (24 files)
This commit is contained in:
@@ -0,0 +1,226 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from "recharts";
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||||
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
||||||
|
import { Separator } from "@/components/ui/separator";
|
||||||
|
import {
|
||||||
|
DollarSign, Users, ShoppingCart, TrendingUp, TrendingDown,
|
||||||
|
ArrowUpRight, ArrowDownRight, MoreHorizontal, Eye,
|
||||||
|
FileText, UserPlus, BarChart3, Download
|
||||||
|
} from "lucide-react";
|
||||||
|
import Sidebar from "@/components/Sidebar";
|
||||||
|
import Header from "@/components/Header";
|
||||||
|
|
||||||
|
const kpiCards = [
|
||||||
|
{
|
||||||
|
title: "Total Revenue",
|
||||||
|
value: "$48.5K",
|
||||||
|
change: "+12.5%",
|
||||||
|
trend: "up" as const,
|
||||||
|
icon: DollarSign,
|
||||||
|
color: "text-sky-600 bg-sky-100",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Active Users",
|
||||||
|
value: "2,438",
|
||||||
|
change: "+8.2%",
|
||||||
|
trend: "up" as const,
|
||||||
|
icon: Users,
|
||||||
|
color: "text-orange-600 bg-orange-100",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Total Orders",
|
||||||
|
value: "1,256",
|
||||||
|
change: "+23.1%",
|
||||||
|
trend: "up" as const,
|
||||||
|
icon: ShoppingCart,
|
||||||
|
color: "text-emerald-600 bg-emerald-100",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Conversion Rate",
|
||||||
|
value: "3.2%",
|
||||||
|
change: "+0.5%",
|
||||||
|
trend: "up" as const,
|
||||||
|
icon: TrendingUp,
|
||||||
|
color: "text-violet-600 bg-violet-100",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const recentOrders = [
|
||||||
|
{ id: "#ORD-7291", customer: "Sarah Mitchell", amount: "$234.50", status: "Completed", statusColor: "bg-emerald-100 text-emerald-700", date: "Apr 10, 2026" },
|
||||||
|
{ id: "#ORD-7290", customer: "James Cooper", amount: "$891.00", status: "Processing", statusColor: "bg-sky-100 text-sky-700", date: "Apr 10, 2026" },
|
||||||
|
{ id: "#ORD-7289", customer: "Emily Zhang", amount: "$156.25", status: "Completed", statusColor: "bg-emerald-100 text-emerald-700", date: "Apr 9, 2026" },
|
||||||
|
{ id: "#ORD-7288", customer: "Michael Brown", amount: "$432.80", status: "Pending", statusColor: "bg-amber-100 text-amber-700", date: "Apr 9, 2026" },
|
||||||
|
{ id: "#ORD-7287", customer: "Lisa Anderson", amount: "$67.90", status: "Cancelled", statusColor: "bg-red-100 text-red-700", date: "Apr 8, 2026" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const activityFeed = [
|
||||||
|
{ user: "SM", name: "Sarah Mitchell", action: "placed a new order for $234.50", time: "2 minutes ago" },
|
||||||
|
{ user: "JC", name: "James Cooper", action: "upgraded to the Pro plan", time: "15 minutes ago" },
|
||||||
|
{ user: "EZ", name: "Emily Zhang", action: "submitted a support ticket", time: "1 hour ago" },
|
||||||
|
{ user: "MB", name: "Michael Brown", action: "updated their billing information", time: "3 hours ago" },
|
||||||
|
{ user: "LA", name: "Lisa Anderson", action: "cancelled order #ORD-7287", time: "5 hours ago" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const revenueData = [
|
||||||
|
{ month: "Jan", revenue: 4200 }, { month: "Feb", revenue: 5400 }, { month: "Mar", revenue: 4800 },
|
||||||
|
{ month: "Apr", revenue: 6200 }, { month: "May", revenue: 5800 }, { month: "Jun", revenue: 7500 },
|
||||||
|
{ month: "Jul", revenue: 6800 }, { month: "Aug", revenue: 8200 }, { month: "Sep", revenue: 7600 },
|
||||||
|
{ month: "Oct", revenue: 9500 }, { month: "Nov", revenue: 8800 }, { month: "Dec", revenue: 10200 },
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function IndexPage() {
|
||||||
|
return (
|
||||||
|
<div className="flex min-h-screen bg-slate-50">
|
||||||
|
<Sidebar activePath="/" />
|
||||||
|
<div className="flex-1 lg:ml-64">
|
||||||
|
<Header />
|
||||||
|
<main className="p-6 space-y-8">
|
||||||
|
{/* ── Quick Actions ── */}
|
||||||
|
<div className="flex flex-wrap gap-3">
|
||||||
|
<Button variant="outline" size="sm" className="active:scale-[0.98] transition-all">
|
||||||
|
<FileText className="mr-2 h-4 w-4 text-sky-600" /> Create Report
|
||||||
|
</Button>
|
||||||
|
<Button variant="outline" size="sm" className="active:scale-[0.98] transition-all">
|
||||||
|
<UserPlus className="mr-2 h-4 w-4 text-emerald-600" /> Add User
|
||||||
|
</Button>
|
||||||
|
<Button variant="outline" size="sm" className="active:scale-[0.98] transition-all">
|
||||||
|
<BarChart3 className="mr-2 h-4 w-4 text-orange-600" /> View Analytics
|
||||||
|
</Button>
|
||||||
|
<Button variant="outline" size="sm" className="active:scale-[0.98] transition-all">
|
||||||
|
<Download className="mr-2 h-4 w-4 text-violet-600" /> Export Data
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ── KPI Cards ── */}
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-6 stagger">
|
||||||
|
{kpiCards.map((kpi) => (
|
||||||
|
<Card key={kpi.title} className="border-0 shadow-sm hover:shadow-lg hover:-translate-y-0.5 transition-all duration-300 backdrop-blur-sm bg-card/80">
|
||||||
|
<CardContent className="p-6">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className={`flex items-center justify-center h-12 w-12 rounded-xl \${kpi.color}`}>
|
||||||
|
<kpi.icon className="h-6 w-6" />
|
||||||
|
</div>
|
||||||
|
<div className={`flex items-center gap-1 text-sm font-medium \${kpi.trend === "up" ? "text-emerald-600" : "text-red-600"}`}>
|
||||||
|
{kpi.trend === "up" ? <TrendingUp className="h-3.5 w-3.5" /> : <TrendingDown className="h-3.5 w-3.5" />}
|
||||||
|
{kpi.change}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mt-4">
|
||||||
|
<p className="text-2xl font-bold text-slate-900">{kpi.value}</p>
|
||||||
|
<p className="text-sm text-slate-500 mt-1">{kpi.title}</p>
|
||||||
|
<div className="mt-2 h-8 bg-gradient-to-r from-primary/5 to-primary/20 rounded" />
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* ── Revenue Chart ── */}
|
||||||
|
<Card className="border-0 shadow-sm animate-scale-in">
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
||||||
|
<div>
|
||||||
|
<CardTitle className="text-lg font-semibold text-slate-900">Revenue Overview</CardTitle>
|
||||||
|
<CardDescription>Monthly revenue performance for the current year</CardDescription>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Button variant="outline" size="sm" className="text-xs active:scale-[0.98]">7D</Button>
|
||||||
|
<Button variant="outline" size="sm" className="text-xs bg-sky-50 text-sky-700 border-sky-200 active:scale-[0.98]">30D</Button>
|
||||||
|
<Button variant="outline" size="sm" className="text-xs active:scale-[0.98]">90D</Button>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="pt-4">
|
||||||
|
<ResponsiveContainer width="100%" height={300}>
|
||||||
|
<BarChart data={revenueData}>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="barGrad" x1="0" y1="0" x2="0" y2="1">
|
||||||
|
<stop offset="0%" stopColor="hsl(var(--primary))" stopOpacity={0.8} />
|
||||||
|
<stop offset="100%" stopColor="hsl(var(--primary))" stopOpacity={0.2} />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<CartesianGrid strokeDasharray="3 3" stroke="hsl(var(--border))" opacity={0.3} />
|
||||||
|
<XAxis dataKey="month" stroke="hsl(var(--muted-foreground))" fontSize={12} />
|
||||||
|
<YAxis stroke="hsl(var(--muted-foreground))" fontSize={12} />
|
||||||
|
<Tooltip />
|
||||||
|
<Bar dataKey="revenue" fill="url(#barGrad)" radius={[4,4,0,0]} />
|
||||||
|
</BarChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* ── Orders + Activity ── */}
|
||||||
|
<div className="grid grid-cols-1 xl:grid-cols-3 gap-6">
|
||||||
|
{/* Recent Orders */}
|
||||||
|
<Card className="xl:col-span-2 border-0 shadow-sm">
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<CardTitle className="text-lg font-semibold text-slate-900">Recent Orders</CardTitle>
|
||||||
|
<CardDescription>Latest customer orders and their status</CardDescription>
|
||||||
|
</div>
|
||||||
|
<Button variant="outline" size="sm" className="text-xs active:scale-[0.98]">
|
||||||
|
View All <ArrowUpRight className="ml-1 h-3 w-3" />
|
||||||
|
</Button>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow className="border-slate-100">
|
||||||
|
<TableHead className="text-slate-500 font-medium">Order</TableHead>
|
||||||
|
<TableHead className="text-slate-500 font-medium">Customer</TableHead>
|
||||||
|
<TableHead className="text-slate-500 font-medium">Amount</TableHead>
|
||||||
|
<TableHead className="text-slate-500 font-medium">Status</TableHead>
|
||||||
|
<TableHead className="text-slate-500 font-medium">Date</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{recentOrders.map((order) => (
|
||||||
|
<TableRow key={order.id} className="border-slate-100 hover:bg-muted/50 transition-colors">
|
||||||
|
<TableCell className="font-medium text-slate-900">{order.id}</TableCell>
|
||||||
|
<TableCell className="text-slate-600">{order.customer}</TableCell>
|
||||||
|
<TableCell className="font-medium text-slate-900">{order.amount}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Badge variant="secondary" className={`\${order.statusColor} border-0 font-medium`}>
|
||||||
|
{order.status}
|
||||||
|
</Badge>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-slate-500">{order.date}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* Activity Feed */}
|
||||||
|
<Card className="border-0 shadow-sm">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-lg font-semibold text-slate-900">Recent Activity</CardTitle>
|
||||||
|
<CardDescription>Latest actions across your workspace</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="space-y-5 stagger">
|
||||||
|
{activityFeed.map((item, i) => (
|
||||||
|
<div key={i} className="flex items-start gap-3">
|
||||||
|
<Avatar className="h-9 w-9 bg-sky-100 text-sky-700">
|
||||||
|
<AvatarFallback className="text-xs font-semibold bg-sky-100 text-sky-700">{item.user}</AvatarFallback>
|
||||||
|
</Avatar>
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<p className="text-sm text-slate-700">
|
||||||
|
<span className="font-medium text-slate-900">{item.name}</span>{" "}
|
||||||
|
{item.action}
|
||||||
|
</p>
|
||||||
|
<p className="text-xs text-slate-400 mt-0.5">{item.time}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user