Bluesky app fork with some witchin' additions 馃挮
at main 137 lines 3.9 kB view raw
1import {useCallback, useImperativeHandle, useState} from 'react' 2import {View} from 'react-native' 3import {type AppBskyGraphDefs} from '@atproto/api' 4import {msg, Trans} from '@lingui/macro' 5import {useLingui} from '@lingui/react' 6 7import {useSession} from '#/state/session' 8import {ListMembers} from '#/view/com/lists/ListMembers' 9import {EmptyState} from '#/view/com/util/EmptyState' 10import {type ListRef} from '#/view/com/util/List' 11import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn' 12import {atoms as a, useBreakpoints} from '#/alf' 13import {Button, ButtonIcon, ButtonText} from '#/components/Button' 14import {BulletList_Stroke1_Corner0_Rounded as ListIcon} from '#/components/icons/BulletList' 15import {PersonPlus_Stroke2_Corner0_Rounded as PersonPlusIcon} from '#/components/icons/Person' 16import {IS_NATIVE} from '#/env' 17 18interface SectionRef { 19 scrollToTop: () => void 20} 21 22interface AboutSectionProps { 23 ref?: React.Ref<SectionRef> 24 list: AppBskyGraphDefs.ListView 25 onPressAddUser: () => void 26 headerHeight: number 27 scrollElRef: ListRef 28} 29 30export function AboutSection({ 31 ref, 32 list, 33 onPressAddUser, 34 headerHeight, 35 scrollElRef, 36}: AboutSectionProps) { 37 const {_} = useLingui() 38 const {currentAccount} = useSession() 39 const {gtMobile} = useBreakpoints() 40 const [isScrolledDown, setIsScrolledDown] = useState(false) 41 const isOwner = list.creator.did === currentAccount?.did 42 43 const onScrollToTop = useCallback(() => { 44 scrollElRef.current?.scrollToOffset({ 45 animated: IS_NATIVE, 46 offset: -headerHeight, 47 }) 48 }, [scrollElRef, headerHeight]) 49 50 useImperativeHandle(ref, () => ({ 51 scrollToTop: onScrollToTop, 52 })) 53 54 const renderHeader = useCallback(() => { 55 if (!isOwner) { 56 return <View /> 57 } 58 if (!gtMobile) { 59 return ( 60 <View style={[a.px_sm, a.py_sm]}> 61 <Button 62 testID="addUserBtn" 63 label={_(msg`Add a user to this list`)} 64 onPress={onPressAddUser} 65 color="primary" 66 size="small" 67 variant="outline" 68 style={[a.py_md]}> 69 <ButtonIcon icon={PersonPlusIcon} /> 70 <ButtonText> 71 <Trans>Add people</Trans> 72 </ButtonText> 73 </Button> 74 </View> 75 ) 76 } 77 return ( 78 <View style={[a.px_lg, a.py_md, a.flex_row_reverse]}> 79 <Button 80 testID="addUserBtn" 81 label={_(msg`Add a user to this list`)} 82 onPress={onPressAddUser} 83 color="primary" 84 size="small" 85 variant="ghost" 86 style={[a.py_sm]}> 87 <ButtonIcon icon={PersonPlusIcon} /> 88 <ButtonText> 89 <Trans>Add people</Trans> 90 </ButtonText> 91 </Button> 92 </View> 93 ) 94 }, [isOwner, _, onPressAddUser, gtMobile]) 95 96 const renderEmptyState = useCallback(() => { 97 return ( 98 <View style={[a.gap_xl, a.align_center]}> 99 <EmptyState icon={ListIcon} message={_(msg`This list is empty.`)} /> 100 {isOwner && ( 101 <Button 102 testID="emptyStateAddUserBtn" 103 label={_(msg`Start adding people`)} 104 onPress={onPressAddUser} 105 color="primary" 106 size="small"> 107 <ButtonIcon icon={PersonPlusIcon} /> 108 <ButtonText> 109 <Trans>Start adding people!</Trans> 110 </ButtonText> 111 </Button> 112 )} 113 </View> 114 ) 115 }, [_, isOwner, onPressAddUser]) 116 117 return ( 118 <View> 119 <ListMembers 120 testID="listItems" 121 list={list.uri} 122 scrollElRef={scrollElRef} 123 renderHeader={renderHeader} 124 renderEmptyState={renderEmptyState} 125 headerOffset={headerHeight} 126 onScrolledDownChange={setIsScrolledDown} 127 /> 128 {isScrolledDown && ( 129 <LoadLatestBtn 130 onPress={onScrollToTop} 131 label={_(msg`Scroll to top`)} 132 showIndicator={false} 133 /> 134 )} 135 </View> 136 ) 137}