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