Compare commits
2 Commits
82e27524b5
...
c4707e5511
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4707e5511 | ||
|
|
2887a6a750 |
281
app/globals.css
281
app/globals.css
@@ -459,21 +459,50 @@
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fintech card styles avec glassmorphism très prononcé */
|
/* Fintech card styles avec design moderne et élégant */
|
||||||
.fintech-card {
|
.fintech-card {
|
||||||
background: var(--card);
|
background: var(--card);
|
||||||
backdrop-filter: blur(50px) saturate(200%);
|
backdrop-filter: blur(40px) saturate(180%);
|
||||||
-webkit-backdrop-filter: blur(50px) saturate(200%);
|
-webkit-backdrop-filter: blur(40px) saturate(180%);
|
||||||
border: 1px solid var(--border);
|
border: 1px solid color-mix(in srgb, var(--border) 60%, transparent);
|
||||||
border-radius: var(--radius);
|
border-radius: calc(var(--radius) + 0.25rem);
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 8px 32px -8px color-mix(in srgb, var(--primary) 8%, transparent),
|
0 1px 3px 0 color-mix(in srgb, var(--foreground) 4%, transparent),
|
||||||
0 2px 8px -2px color-mix(in srgb, var(--foreground) 3%, transparent),
|
0 4px 12px -2px color-mix(in srgb, var(--primary) 6%, transparent),
|
||||||
inset 0 1px 0 0 color-mix(in srgb, white 25%, transparent);
|
0 8px 24px -4px color-mix(in srgb, var(--foreground) 2%, transparent),
|
||||||
|
inset 0 1px 0 0 color-mix(in srgb, white 30%, transparent);
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Texture subtile avec grain/noise */
|
||||||
|
.fintech-card::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background-image:
|
||||||
|
radial-gradient(circle at 1px 1px, color-mix(in srgb, var(--foreground) 2%, transparent) 1px, transparent 0);
|
||||||
|
background-size: 20px 20px;
|
||||||
|
opacity: 0.15;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .fintech-card::before {
|
||||||
|
background-image:
|
||||||
|
radial-gradient(circle at 1px 1px, color-mix(in srgb, white 3%, transparent) 1px, transparent 0);
|
||||||
|
opacity: 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .fintech-card {
|
||||||
|
border-color: color-mix(in srgb, var(--border) 40%, transparent);
|
||||||
|
box-shadow:
|
||||||
|
0 1px 3px 0 color-mix(in srgb, var(--foreground) 8%, transparent),
|
||||||
|
0 4px 12px -2px color-mix(in srgb, var(--primary) 8%, transparent),
|
||||||
|
0 8px 24px -4px color-mix(in srgb, black 40%, transparent),
|
||||||
|
inset 0 1px 0 0 color-mix(in srgb, white 8%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
.fintech-card::after {
|
.fintech-card::after {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -484,140 +513,220 @@
|
|||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
90deg,
|
90deg,
|
||||||
transparent 0%,
|
transparent 0%,
|
||||||
color-mix(in srgb, white 40%, transparent) 50%,
|
color-mix(in srgb, white 50%, transparent) 50%,
|
||||||
transparent 100%
|
transparent 100%
|
||||||
);
|
);
|
||||||
opacity: 0.5;
|
opacity: 0.6;
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Gradient backgrounds for stat cards très vibrants */
|
.dark .fintech-card::after {
|
||||||
|
opacity: 0.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Gradient backgrounds for stat cards - design moderne et subtil */
|
||||||
.stat-card-gradient-1 {
|
.stat-card-gradient-1 {
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
color-mix(in srgb, var(--primary) 8%, var(--card)) 0%,
|
||||||
|
color-mix(in srgb, var(--primary-light) 5%, var(--card)) 50%,
|
||||||
|
color-mix(in srgb, var(--primary) 4%, var(--card)) 100%
|
||||||
|
);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
border-color: color-mix(in srgb, var(--primary) 20%, var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card-gradient-1::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: -30%;
|
||||||
|
right: -20%;
|
||||||
|
width: 150%;
|
||||||
|
height: 150%;
|
||||||
|
background: radial-gradient(
|
||||||
|
circle,
|
||||||
|
color-mix(in srgb, var(--primary) 15%, transparent) 0%,
|
||||||
|
transparent 60%
|
||||||
|
);
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .stat-card-gradient-1 {
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
135deg,
|
135deg,
|
||||||
color-mix(in srgb, var(--primary) 12%, var(--card)) 0%,
|
color-mix(in srgb, var(--primary) 12%, var(--card)) 0%,
|
||||||
color-mix(in srgb, var(--primary-light) 8%, var(--card)) 50%,
|
color-mix(in srgb, var(--primary-light) 8%, var(--card)) 50%,
|
||||||
color-mix(in srgb, var(--primary) 6%, var(--card)) 100%
|
color-mix(in srgb, var(--primary) 6%, var(--card)) 100%
|
||||||
);
|
);
|
||||||
position: relative;
|
border-color: color-mix(in srgb, var(--primary) 30%, var(--border));
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card-gradient-1::before {
|
.dark .stat-card-gradient-1::before {
|
||||||
content: "";
|
opacity: 0.25;
|
||||||
position: absolute;
|
|
||||||
top: -50%;
|
|
||||||
right: -50%;
|
|
||||||
width: 200%;
|
|
||||||
height: 200%;
|
|
||||||
background: radial-gradient(
|
|
||||||
circle,
|
|
||||||
color-mix(in srgb, var(--primary) 20%, transparent) 0%,
|
|
||||||
transparent 70%
|
|
||||||
);
|
|
||||||
opacity: 0.3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card-gradient-2 {
|
.stat-card-gradient-2 {
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
color-mix(in srgb, var(--success) 8%, var(--card)) 0%,
|
||||||
|
color-mix(in srgb, var(--success) 5%, var(--card)) 50%,
|
||||||
|
color-mix(in srgb, var(--success) 4%, var(--card)) 100%
|
||||||
|
);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
border-color: color-mix(in srgb, var(--success) 20%, var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card-gradient-2::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: -30%;
|
||||||
|
right: -20%;
|
||||||
|
width: 150%;
|
||||||
|
height: 150%;
|
||||||
|
background: radial-gradient(
|
||||||
|
circle,
|
||||||
|
color-mix(in srgb, var(--success) 15%, transparent) 0%,
|
||||||
|
transparent 60%
|
||||||
|
);
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .stat-card-gradient-2 {
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
135deg,
|
135deg,
|
||||||
color-mix(in srgb, var(--success) 12%, var(--card)) 0%,
|
color-mix(in srgb, var(--success) 12%, var(--card)) 0%,
|
||||||
color-mix(in srgb, var(--success) 8%, var(--card)) 50%,
|
color-mix(in srgb, var(--success) 8%, var(--card)) 50%,
|
||||||
color-mix(in srgb, var(--success) 6%, var(--card)) 100%
|
color-mix(in srgb, var(--success) 6%, var(--card)) 100%
|
||||||
);
|
);
|
||||||
position: relative;
|
border-color: color-mix(in srgb, var(--success) 30%, var(--border));
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card-gradient-2::before {
|
.dark .stat-card-gradient-2::before {
|
||||||
content: "";
|
opacity: 0.25;
|
||||||
position: absolute;
|
|
||||||
top: -50%;
|
|
||||||
right: -50%;
|
|
||||||
width: 200%;
|
|
||||||
height: 200%;
|
|
||||||
background: radial-gradient(
|
|
||||||
circle,
|
|
||||||
color-mix(in srgb, var(--success) 20%, transparent) 0%,
|
|
||||||
transparent 70%
|
|
||||||
);
|
|
||||||
opacity: 0.3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card-gradient-3 {
|
.stat-card-gradient-3 {
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
color-mix(in srgb, var(--destructive) 8%, var(--card)) 0%,
|
||||||
|
color-mix(in srgb, var(--destructive) 5%, var(--card)) 50%,
|
||||||
|
color-mix(in srgb, var(--destructive) 4%, var(--card)) 100%
|
||||||
|
);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
border-color: color-mix(in srgb, var(--destructive) 20%, var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card-gradient-3::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: -30%;
|
||||||
|
right: -20%;
|
||||||
|
width: 150%;
|
||||||
|
height: 150%;
|
||||||
|
background: radial-gradient(
|
||||||
|
circle,
|
||||||
|
color-mix(in srgb, var(--destructive) 15%, transparent) 0%,
|
||||||
|
transparent 60%
|
||||||
|
);
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .stat-card-gradient-3 {
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
135deg,
|
135deg,
|
||||||
color-mix(in srgb, var(--destructive) 12%, var(--card)) 0%,
|
color-mix(in srgb, var(--destructive) 12%, var(--card)) 0%,
|
||||||
color-mix(in srgb, var(--destructive) 8%, var(--card)) 50%,
|
color-mix(in srgb, var(--destructive) 8%, var(--card)) 50%,
|
||||||
color-mix(in srgb, var(--destructive) 6%, var(--card)) 100%
|
color-mix(in srgb, var(--destructive) 6%, var(--card)) 100%
|
||||||
);
|
);
|
||||||
position: relative;
|
border-color: color-mix(in srgb, var(--destructive) 30%, var(--border));
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card-gradient-3::before {
|
.dark .stat-card-gradient-3::before {
|
||||||
content: "";
|
opacity: 0.25;
|
||||||
position: absolute;
|
|
||||||
top: -50%;
|
|
||||||
right: -50%;
|
|
||||||
width: 200%;
|
|
||||||
height: 200%;
|
|
||||||
background: radial-gradient(
|
|
||||||
circle,
|
|
||||||
color-mix(in srgb, var(--destructive) 20%, transparent) 0%,
|
|
||||||
transparent 70%
|
|
||||||
);
|
|
||||||
opacity: 0.3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card-gradient-4 {
|
.stat-card-gradient-4 {
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
color-mix(in srgb, var(--chart-4) 8%, var(--card)) 0%,
|
||||||
|
color-mix(in srgb, var(--chart-4) 5%, var(--card)) 50%,
|
||||||
|
color-mix(in srgb, var(--chart-4) 4%, var(--card)) 100%
|
||||||
|
);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
border-color: color-mix(in srgb, var(--chart-4) 20%, var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card-gradient-4::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: -30%;
|
||||||
|
right: -20%;
|
||||||
|
width: 150%;
|
||||||
|
height: 150%;
|
||||||
|
background: radial-gradient(
|
||||||
|
circle,
|
||||||
|
color-mix(in srgb, var(--chart-4) 15%, transparent) 0%,
|
||||||
|
transparent 60%
|
||||||
|
);
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .stat-card-gradient-4 {
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
135deg,
|
135deg,
|
||||||
color-mix(in srgb, var(--chart-4) 12%, var(--card)) 0%,
|
color-mix(in srgb, var(--chart-4) 12%, var(--card)) 0%,
|
||||||
color-mix(in srgb, var(--chart-4) 8%, var(--card)) 50%,
|
color-mix(in srgb, var(--chart-4) 8%, var(--card)) 50%,
|
||||||
color-mix(in srgb, var(--chart-4) 6%, var(--card)) 100%
|
color-mix(in srgb, var(--chart-4) 6%, var(--card)) 100%
|
||||||
);
|
);
|
||||||
position: relative;
|
border-color: color-mix(in srgb, var(--chart-4) 30%, var(--border));
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card-gradient-4::before {
|
.dark .stat-card-gradient-4::before {
|
||||||
content: "";
|
opacity: 0.25;
|
||||||
position: absolute;
|
|
||||||
top: -50%;
|
|
||||||
right: -50%;
|
|
||||||
width: 200%;
|
|
||||||
height: 200%;
|
|
||||||
background: radial-gradient(
|
|
||||||
circle,
|
|
||||||
color-mix(in srgb, var(--chart-4) 20%, transparent) 0%,
|
|
||||||
transparent 70%
|
|
||||||
);
|
|
||||||
opacity: 0.3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card-gradient-5 {
|
.stat-card-gradient-5 {
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
color-mix(in srgb, var(--chart-5) 8%, var(--card)) 0%,
|
||||||
|
color-mix(in srgb, var(--chart-5) 5%, var(--card)) 50%,
|
||||||
|
color-mix(in srgb, var(--chart-5) 4%, var(--card)) 100%
|
||||||
|
);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
border-color: color-mix(in srgb, var(--chart-5) 20%, var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card-gradient-5::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: -30%;
|
||||||
|
right: -20%;
|
||||||
|
width: 150%;
|
||||||
|
height: 150%;
|
||||||
|
background: radial-gradient(
|
||||||
|
circle,
|
||||||
|
color-mix(in srgb, var(--chart-5) 15%, transparent) 0%,
|
||||||
|
transparent 60%
|
||||||
|
);
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .stat-card-gradient-5 {
|
||||||
background: linear-gradient(
|
background: linear-gradient(
|
||||||
135deg,
|
135deg,
|
||||||
color-mix(in srgb, var(--chart-5) 12%, var(--card)) 0%,
|
color-mix(in srgb, var(--chart-5) 12%, var(--card)) 0%,
|
||||||
color-mix(in srgb, var(--chart-5) 8%, var(--card)) 50%,
|
color-mix(in srgb, var(--chart-5) 8%, var(--card)) 50%,
|
||||||
color-mix(in srgb, var(--chart-5) 6%, var(--card)) 100%
|
color-mix(in srgb, var(--chart-5) 6%, var(--card)) 100%
|
||||||
);
|
);
|
||||||
position: relative;
|
border-color: color-mix(in srgb, var(--chart-5) 30%, var(--border));
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-card-gradient-5::before {
|
.dark .stat-card-gradient-5::before {
|
||||||
content: "";
|
opacity: 0.25;
|
||||||
position: absolute;
|
|
||||||
top: -50%;
|
|
||||||
right: -50%;
|
|
||||||
width: 200%;
|
|
||||||
height: 200%;
|
|
||||||
background: radial-gradient(
|
|
||||||
circle,
|
|
||||||
color-mix(in srgb, var(--chart-5) 20%, transparent) 0%,
|
|
||||||
transparent 70%
|
|
||||||
);
|
|
||||||
opacity: 0.3;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,18 +59,19 @@ export function OverviewCards({ data }: OverviewCardsProps) {
|
|||||||
return (
|
return (
|
||||||
<div className="grid gap-4 sm:gap-6 grid-cols-1 sm:grid-cols-2 lg:grid-cols-5">
|
<div className="grid gap-4 sm:gap-6 grid-cols-1 sm:grid-cols-2 lg:grid-cols-5">
|
||||||
<Card className="stat-card-gradient-1 card-hover group relative overflow-hidden">
|
<Card className="stat-card-gradient-1 card-hover group relative overflow-hidden">
|
||||||
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-4 px-6 pt-6 sm:px-7 sm:pt-7 lg:px-5 lg:pt-5 relative z-10">
|
{/* Icône en arrière-plan */}
|
||||||
<CardTitle className="text-xs font-bold text-muted-foreground/70 leading-tight uppercase tracking-widest flex-1 min-w-0 pr-2">
|
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
|
||||||
|
<Wallet className="h-20 w-20 sm:h-24 sm:w-24 md:h-28 md:w-28 text-primary" strokeWidth={1} />
|
||||||
|
</div>
|
||||||
|
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-3 px-5 pt-5 sm:px-6 sm:pt-6 relative z-10">
|
||||||
|
<CardTitle className="text-[10px] sm:text-xs font-semibold text-muted-foreground/80 leading-tight uppercase tracking-wider flex-1 min-w-0">
|
||||||
Solde Total
|
Solde Total
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<div className="rounded-2xl bg-gradient-to-br from-primary/30 via-primary/20 to-primary/10 p-3 shrink-0 shadow-lg shadow-primary/20">
|
|
||||||
<Wallet className="h-5 w-5 text-primary" />
|
|
||||||
</div>
|
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="px-6 pb-6 sm:px-7 sm:pb-7 lg:px-5 lg:pb-5 pt-0 relative z-10">
|
<CardContent className="px-5 pb-5 sm:px-6 sm:pb-6 pt-0 relative z-10">
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"text-2xl sm:text-3xl md:text-3xl lg:text-xl xl:text-xl font-black tracking-tight mb-4 leading-none break-words",
|
"text-2xl sm:text-3xl md:text-3xl lg:text-2xl xl:text-3xl font-black tracking-tight mb-3 leading-tight break-words",
|
||||||
totalBalance >= 0
|
totalBalance >= 0
|
||||||
? "text-emerald-600 dark:text-emerald-400"
|
? "text-emerald-600 dark:text-emerald-400"
|
||||||
: "text-red-600 dark:text-red-400"
|
: "text-red-600 dark:text-red-400"
|
||||||
@@ -78,26 +79,27 @@ export function OverviewCards({ data }: OverviewCardsProps) {
|
|||||||
>
|
>
|
||||||
{formatCurrency(totalBalance)}
|
{formatCurrency(totalBalance)}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs sm:text-sm font-semibold text-muted-foreground/60">
|
<p className="text-xs sm:text-sm font-medium text-muted-foreground/70">
|
||||||
{data.accounts.length} compte{data.accounts.length > 1 ? "s" : ""}
|
{data.accounts.length} compte{data.accounts.length > 1 ? "s" : ""}
|
||||||
</p>
|
</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card className="stat-card-gradient-2 card-hover group relative overflow-hidden">
|
<Card className="stat-card-gradient-2 card-hover group relative overflow-hidden">
|
||||||
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-4 px-6 pt-6 sm:px-7 sm:pt-7 lg:px-5 lg:pt-5 relative z-10">
|
{/* Icône en arrière-plan */}
|
||||||
<CardTitle className="text-xs font-bold text-muted-foreground/70 leading-tight uppercase tracking-widest flex-1 min-w-0 pr-2">
|
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
|
||||||
|
<TrendingUp className="h-20 w-20 sm:h-24 sm:w-24 md:h-28 md:w-28 text-success" strokeWidth={1} />
|
||||||
|
</div>
|
||||||
|
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-3 px-5 pt-5 sm:px-6 sm:pt-6 relative z-10">
|
||||||
|
<CardTitle className="text-[10px] sm:text-xs font-semibold text-muted-foreground/80 leading-tight uppercase tracking-wider flex-1 min-w-0">
|
||||||
Revenus du mois
|
Revenus du mois
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<div className="rounded-2xl bg-gradient-to-br from-success/30 via-success/20 to-success/10 p-3 shrink-0 shadow-lg shadow-success/20">
|
|
||||||
<TrendingUp className="h-5 w-5 text-success" />
|
|
||||||
</div>
|
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="px-6 pb-6 sm:px-7 sm:pb-7 lg:px-5 lg:pb-5 pt-0 relative z-10">
|
<CardContent className="px-5 pb-5 sm:px-6 sm:pb-6 pt-0 relative z-10">
|
||||||
<div className="text-2xl sm:text-3xl md:text-3xl lg:text-xl xl:text-xl font-black tracking-tight text-success mb-4 leading-none break-words">
|
<div className="text-2xl sm:text-3xl md:text-3xl lg:text-2xl xl:text-3xl font-black tracking-tight text-success mb-3 leading-tight break-words">
|
||||||
{formatCurrency(income)}
|
{formatCurrency(income)}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs sm:text-sm font-semibold text-muted-foreground/60">
|
<p className="text-xs sm:text-sm font-medium text-muted-foreground/70">
|
||||||
{monthTransactions.filter((t) => t.amount > 0).length} opération
|
{monthTransactions.filter((t) => t.amount > 0).length} opération
|
||||||
{monthTransactions.filter((t) => t.amount > 0).length > 1
|
{monthTransactions.filter((t) => t.amount > 0).length > 1
|
||||||
? "s"
|
? "s"
|
||||||
@@ -107,19 +109,20 @@ export function OverviewCards({ data }: OverviewCardsProps) {
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card className="stat-card-gradient-3 card-hover group relative overflow-hidden">
|
<Card className="stat-card-gradient-3 card-hover group relative overflow-hidden">
|
||||||
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-4 px-6 pt-6 sm:px-7 sm:pt-7 lg:px-5 lg:pt-5 relative z-10">
|
{/* Icône en arrière-plan */}
|
||||||
<CardTitle className="text-xs font-bold text-muted-foreground/70 leading-tight uppercase tracking-widest flex-1 min-w-0 pr-2">
|
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
|
||||||
|
<TrendingDown className="h-20 w-20 sm:h-24 sm:w-24 md:h-28 md:w-28 text-destructive" strokeWidth={1} />
|
||||||
|
</div>
|
||||||
|
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-3 px-5 pt-5 sm:px-6 sm:pt-6 relative z-10">
|
||||||
|
<CardTitle className="text-[10px] sm:text-xs font-semibold text-muted-foreground/80 leading-tight uppercase tracking-wider flex-1 min-w-0">
|
||||||
Dépenses du mois
|
Dépenses du mois
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<div className="rounded-2xl bg-gradient-to-br from-destructive/30 via-destructive/20 to-destructive/10 p-3 shrink-0 shadow-lg shadow-destructive/20">
|
|
||||||
<TrendingDown className="h-5 w-5 text-destructive" />
|
|
||||||
</div>
|
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="px-6 pb-6 sm:px-7 sm:pb-7 lg:px-5 lg:pb-5 pt-0 relative z-10">
|
<CardContent className="px-5 pb-5 sm:px-6 sm:pb-6 pt-0 relative z-10">
|
||||||
<div className="text-2xl sm:text-3xl md:text-3xl lg:text-xl xl:text-xl font-black tracking-tight text-destructive mb-4 leading-none break-words">
|
<div className="text-2xl sm:text-3xl md:text-3xl lg:text-2xl xl:text-3xl font-black tracking-tight text-destructive mb-3 leading-tight break-words">
|
||||||
{formatCurrency(expenses)}
|
{formatCurrency(expenses)}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs sm:text-sm font-semibold text-muted-foreground/60">
|
<p className="text-xs sm:text-sm font-medium text-muted-foreground/70">
|
||||||
{monthTransactions.filter((t) => t.amount < 0).length} opération
|
{monthTransactions.filter((t) => t.amount < 0).length} opération
|
||||||
{monthTransactions.filter((t) => t.amount < 0).length > 1
|
{monthTransactions.filter((t) => t.amount < 0).length > 1
|
||||||
? "s"
|
? "s"
|
||||||
@@ -129,38 +132,40 @@ export function OverviewCards({ data }: OverviewCardsProps) {
|
|||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card className="stat-card-gradient-4 card-hover group relative overflow-hidden">
|
<Card className="stat-card-gradient-4 card-hover group relative overflow-hidden">
|
||||||
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-4 px-6 pt-6 sm:px-7 sm:pt-7 lg:px-5 lg:pt-5 relative z-10">
|
{/* Icône en arrière-plan */}
|
||||||
<CardTitle className="text-xs font-bold text-muted-foreground/70 leading-tight uppercase tracking-widest flex-1 min-w-0 pr-2">
|
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
|
||||||
|
<CreditCard className="h-20 w-20 sm:h-24 sm:w-24 md:h-28 md:w-28 text-chart-4" strokeWidth={1} />
|
||||||
|
</div>
|
||||||
|
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-3 px-5 pt-5 sm:px-6 sm:pt-6 relative z-10">
|
||||||
|
<CardTitle className="text-[10px] sm:text-xs font-semibold text-muted-foreground/80 leading-tight uppercase tracking-wider flex-1 min-w-0">
|
||||||
Pointage
|
Pointage
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<div className="rounded-2xl bg-gradient-to-br from-chart-4/30 via-chart-4/20 to-chart-4/10 p-3 shrink-0 shadow-lg shadow-chart-4/20">
|
|
||||||
<CreditCard className="h-5 w-5 text-chart-4" />
|
|
||||||
</div>
|
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="px-6 pb-6 sm:px-7 sm:pb-7 lg:px-5 lg:pb-5 pt-0 relative z-10">
|
<CardContent className="px-5 pb-5 sm:px-6 sm:pb-6 pt-0 relative z-10">
|
||||||
<div className="text-2xl sm:text-3xl md:text-3xl lg:text-xl xl:text-xl font-black tracking-tight mb-4 leading-none break-words">
|
<div className="text-2xl sm:text-3xl md:text-3xl lg:text-2xl xl:text-3xl font-black tracking-tight mb-3 leading-tight break-words">
|
||||||
{reconciledPercent}%
|
{reconciledPercent}%
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs sm:text-sm font-semibold text-muted-foreground/60">
|
<p className="text-xs sm:text-sm font-medium text-muted-foreground/70">
|
||||||
{reconciled} / {total} opérations pointées
|
{reconciled} / {total} opérations pointées
|
||||||
</p>
|
</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card className="stat-card-gradient-5 card-hover group relative overflow-hidden">
|
<Card className="stat-card-gradient-5 card-hover group relative overflow-hidden">
|
||||||
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-4 px-6 pt-6 sm:px-7 sm:pt-7 lg:px-5 lg:pt-5 relative z-10">
|
{/* Icône en arrière-plan */}
|
||||||
<CardTitle className="text-xs font-bold text-muted-foreground/70 leading-tight uppercase tracking-widest flex-1 min-w-0 pr-2">
|
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
|
||||||
|
<Tag className="h-20 w-20 sm:h-24 sm:w-24 md:h-28 md:w-28 text-chart-5" strokeWidth={1} />
|
||||||
|
</div>
|
||||||
|
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-3 px-5 pt-5 sm:px-6 sm:pt-6 relative z-10">
|
||||||
|
<CardTitle className="text-[10px] sm:text-xs font-semibold text-muted-foreground/80 leading-tight uppercase tracking-wider flex-1 min-w-0">
|
||||||
Catégorisation
|
Catégorisation
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<div className="rounded-2xl bg-gradient-to-br from-chart-5/30 via-chart-5/20 to-chart-5/10 p-3 shrink-0 shadow-lg shadow-chart-5/20">
|
|
||||||
<Tag className="h-5 w-5 text-chart-5" />
|
|
||||||
</div>
|
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="px-6 pb-6 sm:px-7 sm:pb-7 lg:px-5 lg:pb-5 pt-0 relative z-10">
|
<CardContent className="px-5 pb-5 sm:px-6 sm:pb-6 pt-0 relative z-10">
|
||||||
<div className="text-2xl sm:text-3xl md:text-3xl lg:text-xl xl:text-xl font-black tracking-tight mb-4 leading-none break-words">
|
<div className="text-2xl sm:text-3xl md:text-3xl lg:text-2xl xl:text-3xl font-black tracking-tight mb-3 leading-tight break-words">
|
||||||
{categorizedPercent}%
|
{categorizedPercent}%
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs sm:text-sm font-semibold text-muted-foreground/60">
|
<p className="text-xs sm:text-sm font-medium text-muted-foreground/70">
|
||||||
{categorized} / {total} opérations catégorisées
|
{categorized} / {total} opérations catégorisées
|
||||||
</p>
|
</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
LogOut,
|
LogOut,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { Sheet, SheetContent } from "@/components/ui/sheet";
|
import { Sheet, SheetContent, SheetTitle } from "@/components/ui/sheet";
|
||||||
import { useIsMobile } from "@/hooks/use-mobile";
|
import { useIsMobile } from "@/hooks/use-mobile";
|
||||||
import { useLocalStorage } from "@/hooks/use-local-storage";
|
import { useLocalStorage } from "@/hooks/use-local-storage";
|
||||||
|
|
||||||
@@ -165,6 +165,7 @@ export function Sidebar({ open, onOpenChange }: SidebarProps) {
|
|||||||
return (
|
return (
|
||||||
<Sheet open={open} onOpenChange={onOpenChange}>
|
<Sheet open={open} onOpenChange={onOpenChange}>
|
||||||
<SheetContent side="left" className="w-64 p-0">
|
<SheetContent side="left" className="w-64 p-0">
|
||||||
|
<SheetTitle className="sr-only">Navigation</SheetTitle>
|
||||||
<div className="flex flex-col h-full">
|
<div className="flex flex-col h-full">
|
||||||
<SidebarContent
|
<SidebarContent
|
||||||
showHeader
|
showHeader
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export function PageLayout({ children }: PageLayoutProps) {
|
|||||||
<div className="flex h-screen bg-background overflow-hidden page-background">
|
<div className="flex h-screen bg-background overflow-hidden page-background">
|
||||||
<Sidebar open={sidebarOpen} onOpenChange={setSidebarOpen} />
|
<Sidebar open={sidebarOpen} onOpenChange={setSidebarOpen} />
|
||||||
<main className="flex-1 overflow-auto overflow-x-hidden page-content">
|
<main className="flex-1 overflow-auto overflow-x-hidden page-content">
|
||||||
<div className="p-6 md:p-8 lg:p-10 space-y-6 md:space-y-8 max-w-full">
|
<div className="p-3 md:p-8 lg:p-10 space-y-4 md:space-y-8 max-w-full">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -21,59 +21,77 @@ export function StatsSummaryCards({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid gap-3 md:gap-4 grid-cols-2 md:grid-cols-4">
|
<div className="grid gap-3 md:gap-4 grid-cols-2 md:grid-cols-4">
|
||||||
<Card>
|
<Card className="relative overflow-hidden">
|
||||||
<CardHeader className="pb-2">
|
{/* Icône en arrière-plan */}
|
||||||
<CardTitle className="text-xs md:text-sm font-medium text-muted-foreground flex items-center gap-1.5 md:gap-2">
|
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
|
||||||
<TrendingUp className="w-3 h-3 md:w-4 md:h-4 text-emerald-600" />
|
<TrendingUp className="h-16 w-16 md:h-20 md:w-20 text-emerald-600 dark:text-emerald-400" strokeWidth={1} />
|
||||||
|
</div>
|
||||||
|
<CardHeader className="pb-3 px-5 pt-5 relative z-10">
|
||||||
|
<CardTitle className="text-[10px] md:text-xs font-semibold text-muted-foreground/80 uppercase tracking-wider">
|
||||||
Total Revenus
|
Total Revenus
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent className="px-5 pb-5 pt-0 relative z-10">
|
||||||
<div className="text-lg md:text-2xl font-bold text-emerald-600">
|
<div className="text-xl md:text-2xl font-black text-emerald-600 dark:text-emerald-400 tracking-tight">
|
||||||
{formatCurrency(totalIncome)}
|
{formatCurrency(totalIncome)}
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card>
|
<Card className="relative overflow-hidden">
|
||||||
<CardHeader className="pb-2">
|
{/* Icône en arrière-plan */}
|
||||||
<CardTitle className="text-xs md:text-sm font-medium text-muted-foreground flex items-center gap-1.5 md:gap-2">
|
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
|
||||||
<TrendingDown className="w-3 h-3 md:w-4 md:h-4 text-red-600" />
|
<TrendingDown className="h-16 w-16 md:h-20 md:w-20 text-red-600 dark:text-red-400" strokeWidth={1} />
|
||||||
|
</div>
|
||||||
|
<CardHeader className="pb-3 px-5 pt-5 relative z-10">
|
||||||
|
<CardTitle className="text-[10px] md:text-xs font-semibold text-muted-foreground/80 uppercase tracking-wider">
|
||||||
Total Dépenses
|
Total Dépenses
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent className="px-5 pb-5 pt-0 relative z-10">
|
||||||
<div className="text-lg md:text-2xl font-bold text-red-600">
|
<div className="text-xl md:text-2xl font-black text-red-600 dark:text-red-400 tracking-tight">
|
||||||
{formatCurrency(totalExpenses)}
|
{formatCurrency(totalExpenses)}
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card>
|
<Card className="relative overflow-hidden">
|
||||||
<CardHeader className="pb-2">
|
{/* Icône en arrière-plan */}
|
||||||
<CardTitle className="text-xs md:text-sm font-medium text-muted-foreground flex items-center gap-1.5 md:gap-2">
|
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
|
||||||
<ArrowRight className="w-3 h-3 md:w-4 md:h-4" />
|
<ArrowRight className="h-16 w-16 md:h-20 md:w-20 text-muted-foreground/40" strokeWidth={1} />
|
||||||
|
</div>
|
||||||
|
<CardHeader className="pb-3 px-5 pt-5 relative z-10">
|
||||||
|
<CardTitle className="text-[10px] md:text-xs font-semibold text-muted-foreground/80 uppercase tracking-wider">
|
||||||
Moyenne mensuelle
|
Moyenne mensuelle
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent className="px-5 pb-5 pt-0 relative z-10">
|
||||||
<div className="text-lg md:text-2xl font-bold">
|
<div className="text-xl md:text-2xl font-black tracking-tight">
|
||||||
{formatCurrency(avgMonthlyExpenses)}
|
{formatCurrency(avgMonthlyExpenses)}
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<Card>
|
<Card className="relative overflow-hidden">
|
||||||
<CardHeader className="pb-2">
|
{/* Icône en arrière-plan */}
|
||||||
<CardTitle className="text-xs md:text-sm font-medium text-muted-foreground">
|
<div className="absolute bottom-2 right-2 opacity-[0.04] dark:opacity-[0.03] z-0 pointer-events-none">
|
||||||
|
<div className={cn(
|
||||||
|
"h-16 w-16 md:h-20 md:w-20 rounded-full border-2",
|
||||||
|
savings >= 0
|
||||||
|
? "border-emerald-600 dark:border-emerald-400"
|
||||||
|
: "border-red-600 dark:border-red-400"
|
||||||
|
)} />
|
||||||
|
</div>
|
||||||
|
<CardHeader className="pb-3 px-5 pt-5 relative z-10">
|
||||||
|
<CardTitle className="text-[10px] md:text-xs font-semibold text-muted-foreground/80 uppercase tracking-wider">
|
||||||
Économies
|
Économies
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent className="px-5 pb-5 pt-0 relative z-10">
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"text-lg md:text-2xl font-bold",
|
"text-xl md:text-2xl font-black tracking-tight",
|
||||||
savings >= 0 ? "text-emerald-600" : "text-red-600",
|
savings >= 0 ? "text-emerald-600 dark:text-emerald-400" : "text-red-600 dark:text-red-400",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{formatCurrency(savings)}
|
{formatCurrency(savings)}
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ export function TransactionTable({
|
|||||||
const parentRef = useRef<HTMLDivElement>(null);
|
const parentRef = useRef<HTMLDivElement>(null);
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
|
|
||||||
const MOBILE_ROW_HEIGHT = 120;
|
const MOBILE_ROW_HEIGHT = 140;
|
||||||
|
|
||||||
const virtualizer = useVirtualizer({
|
const virtualizer = useVirtualizer({
|
||||||
count: transactions.length,
|
count: transactions.length,
|
||||||
@@ -227,17 +227,17 @@ export function TransactionTable({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="overflow-hidden">
|
<Card className="overflow-hidden w-full">
|
||||||
<CardContent className="p-0">
|
<CardContent className="p-0 w-full">
|
||||||
{transactions.length === 0 ? (
|
{transactions.length === 0 ? (
|
||||||
<div className="flex flex-col items-center justify-center py-12">
|
<div className="flex flex-col items-center justify-center py-12">
|
||||||
<p className="text-muted-foreground">Aucune transaction trouvée</p>
|
<p className="text-muted-foreground">Aucune transaction trouvée</p>
|
||||||
</div>
|
</div>
|
||||||
) : isMobile ? (
|
) : isMobile ? (
|
||||||
<div className="divide-y divide-border">
|
<div className="divide-y divide-border w-full">
|
||||||
<div
|
<div
|
||||||
ref={parentRef}
|
ref={parentRef}
|
||||||
className="overflow-auto"
|
className="overflow-auto w-full"
|
||||||
style={{ height: "calc(100vh - 200px)", minHeight: "600px" }}
|
style={{ height: "calc(100vh - 200px)", minHeight: "600px" }}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -278,30 +278,31 @@ export function TransactionTable({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={cn(
|
className={cn(
|
||||||
"p-4 space-y-3 hover:bg-muted/50 cursor-pointer border-b border-border",
|
"p-4 md:p-4 space-y-3 hover:bg-muted/50 cursor-pointer border-b border-border",
|
||||||
transaction.isReconciled && "bg-emerald-500/5",
|
transaction.isReconciled && "bg-emerald-500/5",
|
||||||
isFocused && "bg-primary/10 ring-1 ring-primary/30",
|
isFocused && "bg-primary/10 ring-1 ring-primary/30",
|
||||||
isDuplicate && "shadow-sm"
|
isDuplicate && "shadow-sm"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex items-start justify-between gap-2">
|
<div className="flex items-start justify-between gap-3">
|
||||||
<div className="flex items-start gap-3 flex-1 min-w-0">
|
<div className="flex items-start gap-0 md:gap-3 flex-1 min-w-0">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={selectedTransactions.has(transaction.id)}
|
checked={selectedTransactions.has(transaction.id)}
|
||||||
onCheckedChange={() => {
|
onCheckedChange={() => {
|
||||||
onToggleSelectTransaction(transaction.id);
|
onToggleSelectTransaction(transaction.id);
|
||||||
}}
|
}}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
className="mt-0.5 hidden md:flex"
|
||||||
/>
|
/>
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<p className="font-medium text-xs md:text-sm truncate">
|
<p className="font-medium text-sm md:text-sm truncate leading-tight">
|
||||||
{transaction.description}
|
{transaction.description}
|
||||||
</p>
|
</p>
|
||||||
{isDuplicate && (
|
{isDuplicate && (
|
||||||
<Tooltip delayDuration={200}>
|
<Tooltip delayDuration={200}>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<AlertTriangle className="h-3 w-3 md:h-4 md:w-4 text-[var(--warning)] shrink-0" />
|
<AlertTriangle className="h-4 w-4 md:h-4 md:w-4 text-[var(--warning)] shrink-0" />
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
<p>
|
<p>
|
||||||
@@ -312,7 +313,7 @@ export function TransactionTable({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{transaction.memo && (
|
{transaction.memo && (
|
||||||
<p className="text-[10px] md:text-xs text-muted-foreground truncate mt-1">
|
<p className="text-xs md:text-xs text-muted-foreground truncate mt-1.5">
|
||||||
{transaction.memo}
|
{transaction.memo}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
@@ -320,7 +321,7 @@ export function TransactionTable({
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"font-semibold tabular-nums text-sm md:text-base shrink-0",
|
"font-semibold tabular-nums text-base md:text-base shrink-0",
|
||||||
transaction.amount >= 0
|
transaction.amount >= 0
|
||||||
? "text-emerald-600"
|
? "text-emerald-600"
|
||||||
: "text-red-600"
|
: "text-red-600"
|
||||||
@@ -331,18 +332,18 @@ export function TransactionTable({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2 md:gap-3 flex-wrap">
|
<div className="flex items-center gap-2.5 md:gap-3 flex-wrap">
|
||||||
<span className="text-[10px] md:text-xs text-muted-foreground">
|
<span className="text-xs md:text-xs text-muted-foreground">
|
||||||
{formatDate(transaction.date)}
|
{formatDate(transaction.date)}
|
||||||
</span>
|
</span>
|
||||||
{account && (
|
{account && (
|
||||||
<span className="text-[10px] md:text-xs text-muted-foreground">
|
<span className="text-xs md:text-xs text-muted-foreground">
|
||||||
• {account.name}
|
• {account.name}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<div
|
<div
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
className="flex-1 relative"
|
className="flex-1 relative min-w-[120px]"
|
||||||
>
|
>
|
||||||
{updatingTransactionIds.has(transaction.id) && (
|
{updatingTransactionIds.has(transaction.id) && (
|
||||||
<div className="absolute inset-0 flex items-center justify-center bg-background/50 z-10 rounded">
|
<div className="absolute inset-0 flex items-center justify-center bg-background/50 z-10 rounded">
|
||||||
@@ -370,9 +371,9 @@ export function TransactionTable({
|
|||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
className="h-8 w-8 shrink-0"
|
className="h-9 w-9 shrink-0"
|
||||||
>
|
>
|
||||||
<MoreVertical className="w-4 h-4" />
|
<MoreVertical className="w-5 h-5" />
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="end">
|
<DropdownMenuContent align="end">
|
||||||
|
|||||||
Reference in New Issue
Block a user