diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..d74ff32 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +rust-ai/target/** linguist-generated=true -diff -merge diff --git a/.gitignore b/.gitignore index 6bf56ef..fc8aaa7 100644 --- a/.gitignore +++ b/.gitignore @@ -55,9 +55,3 @@ browser-use-service/.env # typescript *.tsbuildinfo next-env.d.ts -.git -.git_bak -node_modules -target -# rust build artifacts -rust-ai/target/ diff --git a/src/app/(dashboard)/dashboard/page.tsx b/src/app/(dashboard)/dashboard/page.tsx index b6fe84f..6ec0f57 100644 --- a/src/app/(dashboard)/dashboard/page.tsx +++ b/src/app/(dashboard)/dashboard/page.tsx @@ -62,8 +62,15 @@ export default function DashboardPage() { : [] return ( -
- +
+ {/* Daily Bugle watermark */} +
+ + DAILY BUGLE + +
+ + Dashboard} description="Overview of your sales pipeline"> -

Pipeline Overview

+

Pipeline Overview

{stats @@ -89,7 +96,7 @@ export default function DashboardPage() { }
-

Analytics

+

Analytics

diff --git a/src/app/globals.css b/src/app/globals.css index b50acdf..bc54320 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,7 +1,14 @@ +@import url('https://fonts.googleapis.com/css2?family=Bangers&display=swap'); + @tailwind base; @tailwind components; @tailwind utilities; +@keyframes loading { + 0% { transform: translateX(-100%); } + 100% { transform: translateX(400%); } +} + :root { --background: 210 40% 98%; --foreground: 222.2 84% 4.9%; @@ -9,7 +16,7 @@ --card-foreground: 222.2 84% 4.9%; --popover: 0 0% 100%; --popover-foreground: 222.2 84% 4.9%; - --primary: 221.2 83.2% 53.3%; + --primary: 0 100% 40%; --primary-foreground: 210 40% 98%; --secondary: 210 40% 96.1%; --secondary-foreground: 222.2 47.4% 11.2%; @@ -22,14 +29,14 @@ --border: 214.3 31.8% 91.4%; --input: 214.3 31.8% 91.4%; --ring: 221.2 83.2% 53.3%; - --sidebar: 0 0% 100%; - --sidebar-foreground: 222.2 84% 4.9%; - --sidebar-primary: 221.2 83.2% 53.3%; + --sidebar: 222.2 84% 4.9%; + --sidebar-foreground: 210 40% 98%; + --sidebar-primary: 217.2 91.2% 59.8%; --sidebar-primary-foreground: 0 0% 100%; - --sidebar-accent: 210 40% 96.1%; - --sidebar-accent-foreground: 222.2 84% 4.9%; - --sidebar-border: 214.3 31.8% 91.4%; - --sidebar-ring: 221.2 83.2% 53.3%; + --sidebar-accent: 217.2 32.6% 17.5%; + --sidebar-accent-foreground: 210 40% 98%; + --sidebar-border: 217.2 32.6% 17.5%; + --sidebar-ring: 224.3 76.3% 48%; --radius: 0.5rem; } @@ -40,7 +47,7 @@ --card-foreground: 210 40% 98%; --popover: 222.2 84% 4.9%; --popover-foreground: 210 40% 98%; - --primary: 217.2 91.2% 59.8%; + --primary: 0 100% 53%; --primary-foreground: 222.2 47.4% 11.2%; --secondary: 217.2 32.6% 17.5%; --secondary-foreground: 210 40% 98%; @@ -52,15 +59,267 @@ --destructive-foreground: 210 40% 98%; --border: 217.2 32.6% 17.5%; --input: 217.2 32.6% 17.5%; - --ring: 224.3 76.3% 48%; + --ring: 0 100% 53%; --sidebar: 222.2 84% 4.9%; --sidebar-foreground: 210 40% 98%; - --sidebar-primary: 217.2 91.2% 59.8%; + --sidebar-primary: 0 100% 53%; --sidebar-primary-foreground: 0 0% 100%; --sidebar-accent: 217.2 32.6% 17.5%; --sidebar-accent-foreground: 210 40% 98%; --sidebar-border: 217.2 32.6% 17.5%; - --sidebar-ring: 224.3 76.3% 48%; + --sidebar-ring: 0 100% 53%; +} + +.ocean { + --primary: 187 75% 42%; + --primary-foreground: 210 40% 98%; + --ring: 187 75% 42%; + --sidebar: 0 0% 100%; + --sidebar-foreground: 222.2 84% 4.9%; + --sidebar-primary: 187 75% 42%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 187 30% 94%; + --sidebar-accent-foreground: 187 50% 20%; + --sidebar-border: 187 20% 88%; + --sidebar-ring: 187 75% 42%; +} + +.dark.ocean { + --primary: 187 75% 50%; + --primary-foreground: 222.2 47.4% 11.2%; + --ring: 187 75% 50%; + --sidebar: 222.2 84% 4.9%; + --sidebar-foreground: 210 40% 98%; + --sidebar-primary: 187 75% 55%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 217.2 32.6% 17.5%; + --sidebar-accent-foreground: 210 40% 98%; + --sidebar-border: 217.2 32.6% 17.5%; + --sidebar-ring: 187 75% 50%; +} + +.forest { + --primary: 142 76% 36%; + --primary-foreground: 210 40% 98%; + --ring: 142 76% 36%; + --sidebar: 0 0% 100%; + --sidebar-foreground: 222.2 84% 4.9%; + --sidebar-primary: 142 76% 36%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 142 30% 94%; + --sidebar-accent-foreground: 142 50% 20%; + --sidebar-border: 142 20% 88%; + --sidebar-ring: 142 76% 36%; +} + +.dark.forest { + --primary: 142 76% 44%; + --primary-foreground: 222.2 47.4% 11.2%; + --ring: 142 76% 44%; + --sidebar: 222.2 84% 4.9%; + --sidebar-foreground: 210 40% 98%; + --sidebar-primary: 142 76% 50%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 217.2 32.6% 17.5%; + --sidebar-accent-foreground: 210 40% 98%; + --sidebar-border: 217.2 32.6% 17.5%; + --sidebar-ring: 142 76% 44%; +} + +.sunset { + --primary: 24 95% 53%; + --primary-foreground: 210 40% 98%; + --ring: 24 95% 53%; + --sidebar: 0 0% 100%; + --sidebar-foreground: 222.2 84% 4.9%; + --sidebar-primary: 24 95% 53%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 24 30% 94%; + --sidebar-accent-foreground: 24 50% 20%; + --sidebar-border: 24 20% 88%; + --sidebar-ring: 24 95% 53%; +} + +.dark.sunset { + --primary: 24 95% 58%; + --primary-foreground: 222.2 47.4% 11.2%; + --ring: 24 95% 58%; + --sidebar: 222.2 84% 4.9%; + --sidebar-foreground: 210 40% 98%; + --sidebar-primary: 24 95% 65%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 217.2 32.6% 17.5%; + --sidebar-accent-foreground: 210 40% 98%; + --sidebar-border: 217.2 32.6% 17.5%; + --sidebar-ring: 24 95% 58%; +} + +.midnight { + --primary: 230 75% 55%; + --primary-foreground: 210 40% 98%; + --ring: 230 75% 55%; + --sidebar: 0 0% 100%; + --sidebar-foreground: 222.2 84% 4.9%; + --sidebar-primary: 230 75% 55%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 230 30% 94%; + --sidebar-accent-foreground: 230 50% 20%; + --sidebar-border: 230 20% 88%; + --sidebar-ring: 230 75% 55%; +} + +.dark.midnight { + --primary: 230 75% 62%; + --primary-foreground: 222.2 47.4% 11.2%; + --ring: 230 75% 62%; + --sidebar: 222.2 84% 4.9%; + --sidebar-foreground: 210 40% 98%; + --sidebar-primary: 230 75% 65%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 217.2 32.6% 17.5%; + --sidebar-accent-foreground: 210 40% 98%; + --sidebar-border: 217.2 32.6% 17.5%; + --sidebar-ring: 230 75% 62%; +} + +.rose { + --primary: 346 77% 50%; + --primary-foreground: 210 40% 98%; + --ring: 346 77% 50%; + --sidebar: 0 0% 100%; + --sidebar-foreground: 222.2 84% 4.9%; + --sidebar-primary: 346 77% 50%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 346 30% 94%; + --sidebar-accent-foreground: 346 50% 20%; + --sidebar-border: 346 20% 88%; + --sidebar-ring: 346 77% 50%; +} + +.dark.rose { + --primary: 346 77% 58%; + --primary-foreground: 222.2 47.4% 11.2%; + --ring: 346 77% 58%; + --sidebar: 222.2 84% 4.9%; + --sidebar-foreground: 210 40% 98%; + --sidebar-primary: 346 77% 60%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 217.2 32.6% 17.5%; + --sidebar-accent-foreground: 210 40% 98%; + --sidebar-border: 217.2 32.6% 17.5%; + --sidebar-ring: 346 77% 58%; +} + +.amber { + --primary: 38 92% 50%; + --primary-foreground: 210 40% 98%; + --ring: 38 92% 50%; + --sidebar: 0 0% 100%; + --sidebar-foreground: 222.2 84% 4.9%; + --sidebar-primary: 38 92% 50%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 38 30% 94%; + --sidebar-accent-foreground: 38 50% 20%; + --sidebar-border: 38 20% 88%; + --sidebar-ring: 38 92% 50%; +} + +.dark.amber { + --primary: 38 92% 56%; + --primary-foreground: 222.2 47.4% 11.2%; + --ring: 38 92% 56%; + --sidebar: 222.2 84% 4.9%; + --sidebar-foreground: 210 40% 98%; + --sidebar-primary: 38 92% 60%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 217.2 32.6% 17.5%; + --sidebar-accent-foreground: 210 40% 98%; + --sidebar-border: 217.2 32.6% 17.5%; + --sidebar-ring: 38 92% 56%; +} + +.violet { + --primary: 262 83% 58%; + --primary-foreground: 210 40% 98%; + --ring: 262 83% 58%; + --sidebar: 0 0% 100%; + --sidebar-foreground: 222.2 84% 4.9%; + --sidebar-primary: 262 83% 58%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 262 30% 94%; + --sidebar-accent-foreground: 262 50% 20%; + --sidebar-border: 262 20% 88%; + --sidebar-ring: 262 83% 58%; +} + +.dark.violet { + --primary: 262 83% 65%; + --primary-foreground: 222.2 47.4% 11.2%; + --ring: 262 83% 65%; + --sidebar: 222.2 84% 4.9%; + --sidebar-foreground: 210 40% 98%; + --sidebar-primary: 262 83% 68%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 217.2 32.6% 17.5%; + --sidebar-accent-foreground: 210 40% 98%; + --sidebar-border: 217.2 32.6% 17.5%; + --sidebar-ring: 262 83% 65%; +} + +.slate { + --primary: 215 20% 45%; + --primary-foreground: 210 40% 98%; + --ring: 215 20% 45%; + --sidebar: 0 0% 100%; + --sidebar-foreground: 222.2 84% 4.9%; + --sidebar-primary: 215 20% 45%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 215 20% 94%; + --sidebar-accent-foreground: 215 50% 20%; + --sidebar-border: 215 20% 88%; + --sidebar-ring: 215 20% 45%; +} + +.dark.slate { + --primary: 215 20% 60%; + --primary-foreground: 222.2 47.4% 11.2%; + --ring: 215 20% 60%; + --sidebar: 222.2 84% 4.9%; + --sidebar-foreground: 210 40% 98%; + --sidebar-primary: 215 20% 65%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 217.2 32.6% 17.5%; + --sidebar-accent-foreground: 210 40% 98%; + --sidebar-border: 217.2 32.6% 17.5%; + --sidebar-ring: 215 20% 60%; +} + +.ruby { + --primary: 351 85% 45%; + --primary-foreground: 210 40% 98%; + --ring: 351 85% 45%; + --sidebar: 0 0% 100%; + --sidebar-foreground: 222.2 84% 4.9%; + --sidebar-primary: 351 85% 45%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 351 30% 94%; + --sidebar-accent-foreground: 351 50% 20%; + --sidebar-border: 351 20% 88%; + --sidebar-ring: 351 85% 45%; +} + +.dark.ruby { + --primary: 351 85% 52%; + --primary-foreground: 222.2 47.4% 11.2%; + --ring: 351 85% 52%; + --sidebar: 222.2 84% 4.9%; + --sidebar-foreground: 210 40% 98%; + --sidebar-primary: 351 85% 55%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 217.2 32.6% 17.5%; + --sidebar-accent-foreground: 210 40% 98%; + --sidebar-border: 217.2 32.6% 17.5%; + --sidebar-ring: 351 85% 52%; } .ocean { diff --git a/src/components/dashboard/lead-status-chart.tsx b/src/components/dashboard/lead-status-chart.tsx index 30d2780..decc2c0 100644 --- a/src/components/dashboard/lead-status-chart.tsx +++ b/src/components/dashboard/lead-status-chart.tsx @@ -68,11 +68,24 @@ export function LeadStatusChart({ data }: LeadStatusChartProps) { transition={{ duration: 0.3, delay: 0.2 }} className="h-full" > - + + {/* Spider watermark */} +
+ + + + + + + + + +
+ Lead Status - +
{/* Donut */} diff --git a/src/components/dashboard/leads-per-month-chart.tsx b/src/components/dashboard/leads-per-month-chart.tsx index d58eb23..2ce7078 100644 --- a/src/components/dashboard/leads-per-month-chart.tsx +++ b/src/components/dashboard/leads-per-month-chart.tsx @@ -16,8 +16,8 @@ interface LeadsPerMonthChartProps { data: IntervalData[] } -const NEW_LEADS = "#0d9488" -const CLOSED = "#c9a96e" +const NEW_LEADS = "#CC0000" +const CLOSED = "#0033CC" export function LeadsPerMonthChart({ data: initialData }: LeadsPerMonthChartProps) { const [year, setYear] = useState(new Date().getFullYear()) @@ -153,11 +153,11 @@ export function LeadsPerMonthChart({ data: initialData }: LeadsPerMonthChartProp > - + - + diff --git a/src/components/dashboard/stat-card-skeleton.tsx b/src/components/dashboard/stat-card-skeleton.tsx index 918a7e4..eec1d4c 100644 --- a/src/components/dashboard/stat-card-skeleton.tsx +++ b/src/components/dashboard/stat-card-skeleton.tsx @@ -1,20 +1,17 @@ "use client" -import { Card, CardContent } from "@/components/ui/card" -import { Skeleton } from "@/components/ui/skeleton" - export function StatCardSkeleton() { return ( - - -
-
- - -
- -
- - +
+

+ THWIP! +

+

+ Loading your data... +

+
+
+
+
) } diff --git a/src/components/dashboard/stat-card.tsx b/src/components/dashboard/stat-card.tsx index 960476f..6d00d9c 100644 --- a/src/components/dashboard/stat-card.tsx +++ b/src/components/dashboard/stat-card.tsx @@ -19,12 +19,12 @@ interface StatCardProps { } const cardColors: Record = { - "Total Leads": { bg: "bg-cyan-500/10", text: "text-cyan-600 dark:text-cyan-400", glow: "via-[rgba(6,182,212,0.25)]", accent: "#06b6d4" }, - "Open Leads": { bg: "bg-blue-500/10", text: "text-blue-600 dark:text-blue-400", glow: "via-[rgba(59,130,246,0.25)]", accent: "#3b82f6" }, - "Contacted": { bg: "bg-amber-500/10", text: "text-amber-600 dark:text-amber-400", glow: "via-[rgba(245,158,11,0.25)]", accent: "#f59e0b" }, - "Pending": { bg: "bg-violet-500/10", text: "text-violet-600 dark:text-violet-400", glow: "via-[rgba(139,92,246,0.25)]", accent: "#8b5cf6" }, - "Closed": { bg: "bg-yellow-500/10", text: "text-yellow-600 dark:text-yellow-400", glow: "via-[rgba(234,179,8,0.25)]", accent: "#eab308" }, - "Conversion Rate": { bg: "bg-rose-500/10", text: "text-rose-600 dark:text-rose-400", glow: "via-[rgba(244,63,94,0.25)]", accent: "#f43f5e" }, + "Total Leads": { bg: "bg-[#CC0000]/10", text: "text-[#CC0000] dark:text-[#FF1111]", glow: "via-[rgba(204,0,0,0.25)]", accent: "#CC0000" }, + "Open Leads": { bg: "bg-[#0033CC]/10", text: "text-[#0033CC] dark:text-[#1144FF]", glow: "via-[rgba(0,51,204,0.25)]", accent: "#0033CC" }, + "Contacted": { bg: "bg-[#CC0000]/10", text: "text-[#CC0000] dark:text-[#FF1111]", glow: "via-[rgba(204,0,0,0.25)]", accent: "#CC0000" }, + "Pending": { bg: "bg-[#0033CC]/10", text: "text-[#0033CC] dark:text-[#1144FF]", glow: "via-[rgba(0,51,204,0.25)]", accent: "#0033CC" }, + "Closed": { bg: "bg-[#CC0000]/10", text: "text-[#CC0000] dark:text-[#FF1111]", glow: "via-[rgba(204,0,0,0.25)]", accent: "#CC0000" }, + "Conversion Rate": { bg: "bg-[#0033CC]/10", text: "text-[#0033CC] dark:text-[#1144FF]", glow: "via-[rgba(0,51,204,0.25)]", accent: "#0033CC" }, } function computeGoal(max: number): number { @@ -107,6 +107,10 @@ export function StatCard({ title, value, icon: Icon, description, index = 0, tre const { path: sparkPath, area: sparkArea, goal, gridLines } = buildSparklineSvg() const sparkColor = color.accent + const isRed = index % 2 === 0 + const stripColor = isRed ? "from-[#CC0000] via-[#FF1111] to-[#CC0000]" : "from-[#0033CC] via-[#1144FF] to-[#0033CC]" + const stripGlow = isRed ? "shadow-[#CC0000]/20" : "shadow-[#0033CC]/20" + return ( - + {/* Web overlay decorative */} +
+ + {Array.from({ length: 6 }).map((_, i) => ( + + ))} + {Array.from({ length: 6 }).map((_, i) => ( + + ))} + {Array.from({ length: 6 }).map((_, i) => ( + + ))} + +
+ + {/* Comic action lines on hover */} +
+ + + + + + + + + + + + +
+ + + {/* Red/Blue gradient top strip */} +
+

{title}

-

+

{isNumeric ? display : value}

{description && ( -

{description}

+

{description}

)} {trend && ( )}
-
- +
+
@@ -179,9 +217,9 @@ export function StatCard({ title, value, icon: Icon, description, index = 0, tre {title === "Conversion Rate" && conversionRate !== undefined && (
-
+
-

{conversionRate}% conversion rate

+

{conversionRate}% conversion rate

)} diff --git a/src/components/layout/app-shell.tsx b/src/components/layout/app-shell.tsx index ebd04ef..36eba4b 100644 --- a/src/components/layout/app-shell.tsx +++ b/src/components/layout/app-shell.tsx @@ -34,7 +34,52 @@ export function AppShell({ children }: AppShellProps) { } return ( -
+
+ {/* Spider-Man top gradient bar */} +
+ + {/* Corner spider webs */} +
+ + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + +
+ +
+ {/* Red/Blue diagonal split accent */} +
+ {/* Logo */}
-
- + + + + + + CRM
@@ -88,10 +95,10 @@ export function Topbar({ onMenuClick }: TopbarProps) { {/* Search */}
- +
diff --git a/src/components/shared/page-header.tsx b/src/components/shared/page-header.tsx index 7cd6c34..e24637a 100644 --- a/src/components/shared/page-header.tsx +++ b/src/components/shared/page-header.tsx @@ -19,8 +19,8 @@ export function PageHeader({ title, description, children, className }: PageHead className={cn("flex items-center justify-between pb-6", className)} >
-

{title}

- {description &&

{description}

} +

{title}

+ {description &&

{description}

}
{children &&
{children}
} diff --git a/src/data/dashboard.ts b/src/data/dashboard.ts index 33436d2..dadf75a 100644 --- a/src/data/dashboard.ts +++ b/src/data/dashboard.ts @@ -30,11 +30,11 @@ export function getDashboardStats(period: string): DashboardStats { }) return [ - { name: "Open", value: statusCounts.open, color: "#3b82f6" }, - { name: "Contacted", value: statusCounts.contacted, color: "#f59e0b" }, - { name: "Pending", value: statusCounts.pending, color: "#8b5cf6" }, - { name: "Closed", value: statusCounts.closed, color: "#10b981" }, - { name: "Ignored", value: statusCounts.ignored, color: "#6B7280" }, + { name: "Open", value: statusCounts.open, color: "#CC0000" }, + { name: "Contacted", value: statusCounts.contacted, color: "#0033CC" }, + { name: "Pending", value: statusCounts.pending, color: "#FFFFFF" }, + { name: "Closed", value: statusCounts.closed, color: "#0033CC" }, + { name: "Ignored", value: statusCounts.ignored, color: "#CC0000" }, ] }