diff --git a/src/components/shared/GradientStatCard.tsx b/src/components/shared/GradientStatCard.tsx new file mode 100644 index 0000000..66834cc --- /dev/null +++ b/src/components/shared/GradientStatCard.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import type { LucideIcon } from 'lucide-react'; +import { cn } from '@/lib/utils'; + +interface GradientStatCardProps { + icon: LucideIcon; + value: string | number; + label: string; + badge?: { + text: string; + variant: 'success' | 'warning' | 'info' | 'error' | 'green' | 'gray'; + }; +} + +export const GradientStatCard: React.FC = ({ icon: Icon, value, label, badge }) => { + return ( +
+
+
+
+ +
+ {badge && ( +
+ {badge.text} +
+ )} +
+ +
+

+ {value} +

+

+ {label} +

+
+
+
+ ); +}; diff --git a/src/components/shared/index.ts b/src/components/shared/index.ts index 4f3e6a6..7511dae 100644 --- a/src/components/shared/index.ts +++ b/src/components/shared/index.ts @@ -43,3 +43,4 @@ export { ActiveOnlyToggle } from './ActiveOnlyToggle'; export { SearchBox } from './SearchBox'; export { FormTagInput } from './FormTagInput'; export { MarkdownViewer } from './MarkdownViewer'; +export { GradientStatCard } from './GradientStatCard'; diff --git a/src/features/dashboard/components/StatsGrid.tsx b/src/features/dashboard/components/StatsGrid.tsx index 78a942e..a7ae2a5 100644 --- a/src/features/dashboard/components/StatsGrid.tsx +++ b/src/features/dashboard/components/StatsGrid.tsx @@ -2,12 +2,10 @@ import { useState, useEffect } from "react"; import { Building2, CheckCircle2, - // Users, - // TrendingUp, Package, Heart, } from "lucide-react"; -import { StatCard } from "./StatCard"; +import { GradientStatCard } from "@/components/shared"; import type { StatCardData } from "@/types/dashboard"; import { dashboardService } from "@/services/dashboard-service"; @@ -29,7 +27,7 @@ export const StatsGrid = () => { icon: Building2, value: data.totalTenants, label: "Total Tenants", - badge: { text: `${data.activeTenants} active`, variant: "green" }, + badge: { text: `${data.activeTenants} active`, variant: "success" }, }, { icon: CheckCircle2, @@ -40,26 +38,14 @@ export const StatsGrid = () => { data.totalTenants > 0 ? `${Math.round((data.activeTenants / data.totalTenants) * 100)}% Rate` : "0% Rate", - variant: "green", + variant: "success", }, }, - // { - // icon: Users, - // value: data.totalUsers, - // label: "Total Users", - // badge: { text: "All users", variant: "gray" }, - // }, - // { - // icon: TrendingUp, - // value: data.activeSessions, - // label: "Active Sessions", - // badge: { text: "Live now", variant: "gray" }, - // }, { icon: Package, value: data.registeredModules, label: "Registered Modules", - badge: { text: "Total", variant: "gray" }, + badge: { text: "Total", variant: "info" }, }, { icon: Heart, @@ -73,8 +59,8 @@ export const StatsGrid = () => { variant: data.healthyModules === data.registeredModules && data.registeredModules > 0 - ? "green" - : "gray", + ? "success" + : "info", }, }, ]; @@ -93,15 +79,17 @@ export const StatsGrid = () => { if (isLoading) { return ( -
- {Array.from({ length: 6 }).map((_, index) => ( +
+ {Array.from({ length: 4 }).map((_, index) => (
-
-
-
+
+
+
+
+
))}
@@ -117,9 +105,9 @@ export const StatsGrid = () => { } return ( -
+
{statsData.map((stat, index) => ( - + ))}
); diff --git a/src/index.css b/src/index.css index 15fcf15..19ef123 100644 --- a/src/index.css +++ b/src/index.css @@ -1,9 +1,10 @@ +@import url('https://fonts.googleapis.com/css2?family=Figtree:ital,wght@0,300..900;1,300..900&display=swap'); @import "tailwindcss"; -@import "tw-animate-css"; @custom-variant dark (&:is(.dark *)); @theme inline { + --font-sans: "Figtree", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; --radius-sm: calc(var(--radius) - 4px); --radius-md: calc(var(--radius) - 2px); --radius-lg: var(--radius); @@ -115,9 +116,12 @@ @layer base { * { - @apply border-border outline-ring/50; + border-color: var(--color-border); + outline-color: var(--color-ring); } body { - @apply bg-background text-foreground; + background-color: var(--color-background); + color: var(--color-foreground); + font-family: var(--font-sans); } } \ No newline at end of file diff --git a/src/pages/superadmin/Dashboard.tsx b/src/pages/superadmin/Dashboard.tsx index 6e001f6..b98b6a4 100644 --- a/src/pages/superadmin/Dashboard.tsx +++ b/src/pages/superadmin/Dashboard.tsx @@ -1,8 +1,8 @@ -import type { ReactElement } from 'react'; -import { Layout } from '@/components/layout/Layout'; -import { StatsGrid } from '@/features/dashboard/components/StatsGrid'; -import { RecentActivity } from '@/features/dashboard/components/RecentActivity'; -import { QuickActions } from '@/features/dashboard/components/QuickActions'; +import type { ReactElement } from "react"; +import { Layout } from "@/components/layout/Layout"; +import { StatsGrid } from "@/features/dashboard/components/StatsGrid"; +import { RecentActivity } from "@/features/dashboard/components/RecentActivity"; +import { QuickActions } from "@/features/dashboard/components/QuickActions"; // import { SystemHealth } from '@/features/dashboard/components/SystemHealth'; const Dashboard = (): ReactElement => { @@ -10,19 +10,22 @@ const Dashboard = (): ReactElement => { - {/* Stats Grid */} - {/* Bottom Section */} -
- -
+
+ {/* Main Content Area (Left) */} +
+ +
+ + {/* Sidebar (Right) */} +
- {/* */}
diff --git a/src/pages/tenant/Dashboard.tsx b/src/pages/tenant/Dashboard.tsx index d32caf6..409fb40 100644 --- a/src/pages/tenant/Dashboard.tsx +++ b/src/pages/tenant/Dashboard.tsx @@ -16,9 +16,11 @@ import { workflowService } from "@/services/workflow-service"; import { dashboardService, type TenantDashboardStats } from "@/services/dashboard-service"; import type { WorkflowTask } from "@/types/workflow"; import { useNavigate } from "react-router-dom"; +import { GradientStatCard } from "@/components/shared"; +import type { LucideIcon } from "lucide-react"; interface StatCardProps { - icon: React.ComponentType<{ className?: string; strokeWidth?: number }>; + icon: LucideIcon; value: string | number; label: string; badge?: { @@ -27,52 +29,6 @@ interface StatCardProps { }; } -const StatCard = ({ - icon: Icon, - value, - label, - badge -}: StatCardProps): ReactElement => { - const { primaryColor } = useAppTheme(); - return ( -
-
- {/* Interaction Gradient */} -
- -
-
- -
- {badge && ( -
- {badge.text} -
- )} -
- -
-
- {value} -
-
- {label} -
-
-
-
- ); -}; - const TaskCard = ({ task }: { task: WorkflowTask }) => { // const { primaryColor } = useAppTheme(); const navigate = useNavigate(); @@ -309,12 +265,12 @@ const Dashboard = (): ReactElement => { {/* Main Content Area (Left) */}
{/* Stats Grid */} -
+
{loading ? (
Loading statistics...
) : statCards.length > 0 ? ( statCards.map((card, index) => ( - + )) ) : (
No statistics available
diff --git a/src/pages/tenant/TenantAIDashboard.tsx b/src/pages/tenant/TenantAIDashboard.tsx index d6f4feb..556a006 100644 --- a/src/pages/tenant/TenantAIDashboard.tsx +++ b/src/pages/tenant/TenantAIDashboard.tsx @@ -1,6 +1,11 @@ import { useEffect, useState, type ReactElement } from "react"; import { Layout } from "@/components/layout/Layout"; -import { DataTable, type Column, FilterDropdown } from "@/components/shared"; +import { + DataTable, + type Column, + FilterDropdown, + GradientStatCard, +} from "@/components/shared"; import { aiService } from "@/services/ai-service"; import type { AICostSummary } from "@/types/ai"; import { showToast } from "@/utils/toast"; @@ -184,7 +189,11 @@ export const TenantAIDashboard = (): ReactElement => { @@ -209,78 +218,30 @@ export const TenantAIDashboard = (): ReactElement => {
{/* Stats Row */} -
- {/* Card 1 */} -
-
-
- -
+
+ -
-

- {costs?.summary?.total_completions || 0} -

-

- Total Completions -

-
-
-
+ - {/* Card 2 */} -
-
-
- -
+ -
-

- {formatTokens(costs?.summary?.total_tokens || 0)} -

-

- Total Tokens -

-
-
-
- - {/* Card 3 */} -
-
-
- -
- -
-

- ${(costs?.summary?.total_cost || 0).toFixed(2)} -

-

- Total Cost (USD) -

-
-
-
- - {/* Card 4 */} -
-
-
- -
- -
-

- {formatLatency(costs?.summary?.avg_latency_ms || 0)} -

-

- Avg Latency (ms) -

-
-
-
+
{/* Charts and Tables */} diff --git a/src/types/dashboard.ts b/src/types/dashboard.ts index 07d834d..720294d 100644 --- a/src/types/dashboard.ts +++ b/src/types/dashboard.ts @@ -1,10 +1,12 @@ +import type { LucideIcon } from "lucide-react"; + export interface StatCardData { - icon: React.ComponentType<{ className?: string; strokeWidth?: number; color?: string; style?: React.CSSProperties }>; + icon: LucideIcon; value: string | number; label: string; badge?: { text: string; - variant: 'green' | 'gray'; + variant: 'success' | 'warning' | 'info' | 'error' | 'green' | 'gray'; }; } @@ -17,7 +19,7 @@ export interface ActivityLog { } export interface QuickAction { - icon: React.ComponentType<{ className?: string; strokeWidth?: number; color?: string; style?: React.CSSProperties }>; + icon: LucideIcon; label: string; onClick: () => void; } diff --git a/vite.config.ts b/vite.config.ts index ea8c085..0df761c 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -5,7 +5,7 @@ import path from "path"; // https://vite.dev/config/ export default defineConfig({ - plugins: [tailwindcss(),react()], + plugins: [tailwindcss(), react()], resolve: { alias: { "@": path.resolve(__dirname, "src"),