bigblocks
Version:
Complete Bitcoin UI component library - authentication, social, wallet, market, inscriptions, and blockchain interactions for React
15 lines • 7.16 kB
JSON
{
"name": "profile-management-profileswitcher",
"type": "registry:component",
"dependencies": [],
"devDependencies": [],
"registryDependencies": [],
"files": [
{
"path": "components/profile-management/ProfileSwitcher.tsx",
"type": "registry:component",
"content": "\"use client\";\nimport {\n\tCheckIcon,\n\tChevronDownIcon,\n\tPersonIcon,\n\tPlusIcon,\n} from \"@radix-ui/react-icons\";\nimport { CONTAINER_WIDTHS } from \"../../lib/layout-constants.js\";\nimport type { ProfileInfo } from \"../../lib/types.js\";\nimport { cn } from \"../../lib/utils.js\";\nimport { Avatar, AvatarFallback, AvatarImage } from \"../ui/avatar.js\";\nimport { Button } from \"../ui/button.js\";\nimport {\n\tDropdownMenu,\n\tDropdownMenuContent,\n\tDropdownMenuItem,\n\tDropdownMenuLabel,\n\tDropdownMenuSeparator,\n\tDropdownMenuTrigger,\n} from \"../ui/dropdown-menu.js\";\nimport { ProfileCard } from \"./ProfileCard.js\";\n\nexport interface ProfileSwitcherProps {\n\tprofiles: ProfileInfo[];\n\tactiveProfileId: string;\n\tonSwitch: (profileId: string) => void;\n\tonCreate?: () => void;\n\tmaxProfiles?: number;\n\tclassName?: string;\n\tsize?: \"1\" | \"2\" | \"3\" | \"4\";\n\tvariant?: \"solid\" | \"soft\" | \"ghost\" | \"surface\";\n}\n\n/**\n * ProfileSwitcher allows switching between multiple BAP profiles\n *\n * Features:\n * - Dropdown menu with all available profiles\n * - Active profile indication\n * - Create new profile option\n * - Profile avatar and details\n * - Published/unpublished status badges\n */\nexport function ProfileSwitcher({\n\tprofiles,\n\tactiveProfileId,\n\tonSwitch,\n\tonCreate,\n\tmaxProfiles = 10,\n\tclassName = \"\",\n\tsize = \"2\",\n\tvariant = \"soft\",\n}: ProfileSwitcherProps) {\n\tconst activeProfile = profiles.find((p) => p.id === activeProfileId);\n\tconst canCreateMore = profiles.length < maxProfiles;\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<DropdownMenu>\n\t\t\t<DropdownMenuTrigger asChild>\n\t\t\t\t<Button\n\t\t\t\t\tvariant={\n\t\t\t\t\t\tvariant === \"soft\"\n\t\t\t\t\t\t\t? \"secondary\"\n\t\t\t\t\t\t\t: variant === \"ghost\"\n\t\t\t\t\t\t\t\t? \"ghost\"\n\t\t\t\t\t\t\t\t: \"default\"\n\t\t\t\t\t}\n\t\t\t\t\tsize={\n\t\t\t\t\t\tsize === \"1\"\n\t\t\t\t\t\t\t? \"sm\"\n\t\t\t\t\t\t\t: size === \"3\" || size === \"4\"\n\t\t\t\t\t\t\t\t? \"lg\"\n\t\t\t\t\t\t\t\t: \"default\"\n\t\t\t\t\t}\n\t\t\t\t\tclassName={cn(\"flex items-center gap-2\", className)}\n\t\t\t\t>\n\t\t\t\t\t<Avatar className=\"h-5 w-5\">\n\t\t\t\t\t\t<AvatarImage src={activeProfile?.image} />\n\t\t\t\t\t\t<AvatarFallback>{getInitials(activeProfile?.name)}</AvatarFallback>\n\t\t\t\t\t</Avatar>\n\t\t\t\t\t<span>{activeProfile?.name || \"Select Profile\"}</span>\n\t\t\t\t\t<ChevronDownIcon className=\"h-4 w-4\" />\n\t\t\t\t</Button>\n\t\t\t</DropdownMenuTrigger>\n\n\t\t\t<DropdownMenuContent style={{ minWidth: CONTAINER_WIDTHS.POPOVER_SMALL }}>\n\t\t\t\t<DropdownMenuLabel>Switch Profile</DropdownMenuLabel>\n\n\t\t\t\t{/* Profile List using ProfileCard compact mode */}\n\t\t\t\t{profiles.map((profile) => (\n\t\t\t\t\t<DropdownMenuItem\n\t\t\t\t\t\tkey={profile.id}\n\t\t\t\t\t\tonSelect={() => onSwitch(profile.id)}\n\t\t\t\t\t\tclassName=\"p-0\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<ProfileCard\n\t\t\t\t\t\t\tprofile={profile}\n\t\t\t\t\t\t\tcompact\n\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\tonSwitch={() => onSwitch(profile.id)}\n\t\t\t\t\t\t\tstatus={\n\t\t\t\t\t\t\t\tprofile.id === activeProfileId\n\t\t\t\t\t\t\t\t\t? { label: \"Active\", color: \"green\", variant: \"soft\" }\n\t\t\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\t\t\t\tcursor: \"pointer\",\n\t\t\t\t\t\t\t\tborderRadius: \"calc(var(--radius) * 0.5)\",\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</DropdownMenuItem>\n\t\t\t\t))}\n\n\t\t\t\t{/* Create New Profile */}\n\t\t\t\t{onCreate && canCreateMore && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<DropdownMenuSeparator />\n\t\t\t\t\t\t<DropdownMenuItem onSelect={onCreate}>\n\t\t\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t\t\t<div className=\"w-8 h-8 rounded bg-muted flex items-center justify-center\">\n\t\t\t\t\t\t\t\t\t<PlusIcon className=\"h-4 w-4\" />\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<span className=\"text-sm font-medium\">Create New Profile</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</DropdownMenuItem>\n\t\t\t\t\t</>\n\t\t\t\t)}\n\n\t\t\t\t{/* Profile Limit Warning */}\n\t\t\t\t{!canCreateMore && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<DropdownMenuSeparator />\n\t\t\t\t\t\t<div className=\"px-3 py-2\">\n\t\t\t\t\t\t\t<p className=\"text-xs text-muted-foreground\">\n\t\t\t\t\t\t\t\tMaximum of {maxProfiles} profiles reached\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</DropdownMenuContent>\n\t\t</DropdownMenu>\n\t);\n}\n\n/**\n * ProfileSwitcherCompact - A more compact version for space-constrained areas\n */\nexport function ProfileSwitcherCompact({\n\tprofiles,\n\tactiveProfileId,\n\tonSwitch,\n\tclassName = \"\",\n}: Pick<\n\tProfileSwitcherProps,\n\t\"profiles\" | \"activeProfileId\" | \"onSwitch\" | \"className\"\n>) {\n\tconst activeProfile = profiles.find((p) => p.id === activeProfileId);\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<DropdownMenu>\n\t\t\t<DropdownMenuTrigger asChild>\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\tsize=\"default\"\n\t\t\t\t\tclassName={cn(\"p-0 w-10 h-10\", className)}\n\t\t\t\t>\n\t\t\t\t\t<Avatar className=\"h-8 w-8\">\n\t\t\t\t\t\t<AvatarImage src={activeProfile?.image} />\n\t\t\t\t\t\t<AvatarFallback>{getInitials(activeProfile?.name)}</AvatarFallback>\n\t\t\t\t\t</Avatar>\n\t\t\t\t</Button>\n\t\t\t</DropdownMenuTrigger>\n\n\t\t\t<DropdownMenuContent>\n\t\t\t\t<DropdownMenuLabel>\n\t\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t\t<PersonIcon className=\"h-4 w-4\" />\n\t\t\t\t\t\tProfiles\n\t\t\t\t\t</div>\n\t\t\t\t</DropdownMenuLabel>\n\n\t\t\t\t{profiles.map((profile) => (\n\t\t\t\t\t<DropdownMenuItem\n\t\t\t\t\t\tkey={profile.id}\n\t\t\t\t\t\tonSelect={() => onSwitch(profile.id)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className=\"flex items-center gap-2 w-full\">\n\t\t\t\t\t\t\t<Avatar className=\"h-5 w-5\">\n\t\t\t\t\t\t\t\t<AvatarImage src={profile.image} />\n\t\t\t\t\t\t\t\t<AvatarFallback>{getInitials(profile.name)}</AvatarFallback>\n\t\t\t\t\t\t\t</Avatar>\n\t\t\t\t\t\t\t<span className=\"text-sm\">{profile.name || \"Unnamed\"}</span>\n\t\t\t\t\t\t\t{profile.id === activeProfileId && (\n\t\t\t\t\t\t\t\t<CheckIcon className=\"h-4 w-4 ml-auto\" />\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</DropdownMenuItem>\n\t\t\t\t))}\n\t\t\t</DropdownMenuContent>\n\t\t</DropdownMenu>\n\t);\n}\n",
"target": "<%- config.aliases.components %>/profileswitcher.tsx"
}
]
}