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:
@@ -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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user