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