Bluesky app fork with some witchin' additions 馃挮
at main 175 lines 4.6 kB view raw
1import {lazy, useState} from 'react' 2import {View} from 'react-native' 3// @ts-expect-error missing types 4import QRCode from 'react-native-qrcode-styled' 5import type ViewShot from 'react-native-view-shot' 6import {type AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api' 7import {Trans} from '@lingui/macro' 8 9import {Logo} from '#/view/icons/Logo' 10import {Logotype} from '#/view/icons/Logotype' 11import {useTheme} from '#/alf' 12import {atoms as a} from '#/alf' 13import {LinearGradientBackground} from '#/components/LinearGradientBackground' 14import {Text} from '#/components/Typography' 15import {IS_WEB} from '#/env' 16import * as bsky from '#/types/bsky' 17 18const LazyViewShot = lazy( 19 // @ts-expect-error dynamic import 20 () => import('react-native-view-shot/src/index'), 21) 22 23export function QrCode({ 24 starterPack, 25 link, 26 ref, 27}: { 28 starterPack: AppBskyGraphDefs.StarterPackView 29 link: string 30 ref: React.Ref<ViewShot> 31}) { 32 const {record} = starterPack 33 34 if ( 35 !bsky.dangerousIsType<AppBskyGraphStarterpack.Record>( 36 record, 37 AppBskyGraphStarterpack.isRecord, 38 ) 39 ) { 40 return null 41 } 42 43 return ( 44 <LazyViewShot ref={ref}> 45 <LinearGradientBackground 46 style={[ 47 {width: 300, minHeight: 390}, 48 a.align_center, 49 a.px_sm, 50 a.py_xl, 51 a.rounded_sm, 52 a.justify_between, 53 a.gap_md, 54 ]}> 55 <View style={[a.gap_sm]}> 56 <Text 57 style={[ 58 a.font_semi_bold, 59 a.text_3xl, 60 a.text_center, 61 {color: 'white'}, 62 ]}> 63 {record.name} 64 </Text> 65 </View> 66 <View style={[a.gap_xl, a.align_center]}> 67 <Text 68 style={[ 69 a.font_semi_bold, 70 a.text_center, 71 {color: 'white', fontSize: 18}, 72 ]}> 73 <Trans>Join the conversation</Trans> 74 </Text> 75 <View style={[a.rounded_sm, a.overflow_hidden]}> 76 <QrCodeInner link={link} /> 77 </View> 78 79 <Text 80 style={[ 81 a.flex, 82 a.flex_row, 83 a.align_center, 84 a.font_semi_bold, 85 {color: 'white', fontSize: 18, gap: 6}, 86 ]}> 87 <Trans> 88 on 89 <View style={[a.flex_row, a.align_center, {gap: 6}]}> 90 <Logo width={25} fill="white" /> 91 <View style={[{marginTop: 3.5}]}> 92 <Logotype width={72} fill="white" /> 93 </View> 94 </View> 95 </Trans> 96 </Text> 97 </View> 98 </LinearGradientBackground> 99 </LazyViewShot> 100 ) 101} 102 103export function QrCodeInner({link}: {link: string}) { 104 const t = useTheme() 105 const [logoArea, setLogoArea] = useState<{ 106 x: number 107 y: number 108 width: number 109 height: number 110 } | null>(null) 111 112 const onLogoAreaChange = (area: { 113 x: number 114 y: number 115 width: number 116 height: number 117 }) => { 118 setLogoArea(area) 119 } 120 121 return ( 122 <View style={{position: 'relative'}}> 123 {/* An SVG version of the logo is placed on top of normal `QRCode` `logo` prop, since the PNG fails to load before the export completes on web. */} 124 {IS_WEB && logoArea && ( 125 <View 126 style={{ 127 position: 'absolute', 128 left: logoArea.x, 129 top: logoArea.y + 1, 130 zIndex: 1, 131 padding: 4, 132 }}> 133 <Logo width={logoArea.width - 14} height={logoArea.height - 14} /> 134 </View> 135 )} 136 <QRCode 137 data={link} 138 style={[ 139 a.rounded_sm, 140 {height: 225, width: 225, backgroundColor: '#f3f3f3'}, 141 ]} 142 pieceSize={IS_WEB ? 8 : 6} 143 padding={20} 144 pieceBorderRadius={IS_WEB ? 4.5 : 3.5} 145 outerEyesOptions={{ 146 topLeft: { 147 borderRadius: [12, 12, 0, 12], 148 color: t.palette.primary_500, 149 }, 150 topRight: { 151 borderRadius: [12, 12, 12, 0], 152 color: t.palette.primary_500, 153 }, 154 bottomLeft: { 155 borderRadius: [12, 0, 12, 12], 156 color: t.palette.primary_500, 157 }, 158 }} 159 innerEyesOptions={{borderRadius: 3}} 160 logo={{ 161 href: require('../../../assets/logo.png'), 162 ...(IS_WEB && { 163 onChange: onLogoAreaChange, 164 padding: 28, 165 }), 166 ...(!IS_WEB && { 167 padding: 2, 168 scale: 0.95, 169 }), 170 hidePieces: true, 171 }} 172 /> 173 </View> 174 ) 175}