Seed: project-management template (23 files)

This commit is contained in:
2026-07-23 22:14:35 +00:00
parent 7edc96916d
commit 9d89b18544
+188
View File
@@ -0,0 +1,188 @@
import { useState } from "react";
import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { Progress } from "@/components/ui/progress";
import {
Plus, LayoutGrid, List, Calendar, MoreHorizontal, FolderKanban
} from "lucide-react";
import { toast } from "sonner";
import Sidebar from "@/components/Sidebar";
import Header from "@/components/Header";
const projects = [
{
id: 1,
title: "Website Redesign",
description: "Complete redesign of the main website with modern UI components and improved UX flows.",
progress: 72,
tasks: 34,
completedTasks: 24,
team: ["AK", "MR", "JL"],
teamColors: ["bg-violet-500", "bg-indigo-500", "bg-emerald-500"],
due: "Apr 28, 2026",
status: "Active",
statusColor: "bg-emerald-100 text-emerald-700",
},
{
id: 2,
title: "Mobile App Launch",
description: "Build and launch the native mobile application for iOS and Android platforms.",
progress: 35,
tasks: 48,
completedTasks: 17,
team: ["SC", "TP", "AK"],
teamColors: ["bg-amber-500", "bg-sky-500", "bg-violet-500"],
due: "Jun 15, 2026",
status: "Active",
statusColor: "bg-emerald-100 text-emerald-700",
},
{
id: 3,
title: "API Migration",
description: "Migrate legacy REST endpoints to GraphQL and improve API documentation.",
progress: 100,
tasks: 22,
completedTasks: 22,
team: ["MR", "JL"],
teamColors: ["bg-indigo-500", "bg-emerald-500"],
due: "Mar 30, 2026",
status: "Completed",
statusColor: "bg-slate-100 text-slate-700",
},
{
id: 4,
title: "Design System",
description: "Establish a unified design system with reusable tokens, components, and guidelines.",
progress: 15,
tasks: 28,
completedTasks: 4,
team: ["AK", "SC", "TP"],
teamColors: ["bg-violet-500", "bg-amber-500", "bg-sky-500"],
due: "Jul 10, 2026",
status: "Planning",
statusColor: "bg-blue-100 text-blue-700",
},
{
id: 5,
title: "QA Automation",
description: "Implement end-to-end automated testing pipeline with CI/CD integration.",
progress: 58,
tasks: 19,
completedTasks: 11,
team: ["JL", "MR"],
teamColors: ["bg-emerald-500", "bg-indigo-500"],
due: "May 5, 2026",
status: "Active",
statusColor: "bg-emerald-100 text-emerald-700",
},
{
id: 6,
title: "Security Audit",
description: "SOC 2 compliance audit preparation and security hardening across all services.",
progress: 42,
tasks: 31,
completedTasks: 13,
team: ["TP", "SC", "AK"],
teamColors: ["bg-sky-500", "bg-amber-500", "bg-violet-500"],
due: "May 20, 2026",
status: "Active",
statusColor: "bg-emerald-100 text-emerald-700",
},
];
export default function ProjectsPage() {
const [view, setView] = useState<"grid" | "list">("grid");
return (
<div className="flex min-h-screen bg-slate-50">
<Sidebar activePath="/projects" />
<div className="flex-1 lg:ml-64">
<Header />
<main className="p-6 space-y-6">
{/* ── Header ── */}
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4">
<div>
<h1 className="text-2xl font-bold text-slate-900 animate-fade-up">Projects</h1>
<p className="text-slate-500 mt-1">{projects.length} projects across your workspace</p>
</div>
<div className="flex items-center gap-3">
<div className="flex items-center border rounded-lg overflow-hidden">
<Button
variant={view === "grid" ? "default" : "ghost"}
size="sm"
onClick={() => setView("grid")}
className={`rounded-none \${view === "grid" ? "bg-violet-600 hover:bg-violet-700 text-white" : ""}`}
>
<LayoutGrid className="h-4 w-4" />
</Button>
<Button
variant={view === "list" ? "default" : "ghost"}
size="sm"
onClick={() => setView("list")}
className={`rounded-none \${view === "list" ? "bg-violet-600 hover:bg-violet-700 text-white" : ""}`}
>
<List className="h-4 w-4" />
</Button>
</div>
<Button className="bg-violet-600 hover:bg-violet-700 text-white" onClick={() => toast("New project created!")}>
<Plus className="mr-2 h-4 w-4" /> New Project
</Button>
</div>
</div>
{/* ── Project Grid ── */}
<div className={`grid gap-6 stagger \${view === "grid" ? "grid-cols-1 md:grid-cols-2 xl:grid-cols-3" : "grid-cols-1"}`}>
{projects.map((project) => (
<Card key={project.id} 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 cursor-pointer group animate-fade-up">
<CardContent className="p-6">
<div className="flex items-start justify-between mb-3">
<div className="flex items-center gap-3">
<div className="h-10 w-10 rounded-lg bg-violet-100 flex items-center justify-center">
<FolderKanban className="h-5 w-5 text-violet-600" />
</div>
<div>
<h3 className="font-semibold text-slate-900 group-hover:text-violet-600 transition-colors">{project.title}</h3>
<Badge className={`\${project.statusColor} text-xs font-medium border-0 mt-1`}>{project.status}</Badge>
</div>
</div>
<Button variant="ghost" size="sm" className="h-8 w-8 p-0 text-slate-400 opacity-0 group-hover:opacity-100 transition-opacity">
<MoreHorizontal className="h-4 w-4" />
</Button>
</div>
<p className="text-sm text-slate-500 mb-4 line-clamp-2">{project.description}</p>
{/* Progress */}
<div className="mb-4">
<div className="flex items-center justify-between text-sm mb-1.5">
<span className="text-slate-500">Progress</span>
<span className="font-medium text-slate-700">{project.progress}%</span>
</div>
<Progress value={project.progress} className="h-2 bg-slate-100" />
</div>
{/* Footer */}
<div className="flex items-center justify-between pt-2 border-t border-slate-100">
<div className="flex -space-x-2">
{project.team.map((member, i) => (
<Avatar key={i} className="h-7 w-7 border-2 border-white">
<AvatarFallback className={`text-[10px] text-white \${project.teamColors[i]}`}>{member}</AvatarFallback>
</Avatar>
))}
</div>
<div className="flex items-center gap-3 text-xs text-slate-400">
<span>{project.completedTasks}/{project.tasks} tasks</span>
<span className="flex items-center gap-1"><Calendar className="h-3 w-3" />{project.due}</span>
</div>
</div>
</CardContent>
</Card>
))}
</div>
</main>
</div>
</div>
);
}