UNPKG

bigblocks

Version:

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

17 lines 4.73 kB
{ "name": "profile-management-profilepopover", "type": "registry:component", "dependencies": [ "@radix-ui/react-icons" ], "devDependencies": [], "registryDependencies": [], "files": [ { "path": "components/profile-management/ProfilePopover.tsx", "type": "registry:component", "content": "\"use client\";\n\nimport { ChevronDownIcon } from \"@radix-ui/react-icons\";\nimport React from \"react\";\nimport { CONTAINER_WIDTHS } from \"../../lib/layout-constants.js\";\nimport type { ProfileInfo } from \"../../lib/types.js\";\nimport { BitcoinAvatar } from \"../ui-components/BitcoinAvatar.js\";\nimport { Button } from \"../ui/button.js\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../ui/popover.js\";\nimport { ProfileCard } from \"./ProfileCard.js\";\n\nexport interface ProfilePopoverProps {\n\tprofile: ProfileInfo;\n\tonEdit?: () => void;\n\tonSwitch?: () => void;\n\tonViewDetails?: () => void;\n\tchildren?: React.ReactNode;\n\talign?: \"start\" | \"center\" | \"end\";\n\tside?: \"top\" | \"right\" | \"bottom\" | \"left\";\n\tclassName?: string;\n\topenOnHover?: boolean; // defaults to true\n}\n\n/**\n * ProfilePopover - A popover trigger that shows profile details\n *\n * Features:\n * - Customizable trigger (defaults to avatar + name)\n * - ProfileCard in popover content\n * - Keyboard navigation support\n * - Accessible with ARIA labels\n */\nexport function ProfilePopover({\n\tprofile,\n\tonEdit,\n\tonSwitch,\n\tonViewDetails,\n\tchildren,\n\talign = \"center\",\n\tside = \"bottom\",\n\tclassName = \"\",\n\topenOnHover = true,\n}: ProfilePopoverProps) {\n\tconst [open, setOpen] = React.useState(false);\n\n\tconst getInitials = (name?: string) => {\n\t\tif (!name) return \"?\";\n\t\treturn name\n\t\t\t.split(\" \")\n\t\t\t.map((word) => word[0])\n\t\t\t.join(\"\")\n\t\t\t.toUpperCase()\n\t\t\t.slice(0, 2);\n\t};\n\n\treturn (\n\t\t<Popover open={open} onOpenChange={setOpen}>\n\t\t\t<div\n\t\t\t\tonMouseEnter={openOnHover ? () => setOpen(true) : undefined}\n\t\t\t\tonMouseLeave={openOnHover ? () => setOpen(false) : undefined}\n\t\t\t>\n\t\t\t\t<PopoverTrigger asChild>\n\t\t\t\t\t{children || (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\tclassName={className}\n\t\t\t\t\t\t\taria-label=\"View profile\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t<BitcoinAvatar\n\t\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\t\tsrc={profile.image}\n\t\t\t\t\t\t\t\t\talt={profile.name || \"Profile\"}\n\t\t\t\t\t\t\t\t\tfallback={getInitials(profile.name)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t<span className=\"text-sm font-medium\">\n\t\t\t\t\t\t\t\t\t{profile.name || \"Profile\"}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t<ChevronDownIcon className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t)}\n\t\t\t\t</PopoverTrigger>\n\t\t\t</div>\n\n\t\t\t<PopoverContent\n\t\t\t\talign={align}\n\t\t\t\tside={side}\n\t\t\t\tclassName=\"min-w-[320px]\"\n\t\t\t\tonMouseEnter={openOnHover ? () => setOpen(true) : undefined}\n\t\t\t\tonMouseLeave={openOnHover ? () => setOpen(false) : undefined}\n\t\t\t>\n\t\t\t\t<ProfileCard\n\t\t\t\t\tprofile={profile}\n\t\t\t\t\tonEdit={onEdit}\n\t\t\t\t\tonSwitch={onSwitch}\n\t\t\t\t\tonViewDetails={onViewDetails}\n\t\t\t\t\tshowActions={true}\n\t\t\t\t\tnoWrapper={true} // Don't wrap in Card since Popover.Content provides the container\n\t\t\t\t/>\n\t\t\t</PopoverContent>\n\t\t</Popover>\n\t);\n}\n\n/**\n * ProfilePopoverCompact - A compact version with just avatar\n */\nexport function ProfilePopoverCompact({\n\tprofile,\n\tonEdit,\n\tonSwitch,\n\tonViewDetails,\n\talign = \"center\",\n\tside = \"bottom\",\n\tclassName = \"\",\n\topenOnHover = true,\n}: Omit<ProfilePopoverProps, \"children\">) {\n\tconst getInitials = (name?: string) => {\n\t\tif (!name) return \"?\";\n\t\treturn name\n\t\t\t.split(\" \")\n\t\t\t.map((word) => word[0])\n\t\t\t.join(\"\")\n\t\t\t.toUpperCase()\n\t\t\t.slice(0, 2);\n\t};\n\n\treturn (\n\t\t<ProfilePopover\n\t\t\tprofile={profile}\n\t\t\tonEdit={onEdit}\n\t\t\tonSwitch={onSwitch}\n\t\t\tonViewDetails={onViewDetails}\n\t\t\talign={align}\n\t\t\tside={side}\n\t\t\topenOnHover={openOnHover}\n\t\t>\n\t\t\t<Button\n\t\t\t\tvariant=\"ghost\"\n\t\t\t\tsize=\"sm\"\n\t\t\t\tclassName={className}\n\t\t\t\taria-label=\"View profile\"\n\t\t\t>\n\t\t\t\t<BitcoinAvatar\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\tsrc={profile.image}\n\t\t\t\t\talt={profile.name || \"Profile\"}\n\t\t\t\t\tfallback={getInitials(profile.name)}\n\t\t\t\t/>\n\t\t\t</Button>\n\t\t</ProfilePopover>\n\t);\n}\n", "target": "<%- config.aliases.components %>/profilepopover.tsx" } ] }