Standardize card sizing and spacing
This commit is contained in:
@@ -118,7 +118,7 @@ const SmallLayout = () => {
|
||||
</div>
|
||||
|
||||
{/* Mini Realtime Analytics */}
|
||||
<div>
|
||||
<div className="-mt-1">
|
||||
<div style={{
|
||||
transform: `scale(${ANALYTICS_SCALE})`,
|
||||
transformOrigin: 'top left',
|
||||
|
||||
@@ -78,13 +78,13 @@ const MiniRealtimeAnalytics = () => {
|
||||
|
||||
if (loading && !basicData) {
|
||||
return (
|
||||
<Card className="w-full bg-gradient-to-br from-purple-900 to-purple-800 backdrop-blur-sm h-full">
|
||||
<Card className="w-full bg-gradient-to-br from-sky-900 to-sky-800 backdrop-blur-sm h-full">
|
||||
<CardHeader className="p-4 pb-2">
|
||||
<div className="flex justify-between items-center">
|
||||
<CardTitle className="text-lg font-bold text-purple-100">
|
||||
<CardTitle className="text-lg font-bold text-sky-100">
|
||||
Real-Time Analytics
|
||||
</CardTitle>
|
||||
<Skeleton className="h-4 w-32 bg-purple-700" />
|
||||
<Skeleton className="h-4 w-32 bg-sky-700" />
|
||||
</div>
|
||||
</CardHeader>
|
||||
|
||||
@@ -108,7 +108,7 @@ const MiniRealtimeAnalytics = () => {
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-2 gap-2 mt-1 mb-3">
|
||||
<div className="grid grid-cols-2 gap-2 mt-1 mb-2">
|
||||
{summaryCard(
|
||||
"Last 30 minutes",
|
||||
"Active users",
|
||||
@@ -117,7 +117,7 @@ const MiniRealtimeAnalytics = () => {
|
||||
colorClass: "text-sky-200",
|
||||
titleClass: "text-sky-100 font-bold text-md",
|
||||
descriptionClass: "text-sky-200 text-md font-semibold",
|
||||
background: "bg-gradient-to-br from-sky-800 to-sky-700",
|
||||
background: "h-[150px] bg-gradient-to-br from-sky-900 to-sky-800",
|
||||
icon: Users,
|
||||
iconColor: "text-sky-900",
|
||||
iconBackground: "bg-sky-300"
|
||||
@@ -131,7 +131,7 @@ const MiniRealtimeAnalytics = () => {
|
||||
colorClass: "text-sky-200",
|
||||
titleClass: "text-sky-100 font-bold text-md",
|
||||
descriptionClass: "text-sky-200 text-md font-semibold",
|
||||
background: "bg-gradient-to-br from-sky-800 to-sky-700",
|
||||
background: "h-[150px] bg-gradient-to-br from-sky-900 to-sky-800",
|
||||
icon: Activity,
|
||||
iconColor: "text-sky-900",
|
||||
iconBackground: "bg-sky-300"
|
||||
@@ -139,53 +139,55 @@ const MiniRealtimeAnalytics = () => {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="bg-gradient-to-br from-sky-800 to-sky-700 rounded-lg p-2 h-[200px]">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart
|
||||
data={basicData.byMinute}
|
||||
margin={{ top: 5, right: 5, left: -35, bottom: -5 }}
|
||||
>
|
||||
<XAxis
|
||||
dataKey="minute"
|
||||
tickFormatter={(value) => value + "m"}
|
||||
className="text-xs"
|
||||
tick={{ fill: "#BAE6FD" }}
|
||||
/>
|
||||
<YAxis
|
||||
className="text-xs"
|
||||
tick={{ fill: "#BAE6FD" }}
|
||||
/>
|
||||
<Tooltip
|
||||
content={({ active, payload }) => {
|
||||
if (active && payload && payload.length) {
|
||||
const timestamp = new Date(
|
||||
Date.now() + payload[0].payload.minute * 60000
|
||||
);
|
||||
return (
|
||||
<Card className="p-2 shadow-lg bg-sky-800 border-none">
|
||||
<CardContent className="p-0 space-y-1">
|
||||
<p className="font-medium text-sm text-sky-100 border-b border-sky-700 pb-1 mb-1">
|
||||
{format(timestamp, "h:mm a")}
|
||||
</p>
|
||||
<div className="flex justify-between items-center text-sm">
|
||||
<span className="text-sky-200">
|
||||
Active Users:
|
||||
</span>
|
||||
<span className="font-medium ml-4 text-sky-100">
|
||||
{payload[0].value.toLocaleString()}
|
||||
</span>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}}
|
||||
/>
|
||||
<Bar dataKey="users" fill="#0EA5E9" />
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
<Card className="bg-gradient-to-br from-sky-900 to-sky-800 backdrop-blur-sm">
|
||||
<CardContent className="p-4">
|
||||
<div className="h-[200px]">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart
|
||||
data={basicData.byMinute}
|
||||
margin={{ top: 5, right: 5, left: -35, bottom: -10 }}
|
||||
>
|
||||
<XAxis
|
||||
dataKey="minute"
|
||||
tickFormatter={(value) => value + "m"}
|
||||
className="text-xs"
|
||||
tick={{ fill: "#BAE6FD" }}
|
||||
/>
|
||||
<YAxis
|
||||
className="text-xs"
|
||||
tick={{ fill: "#BAE6FD" }}
|
||||
/>
|
||||
<Tooltip
|
||||
content={({ active, payload }) => {
|
||||
if (active && payload && payload.length) {
|
||||
const timestamp = new Date(payload[0].payload.timestamp);
|
||||
return (
|
||||
<Card className="p-2 shadow-lg bg-sky-800 border-none">
|
||||
<CardContent className="p-0 space-y-1">
|
||||
<p className="font-medium text-sm text-sky-100 border-b border-sky-700 pb-1 mb-1">
|
||||
{format(timestamp, "h:mm a")}
|
||||
</p>
|
||||
<div className="flex justify-between items-center text-sm">
|
||||
<span className="text-sky-200">
|
||||
Active Users:
|
||||
</span>
|
||||
<span className="font-medium ml-4 text-sky-100">
|
||||
{payload[0].value}
|
||||
</span>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}}
|
||||
/>
|
||||
<Bar dataKey="users" fill="#0EA5E9" />
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -72,7 +72,7 @@ const MiniStatCard = memo(({
|
||||
active = true
|
||||
}) => (
|
||||
<Card
|
||||
className={`w-full ${background || 'bg-gradient-to-br from-gray-800 to-gray-900 backdrop-blur-md'} ${
|
||||
className={`w-full ${background || 'bg-gradient-to-br from-gray-900 to-gray-800 backdrop-blur-md'} ${
|
||||
onClick ? 'cursor-pointer transition-all hover:brightness-110' : ''
|
||||
} ${!active ? 'opacity-50' : ''}`}
|
||||
onClick={onClick}
|
||||
@@ -243,7 +243,7 @@ const MiniSalesChart = ({ className = "" }) => {
|
||||
icon={PiggyBank}
|
||||
iconColor="text-emerald-900"
|
||||
iconBackground="bg-emerald-300"
|
||||
background="bg-gradient-to-br from-emerald-900 to-emerald-800"
|
||||
background="h-[150px] bg-gradient-to-br from-emerald-900 to-emerald-800"
|
||||
onClick={() => toggleMetric('revenue')}
|
||||
active={visibleMetrics.revenue}
|
||||
/>
|
||||
@@ -257,7 +257,7 @@ const MiniSalesChart = ({ className = "" }) => {
|
||||
icon={Truck}
|
||||
iconColor="text-blue-900"
|
||||
iconBackground="bg-blue-300"
|
||||
background="bg-gradient-to-br from-blue-900 to-blue-800"
|
||||
background="h-[150px] bg-gradient-to-br from-blue-900 to-blue-800"
|
||||
onClick={() => toggleMetric('orders')}
|
||||
active={visibleMetrics.orders}
|
||||
/>
|
||||
@@ -305,7 +305,6 @@ const MiniSalesChart = ({ className = "" }) => {
|
||||
<YAxis
|
||||
yAxisId="orders"
|
||||
orientation="right"
|
||||
tickFormatter={(value) => value.toLocaleString()}
|
||||
className="text-[10px]"
|
||||
tick={{ fill: "#E9D5FF" }}
|
||||
/>
|
||||
|
||||
@@ -410,7 +410,7 @@ const MiniStatCards = ({
|
||||
onDetailsClick={() => setSelectedMetric("revenue")}
|
||||
isLoading={loading || !stats}
|
||||
variant="mini"
|
||||
background="bg-gradient-to-br from-emerald-900 to-emerald-800"
|
||||
background="h-[150px] bg-gradient-to-br from-emerald-900 to-emerald-800"
|
||||
/>
|
||||
|
||||
<StatCard
|
||||
|
||||
@@ -50,8 +50,8 @@ export const METRIC_COLORS = {
|
||||
export const summaryCard = (label, sublabel, value, options = {}) => {
|
||||
const {
|
||||
colorClass = "text-gray-900 dark:text-gray-100",
|
||||
titleClass = "text-sm font-medium text-gray-600 dark:text-gray-300",
|
||||
descriptionClass = "text-sm text-muted-foreground",
|
||||
titleClass = "text-sm font-medium text-gray-500 dark:text-gray-400",
|
||||
descriptionClass = "text-sm text-gray-600 dark:text-gray-300",
|
||||
background = "bg-white dark:bg-gray-900/60",
|
||||
icon: Icon,
|
||||
iconColor,
|
||||
@@ -59,9 +59,11 @@ export const summaryCard = (label, sublabel, value, options = {}) => {
|
||||
} = options;
|
||||
|
||||
return (
|
||||
<Card className={`${background} backdrop-blur-sm`}>
|
||||
<Card className={`w-full ${background} backdrop-blur-sm`}>
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 px-4 py-2">
|
||||
<span className={titleClass}>{label}</span>
|
||||
<CardTitle className={titleClass}>
|
||||
{label}
|
||||
</CardTitle>
|
||||
{Icon && (
|
||||
<div className="relative p-2">
|
||||
<div className={`absolute inset-0 rounded-full ${iconBackground}`} />
|
||||
@@ -70,10 +72,16 @@ export const summaryCard = (label, sublabel, value, options = {}) => {
|
||||
)}
|
||||
</CardHeader>
|
||||
<CardContent className="px-4 pt-0 pb-2">
|
||||
<div className={`text-2xl font-bold mb-1 ${colorClass}`}>
|
||||
{value.toLocaleString()}
|
||||
<div className="space-y-2">
|
||||
<div>
|
||||
<div className={`text-3xl font-extrabold ${colorClass}`}>
|
||||
{value.toLocaleString()}
|
||||
</div>
|
||||
<div className={descriptionClass}>
|
||||
{sublabel}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={descriptionClass}>{sublabel}</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user