feat(20-02): wire FabMenu and CatalogSearchOverlay into root layout

- Replace old single-action FAB with FabMenu component
- Add CatalogSearchOverlay to root layout
- FAB now visible on all authenticated non-public routes
- Detect setups page for conditional New Setup menu item
- Remove unused openAddPanel reference
This commit is contained in:
2026-04-06 08:04:10 +02:00
parent 720460852c
commit e13f9584fa

View File

@@ -10,8 +10,10 @@ import {
import { useState } from "react";
import "../app.css";
import { CandidateForm } from "../components/CandidateForm";
import { CatalogSearchOverlay } from "../components/CatalogSearchOverlay";
import { ConfirmDialog } from "../components/ConfirmDialog";
import { ExternalLinkDialog } from "../components/ExternalLinkDialog";
import { FabMenu } from "../components/FabMenu";
import { ItemForm } from "../components/ItemForm";
import { OnboardingWizard } from "../components/OnboardingWizard";
import { SlideOutPanel } from "../components/SlideOutPanel";
@@ -80,7 +82,6 @@ function RootLayout() {
// Item panel state
const panelMode = useUIStore((s) => s.panelMode);
const editingItemId = useUIStore((s) => s.editingItemId);
const openAddPanel = useUIStore((s) => s.openAddPanel);
const closePanel = useUIStore((s) => s.closePanel);
// Candidate panel state
@@ -144,16 +145,6 @@ function RootLayout() {
? { 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 ||
(collectionSearch as Record<string, string>).tab === "gear");
// Show loading while checking auth
if (authLoading) {
return (
@@ -168,6 +159,10 @@ function RootLayout() {
const isPublicRoute =
location.pathname.startsWith("/users/") || location.pathname === "/login";
// FAB visibility: show on all authenticated, non-public routes
const isSetupsPage = !!matchRoute({ to: "/setups", fuzzy: true });
const showFab = isAuthenticated && !isPublicRoute;
if (!isAuthenticated && !isPublicRoute) {
window.location.href = "/login";
return (
@@ -253,29 +248,11 @@ function RootLayout() {
/>
)}
{/* Floating Add Button - only on collection gear tab */}
{showFab && isAuthenticated && (
<button
type="button"
onClick={openAddPanel}
className="fixed bottom-6 right-6 z-20 w-14 h-14 bg-gray-700 hover:bg-gray-800 text-white rounded-full shadow-lg hover:shadow-xl transition-all flex items-center justify-center"
title="Add new item"
>
<svg
className="w-6 h-6"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 4v16m8-8H4"
/>
</svg>
</button>
)}
{/* Floating Action Button */}
{showFab && <FabMenu isSetupsPage={isSetupsPage} />}
{/* Catalog Search Overlay */}
<CatalogSearchOverlay />
{/* Onboarding Wizard */}
{showWizard && (