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:
@@ -59,14 +59,38 @@ function RootLayout() {
|
||||
const isItemPanelOpen = panelMode !== "closed";
|
||||
const isCandidatePanelOpen = candidatePanelMode !== "closed";
|
||||
|
||||
// Detect if we're on a thread detail page to get the threadId for candidate forms
|
||||
// Route matching for contextual behavior
|
||||
const matchRoute = useMatchRoute();
|
||||
|
||||
const threadMatch = matchRoute({
|
||||
to: "/threads/$threadId",
|
||||
fuzzy: true,
|
||||
}) as { threadId?: string } | false;
|
||||
const currentThreadId = threadMatch ? Number(threadMatch.threadId) : null;
|
||||
|
||||
const isDashboard = !!matchRoute({ to: "/" });
|
||||
const isCollection = !!matchRoute({ to: "/collection", fuzzy: true });
|
||||
const isSetupDetail = !!matchRoute({ to: "/setups/$setupId", fuzzy: true });
|
||||
|
||||
// Determine TotalsBar props based on current route
|
||||
const totalsBarProps = isDashboard
|
||||
? { stats: [] as Array<{ label: string; value: string }> } // Title only, no stats, no link
|
||||
: isSetupDetail
|
||||
? { linkTo: "/" } // Setup detail will render its own local bar; root bar just has link
|
||||
: { linkTo: "/" }; // All other pages: default stats + link to dashboard
|
||||
|
||||
// On dashboard, don't show the default global stats - pass empty stats
|
||||
// On collection, let TotalsBar fetch its own global stats (default behavior)
|
||||
const finalTotalsProps = isDashboard
|
||||
? { stats: [] as Array<{ label: string; value: string }> }
|
||||
: isCollection
|
||||
? { linkTo: "/" }
|
||||
: { linkTo: "/" };
|
||||
|
||||
// FAB visibility: only show on /collection route when gear tab is active
|
||||
const collectionSearch = matchRoute({ to: "/collection" }) as { tab?: string } | false;
|
||||
const showFab = isCollection && (!collectionSearch || (collectionSearch as Record<string, string>).tab !== "planning");
|
||||
|
||||
// Show a minimal loading state while checking onboarding status
|
||||
if (onboardingLoading) {
|
||||
return (
|
||||
@@ -78,7 +102,7 @@ function RootLayout() {
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50">
|
||||
<TotalsBar />
|
||||
<TotalsBar {...finalTotalsProps} />
|
||||
<Outlet />
|
||||
|
||||
{/* Item Slide-out Panel */}
|
||||
@@ -135,13 +159,13 @@ function RootLayout() {
|
||||
onClose={closeResolveDialog}
|
||||
onResolved={() => {
|
||||
closeResolveDialog();
|
||||
navigate({ to: "/", search: { tab: "planning" } });
|
||||
navigate({ to: "/collection", search: { tab: "planning" } });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Floating Add Button - only on gear tab */}
|
||||
{!threadMatch && (
|
||||
{/* Floating Add Button - only on collection gear tab */}
|
||||
{showFab && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={openAddPanel}
|
||||
|
||||
Reference in New Issue
Block a user