Bluesky app fork with some witchin' additions 💫

lint (#9802)

authored by

Spence Pope and committed by
GitHub
45d6e50e e2a56b01

+207 -205
+32 -52
src/view/shell/bottom-bar/BottomBar.tsx
··· 15 15 import {useHideBottomBarBorder} from '#/lib/hooks/useHideBottomBarBorder' 16 16 import {useMinimalShellFooterTransform} from '#/lib/hooks/useMinimalShellTransform' 17 17 import {useNavigationTabState} from '#/lib/hooks/useNavigationTabState' 18 - import {usePalette} from '#/lib/hooks/usePalette' 19 18 import {clamp} from '#/lib/numbers' 20 19 import {getTabState, TabState} from '#/lib/routes/helpers' 21 20 import {emitSoftReset} from '#/state/events' ··· 57 56 58 57 export function BottomBar({navigation}: BottomTabBarProps) { 59 58 const {hasSession, currentAccount} = useSession() 60 - const pal = usePalette('default') 59 + const t = useTheme() 61 60 const {_} = useLingui() 62 61 const safeAreaInsets = useSafeAreaInsets() 63 62 const {footerHeight} = useShellLayout() ··· 145 144 <Animated.View 146 145 style={[ 147 146 styles.bottomBar, 148 - pal.view, 149 - hideBorder ? {borderColor: pal.view.backgroundColor} : pal.border, 147 + t.atoms.bg, 148 + hideBorder 149 + ? {borderColor: t.atoms.bg.backgroundColor} 150 + : t.atoms.border_contrast_low, 150 151 {paddingBottom: clamp(safeAreaInsets.bottom, 15, 60)}, 151 152 footerMinimalShellTransform, 152 153 ]} ··· 161 162 isAtHome ? ( 162 163 <HomeFilled 163 164 width={iconWidth + 1} 164 - style={[styles.ctrlIcon, pal.text, styles.homeIcon]} 165 + style={[styles.ctrlIcon, t.atoms.text, styles.homeIcon]} 165 166 /> 166 167 ) : ( 167 168 <Home 168 169 width={iconWidth + 1} 169 - style={[styles.ctrlIcon, pal.text, styles.homeIcon]} 170 + style={[styles.ctrlIcon, t.atoms.text, styles.homeIcon]} 170 171 /> 171 172 ) 172 173 } ··· 180 181 isAtSearch ? ( 181 182 <MagnifyingGlassFilled 182 183 width={iconWidth + 2} 183 - style={[styles.ctrlIcon, pal.text, styles.searchIcon]} 184 + style={[styles.ctrlIcon, t.atoms.text, styles.searchIcon]} 184 185 /> 185 186 ) : ( 186 187 <MagnifyingGlass 187 188 testID="bottomBarSearchBtn" 188 189 width={iconWidth + 2} 189 - style={[styles.ctrlIcon, pal.text, styles.searchIcon]} 190 + style={[styles.ctrlIcon, t.atoms.text, styles.searchIcon]} 190 191 /> 191 192 ) 192 193 } ··· 201 202 isAtMessages ? ( 202 203 <MessageFilled 203 204 width={iconWidth - 1} 204 - style={[styles.ctrlIcon, pal.text, styles.feedsIcon]} 205 + style={[styles.ctrlIcon, t.atoms.text, styles.feedsIcon]} 205 206 /> 206 207 ) : ( 207 208 <Message 208 209 width={iconWidth - 1} 209 - style={[styles.ctrlIcon, pal.text, styles.feedsIcon]} 210 + style={[styles.ctrlIcon, t.atoms.text, styles.feedsIcon]} 210 211 /> 211 212 ) 212 213 } ··· 233 234 isAtNotifications ? ( 234 235 <BellFilled 235 236 width={iconWidth} 236 - style={[styles.ctrlIcon, pal.text, styles.bellIcon]} 237 + style={[styles.ctrlIcon, t.atoms.text, styles.bellIcon]} 237 238 /> 238 239 ) : ( 239 240 <Bell 240 241 width={iconWidth} 241 - style={[styles.ctrlIcon, pal.text, styles.bellIcon]} 242 + style={[styles.ctrlIcon, t.atoms.text, styles.bellIcon]} 242 243 /> 243 244 ) 244 245 } ··· 262 263 testID="bottomBarProfileBtn" 263 264 icon={ 264 265 <View style={styles.ctrlIconSizingWrapper}> 265 - {isAtMyProfile ? ( 266 - <View 267 - style={[ 268 - styles.ctrlIcon, 269 - pal.text, 270 - styles.profileIcon, 266 + <View 267 + style={[ 268 + styles.ctrlIcon, 269 + styles.profileIcon, 270 + isAtMyProfile && [ 271 271 styles.onProfile, 272 272 { 273 - borderColor: pal.text.color, 274 - borderWidth: live ? 0 : 1, 275 - }, 276 - ]}> 277 - <UserAvatar 278 - avatar={demoMode ? BOTTOM_BAR_AVI : profile?.avatar} 279 - size={iconWidth - 2} 280 - // See https://github.com/bluesky-social/social-app/pull/1801: 281 - usePlainRNImage={true} 282 - type={profile?.associated?.labeler ? 'labeler' : 'user'} 283 - live={live} 284 - hideLiveBadge 285 - /> 286 - </View> 287 - ) : ( 288 - <View 289 - style={[ 290 - styles.ctrlIcon, 291 - pal.text, 292 - styles.profileIcon, 293 - { 273 + borderColor: t.atoms.text.color, 294 274 borderWidth: live ? 0 : 1, 295 275 }, 296 - ]}> 297 - <UserAvatar 298 - avatar={demoMode ? BOTTOM_BAR_AVI : profile?.avatar} 299 - size={iconWidth - 2} 300 - // See https://github.com/bluesky-social/social-app/pull/1801: 301 - usePlainRNImage={true} 302 - type={profile?.associated?.labeler ? 'labeler' : 'user'} 303 - live={live} 304 - hideLiveBadge 305 - /> 306 - </View> 307 - )} 276 + ], 277 + ]}> 278 + <UserAvatar 279 + avatar={demoMode ? BOTTOM_BAR_AVI : profile?.avatar} 280 + size={iconWidth - (isAtMyProfile ? 3 : 2)} 281 + // See https://github.com/bluesky-social/social-app/pull/1801: 282 + usePlainRNImage={true} 283 + type={profile?.associated?.labeler ? 'labeler' : 'user'} 284 + live={live} 285 + hideLiveBadge 286 + /> 287 + </View> 308 288 </View> 309 289 } 310 290 onPress={onPressProfile} ··· 332 312 style={{flexDirection: 'row', alignItems: 'center', gap: 8}}> 333 313 <Logo width={28} /> 334 314 <View style={{paddingTop: 4}}> 335 - <Logotype width={80} fill={pal.text.color} /> 315 + <Logotype width={80} fill={t.atoms.text.color} /> 336 316 </View> 337 317 </View> 338 318
+175 -153
src/view/shell/bottom-bar/BottomBarWeb.tsx
··· 12 12 import {type CommonNavigatorParams} from '#/lib/routes/types' 13 13 import {useUnreadMessageCount} from '#/state/queries/messages/list-conversations' 14 14 import {useUnreadNotifications} from '#/state/queries/notifications/unread' 15 + import {useProfileQuery} from '#/state/queries/profile' 15 16 import {useSession} from '#/state/session' 16 17 import {useLoggedOutViewControls} from '#/state/shell/logged-out' 17 18 import {useShellLayout} from '#/state/shell/shell-layout' 18 19 import {useCloseAllActiveElements} from '#/state/util' 19 20 import {Link} from '#/view/com/util/Link' 21 + import {UserAvatar} from '#/view/com/util/UserAvatar' 20 22 import {Logo} from '#/view/icons/Logo' 21 23 import {Logotype} from '#/view/icons/Logotype' 22 24 import {atoms as a, useTheme} from '#/alf' 23 25 import {Button, ButtonText} from '#/components/Button' 26 + import {useDialogControl} from '#/components/Dialog' 27 + import {SwitchAccountDialog} from '#/components/dialogs/SwitchAccount' 24 28 import { 25 29 Bell_Filled_Corner0_Rounded as BellFilled, 26 30 Bell_Stroke2_Corner0_Rounded as Bell, ··· 37 41 Message_Stroke2_Corner0_Rounded as Message, 38 42 Message_Stroke2_Corner0_Rounded_Filled as MessageFilled, 39 43 } from '#/components/icons/Message' 40 - import { 41 - UserCircle_Filled_Corner0_Rounded as UserCircleFilled, 42 - UserCircle_Stroke2_Corner0_Rounded as UserCircle, 43 - } from '#/components/icons/UserCircle' 44 44 import {Text} from '#/components/Typography' 45 45 import {styles} from './BottomBarStyles' 46 46 ··· 53 53 const closeAllActiveElements = useCloseAllActiveElements() 54 54 const {footerHeight} = useShellLayout() 55 55 const hideBorder = useHideBottomBarBorder() 56 + const accountSwitchControl = useDialogControl() 57 + const {data: profile} = useProfileQuery({did: currentAccount?.did}) 56 58 const iconWidth = 26 57 59 58 60 const unreadMessageCount = useUnreadMessageCount() ··· 69 71 // setShowLoggedOut(true) 70 72 }, [requestSwitchToAccount, closeAllActiveElements]) 71 73 74 + const onLongPressProfile = React.useCallback(() => { 75 + accountSwitchControl.open() 76 + }, [accountSwitchControl]) 77 + 72 78 return ( 73 - <Animated.View 74 - role="navigation" 75 - style={[ 76 - styles.bottomBar, 77 - styles.bottomBarWeb, 78 - t.atoms.bg, 79 - hideBorder 80 - ? {borderColor: t.atoms.bg.backgroundColor} 81 - : t.atoms.border_contrast_low, 82 - footerMinimalShellTransform, 83 - ]} 84 - onLayout={event => footerHeight.set(event.nativeEvent.layout.height)}> 85 - {hasSession ? ( 86 - <> 87 - <NavItem routeName="Home" href="/"> 88 - {({isActive}) => { 89 - const Icon = isActive ? HomeFilled : Home 90 - return ( 91 - <Icon 92 - aria-hidden={true} 93 - width={iconWidth + 1} 94 - style={[styles.ctrlIcon, t.atoms.text, styles.homeIcon]} 95 - /> 96 - ) 97 - }} 98 - </NavItem> 99 - <NavItem routeName="Search" href="/search"> 100 - {({isActive}) => { 101 - const Icon = isActive ? MagnifyingGlassFilled : MagnifyingGlass 102 - return ( 103 - <Icon 104 - aria-hidden={true} 105 - width={iconWidth + 2} 106 - style={[styles.ctrlIcon, t.atoms.text, styles.searchIcon]} 107 - /> 108 - ) 109 - }} 110 - </NavItem> 79 + <> 80 + <SwitchAccountDialog control={accountSwitchControl} /> 111 81 112 - {hasSession && ( 113 - <> 114 - <NavItem 115 - routeName="Messages" 116 - href="/messages" 117 - notificationCount={unreadMessageCount.numUnread} 118 - hasNew={unreadMessageCount.hasNew}> 119 - {({isActive}) => { 120 - const Icon = isActive ? MessageFilled : Message 121 - return ( 122 - <Icon 123 - aria-hidden={true} 124 - width={iconWidth - 1} 125 - style={[ 126 - styles.ctrlIcon, 127 - t.atoms.text, 128 - styles.messagesIcon, 129 - ]} 130 - /> 131 - ) 132 - }} 133 - </NavItem> 134 - <NavItem 135 - routeName="Notifications" 136 - href="/notifications" 137 - notificationCount={notificationCountStr}> 138 - {({isActive}) => { 139 - const Icon = isActive ? BellFilled : Bell 140 - return ( 141 - <Icon 142 - aria-hidden={true} 143 - width={iconWidth} 144 - style={[styles.ctrlIcon, t.atoms.text, styles.bellIcon]} 145 - /> 146 - ) 147 - }} 148 - </NavItem> 149 - <NavItem 150 - routeName="Profile" 151 - href={ 152 - currentAccount 153 - ? makeProfileLink({ 154 - did: currentAccount.did, 155 - handle: currentAccount.handle, 156 - }) 157 - : '/' 158 - }> 159 - {({isActive}) => { 160 - const Icon = isActive ? UserCircleFilled : UserCircle 161 - return ( 162 - <Icon 163 - aria-hidden={true} 164 - width={iconWidth} 165 - style={[ 166 - styles.ctrlIcon, 167 - t.atoms.text, 168 - styles.profileIcon, 169 - ]} 170 - /> 171 - ) 172 - }} 173 - </NavItem> 174 - </> 175 - )} 176 - </> 177 - ) : ( 178 - <> 179 - <View 180 - style={{ 181 - width: '100%', 182 - flexDirection: 'row', 183 - alignItems: 'center', 184 - justifyContent: 'space-between', 185 - paddingTop: 14, 186 - paddingBottom: 14, 187 - paddingLeft: 14, 188 - paddingRight: 6, 189 - gap: 8, 190 - }}> 191 - <View style={{flexDirection: 'row', alignItems: 'center', gap: 12}}> 192 - <Logo width={32} /> 193 - <View style={{paddingTop: 4}}> 194 - <Logotype width={80} fill={t.atoms.text.color} /> 82 + <Animated.View 83 + role="navigation" 84 + style={[ 85 + styles.bottomBar, 86 + styles.bottomBarWeb, 87 + t.atoms.bg, 88 + hideBorder 89 + ? {borderColor: t.atoms.bg.backgroundColor} 90 + : t.atoms.border_contrast_low, 91 + footerMinimalShellTransform, 92 + ]} 93 + onLayout={event => footerHeight.set(event.nativeEvent.layout.height)}> 94 + {hasSession ? ( 95 + <> 96 + <NavItem routeName="Home" href="/"> 97 + {({isActive}) => { 98 + const Icon = isActive ? HomeFilled : Home 99 + return ( 100 + <Icon 101 + aria-hidden={true} 102 + width={iconWidth + 1} 103 + style={[styles.ctrlIcon, t.atoms.text, styles.homeIcon]} 104 + /> 105 + ) 106 + }} 107 + </NavItem> 108 + <NavItem routeName="Search" href="/search"> 109 + {({isActive}) => { 110 + const Icon = isActive ? MagnifyingGlassFilled : MagnifyingGlass 111 + return ( 112 + <Icon 113 + aria-hidden={true} 114 + width={iconWidth + 2} 115 + style={[styles.ctrlIcon, t.atoms.text, styles.searchIcon]} 116 + /> 117 + ) 118 + }} 119 + </NavItem> 120 + 121 + {hasSession && ( 122 + <> 123 + <NavItem 124 + routeName="Messages" 125 + href="/messages" 126 + notificationCount={unreadMessageCount.numUnread} 127 + hasNew={unreadMessageCount.hasNew}> 128 + {({isActive}) => { 129 + const Icon = isActive ? MessageFilled : Message 130 + return ( 131 + <Icon 132 + aria-hidden={true} 133 + width={iconWidth - 1} 134 + style={[ 135 + styles.ctrlIcon, 136 + t.atoms.text, 137 + styles.messagesIcon, 138 + ]} 139 + /> 140 + ) 141 + }} 142 + </NavItem> 143 + <NavItem 144 + routeName="Notifications" 145 + href="/notifications" 146 + notificationCount={notificationCountStr}> 147 + {({isActive}) => { 148 + const Icon = isActive ? BellFilled : Bell 149 + return ( 150 + <Icon 151 + aria-hidden={true} 152 + width={iconWidth} 153 + style={[styles.ctrlIcon, t.atoms.text, styles.bellIcon]} 154 + /> 155 + ) 156 + }} 157 + </NavItem> 158 + <NavItem 159 + routeName="Profile" 160 + href={ 161 + currentAccount 162 + ? makeProfileLink({ 163 + did: currentAccount.did, 164 + handle: currentAccount.handle, 165 + }) 166 + : '/' 167 + } 168 + onLongPress={onLongPressProfile}> 169 + {({isActive}) => ( 170 + <View style={styles.ctrlIconSizingWrapper}> 171 + <View 172 + style={[ 173 + styles.ctrlIcon, 174 + styles.profileIcon, 175 + isActive && [ 176 + styles.onProfile, 177 + {borderColor: t.atoms.text.color}, 178 + ], 179 + ]}> 180 + <UserAvatar 181 + avatar={profile?.avatar} 182 + size={iconWidth - 3} 183 + type={ 184 + profile?.associated?.labeler ? 'labeler' : 'user' 185 + } 186 + /> 187 + </View> 188 + </View> 189 + )} 190 + </NavItem> 191 + </> 192 + )} 193 + </> 194 + ) : ( 195 + <> 196 + <View 197 + style={[ 198 + a.w_full, 199 + a.flex_row, 200 + a.align_center, 201 + a.justify_between, 202 + a.gap_sm, 203 + { 204 + paddingTop: 14, 205 + paddingBottom: 14, 206 + paddingLeft: 14, 207 + paddingRight: 6, 208 + }, 209 + ]}> 210 + <View style={[a.flex_row, a.align_center, a.gap_md]}> 211 + <Logo width={32} /> 212 + <View style={{paddingTop: 4}}> 213 + <Logotype width={80} fill={t.atoms.text.color} /> 214 + </View> 195 215 </View> 196 - </View> 197 216 198 - <View style={[a.flex_row, a.flex_wrap, a.gap_sm]}> 199 - <Button 200 - onPress={showCreateAccount} 201 - label={_(msg`Create account`)} 202 - size="small" 203 - variant="solid" 204 - color="primary"> 205 - <ButtonText> 206 - <Trans>Create account</Trans> 207 - </ButtonText> 208 - </Button> 209 - <Button 210 - onPress={showSignIn} 211 - label={_(msg`Sign in`)} 212 - size="small" 213 - variant="solid" 214 - color="secondary"> 215 - <ButtonText> 216 - <Trans>Sign in</Trans> 217 - </ButtonText> 218 - </Button> 217 + <View style={[a.flex_row, a.flex_wrap, a.gap_sm]}> 218 + <Button 219 + onPress={showCreateAccount} 220 + label={_(msg`Create account`)} 221 + size="small" 222 + variant="solid" 223 + color="primary"> 224 + <ButtonText> 225 + <Trans>Create account</Trans> 226 + </ButtonText> 227 + </Button> 228 + <Button 229 + onPress={showSignIn} 230 + label={_(msg`Sign in`)} 231 + size="small" 232 + variant="solid" 233 + color="secondary"> 234 + <ButtonText> 235 + <Trans>Sign in</Trans> 236 + </ButtonText> 237 + </Button> 238 + </View> 219 239 </View> 220 - </View> 221 - </> 222 - )} 223 - </Animated.View> 240 + </> 241 + )} 242 + </Animated.View> 243 + </> 224 244 ) 225 245 } 226 246 ··· 230 250 routeName: string 231 251 hasNew?: boolean 232 252 notificationCount?: string 233 - }> = ({children, href, routeName, hasNew, notificationCount}) => { 253 + onLongPress?: () => void 254 + }> = ({children, href, routeName, hasNew, notificationCount, onLongPress}) => { 234 255 const t = useTheme() 235 256 const {_} = useLingui() 236 257 const {currentAccount} = useSession() ··· 264 285 navigationAction={isOnDifferentProfile ? 'push' : 'navigate'} 265 286 aria-role="link" 266 287 aria-label={routeName} 267 - accessible={true}> 288 + accessible={true} 289 + onLongPress={onLongPress}> 268 290 {children({isActive})} 269 291 {notificationCount ? ( 270 292 <View