{"path":"apps/dashboard/src/App.tsx","size":9701,"locked":false,"binary":false,"truncated":false,"content":"import { useState } from \"react\";\nimport { Switch, Route, Router as WouterRouter, Link, useLocation } from \"wouter\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { Toaster } from \"@/components/ui/toaster\";\nimport { TooltipProvider } from \"@/components/ui/tooltip\";\nimport { Activity, LayoutDashboard, List, PlusCircle, X, Menu, Hexagon } from \"lucide-react\";\nimport { SolanaWalletProvider } from \"@/components/wallet-provider\";\nimport { WalletButton } from \"@/components/wallet-button\";\nimport NotFound from \"@/pages/not-found\";\n\nimport Dashboard from \"./pages/dashboard\";\nimport Jobs from \"./pages/jobs\";\nimport CreateJob from \"./pages/create-job\";\nimport JobDetail from \"./pages/job-detail\";\nimport Oracle from \"./pages/oracle\";\n\nconst queryClient = new QueryClient({\n  defaultOptions: {\n    queries: { staleTime: 10_000, retry: 1 },\n  },\n});\n\nconst NAV = [\n  { href: \"/\",         label: \"Dashboard\", icon: LayoutDashboard },\n  { href: \"/jobs\",     label: \"All Jobs\",  icon: List },\n  { href: \"/jobs/new\", label: \"Create\",    icon: PlusCircle },\n  { href: \"/oracle\",   label: \"Oracle\",    icon: Activity },\n];\n\nfunction Logo() {\n  return (\n    <div className=\"flex items-center gap-3\">\n      <div className=\"relative w-8 h-8 flex items-center justify-center shrink-0\">\n        <div className=\"absolute inset-0 bg-gradient-to-br from-emerald-400/20 to-purple-500/20 rounded-xl blur-sm\" />\n        <div className=\"relative w-8 h-8 rounded-xl bg-gradient-to-br from-emerald-500 to-emerald-400 flex items-center justify-center shadow-[0_0_16px_rgba(20,241,149,0.3)]\">\n          <Hexagon className=\"w-4 h-4 text-black fill-black/20\" strokeWidth={2.5} />\n        </div>\n      </div>\n      <div>\n        <div className=\"font-bold text-[13px] tracking-tight leading-none text-white\">Mappers</div>\n        <div className=\"text-[9px] text-emerald-400/60 font-mono leading-none mt-0.5 uppercase tracking-widest\">Protocol</div>\n      </div>\n    </div>\n  );\n}\n\nfunction DesktopSidebar({ location }: { location: string }) {\n  return (\n    <aside className=\"hidden md:flex flex-col w-60 shrink-0 min-h-screen relative\">\n      {/* Glass sidebar */}\n      <div className=\"absolute inset-0 bg-black/40 backdrop-blur-2xl border-r border-white/[0.06]\" />\n      {/* Gradient accent */}\n      <div className=\"absolute top-0 left-0 right-0 h-px bg-gradient-to-r from-transparent via-emerald-500/20 to-transparent\" />\n\n      <div className=\"relative z-10 flex flex-col h-full\">\n        <div className=\"h-16 flex items-center px-5 border-b border-white/[0.05]\">\n          <Logo />\n        </div>\n\n        <nav className=\"flex-1 py-4 px-3 space-y-1\">\n          {NAV.map(({ href, label, icon: Icon }) => {\n            const active = location === href || (href === \"/jobs\" && location.startsWith(\"/jobs/\") && location !== \"/jobs/new\");\n            return (\n              <Link\n                key={href}\n                href={href}\n                className={`group flex items-center gap-3 px-3 py-2.5 text-sm font-mono rounded-xl transition-all duration-200 ${\n                  active\n                    ? \"bg-gradient-to-r from-emerald-500/15 to-emerald-500/5 text-emerald-400 border border-emerald-500/20 shadow-[0_0_20px_rgba(20,241,149,0.05)]\"\n                    : \"text-white/40 hover:text-white/80 hover:bg-white/[0.04] border border-transparent\"\n                }`}\n              >\n                <Icon className={`w-4 h-4 shrink-0 transition-all ${active ? \"text-emerald-400\" : \"group-hover:text-white/70\"}`} />\n                {label}\n                {active && <div className=\"ml-auto w-1.5 h-1.5 rounded-full bg-emerald-400 shadow-[0_0_6px_rgba(20,241,149,0.8)]\" />}\n              </Link>\n            );\n          })}\n        </nav>\n\n        <div className=\"px-3 pb-4 pt-2 border-t border-white/[0.05] space-y-3\">\n          <WalletButton />\n          <div className=\"glass rounded-xl px-3 py-2.5 space-y-1\">\n            <div className=\"flex items-center gap-1.5\">\n              <div className=\"w-1.5 h-1.5 rounded-full bg-emerald-400 animate-pulse shadow-[0_0_6px_rgba(20,241,149,0.8)]\" />\n              <span className=\"text-[9px] font-mono text-emerald-400/80 uppercase tracking-widest\">Devnet</span>\n            </div>\n            <div className=\"text-[9px] font-mono text-white/30 truncate\">52yt1g…KX2Mu</div>\n          </div>\n        </div>\n      </div>\n    </aside>\n  );\n}\n\nfunction MobileHeader({ onMenu }: { onMenu: () => void }) {\n  return (\n    <header className=\"md:hidden flex items-center justify-between h-14 px-4 border-b border-white/[0.06] bg-black/40 backdrop-blur-2xl shrink-0 gap-2 relative z-30\">\n      <Logo />\n      <div className=\"flex items-center gap-2\">\n        <WalletButton compact />\n        <button\n          onClick={onMenu}\n          className=\"w-9 h-9 flex items-center justify-center text-white/40 hover:text-white/80 glass rounded-xl transition-all duration-200 active:scale-95\"\n          aria-label=\"Open menu\"\n        >\n          <Menu className=\"w-4.5 h-4.5\" />\n        </button>\n      </div>\n    </header>\n  );\n}\n\nfunction MobileDrawer({\n  open,\n  onClose,\n  location,\n}: {\n  open: boolean;\n  onClose: () => void;\n  location: string;\n}) {\n  if (!open) return null;\n  return (\n    <div className=\"md:hidden fixed inset-0 z-50 flex\">\n      <div\n        className=\"absolute inset-0 bg-black/70 backdrop-blur-sm\"\n        onClick={onClose}\n      />\n      <div className=\"relative w-72 max-w-[85vw] bg-black/80 backdrop-blur-2xl border-r border-white/[0.07] flex flex-col shadow-[4px_0_32px_rgba(0,0,0,0.6)] animate-in slide-in-from-left-4 duration-200\">\n        <div className=\"h-14 flex items-center justify-between px-5 border-b border-white/[0.06]\">\n          <Logo />\n          <button\n            onClick={onClose}\n            className=\"w-8 h-8 flex items-center justify-center text-white/40 hover:text-white/80 glass rounded-lg transition-all active:scale-95\"\n          >\n            <X className=\"w-4 h-4\" />\n          </button>\n        </div>\n        <nav className=\"flex-1 py-4 px-3 space-y-1\">\n          {NAV.map(({ href, label, icon: Icon }) => {\n            const active = location === href;\n            return (\n              <Link\n                key={href}\n                href={href}\n                onClick={onClose}\n                className={`group flex items-center gap-3 px-3 py-3 text-sm font-mono rounded-xl transition-all duration-200 ${\n                  active\n                    ? \"bg-emerald-500/15 text-emerald-400 border border-emerald-500/20\"\n                    : \"text-white/40 hover:text-white/80 hover:bg-white/[0.04] border border-transparent\"\n                }`}\n              >\n                <Icon className=\"w-4 h-4 shrink-0\" />\n                {label}\n              </Link>\n            );\n          })}\n        </nav>\n        <div className=\"px-4 py-4 border-t border-white/[0.05] space-y-3\">\n          <WalletButton />\n          <div className=\"text-[9px] font-mono text-white/30 space-y-0.5\">\n            <div className=\"text-emerald-400/60 font-medium uppercase tracking-widest\">Solana Devnet</div>\n            <div className=\"break-all text-[8.5px] leading-relaxed\">\n              52yt1gCbPeiKP4JYjUVKmMJSgBMMcUx8xRGqozMKX2Mu\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nfunction MobileBottomNav({ location }: { location: string }) {\n  return (\n    <nav className=\"md:hidden fixed bottom-0 left-0 right-0 z-40 flex border-t border-white/[0.06] bg-black/70 backdrop-blur-2xl\">\n      {NAV.map(({ href, label, icon: Icon }) => {\n        const active = location === href;\n        return (\n          <Link\n            key={href}\n            href={href}\n            className={`flex-1 flex flex-col items-center justify-center gap-1 py-2.5 min-h-[56px] transition-all duration-200 ${\n              active ? \"text-emerald-400\" : \"text-white/30 hover:text-white/60\"\n            }`}\n          >\n            <Icon className={`w-5 h-5 transition-all ${active ? \"drop-shadow-[0_0_6px_rgba(20,241,149,0.6)]\" : \"\"}`} strokeWidth={active ? 2.5 : 2} />\n            <span className=\"text-[9px] font-mono uppercase tracking-wider\">{label}</span>\n          </Link>\n        );\n      })}\n    </nav>\n  );\n}\n\nfunction Shell({ children }: { children: React.ReactNode }) {\n  const [location] = useLocation();\n  const [drawerOpen, setDrawerOpen] = useState(false);\n\n  return (\n    <div className=\"flex min-h-dvh w-full\">\n      <DesktopSidebar location={location} />\n\n      <MobileDrawer\n        open={drawerOpen}\n        onClose={() => setDrawerOpen(false)}\n        location={location}\n      />\n\n      <div className=\"flex-1 flex flex-col min-w-0\">\n        <MobileHeader onMenu={() => setDrawerOpen(true)} />\n        <main className=\"flex-1 flex flex-col pb-16 md:pb-0 min-w-0\">\n          {children}\n        </main>\n      </div>\n\n      <MobileBottomNav location={location} />\n    </div>\n  );\n}\n\nfunction Router() {\n  return (\n    <Shell>\n      <Switch>\n        <Route path=\"/\" component={Dashboard} />\n        <Route path=\"/jobs\" component={Jobs} />\n        <Route path=\"/jobs/new\" component={CreateJob} />\n        <Route path=\"/jobs/:jobId\" component={JobDetail} />\n        <Route path=\"/oracle\" component={Oracle} />\n        <Route component={NotFound} />\n      </Switch>\n    </Shell>\n  );\n}\n\nexport default function App() {\n  return (\n    <SolanaWalletProvider>\n      <QueryClientProvider client={queryClient}>\n        <TooltipProvider>\n          <WouterRouter base={import.meta.env.BASE_URL.replace(/\\/$/, \"\")}>\n            <Router />\n          </WouterRouter>\n          <Toaster />\n        </TooltipProvider>\n      </QueryClientProvider>\n    </SolanaWalletProvider>\n  );\n}\n"}