feat: enhance UI with new background gradients and responsive design adjustments across various components

This commit is contained in:
Julien Froidefond
2025-12-07 17:23:53 +01:00
parent b704cc5a84
commit d4db94d156
10 changed files with 399 additions and 191 deletions

View File

@@ -30,10 +30,26 @@ import {
} from "@/lib/store-db";
import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Building2, Folder, Plus, List, LayoutGrid } from "lucide-react";
import {
Building2,
Folder,
Plus,
List,
LayoutGrid,
MoreVertical,
Pencil,
Trash2,
} from "lucide-react";
import type { Account, Folder as FolderType } from "@/lib/types";
import { cn } from "@/lib/utils";
import { getAccountBalance } from "@/lib/account-utils";
import { useIsMobile } from "@/hooks/use-mobile";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
// Composant wrapper pour les zones de drop des dossiers
function FolderDropZone({
@@ -61,6 +77,7 @@ function FolderDropZone({
export default function AccountsPage() {
const queryClient = useQueryClient();
const isMobile = useIsMobile();
const { data: metadata, isLoading: isLoadingMetadata } = useBankingMetadata();
const { data: accountsWithStats, isLoading: isLoadingAccounts } =
useAccountsWithStats();
@@ -376,12 +393,12 @@ export default function AccountsPage() {
<PageLayout>
<PageHeader
title="Comptes"
description="Gérez vos comptes bancaires et leur organisation"
description={isMobile ? undefined : "Gérez vos comptes bancaires et leur organisation"}
actions={
<div className="flex items-center gap-2">
<Button
variant="outline"
size="icon"
size={isMobile ? "icon" : "default"}
onClick={() => setIsCompactView(!isCompactView)}
title={isCompactView ? "Vue détaillée" : "Vue compacte"}
>
@@ -390,22 +407,31 @@ export default function AccountsPage() {
) : (
<List className="w-4 h-4" />
)}
{!isMobile && (
<span className="ml-2">
{isCompactView ? "Détaillée" : "Compacte"}
</span>
)}
</Button>
<Button onClick={handleNewFolder}>
<Plus className="w-4 h-4 mr-2" />
Nouveau dossier
<Button onClick={handleNewFolder} size={isMobile ? "icon" : "default"}>
<Plus className="w-4 h-4" />
{!isMobile && <span className="ml-2">Nouveau dossier</span>}
</Button>
</div>
}
rightContent={
<div className="text-right">
<p className="text-sm text-muted-foreground">Solde total</p>
<div className={cn("text-right", isMobile && "text-left")}>
{!isMobile && (
<p className="text-sm text-muted-foreground">Solde total</p>
)}
<p
className={cn(
"text-2xl font-bold",
isMobile ? "text-xl" : "text-2xl",
"font-bold",
totalBalance >= 0 ? "text-emerald-600" : "text-red-600",
)}
>
{isMobile && <span className="text-xs text-muted-foreground mr-2">Total:</span>}
{formatCurrency(totalBalance)}
</p>
</div>
@@ -440,32 +466,36 @@ export default function AccountsPage() {
{accountsByFolder["no-folder"] &&
accountsByFolder["no-folder"].length > 0 && (
<FolderDropZone folderId="root">
<div className="flex items-center gap-2 mb-4">
<Folder className="w-5 h-5 text-muted-foreground" />
<h2 className="text-lg font-semibold">Sans dossier</h2>
<span className="text-sm text-muted-foreground">
({accountsByFolder["no-folder"].length})
</span>
<span
className={cn(
"text-sm font-semibold tabular-nums ml-auto",
accountsByFolder["no-folder"].reduce(
(sum, a) => sum + getAccountBalance(a),
0,
) >= 0
? "text-emerald-600"
: "text-red-600",
)}
>
{formatCurrency(
accountsByFolder["no-folder"].reduce(
(sum, a) => sum + getAccountBalance(a),
0,
),
)}
</span>
<div className="flex items-center gap-2 mb-3 sm:mb-4">
<Folder className="w-5 h-5 text-muted-foreground shrink-0" />
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 flex-wrap">
<h2 className="text-base sm:text-lg font-semibold">Sans dossier</h2>
<span className="text-xs sm:text-sm text-muted-foreground shrink-0">
({accountsByFolder["no-folder"].length})
</span>
<span
className={cn(
"text-xs sm:text-sm font-semibold tabular-nums shrink-0",
accountsByFolder["no-folder"].reduce(
(sum, a) => sum + getAccountBalance(a),
0,
) >= 0
? "text-emerald-600"
: "text-red-600",
)}
>
{formatCurrency(
accountsByFolder["no-folder"].reduce(
(sum, a) => sum + getAccountBalance(a),
0,
),
)}
</span>
</div>
</div>
</div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
<div className="grid gap-2 sm:gap-3 md:gap-4 grid-cols-2 sm:grid-cols-2 lg:grid-cols-3">
{accountsByFolder["no-folder"].map((account) => {
const folder = metadata.folders.find(
(f: FolderType) => f.id === account.folderId,
@@ -501,9 +531,9 @@ export default function AccountsPage() {
return (
<FolderDropZone key={folder.id} folderId={folder.id}>
<div className="flex items-center gap-2 mb-4">
<div className="flex items-center gap-2 mb-3 sm:mb-4">
<div
className="w-5 h-5 rounded flex items-center justify-center"
className="w-5 h-5 rounded flex items-center justify-center shrink-0"
style={{ backgroundColor: `${folder.color}20` }}
>
<Folder
@@ -511,41 +541,72 @@ export default function AccountsPage() {
style={{ color: folder.color }}
/>
</div>
<h2 className="text-lg font-semibold">{folder.name}</h2>
<span className="text-sm text-muted-foreground">
({folderAccounts.length})
</span>
{folderAccounts.length > 0 && (
<span
className={cn(
"text-sm font-semibold tabular-nums",
folderBalance >= 0
? "text-emerald-600"
: "text-red-600",
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 flex-wrap">
<h2 className="text-base sm:text-lg font-semibold truncate">
{folder.name}
</h2>
<span className="text-xs sm:text-sm text-muted-foreground shrink-0">
({folderAccounts.length})
</span>
{folderAccounts.length > 0 && (
<span
className={cn(
"text-xs sm:text-sm font-semibold tabular-nums shrink-0",
folderBalance >= 0
? "text-emerald-600"
: "text-red-600",
)}
>
{formatCurrency(folderBalance)}
</span>
)}
>
{formatCurrency(folderBalance)}
</span>
</div>
</div>
{isMobile ? (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="h-8 w-8 shrink-0">
<MoreVertical className="w-4 h-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => handleEditFolder(folder)}>
<Pencil className="w-4 h-4 mr-2" />
Modifier
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => handleDeleteFolder(folder.id)}
variant="destructive"
>
<Trash2 className="w-4 h-4 mr-2" />
Supprimer
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
) : (
<>
<Button
variant="ghost"
size="sm"
onClick={() => handleEditFolder(folder)}
className="ml-auto shrink-0"
>
Modifier
</Button>
<Button
variant="ghost"
size="sm"
onClick={() => handleDeleteFolder(folder.id)}
className="text-destructive hover:text-destructive shrink-0"
>
Supprimer
</Button>
</>
)}
<Button
variant="ghost"
size="sm"
onClick={() => handleEditFolder(folder)}
className="ml-auto"
>
Modifier
</Button>
<Button
variant="ghost"
size="sm"
onClick={() => handleDeleteFolder(folder.id)}
className="text-destructive hover:text-destructive"
>
Supprimer
</Button>
</div>
{folderAccounts.length > 0 ? (
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
<div className="grid gap-2 sm:gap-3 md:gap-4 grid-cols-2 sm:grid-cols-2 lg:grid-cols-3">
{folderAccounts.map((account) => {
const accountFolder = metadata.folders.find(
(f: FolderType) => f.id === account.folderId,