UNPKG

bigblocks

Version:

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

15 lines 5.61 kB
{ "name": "metalens-components-metalensreactions", "type": "registry:component", "dependencies": [], "devDependencies": [], "registryDependencies": [], "files": [ { "path": "components/metalens/components/MetaLensReactions.tsx", "type": "registry:component", "content": "\"use client\";\n\nimport { useState } from \"react\";\nimport { Button } from \"../../ui/button.js\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../../ui/popover.js\";\n// Removed: import { responsive } from \"../../../lib/layout-constants.js\";\n\n/**\n * Reaction picker and display component\n *\n * Based on patterns from:\n * - Social media reaction systems\n * - /Users/satchmo/code/metalens.app/BIGBLOCKS_COMPONENT_PLAN.md\n *\n * @example\n * ```tsx\n * <MetaLensReactions\n * commentId=\"abc123\"\n * reactions={{ '👍': 5, '❤️': 2 }}\n * userReaction=\"👍\"\n * onReact={(emoji) => handleReaction(emoji)}\n * />\n * ```\n */\n\ninterface MetaLensReactionsProps {\n\tcommentId: string;\n\treactions: Record<string, number>;\n\tuserReaction?: string;\n\tonReact?: (emoji: string) => void;\n\tallowedReactions?: string[];\n\tsize?: \"1\" | \"2\" | \"3\";\n}\n\nexport function MetaLensReactions({\n\tcommentId: _commentId,\n\treactions = {},\n\tuserReaction,\n\tonReact,\n\tallowedReactions = [\"👍\", \"👎\", \"❤️\", \"🔥\", \"😂\", \"😮\", \"😢\", \"🎉\"],\n\tsize = \"2\",\n}: MetaLensReactionsProps) {\n\tconst [showPicker, setShowPicker] = useState(false);\n\tconst [hoveredEmoji, setHoveredEmoji] = useState<string | null>(null);\n\n\t// PSEUDOCODE for reaction handling:\n\n\t// 1. Reaction display logic\n\t// - Show top 3-5 reactions with counts\n\t// - Highlight user's reaction\n\t// - Animate on hover/click\n\t// - Batch similar reactions\n\n\t// 2. Reaction picker\n\t// - Grid layout of emojis\n\t// - Search/filter for many emojis\n\t// - Recent/frequent reactions\n\t// - Custom emoji support\n\n\t// 3. Animation effects\n\t// - Scale on hover\n\t// - Bounce on select\n\t// - +1 float animation\n\t// - Particle effects for special reactions\n\n\t// 4. Optimization\n\t// - Debounce reaction clicks\n\t// - Batch API calls\n\t// - Optimistic updates\n\n\t// Get sorted reactions (most used first)\n\tconst sortedReactions = Object.entries(reactions)\n\t\t.sort(([, a], [, b]) => b - a)\n\t\t.slice(0, 3);\n\n\tconst handleReaction = (emoji: string) => {\n\t\t// PSEUDOCODE:\n\t\t// 1. Optimistic update\n\t\t// 2. Call onReact\n\t\t// 3. Close picker\n\t\t// 4. Show animation\n\t\tonReact?.(emoji);\n\t\tsetShowPicker(false);\n\t};\n\n\treturn (\n\t\t<div className=\"flex items-center gap-2\">\n\t\t\t{/* Displayed reactions */}\n\t\t\t{sortedReactions.map(([emoji, count]) => (\n\t\t\t\t<Button\n\t\t\t\t\tkey={emoji}\n\t\t\t\t\tvariant={userReaction === emoji ? \"default\" : \"secondary\"}\n\t\t\t\t\tsize={size === \"1\" ? \"sm\" : size === \"2\" ? \"default\" : \"lg\"}\n\t\t\t\t\tonClick={() => handleReaction(emoji)}\n\t\t\t\t\tonMouseEnter={() => setHoveredEmoji(emoji)}\n\t\t\t\t\tonMouseLeave={() => setHoveredEmoji(null)}\n\t\t\t\t\tclassName=\"h-auto min-w-0 px-2 py-1 transition-transform duration-200 ease-in-out\"\n\t\t\t\t\tstyle={{\n\t\t\t\t\t\ttransform: hoveredEmoji === emoji ? \"scale(1.1)\" : \"scale(1)\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<span\n\t\t\t\t\t\tclassName={\n\t\t\t\t\t\t\tsize === \"1\" ? \"text-sm\" : size === \"2\" ? \"text-base\" : \"text-lg\"\n\t\t\t\t\t\t}\n\t\t\t\t\t>\n\t\t\t\t\t\t{emoji}\n\t\t\t\t\t</span>\n\t\t\t\t\t{count > 0 && (\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tclassName={`ml-1 font-medium ${size === \"1\" ? \"text-xs\" : \"text-sm\"}`}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{count}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t)}\n\t\t\t\t</Button>\n\t\t\t))}\n\n\t\t\t{/* Add reaction button */}\n\t\t\t<Popover open={showPicker} onOpenChange={setShowPicker}>\n\t\t\t\t<PopoverTrigger asChild>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tsize={size === \"1\" ? \"sm\" : size === \"2\" ? \"default\" : \"lg\"}\n\t\t\t\t\t\tclassName=\"h-auto min-w-0 px-2 py-1\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\twidth=\"16\"\n\t\t\t\t\t\t\theight=\"16\"\n\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\tstrokeWidth=\"2\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<title>Add reaction</title>\n\t\t\t\t\t\t\t<circle cx=\"12\" cy=\"12\" r=\"10\" />\n\t\t\t\t\t\t\t<path d=\"M8 14s1.5 2 4 2 4-2 4-2\" />\n\t\t\t\t\t\t\t<line x1=\"9\" y1=\"9\" x2=\"9.01\" y2=\"9\" />\n\t\t\t\t\t\t\t<line x1=\"15\" y1=\"9\" x2=\"15.01\" y2=\"9\" />\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t</Button>\n\t\t\t\t</PopoverTrigger>\n\n\t\t\t\t<PopoverContent className=\"p-2 max-w-72\">\n\t\t\t\t\t<div className=\"grid grid-cols-4 gap-1\">\n\t\t\t\t\t\t{allowedReactions.map((emoji) => (\n\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\tkey={emoji}\n\t\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\t\tsize=\"lg\"\n\t\t\t\t\t\t\t\tonClick={() => handleReaction(emoji)}\n\t\t\t\t\t\t\t\tclassName=\"aspect-square text-xl transition-transform duration-200 ease-in-out hover:scale-110\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{emoji}\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</div>\n\t\t\t\t</PopoverContent>\n\t\t\t</Popover>\n\n\t\t\t{/* Total reactions count */}\n\t\t\t{Object.keys(reactions).length > 3 && (\n\t\t\t\t<span className=\"text-xs text-muted-foreground\">\n\t\t\t\t\t+{Object.keys(reactions).length - 3} more\n\t\t\t\t</span>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n", "target": "<%- config.aliases.components %>/metalensreactions.tsx" } ] }