Bluesky app fork with some witchin' additions 馃挮
at linkat-integration 168 lines 4.0 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 {useEnableSquareButtons} from '#/state/preferences/enable-square-buttons' 8import {UserAvatar} from '#/view/com/util/UserAvatar' 9import {atoms as a, native, useTheme, type ViewStyleProp} from '#/alf' 10import {Button, ButtonIcon} from '#/components/Button' 11import * as FeedCard from '#/components/FeedCard' 12import {sizes as iconSizes} from '#/components/icons/common' 13import {MagnifyingGlass_Stroke2_Corner0_Rounded as SearchIcon} from '#/components/icons/MagnifyingGlass' 14import {Link} from '#/components/Link' 15import {Text, type TextProps} from '#/components/Typography' 16import {useAnalytics} from '#/analytics' 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 ax = useAnalytics() 131 const enableSquareButtons = useEnableSquareButtons() 132 return ( 133 <Button 134 label={label} 135 size="small" 136 variant="ghost" 137 color="secondary" 138 shape={enableSquareButtons ? 'square' : 'round'} 139 PressableComponent={native(PressableScale)} 140 onPress={() => { 141 ax.metric('explore:module:searchButtonPress', {module: metricsTag}) 142 onPress?.() 143 }} 144 style={[ 145 { 146 right: -4, 147 }, 148 ]}> 149 <ButtonIcon icon={SearchIcon} size="lg" /> 150 </Button> 151 ) 152} 153 154export function PinButton({feed}: {feed: AppBskyFeedDefs.GeneratorView}) { 155 return ( 156 <View style={[a.z_20, {marginRight: -6}]}> 157 <FeedCard.SaveButton 158 pin 159 view={feed} 160 size="large" 161 color="secondary" 162 variant="ghost" 163 shape="square" 164 text={false} 165 /> 166 </View> 167 ) 168}