fix(analytics): stabilize responsive row alignment

This commit is contained in:
Tam Nhu Tran
2026-02-13 06:28:46 +07:00
parent 43d441ce23
commit 0cc1f111f7
10 changed files with 40 additions and 27 deletions
@@ -32,7 +32,7 @@ export function CliproxyStatsCard({
if (isLoading) {
return (
<Card className={cn('flex flex-col h-full', className)}>
<Card className={cn('flex flex-col h-full min-h-0 overflow-hidden gap-0 py-0', className)}>
<CardHeader className="px-3 py-2">
<CardTitle className="text-base font-semibold flex items-center gap-2">
<Server className="h-4 w-4" />
@@ -52,7 +52,12 @@ export function CliproxyStatsCard({
// Proxy not running
if (!status?.running) {
return (
<Card className={cn('flex flex-col h-full border-dashed', className)}>
<Card
className={cn(
'flex flex-col h-full min-h-0 overflow-hidden gap-0 py-0 border-dashed',
className
)}
>
<CardHeader className="px-3 py-2">
<div className="flex items-center justify-between">
<CardTitle className="text-base font-semibold flex items-center gap-2">
@@ -76,7 +81,12 @@ export function CliproxyStatsCard({
// Error fetching stats
if (error) {
return (
<Card className={cn('flex flex-col h-full border-destructive/50', className)}>
<Card
className={cn(
'flex flex-col h-full min-h-0 overflow-hidden gap-0 py-0 border-destructive/50',
className
)}
>
<CardHeader className="px-3 py-2">
<div className="flex items-center justify-between">
<CardTitle className="text-base font-semibold flex items-center gap-2">
@@ -110,7 +120,7 @@ export function CliproxyStatsCard({
const maxModelRequests = models.length > 0 ? models[0][1] : 1;
return (
<Card className={cn('flex flex-col h-full overflow-hidden', className)}>
<Card className={cn('flex flex-col h-full min-h-0 overflow-hidden gap-0 py-0', className)}>
<CardHeader className="px-3 py-2 border-b bg-muted/5">
<div className="flex items-center justify-between">
<CardTitle className="text-base font-semibold flex items-center gap-2">
@@ -70,7 +70,7 @@ export function DateRangeFilter({
};
return (
<div className={cn('flex items-center gap-2', className)}>
<div className={cn('flex flex-wrap items-center gap-2', className)}>
{presets.map((preset) => (
<Button
key={preset.label}
@@ -87,7 +87,7 @@ export function DateRangeFilter({
id="date"
variant={'outline'}
className={cn(
'w-auto min-w-[240px] justify-start text-left font-normal',
'w-auto min-w-[200px] sm:min-w-[240px] justify-start text-left font-normal',
!value && 'text-muted-foreground'
)}
>
@@ -34,12 +34,12 @@ export function ModelBreakdownChart({ data, isLoading, className }: ModelBreakdo
}, [data]);
if (isLoading) {
return <Skeleton className={cn('h-[300px] w-full', className)} />;
return <Skeleton className={cn('h-full min-h-[100px] w-full', className)} />;
}
if (!data || data.length === 0) {
return (
<div className={cn('h-[300px] flex items-center justify-center', className)}>
<div className={cn('h-full min-h-[100px] flex items-center justify-center', className)}>
<p className="text-muted-foreground">No model data available</p>
</div>
);
@@ -72,8 +72,8 @@ export function ModelBreakdownChart({ data, isLoading, className }: ModelBreakdo
};
return (
<div className={cn('w-full', className)}>
<ResponsiveContainer width="100%" height={250}>
<div className={cn('w-full h-full min-h-[100px]', className)}>
<ResponsiveContainer width="100%" height="100%">
<PieChart>
<Pie
data={chartData}
@@ -55,7 +55,7 @@ export function SessionStatsCard({ data, isLoading, className }: SessionStatsCar
if (isLoading) {
return (
<Card className={cn('flex flex-col h-full', className)}>
<Card className={cn('flex flex-col h-full min-h-0 overflow-hidden gap-0 py-0', className)}>
<CardHeader className="px-3 py-2">
<Skeleton className="h-5 w-32" />
</CardHeader>
@@ -68,7 +68,7 @@ export function SessionStatsCard({ data, isLoading, className }: SessionStatsCar
if (!stats) {
return (
<Card className={cn('flex flex-col h-full', className)}>
<Card className={cn('flex flex-col h-full min-h-0 overflow-hidden gap-0 py-0', className)}>
<CardHeader className="px-3 py-2">
<CardTitle className="text-base font-semibold flex items-center gap-2">
<Terminal className="w-4 h-4" />
@@ -83,14 +83,16 @@ export function SessionStatsCard({ data, isLoading, className }: SessionStatsCar
}
return (
<Card className={cn('flex flex-col h-full shadow-sm', className)}>
<Card
className={cn('flex flex-col h-full min-h-0 overflow-hidden gap-0 py-0 shadow-sm', className)}
>
<CardHeader className="px-3 py-2">
<CardTitle className="text-base font-semibold flex items-center gap-2">
<Terminal className="w-4 h-4" />
Session Stats
</CardTitle>
</CardHeader>
<CardContent className="px-3 pb-3 pt-0 flex-1 flex flex-col gap-4">
<CardContent className="px-3 pb-3 pt-0 flex-1 min-h-0 flex flex-col gap-3">
{/* Key Metrics Grid */}
<div className="grid grid-cols-2 gap-2">
{/* Total Sessions */}
@@ -119,12 +121,12 @@ export function SessionStatsCard({ data, isLoading, className }: SessionStatsCar
</div>
{/* Recent Activity List */}
<div className="flex-1 space-y-2">
<div className="flex-1 min-h-0 space-y-2">
<div className="flex items-center gap-1 text-xs text-muted-foreground font-medium mb-1">
<Clock className="w-3 h-3" />
Recent Activity
</div>
<div className="space-y-1.5">
<div className="space-y-1.5 max-h-full overflow-y-auto pr-1">
{stats.recentSessions.map((session) => (
<div
key={session.sessionId}
@@ -23,7 +23,7 @@ export function UsageSummaryCards({ data, isLoading }: UsageSummaryCardsProps) {
if (isLoading) {
return (
<div className="grid grid-cols-2 md:grid-cols-3 xl:grid-cols-5 gap-4">
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-4">
{[1, 2, 3, 4, 5].map((i) => (
<Card key={i}>
<CardContent className="p-6">
@@ -95,7 +95,7 @@ export function UsageSummaryCards({ data, isLoading }: UsageSummaryCardsProps) {
];
return (
<div className="grid grid-cols-2 md:grid-cols-3 xl:grid-cols-5 gap-4">
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-4">
{cards.map((card, index) => {
const Icon = card.icon;
return (
+1 -1
View File
@@ -109,7 +109,7 @@ function SidebarProvider({
} as React.CSSProperties
}
className={cn(
'group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full',
'group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex h-svh min-h-0 w-full overflow-hidden',
className
)}
{...props}
@@ -30,12 +30,12 @@ export function AnalyticsHeader({
viewMode,
}: AnalyticsHeaderProps) {
return (
<div className="flex items-center justify-between shrink-0">
<div className="flex flex-col gap-3 shrink-0 xl:flex-row xl:items-center xl:justify-between">
<div>
<h1 className="text-xl font-semibold">Analytics</h1>
<p className="text-sm text-muted-foreground">Track usage & insights</p>
</div>
<div className="flex items-center gap-2">
<div className="flex flex-wrap items-center gap-2 xl:justify-end">
<Button
variant={viewMode === 'hourly' ? 'default' : 'outline'}
size="sm"
@@ -45,6 +45,7 @@ export function AnalyticsHeader({
24H
</Button>
<DateRangeFilter
className="flex-wrap"
value={dateRange}
onChange={onDateRangeChange}
presets={[
@@ -44,9 +44,9 @@ export function ChartsGrid({
const { privacyMode } = usePrivacy();
return (
<div className="flex-1 flex flex-col min-h-0 gap-4">
<div className="min-h-0 grid gap-4 lg:grid-rows-[minmax(260px,1.2fr)_minmax(220px,0.9fr)]">
{/* Usage Trend Chart - Full Width */}
<Card className="flex flex-col flex-1 min-h-0 max-h-[500px] overflow-hidden shadow-sm">
<Card className="flex flex-col h-full min-h-[220px] lg:min-h-[240px] overflow-hidden gap-0 py-0 shadow-sm">
<CardHeader className="px-3 py-2 shrink-0">
<CardTitle className="text-base font-semibold flex items-center gap-2">
<TrendingUp className="w-4 h-4" />
@@ -63,7 +63,7 @@ export function ChartsGrid({
</Card>
{/* Bottom Row */}
<div className="grid grid-cols-1 lg:grid-cols-10 gap-4 h-auto lg:h-[180px] shrink-0">
<div className="grid grid-cols-1 lg:grid-cols-10 gap-4 h-auto min-h-[220px] lg:h-full lg:min-h-[220px] lg:grid-rows-[minmax(0,1fr)] lg:[&>*]:min-h-0">
{/* Cost by Model */}
<CostByModelCard
models={models}
@@ -73,7 +73,7 @@ export function ChartsGrid({
/>
{/* Model Distribution */}
<Card className="flex flex-col h-full min-h-0 shadow-sm lg:col-span-2">
<Card className="flex flex-col h-full min-h-0 overflow-hidden gap-0 py-0 shadow-sm lg:col-span-2">
<CardHeader className="px-3 py-2">
<CardTitle className="text-base font-semibold flex items-center gap-2">
<PieChart className="w-4 h-4" />
@@ -26,7 +26,7 @@ export function CostByModelCard({
privacyMode,
}: CostByModelCardProps) {
return (
<Card className="flex flex-col h-full min-h-0 shadow-sm lg:col-span-4">
<Card className="flex flex-col h-full min-h-0 overflow-hidden gap-0 py-0 shadow-sm lg:col-span-4">
<CardHeader className="px-3 py-2">
<CardTitle className="text-base font-semibold flex items-center gap-2">
<DollarSign className="w-4 h-4" />
+1 -1
View File
@@ -40,7 +40,7 @@ export function AnalyticsPage() {
} = useAnalyticsPage();
return (
<div className="flex flex-col h-full overflow-hidden px-4 pt-4 pb-50 gap-4">
<div className="grid h-full min-h-0 grid-rows-[auto_auto_minmax(0,1fr)] gap-4 overflow-y-auto px-4 py-4">
{/* Header */}
<AnalyticsHeader
dateRange={dateRange}