Bluesky app fork with some witchin' additions 馃挮
at post-text-option 171 lines 4.1 kB view raw
1import {useMemo} from 'react' 2import {View} from 'react-native' 3import {type AppBskyFeedDefs, AtUri} from '@atproto/api' 4 5import {PressableScale} from '#/lib/custom-animations/PressableScale' 6import {makeCustomFeedLink} from '#/lib/routes/links' 7import {logger} from '#/logger' 8import {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 9import {UserAvatar} from '#/view/com/util/UserAvatar' 10import {atoms as a, native, useTheme, type ViewStyleProp} from '#/alf' 11import {Button, ButtonIcon} from '#/components/Button' 12import * as FeedCard from '#/components/FeedCard' 13import {sizes as iconSizes} from '#/components/icons/common' 14import {MagnifyingGlass_Stroke2_Corner0_Rounded as SearchIcon} from '#/components/icons/MagnifyingGlass' 15import {Link} from '#/components/Link' 16import {Text, type TextProps} from '#/components/Typography' 17 18export function Container({ 19 style, 20 children, 21 bottomBorder, 22}: { 23 children: React.ReactNode 24 bottomBorder?: boolean 25} & ViewStyleProp) { 26 const t = useTheme() 27 return ( 28 <View 29 style={[ 30 a.flex_row, 31 a.align_center, 32 a.px_lg, 33 a.pt_2xl, 34 a.pb_md, 35 a.gap_sm, 36 t.atoms.bg, 37 bottomBorder && [a.border_b, t.atoms.border_contrast_low], 38 style, 39 ]}> 40 {children} 41 </View> 42 ) 43} 44 45export function FeedLink({ 46 feed, 47 children, 48}: { 49 feed: AppBskyFeedDefs.GeneratorView 50 children?: React.ReactNode 51}) { 52 const t = useTheme() 53 const {host: did, rkey} = useMemo(() => new AtUri(feed.uri), [feed.uri]) 54 return ( 55 <Link 56 to={makeCustomFeedLink(did, rkey)} 57 label={feed.displayName} 58 style={[a.flex_1]}> 59 {({focused, hovered, pressed}) => ( 60 <View 61 style={[ 62 a.flex_1, 63 a.flex_row, 64 a.align_center, 65 {gap: 10}, 66 a.rounded_md, 67 a.p_xs, 68 {marginLeft: -6}, 69 (focused || hovered || pressed) && t.atoms.bg_contrast_25, 70 ]}> 71 {children} 72 </View> 73 )} 74 </Link> 75 ) 76} 77 78export function FeedAvatar({feed}: {feed: AppBskyFeedDefs.GeneratorView}) { 79 return <UserAvatar type="algo" size={38} avatar={feed.avatar} /> 80} 81 82export function Icon({ 83 icon: Comp, 84 size = 'lg', 85}: Pick<React.ComponentProps<typeof ButtonIcon>, 'icon' | 'size'>) { 86 const iconSize = iconSizes[size] 87 88 return ( 89 <View style={[a.z_20, {width: iconSize, height: iconSize, marginLeft: -2}]}> 90 <Comp width={iconSize} /> 91 </View> 92 ) 93} 94 95export function TitleText({style, ...props}: TextProps) { 96 return ( 97 <Text 98 style={[a.font_semi_bold, a.flex_1, a.text_xl, style]} 99 emoji 100 {...props} 101 /> 102 ) 103} 104 105export function SubtitleText({style, ...props}: TextProps) { 106 const t = useTheme() 107 return ( 108 <Text 109 style={[ 110 t.atoms.text_contrast_medium, 111 a.leading_tight, 112 a.flex_1, 113 a.text_sm, 114 style, 115 ]} 116 {...props} 117 /> 118 ) 119} 120 121export function SearchButton({ 122 label, 123 metricsTag, 124 onPress, 125}: { 126 label: string 127 metricsTag: 'suggestedAccounts' | 'suggestedFeeds' 128 onPress?: () => void 129}) { 130 const enableSquareButtons = useEnableSquareButtons() 131 return ( 132 <Button 133 label={label} 134 size="small" 135 variant="ghost" 136 color="secondary" 137 shape={enableSquareButtons ? 'square' : 'round'} 138 PressableComponent={native(PressableScale)} 139 onPress={() => { 140 logger.metric( 141 'explore:module:searchButtonPress', 142 {module: metricsTag}, 143 {statsig: true}, 144 ) 145 onPress?.() 146 }} 147 style={[ 148 { 149 right: -4, 150 }, 151 ]}> 152 <ButtonIcon icon={SearchIcon} size="lg" /> 153 </Button> 154 ) 155} 156 157export function PinButton({feed}: {feed: AppBskyFeedDefs.GeneratorView}) { 158 return ( 159 <View style={[a.z_20, {marginRight: -6}]}> 160 <FeedCard.SaveButton 161 pin 162 view={feed} 163 size="large" 164 color="secondary" 165 variant="ghost" 166 shape="square" 167 text={false} 168 /> 169 </View> 170 ) 171}