Adds initial backend API endpoints for fetching users and attendances, including basic filtering. Sets up the frontend routing with a layout component and includes placeholder pages for dashboard, users, and login. Refactors the README for local development setup.
41 lines
1.8 KiB
TypeScript
41 lines
1.8 KiB
TypeScript
import React from 'react';
|
|
import { LucideIcon } from 'lucide-react';
|
|
|
|
interface KPICardProps {
|
|
title: string;
|
|
value: string | number;
|
|
subValue?: string;
|
|
trend?: 'up' | 'down' | 'neutral';
|
|
trendValue?: string;
|
|
icon: LucideIcon;
|
|
colorClass?: string;
|
|
}
|
|
|
|
export const KPICard: React.FC<KPICardProps> = ({ title, value, subValue, trend, trendValue, icon: Icon, colorClass = "bg-blue-500" }) => {
|
|
return (
|
|
<div className="bg-white p-6 rounded-2xl shadow-sm border border-slate-100 flex flex-col justify-between hover:shadow-md transition-shadow duration-300">
|
|
<div className="flex justify-between items-start mb-4">
|
|
<div>
|
|
<h3 className="text-slate-500 text-sm font-medium mb-1">{title}</h3>
|
|
<div className="text-3xl font-bold text-slate-800 tracking-tight">{value}</div>
|
|
</div>
|
|
<div className={`p-3 rounded-xl ${colorClass} bg-opacity-10 text-opacity-100`}>
|
|
{/* Note: In Tailwind bg-opacity works if colorClass is like 'bg-blue-500'.
|
|
Here we assume the consumer passes specific utility classes or we construct them.
|
|
Simpler approach: Use a wrapper */}
|
|
<div className={`w-8 h-8 flex items-center justify-center rounded-lg ${colorClass.replace('text', 'bg').replace('500', '100')} ${colorClass}`}>
|
|
<Icon size={20} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{(trend || subValue) && (
|
|
<div className="flex items-center gap-2 text-sm mt-auto">
|
|
{trend === 'up' && <span className="text-green-500 flex items-center font-medium">▲ {trendValue}</span>}
|
|
{trend === 'down' && <span className="text-red-500 flex items-center font-medium">▼ {trendValue}</span>}
|
|
{subValue && <span className="text-slate-400">{subValue}</span>}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}; |