Bluesky app fork with some witchin' additions 💫 witchsky.app
bluesky fork client

[ELI5] Tweaks to hosting provider (#6935)

* minimal hosting provider

* change wording and move back up

* first time user nudge

* move tip

* reexport ticket svg

* fix ticket fr this time

* text tweak + add minHeight

authored by samuel.fm and committed by

GitHub 7c8c78b1 40ab7778

+122 -83
+1 -1
assets/icons/ticket_stroke2_corner0_rounded.svg
··· 1 - <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" stroke="#000" stroke-linejoin="round" d="M4 5.5a.5.5 0 0 0-.5.5v2.535a.5.5 0 0 0 .25.433A3.5 3.5 0 0 1 5.5 12a3.5 3.5 0 0 1-1.75 3.032.5.5 0 0 0-.25.433V18a.5.5 0 0 0 .5.5h16a.5.5 0 0 0 .5-.5v-2.535a.5.5 0 0 0-.25-.433A3.5 3.5 0 0 1 18.5 12a3.5 3.5 0 0 1 1.75-3.032.5.5 0 0 0 .25-.433V6a.5.5 0 0 0-.5-.5H4ZM2.5 6A1.5 1.5 0 0 1 4 4.5h16A1.5 1.5 0 0 1 21.5 6v3.17a.5.5 0 0 1-.333.472 2.501 2.501 0 0 0 0 4.716.5.5 0 0 1 .333.471V18a1.5 1.5 0 0 1-1.5 1.5H4A1.5 1.5 0 0 1 2.5 18v-3.17a.5.5 0 0 1 .333-.472 2.501 2.501 0 0 0 0-4.716.5.5 0 0 1-.333-.471V6Zm12 2a.5.5 0 1 1 1 0 .5.5 0 0 1-1 0Zm0 4a.5.5 0 1 1 1 0 .5.5 0 0 1-1 0Zm0 4a.5.5 0 1 1 1 0 .5.5 0 0 1-1 0Z"/></svg> 1 + <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M3 4a1 1 0 0 0-1 1v4.17a1 1 0 0 0 .667.944 2.001 2.001 0 0 1 0 3.772A1 1 0 0 0 2 14.83V19a1 1 0 0 0 1 1h18a1 1 0 0 0 1-1v-4.17a1 1 0 0 0-.667-.944 2.001 2.001 0 0 1 0-3.772A1 1 0 0 0 22 9.17V5a1 1 0 0 0-1-1H3Zm1 4.535V6h16v2.535A4 4 0 0 0 18 12c0 1.482.805 2.773 2 3.465V18H4v-2.535A4 4 0 0 0 6 12a4 4 0 0 0-2-3.465ZM15 15a1 1 0 1 0 0 2 1 1 0 0 0 0-2Zm-1-3a1 1 0 1 1 2 0 1 1 0 0 1-2 0Zm1-5a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z" clip-rule="evenodd"/></svg>
+83 -60
src/components/forms/HostingProvider.tsx
··· 6 6 import {toNiceDomain} from '#/lib/strings/url-helpers' 7 7 import {isAndroid} from '#/platform/detection' 8 8 import {ServerInputDialog} from '#/view/com/auth/server-input' 9 - import {atoms as a, useTheme} from '#/alf' 10 - import {Globe_Stroke2_Corner0_Rounded as Globe} from '#/components/icons/Globe' 11 - import {PencilLine_Stroke2_Corner0_Rounded as Pencil} from '#/components/icons/Pencil' 12 - import {Button} from '../Button' 13 - import {useDialogControl} from '../Dialog' 14 - import {Text} from '../Typography' 9 + import {atoms as a, tokens, useTheme} from '#/alf' 10 + import {Button, ButtonIcon, ButtonText} from '#/components/Button' 11 + import {useDialogControl} from '#/components/Dialog' 12 + import {Globe_Stroke2_Corner0_Rounded as GlobeIcon} from '#/components/icons/Globe' 13 + import {PencilLine_Stroke2_Corner0_Rounded as PencilIcon} from '#/components/icons/Pencil' 14 + import {Text} from '#/components/Typography' 15 15 16 16 export function HostingProvider({ 17 17 serviceUrl, 18 18 onSelectServiceUrl, 19 19 onOpenDialog, 20 + minimal, 20 21 }: { 21 22 serviceUrl: string 22 23 onSelectServiceUrl: (provider: string) => void 23 24 onOpenDialog?: () => void 25 + minimal?: boolean 24 26 }) { 25 27 const serverInputControl = useDialogControl() 26 28 const t = useTheme() ··· 29 31 const onPressSelectService = React.useCallback(() => { 30 32 Keyboard.dismiss() 31 33 serverInputControl.open() 32 - if (onOpenDialog) { 33 - onOpenDialog() 34 - } 34 + onOpenDialog?.() 35 35 }, [onOpenDialog, serverInputControl]) 36 36 37 37 return ( ··· 40 40 control={serverInputControl} 41 41 onSelect={onSelectServiceUrl} 42 42 /> 43 - <Button 44 - testID="selectServiceButton" 45 - label={toNiceDomain(serviceUrl)} 46 - accessibilityHint={_(msg`Press to change hosting provider`)} 47 - variant="solid" 48 - color="secondary" 49 - style={[ 50 - a.w_full, 51 - a.flex_row, 52 - a.align_center, 53 - a.rounded_sm, 54 - a.px_md, 55 - a.pr_sm, 56 - a.gap_xs, 57 - {paddingVertical: isAndroid ? 14 : 9}, 58 - ]} 59 - onPress={onPressSelectService}> 60 - {({hovered, pressed}) => { 61 - const interacted = hovered || pressed 62 - return ( 63 - <> 64 - <View style={a.pr_xs}> 65 - <Globe 66 - size="md" 67 - fill={ 68 - interacted ? t.palette.contrast_800 : t.palette.contrast_500 69 - } 70 - /> 71 - </View> 72 - <Text style={[a.text_md]}>{toNiceDomain(serviceUrl)}</Text> 73 - <View 74 - style={[ 75 - a.rounded_sm, 76 - interacted 77 - ? t.atoms.bg_contrast_300 78 - : t.atoms.bg_contrast_100, 79 - {marginLeft: 'auto', padding: 6}, 80 - ]}> 81 - <Pencil 82 - size="sm" 83 - style={{ 84 - color: interacted 85 - ? t.palette.contrast_800 86 - : t.palette.contrast_500, 87 - }} 88 - /> 89 - </View> 90 - </> 91 - ) 92 - }} 93 - </Button> 43 + {minimal ? ( 44 + <View style={[a.flex_row, a.align_center, a.flex_wrap]}> 45 + <Text style={[a.text_sm, t.atoms.text_contrast_medium]}> 46 + You are creating an account on{' '} 47 + </Text> 48 + <Button 49 + label={toNiceDomain(serviceUrl)} 50 + accessibilityHint={_(msg`Press to change hosting provider`)} 51 + onPress={onPressSelectService} 52 + variant="ghost" 53 + color="secondary" 54 + size="tiny" 55 + style={[a.px_xs, {marginLeft: tokens.space.xs * -1}]}> 56 + <ButtonText style={[a.text_sm]}> 57 + {toNiceDomain(serviceUrl)} 58 + </ButtonText> 59 + <ButtonIcon icon={PencilIcon} /> 60 + </Button> 61 + </View> 62 + ) : ( 63 + <Button 64 + testID="selectServiceButton" 65 + label={toNiceDomain(serviceUrl)} 66 + accessibilityHint={_(msg`Press to change hosting provider`)} 67 + variant="solid" 68 + color="secondary" 69 + style={[ 70 + a.w_full, 71 + a.flex_row, 72 + a.align_center, 73 + a.rounded_sm, 74 + a.px_md, 75 + a.pr_sm, 76 + a.gap_xs, 77 + {paddingVertical: isAndroid ? 14 : 9}, 78 + ]} 79 + onPress={onPressSelectService}> 80 + {({hovered, pressed}) => { 81 + const interacted = hovered || pressed 82 + return ( 83 + <> 84 + <View style={a.pr_xs}> 85 + <GlobeIcon 86 + size="md" 87 + fill={ 88 + interacted 89 + ? t.palette.contrast_800 90 + : t.palette.contrast_500 91 + } 92 + /> 93 + </View> 94 + <Text style={[a.text_md]}>{toNiceDomain(serviceUrl)}</Text> 95 + <View 96 + style={[ 97 + a.rounded_sm, 98 + interacted 99 + ? t.atoms.bg_contrast_300 100 + : t.atoms.bg_contrast_100, 101 + {marginLeft: 'auto', padding: 6}, 102 + ]}> 103 + <PencilIcon 104 + size="sm" 105 + style={{ 106 + color: interacted 107 + ? t.palette.contrast_800 108 + : t.palette.contrast_500, 109 + }} 110 + /> 111 + </View> 112 + </> 113 + ) 114 + }} 115 + </Button> 116 + )} 94 117 </> 95 118 ) 96 119 }
+1 -1
src/components/icons/Ticket.tsx
··· 1 1 import {createSinglePathSVG} from './TEMPLATE' 2 2 3 3 export const Ticket_Stroke2_Corner0_Rounded = createSinglePathSVG({ 4 - path: 'M4 5.5a.5.5 0 0 0-.5.5v2.535a.5.5 0 0 0 .25.433A3.498 3.498 0 0 1 5.5 12a3.498 3.498 0 0 1-1.75 3.032.5.5 0 0 0-.25.433V18a.5.5 0 0 0 .5.5h16a.5.5 0 0 0 .5-.5v-2.535a.5.5 0 0 0-.25-.433A3.498 3.498 0 0 1 18.5 12a3.5 3.5 0 0 1 1.75-3.032.5.5 0 0 0 .25-.433V6a.5.5 0 0 0-.5-.5H4ZM2.5 6A1.5 1.5 0 0 1 4 4.5h16A1.5 1.5 0 0 1 21.5 6v3.17a.5.5 0 0 1-.333.472 2.501 2.501 0 0 0 0 4.716.5.5 0 0 1 .333.471V18a1.5 1.5 0 0 1-1.5 1.5H4A1.5 1.5 0 0 1 2.5 18v-3.17a.5.5 0 0 1 .333-.472 2.501 2.501 0 0 0 0-4.716.5.5 0 0 1-.333-.471V6Zm12 2a.5.5 0 1 1 1 0 .5.5 0 0 1-1 0Zm0 4a.5.5 0 1 1 1 0 .5.5 0 0 1-1 0Zm0 4a.5.5 0 1 1 1 0 .5.5 0 0 1-1 0Z', 4 + path: 'M3 4a1 1 0 0 0-1 1v4.17a1 1 0 0 0 .667.944 2.001 2.001 0 0 1 0 3.772A1 1 0 0 0 2 14.83V19a1 1 0 0 0 1 1h18a1 1 0 0 0 1-1v-4.17a1 1 0 0 0-.667-.944 2.001 2.001 0 0 1 0-3.772A1 1 0 0 0 22 9.17V5a1 1 0 0 0-1-1H3Zm1 4.535V6h16v2.535A4 4 0 0 0 18 12c0 1.482.805 2.773 2 3.465V18H4v-2.535A4 4 0 0 0 6 12a4 4 0 0 0-2-3.465ZM15 15a1 1 0 1 0 0 2 1 1 0 0 0 0-2Zm-1-3a1 1 0 1 1 2 0 1 1 0 0 1-2 0Zm1-5a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z', 5 5 })
+5 -11
src/screens/Signup/StepInfo/index.tsx
··· 128 128 <ScreenTransition> 129 129 <View style={[a.gap_md]}> 130 130 <FormError error={state.error} /> 131 - <View> 132 - <TextField.LabelText> 133 - <Trans>Hosting provider</Trans> 134 - </TextField.LabelText> 135 - <HostingProvider 136 - serviceUrl={state.serviceUrl} 137 - onSelectServiceUrl={v => 138 - dispatch({type: 'setServiceUrl', value: v}) 139 - } 140 - /> 141 - </View> 131 + <HostingProvider 132 + minimal 133 + serviceUrl={state.serviceUrl} 134 + onSelectServiceUrl={v => dispatch({type: 'setServiceUrl', value: v})} 135 + /> 142 136 {state.isLoading || isLoadingStarterPack ? ( 143 137 <View style={[a.align_center]}> 144 138 <Loader size="xl" />
+32 -10
src/view/com/auth/server-input/index.tsx
··· 1 1 import React from 'react' 2 2 import {View} from 'react-native' 3 + import {useWindowDimensions} from 'react-native' 3 4 import {msg, Trans} from '@lingui/macro' 4 5 import {useLingui} from '@lingui/react' 5 6 6 7 import {BSKY_SERVICE} from '#/lib/constants' 7 8 import * as persisted from '#/state/persisted' 9 + import {useSession} from '#/state/session' 8 10 import {atoms as a, useBreakpoints, useTheme} from '#/alf' 11 + import {Admonition} from '#/components/Admonition' 9 12 import {Button, ButtonText} from '#/components/Button' 10 13 import * as Dialog from '#/components/Dialog' 11 14 import * as TextField from '#/components/forms/TextField' ··· 23 26 }) { 24 27 const {_} = useLingui() 25 28 const t = useTheme() 29 + const {height} = useWindowDimensions() 26 30 const {gtMobile} = useBreakpoints() 27 31 const [pdsAddressHistory, setPdsAddressHistory] = React.useState<string[]>( 28 32 persisted.get('pdsAddressHistory') || [], 29 33 ) 30 34 const [fixedOption, setFixedOption] = React.useState([BSKY_SERVICE]) 31 35 const [customAddress, setCustomAddress] = React.useState('') 36 + const {accounts} = useSession() 37 + 38 + const isFirstTimeUser = accounts.length === 0 32 39 33 40 const onClose = React.useCallback(() => { 34 41 let url ··· 66 73 ]) 67 74 68 75 return ( 69 - <Dialog.Outer control={control} onClose={onClose}> 76 + <Dialog.Outer 77 + control={control} 78 + onClose={onClose} 79 + nativeOptions={{minHeight: height / 2}}> 70 80 <Dialog.Handle /> 71 81 <Dialog.ScrollableInner 72 82 accessibilityDescribedBy="dialog-description" 73 83 accessibilityLabelledBy="dialog-title"> 74 84 <View style={[a.relative, a.gap_md, a.w_full]}> 75 85 <Text nativeID="dialog-title" style={[a.text_2xl, a.font_bold]}> 76 - <Trans>Choose Service</Trans> 86 + <Trans>Choose your account provider</Trans> 77 87 </Text> 78 - <P nativeID="dialog-description" style={[a.text_sm]}> 79 - <Trans>Select the service that hosts your data.</Trans> 80 - </P> 81 - 82 88 <ToggleButton.Group 83 89 label="Preferences" 84 90 values={fixedOption} ··· 98 104 </ToggleButton.Button> 99 105 </ToggleButton.Group> 100 106 107 + {fixedOption[0] === BSKY_SERVICE && isFirstTimeUser && ( 108 + <Admonition type="tip"> 109 + <Trans> 110 + Bluesky is an open network where you can choose your own 111 + provider. If you're new here, we recommend sticking with the 112 + default Bluesky Social option. 113 + </Trans> 114 + </Admonition> 115 + )} 116 + 101 117 {fixedOption[0] === 'custom' && ( 102 118 <View 103 119 style={[ ··· 148 164 a.leading_snug, 149 165 a.flex_1, 150 166 ]}> 151 - <Trans> 152 - Bluesky is an open network where you can choose your hosting 153 - provider. If you're a developer, you can host your own server. 154 - </Trans>{' '} 167 + {isFirstTimeUser ? ( 168 + <Trans> 169 + If you're a developer, you can host your own server. 170 + </Trans> 171 + ) : ( 172 + <Trans> 173 + Bluesky is an open network where you can choose your hosting 174 + provider. If you're a developer, you can host your own server. 175 + </Trans> 176 + )}{' '} 155 177 <InlineLinkText 156 178 label={_(msg`Learn more about self hosting your PDS.`)} 157 179 to="https://atproto.com/guides/self-hosting">