Initial commit: MyMidas personal finance tracker
Full-stack self-hosted finance app with FastAPI backend and React frontend. Features: - Accounts, transactions, budgets, investments with GBP base currency - CSV import with auto-detection for 10 UK bank formats - ML predictions: spending forecast, net worth projection, Monte Carlo - 7 selectable themes (Obsidian, Arctic, Midnight, Vault, Terminal, Synthwave, Ledger) - Receipt/document attachments on transactions (JPEG, PNG, WebP, PDF) - AES-256-GCM field encryption, RS256 JWT, TOTP 2FA, RLS, audit log - Encrypted nightly backups + key rotation script - Mobile-responsive layout with bottom nav Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
61a7884ee5
127 changed files with 13323 additions and 0 deletions
84
frontend/src/components/layout/Sidebar.tsx
Normal file
84
frontend/src/components/layout/Sidebar.tsx
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import { Link, useLocation } from "react-router-dom";
|
||||
import { cn } from "@/utils/cn";
|
||||
import { useUiStore } from "@/store/uiStore";
|
||||
import {
|
||||
LayoutDashboard,
|
||||
CreditCard,
|
||||
ArrowLeftRight,
|
||||
PiggyBank,
|
||||
TrendingUp,
|
||||
BarChart3,
|
||||
Sparkles,
|
||||
Settings,
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
DollarSign,
|
||||
} from "lucide-react";
|
||||
|
||||
const navItems = [
|
||||
{ href: "/", icon: LayoutDashboard, label: "Dashboard" },
|
||||
{ href: "/accounts", icon: CreditCard, label: "Accounts" },
|
||||
{ href: "/transactions", icon: ArrowLeftRight, label: "Transactions" },
|
||||
{ href: "/budgets", icon: PiggyBank, label: "Budgets" },
|
||||
{ href: "/investments", icon: TrendingUp, label: "Investments" },
|
||||
{ href: "/reports", icon: BarChart3, label: "Reports" },
|
||||
{ href: "/predictions", icon: Sparkles, label: "Predictions" },
|
||||
{ href: "/settings", icon: Settings, label: "Settings" },
|
||||
];
|
||||
|
||||
export default function Sidebar() {
|
||||
const location = useLocation();
|
||||
const { sidebarOpen, setSidebarOpen } = useUiStore();
|
||||
|
||||
return (
|
||||
<aside
|
||||
className={cn(
|
||||
"fixed left-0 top-0 h-full z-30 bg-card border-r border-border transition-all duration-200 flex flex-col",
|
||||
sidebarOpen ? "w-64" : "w-16"
|
||||
)}
|
||||
>
|
||||
{/* Logo */}
|
||||
<div className="flex items-center h-16 px-4 border-b border-border shrink-0">
|
||||
<DollarSign className="w-7 h-7 text-primary shrink-0" />
|
||||
{sidebarOpen && (
|
||||
<span className="ml-2 font-semibold text-lg truncate">Finance</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Nav */}
|
||||
<nav className="flex-1 overflow-y-auto py-4 space-y-1 px-2">
|
||||
{navItems.map(({ href, icon: Icon, label }) => {
|
||||
const active = location.pathname === href || (href !== "/" && location.pathname.startsWith(href));
|
||||
return (
|
||||
<Link
|
||||
key={href}
|
||||
to={href}
|
||||
className={cn(
|
||||
"flex items-center gap-3 px-2 py-2 rounded-md text-sm font-medium transition-colors",
|
||||
active
|
||||
? "bg-primary/15 text-primary"
|
||||
: "text-muted-foreground hover:bg-secondary hover:text-foreground"
|
||||
)}
|
||||
title={!sidebarOpen ? label : undefined}
|
||||
>
|
||||
<Icon className="w-5 h-5 shrink-0" />
|
||||
{sidebarOpen && <span className="truncate">{label}</span>}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
|
||||
{/* Toggle */}
|
||||
<button
|
||||
onClick={() => setSidebarOpen(!sidebarOpen)}
|
||||
className="flex items-center justify-center h-10 w-full border-t border-border text-muted-foreground hover:text-foreground transition-colors"
|
||||
>
|
||||
{sidebarOpen ? (
|
||||
<ChevronLeft className="w-4 h-4" />
|
||||
) : (
|
||||
<ChevronRight className="w-4 h-4" />
|
||||
)}
|
||||
</button>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue