Seed: project-management template (23 files)

This commit is contained in:
2026-07-23 22:14:34 +00:00
parent 349e7e2f4b
commit 7edc96916d
+167
View File
@@ -0,0 +1,167 @@
import { useState } from "react";
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { Checkbox } from "@/components/ui/checkbox";
import { Separator } from "@/components/ui/separator";
import {
FolderKanban, ListChecks, CheckCircle2, AlertTriangle,
Clock, ArrowUpRight, MoreHorizontal, Plus
} from "lucide-react";
import { toast } from "sonner";
import Sidebar from "@/components/Sidebar";
import Header from "@/components/Header";
const kpiCards = [
{
title: "Total Projects",
value: "24",
change: "+3 this month",
icon: FolderKanban,
color: "text-violet-600 bg-violet-100",
},
{
title: "Active Tasks",
value: "142",
change: "+18 this week",
icon: ListChecks,
color: "text-indigo-600 bg-indigo-100",
},
{
title: "Completed This Week",
value: "38",
change: "+12% vs last week",
icon: CheckCircle2,
color: "text-emerald-600 bg-emerald-100",
},
{
title: "Overdue",
value: "7",
change: "-2 from yesterday",
icon: AlertTriangle,
color: "text-red-600 bg-red-100",
},
];
const activityFeed = [
{ initials: "AK", name: "Alex Kim", action: "completed the homepage redesign task", time: "5 minutes ago", color: "bg-violet-500" },
{ initials: "MR", name: "Maria Rodriguez", action: "moved API integration to In Progress", time: "22 minutes ago", color: "bg-indigo-500" },
{ initials: "JL", name: "Jordan Lee", action: "added a comment on the onboarding flow", time: "1 hour ago", color: "bg-emerald-500" },
{ initials: "SC", name: "Sam Chen", action: "created a new project: Mobile App v2", time: "3 hours ago", color: "bg-amber-500" },
{ initials: "TP", name: "Taylor Park", action: "uploaded design assets to the brand kit", time: "5 hours ago", color: "bg-sky-500" },
];
const myTasks = [
{ id: 1, title: "Design system color tokens", priority: "High", priorityColor: "bg-red-100 text-red-700", due: "Apr 13", assignee: "AK", done: false },
{ id: 2, title: "API integration for user auth", priority: "High", priorityColor: "bg-red-100 text-red-700", due: "Apr 14", assignee: "MR", done: false },
{ id: 3, title: "Update onboarding flow copy", priority: "Medium", priorityColor: "bg-amber-100 text-amber-700", due: "Apr 15", assignee: "JL", done: false },
{ id: 4, title: "Fix sidebar responsive layout", priority: "Medium", priorityColor: "bg-amber-100 text-amber-700", due: "Apr 16", assignee: "SC", done: true },
{ id: 5, title: "Write unit tests for dashboard", priority: "Low", priorityColor: "bg-slate-100 text-slate-700", due: "Apr 18", assignee: "TP", done: false },
];
export default function IndexPage() {
const [tasks, setTasks] = useState(myTasks);
const toggleTask = (id: number) => {
setTasks(prev => prev.map(t => t.id === id ? { ...t, done: !t.done } : t));
toast("Task completed!");
};
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">
{/* ── Welcome ── */}
<div>
<h1 className="text-2xl font-bold text-slate-900 animate-fade-up">Welcome back, Alex</h1>
<p className="text-slate-500 mt-1">Here is what is happening across your projects today.</p>
</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 backdrop-blur-sm bg-card/80 border-border/50 hover:-translate-y-1 hover:shadow-lg transition-all duration-300 animate-fade-up">
<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>
<Button variant="ghost" size="sm" className="h-8 w-8 p-0 text-slate-400">
<MoreHorizontal className="h-4 w-4" />
</Button>
</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>
<p className="text-xs text-emerald-600 mt-2 font-medium">{kpi.change}</p>
</div>
</CardContent>
</Card>
))}
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* ── Recent Activity ── */}
<Card className="border-0 shadow-sm">
<CardHeader className="flex flex-row items-center justify-between pb-2">
<div>
<CardTitle className="text-lg font-semibold text-slate-900">Recent Activity</CardTitle>
<CardDescription>Latest actions across your workspace</CardDescription>
</div>
<Button variant="ghost" size="sm" className="text-violet-600 hover:text-violet-700">View All</Button>
</CardHeader>
<CardContent className="space-y-4">
{activityFeed.map((item, i) => (
<div key={i} className="flex items-start gap-3 p-2 rounded-lg backdrop-blur-sm bg-card/80 border-border/50">
<div className={`h-8 w-8 rounded-full \${item.color} flex items-center justify-center shrink-0`}>
<span className="text-xs font-semibold text-white">{item.initials}</span>
</div>
<div className="flex-1 min-w-0">
<p className="text-sm text-slate-700">
<span className="font-medium">{item.name}</span>{" "}{item.action}
</p>
<p className="text-xs text-slate-400 mt-0.5 flex items-center gap-1">
<Clock className="h-3 w-3" />{item.time}
</p>
</div>
</div>
))}
</CardContent>
</Card>
{/* ── My Tasks ── */}
<Card className="border-0 shadow-sm">
<CardHeader className="flex flex-row items-center justify-between pb-2">
<div>
<CardTitle className="text-lg font-semibold text-slate-900">My Tasks</CardTitle>
<CardDescription>Your assigned tasks for this sprint</CardDescription>
</div>
<Button size="sm" className="bg-violet-600 hover:bg-violet-700 text-white">
<Plus className="mr-1 h-4 w-4" /> Add Task
</Button>
</CardHeader>
<CardContent className="space-y-2">
{tasks.map((task) => (
<div key={task.id} className={`flex items-center gap-3 p-3 rounded-lg hover:bg-slate-50 transition-colors \${task.done ? "opacity-60" : ""}`}>
<Checkbox checked={task.done} onCheckedChange={() => toggleTask(task.id)} className="border-slate-300 data-[state=checked]:bg-violet-600 data-[state=checked]:border-violet-600" />
<div className="flex-1 min-w-0">
<p className={`text-sm font-medium \${task.done ? "line-through text-slate-400" : "text-slate-900"}`}>{task.title}</p>
</div>
<Badge className={`\${task.priorityColor} text-xs font-medium border-0`}>{task.priority}</Badge>
<span className="text-xs text-slate-400 hidden sm:block">{task.due}</span>
<Avatar className="h-6 w-6">
<AvatarFallback className="text-[10px] bg-violet-100 text-violet-700">{task.assignee}</AvatarFallback>
</Avatar>
</div>
))}
</CardContent>
</Card>
</div>
</main>
</div>
</div>
);
}