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

feat: add Linkat links tab to profile #52

closed opened by ewancroft.uk targeting main from linkat-integration

Adds support for displaying Linkat board links on user profiles. The Links tab appears when a user has configured a blue.linkat.board record with link cards.

Labels

None yet.

assignee

None yet.

Participants 1
AT URI
at://did:plc:ofrbh253gwicbkc5nktqepol/sh.tangled.repo.pull/3mddzf72chb22
+37 -230
Interdiff #0 #1
-3
src/components/ProfileLinkatSection.tsx
··· 1 - // This file has been moved to /src/screens/Profile/Sections/Linkat.tsx 2 - // Keeping this stub to prevent import errors 3 - export {}
src/screens/Profile/Sections/Linkat.tsx

This file has not been changed.

src/state/queries/linkat.ts

This file has not been changed.

src/view/screens/Profile.tsx

This file has not been changed.

+15 -7
README.md
··· 21 21 - Embed player works with [stream.place](https://stream.place/) links! 22 22 - Open skeets in PDSls and original pages of bridged posts 23 23 - You can redraft skeets 24 - - Better defaults (alt text required 😉 autoplay off 🫨) 24 + - Better defaults (alt text required 😉) 25 25 - More unique repost icons 26 26 - Can download videos 27 27 - 'Mutuals' in place of 'Following' when relevant ··· 50 50 - Toggle similar account recommendations 51 51 - Toggle to make all user avatars square (like labelers) 52 52 - Toggle for more square-ish UI (still slightly rounded) 53 - - Toggle to remove the composer prompt at the top of the Following & Discover feeds 54 - - Change post translation provider (between Google, Kagi, Papago, and LibreTranslate) 55 53 56 54 #### Metrics 57 55 ··· 66 64 - following 67 65 - & who someone's followed by 68 66 67 + #### Gates 68 + 69 + - Toggle for an alternate share icon 70 + - Toggle to show feed context for debugging 71 + - Toggle to hide the 'show latest' button 72 + - Toggle to make reply button open thread from feeds 73 + - More may be available in developer mode? Often less 🤷 74 + - (Accessible by holding the version in the About settings screen) 75 + 69 76 ## Upcoming or wishful features 70 77 71 78 - Better OpenGraph support for sharing profiles & skeets (including videos & fixing quotes) ··· 76 83 ### TODO: Xan 77 84 78 85 - [ ] Setup App Linking for Android (.well-known w/ app package fingerprint) 79 - - [ ] Fallback/email addresses to use witchsky.social in Automatic PDS detection 86 + - [ ] Automatic PDS detection like other social-app forks (fallback/email addresses to use witchsky.social) 80 87 - [ ] Change followed accounts [on onboarding](https://github.com/blacksky-algorithms/blacksky.community/commit/e36ee43efb4999f070860d7f70122e45b28c1e2b) 81 - - [ ] Join date & switch accounts in composer from a fork like [deer.aylac.top](https://github.com/ayla6/deer-social-test) 88 + - [ ] Join date & switch accounts from composer from a fork like [deer.aylac.top](https://github.com/ayla6/deer-social-test) 82 89 - [ ] Visual replies indicator like the [Firmament userstyle](https://witchsky.app/profile/did:plc:jwhxcrf5uvl3vyw7nurecgt5/post/3m4rr3vzmak2a) (and likes?) 90 + - [ ] Additional translation service providers + setting (Deepl, Kagi) 83 91 - [ ] Put DeerSettings into separate subpages 84 92 - [ ] After subpages for options, add [Outlinks page](https://witchsky.app/profile/did:plc:q7suwaz53ztc4mbiqyygbn43/post/3m5zjhhshic2g) & 85 93 - [ ] ShareMenuItems.tsx, ShareMenuItems.web.tsx 86 94 - [ ] For profile meatball button, Open profile in PDSls & Open bridged OG fedi account page 87 95 - [ ] ProfileMenu.tsx 88 - - [ ] Witchsky PDS and .social site (list good songs containing 'bitch' in their titles for related site) 96 + - [ ] Witchsky PDS and .social site (list good songs containing 'bitch' in their titles) 89 97 90 98 ### Even more wishful or far off 91 99 ··· 93 101 - [ ] Submit releases to the Google Play Store and iOS App Store 94 102 - [ ] Move from [Cloudflare Pages](https://pages.cloudflare.com/) to [wisp.place](https://wisp.place/) (needs serverless for embeds) 95 103 - [ ] Toggle between handle and DID in share links 96 - - [ ] Move TOS and privacy policy to Jollywhoppers website 104 + - [ ] Move TOS and privacy policy to Jollywhoppers website? 97 105 - [ ] Ignore `!no-unauthenticated` labels 98 106 - [ ] Material 3 Expressive theming on Android (Liquid **ass on iOS) 99 107
+1 -10
src/lib/hooks/useTranslate.ts
··· 1 1 import {useCallback} from 'react' 2 2 import * as IntentLauncher from 'expo-intent-launcher' 3 3 4 - import { 5 - getTranslatorLink, 6 - getTranslatorLinkKagi, 7 - getTranslatorLinkLibreTranslate, 8 - getTranslatorLinkPapago, 9 - } from '#/locale/helpers' 4 + import {getTranslatorLink, getTranslatorLinkKagi} from '#/locale/helpers' 10 5 import {useTranslationServicePreference} from '#/state/preferences/translation-service-preference' 11 6 import {IS_ANDROID} from '#/env' 12 7 import {useOpenLink} from './useOpenLink' ··· 24 19 // it is a mystery https://www.youtube.com/watch?v=fq3abPnEEGE 25 20 if (translationServicePreference == 'kagi') { 26 21 translateUrl = getTranslatorLinkKagi(text, language) 27 - } else if (translationServicePreference == 'papago') { 28 - translateUrl = getTranslatorLinkPapago(text, language) 29 - } else if (translationServicePreference == 'libreTranslate') { 30 - translateUrl = getTranslatorLinkLibreTranslate(text, language) 31 22 } else { 32 23 translateUrl = getTranslatorLink(text, language) 33 24 }
-17
src/locale/helpers.ts
··· 3 3 import lande from 'lande' 4 4 5 5 import {hasProp} from '#/lib/type-guards' 6 - import * as persisted from '#/state/persisted' 7 6 import { 8 7 AppLanguage, 9 8 type Language, ··· 139 138 return `https://translate.kagi.com/?from=auto&to=${lang}&text=${encodeURIComponent( 140 139 text, 141 140 )}` 142 - } 143 - 144 - export function getTranslatorLinkPapago(text: string, lang: string): string { 145 - return `https://papago.naver.com/?sk=auto&tk=${lang}&st=${encodeURIComponent( 146 - text, 147 - )}` 148 - } 149 - 150 - export function getTranslatorLinkLibreTranslate( 151 - text: string, 152 - lang: string, 153 - ): string { 154 - const instance = 155 - persisted.get('libreTranslateInstance') ?? 156 - persisted.defaults.libreTranslateInstance! 157 - return `${instance}?source=auto&target=${lang}&q=${encodeURIComponent(text)}` 158 141 } 159 142 160 143 /**
+19 -142
src/screens/Settings/DeerSettings.tsx
··· 108 108 useShowLinkInHandle, 109 109 } from '#/state/preferences/show-link-in-handle.tsx' 110 110 import { 111 - useLibreTranslateInstance, 112 - useSetLibreTranslateInstance, 113 111 useSetTranslationServicePreference, 114 112 useTranslationServicePreference, 115 113 } from '#/state/preferences/translation-service-preference' ··· 130 128 import {Star_Stroke2_Corner0_Rounded as StarIcon} from '#/components/icons/Star' 131 129 import {Verified_Stroke2_Corner2_Rounded as VerifiedIcon} from '#/components/icons/Verified' 132 130 import * as Layout from '#/components/Layout' 133 - import {InlineLinkText} from '#/components/Link' 134 131 import {Text} from '#/components/Typography' 135 132 import {IS_WEB} from '#/env' 136 133 import {SearchProfileCard} from '../Search/components/SearchProfileCard' ··· 145 142 const pal = usePalette('default') 146 143 const {_} = useLingui() 147 144 148 - const constellationInstance = useConstellationInstance() 149 - const [url, setUrl] = useState(constellationInstance ?? '') 145 + const [url, setUrl] = useState('') 150 146 const setConstellationInstance = useSetConstellationInstance() 151 147 152 148 const submit = () => { ··· 166 162 <Dialog.Outer 167 163 control={control} 168 164 nativeOptions={{preventExpansion: true}} 169 - onClose={() => setUrl(constellationInstance ?? '')}> 165 + onClose={() => setUrl('')}> 170 166 <Dialog.Handle /> 171 167 <Dialog.ScrollableInner label={_(msg`Constellations instance URL`)}> 172 168 <View style={[a.gap_sm, a.pb_lg]}> ··· 189 185 accessibilityHint={_( 190 186 msg`Input the url of the constellations instance to use`, 191 187 )} 192 - defaultValue={constellationInstance} 193 - /> 194 - 195 - <View style={IS_WEB && [a.flex_row, a.justify_end]}> 196 - <Button 197 - label={_(msg`Save`)} 198 - size="large" 199 - onPress={submit} 200 - variant="solid" 201 - color="primary" 202 - disabled={shouldDisable()}> 203 - <ButtonText> 204 - <Trans>Save</Trans> 205 - </ButtonText> 206 - </Button> 207 - </View> 208 - </View> 209 - 210 - <Dialog.Close /> 211 - </Dialog.ScrollableInner> 212 - </Dialog.Outer> 213 - ) 214 - } 215 - 216 - function LibreTranslateInstanceDialog({ 217 - control, 218 - }: { 219 - control: Dialog.DialogControlProps 220 - }) { 221 - const pal = usePalette('default') 222 - const {_} = useLingui() 223 - 224 - const libreTranslateInstance = useLibreTranslateInstance() 225 - const [url, setUrl] = useState(libreTranslateInstance ?? '') 226 - const setLibreTranslateInstance = useSetLibreTranslateInstance() 227 - 228 - const submit = () => { 229 - setLibreTranslateInstance(url) 230 - control.close() 231 - } 232 - 233 - const shouldDisable = () => { 234 - try { 235 - return !new URL(url).hostname.includes('.') 236 - } catch (e) { 237 - return true 238 - } 239 - } 240 - 241 - return ( 242 - <Dialog.Outer 243 - control={control} 244 - nativeOptions={{preventExpansion: true}} 245 - onClose={() => setUrl(libreTranslateInstance ?? '')}> 246 - <Dialog.Handle /> 247 - <Dialog.ScrollableInner label={_(msg`LibreTranslate instance URL`)}> 248 - <View style={[a.gap_sm, a.pb_lg]}> 249 - <Text style={[a.text_2xl, a.font_bold]}> 250 - <Trans>LibreTranslate instance URL</Trans> 251 - </Text> 252 - </View> 253 - 254 - <View style={a.gap_lg}> 255 - <Dialog.Input 256 - label="Text input field" 257 - autoFocus 258 - style={[styles.textInput, pal.border, pal.text]} 259 - onChangeText={value => { 260 - setUrl(value) 261 - }} 262 - placeholder={persisted.defaults.libreTranslateInstance} 263 - placeholderTextColor={pal.colors.textLight} 264 - onSubmitEditing={submit} 265 - accessibilityHint={_( 266 - msg`Input the url of the LibreTranslate instance to use`, 267 - )} 268 - defaultValue={libreTranslateInstance} 269 188 /> 270 189 271 190 <View style={IS_WEB && [a.flex_row, a.justify_end]}> ··· 423 342 const translationServicePreference = useTranslationServicePreference() 424 343 const setTranslationServicePreference = useSetTranslationServicePreference() 425 344 426 - const setLibreTranslateInstanceControl = Dialog.useDialogControl() 427 - 428 345 return ( 429 346 <Layout.Screen> 430 347 <Layout.Header.Outer> ··· 472 389 <Toggle.LabelText style={[a.flex_1]}> 473 390 <Trans> 474 391 Fetch records directly from PDS to see contents of blocked and 475 - detached quotes 392 + detatched quotes 476 393 </Trans> 477 394 </Toggle.LabelText> 478 395 <Toggle.Platform /> ··· 563 480 <Trans> 564 481 Constellation is used to supplement AppView responses for custom 565 482 verifications and nuclear block bypass, via backlinks. Current 566 - instance: 567 - <InlineLinkText 568 - to={constellationInstance} 569 - label={constellationInstance}> 570 - {constellationInstance} 571 - </InlineLinkText> 483 + instance: {constellationInstance} 572 484 </Trans> 573 485 </Admonition> 574 486 </SettingsList.Item> 575 - 576 - <SettingsList.Divider /> 577 487 578 488 <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 579 489 <SettingsList.ItemIcon icon={PaintRollerIcon} /> ··· 733 643 </Admonition> 734 644 </SettingsList.Group> 735 645 736 - <SettingsList.Divider /> 737 - 738 646 <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 739 647 <SettingsList.ItemIcon icon={EarthIcon} /> 740 648 <SettingsList.ItemText> 741 - <Trans>Post Translation Engine</Trans> 649 + <Trans>Translation Engine</Trans> 742 650 </SettingsList.ItemText> 651 + 652 + <Admonition type="info" style={[a.flex_1]}> 653 + <Trans>Choose the engine to use when translating posts.</Trans> 654 + </Admonition> 743 655 744 656 <Toggle.Item 745 657 name="service_google" ··· 764 676 </Toggle.LabelText> 765 677 <Toggle.Radio /> 766 678 </Toggle.Item> 767 - 768 - <Toggle.Item 769 - name="service_papago" 770 - label={_(msg`Use Naver Papago`)} 771 - value={translationServicePreference === 'papago'} 772 - onChange={() => setTranslationServicePreference('papago')} 773 - style={[a.w_full]}> 774 - <Toggle.LabelText style={[a.flex_1]}> 775 - <Trans>Use Naver Papago</Trans> 776 - </Toggle.LabelText> 777 - <Toggle.Radio /> 778 - </Toggle.Item> 779 - 780 - <Toggle.Item 781 - name="service_libreTranslate" 782 - label={_(msg`Use LibreTranslate`)} 783 - value={translationServicePreference === 'libreTranslate'} 784 - onChange={() => setTranslationServicePreference('libreTranslate')} 785 - style={[a.w_full]}> 786 - <Toggle.LabelText style={[a.flex_1]}> 787 - <Trans>Use LibreTranslate</Trans> 788 - </Toggle.LabelText> 789 - <Toggle.Radio /> 790 - </Toggle.Item> 791 679 </SettingsList.Group> 792 680 793 - {translationServicePreference === 'libreTranslate' && ( 794 - <SettingsList.Item> 795 - <SettingsList.ItemIcon icon={EarthIcon} /> 796 - <SettingsList.ItemText> 797 - <Trans>{`LibreTranslate Instance`}</Trans> 798 - </SettingsList.ItemText> 799 - <SettingsList.BadgeButton 800 - label={_(msg`Change`)} 801 - onPress={() => setLibreTranslateInstanceControl.open()} 802 - /> 803 - </SettingsList.Item> 804 - )} 805 - 806 - <SettingsList.Divider /> 807 - 808 681 <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 809 682 <SettingsList.ItemIcon icon={VisibilityIcon} /> 810 683 <SettingsList.ItemText> ··· 825 698 826 699 <Toggle.Item 827 700 name="disable_reposts_metrics" 828 - label={_(msg`Disable reskeet metrics`)} 701 + label={_(msg`Disable reskeets metrics`)} 829 702 value={disableRepostsMetrics} 830 703 onChange={value => setDisableRepostsMetrics(value)} 831 704 style={[a.w_full]}> 832 705 <Toggle.LabelText style={[a.flex_1]}> 833 - <Trans>Disable reskeet metrics</Trans> 706 + <Trans>Disable reskeets metrics</Trans> 834 707 </Toggle.LabelText> 835 708 <Toggle.Platform /> 836 709 </Toggle.Item> ··· 920 793 </Toggle.Item> 921 794 </SettingsList.Group> 922 795 923 - <SettingsList.Divider /> 796 + <SettingsList.Item> 797 + <Admonition type="warning" style={[a.flex_1]}> 798 + <Trans> 799 + These settings might summon nasal demons! Restart the app after 800 + changing if anything breaks. 801 + </Trans> 802 + </Admonition> 803 + </SettingsList.Item> 924 804 925 805 <SettingsList.Group contentContainerStyle={[a.gap_sm]}> 926 806 <SettingsList.ItemIcon icon={RaisingHandIcon} /> ··· 967 847 </Layout.Content> 968 848 <ConstellationInstanceDialog control={setConstellationInstanceControl} /> 969 849 <TrustedVerifiersDialog control={setTrustedVerifiersDialogControl} /> 970 - <LibreTranslateInstanceDialog 971 - control={setLibreTranslateInstanceControl} 972 - /> 973 850 </Layout.Screen> 974 851 ) 975 852 }
+1 -8
src/state/persisted/schema.ts
··· 172 172 173 173 showExternalShareButtons: z.boolean().optional(), 174 174 175 - translationServicePreference: z.enum([ 176 - 'google', 177 - 'kagi', 178 - 'papago', 179 - 'libreTranslate', 180 - ]), 181 - libreTranslateInstance: z.string().optional(), 175 + translationServicePreference: z.enum(['google', 'kagi']), 182 176 183 177 /** @deprecated */ 184 178 mutedThreads: z.array(z.string()), ··· 290 284 hideUnreplyablePosts: false, 291 285 showExternalShareButtons: false, 292 286 translationServicePreference: 'google', 293 - libreTranslateInstance: 'https://libretranslate.com/', 294 287 } 295 288 296 289 export function tryParse(rawData: string): Schema | undefined {
+1 -43
src/state/preferences/translation-service-preference.tsx
··· 4 4 5 5 type StateContext = persisted.Schema['translationServicePreference'] 6 6 type SetContext = (v: persisted.Schema['translationServicePreference']) => void 7 - type InstanceStateContext = persisted.Schema['libreTranslateInstance'] 8 - type SetInstanceContext = ( 9 - v: persisted.Schema['libreTranslateInstance'], 10 - ) => void 11 7 12 8 const stateContext = React.createContext<StateContext>( 13 9 persisted.defaults.translationServicePreference, ··· 15 11 const setContext = React.createContext<SetContext>( 16 12 (_: persisted.Schema['translationServicePreference']) => {}, 17 13 ) 18 - const instanceStateContext = React.createContext<InstanceStateContext>( 19 - persisted.defaults.libreTranslateInstance, 20 - ) 21 - const setInstanceContext = React.createContext<SetInstanceContext>( 22 - (_: persisted.Schema['libreTranslateInstance']) => {}, 23 - ) 24 14 25 15 export function Provider({children}: React.PropsWithChildren<{}>) { 26 16 const [state, setState] = React.useState( 27 17 persisted.get('translationServicePreference'), 28 18 ) 29 - const [instanceState, setInstanceState] = React.useState( 30 - persisted.get('libreTranslateInstance'), 31 - ) 32 19 33 20 const setStateWrapped = React.useCallback( 34 21 ( ··· 43 30 [setState], 44 31 ) 45 32 46 - const setInstanceStateWrapped = React.useCallback( 47 - (libreTranslateInstance: persisted.Schema['libreTranslateInstance']) => { 48 - setInstanceState(libreTranslateInstance) 49 - persisted.write('libreTranslateInstance', libreTranslateInstance) 50 - }, 51 - [setInstanceState], 52 - ) 53 - 54 33 React.useEffect(() => { 55 34 return persisted.onUpdate( 56 35 'translationServicePreference', ··· 60 39 ) 61 40 }, [setStateWrapped]) 62 41 63 - React.useEffect(() => { 64 - return persisted.onUpdate('libreTranslateInstance', nextInstance => { 65 - setInstanceState(nextInstance) 66 - }) 67 - }, [setInstanceStateWrapped]) 68 - 69 42 return ( 70 43 <stateContext.Provider value={state}> 71 44 <setContext.Provider value={setStateWrapped}> 72 - <instanceStateContext.Provider value={instanceState}> 73 - <setInstanceContext.Provider value={setInstanceStateWrapped}> 74 - {children} 75 - </setInstanceContext.Provider> 76 - </instanceStateContext.Provider> 45 + {children} 77 46 </setContext.Provider> 78 47 </stateContext.Provider> 79 48 ) ··· 86 55 export function useSetTranslationServicePreference() { 87 56 return React.useContext(setContext) 88 57 } 89 - 90 - export function useLibreTranslateInstance() { 91 - return ( 92 - React.useContext(instanceStateContext) ?? 93 - persisted.defaults.libreTranslateInstance! 94 - ) 95 - } 96 - 97 - export function useSetLibreTranslateInstance() { 98 - return React.useContext(setInstanceContext) 99 - }

History

2 rounds 0 comments
sign up or login to add to the discussion
2 commits
expand
feat: add Linkat links tab to profile
chore: remove unnecessary file
expand 0 comments
closed without merging
1 commit
expand
feat: add Linkat links tab to profile
expand 0 comments