import SliderToggle from "@/components/Toggle" import { Button } from "@/components/ui/button" import { Sheet, SheetContent } from "@/components/ui/sheet" import { Link, useNavigate } from "@/hashParams" import { changeTheme, useTheme } from "@/ThemeProvider" import { Blocks, Code2, Database, FileCode2, FileText, Menu, RadioTower, Search, Send, Wallet, } from "lucide-react" import { FC, FormEvent, PropsWithChildren, useState } from "react" import { useLocation } from "react-router-dom" import { twMerge } from "tailwind-merge" import { NetworkSwitcher } from "./Network/Network" type NavigationItem = { path: string label: string icon: FC<{ size?: number; className?: string }> } const navigationGroups: Array<{ label: string items: NavigationItem[] }> = [ { label: "Core", items: [ { path: "/explorer", label: "Explorer", icon: Blocks }, { path: "/storage", label: "Storage", icon: Database }, { path: "/extrinsics", label: "Extrinsics", icon: Send }, { path: "/constants", label: "Constants", icon: FileText }, { path: "/runtimeCalls", label: "Runtime Calls", icon: Code2 }, { path: "/accounts", label: "Accounts", icon: Wallet }, ], }, { label: "Tools", items: [ { path: "/viewFns", label: "View Functions", icon: FileCode2 }, { path: "/metadata", label: "Metadata", icon: Blocks }, { path: "/rpcCalls", label: "RPC Calls", icon: RadioTower }, ], }, ] const navigationItems = navigationGroups.flatMap((group) => group.items) export const AppShell: FC = ({ children }) => { const [sidebarOpen, setSidebarOpen] = useState(false) return (
setSidebarOpen(false)} mobile />
setSidebarOpen(true)} />
{children}
) } const SidebarContent: FC<{ mobile?: boolean; onNavigate?: () => void }> = ({ mobile, onNavigate, }) => (
papi logo papi logo
papi{" "} console
beta
{mobile ? (
) : null}
GitHub
) const TopBar: FC<{ onOpenSidebar: () => void }> = ({ onOpenSidebar }) => { const location = useLocation() const activeItem = getActiveNavigationItem(location.pathname) return (
Section {activeItem.label}
) } const GlobalJumpSearch = () => { const navigate = useNavigate() const [value, setValue] = useState("") const handleSubmit = (evt: FormEvent) => { evt.preventDefault() const target = getJumpTarget(value) if (!target) return navigate(target) setValue("") } return (
) } const SidebarLink: FC<{ item: NavigationItem; onClick?: () => void }> = ({ item, onClick, }) => { const location = useLocation() const active = isNavigationItemActive(location.pathname, item.path) const Icon = item.icon return ( {item.label} ) } const getActiveNavigationItem = (pathname: string) => navigationItems.find((item) => isNavigationItemActive(pathname, item.path)) ?? navigationItems[0] const isNavigationItemActive = (pathname: string, path: string) => pathname === path || pathname.startsWith(`${path}/`) const getJumpTarget = (value: string) => { const query = value.trim() if (!query) return null if (query.startsWith("/")) return query const normalizedQuery = normalizeLabel(query) const exactSection = navigationItems.find( ({ label }) => normalizeLabel(label) === normalizedQuery, ) if (exactSection) return exactSection.path const matchingSection = navigationItems.find(({ label }) => normalizeLabel(label).startsWith(normalizedQuery), ) if (matchingSection) return matchingSection.path if (/^(0x[0-9a-f]+|\d+)$/i.test(query)) { return `/explorer/${query}` } return null } const normalizeLabel = (value: string) => value.toLowerCase().replace(/[\s_-]/g, "") const ThemeToggle = () => { const theme = useTheme() return ( ) }