Seed: project-management template (23 files)
This commit is contained in:
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user