repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | "use client"; |
| #2 | |
| #3 | import { Button } from "@/components/ui/button"; |
| #4 | import { HiHome, HiMiniRectangleStack } from "react-icons/hi2"; |
| #5 | import { RiApps2AddFill } from "react-icons/ri"; |
| #6 | import { FiRefreshCcw } from "react-icons/fi"; |
| #7 | import Link from "next/link"; |
| #8 | import { usePathname } from "next/navigation"; |
| #9 | import { CreateMemoryDialog } from "@/app/memories/components/CreateMemoryDialog"; |
| #10 | import { useMemoriesApi } from "@/hooks/useMemoriesApi"; |
| #11 | import Image from "next/image"; |
| #12 | import { useStats } from "@/hooks/useStats"; |
| #13 | import { useAppsApi } from "@/hooks/useAppsApi"; |
| #14 | import { Settings } from "lucide-react"; |
| #15 | import { useConfig } from "@/hooks/useConfig"; |
| #16 | |
| #17 | export function Navbar() { |
| #18 | const pathname = usePathname(); |
| #19 | |
| #20 | const memoriesApi = useMemoriesApi(); |
| #21 | const appsApi = useAppsApi(); |
| #22 | const statsApi = useStats(); |
| #23 | const configApi = useConfig(); |
| #24 | |
| #25 | // Define route matchers with typed parameter extraction |
| #26 | const routeBasedFetchMapping: { |
| #27 | match: RegExp; |
| #28 | getFetchers: (params: Record<string, string>) => (() => Promise<any>)[]; |
| #29 | }[] = [ |
| #30 | { |
| #31 | match: /^\/memory\/([^/]+)$/, |
| #32 | getFetchers: ({ memory_id }) => [ |
| #33 | () => memoriesApi.fetchMemoryById(memory_id), |
| #34 | () => memoriesApi.fetchAccessLogs(memory_id), |
| #35 | () => memoriesApi.fetchRelatedMemories(memory_id), |
| #36 | ], |
| #37 | }, |
| #38 | { |
| #39 | match: /^\/apps\/([^/]+)$/, |
| #40 | getFetchers: ({ app_id }) => [ |
| #41 | () => appsApi.fetchAppMemories(app_id), |
| #42 | () => appsApi.fetchAppAccessedMemories(app_id), |
| #43 | () => appsApi.fetchAppDetails(app_id), |
| #44 | ], |
| #45 | }, |
| #46 | { |
| #47 | match: /^\/memories$/, |
| #48 | getFetchers: () => [memoriesApi.fetchMemories], |
| #49 | }, |
| #50 | { |
| #51 | match: /^\/apps$/, |
| #52 | getFetchers: () => [appsApi.fetchApps], |
| #53 | }, |
| #54 | { |
| #55 | match: /^\/$/, |
| #56 | getFetchers: () => [statsApi.fetchStats, memoriesApi.fetchMemories], |
| #57 | }, |
| #58 | { |
| #59 | match: /^\/settings$/, |
| #60 | getFetchers: () => [configApi.fetchConfig], |
| #61 | }, |
| #62 | ]; |
| #63 | |
| #64 | const getFetchersForPath = (path: string) => { |
| #65 | for (const route of routeBasedFetchMapping) { |
| #66 | const match = path.match(route.match); |
| #67 | if (match) { |
| #68 | if (route.match.source.includes("memory")) { |
| #69 | return route.getFetchers({ memory_id: match[1] }); |
| #70 | } |
| #71 | if (route.match.source.includes("app")) { |
| #72 | return route.getFetchers({ app_id: match[1] }); |
| #73 | } |
| #74 | return route.getFetchers({}); |
| #75 | } |
| #76 | } |
| #77 | return []; |
| #78 | }; |
| #79 | |
| #80 | const handleRefresh = async () => { |
| #81 | const fetchers = getFetchersForPath(pathname); |
| #82 | await Promise.allSettled(fetchers.map((fn) => fn())); |
| #83 | }; |
| #84 | |
| #85 | const isActive = (href: string) => { |
| #86 | if (href === "/") return pathname === href; |
| #87 | return pathname.startsWith(href.substring(0, 5)); |
| #88 | }; |
| #89 | |
| #90 | const activeClass = "bg-zinc-800 text-white border-zinc-600"; |
| #91 | const inactiveClass = "text-zinc-300"; |
| #92 | |
| #93 | return ( |
| #94 | <header className="sticky top-0 z-50 w-full border-b border-zinc-800 bg-zinc-950/95 backdrop-blur supports-[backdrop-filter]:bg-zinc-950/60"> |
| #95 | <div className="container flex h-14 items-center justify-between"> |
| #96 | <Link href="/" className="flex items-center gap-2"> |
| #97 | <Image src="/logo.svg" alt="OpenMemory" width={26} height={26} /> |
| #98 | <span className="text-xl font-medium">OpenMemory</span> |
| #99 | </Link> |
| #100 | <div className="flex items-center gap-2"> |
| #101 | <Link href="/"> |
| #102 | <Button |
| #103 | variant="outline" |
| #104 | size="sm" |
| #105 | className={`flex items-center gap-2 border-none ${ |
| #106 | isActive("/") ? activeClass : inactiveClass |
| #107 | }`} |
| #108 | > |
| #109 | <HiHome /> |
| #110 | Dashboard |
| #111 | </Button> |
| #112 | </Link> |
| #113 | <Link href="/memories"> |
| #114 | <Button |
| #115 | variant="outline" |
| #116 | size="sm" |
| #117 | className={`flex items-center gap-2 border-none ${ |
| #118 | isActive("/memories") ? activeClass : inactiveClass |
| #119 | }`} |
| #120 | > |
| #121 | <HiMiniRectangleStack /> |
| #122 | Memories |
| #123 | </Button> |
| #124 | </Link> |
| #125 | <Link href="/apps"> |
| #126 | <Button |
| #127 | variant="outline" |
| #128 | size="sm" |
| #129 | className={`flex items-center gap-2 border-none ${ |
| #130 | isActive("/apps") ? activeClass : inactiveClass |
| #131 | }`} |
| #132 | > |
| #133 | <RiApps2AddFill /> |
| #134 | Apps |
| #135 | </Button> |
| #136 | </Link> |
| #137 | <Link href="/settings"> |
| #138 | <Button |
| #139 | variant="outline" |
| #140 | size="sm" |
| #141 | className={`flex items-center gap-2 border-none ${ |
| #142 | isActive("/settings") ? activeClass : inactiveClass |
| #143 | }`} |
| #144 | > |
| #145 | <Settings /> |
| #146 | Settings |
| #147 | </Button> |
| #148 | </Link> |
| #149 | </div> |
| #150 | <div className="flex items-center gap-4"> |
| #151 | <Button |
| #152 | onClick={handleRefresh} |
| #153 | variant="outline" |
| #154 | size="sm" |
| #155 | className="border-zinc-700/50 bg-zinc-900 hover:bg-zinc-800" |
| #156 | > |
| #157 | <FiRefreshCcw className="transition-transform duration-300 group-hover:rotate-180" /> |
| #158 | Refresh |
| #159 | </Button> |
| #160 | <CreateMemoryDialog /> |
| #161 | </div> |
| #162 | </div> |
| #163 | </header> |
| #164 | ); |
| #165 | } |
| #166 |