Skip to main content
Glama

Karakeep MCP server

by karakeep-app
lists.tsx4.84 kB
import { useEffect, useState } from "react"; import { FlatList, Pressable, View } from "react-native"; import * as Haptics from "expo-haptics"; import { Link, router } from "expo-router"; import FullPageError from "@/components/FullPageError"; import ChevronRight from "@/components/ui/ChevronRight"; import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView"; import FullPageSpinner from "@/components/ui/FullPageSpinner"; import PageTitle from "@/components/ui/PageTitle"; import { Text } from "@/components/ui/Text"; import { api } from "@/lib/trpc"; import { useColorScheme } from "@/lib/useColorScheme"; import { condProps } from "@/lib/utils"; import { Plus } from "lucide-react-native"; import { useBookmarkLists } from "@karakeep/shared-react/hooks/lists"; import { ZBookmarkListTreeNode } from "@karakeep/shared/utils/listUtils"; function HeaderRight({ openNewListModal }: { openNewListModal: () => void }) { return ( <Pressable className="my-auto px-4" onPress={() => { Haptics.selectionAsync(); openNewListModal(); }} > <Plus color="rgb(0, 122, 255)" /> </Pressable> ); } interface ListLink { id: string; logo: string; name: string; href: string; level: number; parent?: string; numChildren: number; collapsed: boolean; } function traverseTree( node: ZBookmarkListTreeNode, links: ListLink[], showChildrenOf: Record<string, boolean>, parent?: string, level = 0, ) { links.push({ id: node.item.id, logo: node.item.icon, name: node.item.name, href: `/dashboard/lists/${node.item.id}`, level, parent, numChildren: node.children?.length ?? 0, collapsed: !showChildrenOf[node.item.id], }); if (node.children && showChildrenOf[node.item.id]) { node.children.forEach((child) => traverseTree(child, links, showChildrenOf, node.item.id, level + 1), ); } } export default function Lists() { const { colors } = useColorScheme(); const [refreshing, setRefreshing] = useState(false); const { data: lists, isPending, error, refetch } = useBookmarkLists(); const [showChildrenOf, setShowChildrenOf] = useState<Record<string, boolean>>( {}, ); const apiUtils = api.useUtils(); useEffect(() => { setRefreshing(isPending); }, [isPending]); if (error) { return <FullPageError error={error.message} onRetry={() => refetch()} />; } if (!lists) { return <FullPageSpinner />; } const onRefresh = () => { apiUtils.lists.list.invalidate(); }; const links: ListLink[] = [ { id: "fav", logo: "⭐️", name: "Favourites", href: "/dashboard/favourites", level: 0, numChildren: 0, collapsed: false, }, { id: "arch", logo: "🗄️", name: "Archive", href: "/dashboard/archive", level: 0, numChildren: 0, collapsed: false, }, ]; Object.values(lists.root).forEach((list) => traverseTree(list, links, showChildrenOf), ); return ( <CustomSafeAreaView> <FlatList className="h-full" ListHeaderComponent={ <View className="flex flex-row justify-between"> <PageTitle title="Lists" /> <HeaderRight openNewListModal={() => router.push("/dashboard/lists/new")} /> </View> } contentContainerStyle={{ gap: 5, }} renderItem={(l) => ( <View className="mx-2 flex flex-row items-center rounded-xl border border-input bg-card px-4 py-2" style={condProps({ condition: l.item.level > 0, props: { marginLeft: l.item.level * 20 }, })} > {l.item.numChildren > 0 && ( <Pressable className="pr-2" onPress={() => { setShowChildrenOf((prev) => ({ ...prev, [l.item.id]: !prev[l.item.id], })); }} > <ChevronRight color={colors.foreground} style={{ transform: [ { rotate: l.item.collapsed ? "0deg" : "90deg" }, ], }} /> </Pressable> )} <Link asChild key={l.item.id} href={l.item.href} className="flex-1"> <Pressable className="flex flex-row justify-between"> <Text> {l.item.logo} {l.item.name} </Text> <ChevronRight /> </Pressable> </Link> </View> )} data={links} refreshing={refreshing} onRefresh={onRefresh} /> </CustomSafeAreaView> ); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/karakeep-app/karakeep'

If you have feedback or need assistance with the MCP directory API, please join our Discord server