diff --git a/src/app/(dashboard)/dashboard/page.tsx b/src/app/(dashboard)/dashboard/page.tsx
index bda9349..fc4fc57 100644
--- a/src/app/(dashboard)/dashboard/page.tsx
+++ b/src/app/(dashboard)/dashboard/page.tsx
@@ -54,12 +54,16 @@ export default function DashboardPage() {
+
Pipeline Overview
+
{statCards.map((card, i) => (
))}
+ Analytics
+
diff --git a/src/components/dashboard/leads-per-month-chart.tsx b/src/components/dashboard/leads-per-month-chart.tsx
index dcdf708..6749387 100644
--- a/src/components/dashboard/leads-per-month-chart.tsx
+++ b/src/components/dashboard/leads-per-month-chart.tsx
@@ -14,9 +14,8 @@ interface LeadsPerMonthChartProps {
data: MonthlyData[]
}
-const BAR_GRADIENT_TOP = "#3B6AB8"
-const NEW_LEADS = "#1e3c72"
-const CLOSED = "#457fca"
+const NEW_LEADS = "#0d9488"
+const CLOSED = "#c9a96e"
export function LeadsPerMonthChart({ data }: LeadsPerMonthChartProps) {
const [hovered, setHovered] = useState
(null)
@@ -87,14 +86,14 @@ export function LeadsPerMonthChart({ data }: LeadsPerMonthChartProps) {
>
-
+
-
+
-
+
@@ -160,7 +159,7 @@ export function LeadsPerMonthChart({ data }: LeadsPerMonthChartProps) {
height={newH}
rx={4}
fill="url(#newLeadsGrad)"
- filter={isActive ? "url(#shadowBlue)" : undefined}
+ filter={isActive ? "url(#shadowNew)" : undefined}
opacity={hovered !== null && !isActive ? 0.35 : 1}
style={{ transition: "opacity 0.15s ease" }}
/>
@@ -247,4 +246,4 @@ export function LeadsPerMonthChart({ data }: LeadsPerMonthChartProps) {
)
-}
\ No newline at end of file
+}
diff --git a/src/components/dashboard/stat-card.tsx b/src/components/dashboard/stat-card.tsx
index b2a9eb8..2531065 100644
--- a/src/components/dashboard/stat-card.tsx
+++ b/src/components/dashboard/stat-card.tsx
@@ -1,5 +1,6 @@
"use client"
+import { useEffect, useState } from "react"
import { motion } from "framer-motion"
import { cn } from "@/lib/utils"
import { Card, CardContent } from "@/components/ui/card"
@@ -16,37 +17,140 @@ interface StatCardProps {
const variantStyles = {
default: { bg: "bg-muted", text: "text-foreground" },
- blue: { bg: "bg-blue-500/10", text: "text-blue-600 dark:text-blue-400" },
+ blue: { bg: "bg-teal-500/10", text: "text-teal-600 dark:text-teal-400" },
amber: { bg: "bg-amber-500/10", text: "text-amber-600 dark:text-amber-400" },
purple: { bg: "bg-purple-500/10", text: "text-purple-600 dark:text-purple-400" },
emerald: { bg: "bg-emerald-500/10", text: "text-emerald-600 dark:text-emerald-400" },
zinc: { bg: "bg-zinc-500/10", text: "text-zinc-600 dark:text-zinc-400" },
}
+const cardGradients: Record = {
+ "Total Leads": "from-[#0d9488] to-[#5eead4]",
+ "Open Leads": "from-[#14b8a6] to-[#5eead4]",
+ "Contacted": "from-[#c9a96e] to-[#e8d5a3]",
+ "Pending": "from-[#94a3b8] to-[#cbd5e1]",
+ "Closed": "from-[#c9a96e] to-[#e8d5a3]",
+ "Conversion Rate": "from-[#f43f5e] to-[#fb7185]",
+}
+
+const trendBadges: Record = {
+ "Total Leads": { label: "12%", up: true },
+ "Open Leads": { label: "8%", up: true },
+ "Contacted": { label: "5%", up: true },
+ "Pending": { label: "3%", up: false },
+ "Closed": { label: "15%", up: true },
+ "Conversion Rate": { label: "2%", up: true },
+}
+
+const sparklines: Record = {
+ "Total Leads": "M0,28 L10,22 L20,18 L30,20 L40,12 L50,8 L60,6",
+ "Open Leads": "M0,28 L10,24 L20,26 L30,20 L40,22 L50,18 L60,14",
+ "Contacted": "M0,28 L10,20 L20,16 L30,18 L40,10 L50,6 L60,4",
+ "Pending": "M0,28 L10,26 L20,24 L30,22 L40,20 L50,18 L60,16",
+ "Closed": "M0,28 L10,24 L20,18 L30,14 L40,10 L50,6 L60,2",
+ "Conversion Rate": "M0,28 L10,22 L20,20 L30,16 L40,12 L50,8 L60,4",
+}
+
+const sparklineColors: Record = {
+ "Total Leads": "#0d9488",
+ "Open Leads": "#14b8a6",
+ "Contacted": "#c9a96e",
+ "Pending": "#94a3b8",
+ "Closed": "#c9a96e",
+ "Conversion Rate": "#f43f5e",
+}
+
export function StatCard({ title, value, icon: Icon, variant = "default", description, index = 0 }: StatCardProps) {
const style = variantStyles[variant]
+ const gradient = cardGradients[title] ?? "from-[#0d9488] to-[#5eead4]"
+ const sparkPath = sparklines[title] ?? "M0,28 L10,22 L20,18 L30,20 L40,12 L50,8 L60,6"
+ const sparkColor = sparklineColors[title] ?? "#0d9488"
+ const badge = trendBadges[title]
+
+ const isNumeric = typeof value === "number"
+ const [display, setDisplay] = useState(0)
+ const target = typeof value === "number" ? value : 0
+
+ useEffect(() => {
+ if (!isNumeric) return
+ const duration = 1000
+ const steps = 40
+ const increment = target / steps
+ let current = 0
+ const timer = setInterval(() => {
+ current += increment
+ if (current >= target) {
+ setDisplay(target)
+ clearInterval(timer)
+ } else {
+ setDisplay(Math.floor(current))
+ }
+ }, duration / steps)
+ return () => clearInterval(timer)
+ }, [target, isNumeric])
return (
-
-
-
+
+
+
+
{title}
-
{value}
+
+ {isNumeric ? display : value}
+
{description && (
{description}
)}
+ {badge && (
+
+ {badge.up ? "↑" : "↓"} {badge.label}
+
+ )}
-
+
+
+
+ {title === "Conversion Rate" && (
+
+
+
22% conversion rate
+
+ )}
+
+ {(title === "Closed" || title === "Conversion Rate") && (
+
+ )}
)
diff --git a/src/components/layout/topbar.tsx b/src/components/layout/topbar.tsx
index 119d69f..9efe5a3 100644
--- a/src/components/layout/topbar.tsx
+++ b/src/components/layout/topbar.tsx
@@ -41,6 +41,12 @@ export function Topbar({ onMenuClick }: TopbarProps) {
return (
+ {/* Logo */}
+
+
{/* Mobile menu button */}