Project structure changes ad new files added in dashboard folders

This commit is contained in:
2026-07-23 18:32:07 +05:30
parent 1993d91319
commit 5a2ae769d8
63 changed files with 1550 additions and 190 deletions

View File

@@ -0,0 +1,14 @@
import { ButtonProps } from "@/types/types";
export default function Button({
children,
onClick,
className,
}: ButtonProps) {
return (
<button onClick={onClick} className={className}>
{children}
</button>
);
}

View File

@@ -0,0 +1,14 @@
export function CardHeader({ title, subtitle }: { title: string; subtitle?: string }) {
return (
<div className="flex justify-between items-baseline mb-2 border-b border-[#162942]/50 pb-3">
<h3 className="text-white text-base font-semibold tracking-wide">{title}</h3>
{subtitle && (
<span className="text-[#4e6178] text-xs font-medium uppercase tracking-wider">
{subtitle}
</span>
)}
</div>
);
}

View File

@@ -0,0 +1,9 @@
export function Card({ children, className = "" }:
{ children: React.ReactNode; className?: string }) {
return (
<div className={`bg-[#0a1526] border border-[#162942] rounded-xl p-3
shadow-xl flex flex-col justify-between ${className}`}>
{children}
</div>
);
}

View File

@@ -0,0 +1,66 @@
import { StatCardProps } from "@/types/types";
import { colorMap } from "@/constants/constant";
export default function StatCard({
title,
value,
variant = "progress",
subtitle,
progress,
color = "teal",
icon: Icon,
badgeText,
badgeClassName = "text-slate-500 font-mono uppercase",
iconContainerClassName = "bg-[#11233a] border-[#1b2c3f]/50 text-cyan-400",
isActiveCard = false,
}: StatCardProps) {
// Base structural classes matched exactly to your dark UI design
const cardBorder = isActiveCard ? "border-[#0d9488]" : "border-[#142538]";
return (
<div className={`relative rounded-2xl border ${cardBorder} bg-[#091624] p-5 flex flex-col justify-between min-h-[142px] w-full transition-all duration-300`}>
{/* --- TOP HEADER SECTION --- */}
<div className="flex items-center justify-between w-full">
{variant === "icon" && Icon ? (
<div className={`flex h-9 w-9 items-center justify-center rounded-lg border ${iconContainerClassName}`}>
<Icon size={18} />
</div>
) : (
<span className="text-xs font-bold uppercase tracking-wider text-slate-400/80">
{title}
</span>
)}
{badgeText && (
<span className={`text-[10px] font-semibold tracking-wider ${badgeClassName}`}>
{badgeText}
</span>
)}
</div>
{/* --- BODY STATS SECTION --- */}
<div className="mt-4 flex-grow flex flex-col justify-end">
<div className="text-3xl font-extrabold text-white tracking-tight leading-none">
{value}
</div>
{/* Subtitle / Bottom Label text arrangement layout swap */}
<p className="text-xs font-semibold text-slate-400/70 mt-2">
{variant === "icon" ? title : subtitle}
</p>
</div>
{/* --- PROGRESS LAYER (Only renders if variant="progress") --- */}
{variant === "progress" && progress !== undefined && (
<div className="w-full bg-[#162a45] h-1.5 rounded-full mt-3 overflow-hidden">
<div
className={`h-1.5 rounded-full ${colorMap[color] || 'bg-teal-500'} transition-all duration-500`}
style={{ width: `${progress}%` }}
/>
</div>
)}
</div>
);
}

View File

@@ -0,0 +1,55 @@
import React from "react";
type TableProps = {
headers: string[];
rows: React.ReactNode[][];
};
export default function Table({ headers, rows }: TableProps) {
return (
<div className="w-full overflow-hidden rounded-2xl border border-slate-800 bg-[#0B1727] shadow-xl">
<div className="overflow-x-auto">
<table className="w-full border-collapse text-[12px]">
<thead>
<tr className="border-b border-slate-800 uppercase tracking-[0.12em] text-[10px] text-slate-500">
{headers.map((header, index) => (
<th
key={index}
className={`px-5 py-4 font-semibold whitespace-nowrap ${
index === headers.length - 1
? "text-center"
: "text-left"
}`}
>
{header}
</th>
))}
</tr>
</thead>
<tbody className="divide-y divide-slate-800/70">
{rows.map((row, rowIndex) => (
<tr
key={rowIndex}
className="transition-colors duration-200 hover:bg-slate-800/30"
>
{row.map((cell, cellIndex) => (
<td
key={cellIndex}
className={`px-5 py-4 text-[12px] text-slate-300 whitespace-nowrap ${
cellIndex === row.length - 1
? "text-center"
: "text-left"
}`}
>
{cell}
</td>
))}
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}

View File

@@ -0,0 +1,25 @@
import { FormProps } from "@/types/types";
export default function FormInput({
label,
value,
type = "text",
placeholder="string"
}: FormProps) {
return (
<div>
<label className="mb-2 block text-sm text-slate-400">
{label}
</label>
<input
type={type}
defaultValue={value}
placeholder={placeholder}
className="h-10 w-full rounded-xl border border-slate-700 text-white px-5"
/>
</div>
);
}

View File

@@ -0,0 +1,22 @@
import {InfoBannerProps} from "@/types/types";
export default function InfoBanner({
boldText,
normalText,
}: InfoBannerProps) {
return (
<div className="w-full
rounded-xl border border-l-4 border-[#142538]
border-l-[#10b981] bg-[#091624]
p-4 flex items-center shadow-sm">
<p className="text-sm font-medium text-slate-300 tracking-wide leading-relaxed">
{boldText && <strong className="text-white font-bold mr-1.5">{boldText}</strong>}
{normalText}
</p>
</div>
);
}

View File

@@ -0,0 +1,44 @@
import { FilterTabsProps } from "@/types/types";
export default function FilterTabs({
options = [],
activeFilter,
onChange,
className = "",
}: FilterTabsProps) {
if (!Array.isArray(options) || options.length === 0) {
return null;
}
return (
<div className={`flex items-center gap-2.5 overflow-x-auto no-scrollbar py-1 ${className}`}>
{options.map((filter) => {
const isActive = activeFilter === filter.label;
return (
<button
key={filter.label}
type="button"
onClick={() => onChange(filter.label)}
className={`flex items-center gap-2 px-3.5 py-1.5 rounded-full text-xs font-medium transition-all whitespace-nowrap cursor-pointer ${
isActive
? "bg-teal-950/40 text-teal-400 border border-teal-500/50"
: "bg-[#0b1727] text-slate-400 border border-slate-800/80 hover:text-slate-200"
}`}
>
<span>{filter.label}</span>
{filter.count !== undefined && (
<span
className={`font-mono text-[11px] ${
isActive ? "text-teal-400 font-bold" : "text-slate-400"
}`}
>
{filter.count}
</span>
)}
</button>
);
})}
</div>
);
}

View File

@@ -0,0 +1,31 @@
import { NavigationTabsProps } from "@/types/types";
export default function NavigationTabs({
tabs,
activeTab,
onTabChange,
className = '',
}: NavigationTabsProps) {
return (
<div
className={`flex items-center gap-8 border-b border-slate-800 text-sm font-semibold overflow-x-auto no-scrollbar ${className}`}
>
{tabs.map((tab) => (
<button
key={tab}
onClick={() => onTabChange(tab)}
className={`pb-3 relative transition-colors whitespace-nowrap ${
activeTab === tab
? 'text-teal-400 border-b-2 border-teal-400 font-bold'
: 'text-slate-400 hover:text-slate-200'
}`}
>
{tab}
</button>
))}
</div>
);
}