refactor: decompose monolithic App.tsx into per-component files

- Extract views to src/components/views/ (Overview, Logbook, Trends, Settings, Auth)
- Extract standalone components (EntryModal, ImportPreviewModal, ConfirmDialog,
  Sidebar, TopBar, MobileNav, EntryLedger, FiltersPanel, QuickAddPanel, etc.)
- Move shared helpers to src/lib (dashboard, filters, userDisplay) and static
  data to src/data (accents, quickAdds)
- App.tsx now orchestration-only (2971 -> 777 lines); no behavior change
This commit is contained in:
nh9961
2026-07-19 19:31:40 +00:00
parent 2cd8dd5130
commit 50c729eae7
34 changed files with 2312 additions and 2218 deletions
+61
View File
@@ -0,0 +1,61 @@
import { Camera, Plus } from "lucide-react";
import { NAV_ITEMS } from "./navItems";
import type { AppView } from "../types";
type TopBarProps = {
activeView: AppView;
busyAction: string | null;
onAdd: () => void;
onScan: () => void;
className?: string;
};
export function TopBar({ activeView, busyAction, onAdd, onScan, className = "" }: TopBarProps) {
const activeItem = NAV_ITEMS.find((item) => item.id === activeView) ?? NAV_ITEMS[0];
const ActiveIcon = activeItem.icon;
const title = activeItem.label;
const subtitle = new Intl.DateTimeFormat("en-GB", {
weekday: "long",
day: "numeric",
month: "long",
}).format(new Date());
return (
<header className={`top-app-bar ${className}`.trim()} data-view={activeView}>
<div className="top-app-bar-main">
<div className="top-title-cluster">
<span className="top-app-icon">
<ActiveIcon size={24} aria-hidden="true" />
</span>
<div className="min-w-0">
<p className="top-kicker">{subtitle}</p>
<h1 className="top-title">{title}</h1>
</div>
</div>
</div>
<div className="top-action-row">
<button
className="secondary-button top-action-button justify-center active:scale-95"
type="button"
onClick={onScan}
disabled={Boolean(busyAction)}
aria-label="Scan barcode"
>
<Camera size={18} aria-hidden="true" />
<span className="top-action-label">Scan</span>
</button>
<button
className="primary-button top-action-button justify-center active:scale-95"
type="button"
onClick={onAdd}
disabled={Boolean(busyAction)}
aria-label="Add intake"
>
<Plus size={18} aria-hidden="true" />
<span className="top-action-label">Add intake</span>
</button>
</div>
</header>
);
}