feat: enhance responsive design and layout consistency across various components, including dashboard, statistics, and rules pages
This commit is contained in:
@@ -57,24 +57,25 @@ export function CategoryPieChart({
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle>{title}</CardTitle>
|
||||
<div className="flex gap-2">
|
||||
<CardHeader className="flex flex-col md:flex-row md:items-center md:justify-between space-y-2 md:space-y-0 pb-2">
|
||||
<CardTitle className="text-sm md:text-base">{title}</CardTitle>
|
||||
<div className="flex flex-col md:flex-row gap-2 w-full md:w-auto">
|
||||
{hasParentData && (
|
||||
<Button
|
||||
variant={groupByParent ? "default" : "ghost"}
|
||||
size="sm"
|
||||
onClick={() => setGroupByParent(!groupByParent)}
|
||||
title={groupByParent ? "Afficher toutes les catégories" : "Regrouper par catégories parentes"}
|
||||
className="w-full md:w-auto text-xs md:text-sm"
|
||||
>
|
||||
{groupByParent ? (
|
||||
<>
|
||||
<List className="w-4 h-4 mr-1" />
|
||||
<List className="w-3 h-3 md:w-4 md:h-4 mr-1" />
|
||||
Par catégorie
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Layers className="w-4 h-4 mr-1" />
|
||||
<Layers className="w-3 h-3 md:w-4 md:h-4 mr-1" />
|
||||
Par parent
|
||||
</>
|
||||
)}
|
||||
@@ -85,15 +86,16 @@ export function CategoryPieChart({
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => setIsExpanded(!isExpanded)}
|
||||
className="w-full md:w-auto text-xs md:text-sm"
|
||||
>
|
||||
{isExpanded ? (
|
||||
<>
|
||||
<ChevronUp className="w-4 h-4 mr-1" />
|
||||
<ChevronUp className="w-3 h-3 md:w-4 md:h-4 mr-1" />
|
||||
Réduire
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<ChevronDown className="w-4 h-4 mr-1" />
|
||||
<ChevronDown className="w-3 h-3 md:w-4 md:h-4 mr-1" />
|
||||
Voir tout ({baseData.length})
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -20,16 +20,16 @@ export function StatsSummaryCards({
|
||||
const savings = totalIncome - totalExpenses;
|
||||
|
||||
return (
|
||||
<div className="grid gap-4 md:grid-cols-4">
|
||||
<div className="grid gap-3 md:gap-4 grid-cols-2 md:grid-cols-4">
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm font-medium text-muted-foreground flex items-center gap-2">
|
||||
<TrendingUp className="w-4 h-4 text-emerald-600" />
|
||||
<CardTitle className="text-xs md:text-sm font-medium text-muted-foreground flex items-center gap-1.5 md:gap-2">
|
||||
<TrendingUp className="w-3 h-3 md:w-4 md:h-4 text-emerald-600" />
|
||||
Total Revenus
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-emerald-600">
|
||||
<div className="text-lg md:text-2xl font-bold text-emerald-600">
|
||||
{formatCurrency(totalIncome)}
|
||||
</div>
|
||||
</CardContent>
|
||||
@@ -37,13 +37,13 @@ export function StatsSummaryCards({
|
||||
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm font-medium text-muted-foreground flex items-center gap-2">
|
||||
<TrendingDown className="w-4 h-4 text-red-600" />
|
||||
<CardTitle className="text-xs md:text-sm font-medium text-muted-foreground flex items-center gap-1.5 md:gap-2">
|
||||
<TrendingDown className="w-3 h-3 md:w-4 md:h-4 text-red-600" />
|
||||
Total Dépenses
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-red-600">
|
||||
<div className="text-lg md:text-2xl font-bold text-red-600">
|
||||
{formatCurrency(totalExpenses)}
|
||||
</div>
|
||||
</CardContent>
|
||||
@@ -51,13 +51,13 @@ export function StatsSummaryCards({
|
||||
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm font-medium text-muted-foreground flex items-center gap-2">
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
<CardTitle className="text-xs md:text-sm font-medium text-muted-foreground flex items-center gap-1.5 md:gap-2">
|
||||
<ArrowRight className="w-3 h-3 md:w-4 md:h-4" />
|
||||
Moyenne mensuelle
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold">
|
||||
<div className="text-lg md:text-2xl font-bold">
|
||||
{formatCurrency(avgMonthlyExpenses)}
|
||||
</div>
|
||||
</CardContent>
|
||||
@@ -65,14 +65,14 @@ export function StatsSummaryCards({
|
||||
|
||||
<Card>
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-sm font-medium text-muted-foreground">
|
||||
<CardTitle className="text-xs md:text-sm font-medium text-muted-foreground">
|
||||
Économies
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div
|
||||
className={cn(
|
||||
"text-2xl font-bold",
|
||||
"text-lg md:text-2xl font-bold",
|
||||
savings >= 0 ? "text-emerald-600" : "text-red-600"
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { CategoryIcon } from "@/components/ui/category-icon";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { useIsMobile } from "@/hooks/use-mobile";
|
||||
import type { Transaction, Category } from "@/lib/types";
|
||||
|
||||
interface TopExpensesListProps {
|
||||
@@ -15,58 +17,66 @@ export function TopExpensesList({
|
||||
categories,
|
||||
formatCurrency,
|
||||
}: TopExpensesListProps) {
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Top 5 dépenses</CardTitle>
|
||||
<CardTitle className="text-sm md:text-base">Top 5 dépenses</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{expenses.length > 0 ? (
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-3 md:space-y-4">
|
||||
{expenses.map((expense, index) => {
|
||||
const category = categories.find(
|
||||
(c) => c.id === expense.categoryId
|
||||
);
|
||||
return (
|
||||
<div key={expense.id} className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 rounded-full bg-muted flex items-center justify-center text-sm font-semibold">
|
||||
<div key={expense.id} className="flex items-start gap-2 md:gap-3">
|
||||
<div className="w-6 h-6 md:w-8 md:h-8 rounded-full bg-muted flex items-center justify-center text-xs md:text-sm font-semibold shrink-0">
|
||||
{index + 1}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="font-medium text-sm truncate">
|
||||
{expense.description}
|
||||
</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs text-muted-foreground">
|
||||
<div className="flex items-start justify-between gap-2 mb-1">
|
||||
<p className="font-medium text-xs md:text-sm truncate flex-1">
|
||||
{expense.description}
|
||||
</p>
|
||||
<div className="text-red-600 font-semibold tabular-nums text-xs md:text-sm shrink-0">
|
||||
{formatCurrency(expense.amount)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5 md:gap-2 flex-wrap">
|
||||
<span className="text-[10px] md:text-xs text-muted-foreground">
|
||||
{new Date(expense.date).toLocaleDateString("fr-FR")}
|
||||
</span>
|
||||
{category && (
|
||||
<span
|
||||
className="text-xs px-1.5 py-0.5 rounded inline-flex items-center gap-1"
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="text-[10px] md:text-xs px-1.5 md:px-2 py-0.5 inline-flex items-center gap-1 shrink-0"
|
||||
style={{
|
||||
backgroundColor: `${category.color}20`,
|
||||
color: category.color,
|
||||
borderColor: `${category.color}30`,
|
||||
}}
|
||||
>
|
||||
<CategoryIcon
|
||||
icon={category.icon}
|
||||
color={category.color}
|
||||
size={10}
|
||||
size={isMobile ? 8 : 10}
|
||||
/>
|
||||
{category.name}
|
||||
</span>
|
||||
<span className="truncate max-w-[120px] md:max-w-none">
|
||||
{category.name}
|
||||
</span>
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-red-600 font-semibold tabular-nums">
|
||||
{formatCurrency(expense.amount)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
<div className="h-[200px] flex items-center justify-center text-muted-foreground">
|
||||
<div className="h-[200px] flex items-center justify-center text-muted-foreground text-xs md:text-sm">
|
||||
Pas de dépenses pour cette période
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user