Migrate all components and pages to shadcn/ui with DataTable
All checks were successful
Deploy to VPS / deploy (push) Successful in 28s

Replace custom markup across all pages and components with shadcn/ui
primitives (Dialog, Sheet, Select, Card, Tabs, etc.). Add reusable
DataTable component powered by @tanstack/react-table with sortable
column headers and client-side pagination. Introduce TransactionList
with responsive mobile cards and desktop DataTable, dashboard section
customization (DashboardSection, SectionConfigDialog), and settings
API types.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Carlos Escalante
2026-03-22 14:45:44 -06:00
parent 46f2d8679c
commit 2cd0d3b2e1
17 changed files with 1626 additions and 1109 deletions

View File

@@ -7,13 +7,22 @@ import {
LogOut,
Wallet,
Menu,
X,
Sun,
Moon,
} from 'lucide-react';
import { useState } from 'react';
import { useAuth } from '../AuthContext';
import { useTheme } from '../ThemeContext';
import { Button } from '@/components/ui/button';
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
SheetClose,
} from '@/components/ui/sheet';
import { Separator } from '@/components/ui/separator';
import { cn } from '@/lib/utils';
const navItems = [
{ to: '/', icon: LayoutDashboard, label: 'Dashboard' },
@@ -34,16 +43,16 @@ export default function Layout() {
};
return (
<div className="min-h-screen bg-surface text-text-primary">
<div className="min-h-screen bg-background text-foreground">
{/* Top bar */}
<header className="border-b border-border backdrop-blur-sm sticky top-0 z-50 bg-surface/90">
<header className="border-b border-border backdrop-blur-sm sticky top-0 z-50 bg-background/90">
<div className="max-w-7xl mx-auto px-4 sm:px-6 py-3 flex items-center justify-between">
<div className="flex items-center gap-2.5">
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-[#606C38] to-[#DDA15E] flex items-center justify-center">
<Wallet className="w-4 h-4 text-[#FEFAE0]" strokeWidth={2.5} />
<div className="w-8 h-8 rounded-lg bg-primary flex items-center justify-center">
<Wallet className="w-4 h-4 text-primary-foreground" strokeWidth={2.5} />
</div>
<span className="text-lg font-bold tracking-tight hidden sm:inline">
Wealthy<span className="text-[#606C38] dark:text-[#7a8a4a]">Smart</span>
<span className="text-lg font-bold tracking-tight hidden sm:inline font-heading">
Wealthy<span className="text-primary">Smart</span>
</span>
</div>
@@ -55,11 +64,12 @@ export default function Layout() {
to={to}
end={to === '/'}
className={({ isActive }) =>
`flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium transition-colors ${
cn(
'flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium transition-colors',
isActive
? 'bg-[#606C38]/10 text-[#606C38] dark:text-[#7a8a4a]'
: 'text-text-muted hover:text-text-primary hover:bg-surface-hover'
}`
? 'bg-primary/10 text-primary'
: 'text-muted-foreground hover:text-foreground hover:bg-muted'
)
}
>
<Icon className="w-4 h-4" />
@@ -68,59 +78,80 @@ export default function Layout() {
))}
</nav>
<div className="flex items-center gap-2">
<button
onClick={toggleTheme}
className="p-2 rounded-lg text-text-muted hover:text-text-primary hover:bg-surface-hover transition-colors"
>
<div className="flex items-center gap-1">
<Button variant="ghost" size="icon" onClick={toggleTheme} title="Toggle theme" aria-label="Toggle theme">
{theme === 'dark' ? <Sun className="w-4 h-4" /> : <Moon className="w-4 h-4" />}
</button>
<button
</Button>
<Button
variant="ghost"
size="icon"
onClick={handleLogout}
className="hidden md:flex items-center gap-2 text-text-muted hover:text-text-secondary text-sm transition-colors"
title="Sign out"
aria-label="Sign out"
className="hidden md:inline-flex"
>
<LogOut className="w-4 h-4" />
</button>
<button
onClick={() => setMobileOpen(!mobileOpen)}
className="md:hidden text-text-muted"
</Button>
<Button
variant="ghost"
size="icon"
onClick={() => setMobileOpen(true)}
title="Open menu"
aria-label="Open menu"
className="md:hidden"
>
{mobileOpen ? <X className="w-5 h-5" /> : <Menu className="w-5 h-5" />}
</button>
<Menu className="w-5 h-5" />
</Button>
</div>
</div>
</header>
{/* Mobile nav */}
{mobileOpen && (
<div className="md:hidden border-t border-border px-4 pb-4 space-y-1">
{/* Mobile nav sheet */}
<Sheet open={mobileOpen} onOpenChange={setMobileOpen}>
<SheetContent side="left" className="p-0">
<SheetHeader className="p-4">
<SheetTitle className="flex items-center gap-2.5">
<div className="w-8 h-8 rounded-lg bg-primary flex items-center justify-center">
<Wallet className="w-4 h-4 text-primary-foreground" strokeWidth={2.5} />
</div>
<span className="font-heading">
Wealthy<span className="text-primary">Smart</span>
</span>
</SheetTitle>
</SheetHeader>
<Separator />
<nav className="flex flex-col gap-1 p-4">
{navItems.map(({ to, icon: Icon, label }) => (
<NavLink
key={to}
to={to}
end={to === '/'}
onClick={() => setMobileOpen(false)}
className={({ isActive }) =>
`flex items-center gap-3 px-4 py-3 rounded-lg text-sm font-medium transition-colors ${
isActive
? 'bg-[#606C38]/10 text-[#606C38] dark:text-[#7a8a4a]'
: 'text-text-muted hover:text-text-primary hover:bg-surface-hover'
}`
}
>
<Icon className="w-4 h-4" />
{label}
</NavLink>
<SheetClose key={to} render={<span />}>
<NavLink
to={to}
end={to === '/'}
onClick={() => setMobileOpen(false)}
className={({ isActive }) =>
cn(
'flex items-center gap-3 px-4 py-3 rounded-lg text-sm font-medium transition-colors',
isActive
? 'bg-primary/10 text-primary'
: 'text-muted-foreground hover:text-foreground hover:bg-muted'
)
}
>
<Icon className="w-4 h-4" />
{label}
</NavLink>
</SheetClose>
))}
<Separator className="my-2" />
<button
onClick={handleLogout}
className="flex items-center gap-3 px-4 py-3 rounded-lg text-sm font-medium text-text-muted hover:text-text-primary hover:bg-surface-hover w-full"
className="flex items-center gap-3 px-4 py-3 rounded-lg text-sm font-medium text-muted-foreground hover:text-foreground hover:bg-muted w-full"
>
<LogOut className="w-4 h-4" />
Sign out
</button>
</div>
)}
</header>
</nav>
</SheetContent>
</Sheet>
<main className="max-w-7xl mx-auto px-4 sm:px-6 py-6">
<Outlet />