feat(03-02): navigation restructure, TotalsBar refactor, and setup hooks

- Move collection view from / to /collection with gear/planning tabs
- Rewrite / as dashboard with three summary cards (Collection, Planning, Setups)
- Refactor TotalsBar to accept optional stats/linkTo/title props
- Create DashboardCard component for dashboard summary cards
- Create useSetups hooks (CRUD + sync/remove item mutations)
- Update __root.tsx with route-aware TotalsBar, FAB visibility, resolve navigation
- Add item picker and setup delete UI state to uiStore
- Invalidate setups queries on item update/delete for stale data prevention
- Update routeTree.gen.ts with new collection/setups routes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-15 12:49:03 +01:00
parent c2b8985d37
commit 86a7a0def1
11 changed files with 637 additions and 270 deletions

View File

@@ -0,0 +1,50 @@
import { Link } from "@tanstack/react-router";
import type { ReactNode } from "react";
interface DashboardCardProps {
to: string;
search?: Record<string, string>;
title: string;
icon: ReactNode;
stats: Array<{ label: string; value: string }>;
emptyText?: string;
}
export function DashboardCard({
to,
search,
title,
icon,
stats,
emptyText,
}: DashboardCardProps) {
const allZero = stats.every(
(s) => s.value === "0" || s.value === "$0.00" || s.value === "0g",
);
return (
<Link
to={to}
search={search}
className="block bg-white rounded-xl border border-gray-100 hover:border-gray-200 hover:shadow-md transition-all p-6"
>
<div className="flex items-center gap-3 mb-4">
<span className="text-2xl">{icon}</span>
<h2 className="text-lg font-semibold text-gray-900">{title}</h2>
</div>
<div className="space-y-1.5">
{stats.map((stat) => (
<div key={stat.label} className="flex items-center justify-between">
<span className="text-sm text-gray-500">{stat.label}</span>
<span className="text-sm font-medium text-gray-700">
{stat.value}
</span>
</div>
))}
</div>
{allZero && emptyText && (
<p className="mt-4 text-sm text-blue-600 font-medium">{emptyText}</p>
)}
</Link>
);
}