UNPKG

bigblocks

Version:

Complete Bitcoin UI component library - authentication, social, wallet, market, inscriptions, and blockchain interactions for React

15 lines 6.49 kB
{ "name": "metalens-components-metalensprovider", "type": "registry:component", "dependencies": [], "devDependencies": [], "registryDependencies": [], "files": [ { "path": "components/metalens/components/MetaLensProvider.tsx", "type": "registry:component", "content": "\"use client\";\n\nimport { createContext, useContext, useEffect, useMemo, useRef } from \"react\";\nimport { DROPLIT_API_URL } from \"../../droplit/constants.js\";\nimport type { MetaLensConfig, MetaLensProviderProps } from \"../types/index.js\";\n\n/**\n * MetaLens context provider that manages configuration and state\n *\n * Based on patterns from:\n * - /Users/satchmo/code/metalens.app/BIGBLOCKS_COMPONENT_PLAN.md\n * - TonicPow MetaLens implementation\n *\n * @example\n * ```tsx\n * <MetaLensProvider config={{\n * apiUrl: 'https://custom-api.com',\n * theme: { buttonBackground: '#7a89d6' }\n * }}>\n * <App />\n * </MetaLensProvider>\n * ```\n */\n\ninterface MetaLensContextValue {\n\tconfig: Required<MetaLensConfig>;\n\teventSourceManager: EventSourceManager;\n\tapiClient: MetaLensAPIClient;\n}\n\n// Simple EventSource manager for real-time updates\nclass EventSourceManager {\n\tprivate connections: Map<string, EventSource> = new Map();\n\tprivate baseUrl: string;\n\n\tconstructor(baseUrl: string) {\n\t\tthis.baseUrl = baseUrl;\n\t}\n\n\tconnect(\n\t\tkey: string,\n\t\tpath: string,\n\t\thandlers: Record<string, (event: MessageEvent) => void>,\n\t) {\n\t\t// Close existing connection\n\t\tthis.disconnect(key);\n\n\t\ttry {\n\t\t\tconst url = `${this.baseUrl}${path}`;\n\t\t\tconst eventSource = new EventSource(url);\n\n\t\t\t// Set up event handlers\n\t\t\tfor (const [event, handler] of Object.entries(handlers)) {\n\t\t\t\teventSource.addEventListener(event, handler);\n\t\t\t}\n\n\t\t\t// Store connection\n\t\t\tthis.connections.set(key, eventSource);\n\n\t\t\treturn eventSource;\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Failed to create EventSource:\", error);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tdisconnect(key: string) {\n\t\tconst connection = this.connections.get(key);\n\t\tif (connection) {\n\t\t\tconnection.close();\n\t\t\tthis.connections.delete(key);\n\t\t}\n\t}\n\n\tdisconnectAll() {\n\t\tfor (const connection of this.connections.values()) {\n\t\t\tconnection.close();\n\t\t}\n\t\tthis.connections.clear();\n\t}\n}\n\n// BMAP API client for MetaLens\nclass MetaLensAPIClient {\n\tprivate baseUrl: string;\n\n\tconstructor(baseUrl: string) {\n\t\tthis.baseUrl = baseUrl;\n\t}\n\n\tasync fetchComments(context: string, value: string, options?: RequestInit) {\n\t\t// For now, search for comments that contain the context value\n\t\t// This is a simplified approach until we have proper MetaLens protocol data\n\t\tconst searchQuery = encodeURIComponent(`${context}:${value}`);\n\t\tconst params = new URLSearchParams({\n\t\t\tq: searchQuery,\n\t\t\tlimit: \"50\", // Get more comments for better results\n\t\t});\n\n\t\tconst response = await fetch(\n\t\t\t`${this.baseUrl}/social/post/search?${params}`,\n\t\t\toptions,\n\t\t);\n\t\tif (!response.ok) throw new Error(\"Failed to fetch comments from BMAP API\");\n\n\t\tconst data = await response.json();\n\n\t\t// Return the BMAP API response format\n\t\treturn {\n\t\t\tresults: data.results || [],\n\t\t\tsigners: data.signers || [],\n\t\t\tmeta: data.meta || [],\n\t\t\tcount: data.count || 0,\n\t\t\tpage: data.page || 1,\n\t\t\tlimit: data.limit || 50,\n\t\t};\n\t}\n\n\tasync getCommentCount(context: string, value: string) {\n\t\ttry {\n\t\t\tconst response = await this.fetchComments(context, value);\n\t\t\treturn response.count || 0;\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Failed to get comment count:\", error);\n\t\t\treturn 0;\n\t\t}\n\t}\n}\n\nconst MetaLensContext = createContext<MetaLensContextValue | null>(null);\n\nexport function MetaLensProvider({\n\tconfig = {},\n\tchildren,\n}: MetaLensProviderProps) {\n\tconst mergedConfig = useMemo<Required<MetaLensConfig>>(\n\t\t() => ({\n\t\t\t// Default values based on research\n\t\t\tapiUrl: config.apiUrl || \"https://bmap-api-production.up.railway.app\",\n\t\t\tfaucetUrl: config.faucetUrl || DROPLIT_API_URL, // droplit push endpoint\n\t\t\tappName: config.appName || \"bigblocks-metalens\",\n\t\t\ttheme: {\n\t\t\t\tbackground: \"transparent\",\n\t\t\t\tbuttonBackground: \"hsl(var(--primary))\",\n\t\t\t\tbuttonColor: \"hsl(var(--primary-foreground))\",\n\t\t\t\tcolor: \"hsl(var(--foreground))\",\n\t\t\t\tinputBackground: \"transparent\",\n\t\t\t\tinputColor: \"hsl(var(--foreground))\",\n\t\t\t\tinputBorder: \"hsl(var(--border))\",\n\t\t\t\t...config.theme,\n\t\t\t},\n\t\t\tenableRealTime: config.enableRealTime ?? true,\n\t\t\tenableModeration: config.enableModeration ?? false,\n\t\t\tmoderationWords: config.moderationWords || [],\n\t\t}),\n\t\t[config],\n\t);\n\n\t// Initialize API client\n\tconst apiClient = useMemo(() => {\n\t\treturn new MetaLensAPIClient(mergedConfig.apiUrl);\n\t}, [mergedConfig.apiUrl]);\n\n\t// Initialize EventSource manager\n\tconst eventSourceManagerRef = useRef<EventSourceManager | null>(null);\n\tif (!eventSourceManagerRef.current) {\n\t\teventSourceManagerRef.current = new EventSourceManager(mergedConfig.apiUrl);\n\t}\n\n\tuseEffect(() => {\n\t\t// Update base URL if it changes\n\t\teventSourceManagerRef.current = new EventSourceManager(mergedConfig.apiUrl);\n\n\t\treturn () => {\n\t\t\teventSourceManagerRef.current?.disconnectAll();\n\t\t};\n\t}, [mergedConfig.apiUrl]);\n\n\t// Theme injection for CSS variables\n\tuseEffect(() => {\n\t\tif (typeof document !== \"undefined\") {\n\t\t\tconst root = document.documentElement;\n\t\t\tfor (const [key, value] of Object.entries(mergedConfig.theme)) {\n\t\t\t\troot.style.setProperty(`--metalens-${key}`, value);\n\t\t\t}\n\t\t}\n\t}, [mergedConfig.theme]);\n\n\tconst contextValue: MetaLensContextValue = {\n\t\tconfig: mergedConfig,\n\t\tapiClient,\n\t\teventSourceManager:\n\t\t\teventSourceManagerRef.current ||\n\t\t\tnew EventSourceManager(mergedConfig.apiUrl),\n\t};\n\n\treturn (\n\t\t<MetaLensContext.Provider value={contextValue}>\n\t\t\t{children}\n\t\t</MetaLensContext.Provider>\n\t);\n}\n\nexport function useMetaLensProvider() {\n\tconst context = useContext(MetaLensContext);\n\tif (!context) {\n\t\tthrow new Error(\"useMetaLensProvider must be used within MetaLensProvider\");\n\t}\n\treturn context;\n}\n", "target": "<%- config.aliases.components %>/metalensprovider.tsx" } ] }