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
+40
View File
@@ -0,0 +1,40 @@
import { AlertTriangle, Loader2 } from "lucide-react";
import type { SetupStatus } from "../types";
type StatusRailProps = {
busyAction: string | null;
syncError: string;
setupStatus: SetupStatus;
};
export function StatusRail({ busyAction, syncError, setupStatus }: StatusRailProps) {
if (!busyAction && !syncError && setupStatus.state === "ok") return null;
return (
<div className="mt-3 grid gap-2">
{busyAction && (
<div className="status-card">
<Loader2 className="animate-spin" size={17} aria-hidden="true" />
Working on {actionLabel(busyAction)}...
</div>
)}
{syncError && (
<div className="status-card" style={{ borderColor: "#ffc9c2", background: "#fff3f1", color: "#9f1c16" }}>
<AlertTriangle size={17} aria-hidden="true" />
{syncError}
</div>
)}
{setupStatus.state === "error" && (
<div className="status-card" style={{ borderColor: "#f9e3b0", background: "#fff8e8", color: "#7a4e00" }}>
<AlertTriangle size={17} aria-hidden="true" />
{setupStatus.message}
</div>
)}
</div>
);
}
function actionLabel(value: string) {
return value
.replace(/^quick-/, "quick add ")
.replace(/-/g, " ");
}