Spaces:
Runtime error
Runtime error
File size: 6,348 Bytes
c0a9bce |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
import { motion } from 'framer-motion';
import { useStore } from '@nanostores/react';
import { classNames } from '~/utils/classNames';
import { profileStore } from '~/lib/stores/profile';
import type { TabType, Profile } from './types';
const BetaLabel = () => (
<span className="px-1.5 py-0.5 rounded-full bg-purple-500/10 dark:bg-purple-500/20 text-[10px] font-medium text-purple-600 dark:text-purple-400 ml-2">
BETA
</span>
);
interface AvatarDropdownProps {
onSelectTab: (tab: TabType) => void;
}
export const AvatarDropdown = ({ onSelectTab }: AvatarDropdownProps) => {
const profile = useStore(profileStore) as Profile;
return (
<DropdownMenu.Root>
<DropdownMenu.Trigger asChild>
<motion.button
className="w-10 h-10 rounded-full bg-transparent flex items-center justify-center focus:outline-none"
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
{profile?.avatar ? (
<img
src={profile.avatar}
alt={profile?.username || 'Profile'}
className="w-full h-full rounded-full object-cover"
loading="eager"
decoding="sync"
/>
) : (
<div className="w-full h-full rounded-full flex items-center justify-center bg-white dark:bg-gray-800 text-gray-400 dark:text-gray-500">
<div className="i-ph:question w-6 h-6" />
</div>
)}
</motion.button>
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content
className={classNames(
'min-w-[240px] z-[250]',
'bg-white dark:bg-[#141414]',
'rounded-lg shadow-lg',
'border border-gray-200/50 dark:border-gray-800/50',
'animate-in fade-in-0 zoom-in-95',
'py-1',
)}
sideOffset={5}
align="end"
>
<div
className={classNames(
'px-4 py-3 flex items-center gap-3',
'border-b border-gray-200/50 dark:border-gray-800/50',
)}
>
<div className="w-10 h-10 rounded-full overflow-hidden flex-shrink-0 bg-white dark:bg-gray-800 shadow-sm">
{profile?.avatar ? (
<img
src={profile.avatar}
alt={profile?.username || 'Profile'}
className={classNames('w-full h-full', 'object-cover', 'transform-gpu', 'image-rendering-crisp')}
loading="eager"
decoding="sync"
/>
) : (
<div className="w-full h-full flex items-center justify-center text-gray-400 dark:text-gray-500 font-medium text-lg">
<span className="relative -top-0.5">?</span>
</div>
)}
</div>
<div className="flex-1 min-w-0">
<div className="font-medium text-sm text-gray-900 dark:text-white truncate">
{profile?.username || 'Guest User'}
</div>
{profile?.bio && <div className="text-xs text-gray-500 dark:text-gray-400 truncate">{profile.bio}</div>}
</div>
</div>
<DropdownMenu.Item
className={classNames(
'flex items-center gap-2 px-4 py-2.5',
'text-sm text-gray-700 dark:text-gray-200',
'hover:bg-purple-50 dark:hover:bg-purple-500/10',
'hover:text-purple-500 dark:hover:text-purple-400',
'cursor-pointer transition-all duration-200',
'outline-none',
'group',
)}
onClick={() => onSelectTab('profile')}
>
<div className="i-ph:user-circle w-4 h-4 text-gray-400 group-hover:text-purple-500 dark:group-hover:text-purple-400 transition-colors" />
Edit Profile
</DropdownMenu.Item>
<DropdownMenu.Item
className={classNames(
'flex items-center gap-2 px-4 py-2.5',
'text-sm text-gray-700 dark:text-gray-200',
'hover:bg-purple-50 dark:hover:bg-purple-500/10',
'hover:text-purple-500 dark:hover:text-purple-400',
'cursor-pointer transition-all duration-200',
'outline-none',
'group',
)}
onClick={() => onSelectTab('settings')}
>
<div className="i-ph:gear-six w-4 h-4 text-gray-400 group-hover:text-purple-500 dark:group-hover:text-purple-400 transition-colors" />
Settings
</DropdownMenu.Item>
<div className="my-1 border-t border-gray-200/50 dark:border-gray-800/50" />
<DropdownMenu.Item
className={classNames(
'flex items-center gap-2 px-4 py-2.5',
'text-sm text-gray-700 dark:text-gray-200',
'hover:bg-purple-50 dark:hover:bg-purple-500/10',
'hover:text-purple-500 dark:hover:text-purple-400',
'cursor-pointer transition-all duration-200',
'outline-none',
'group',
)}
onClick={() => onSelectTab('task-manager')}
>
<div className="i-ph:activity w-4 h-4 text-gray-400 group-hover:text-purple-500 dark:group-hover:text-purple-400 transition-colors" />
Task Manager
<BetaLabel />
</DropdownMenu.Item>
<DropdownMenu.Item
className={classNames(
'flex items-center gap-2 px-4 py-2.5',
'text-sm text-gray-700 dark:text-gray-200',
'hover:bg-purple-50 dark:hover:bg-purple-500/10',
'hover:text-purple-500 dark:hover:text-purple-400',
'cursor-pointer transition-all duration-200',
'outline-none',
'group',
)}
onClick={() => onSelectTab('service-status')}
>
<div className="i-ph:heartbeat w-4 h-4 text-gray-400 group-hover:text-purple-500 dark:group-hover:text-purple-400 transition-colors" />
Service Status
<BetaLabel />
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
);
};
|