This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

semble / src / webapp / features / profile / components / profileMenu / ProfileMenu.tsx
5.3 kB 189 lines
1'use client'; 2 3import { 4 Skeleton, 5 Avatar, 6 Group, 7 Alert, 8 Menu, 9 Card, 10 Text, 11 UnstyledButton, 12 Stack, 13} from '@mantine/core'; 14import { useMantineColorScheme } from '@mantine/core'; 15import useMyProfile from '../../lib/queries/useMyProfile'; 16import { 17 MdOutlineBugReport, 18 MdOutlineCollectionsBookmark, 19 MdOutlineSmartphone, 20 MdOutlineDarkMode, 21 MdOutlineLightMode, 22} from 'react-icons/md'; 23import { TbStackForward } from 'react-icons/tb'; 24import { useAuth } from '@/hooks/useAuth'; 25import { useRouter } from 'next/navigation'; 26import Link from 'next/link'; 27import { IoMdLogOut } from 'react-icons/io'; 28import { useNavbarContext } from '@/providers/navbar'; 29import { useOs } from '@mantine/hooks'; 30import { BsThreeDots } from 'react-icons/bs'; 31import styles from './ProfileMenu.module.css'; 32import { sanitizeText } from '@/lib/utils/text'; 33import { isBotAccount } from '@/features/platforms/bluesky/lib/utils/account'; 34import BotLabel from '../botLabel/BotLabel'; 35 36const schemes = ['light', 'dark', 'auto'] as const; 37type ColorScheme = (typeof schemes)[number]; 38 39const schemeConfig: Record< 40 ColorScheme, 41 { icon: React.ReactNode; label: string; next: ColorScheme } 42> = { 43 light: { 44 icon: <MdOutlineLightMode size={22} />, 45 label: 'Light', 46 next: 'dark', 47 }, 48 dark: { icon: <MdOutlineDarkMode size={22} />, label: 'Dark', next: 'auto' }, 49 auto: { 50 icon: <MdOutlineSmartphone size={22} />, 51 label: 'Auto', 52 next: 'light', 53 }, 54}; 55 56export default function ProfileMenu() { 57 const router = useRouter(); 58 const os = useOs(); 59 const { toggleMobile } = useNavbarContext(); 60 const { data, error, isPending } = useMyProfile(); 61 const { logout } = useAuth(); 62 const { colorScheme, setColorScheme } = useMantineColorScheme(); 63 64 const current = schemeConfig[colorScheme as ColorScheme] ?? schemeConfig.auto; 65 66 const handleLogout = async () => { 67 try { 68 await logout(); 69 router.push('/'); 70 } catch (error) { 71 console.error('Error logging out:', error); 72 } 73 }; 74 75 if (isPending || !data) { 76 return <Skeleton w={38} h={38} radius="md" ml={4} />; 77 } 78 79 if (error) { 80 return <Alert color="red" title="Could not load profile" />; 81 } 82 83 return ( 84 <Group> 85 <Menu shadow="sm" width={280}> 86 <Menu.Target> 87 <Card px={5} py={5} flex={1} className={styles.root}> 88 <UnstyledButton> 89 <Group justify="space-between" wrap="nowrap"> 90 <Group gap={'xs'} c={'bright'} wrap="nowrap"> 91 <Avatar 92 src={data.avatarUrl?.replace('avatar', 'avatar_thumbnail')} 93 /> 94 <Text fw={600} lineClamp={1}> 95 {data.name} 96 </Text> 97 98 {isBotAccount(data) && <BotLabel />} 99 </Group> 100 <BsThreeDots /> 101 </Group> 102 </UnstyledButton> 103 </Card> 104 </Menu.Target> 105 106 <Menu.Dropdown> 107 <Menu.Item 108 component={Link} 109 href={`/profile/${data.handle}`} 110 onClick={toggleMobile} 111 > 112 <Group gap={'xs'} wrap="nowrap"> 113 <Avatar 114 src={data.avatarUrl?.replace('avatar', 'avatar_thumbnail')} 115 alt={`${data.handle}'s avatar`} 116 /> 117 118 <Stack gap={0}> 119 <Group gap={'xs'} wrap="nowrap"> 120 <Text fw={600} c={'bright'} lineClamp={1}> 121 {sanitizeText(data.name) || data.handle} 122 </Text> 123 {isBotAccount(data) && <BotLabel />} 124 </Group> 125 126 <Text fw={600} c={'gray'} lineClamp={1}> 127 @{data.handle} 128 </Text> 129 </Stack> 130 </Group> 131 </Menu.Item> 132 133 <Menu.Divider /> 134 135 <Menu.Item 136 color="gray" 137 closeMenuOnClick={false} 138 leftSection={current.icon} 139 onClick={() => setColorScheme(current.next)} 140 > 141 Theme: {current.label} 142 </Menu.Item> 143 144 <Menu.Item 145 component="a" 146 href="https://tangled.org/@cosmik.network/semble/issues" 147 target="_blank" 148 leftSection={<MdOutlineBugReport size={22} />} 149 color="gray" 150 > 151 Submit an issue 152 </Menu.Item> 153 154 <Menu.Item 155 color="gray" 156 leftSection={<MdOutlineCollectionsBookmark size={22} />} 157 component={Link} 158 href={'/bookmarklet'} 159 target="_blank" 160 > 161 Install bookmarklet 162 </Menu.Item> 163 164 {os === 'ios' && ( 165 <Menu.Item 166 color="gray" 167 leftSection={<TbStackForward size={22} />} 168 component={Link} 169 href={ 170 'https://www.icloud.com/shortcuts/9c4b4b4bc4ef4d6d93513c59373b0af6' 171 } 172 target="_blank" 173 > 174 Install iOS shortcut 175 </Menu.Item> 176 )} 177 178 <Menu.Item 179 color="red" 180 leftSection={<IoMdLogOut size={22} />} 181 onClick={handleLogout} 182 > 183 Log out 184 </Menu.Item> 185 </Menu.Dropdown> 186 </Menu> 187 </Group> 188 ); 189}