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

Merge with upstream https://github.com/bluesky-social/social-app/

xan.lol 020904c9 810d1a52

verified
+804 -270
+2 -2
Dockerfile
··· 1 - FROM golang:1.24.5-bullseye AS build-env 2 3 WORKDIR /usr/src/social-app 4 ··· 89 -o /bskyweb \ 90 ./cmd/bskyweb 91 92 - FROM debian:bullseye-slim 93 94 ENV GODEBUG=netdns=go 95 ENV TZ=Etc/UTC
··· 1 + FROM golang:1.25-bookworm AS build-env 2 3 WORKDIR /usr/src/social-app 4 ··· 89 -o /bskyweb \ 90 ./cmd/bskyweb 91 92 + FROM debian:bookworm-slim 93 94 ENV GODEBUG=netdns=go 95 ENV TZ=Etc/UTC
+2 -2
Dockerfile.embedr
··· 1 - FROM golang:1.24.5-bullseye AS build-env 2 3 WORKDIR /usr/src/social-app 4 ··· 58 -o /embedr \ 59 ./cmd/embedr 60 61 - FROM debian:bullseye-slim 62 63 ENV GODEBUG=netdns=go 64 ENV TZ=Etc/UTC
··· 1 + FROM golang:1.25-bookworm AS build-env 2 3 WORKDIR /usr/src/social-app 4 ··· 58 -o /embedr \ 59 ./cmd/embedr 60 61 + FROM debian:bookworm-slim 62 63 ENV GODEBUG=netdns=go 64 ENV TZ=Etc/UTC
+1
assets/icons/bulletlist_stroke1_corner0_rounded.svg
···
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 46 38"><path stroke="#405168" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M22.333 31.667H45M22.333 6.333H45m-33.333 0A5.333 5.333 0 1 1 1 6.333a5.333 5.333 0 0 1 10.667 0Zm0 25.334a5.333 5.333 0 1 1-10.667 0 5.333 5.333 0 0 1 10.667 0Z"/></svg>
+1
assets/icons/circle_and_square_stroke1_corner0_rounded_filled.svg
···
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 62 53"><path fill="#405168" d="M28.173.231a5.653 5.653 0 0 1 7.018 3.83l2.66 9.046a20 20 0 0 1 3.986-.397c11.026 0 19.964 8.937 19.964 19.962l-.006.516c-.274 10.787-9.104 19.448-19.958 19.448l-.514-.007c-8.332-.21-15.394-5.528-18.178-12.938l-8.805 2.59a5.654 5.654 0 0 1-7.02-3.83L.232 14.34a5.654 5.654 0 0 1 3.83-7.018L28.172.23ZM41.838 14.71c-1.17 0-2.313.111-3.42.325l3.863 13.137a5.653 5.653 0 0 1-3.83 7.019L25.07 39.126c2.593 6.732 9.122 11.51 16.768 11.51 9.92 0 17.963-8.043 17.963-17.964S51.758 14.71 41.837 14.71ZM33.271 4.624a3.653 3.653 0 0 0-4.535-2.474L4.624 9.24a3.653 3.653 0 0 0-2.475 4.535l7.09 24.113a3.654 3.654 0 0 0 4.536 2.475l8.762-2.577a20 20 0 0 1-.662-5.114c0-8.961 5.905-16.544 14.037-19.069l-2.64-8.98Zm3.204 10.899c-7.302 2.28-12.601 9.096-12.601 17.15 0 1.571.203 3.095.582 4.548l13.431-3.948a3.654 3.654 0 0 0 2.474-4.536l-3.886-13.214Z"/></svg>
+1
assets/icons/editbig_stroke1_corner0_rounded.svg
···
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48"><path fill="#405168" d="M19.667 4.458a1 1 0 1 0 0-2v2Zm25 23a1 1 0 0 0-2 0h2ZM3.912 45.543l.454-.891-.454.89Zm-2.33-2.33.89-.455h0l-.89.454Zm39.173 2.33-.454-.891h0l.454.89Zm2.33-2.33-.89-.455.89.454ZM1.581 6.37l-.89-.454h0l.89.454Zm2.331-2.331-.454-.891.454.89ZM14.333 32.79h-1a1 1 0 0 0 1 1v-1Zm.781-8.781.707.707-.707-.707ZM36.562 2.562l-.707-.707v0l.707.707Zm7.543 0-.707.707v0l.707-.707Zm.457.458.707-.707v0l-.707.707Zm0 7.542.707.707-.707-.707ZM23.114 32.01l.707.707-.707-.707Zm12.02 14.114v-1h-25.6v2h25.6v-1ZM1 37.591h1v-25.6H0v25.6h1ZM9.533 3.458v1h10.134v-2H9.533v1Zm34.134 24h-1V37.59h2V27.457h-1ZM9.533 46.124v-1c-1.51 0-2.582 0-3.421-.07-.828-.067-1.34-.195-1.746-.402l-.454.89-.454.892c.735.374 1.54.537 2.491.614.94.077 2.107.076 3.584.076v-1ZM1 37.591H0c0 1.477 0 2.645.076 3.584.078.951.24 1.756.614 2.491l.891-.454.891-.454c-.207-.406-.335-.918-.403-1.746C2.001 40.173 2 39.101 2 37.591H1Zm2.912 7.952.454-.891a4.33 4.33 0 0 1-1.894-1.894l-.89.454-.892.454a6.33 6.33 0 0 0 2.768 2.768l.454-.891Zm31.221.581v1c1.477 0 2.645.001 3.585-.076.95-.078 1.756-.24 2.49-.614l-.453-.891-.454-.891c-.406.207-.919.335-1.746.403-.84.068-1.912.07-3.422.07v1Zm8.534-8.533h-1c0 1.51-.001 2.582-.07 3.421-.067.828-.196 1.34-.403 1.746l.891.454.891.454c.375-.735.537-1.54.615-2.49.076-.94.076-2.108.076-3.585h-1Zm-2.912 7.952.454.89a6.33 6.33 0 0 0 2.767-2.767l-.89-.454-.892-.454a4.33 4.33 0 0 1-1.893 1.894l.454.89ZM1 11.99h1c0-1.51 0-2.582.07-3.422.067-.827.195-1.34.402-1.745l-.89-.454-.892-.454c-.374.734-.536 1.54-.614 2.49C-.001 9.345 0 10.513 0 11.99h1Zm8.533-8.533v-1c-1.477 0-2.645-.001-3.584.076-.951.077-1.756.24-2.49.614l.453.89.454.892c.406-.207.918-.336 1.746-.403.839-.069 1.911-.07 3.421-.07v-1ZM1.581 6.37l.891.454A4.33 4.33 0 0 1 4.366 4.93l-.454-.891-.454-.891A6.33 6.33 0 0 0 .69 5.916l.891.454Zm12.752 19.525h-1v6.896h2v-6.896h-1Zm0 6.896v1h6.896v-2h-6.896v1Zm.781-8.781.707.707L37.27 3.269l-.707-.707-.707-.707-21.448 21.448.707.707Zm28.99-21.448-.706.707.457.458.707-.707.707-.707-.457-.458-.707.707Zm.458 8-.707-.707-21.448 21.448.707.707.707.707L45.27 11.269l-.707-.707Zm0-7.542-.707.707a4.333 4.333 0 0 1 0 6.128l.707.707.707.707a6.333 6.333 0 0 0 0-8.956l-.707.707Zm-8-.458.707.707a4.333 4.333 0 0 1 6.129 0l.707-.707.707-.707a6.333 6.333 0 0 0-8.957 0l.707.707ZM21.23 32.791v1c.972 0 1.905-.386 2.593-1.074l-.708-.707-.707-.707a1.67 1.67 0 0 1-1.178.488v1Zm-6.896-6.896h1c0-.442.176-.866.489-1.178l-.708-.707-.707-.707a3.67 3.67 0 0 0-1.074 2.592h1Z"/></svg>
+1
assets/icons/hashtagwide_stroke1_corner0_rounded.svg
···
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 46 46"><path stroke="#405168" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.333 1 9 45M37 1l-5.333 44M1 11.667h44m0 22.666H1"/></svg>
+1
assets/icons/heart2_stroke1_corner0_rounded.svg
···
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 50 45"><path stroke="#405168" stroke-linejoin="round" stroke-width="2" d="M49 17c0 15.333-22 26.667-24 26.667S1 32.333 1 17C1 6.333 7.667 1 14.333 1S25 5 25 5s4-4 10.667-4S49 6.333 49 17Z"/></svg>
+1
assets/icons/image_stroke1_corner0_rounded.svg
···
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 46 46"><path stroke="#080B12" stroke-linecap="round" stroke-width="1.5" d="m1.417 28.645 7.586-5.676a5.33 5.33 0 0 1 6.867.809c3.98 4.286 8.594 8.182 14.88 8.182 5.794 0 9.633-2.147 13.333-5.847m-38 18.637h33.334a5.333 5.333 0 0 0 5.333-5.333V6.083A5.333 5.333 0 0 0 39.417.75H6.083A5.333 5.333 0 0 0 .75 6.083v33.334a5.333 5.333 0 0 0 5.333 5.333ZM36.75 14.083a5.333 5.333 0 1 1-10.667 0 5.333 5.333 0 0 1 10.667 0Z"/></svg>
+1
assets/icons/message_stroke1_corner0_rounded_filled.svg
···
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 50 50"><path stroke="#405168" stroke-linecap="square" stroke-linejoin="round" stroke-width="2" d="M9 1h32a8 8 0 0 1 8 8v21.333a8 8 0 0 1-8 8H27.667L14.333 49V38.333H9a8 8 0 0 1-8-8V9a8 8 0 0 1 8-8Z"/></svg>
+1
assets/icons/peopleremove2_stroke1_corner0_rounded.svg
···
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 43 48"><path stroke="#405168" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.603 46.333H3.532c-1.572 0-2.816-1.358-2.472-2.891 2.033-9.046 9.421-15.775 19.543-15.775q1.367 0 2.666.16m18.667 7.84L36.603 41m0 0-5.334 5.333M36.603 41l-5.334-5.333M36.603 41l5.333 5.333m-12-36A9.333 9.333 0 1 1 20.603 1a9.333 9.333 0 0 1 9.333 9.333Z"/></svg>
+1
assets/icons/videoclip_stroke1_corner0_rounded.svg
···
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 46 46"><path stroke="#405168" stroke-linecap="square" stroke-linejoin="round" stroke-width="2" d="M1 23h10.667M1 23V12m0 11v11m10.667-11h22.666m-22.666 0v11m0-11V12m22.666 11H45m-10.667 0v12.222m0-12.222V12M45 23V12m0 11v12.222M34.333 45h5.334A5.333 5.333 0 0 0 45 39.667v-4.445M34.333 45v-9.778m0 9.778H11.667M34.333 1h5.334A5.333 5.333 0 0 1 45 6.333V12M34.333 1v11m0-11H11.667m22.666 11H45M34.333 35.222H45M11.667 45H6.333A5.333 5.333 0 0 1 1 39.667V34m10.667 11V34m0-33H6.333A5.333 5.333 0 0 0 1 6.333V12M11.667 1v11M1 12h10.667M1 34h10.667"/></svg>
+1 -1
bskyweb/go.mod
··· 1 module github.com/bluesky-social/social-app/bskyweb 2 3 - go 1.24.5 4 5 require ( 6 github.com/bluesky-social/indigo v0.0.0-20250729223159-573ae927246a
··· 1 module github.com/bluesky-social/social-app/bskyweb 2 3 + go 1.25 4 5 require ( 6 github.com/bluesky-social/indigo v0.0.0-20250729223159-573ae927246a
+2 -1
src/components/Button.tsx
··· 801 * also so that we can calculate transforms. 802 */ 803 const iconSize = { 804 - '2xs': 8, 805 xs: 12, 806 sm: 16, 807 md: 18, 808 lg: 24, 809 xl: 28, 810 '2xl': 32, 811 }[iconSizeShorthand] 812 813 /*
··· 801 * also so that we can calculate transforms. 802 */ 803 const iconSize = { 804 xs: 12, 805 sm: 16, 806 md: 18, 807 lg: 24, 808 xl: 28, 809 + '2xs': 8, 810 '2xl': 32, 811 + '3xl': 40, 812 }[iconSizeShorthand] 813 814 /*
+27
src/components/Lists.tsx
··· 4 import {useLingui} from '@lingui/react' 5 6 import {cleanError} from '#/lib/strings/errors' 7 import {CenteredView} from '#/view/com/util/Views' 8 import {atoms as a, useBreakpoints, useTheme} from '#/alf' 9 import {Button, ButtonText} from '#/components/Button' ··· 129 hideBackButton, 130 sideBorders, 131 topBorder = false, 132 }: { 133 isLoading: boolean 134 noEmpty?: boolean ··· 143 hideBackButton?: boolean 144 sideBorders?: boolean 145 topBorder?: boolean 146 }): React.ReactNode => { 147 const t = useTheme() 148 const {_} = useLingui() ··· 177 sideBorders={sideBorders} 178 hideBackButton={hideBackButton} 179 /> 180 ) 181 } 182
··· 4 import {useLingui} from '@lingui/react' 5 6 import {cleanError} from '#/lib/strings/errors' 7 + import { 8 + EmptyState, 9 + type EmptyStateButtonProps, 10 + } from '#/view/com/util/EmptyState' 11 import {CenteredView} from '#/view/com/util/Views' 12 import {atoms as a, useBreakpoints, useTheme} from '#/alf' 13 import {Button, ButtonText} from '#/components/Button' ··· 133 hideBackButton, 134 sideBorders, 135 topBorder = false, 136 + emptyStateIcon, 137 + emptyStateButton, 138 + useEmptyState = false, 139 }: { 140 isLoading: boolean 141 noEmpty?: boolean ··· 150 hideBackButton?: boolean 151 sideBorders?: boolean 152 topBorder?: boolean 153 + emptyStateIcon?: React.ComponentType<any> | React.ReactElement 154 + emptyStateButton?: EmptyStateButtonProps 155 + useEmptyState?: boolean 156 }): React.ReactNode => { 157 const t = useTheme() 158 const {_} = useLingui() ··· 187 sideBorders={sideBorders} 188 hideBackButton={hideBackButton} 189 /> 190 + ) 191 + } 192 + 193 + if (useEmptyState) { 194 + return ( 195 + <View style={[t.atoms.border_contrast_low]}> 196 + <EmptyState 197 + icon={emptyStateIcon} 198 + message={ 199 + emptyMessage ?? 200 + (emptyType === 'results' 201 + ? _(msg`No results found`) 202 + : _(msg`Page not found`)) 203 + } 204 + button={emptyStateButton} 205 + /> 206 + </View> 207 ) 208 } 209
+8 -1
src/components/StarterPack/Main/PostsList.tsx
··· 9 import {EmptyState} from '#/view/com/util/EmptyState' 10 import {type ListRef} from '#/view/com/util/List' 11 import {type SectionRef} from '#/screens/Profile/Sections/types' 12 13 interface ProfilesListProps { 14 listUri: string ··· 33 })) 34 35 const renderPostsEmpty = useCallback(() => { 36 - return <EmptyState icon="hashtag" message={_(msg`This feed is empty.`)} /> 37 }, [_]) 38 39 return (
··· 9 import {EmptyState} from '#/view/com/util/EmptyState' 10 import {type ListRef} from '#/view/com/util/List' 11 import {type SectionRef} from '#/screens/Profile/Sections/types' 12 + import {HashtagWide_Stroke1_Corner0_Rounded as HashtagWideIcon} from '#/components/icons/Hashtag' 13 14 interface ProfilesListProps { 15 listUri: string ··· 34 })) 35 36 const renderPostsEmpty = useCallback(() => { 37 + return ( 38 + <EmptyState 39 + icon={HashtagWideIcon} 40 + iconSize="2xl" 41 + message={_(msg`This feed is empty.`)} 42 + /> 43 + ) 44 }, [_]) 45 46 return (
+33 -1
src/components/StarterPack/ProfileStarterPacks.tsx
··· 21 import {logger} from '#/logger' 22 import {isIOS} from '#/platform/detection' 23 import {useActorStarterPacksQuery} from '#/state/queries/actor-starter-packs' 24 import {List, type ListRef} from '#/view/com/util/List' 25 import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' 26 import {atoms as a, ios, useTheme} from '#/alf' ··· 47 testID?: string 48 setScrollViewTag: (tag: number | null) => void 49 isMe: boolean 50 } 51 52 function keyExtractor(item: AppBskyGraphDefs.StarterPackView) { ··· 63 testID, 64 setScrollViewTag, 65 isMe, 66 }: ProfileFeedgensProps) { 67 const t = useTheme() 68 const bottomBarOffset = useBottomBarOffset(100) ··· 79 const {isTabletOrDesktop} = useWebMediaQueries() 80 81 const items = data?.pages.flatMap(page => page.starterPacks) 82 83 useImperativeHandle(ref, () => ({ 84 scrollToTop: () => {}, ··· 146 onEndReached={onEndReached} 147 onRefresh={onRefresh} 148 ListEmptyComponent={ 149 - data ? (isMe ? Empty : undefined) : FeedLoadingPlaceholder 150 } 151 ListFooterComponent={ 152 !!data && items?.length !== 0 && isMe ? CreateAnother : undefined
··· 21 import {logger} from '#/logger' 22 import {isIOS} from '#/platform/detection' 23 import {useActorStarterPacksQuery} from '#/state/queries/actor-starter-packs' 24 + import { 25 + EmptyState, 26 + type EmptyStateButtonProps, 27 + } from '#/view/com/util/EmptyState' 28 import {List, type ListRef} from '#/view/com/util/List' 29 import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' 30 import {atoms as a, ios, useTheme} from '#/alf' ··· 51 testID?: string 52 setScrollViewTag: (tag: number | null) => void 53 isMe: boolean 54 + emptyStateMessage?: string 55 + emptyStateButton?: EmptyStateButtonProps 56 + emptyStateIcon?: React.ComponentType<any> | React.ReactElement 57 } 58 59 function keyExtractor(item: AppBskyGraphDefs.StarterPackView) { ··· 70 testID, 71 setScrollViewTag, 72 isMe, 73 + emptyStateMessage, 74 + emptyStateButton, 75 + emptyStateIcon, 76 }: ProfileFeedgensProps) { 77 const t = useTheme() 78 const bottomBarOffset = useBottomBarOffset(100) ··· 89 const {isTabletOrDesktop} = useWebMediaQueries() 90 91 const items = data?.pages.flatMap(page => page.starterPacks) 92 + const {_} = useLingui() 93 + 94 + const EmptyComponent = useCallback(() => { 95 + if (emptyStateMessage || emptyStateButton || emptyStateIcon) { 96 + return ( 97 + <View style={[a.px_lg, a.align_center, a.justify_center]}> 98 + <EmptyState 99 + icon={emptyStateIcon} 100 + iconSize="3xl" 101 + message={ 102 + emptyStateMessage ?? 103 + _( 104 + 'Starter packs let you share your favorite feeds and people with your friends.', 105 + ) 106 + } 107 + button={emptyStateButton} 108 + /> 109 + </View> 110 + ) 111 + } 112 + return <Empty /> 113 + }, [_, emptyStateMessage, emptyStateButton, emptyStateIcon]) 114 115 useImperativeHandle(ref, () => ({ 116 scrollToTop: () => {}, ··· 178 onEndReached={onEndReached} 179 onRefresh={onRefresh} 180 ListEmptyComponent={ 181 + data ? (isMe ? EmptyComponent : undefined) : FeedLoadingPlaceholder 182 } 183 ListFooterComponent={ 184 !!data && items?.length !== 0 && isMe ? CreateAnother : undefined
+8
src/components/icons/BulletList.tsx
··· 1 import {createSinglePathSVG} from './TEMPLATE' 2 3 export const BulletList_Stroke2_Corner0_Rounded = createSinglePathSVG({ 4 path: 'M6 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2ZM3 7a3 3 0 1 1 6 0 3 3 0 0 1-6 0Zm9 0a1 1 0 0 1 1-1h7a1 1 0 1 1 0 2h-7a1 1 0 0 1-1-1Zm-6 9a1 1 0 1 0 0 2 1 1 0 0 0 0-2Zm-3 1a3 3 0 1 1 6 0 3 3 0 0 1-6 0Zm9 0a1 1 0 0 1 1-1h7a1 1 0 1 1 0 2h-7a1 1 0 0 1-1-1Z', 5 })
··· 1 import {createSinglePathSVG} from './TEMPLATE' 2 3 + export const BulletList_Stroke1_Corner0_Rounded = createSinglePathSVG({ 4 + viewBox: '0 0 47 38', 5 + strokeLinecap: 'round', 6 + strokeLinejoin: 'round', 7 + strokeWidth: 2, 8 + path: 'M22.333 31.667H45M22.333 6.333H45m-33.333 0A5.333 5.333 0 1 1 1 6.333a5.333 5.333 0 0 1 10.667 0Zm0 25.334a5.333 5.333 0 1 1-10.667 0 5.333 5.333 0 0 1 10.667 0Z', 9 + }) 10 + 11 export const BulletList_Stroke2_Corner0_Rounded = createSinglePathSVG({ 12 path: 'M6 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2ZM3 7a3 3 0 1 1 6 0 3 3 0 0 1-6 0Zm9 0a1 1 0 0 1 1-1h7a1 1 0 1 1 0 2h-7a1 1 0 0 1-1-1Zm-6 9a1 1 0 1 0 0 2 1 1 0 0 0 0-2Zm-3 1a3 3 0 1 1 6 0 3 3 0 0 1-6 0Zm9 0a1 1 0 0 1 1-1h7a1 1 0 1 1 0 2h-7a1 1 0 0 1-1-1Z', 13 })
+7
src/components/icons/CircleAndSquare.tsx
···
··· 1 + import {createSinglePathSVG} from './TEMPLATE' 2 + 3 + export const Circle_And_Square_Stroke1_Corner0_Rounded_Filled = 4 + createSinglePathSVG({ 5 + viewBox: '0 0 62 53', 6 + path: 'M28.173.231a5.653 5.653 0 0 1 7.018 3.83l2.66 9.046a20 20 0 0 1 3.986-.397c11.026 0 19.964 8.937 19.964 19.962l-.006.516c-.274 10.787-9.104 19.448-19.958 19.448l-.514-.007c-8.332-.21-15.394-5.528-18.178-12.938l-8.805 2.59a5.654 5.654 0 0 1-7.02-3.83L.232 14.34a5.654 5.654 0 0 1 3.83-7.018L28.172.23ZM41.838 14.71c-1.17 0-2.313.111-3.42.325l3.863 13.137a5.653 5.653 0 0 1-3.83 7.019L25.07 39.126c2.593 6.732 9.122 11.51 16.768 11.51 9.92 0 17.963-8.043 17.963-17.964S51.758 14.71 41.837 14.71ZM33.271 4.624a3.653 3.653 0 0 0-4.535-2.474L4.624 9.24a3.653 3.653 0 0 0-2.475 4.535l7.09 24.113a3.654 3.654 0 0 0 4.536 2.475l8.762-2.577a20 20 0 0 1-.662-5.114c0-8.961 5.905-16.544 14.037-19.069l-2.64-8.98Zm3.204 10.899c-7.302 2.28-12.601 9.096-12.601 17.15 0 1.571.203 3.095.582 4.548l13.431-3.948a3.654 3.654 0 0 0 2.474-4.536l-3.886-13.214Z', 7 + })
+5
src/components/icons/EditBig.tsx
··· 1 import {createSinglePathSVG} from './TEMPLATE' 2 3 export const EditBig_Stroke2_Corner0_Rounded = createSinglePathSVG({ 4 path: 'M17.293 2.293a1 1 0 0 1 1.414 0l3 3a1 1 0 0 1 0 1.414l-9 9A1 1 0 0 1 12 16H9a1 1 0 0 1-1-1v-3a1 1 0 0 1 .293-.707l9-9ZM10 12.414V14h1.586l8-8L18 4.414l-8 8ZM3 4a1 1 0 0 1 1-1h7a1 1 0 1 1 0 2H5v14h14v-6a1 1 0 1 1 2 0v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4Z', 5 })
··· 1 import {createSinglePathSVG} from './TEMPLATE' 2 3 + export const EditBig_Stroke1_Corner0_Rounded = createSinglePathSVG({ 4 + viewBox: '0 0 48 48', 5 + path: 'M19.667 4.458a1 1 0 1 0 0-2v2Zm25 23a1 1 0 0 0-2 0h2ZM3.912 45.543l.454-.891-.454.89Zm-2.33-2.33.89-.455h0l-.89.454Zm39.173 2.33-.454-.891h0l.454.89Zm2.33-2.33-.89-.455.89.454ZM1.581 6.37l-.89-.454h0l.89.454Zm2.331-2.331-.454-.891.454.89ZM14.333 32.79h-1a1 1 0 0 0 1 1v-1Zm.781-8.781.707.707-.707-.707ZM36.562 2.562l-.707-.707v0l.707.707Zm7.543 0-.707.707v0l.707-.707Zm.457.458.707-.707v0l-.707.707Zm0 7.542.707.707-.707-.707ZM23.114 32.01l.707.707-.707-.707Zm12.02 14.114v-1h-25.6v2h25.6v-1ZM1 37.591h1v-25.6H0v25.6h1ZM9.533 3.458v1h10.134v-2H9.533v1Zm34.134 24h-1V37.59h2V27.457h-1ZM9.533 46.124v-1c-1.51 0-2.582 0-3.421-.07-.828-.067-1.34-.195-1.746-.402l-.454.89-.454.892c.735.374 1.54.537 2.491.614.94.077 2.107.076 3.584.076v-1ZM1 37.591H0c0 1.477 0 2.645.076 3.584.078.951.24 1.756.614 2.491l.891-.454.891-.454c-.207-.406-.335-.918-.403-1.746C2.001 40.173 2 39.101 2 37.591H1Zm2.912 7.952.454-.891a4.33 4.33 0 0 1-1.894-1.894l-.89.454-.892.454a6.33 6.33 0 0 0 2.768 2.768l.454-.891Zm31.221.581v1c1.477 0 2.645.001 3.585-.076.95-.078 1.756-.24 2.49-.614l-.453-.891-.454-.891c-.406.207-.919.335-1.746.403-.84.068-1.912.07-3.422.07v1Zm8.534-8.533h-1c0 1.51-.001 2.582-.07 3.421-.067.828-.196 1.34-.403 1.746l.891.454.891.454c.375-.735.537-1.54.615-2.49.076-.94.076-2.108.076-3.585h-1Zm-2.912 7.952.454.89a6.33 6.33 0 0 0 2.767-2.767l-.89-.454-.892-.454a4.33 4.33 0 0 1-1.893 1.894l.454.89ZM1 11.99h1c0-1.51 0-2.582.07-3.422.067-.827.195-1.34.402-1.745l-.89-.454-.892-.454c-.374.734-.536 1.54-.614 2.49C-.001 9.345 0 10.513 0 11.99h1Zm8.533-8.533v-1c-1.477 0-2.645-.001-3.584.076-.951.077-1.756.24-2.49.614l.453.89.454.892c.406-.207.918-.336 1.746-.403.839-.069 1.911-.07 3.421-.07v-1ZM1.581 6.37l.891.454A4.33 4.33 0 0 1 4.366 4.93l-.454-.891-.454-.891A6.33 6.33 0 0 0 .69 5.916l.891.454Zm12.752 19.525h-1v6.896h2v-6.896h-1Zm0 6.896v1h6.896v-2h-6.896v1Zm.781-8.781.707.707L37.27 3.269l-.707-.707-.707-.707-21.448 21.448.707.707Zm28.99-21.448-.706.707.457.458.707-.707.707-.707-.457-.458-.707.707Zm.458 8-.707-.707-21.448 21.448.707.707.707.707L45.27 11.269l-.707-.707Zm0-7.542-.707.707a4.333 4.333 0 0 1 0 6.128l.707.707.707.707a6.333 6.333 0 0 0 0-8.956l-.707.707Zm-8-.458.707.707a4.333 4.333 0 0 1 6.129 0l.707-.707.707-.707a6.333 6.333 0 0 0-8.957 0l.707.707ZM21.23 32.791v1c.972 0 1.905-.386 2.593-1.074l-.708-.707-.707-.707a1.67 1.67 0 0 1-1.178.488v1Zm-6.896-6.896h1c0-.442.176-.866.489-1.178l-.708-.707-.707-.707a3.67 3.67 0 0 0-1.074 2.592h1Z', 6 + }) 7 + 8 export const EditBig_Stroke2_Corner0_Rounded = createSinglePathSVG({ 9 path: 'M17.293 2.293a1 1 0 0 1 1.414 0l3 3a1 1 0 0 1 0 1.414l-9 9A1 1 0 0 1 12 16H9a1 1 0 0 1-1-1v-3a1 1 0 0 1 .293-.707l9-9ZM10 12.414V14h1.586l8-8L18 4.414l-8 8ZM3 4a1 1 0 0 1 1-1h7a1 1 0 1 1 0 2H5v14h14v-6a1 1 0 1 1 2 0v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4Z', 10 })
+8
src/components/icons/Hashtag.tsx
··· 1 import {createSinglePathSVG} from './TEMPLATE' 2 3 export const Hashtag_Stroke2_Corner0_Rounded = createSinglePathSVG({ 4 path: 'M9.124 3.008a1 1 0 0 1 .868 1.116L9.632 7h5.985l.39-3.124a1 1 0 0 1 1.985.248L17.632 7H20a1 1 0 1 1 0 2h-2.617l-.75 6H20a1 1 0 1 1 0 2h-3.617l-.39 3.124a1 1 0 1 1-1.985-.248l.36-2.876H8.382l-.39 3.124a1 1 0 1 1-1.985-.248L6.368 17H4a1 1 0 1 1 0-2h2.617l.75-6H4a1 1 0 1 1 0-2h3.617l.39-3.124a1 1 0 0 1 1.117-.868ZM9.383 9l-.75 6h5.984l.75-6H9.383Z', 5 })
··· 1 import {createSinglePathSVG} from './TEMPLATE' 2 3 + export const HashtagWide_Stroke1_Corner0_Rounded = createSinglePathSVG({ 4 + viewBox: '0 0 46 46', 5 + strokeLinecap: 'round', 6 + strokeLinejoin: 'round', 7 + strokeWidth: 2, 8 + path: 'M14.333 1 9 45M37 1l-5.333 44M1 11.667h44m0 22.666H1', 9 + }) 10 + 11 export const Hashtag_Stroke2_Corner0_Rounded = createSinglePathSVG({ 12 path: 'M9.124 3.008a1 1 0 0 1 .868 1.116L9.632 7h5.985l.39-3.124a1 1 0 0 1 1.985.248L17.632 7H20a1 1 0 1 1 0 2h-2.617l-.75 6H20a1 1 0 1 1 0 2h-3.617l-.39 3.124a1 1 0 1 1-1.985-.248l.36-2.876H8.382l-.39 3.124a1 1 0 1 1-1.985-.248L6.368 17H4a1 1 0 1 1 0-2h2.617l.75-6H4a1 1 0 1 1 0-2h3.617l.39-3.124a1 1 0 0 1 1.117-.868ZM9.383 9l-.75 6h5.984l.75-6H9.383Z', 13 })
+7
src/components/icons/Heart2.tsx
··· 1 import {createSinglePathSVG} from './TEMPLATE' 2 3 export const Heart2_Stroke2_Corner0_Rounded = createSinglePathSVG({ 4 path: 'M16.734 5.091c-1.238-.276-2.708.047-4.022 1.38a1 1 0 0 1-1.424 0C9.974 5.137 8.504 4.814 7.266 5.09c-1.263.282-2.379 1.206-2.92 2.556C3.33 10.18 4.252 14.84 12 19.348c7.747-4.508 8.67-9.168 7.654-11.7-.541-1.351-1.657-2.275-2.92-2.557Zm4.777 1.812c1.604 4-.494 9.69-9.022 14.47a1 1 0 0 1-.978 0C2.983 16.592.885 10.902 2.49 6.902c.779-1.942 2.414-3.334 4.342-3.764 1.697-.378 3.552.003 5.169 1.286 1.617-1.283 3.472-1.664 5.17-1.286 1.927.43 3.562 1.822 4.34 3.764Z', 5 })
··· 1 import {createSinglePathSVG} from './TEMPLATE' 2 3 + export const Heart2_Stroke1_Corner0_Rounded = createSinglePathSVG({ 4 + viewBox: '0 0 51 46', 5 + strokeLinejoin: 'round', 6 + strokeWidth: 2, 7 + path: 'M49 17c0 15.333-22 26.667-24 26.667S1 32.333 1 17C1 6.333 7.667 1 14.333 1S25 5 25 5s4-4 10.667-4S49 6.333 49 17Z', 8 + }) 9 + 10 export const Heart2_Stroke2_Corner0_Rounded = createSinglePathSVG({ 11 path: 'M16.734 5.091c-1.238-.276-2.708.047-4.022 1.38a1 1 0 0 1-1.424 0C9.974 5.137 8.504 4.814 7.266 5.09c-1.263.282-2.379 1.206-2.92 2.556C3.33 10.18 4.252 14.84 12 19.348c7.747-4.508 8.67-9.168 7.654-11.7-.541-1.351-1.657-2.275-2.92-2.557Zm4.777 1.812c1.604 4-.494 9.69-9.022 14.47a1 1 0 0 1-.978 0C2.983 16.592.885 10.902 2.49 6.902c.779-1.942 2.414-3.334 4.342-3.764 1.697-.378 3.552.003 5.169 1.286 1.617-1.283 3.472-1.664 5.17-1.286 1.927.43 3.562 1.822 4.34 3.764Z', 12 })
+7
src/components/icons/Image.tsx
··· 1 import {createSinglePathSVG} from './TEMPLATE' 2 3 export const Image_Stroke2_Corner0_Rounded = createSinglePathSVG({ 4 path: 'M3 4a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4Zm2 1v7.213l1.246-.932.044-.03a3 3 0 0 1 3.863.454c1.468 1.58 2.941 2.749 4.847 2.749 1.703 0 2.855-.555 4-1.618V5H5Zm14 10.357c-1.112.697-2.386 1.097-4 1.097-2.81 0-4.796-1.755-6.313-3.388a1 1 0 0 0-1.269-.164L5 14.712V19h14v-3.643ZM15 8a1 1 0 1 0 0 2 1 1 0 0 0 0-2Zm-3 1a3 3 0 1 1 6 0 3 3 0 0 1-6 0Z', 5 })
··· 1 import {createSinglePathSVG} from './TEMPLATE' 2 3 + export const Image_Stroke1_Corner0_Rounded = createSinglePathSVG({ 4 + viewBox: '0 0 46 46', 5 + strokeLinecap: 'round', 6 + strokeWidth: 1.5, 7 + path: 'm1.417 28.645 7.586-5.676a5.33 5.33 0 0 1 6.867.809c3.98 4.286 8.594 8.182 14.88 8.182 5.794 0 9.633-2.147 13.333-5.847m-38 18.637h33.334a5.333 5.333 0 0 0 5.333-5.333V6.083A5.333 5.333 0 0 0 39.417.75H6.083A5.333 5.333 0 0 0 .75 6.083v33.334a5.333 5.333 0 0 0 5.333 5.333ZM36.75 14.083a5.333 5.333 0 1 1-10.667 0 5.333 5.333 0 0 1 10.667 0Z', 8 + }) 9 + 10 export const Image_Stroke2_Corner0_Rounded = createSinglePathSVG({ 11 path: 'M3 4a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4Zm2 1v7.213l1.246-.932.044-.03a3 3 0 0 1 3.863.454c1.468 1.58 2.941 2.749 4.847 2.749 1.703 0 2.855-.555 4-1.618V5H5Zm14 10.357c-1.112.697-2.386 1.097-4 1.097-2.81 0-4.796-1.755-6.313-3.388a1 1 0 0 0-1.269-.164L5 14.712V19h14v-3.643ZM15 8a1 1 0 1 0 0 2 1 1 0 0 0 0-2Zm-3 1a3 3 0 1 1 6 0 3 3 0 0 1-6 0Z', 12 })
+8
src/components/icons/Message.tsx
··· 1 import {createSinglePathSVG} from './TEMPLATE' 2 3 export const Message_Stroke2_Corner0_Rounded_Filled = createSinglePathSVG({ 4 path: 'M2 12C2 6.477 6.477 2 12 2s10 4.477 10 10-4.477 10-10 10a9.968 9.968 0 0 1-4.136-.893l-4.68.876a1 1 0 0 1-1.164-1.184l.931-4.537A9.965 9.965 0 0 1 2 12Zm4.25 0a1.25 1.25 0 1 0 2.5 0 1.25 1.25 0 0 0-2.5 0Zm4.5 0a1.25 1.25 0 1 0 2.5 0 1.25 1.25 0 0 0-2.5 0Zm5.75 1.25a1.25 1.25 0 1 1 0-2.5 1.25 1.25 0 0 1 0 2.5Z', 5 })
··· 1 import {createSinglePathSVG} from './TEMPLATE' 2 3 + export const Message_Stroke1_Corner0_Rounded_Filled = createSinglePathSVG({ 4 + viewBox: '0 0 51 51', 5 + strokeWidth: 2, 6 + strokeLinecap: 'square', 7 + strokeLinejoin: 'round', 8 + path: 'M9 1h32a8 8 0 0 1 8 8v21.333a8 8 0 0 1-8 8H27.667L14.333 49V38.333H9a8 8 0 0 1-8-8V9a8 8 0 0 1 8-8Z', 9 + }) 10 + 11 export const Message_Stroke2_Corner0_Rounded_Filled = createSinglePathSVG({ 12 path: 'M2 12C2 6.477 6.477 2 12 2s10 4.477 10 10-4.477 10-10 10a9.968 9.968 0 0 1-4.136-.893l-4.68.876a1 1 0 0 1-1.164-1.184l.931-4.537A9.965 9.965 0 0 1 2 12Zm4.25 0a1.25 1.25 0 1 0 2.5 0 1.25 1.25 0 0 0-2.5 0Zm4.5 0a1.25 1.25 0 1 0 2.5 0 1.25 1.25 0 0 0-2.5 0Zm5.75 1.25a1.25 1.25 0 1 1 0-2.5 1.25 1.25 0 0 1 0 2.5Z', 13 })
+8
src/components/icons/PeopleRemove2.tsx
··· 1 import {createSinglePathSVG} from './TEMPLATE' 2 3 export const PeopleRemove2_Stroke2_Corner0_Rounded = createSinglePathSVG({ 4 path: 'M10 4a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5ZM5.5 6.5a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM16 11a1 1 0 0 1 1-1h5a1 1 0 1 1 0 2h-5a1 1 0 0 1-1-1ZM3.678 19h12.644c-.71-2.909-3.092-5-6.322-5s-5.613 2.091-6.322 5Zm-2.174.906C1.917 15.521 5.242 12 10 12c4.758 0 8.083 3.521 8.496 7.906A1 1 0 0 1 17.5 21h-15a1 1 0 0 1-.996-1.094Z', 5 })
··· 1 import {createSinglePathSVG} from './TEMPLATE' 2 3 + export const PeopleRemove2_Stroke1_Corner0_Rounded = createSinglePathSVG({ 4 + viewBox: '-15 0 65 64', 5 + strokeWidth: 2, 6 + strokeLinecap: 'round', 7 + strokeLinejoin: 'round', 8 + path: 'M20.603 46.333H3.532c-1.572 0-2.816-1.358-2.472-2.891 2.033-9.046 9.421-15.775 19.543-15.775q1.367 0 2.666.16m18.667 7.84L36.603 41m0 0-5.334 5.333M36.603 41l-5.334-5.333M36.603 41l5.333 5.333m-12-36A9.333 9.333 0 1 1 20.603 1a9.333 9.333 0 0 1 9.333 9.333Z', 9 + }) 10 + 11 export const PeopleRemove2_Stroke2_Corner0_Rounded = createSinglePathSVG({ 12 path: 'M10 4a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5ZM5.5 6.5a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM16 11a1 1 0 0 1 1-1h5a1 1 0 1 1 0 2h-5a1 1 0 0 1-1-1ZM3.678 19h12.644c-.71-2.909-3.092-5-6.322-5s-5.613 2.091-6.322 5Zm-2.174.906C1.917 15.521 5.242 12 10 12c4.758 0 8.083 3.521 8.496 7.906A1 1 0 0 1 17.5 21h-15a1 1 0 0 1-.996-1.094Z', 13 })
+44 -1
src/components/icons/TEMPLATE.tsx
··· 28 }, 29 ) 30 31 - export function createSinglePathSVG({path}: {path: string}) { 32 return React.forwardRef<Svg, Props>(function LogoImpl(props, ref) { 33 const {fill, size, style, gradient, ...rest} = useCommonSVGProps(props) 34
··· 28 }, 29 ) 30 31 + export function createSinglePathSVG({ 32 + path, 33 + viewBox, 34 + strokeWidth = 0, 35 + strokeLinecap = 'butt', 36 + strokeLinejoin = 'miter', 37 + }: { 38 + path: string 39 + viewBox?: string 40 + strokeWidth?: number 41 + strokeLinecap?: 'butt' | 'round' | 'square' 42 + strokeLinejoin?: 'miter' | 'round' | 'bevel' 43 + }) { 44 + return React.forwardRef<Svg, Props>(function LogoImpl(props, ref) { 45 + const {fill, size, style, gradient, ...rest} = useCommonSVGProps(props) 46 + 47 + const hasStroke = strokeWidth > 0 48 + 49 + return ( 50 + <Svg 51 + fill="none" 52 + {...rest} 53 + ref={ref} 54 + viewBox={viewBox || '0 0 24 24'} 55 + width={size} 56 + height={size} 57 + style={[style]}> 58 + {gradient} 59 + <Path 60 + fill={hasStroke ? 'none' : fill} 61 + stroke={hasStroke ? fill : 'none'} 62 + strokeWidth={strokeWidth} 63 + strokeLinecap={strokeLinecap} 64 + strokeLinejoin={strokeLinejoin} 65 + fillRule="evenodd" 66 + clipRule="evenodd" 67 + d={path} 68 + /> 69 + </Svg> 70 + ) 71 + }) 72 + } 73 + 74 + export function createSinglePathSVG2({path}: {path: string}) { 75 return React.forwardRef<Svg, Props>(function LogoImpl(props, ref) { 76 const {fill, size, style, gradient, ...rest} = useCommonSVGProps(props) 77
+8
src/components/icons/VideoClip.tsx
··· 1 import {createSinglePathSVG} from './TEMPLATE' 2 3 export const VideoClip_Stroke2_Corner0_Rounded = createSinglePathSVG({ 4 path: 'M3 4a1 1 0 011-1h16a1 1 0 011 1v16a1 1 0 01-1 1H4a1 1 0 01-1-1V4Zm2 1v2h2V5H5Zm4 0v6h6V5H9Zm8 0v2h2V5h-2Zm2 4h-2v2h2V9Zm0 4h-2v2h2V13Zm0 4h-2V19h2ZM15 19v-6H9v6h6Zm-8 0v-2H5v2h2Zm-2-4h2v-2H5v2Zm0-4h2V9H5v2Z', 5 })
··· 1 import {createSinglePathSVG} from './TEMPLATE' 2 3 + export const VideoClip_Stroke1_Corner0_Rounded = createSinglePathSVG({ 4 + viewBox: '0 0 46 46', 5 + strokeLinecap: 'square', 6 + strokeLinejoin: 'round', 7 + strokeWidth: 2, 8 + path: 'M1 23h10.667M1 23V12m0 11v11m10.667-11h22.666m-22.666 0v11m0-11V12m22.666 11H45m-10.667 0v12.222m0-12.222V12M45 23V12m0 11v12.222M34.333 45h5.334A5.333 5.333 0 0 0 45 39.667v-4.445M34.333 45v-9.778m0 9.778H11.667M34.333 1h5.334A5.333 5.333 0 0 1 45 6.333V12M34.333 1v11m0-11H11.667m22.666 11H45M34.333 35.222H45M11.667 45H6.333A5.333 5.333 0 0 1 1 39.667V34m10.667 11V34m0-33H6.333A5.333 5.333 0 0 0 1 6.333V12M11.667 1v11M1 12h10.667M1 34h10.667', 9 + }) 10 + 11 export const VideoClip_Stroke2_Corner0_Rounded = createSinglePathSVG({ 12 path: 'M3 4a1 1 0 011-1h16a1 1 0 011 1v16a1 1 0 01-1 1H4a1 1 0 01-1-1V4Zm2 1v2h2V5H5Zm4 0v6h6V5H9Zm8 0v2h2V5h-2Zm2 4h-2v2h2V9Zm0 4h-2v2h2V13Zm0 4h-2V19h2ZM15 19v-6H9v6h6Zm-8 0v-2H5v2h2Zm-2-4h2v-2H5v2Zm0-4h2V9H5v2Z', 13 })
+1
src/components/icons/common.tsx
··· 20 lg: 24, 21 xl: 28, 22 '2xl': 32, 23 } as const 24 25 export function useCommonSVGProps(props: Props) {
··· 20 lg: 24, 21 xl: 28, 22 '2xl': 32, 23 + '3xl': 48, 24 } as const 25 26 export function useCommonSVGProps(props: Props) {
+12
src/lib/strings/errors.ts
··· 52 const str = String(e) 53 return str.includes('Bad token scope') || str.includes('Bad token method') 54 }
··· 52 const str = String(e) 53 return str.includes('Bad token scope') || str.includes('Bad token method') 54 } 55 + 56 + /** 57 + * Intended to capture "User cancelled" or "Crop cancelled" errors 58 + * that we often get from expo modules such expo-image-crop-tool 59 + * 60 + * The exact name has changed in the past so let's just see if the string 61 + * contains "cancel" 62 + */ 63 + export function isCancelledError(e: unknown) { 64 + const str = String(e).toLowerCase() 65 + return str.includes('cancel') 66 + }
+11 -1
src/lib/strings/time.ts
··· 1 import {type I18n} from '@lingui/core' 2 3 export function niceDate( 4 i18n: I18n, 5 date: number | string | Date, 6 - dateStyle: 'short' | 'medium' | 'long' | 'full' = 'long', 7 ) { 8 const d = new Date(date) 9 10 return i18n.date(d, { 11 dateStyle,
··· 1 import {type I18n} from '@lingui/core' 2 + import {msg} from '@lingui/macro' 3 4 export function niceDate( 5 i18n: I18n, 6 date: number | string | Date, 7 + dateStyle: 'short' | 'medium' | 'long' | 'full' | 'dot separated' = 'long', 8 ) { 9 const d = new Date(date) 10 + 11 + if (dateStyle === 'dot separated') { 12 + return i18n._( 13 + msg({ 14 + context: 'date and time formatted like this: [time] · [date]', 15 + message: `${i18n.date(d, {timeStyle: 'short'})} · ${i18n.date(d, {day: 'numeric', month: 'numeric', year: '2-digit'})}`, 16 + }), 17 + ) 18 + } 19 20 return i18n.date(d, { 21 dateStyle,
+199 -126
src/locale/locales/en/messages.po
··· 128 msgid "{0, plural, other {+# more}}" 129 msgstr "" 130 131 #: src/components/moderation/ContentHider.tsx:89 132 msgid "{0} (Account)" 133 msgstr "" ··· 695 msgid "Add a temporary live status to your profile. When someone clicks on your avatar, they’ll see information about your live event." 696 msgstr "" 697 698 - #: src/screens/ProfileList/AboutSection.tsx:62 699 - #: src/screens/ProfileList/AboutSection.tsx:80 700 msgid "Add a user to this list" 701 msgstr "" 702 ··· 738 msgid "Add app password" 739 msgstr "" 740 741 - #: src/screens/Settings/AppPasswords.tsx:73 742 - #: src/screens/Settings/AppPasswords.tsx:81 743 #: src/screens/Settings/components/AddAppPasswordDialog.tsx:111 744 msgid "Add App Password" 745 msgstr "" ··· 766 msgid "Add muted words and tags" 767 msgstr "" 768 769 - #: src/screens/ProfileList/AboutSection.tsx:70 770 - #: src/screens/ProfileList/AboutSection.tsx:88 771 msgid "Add people" 772 msgstr "" 773 ··· 958 msgid "Allow your followers to reply" 959 msgstr "" 960 961 - #: src/screens/Settings/AppPasswords.tsx:199 962 msgid "Allows access to direct messages" 963 msgstr "" 964 ··· 996 msgid "Alt Text" 997 msgstr "" 998 999 - #: src/view/com/composer/photos/Gallery.tsx:260 1000 msgid "Alt text describes images for blind and low-vision users, and helps give context to everyone." 1001 msgstr "" 1002 ··· 1031 msgid "An error occurred while fetching the feed." 1032 msgstr "" 1033 1034 - #: src/components/StarterPack/ProfileStarterPacks.tsx:339 1035 msgid "An error occurred while generating your starter pack. Want to try again?" 1036 msgstr "" 1037 ··· 1160 msgid "App Password" 1161 msgstr "" 1162 1163 - #: src/screens/Settings/AppPasswords.tsx:145 1164 msgctxt "toast" 1165 msgid "App password deleted" 1166 msgstr "" ··· 1183 msgstr "" 1184 1185 #: src/Navigation.tsx:351 1186 - #: src/screens/Settings/AppPasswords.tsx:49 1187 msgid "App Passwords" 1188 msgstr "" 1189 ··· 1244 msgid "Archived post" 1245 msgstr "" 1246 1247 - #: src/screens/Settings/AppPasswords.tsx:208 1248 msgid "Are you sure you want to delete the app password \"{0}\"?" 1249 msgstr "" 1250 ··· 1368 msgstr "" 1369 1370 #: src/components/dialogs/StarterPackDialog.tsx:71 1371 - #: src/components/StarterPack/ProfileStarterPacks.tsx:231 1372 - #: src/components/StarterPack/ProfileStarterPacks.tsx:241 1373 msgid "Before creating a starter pack, you must first verify your email." 1374 msgstr "" 1375 ··· 1530 msgid "Bluesky Social Terms of Service" 1531 msgstr "" 1532 1533 - #: src/components/StarterPack/ProfileStarterPacks.tsx:306 1534 msgid "Bluesky will choose a set of recommended accounts from people in your network." 1535 msgstr "" 1536 ··· 1565 1566 #: src/components/moderation/ReportDialog/utils/useReportOptions.ts:215 1567 msgid "Breaking site rules" 1568 msgstr "" 1569 1570 #: src/components/FeedInterstitials.tsx:436 ··· 1613 msgid "Business" 1614 msgstr "" 1615 1616 #: src/components/LabelingServiceCard/index.tsx:62 1617 #: src/components/moderation/ReportDialog/index.tsx:834 1618 #: src/screens/Search/components/StarterPackCard.tsx:106 ··· 1880 msgid "Choose Feeds" 1881 msgstr "" 1882 1883 - #: src/components/StarterPack/ProfileStarterPacks.tsx:314 1884 msgid "Choose for me" 1885 msgstr "" 1886 ··· 2447 msgid "Could not leave chat" 2448 msgstr "" 2449 2450 - #: src/screens/Profile/ProfileFeed/index.tsx:83 2451 msgid "Could not load feed" 2452 msgstr "" 2453 ··· 2477 #. Text on button to create a new starter pack 2478 #: src/components/dialogs/StarterPackDialog.tsx:112 2479 #: src/components/dialogs/StarterPackDialog.tsx:201 2480 - #: src/components/StarterPack/ProfileStarterPacks.tsx:296 2481 msgid "Create" 2482 msgstr "" 2483 2484 #: src/components/StarterPack/QrCodeDialog.tsx:163 2485 msgid "Create a QR code for a starter pack" 2486 msgstr "" 2487 2488 - #: src/components/StarterPack/ProfileStarterPacks.tsx:174 2489 - #: src/components/StarterPack/ProfileStarterPacks.tsx:283 2490 #: src/Navigation.tsx:589 2491 msgid "Create a starter pack" 2492 msgstr "" 2493 2494 - #: src/components/StarterPack/ProfileStarterPacks.tsx:270 2495 msgid "Create a starter pack for me" 2496 msgstr "" 2497 ··· 2528 msgid "Create an avatar instead" 2529 msgstr "" 2530 2531 - #: src/components/StarterPack/ProfileStarterPacks.tsx:181 2532 msgid "Create another" 2533 msgstr "" 2534 ··· 2556 msgid "Create user list" 2557 msgstr "" 2558 2559 - #: src/screens/Settings/AppPasswords.tsx:172 2560 msgid "Created {0}" 2561 msgstr "" 2562 ··· 2602 msgid "Dark" 2603 msgstr "" 2604 2605 - #: src/view/screens/Debug.tsx:68 2606 msgid "Dark mode" 2607 msgstr "" 2608 ··· 2624 msgid "Debug Moderation" 2625 msgstr "" 2626 2627 - #: src/view/screens/Debug.tsx:88 2628 msgid "Debug panel" 2629 msgstr "" 2630 ··· 2644 #: src/components/PostControls/PostMenu/PostMenuItems.tsx:736 2645 #: src/screens/Messages/components/ChatStatusInfo.tsx:55 2646 #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:280 2647 - #: src/screens/Settings/AppPasswords.tsx:211 2648 #: src/screens/StarterPack/StarterPackScreen.tsx:601 2649 #: src/screens/StarterPack/StarterPackScreen.tsx:690 2650 #: src/screens/StarterPack/StarterPackScreen.tsx:762 ··· 2660 msgid "Delete Account <0>\"</0><1>{0}</1><2>\"</2>" 2661 msgstr "" 2662 2663 - #: src/screens/Settings/AppPasswords.tsx:185 2664 msgid "Delete app password" 2665 msgstr "" 2666 2667 - #: src/screens/Settings/AppPasswords.tsx:206 2668 msgid "Delete app password?" 2669 msgstr "" 2670 ··· 3260 msgid "Enabled" 3261 msgstr "" 3262 3263 - #: src/screens/Profile/Sections/Feed.tsx:109 3264 msgid "End of feed" 3265 msgstr "" 3266 ··· 3746 #: src/screens/Search/SearchResults.tsx:77 3747 #: src/screens/StarterPack/StarterPackScreen.tsx:190 3748 #: src/view/screens/Feeds.tsx:511 3749 - #: src/view/screens/Profile.tsx:230 3750 #: src/view/shell/desktop/LeftNav.tsx:728 3751 #: src/view/shell/Drawer.tsx:530 3752 msgid "Feeds" ··· 4056 msgid "From <0/>" 4057 msgstr "" 4058 4059 - #: src/components/StarterPack/ProfileStarterPacks.tsx:303 4060 msgid "Generate a starter pack" 4061 msgstr "" 4062 ··· 4147 #: src/components/moderation/ScreenHider.tsx:160 4148 #: src/components/moderation/ScreenHider.tsx:169 4149 #: src/screens/Messages/Inbox.tsx:251 4150 - #: src/screens/Profile/ProfileFeed/index.tsx:92 4151 #: src/screens/ProfileList/components/ErrorScreen.tsx:34 4152 #: src/screens/ProfileList/components/ErrorScreen.tsx:40 4153 #: src/screens/VideoFeed/components/Header.tsx:163 4154 #: src/screens/VideoFeed/index.tsx:1162 4155 #: src/screens/VideoFeed/index.tsx:1166 4156 #: src/view/com/auth/LoggedOut.tsx:72 4157 #: src/view/screens/NotFound.tsx:57 4158 msgid "Go back" 4159 msgstr "" ··· 4162 #: src/screens/List/ListHiddenScreen.tsx:224 4163 #: src/screens/Profile/ErrorState.tsx:62 4164 #: src/screens/Profile/ErrorState.tsx:66 4165 - #: src/screens/Profile/ProfileFeed/index.tsx:97 4166 #: src/screens/StarterPack/StarterPackScreen.tsx:775 4167 #: src/view/screens/NotFound.tsx:56 4168 msgid "Go Back" ··· 4180 msgid "Go home" 4181 msgstr "" 4182 4183 #: src/view/screens/NotFound.tsx:57 4184 msgid "Go home" 4185 msgstr "" ··· 4433 msgid "Hides the content" 4434 msgstr "" 4435 4436 - #: src/view/com/posts/PostFeedErrorMessage.tsx:121 4437 msgid "Hmm, some kind of issue occurred when contacting the feed server. Please let the feed owner know about this issue." 4438 msgstr "" 4439 4440 - #: src/view/com/posts/PostFeedErrorMessage.tsx:109 4441 msgid "Hmm, the feed server appears to be misconfigured. Please let the feed owner know about this issue." 4442 msgstr "" 4443 4444 - #: src/view/com/posts/PostFeedErrorMessage.tsx:115 4445 msgid "Hmm, the feed server appears to be offline. Please let the feed owner know about this issue." 4446 msgstr "" 4447 4448 - #: src/view/com/posts/PostFeedErrorMessage.tsx:112 4449 msgid "Hmm, the feed server gave a bad response. Please let the feed owner know about this issue." 4450 msgstr "" 4451 4452 - #: src/view/com/posts/PostFeedErrorMessage.tsx:106 4453 msgid "Hmm, we're having trouble finding this feed. It may have been deleted." 4454 msgstr "" 4455 ··· 4763 msgstr "" 4764 4765 #: src/view/com/composer/labels/LabelsBtn.tsx:69 4766 - #: src/view/screens/Profile.tsx:223 4767 msgid "Labels" 4768 msgstr "" 4769 ··· 4905 msgid "left to go." 4906 msgstr "" 4907 4908 - #: src/components/StarterPack/ProfileStarterPacks.tsx:319 4909 msgid "Let me choose" 4910 msgstr "" 4911 ··· 4986 #: src/lib/hooks/useNotificationHandler.ts:126 4987 #: src/screens/Settings/NotificationSettings/index.tsx:126 4988 #: src/screens/Settings/NotificationSettings/LikeNotificationSettings.tsx:41 4989 - #: src/view/screens/Profile.tsx:229 4990 msgid "Likes" 4991 msgstr "" 4992 ··· 5091 5092 #: src/Navigation.tsx:172 5093 #: src/view/screens/Lists.tsx:67 5094 - #: src/view/screens/Profile.tsx:224 5095 - #: src/view/screens/Profile.tsx:232 5096 #: src/view/shell/desktop/LeftNav.tsx:746 5097 #: src/view/shell/Drawer.tsx:545 5098 msgid "Lists" 5099 msgstr "" 5100 5101 #: src/components/dms/BlockedByListDialog.tsx:39 ··· 5131 msgid "Load new notifications" 5132 msgstr "" 5133 5134 - #: src/screens/Profile/ProfileFeed/index.tsx:224 5135 - #: src/screens/Profile/Sections/Feed.tsx:94 5136 - #: src/screens/ProfileList/FeedSection.tsx:105 5137 #: src/view/com/feeds/FeedPage.tsx:169 5138 msgid "Load new posts" 5139 msgstr "" ··· 5195 msgid "Make adjustments to email settings for your account" 5196 msgstr "" 5197 5198 - #: src/components/StarterPack/ProfileStarterPacks.tsx:278 5199 msgid "Make one for me" 5200 msgstr "" 5201 ··· 5237 msgid "Maybe later" 5238 msgstr "" 5239 5240 - #: src/view/screens/Profile.tsx:227 5241 msgid "Media" 5242 msgstr "" 5243 ··· 5281 msgid "Message from @{0}: {1}" 5282 msgstr "" 5283 5284 - #: src/view/com/posts/PostFeedErrorMessage.tsx:205 5285 msgid "Message from server: {0}" 5286 msgstr "" 5287 ··· 5625 msgid "New password" 5626 msgstr "" 5627 5628 - #: src/screens/Profile/ProfileFeed/index.tsx:241 5629 #: src/screens/ProfileList/index.tsx:246 5630 #: src/screens/ProfileList/index.tsx:284 5631 #: src/view/screens/Feeds.tsx:552 5632 #: src/view/screens/Notifications.tsx:167 5633 - #: src/view/screens/Profile.tsx:510 5634 msgid "New post" 5635 msgstr "" 5636 ··· 5699 msgid "No ads, no invasive tracking, no engagement traps. Bluesky respects your time and attention." 5700 msgstr "" 5701 5702 - #: src/screens/Settings/AppPasswords.tsx:106 5703 msgid "No app passwords yet" 5704 msgstr "" 5705 ··· 5720 msgid "No feeds found. Try searching for something else." 5721 msgstr "" 5722 5723 #: src/components/live/LinkPreview.tsx:63 5724 msgid "No image" 5725 msgstr "" 5726 5727 #: src/components/LikedByList.tsx:84 5728 #: src/view/com/post-thread/PostLikedBy.tsx:84 5729 msgid "No likes yet" 5730 msgstr "" 5731 ··· 5735 msgid "No longer following {0}" 5736 msgstr "" 5737 5738 #: src/screens/Messages/components/ChatListItem.tsx:142 5739 msgid "No messages yet" 5740 msgstr "" ··· 5743 msgid "No more doomscrolling junk-filled algorithms. Find feeds that work for you, not against you." 5744 msgstr "" 5745 5746 - #: src/view/com/notifications/NotificationFeed.tsx:122 5747 msgid "No notifications yet!" 5748 msgstr "" 5749 ··· 5759 msgid "No one but the author can quote this post." 5760 msgstr "" 5761 5762 - #: src/screens/Notifications/ActivityList.tsx:38 5763 msgid "No posts here" 5764 msgstr "" 5765 5766 - #: src/screens/Profile/Sections/Feed.tsx:62 5767 - msgid "No posts yet." 5768 msgstr "" 5769 5770 #: src/view/com/post-thread/PostQuotes.tsx:105 5771 msgid "No quotes yet" 5772 msgstr "" 5773 5774 #: src/view/com/post-thread/PostRepostedBy.tsx:90 5775 msgid "No reposts yet" 5776 msgstr "" ··· 5789 msgid "No results for \"{0}\"." 5790 msgstr "" 5791 5792 - #: src/components/Lists.tsx:189 5793 msgid "No results found" 5794 msgstr "" 5795 ··· 5814 msgid "No thanks" 5815 msgstr "" 5816 5817 #: src/components/dialogs/PostInteractionSettingsDialog.tsx:465 5818 msgid "Nobody" 5819 msgstr "" ··· 5852 msgstr "" 5853 5854 #: src/Navigation.tsx:167 5855 - #: src/view/screens/Profile.tsx:125 5856 msgid "Not Found" 5857 msgstr "" 5858 ··· 5877 msgstr "" 5878 5879 #: src/screens/Bookmarks/components/EmptyState.tsx:35 5880 msgid "Nothing saved yet" 5881 msgstr "" 5882 ··· 5896 5897 #: src/Navigation.tsx:564 5898 #: src/Navigation.tsx:764 5899 - #: src/screens/Notifications/ActivityList.tsx:29 5900 #: src/screens/Settings/NotificationSettings/ActivityNotificationSettings.tsx:90 5901 #: src/screens/Settings/NotificationSettings/index.tsx:92 5902 #: src/screens/Settings/NotificationSettings/LikeNotificationSettings.tsx:30 ··· 6015 msgid "Only WebVTT (.vtt) files are supported" 6016 msgstr "" 6017 6018 - #: src/components/Lists.tsx:94 6019 msgid "Oops, something went wrong!" 6020 msgstr "" 6021 6022 - #: src/components/Lists.tsx:173 6023 - #: src/components/StarterPack/ProfileStarterPacks.tsx:328 6024 - #: src/components/StarterPack/ProfileStarterPacks.tsx:337 6025 - #: src/screens/Settings/AppPasswords.tsx:57 6026 #: src/screens/Settings/components/ChangeHandleDialog.tsx:106 6027 - #: src/view/screens/Profile.tsx:125 6028 msgid "Oops!" 6029 msgstr "" 6030 ··· 6268 msgid "Our moderators have reviewed reports and decided to disable your access to chats on Bluesky." 6269 msgstr "" 6270 6271 - #: src/components/Lists.tsx:190 6272 #: src/view/screens/NotFound.tsx:47 6273 msgid "Page not found" 6274 msgstr "" ··· 6596 msgid "Post" 6597 msgstr "" 6598 6599 #: src/view/com/composer/Composer.tsx:1117 6600 msgctxt "action" 6601 msgid "Post All" ··· 6676 #: src/screens/ProfileList/index.tsx:166 6677 #: src/screens/Settings/NotificationSettings/ActivityNotificationSettings.tsx:216 6678 #: src/screens/StarterPack/StarterPackScreen.tsx:191 6679 - #: src/view/screens/Profile.tsx:225 6680 msgid "Posts" 6681 msgstr "" 6682 ··· 6684 msgid "Posts can be muted based on their text, their tags, or both. We recommend avoiding common words that appear in many posts, since it can result in no posts being shown." 6685 msgstr "" 6686 6687 - #: src/view/com/posts/PostFeedErrorMessage.tsx:72 6688 msgid "Posts hidden" 6689 msgstr "" 6690 ··· 6705 msgstr "" 6706 6707 #: src/components/Error.tsx:60 6708 - #: src/components/Lists.tsx:99 6709 #: src/screens/Messages/components/MessageListError.tsx:24 6710 #: src/screens/Signup/BackNextButtons.tsx:47 6711 msgid "Press to retry" ··· 6770 msgstr "" 6771 6772 #: src/view/screens/DebugMod.tsx:936 6773 - #: src/view/screens/Profile.tsx:364 6774 msgid "profile" 6775 msgstr "" 6776 ··· 6802 msgid "Public, sharable lists of users to mute or block in bulk." 6803 msgstr "" 6804 6805 - #: src/view/com/lists/MyLists.tsx:72 6806 - msgid "Public, sharable lists which can be used to drive feeds." 6807 - msgstr "" 6808 - 6809 #. Accessibility label for button to publish a single post 6810 #: src/view/com/composer/Composer.tsx:1099 6811 msgid "Publish post" ··· 7011 #: src/components/FeedCard.tsx:343 7012 #: src/components/StarterPack/Wizard/WizardListCard.tsx:105 7013 #: src/components/StarterPack/Wizard/WizardListCard.tsx:112 7014 - #: src/screens/Bookmarks/index.tsx:255 7015 #: src/screens/Settings/Settings.tsx:664 7016 #: src/view/com/modals/UserAddRemoveLists.tsx:235 7017 - #: src/view/com/posts/PostFeedErrorMessage.tsx:217 7018 msgid "Remove" 7019 msgstr "" 7020 ··· 7051 7052 #: src/view/com/posts/FeedShutdownMsg.tsx:116 7053 #: src/view/com/posts/FeedShutdownMsg.tsx:120 7054 - #: src/view/com/posts/PostFeedErrorMessage.tsx:173 7055 msgid "Remove feed" 7056 msgstr "" 7057 7058 - #: src/view/com/posts/PostFeedErrorMessage.tsx:214 7059 msgid "Remove feed?" 7060 msgstr "" 7061 ··· 7077 msgstr "" 7078 7079 #: src/components/PostControls/BookmarkButton.tsx:128 7080 - #: src/screens/Bookmarks/index.tsx:249 7081 msgid "Remove from saved posts" 7082 msgstr "" 7083 ··· 7111 msgid "Remove subtitle file" 7112 msgstr "" 7113 7114 - #: src/view/com/posts/PostFeedErrorMessage.tsx:215 7115 msgid "Remove this feed from your saved feeds" 7116 msgstr "" 7117 ··· 7148 msgstr "" 7149 7150 #: src/components/PostControls/BookmarkButton.tsx:94 7151 - #: src/screens/Bookmarks/index.tsx:207 7152 msgid "Removed from saved posts" 7153 msgstr "" 7154 ··· 7197 #: src/screens/Settings/NotificationSettings/ActivityNotificationSettings.tsx:218 7198 #: src/screens/Settings/NotificationSettings/index.tsx:148 7199 #: src/screens/Settings/NotificationSettings/ReplyNotificationSettings.tsx:41 7200 - #: src/view/screens/Profile.tsx:226 7201 msgid "Replies" 7202 msgstr "" 7203 ··· 7460 7461 #: src/components/dms/MessageItem.tsx:322 7462 #: src/components/Error.tsx:65 7463 - #: src/components/Lists.tsx:110 7464 #: src/components/moderation/ReportDialog/index.tsx:274 7465 #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoFallback.tsx:55 7466 #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoFallback.tsx:58 7467 - #: src/components/StarterPack/ProfileStarterPacks.tsx:342 7468 #: src/screens/Login/LoginForm.tsx:326 7469 #: src/screens/Login/LoginForm.tsx:333 7470 #: src/screens/Messages/ChatList.tsx:292 ··· 7498 msgid "Returns to home page" 7499 msgstr "" 7500 7501 - #: src/screens/Profile/ProfileFeed/index.tsx:93 7502 #: src/screens/ProfileList/components/ErrorScreen.tsx:35 7503 #: src/screens/Settings/components/ChangeHandleDialog.tsx:575 7504 #: src/screens/VideoFeed/index.tsx:1163 ··· 7582 7583 #: src/components/dialogs/nuxs/BookmarksAnnouncement.tsx:143 7584 #: src/Navigation.tsx:608 7585 - #: src/screens/Bookmarks/index.tsx:55 7586 msgid "Saved Posts" 7587 msgstr "" 7588 ··· 7615 msgid "Scroll right" 7616 msgstr "" 7617 7618 - #: src/screens/ProfileList/AboutSection.tsx:130 7619 msgid "Scroll to top" 7620 msgstr "" 7621 ··· 7747 7748 #: src/components/FeedInterstitials.tsx:392 7749 msgid "See more suggested profiles on the Explore page" 7750 msgstr "" 7751 7752 #: src/screens/SavedFeeds.tsx:220 ··· 8416 msgid "Something went wrong, please try again." 8417 msgstr "" 8418 8419 - #: src/components/Lists.tsx:174 8420 msgid "Something went wrong!" 8421 msgstr "" 8422 ··· 8480 msgid "Start a new chat" 8481 msgstr "" 8482 8483 - #: src/screens/ProfileList/AboutSection.tsx:102 8484 - #: src/screens/ProfileList/FeedSection.tsx:74 8485 msgid "Start adding people" 8486 msgstr "" 8487 8488 - #: src/screens/ProfileList/AboutSection.tsx:108 8489 - #: src/screens/ProfileList/FeedSection.tsx:80 8490 msgid "Start adding people!" 8491 msgstr "" 8492 ··· 8518 msgstr "" 8519 8520 #: src/screens/Search/Explore.tsx:625 8521 - #: src/view/screens/Profile.tsx:231 8522 msgid "Starter Packs" 8523 msgstr "" 8524 8525 - #: src/components/StarterPack/ProfileStarterPacks.tsx:262 8526 msgid "Starter packs let you easily share your favorite feeds and people with your friends." 8527 msgstr "" 8528 8529 #: src/screens/Settings/AboutSettings.tsx:100 ··· 8928 msgid "There was an issue contacting the server, please check your internet connection and try again." 8929 msgstr "" 8930 8931 - #: src/view/com/notifications/NotificationFeed.tsx:130 8932 msgid "There was an issue fetching notifications. Tap here to try again." 8933 msgstr "" 8934 ··· 8941 msgid "There was an issue fetching the list. Tap here to try again." 8942 msgstr "" 8943 8944 - #: src/screens/Settings/AppPasswords.tsx:58 8945 msgid "There was an issue fetching your app passwords" 8946 msgstr "" 8947 8948 - #: src/view/com/feeds/ProfileFeedgens.tsx:163 8949 - #: src/view/com/lists/ProfileLists.tsx:161 8950 msgid "There was an issue fetching your lists. Tap here to try again." 8951 msgstr "" 8952 ··· 8954 msgid "There was an issue fetching your service info" 8955 msgstr "" 8956 8957 - #: src/view/com/posts/PostFeedErrorMessage.tsx:149 8958 msgid "There was an issue removing this feed. Please check your internet connection and try again." 8959 msgstr "" 8960 ··· 9070 msgid "This content is not available because one of the users involved has blocked the other." 9071 msgstr "" 9072 9073 - #: src/view/com/posts/PostFeedErrorMessage.tsx:118 9074 msgid "This content is not viewable without a Bluesky account." 9075 msgstr "" 9076 ··· 9098 msgid "This feature is not available while using an App Password. Please sign in with your main password." 9099 msgstr "" 9100 9101 - #: src/view/com/posts/PostFeedErrorMessage.tsx:124 9102 msgid "This feed is currently receiving high traffic and is temporarily unavailable. Please try again later." 9103 msgstr "" 9104 ··· 9106 msgid "This feed is empty! You may need to follow more users or tune your language settings." 9107 msgstr "" 9108 9109 - #: src/components/StarterPack/Main/PostsList.tsx:36 9110 - #: src/screens/Profile/ProfileFeed/index.tsx:192 9111 - #: src/screens/ProfileList/FeedSection.tsx:71 9112 msgid "This feed is empty." 9113 msgstr "" 9114 ··· 9124 msgid "This information is private and not shared with other users." 9125 msgstr "" 9126 9127 #: src/components/live/EditLiveDialog.tsx:189 9128 #: src/components/live/GoLiveDialog.tsx:157 9129 msgid "This is not a valid link" ··· 9153 msgid "This list – created by you – contains possible violations of Bluesky's community guidelines in its name or description." 9154 msgstr "" 9155 9156 - #: src/screens/ProfileList/AboutSection.tsx:98 9157 msgid "This list is empty." 9158 msgstr "" 9159 ··· 9173 msgid "This post is only visible to logged-in users." 9174 msgstr "" 9175 9176 - #: src/screens/Bookmarks/index.tsx:245 9177 msgid "This post was deleted by its author" 9178 msgstr "" 9179 ··· 9209 msgid "This user does not have a display name, and therefore cannot be verified." 9210 msgstr "" 9211 9212 - #: src/view/com/profile/ProfileFollowers.tsx:133 9213 msgid "This user doesn't have any followers." 9214 msgstr "" 9215 ··· 9238 msgid "This user is new here. Press for more info about when they joined." 9239 msgstr "" 9240 9241 - #: src/view/com/profile/ProfileFollows.tsx:133 9242 msgid "This user isn't following anyone." 9243 msgstr "" 9244 ··· 9706 msgid "Uploading video..." 9707 msgstr "" 9708 9709 - #: src/screens/Settings/AppPasswords.tsx:65 9710 msgid "Use app passwords to sign in to other Bluesky clients without giving full access to your account or password." 9711 msgstr "" 9712 ··· 9960 msgid "Video: {0}" 9961 msgstr "" 9962 9963 - #: src/view/screens/Profile.tsx:228 9964 msgid "Videos" 9965 msgstr "" 9966 ··· 10032 #: src/components/ProfileHoverCard/index.web.tsx:466 10033 #: src/components/ProfileHoverCard/index.web.tsx:486 10034 #: src/components/ProfileHoverCard/index.web.tsx:513 10035 - #: src/view/com/posts/PostFeedErrorMessage.tsx:179 10036 #: src/view/com/util/PostMeta.tsx:90 10037 #: src/view/com/util/PostMeta.tsx:127 10038 msgid "View profile" ··· 10262 msgid "We're sorry! The post you are replying to has been deleted." 10263 msgstr "" 10264 10265 - #: src/components/Lists.tsx:194 10266 #: src/view/screens/NotFound.tsx:50 10267 msgid "We're sorry! We can't find the page you were looking for." 10268 msgstr "" ··· 10386 msgid "Write a message" 10387 msgstr "" 10388 10389 #: src/view/com/composer/Composer.tsx:955 10390 msgid "Write post" 10391 msgstr "" ··· 10471 msgid "You are not allowed to upload videos." 10472 msgstr "" 10473 10474 - #: src/view/com/profile/ProfileFollows.tsx:132 10475 - msgid "You are not following anyone." 10476 msgstr "" 10477 10478 #: src/components/live/queries.ts:156 ··· 10549 msgid "You can update this later from your settings." 10550 msgstr "" 10551 10552 - #: src/view/com/profile/ProfileFollowers.tsx:132 10553 - msgid "You do not have any followers." 10554 - msgstr "" 10555 - 10556 #: src/screens/Profile/KnownFollowers.tsx:112 10557 msgid "You don't follow any users who follow @{name}." 10558 msgstr "" ··· 10614 msgid "You have no conversations yet. Start one!" 10615 msgstr "" 10616 10617 - #: src/view/com/feeds/ProfileFeedgens.tsx:151 10618 - msgid "You have no feeds." 10619 - msgstr "" 10620 - 10621 #: src/view/com/lists/MyLists.tsx:81 10622 - #: src/view/com/lists/ProfileLists.tsx:149 10623 msgid "You have no lists." 10624 msgstr "" 10625 ··· 10635 msgid "You have not muted any accounts yet. To mute an account, go to their profile and select \"Mute account\" from the menu on their account." 10636 msgstr "" 10637 10638 - #: src/components/Lists.tsx:57 10639 msgid "You have reached the end" 10640 msgstr "" 10641 ··· 10647 msgid "You have temporarily reached the limit for video uploads. Please try again later." 10648 msgstr "" 10649 10650 - #: src/components/StarterPack/ProfileStarterPacks.tsx:259 10651 msgid "You haven't created a starter pack yet!" 10652 msgstr "" 10653 10654 #: src/components/dialogs/MutedWords.tsx:403 ··· 10696 msgid "You must be at least 13 years old to use Bluesky. Read our <0>Terms of Service</0> for more information." 10697 msgstr "" 10698 10699 - #: src/components/StarterPack/ProfileStarterPacks.tsx:330 10700 msgid "You must be following at least seven other people to generate a starter pack." 10701 msgstr "" 10702
··· 128 msgid "{0, plural, other {+# more}}" 129 msgstr "" 130 131 + #: src/lib/strings/time.ts:13 132 + msgctxt "date and time formatted like this: [time] · [date]" 133 + msgid "{0} · {1}" 134 + msgstr "" 135 + 136 #: src/components/moderation/ContentHider.tsx:89 137 msgid "{0} (Account)" 138 msgstr "" ··· 700 msgid "Add a temporary live status to your profile. When someone clicks on your avatar, they’ll see information about your live event." 701 msgstr "" 702 703 + #: src/screens/ProfileList/AboutSection.tsx:63 704 + #: src/screens/ProfileList/AboutSection.tsx:81 705 msgid "Add a user to this list" 706 msgstr "" 707 ··· 743 msgid "Add app password" 744 msgstr "" 745 746 + #: src/screens/Settings/AppPasswords.tsx:74 747 + #: src/screens/Settings/AppPasswords.tsx:82 748 #: src/screens/Settings/components/AddAppPasswordDialog.tsx:111 749 msgid "Add App Password" 750 msgstr "" ··· 771 msgid "Add muted words and tags" 772 msgstr "" 773 774 + #: src/screens/ProfileList/AboutSection.tsx:71 775 + #: src/screens/ProfileList/AboutSection.tsx:89 776 msgid "Add people" 777 msgstr "" 778 ··· 963 msgid "Allow your followers to reply" 964 msgstr "" 965 966 + #: src/screens/Settings/AppPasswords.tsx:200 967 msgid "Allows access to direct messages" 968 msgstr "" 969 ··· 1001 msgid "Alt Text" 1002 msgstr "" 1003 1004 + #: src/view/com/composer/photos/Gallery.tsx:261 1005 msgid "Alt text describes images for blind and low-vision users, and helps give context to everyone." 1006 msgstr "" 1007 ··· 1036 msgid "An error occurred while fetching the feed." 1037 msgstr "" 1038 1039 + #: src/components/StarterPack/ProfileStarterPacks.tsx:371 1040 msgid "An error occurred while generating your starter pack. Want to try again?" 1041 msgstr "" 1042 ··· 1165 msgid "App Password" 1166 msgstr "" 1167 1168 + #: src/screens/Settings/AppPasswords.tsx:146 1169 msgctxt "toast" 1170 msgid "App password deleted" 1171 msgstr "" ··· 1188 msgstr "" 1189 1190 #: src/Navigation.tsx:351 1191 + #: src/screens/Settings/AppPasswords.tsx:50 1192 msgid "App Passwords" 1193 msgstr "" 1194 ··· 1249 msgid "Archived post" 1250 msgstr "" 1251 1252 + #: src/screens/Settings/AppPasswords.tsx:209 1253 msgid "Are you sure you want to delete the app password \"{0}\"?" 1254 msgstr "" 1255 ··· 1373 msgstr "" 1374 1375 #: src/components/dialogs/StarterPackDialog.tsx:71 1376 + #: src/components/StarterPack/ProfileStarterPacks.tsx:263 1377 + #: src/components/StarterPack/ProfileStarterPacks.tsx:273 1378 + #: src/view/screens/Profile.tsx:351 1379 msgid "Before creating a starter pack, you must first verify your email." 1380 msgstr "" 1381 ··· 1536 msgid "Bluesky Social Terms of Service" 1537 msgstr "" 1538 1539 + #: src/components/StarterPack/ProfileStarterPacks.tsx:338 1540 msgid "Bluesky will choose a set of recommended accounts from people in your network." 1541 msgstr "" 1542 ··· 1571 1572 #: src/components/moderation/ReportDialog/utils/useReportOptions.ts:215 1573 msgid "Breaking site rules" 1574 + msgstr "" 1575 + 1576 + #: src/view/com/feeds/ProfileFeedgens.tsx:158 1577 + #: src/view/com/feeds/ProfileFeedgens.tsx:159 1578 + msgid "Browse custom feeds" 1579 msgstr "" 1580 1581 #: src/components/FeedInterstitials.tsx:436 ··· 1624 msgid "Business" 1625 msgstr "" 1626 1627 + #: src/screens/Bookmarks/index.tsx:277 1628 + msgid "Button to go back to the home timeline" 1629 + msgstr "" 1630 + 1631 #: src/components/LabelingServiceCard/index.tsx:62 1632 #: src/components/moderation/ReportDialog/index.tsx:834 1633 #: src/screens/Search/components/StarterPackCard.tsx:106 ··· 1895 msgid "Choose Feeds" 1896 msgstr "" 1897 1898 + #: src/components/StarterPack/ProfileStarterPacks.tsx:346 1899 msgid "Choose for me" 1900 msgstr "" 1901 ··· 2462 msgid "Could not leave chat" 2463 msgstr "" 2464 2465 + #: src/screens/Profile/ProfileFeed/index.tsx:84 2466 msgid "Could not load feed" 2467 msgstr "" 2468 ··· 2492 #. Text on button to create a new starter pack 2493 #: src/components/dialogs/StarterPackDialog.tsx:112 2494 #: src/components/dialogs/StarterPackDialog.tsx:201 2495 + #: src/components/StarterPack/ProfileStarterPacks.tsx:328 2496 msgid "Create" 2497 + msgstr "" 2498 + 2499 + #: src/view/com/lists/ProfileLists.tsx:159 2500 + #: src/view/com/lists/ProfileLists.tsx:160 2501 + msgid "Create a list" 2502 msgstr "" 2503 2504 #: src/components/StarterPack/QrCodeDialog.tsx:163 2505 msgid "Create a QR code for a starter pack" 2506 msgstr "" 2507 2508 + #: src/components/StarterPack/ProfileStarterPacks.tsx:206 2509 + #: src/components/StarterPack/ProfileStarterPacks.tsx:315 2510 #: src/Navigation.tsx:589 2511 msgid "Create a starter pack" 2512 msgstr "" 2513 2514 + #: src/view/screens/Profile.tsx:542 2515 + #: src/view/screens/Profile.tsx:543 2516 + msgid "Create a Starter Pack" 2517 + msgstr "" 2518 + 2519 + #: src/components/StarterPack/ProfileStarterPacks.tsx:302 2520 msgid "Create a starter pack for me" 2521 msgstr "" 2522 ··· 2553 msgid "Create an avatar instead" 2554 msgstr "" 2555 2556 + #: src/components/StarterPack/ProfileStarterPacks.tsx:213 2557 msgid "Create another" 2558 msgstr "" 2559 ··· 2581 msgid "Create user list" 2582 msgstr "" 2583 2584 + #: src/screens/Settings/AppPasswords.tsx:173 2585 msgid "Created {0}" 2586 msgstr "" 2587 ··· 2627 msgid "Dark" 2628 msgstr "" 2629 2630 + #: src/view/screens/Debug.tsx:69 2631 msgid "Dark mode" 2632 msgstr "" 2633 ··· 2649 msgid "Debug Moderation" 2650 msgstr "" 2651 2652 + #: src/view/screens/Debug.tsx:89 2653 msgid "Debug panel" 2654 msgstr "" 2655 ··· 2669 #: src/components/PostControls/PostMenu/PostMenuItems.tsx:736 2670 #: src/screens/Messages/components/ChatStatusInfo.tsx:55 2671 #: src/screens/ProfileList/components/MoreOptionsMenu.tsx:280 2672 + #: src/screens/Settings/AppPasswords.tsx:212 2673 #: src/screens/StarterPack/StarterPackScreen.tsx:601 2674 #: src/screens/StarterPack/StarterPackScreen.tsx:690 2675 #: src/screens/StarterPack/StarterPackScreen.tsx:762 ··· 2685 msgid "Delete Account <0>\"</0><1>{0}</1><2>\"</2>" 2686 msgstr "" 2687 2688 + #: src/screens/Settings/AppPasswords.tsx:186 2689 msgid "Delete app password" 2690 msgstr "" 2691 2692 + #: src/screens/Settings/AppPasswords.tsx:207 2693 msgid "Delete app password?" 2694 msgstr "" 2695 ··· 3285 msgid "Enabled" 3286 msgstr "" 3287 3288 + #: src/screens/Profile/Sections/Feed.tsx:131 3289 msgid "End of feed" 3290 msgstr "" 3291 ··· 3771 #: src/screens/Search/SearchResults.tsx:77 3772 #: src/screens/StarterPack/StarterPackScreen.tsx:190 3773 #: src/view/screens/Feeds.tsx:511 3774 + #: src/view/screens/Profile.tsx:239 3775 #: src/view/shell/desktop/LeftNav.tsx:728 3776 #: src/view/shell/Drawer.tsx:530 3777 msgid "Feeds" ··· 4081 msgid "From <0/>" 4082 msgstr "" 4083 4084 + #: src/components/StarterPack/ProfileStarterPacks.tsx:335 4085 msgid "Generate a starter pack" 4086 msgstr "" 4087 ··· 4172 #: src/components/moderation/ScreenHider.tsx:160 4173 #: src/components/moderation/ScreenHider.tsx:169 4174 #: src/screens/Messages/Inbox.tsx:251 4175 + #: src/screens/Profile/ProfileFeed/index.tsx:93 4176 #: src/screens/ProfileList/components/ErrorScreen.tsx:34 4177 #: src/screens/ProfileList/components/ErrorScreen.tsx:40 4178 #: src/screens/VideoFeed/components/Header.tsx:163 4179 #: src/screens/VideoFeed/index.tsx:1162 4180 #: src/screens/VideoFeed/index.tsx:1166 4181 #: src/view/com/auth/LoggedOut.tsx:72 4182 + #: src/view/com/profile/ProfileFollowers.tsx:144 4183 + #: src/view/com/profile/ProfileFollowers.tsx:145 4184 #: src/view/screens/NotFound.tsx:57 4185 msgid "Go back" 4186 msgstr "" ··· 4189 #: src/screens/List/ListHiddenScreen.tsx:224 4190 #: src/screens/Profile/ErrorState.tsx:62 4191 #: src/screens/Profile/ErrorState.tsx:66 4192 + #: src/screens/Profile/ProfileFeed/index.tsx:98 4193 #: src/screens/StarterPack/StarterPackScreen.tsx:775 4194 #: src/view/screens/NotFound.tsx:56 4195 msgid "Go Back" ··· 4207 msgid "Go home" 4208 msgstr "" 4209 4210 + #: src/screens/Bookmarks/index.tsx:278 4211 #: src/view/screens/NotFound.tsx:57 4212 msgid "Go home" 4213 msgstr "" ··· 4461 msgid "Hides the content" 4462 msgstr "" 4463 4464 + #: src/view/com/posts/PostFeedErrorMessage.tsx:124 4465 msgid "Hmm, some kind of issue occurred when contacting the feed server. Please let the feed owner know about this issue." 4466 msgstr "" 4467 4468 + #: src/view/com/posts/PostFeedErrorMessage.tsx:112 4469 msgid "Hmm, the feed server appears to be misconfigured. Please let the feed owner know about this issue." 4470 msgstr "" 4471 4472 + #: src/view/com/posts/PostFeedErrorMessage.tsx:118 4473 msgid "Hmm, the feed server appears to be offline. Please let the feed owner know about this issue." 4474 msgstr "" 4475 4476 + #: src/view/com/posts/PostFeedErrorMessage.tsx:115 4477 msgid "Hmm, the feed server gave a bad response. Please let the feed owner know about this issue." 4478 msgstr "" 4479 4480 + #: src/view/com/posts/PostFeedErrorMessage.tsx:109 4481 msgid "Hmm, we're having trouble finding this feed. It may have been deleted." 4482 msgstr "" 4483 ··· 4791 msgstr "" 4792 4793 #: src/view/com/composer/labels/LabelsBtn.tsx:69 4794 + #: src/view/screens/Profile.tsx:232 4795 msgid "Labels" 4796 msgstr "" 4797 ··· 4933 msgid "left to go." 4934 msgstr "" 4935 4936 + #: src/components/StarterPack/ProfileStarterPacks.tsx:351 4937 msgid "Let me choose" 4938 msgstr "" 4939 ··· 5014 #: src/lib/hooks/useNotificationHandler.ts:126 5015 #: src/screens/Settings/NotificationSettings/index.tsx:126 5016 #: src/screens/Settings/NotificationSettings/LikeNotificationSettings.tsx:41 5017 + #: src/view/screens/Profile.tsx:238 5018 msgid "Likes" 5019 msgstr "" 5020 ··· 5119 5120 #: src/Navigation.tsx:172 5121 #: src/view/screens/Lists.tsx:67 5122 + #: src/view/screens/Profile.tsx:233 5123 + #: src/view/screens/Profile.tsx:241 5124 #: src/view/shell/desktop/LeftNav.tsx:746 5125 #: src/view/shell/Drawer.tsx:545 5126 msgid "Lists" 5127 + msgstr "" 5128 + 5129 + #: src/view/com/lists/MyLists.tsx:72 5130 + #: src/view/com/lists/ProfileLists.tsx:155 5131 + msgid "Lists allow you to see content from your favorite people." 5132 msgstr "" 5133 5134 #: src/components/dms/BlockedByListDialog.tsx:39 ··· 5164 msgid "Load new notifications" 5165 msgstr "" 5166 5167 + #: src/screens/Profile/ProfileFeed/index.tsx:231 5168 + #: src/screens/Profile/Sections/Feed.tsx:116 5169 + #: src/screens/ProfileList/FeedSection.tsx:112 5170 #: src/view/com/feeds/FeedPage.tsx:169 5171 msgid "Load new posts" 5172 msgstr "" ··· 5228 msgid "Make adjustments to email settings for your account" 5229 msgstr "" 5230 5231 + #: src/components/StarterPack/ProfileStarterPacks.tsx:310 5232 msgid "Make one for me" 5233 msgstr "" 5234 ··· 5270 msgid "Maybe later" 5271 msgstr "" 5272 5273 + #: src/view/screens/Profile.tsx:236 5274 msgid "Media" 5275 msgstr "" 5276 ··· 5314 msgid "Message from @{0}: {1}" 5315 msgstr "" 5316 5317 + #: src/view/com/posts/PostFeedErrorMessage.tsx:208 5318 msgid "Message from server: {0}" 5319 msgstr "" 5320 ··· 5658 msgid "New password" 5659 msgstr "" 5660 5661 + #: src/screens/Profile/ProfileFeed/index.tsx:248 5662 #: src/screens/ProfileList/index.tsx:246 5663 #: src/screens/ProfileList/index.tsx:284 5664 #: src/view/screens/Feeds.tsx:552 5665 #: src/view/screens/Notifications.tsx:167 5666 + #: src/view/screens/Profile.tsx:571 5667 msgid "New post" 5668 msgstr "" 5669 ··· 5732 msgid "No ads, no invasive tracking, no engagement traps. Bluesky respects your time and attention." 5733 msgstr "" 5734 5735 + #: src/screens/Settings/AppPasswords.tsx:107 5736 msgid "No app passwords yet" 5737 msgstr "" 5738 ··· 5753 msgid "No feeds found. Try searching for something else." 5754 msgstr "" 5755 5756 + #: src/view/com/profile/ProfileFollowers.tsx:135 5757 + msgid "No followers yet" 5758 + msgstr "" 5759 + 5760 #: src/components/live/LinkPreview.tsx:63 5761 msgid "No image" 5762 msgstr "" 5763 5764 #: src/components/LikedByList.tsx:84 5765 #: src/view/com/post-thread/PostLikedBy.tsx:84 5766 + #: src/view/screens/Profile.tsx:511 5767 msgid "No likes yet" 5768 msgstr "" 5769 ··· 5773 msgid "No longer following {0}" 5774 msgstr "" 5775 5776 + #: src/view/screens/Profile.tsx:467 5777 + msgid "No media yet" 5778 + msgstr "" 5779 + 5780 #: src/screens/Messages/components/ChatListItem.tsx:142 5781 msgid "No messages yet" 5782 msgstr "" ··· 5785 msgid "No more doomscrolling junk-filled algorithms. Find feeds that work for you, not against you." 5786 msgstr "" 5787 5788 + #: src/view/com/notifications/NotificationFeed.tsx:123 5789 msgid "No notifications yet!" 5790 msgstr "" 5791 ··· 5801 msgid "No one but the author can quote this post." 5802 msgstr "" 5803 5804 + #: src/screens/Notifications/ActivityList.tsx:42 5805 msgid "No posts here" 5806 msgstr "" 5807 5808 + #: src/screens/Profile/Sections/Feed.tsx:80 5809 + #: src/view/screens/Profile.tsx:431 5810 + msgid "No posts yet" 5811 msgstr "" 5812 5813 #: src/view/com/post-thread/PostQuotes.tsx:105 5814 msgid "No quotes yet" 5815 msgstr "" 5816 5817 + #: src/view/screens/Profile.tsx:452 5818 + msgid "No replies yet" 5819 + msgstr "" 5820 + 5821 #: src/view/com/post-thread/PostRepostedBy.tsx:90 5822 msgid "No reposts yet" 5823 msgstr "" ··· 5836 msgid "No results for \"{0}\"." 5837 msgstr "" 5838 5839 + #: src/components/Lists.tsx:201 5840 + #: src/components/Lists.tsx:216 5841 msgid "No results found" 5842 msgstr "" 5843 ··· 5862 msgid "No thanks" 5863 msgstr "" 5864 5865 + #: src/view/screens/Profile.tsx:489 5866 + msgid "No video posts yet" 5867 + msgstr "" 5868 + 5869 #: src/components/dialogs/PostInteractionSettingsDialog.tsx:465 5870 msgid "Nobody" 5871 msgstr "" ··· 5904 msgstr "" 5905 5906 #: src/Navigation.tsx:167 5907 + #: src/view/screens/Profile.tsx:132 5908 msgid "Not Found" 5909 msgstr "" 5910 ··· 5929 msgstr "" 5930 5931 #: src/screens/Bookmarks/components/EmptyState.tsx:35 5932 + #: src/screens/Bookmarks/index.tsx:274 5933 msgid "Nothing saved yet" 5934 msgstr "" 5935 ··· 5949 5950 #: src/Navigation.tsx:564 5951 #: src/Navigation.tsx:764 5952 + #: src/screens/Notifications/ActivityList.tsx:30 5953 #: src/screens/Settings/NotificationSettings/ActivityNotificationSettings.tsx:90 5954 #: src/screens/Settings/NotificationSettings/index.tsx:92 5955 #: src/screens/Settings/NotificationSettings/LikeNotificationSettings.tsx:30 ··· 6068 msgid "Only WebVTT (.vtt) files are supported" 6069 msgstr "" 6070 6071 + #: src/components/Lists.tsx:98 6072 msgid "Oops, something went wrong!" 6073 msgstr "" 6074 6075 + #: src/components/Lists.tsx:183 6076 + #: src/components/StarterPack/ProfileStarterPacks.tsx:360 6077 + #: src/components/StarterPack/ProfileStarterPacks.tsx:369 6078 + #: src/screens/Settings/AppPasswords.tsx:58 6079 #: src/screens/Settings/components/ChangeHandleDialog.tsx:106 6080 + #: src/view/screens/Profile.tsx:132 6081 msgid "Oops!" 6082 msgstr "" 6083 ··· 6321 msgid "Our moderators have reviewed reports and decided to disable your access to chats on Bluesky." 6322 msgstr "" 6323 6324 + #: src/components/Lists.tsx:202 6325 + #: src/components/Lists.tsx:217 6326 #: src/view/screens/NotFound.tsx:47 6327 msgid "Page not found" 6328 msgstr "" ··· 6650 msgid "Post" 6651 msgstr "" 6652 6653 + #: src/view/screens/Profile.tsx:469 6654 + #: src/view/screens/Profile.tsx:470 6655 + msgid "Post a photo" 6656 + msgstr "" 6657 + 6658 + #: src/view/screens/Profile.tsx:491 6659 + #: src/view/screens/Profile.tsx:492 6660 + msgid "Post a video" 6661 + msgstr "" 6662 + 6663 #: src/view/com/composer/Composer.tsx:1117 6664 msgctxt "action" 6665 msgid "Post All" ··· 6740 #: src/screens/ProfileList/index.tsx:166 6741 #: src/screens/Settings/NotificationSettings/ActivityNotificationSettings.tsx:216 6742 #: src/screens/StarterPack/StarterPackScreen.tsx:191 6743 + #: src/view/screens/Profile.tsx:234 6744 msgid "Posts" 6745 msgstr "" 6746 ··· 6748 msgid "Posts can be muted based on their text, their tags, or both. We recommend avoiding common words that appear in many posts, since it can result in no posts being shown." 6749 msgstr "" 6750 6751 + #: src/view/com/posts/PostFeedErrorMessage.tsx:75 6752 msgid "Posts hidden" 6753 msgstr "" 6754 ··· 6769 msgstr "" 6770 6771 #: src/components/Error.tsx:60 6772 + #: src/components/Lists.tsx:103 6773 #: src/screens/Messages/components/MessageListError.tsx:24 6774 #: src/screens/Signup/BackNextButtons.tsx:47 6775 msgid "Press to retry" ··· 6834 msgstr "" 6835 6836 #: src/view/screens/DebugMod.tsx:936 6837 + #: src/view/screens/Profile.tsx:384 6838 msgid "profile" 6839 msgstr "" 6840 ··· 6866 msgid "Public, sharable lists of users to mute or block in bulk." 6867 msgstr "" 6868 6869 #. Accessibility label for button to publish a single post 6870 #: src/view/com/composer/Composer.tsx:1099 6871 msgid "Publish post" ··· 7071 #: src/components/FeedCard.tsx:343 7072 #: src/components/StarterPack/Wizard/WizardListCard.tsx:105 7073 #: src/components/StarterPack/Wizard/WizardListCard.tsx:112 7074 + #: src/screens/Bookmarks/index.tsx:259 7075 #: src/screens/Settings/Settings.tsx:664 7076 #: src/view/com/modals/UserAddRemoveLists.tsx:235 7077 + #: src/view/com/posts/PostFeedErrorMessage.tsx:220 7078 msgid "Remove" 7079 msgstr "" 7080 ··· 7111 7112 #: src/view/com/posts/FeedShutdownMsg.tsx:116 7113 #: src/view/com/posts/FeedShutdownMsg.tsx:120 7114 + #: src/view/com/posts/PostFeedErrorMessage.tsx:176 7115 msgid "Remove feed" 7116 msgstr "" 7117 7118 + #: src/view/com/posts/PostFeedErrorMessage.tsx:217 7119 msgid "Remove feed?" 7120 msgstr "" 7121 ··· 7137 msgstr "" 7138 7139 #: src/components/PostControls/BookmarkButton.tsx:128 7140 + #: src/screens/Bookmarks/index.tsx:253 7141 msgid "Remove from saved posts" 7142 msgstr "" 7143 ··· 7171 msgid "Remove subtitle file" 7172 msgstr "" 7173 7174 + #: src/view/com/posts/PostFeedErrorMessage.tsx:218 7175 msgid "Remove this feed from your saved feeds" 7176 msgstr "" 7177 ··· 7208 msgstr "" 7209 7210 #: src/components/PostControls/BookmarkButton.tsx:94 7211 + #: src/screens/Bookmarks/index.tsx:211 7212 msgid "Removed from saved posts" 7213 msgstr "" 7214 ··· 7257 #: src/screens/Settings/NotificationSettings/ActivityNotificationSettings.tsx:218 7258 #: src/screens/Settings/NotificationSettings/index.tsx:148 7259 #: src/screens/Settings/NotificationSettings/ReplyNotificationSettings.tsx:41 7260 + #: src/view/screens/Profile.tsx:235 7261 msgid "Replies" 7262 msgstr "" 7263 ··· 7520 7521 #: src/components/dms/MessageItem.tsx:322 7522 #: src/components/Error.tsx:65 7523 + #: src/components/Lists.tsx:114 7524 #: src/components/moderation/ReportDialog/index.tsx:274 7525 #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoFallback.tsx:55 7526 #: src/components/Post/Embed/VideoEmbed/VideoEmbedInner/VideoFallback.tsx:58 7527 + #: src/components/StarterPack/ProfileStarterPacks.tsx:374 7528 #: src/screens/Login/LoginForm.tsx:326 7529 #: src/screens/Login/LoginForm.tsx:333 7530 #: src/screens/Messages/ChatList.tsx:292 ··· 7558 msgid "Returns to home page" 7559 msgstr "" 7560 7561 + #: src/screens/Profile/ProfileFeed/index.tsx:94 7562 #: src/screens/ProfileList/components/ErrorScreen.tsx:35 7563 #: src/screens/Settings/components/ChangeHandleDialog.tsx:575 7564 #: src/screens/VideoFeed/index.tsx:1163 ··· 7642 7643 #: src/components/dialogs/nuxs/BookmarksAnnouncement.tsx:143 7644 #: src/Navigation.tsx:608 7645 + #: src/screens/Bookmarks/index.tsx:59 7646 msgid "Saved Posts" 7647 msgstr "" 7648 ··· 7675 msgid "Scroll right" 7676 msgstr "" 7677 7678 + #: src/screens/ProfileList/AboutSection.tsx:131 7679 msgid "Scroll to top" 7680 msgstr "" 7681 ··· 7807 7808 #: src/components/FeedInterstitials.tsx:392 7809 msgid "See more suggested profiles on the Explore page" 7810 + msgstr "" 7811 + 7812 + #: src/view/com/profile/ProfileFollows.tsx:155 7813 + #: src/view/com/profile/ProfileFollows.tsx:156 7814 + msgid "See suggested accounts" 7815 msgstr "" 7816 7817 #: src/screens/SavedFeeds.tsx:220 ··· 8481 msgid "Something went wrong, please try again." 8482 msgstr "" 8483 8484 + #: src/components/Lists.tsx:184 8485 msgid "Something went wrong!" 8486 msgstr "" 8487 ··· 8545 msgid "Start a new chat" 8546 msgstr "" 8547 8548 + #: src/screens/ProfileList/AboutSection.tsx:103 8549 + #: src/screens/ProfileList/FeedSection.tsx:81 8550 msgid "Start adding people" 8551 msgstr "" 8552 8553 + #: src/screens/ProfileList/AboutSection.tsx:109 8554 + #: src/screens/ProfileList/FeedSection.tsx:87 8555 msgid "Start adding people!" 8556 msgstr "" 8557 ··· 8583 msgstr "" 8584 8585 #: src/screens/Search/Explore.tsx:625 8586 + #: src/view/screens/Profile.tsx:240 8587 msgid "Starter Packs" 8588 msgstr "" 8589 8590 + #: src/components/StarterPack/ProfileStarterPacks.tsx:294 8591 msgid "Starter packs let you easily share your favorite feeds and people with your friends." 8592 + msgstr "" 8593 + 8594 + #: src/view/screens/Profile.tsx:539 8595 + msgid "Starter packs let you share your favorite feeds and people with your friends." 8596 msgstr "" 8597 8598 #: src/screens/Settings/AboutSettings.tsx:100 ··· 8997 msgid "There was an issue contacting the server, please check your internet connection and try again." 8998 msgstr "" 8999 9000 + #: src/view/com/notifications/NotificationFeed.tsx:131 9001 msgid "There was an issue fetching notifications. Tap here to try again." 9002 msgstr "" 9003 ··· 9010 msgid "There was an issue fetching the list. Tap here to try again." 9011 msgstr "" 9012 9013 + #: src/screens/Settings/AppPasswords.tsx:59 9014 msgid "There was an issue fetching your app passwords" 9015 msgstr "" 9016 9017 + #: src/view/com/feeds/ProfileFeedgens.tsx:174 9018 + #: src/view/com/lists/ProfileLists.tsx:175 9019 msgid "There was an issue fetching your lists. Tap here to try again." 9020 msgstr "" 9021 ··· 9023 msgid "There was an issue fetching your service info" 9024 msgstr "" 9025 9026 + #: src/view/com/posts/PostFeedErrorMessage.tsx:152 9027 msgid "There was an issue removing this feed. Please check your internet connection and try again." 9028 msgstr "" 9029 ··· 9139 msgid "This content is not available because one of the users involved has blocked the other." 9140 msgstr "" 9141 9142 + #: src/view/com/posts/PostFeedErrorMessage.tsx:121 9143 msgid "This content is not viewable without a Bluesky account." 9144 msgstr "" 9145 ··· 9167 msgid "This feature is not available while using an App Password. Please sign in with your main password." 9168 msgstr "" 9169 9170 + #: src/view/com/posts/PostFeedErrorMessage.tsx:127 9171 msgid "This feed is currently receiving high traffic and is temporarily unavailable. Please try again later." 9172 msgstr "" 9173 ··· 9175 msgid "This feed is empty! You may need to follow more users or tune your language settings." 9176 msgstr "" 9177 9178 + #: src/components/StarterPack/Main/PostsList.tsx:41 9179 + #: src/screens/Profile/ProfileFeed/index.tsx:197 9180 + #: src/screens/ProfileList/FeedSection.tsx:77 9181 msgid "This feed is empty." 9182 msgstr "" 9183 ··· 9193 msgid "This information is private and not shared with other users." 9194 msgstr "" 9195 9196 + #: src/view/screens/Debug.tsx:343 9197 + msgid "This is an empty state" 9198 + msgstr "" 9199 + 9200 #: src/components/live/EditLiveDialog.tsx:189 9201 #: src/components/live/GoLiveDialog.tsx:157 9202 msgid "This is not a valid link" ··· 9226 msgid "This list – created by you – contains possible violations of Bluesky's community guidelines in its name or description." 9227 msgstr "" 9228 9229 + #: src/screens/ProfileList/AboutSection.tsx:99 9230 msgid "This list is empty." 9231 msgstr "" 9232 ··· 9246 msgid "This post is only visible to logged-in users." 9247 msgstr "" 9248 9249 + #: src/screens/Bookmarks/index.tsx:249 9250 msgid "This post was deleted by its author" 9251 msgstr "" 9252 ··· 9282 msgid "This user does not have a display name, and therefore cannot be verified." 9283 msgstr "" 9284 9285 + #: src/view/com/profile/ProfileFollowers.tsx:136 9286 msgid "This user doesn't have any followers." 9287 msgstr "" 9288 ··· 9311 msgid "This user is new here. Press for more info about when they joined." 9312 msgstr "" 9313 9314 + #: src/view/com/profile/ProfileFollows.tsx:147 9315 msgid "This user isn't following anyone." 9316 msgstr "" 9317 ··· 9779 msgid "Uploading video..." 9780 msgstr "" 9781 9782 + #: src/screens/Settings/AppPasswords.tsx:66 9783 msgid "Use app passwords to sign in to other Bluesky clients without giving full access to your account or password." 9784 msgstr "" 9785 ··· 10033 msgid "Video: {0}" 10034 msgstr "" 10035 10036 + #: src/view/screens/Profile.tsx:237 10037 msgid "Videos" 10038 msgstr "" 10039 ··· 10105 #: src/components/ProfileHoverCard/index.web.tsx:466 10106 #: src/components/ProfileHoverCard/index.web.tsx:486 10107 #: src/components/ProfileHoverCard/index.web.tsx:513 10108 + #: src/view/com/posts/PostFeedErrorMessage.tsx:182 10109 #: src/view/com/util/PostMeta.tsx:90 10110 #: src/view/com/util/PostMeta.tsx:127 10111 msgid "View profile" ··· 10335 msgid "We're sorry! The post you are replying to has been deleted." 10336 msgstr "" 10337 10338 + #: src/components/Lists.tsx:221 10339 #: src/view/screens/NotFound.tsx:50 10340 msgid "We're sorry! We can't find the page you were looking for." 10341 msgstr "" ··· 10459 msgid "Write a message" 10460 msgstr "" 10461 10462 + #: src/view/screens/Profile.tsx:433 10463 + #: src/view/screens/Profile.tsx:434 10464 + msgid "Write a post" 10465 + msgstr "" 10466 + 10467 #: src/view/com/composer/Composer.tsx:955 10468 msgid "Write post" 10469 msgstr "" ··· 10549 msgid "You are not allowed to upload videos." 10550 msgstr "" 10551 10552 + #: src/view/com/profile/ProfileFollows.tsx:146 10553 + msgid "You are not following anyone yet" 10554 msgstr "" 10555 10556 #: src/components/live/queries.ts:156 ··· 10627 msgid "You can update this later from your settings." 10628 msgstr "" 10629 10630 #: src/screens/Profile/KnownFollowers.tsx:112 10631 msgid "You don't follow any users who follow @{name}." 10632 msgstr "" ··· 10688 msgid "You have no conversations yet. Start one!" 10689 msgstr "" 10690 10691 #: src/view/com/lists/MyLists.tsx:81 10692 msgid "You have no lists." 10693 msgstr "" 10694 ··· 10704 msgid "You have not muted any accounts yet. To mute an account, go to their profile and select \"Mute account\" from the menu on their account." 10705 msgstr "" 10706 10707 + #: src/components/Lists.tsx:61 10708 msgid "You have reached the end" 10709 msgstr "" 10710 ··· 10716 msgid "You have temporarily reached the limit for video uploads. Please try again later." 10717 msgstr "" 10718 10719 + #: src/components/StarterPack/ProfileStarterPacks.tsx:291 10720 msgid "You haven't created a starter pack yet!" 10721 + msgstr "" 10722 + 10723 + #: src/view/com/feeds/ProfileFeedgens.tsx:155 10724 + msgid "You haven't made any custom feeds yet." 10725 msgstr "" 10726 10727 #: src/components/dialogs/MutedWords.tsx:403 ··· 10769 msgid "You must be at least 13 years old to use Bluesky. Read our <0>Terms of Service</0> for more information." 10770 msgstr "" 10771 10772 + #: src/components/StarterPack/ProfileStarterPacks.tsx:362 10773 msgid "You must be following at least seven other people to generate a starter pack." 10774 msgstr "" 10775
+30 -4
src/screens/Bookmarks/index.tsx
··· 7 } from '@atproto/api' 8 import {msg, Trans} from '@lingui/macro' 9 import {useLingui} from '@lingui/react' 10 - import {useFocusEffect} from '@react-navigation/native' 11 12 import {useCleanError} from '#/lib/hooks/useCleanError' 13 import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender' ··· 21 import {useBookmarksQuery} from '#/state/queries/bookmarks/useBookmarksQuery' 22 import {useSetMinimalShellMode} from '#/state/shell' 23 import {Post} from '#/view/com/post/Post' 24 import {List} from '#/view/com/util/List' 25 import {PostFeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' 26 - import {EmptyState} from '#/screens/Bookmarks/components/EmptyState' 27 import {atoms as a, useTheme} from '#/alf' 28 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 29 - import {BookmarkFilled} from '#/components/icons/Bookmark' 30 import {CircleQuestion_Stroke2_Corner2_Rounded as QuestionIcon} from '#/components/icons/CircleQuestion' 31 import * as Layout from '#/components/Layout' 32 import {ListFooter} from '#/components/Lists' ··· 259 ) 260 } 261 262 function renderItem({item, index}: {item: ListItem; index: number}) { 263 switch (item.type) { 264 case 'loading': { 265 return <PostFeedLoadingPlaceholder /> 266 } 267 case 'empty': { 268 - return <EmptyState /> 269 } 270 case 'bookmark': { 271 return (
··· 7 } from '@atproto/api' 8 import {msg, Trans} from '@lingui/macro' 9 import {useLingui} from '@lingui/react' 10 + import { 11 + type NavigationProp, 12 + useFocusEffect, 13 + useNavigation, 14 + } from '@react-navigation/native' 15 16 import {useCleanError} from '#/lib/hooks/useCleanError' 17 import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender' ··· 25 import {useBookmarksQuery} from '#/state/queries/bookmarks/useBookmarksQuery' 26 import {useSetMinimalShellMode} from '#/state/shell' 27 import {Post} from '#/view/com/post/Post' 28 + import {EmptyState} from '#/view/com/util/EmptyState' 29 import {List} from '#/view/com/util/List' 30 import {PostFeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' 31 import {atoms as a, useTheme} from '#/alf' 32 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 33 + import {BookmarkDeleteLarge, BookmarkFilled} from '#/components/icons/Bookmark' 34 import {CircleQuestion_Stroke2_Corner2_Rounded as QuestionIcon} from '#/components/icons/CircleQuestion' 35 import * as Layout from '#/components/Layout' 36 import {ListFooter} from '#/components/Lists' ··· 263 ) 264 } 265 266 + function BookmarksEmpty() { 267 + const t = useTheme() 268 + const {_} = useLingui() 269 + const navigation = useNavigation<NavigationProp<CommonNavigatorParams>>() 270 + 271 + return ( 272 + <EmptyState 273 + icon={BookmarkDeleteLarge} 274 + message={_(msg`Nothing saved yet`)} 275 + textStyle={[t.atoms.text_contrast_medium, a.font_medium]} 276 + button={{ 277 + label: _(msg`Button to go back to the home timeline`), 278 + text: _(msg`Go home`), 279 + onPress: () => navigation.navigate('Home' as never), 280 + size: 'small', 281 + color: 'secondary', 282 + }} 283 + style={[a.pt_3xl]} 284 + /> 285 + ) 286 + } 287 + 288 function renderItem({item, index}: {item: ListItem; index: number}) { 289 switch (item.type) { 290 case 'loading': { 291 return <PostFeedLoadingPlaceholder /> 292 } 293 case 'empty': { 294 + return <BookmarksEmpty /> 295 } 296 case 'bookmark': { 297 return (
+6 -1
src/screens/Notifications/ActivityList.tsx
··· 5 import {type AllNavigatorParams} from '#/lib/routes/types' 6 import {PostFeed} from '#/view/com/posts/PostFeed' 7 import {EmptyState} from '#/view/com/util/EmptyState' 8 import * as Layout from '#/components/Layout' 9 import {ListFooter} from '#/components/Lists' 10 ··· 35 feed={`posts|${uris}`} 36 disablePoll 37 renderEmptyState={() => ( 38 - <EmptyState icon="growth" message={_(msg`No skeets here`)} /> 39 )} 40 renderEndOfFeed={() => <ListFooter />} 41 />
··· 5 import {type AllNavigatorParams} from '#/lib/routes/types' 6 import {PostFeed} from '#/view/com/posts/PostFeed' 7 import {EmptyState} from '#/view/com/util/EmptyState' 8 + import {EditBig_Stroke1_Corner0_Rounded as EditIcon} from '#/components/icons/EditBig' 9 import * as Layout from '#/components/Layout' 10 import {ListFooter} from '#/components/Lists' 11 ··· 36 feed={`posts|${uris}`} 37 disablePoll 38 renderEmptyState={() => ( 39 + <EmptyState 40 + icon={EditIcon} 41 + iconSize="2xl" 42 + message={_(msg`No posts here`)} 43 + /> 44 )} 45 renderEndOfFeed={() => <ListFooter />} 46 />
+13 -5
src/screens/Onboarding/StepProfile/index.tsx
··· 15 import {getDataUriSize} from '#/lib/media/util' 16 import {useRequestNotificationsPermission} from '#/lib/notifications/notifications' 17 import {logEvent, useGate} from '#/lib/statsig/statsig' 18 import {isNative, isWeb} from '#/platform/detection' 19 import { 20 DescriptionText, ··· 184 if (!image) return 185 186 if (!isWeb) { 187 - image = await openCropper({ 188 - imageUri: image.path, 189 - shape: 'circle', 190 - aspectRatio: 1 / 1, 191 - }) 192 } 193 image = await compressIfNeeded(image, 1000000) 194
··· 15 import {getDataUriSize} from '#/lib/media/util' 16 import {useRequestNotificationsPermission} from '#/lib/notifications/notifications' 17 import {logEvent, useGate} from '#/lib/statsig/statsig' 18 + import {isCancelledError} from '#/lib/strings/errors' 19 + import {logger} from '#/logger' 20 import {isNative, isWeb} from '#/platform/detection' 21 import { 22 DescriptionText, ··· 186 if (!image) return 187 188 if (!isWeb) { 189 + try { 190 + image = await openCropper({ 191 + imageUri: image.path, 192 + shape: 'circle', 193 + aspectRatio: 1 / 1, 194 + }) 195 + } catch (e) { 196 + if (!isCancelledError(e)) { 197 + logger.error('Failed to crop avatar in onboarding', {error: e}) 198 + } 199 + } 200 } 201 image = await compressIfNeeded(image, 1000000) 202
+2 -2
src/screens/PostThread/components/ThreadItemAnchor.tsx
··· 588 <BackdatedPostIndicator post={post} /> 589 <View style={[a.flex_row, a.align_center, a.flex_wrap, a.gap_sm]}> 590 <Text style={[a.text_sm, t.atoms.text_contrast_medium]}> 591 - {niceDate(i18n, post.indexedAt, 'medium')} 592 </Text> 593 {isRootPost && ( 594 <WhoCanReply post={post} isThreadAuthor={isThreadAuthor} /> ··· 674 a.leading_tight, 675 t.atoms.text_contrast_medium, 676 ]}> 677 - <Trans>Archived from {niceDate(i18n, createdAt)}</Trans> 678 </Text> 679 </View> 680 )}
··· 588 <BackdatedPostIndicator post={post} /> 589 <View style={[a.flex_row, a.align_center, a.flex_wrap, a.gap_sm]}> 590 <Text style={[a.text_sm, t.atoms.text_contrast_medium]}> 591 + {niceDate(i18n, post.indexedAt, 'dot separated')} 592 </Text> 593 {isRootPost && ( 594 <WhoCanReply post={post} isThreadAuthor={isThreadAuthor} /> ··· 674 a.leading_tight, 675 t.atoms.text_contrast_medium, 676 ]}> 677 + <Trans>Archived from {niceDate(i18n, createdAt, 'medium')}</Trans> 678 </Text> 679 </View> 680 )}
+8 -1
src/screens/Profile/ProfileFeed/index.tsx
··· 45 ProfileFeedHeader, 46 ProfileFeedHeaderSkeleton, 47 } from '#/screens/Profile/components/ProfileFeedHeader' 48 import * as Layout from '#/components/Layout' 49 50 type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFeed'> ··· 189 }, [onScrollToTop, isScreenFocused]) 190 191 const renderPostsEmpty = useCallback(() => { 192 - return <EmptyState icon="hashtag" message={_(msg`This feed is empty.`)} /> 193 }, [_]) 194 195 const isVideoFeed = React.useMemo(() => {
··· 45 ProfileFeedHeader, 46 ProfileFeedHeaderSkeleton, 47 } from '#/screens/Profile/components/ProfileFeedHeader' 48 + import {HashtagWide_Stroke1_Corner0_Rounded as HashtagWideIcon} from '#/components/icons/Hashtag' 49 import * as Layout from '#/components/Layout' 50 51 type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFeed'> ··· 190 }, [onScrollToTop, isScreenFocused]) 191 192 const renderPostsEmpty = useCallback(() => { 193 + return ( 194 + <EmptyState 195 + icon={HashtagWideIcon} 196 + iconSize="2xl" 197 + message={_(msg`This feed is empty.`)} 198 + /> 199 + ) 200 }, [_]) 201 202 const isVideoFeed = React.useMemo(() => {
+28 -6
src/screens/Profile/Sections/Feed.tsx
··· 6 7 import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender' 8 import {isIOS, isNative} from '#/platform/detection' 9 - import {type FeedDescriptor} from '#/state/queries/post-feed' 10 - import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed' 11 import {truncateAndInvalidate} from '#/state/queries/util' 12 import {PostFeed} from '#/view/com/posts/PostFeed' 13 - import {EmptyState} from '#/view/com/util/EmptyState' 14 import {type ListRef} from '#/view/com/util/List' 15 import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn' 16 import {atoms as a, ios, useTheme} from '#/alf' 17 import {Text} from '#/components/Typography' 18 import {type SectionRef} from './types' 19 ··· 25 scrollElRef: ListRef 26 ignoreFilterFor?: string 27 setScrollViewTag: (tag: number | null) => void 28 } 29 export function ProfileFeedSection({ 30 ref, 31 feed, ··· 34 scrollElRef, 35 ignoreFilterFor, 36 setScrollViewTag, 37 }: FeedSectionProps) { 38 const {_} = useLingui() 39 const queryClient = useQueryClient() ··· 44 const adjustedInitialNumToRender = useInitialNumToRender({ 45 screenHeightOffset: headerHeight, 46 }) 47 - 48 const onScrollToTop = useCallback(() => { 49 scrollElRef.current?.scrollToOffset({ 50 animated: isNative, ··· 59 })) 60 61 const renderPostsEmpty = useCallback(() => { 62 - return <EmptyState icon="growth" message={_(msg`No skeets yet.`)} /> 63 - }, [_]) 64 65 useEffect(() => { 66 if (isIOS && isFocused && scrollElRef.current) {
··· 6 7 import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender' 8 import {isIOS, isNative} from '#/platform/detection' 9 + import { 10 + type FeedDescriptor, 11 + RQKEY as FEED_RQKEY, 12 + } from '#/state/queries/post-feed' 13 import {truncateAndInvalidate} from '#/state/queries/util' 14 import {PostFeed} from '#/view/com/posts/PostFeed' 15 + import { 16 + EmptyState, 17 + type EmptyStateButtonProps, 18 + } from '#/view/com/util/EmptyState' 19 import {type ListRef} from '#/view/com/util/List' 20 import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn' 21 import {atoms as a, ios, useTheme} from '#/alf' 22 + import {EditBig_Stroke1_Corner0_Rounded as EditIcon} from '#/components/icons/EditBig' 23 import {Text} from '#/components/Typography' 24 import {type SectionRef} from './types' 25 ··· 31 scrollElRef: ListRef 32 ignoreFilterFor?: string 33 setScrollViewTag: (tag: number | null) => void 34 + emptyStateMessage?: string 35 + emptyStateButton?: EmptyStateButtonProps 36 + emptyStateIcon?: React.ComponentType<any> | React.ReactElement 37 } 38 + 39 export function ProfileFeedSection({ 40 ref, 41 feed, ··· 44 scrollElRef, 45 ignoreFilterFor, 46 setScrollViewTag, 47 + emptyStateMessage, 48 + emptyStateButton, 49 + emptyStateIcon, 50 }: FeedSectionProps) { 51 const {_} = useLingui() 52 const queryClient = useQueryClient() ··· 57 const adjustedInitialNumToRender = useInitialNumToRender({ 58 screenHeightOffset: headerHeight, 59 }) 60 const onScrollToTop = useCallback(() => { 61 scrollElRef.current?.scrollToOffset({ 62 animated: isNative, ··· 71 })) 72 73 const renderPostsEmpty = useCallback(() => { 74 + return ( 75 + <View style={[a.flex_1, a.justify_center, a.align_center]}> 76 + <EmptyState 77 + style={{width: '100%'}} 78 + icon={emptyStateIcon || EditIcon} 79 + iconSize="3xl" 80 + message={emptyStateMessage || _(msg`No posts yet`)} 81 + button={emptyStateButton} 82 + /> 83 + </View> 84 + ) 85 + }, [_, emptyStateButton, emptyStateIcon, emptyStateMessage]) 86 87 useEffect(() => { 88 if (isIOS && isFocused && scrollElRef.current) {
+3 -2
src/screens/ProfileList/AboutSection.tsx
··· 12 import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn' 13 import {atoms as a, useBreakpoints} from '#/alf' 14 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 15 import {PersonPlus_Stroke2_Corner0_Rounded as PersonPlusIcon} from '#/components/icons/Person' 16 17 interface SectionRef { ··· 95 const renderEmptyState = useCallback(() => { 96 return ( 97 <View style={[a.gap_xl, a.align_center]}> 98 - <EmptyState icon="users-slash" message={_(msg`This list is empty.`)} /> 99 {isOwner && ( 100 <Button 101 testID="emptyStateAddUserBtn" ··· 111 )} 112 </View> 113 ) 114 - }, [_, onPressAddUser, isOwner]) 115 116 return ( 117 <View>
··· 12 import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn' 13 import {atoms as a, useBreakpoints} from '#/alf' 14 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 15 + import {BulletList_Stroke1_Corner0_Rounded as ListIcon} from '#/components/icons/BulletList' 16 import {PersonPlus_Stroke2_Corner0_Rounded as PersonPlusIcon} from '#/components/icons/Person' 17 18 interface SectionRef { ··· 96 const renderEmptyState = useCallback(() => { 97 return ( 98 <View style={[a.gap_xl, a.align_center]}> 99 + <EmptyState icon={ListIcon} message={_(msg`This list is empty.`)} /> 100 {isOwner && ( 101 <Button 102 testID="emptyStateAddUserBtn" ··· 112 )} 113 </View> 114 ) 115 + }, [_, isOwner, onPressAddUser]) 116 117 return ( 118 <View>
+10 -3
src/screens/ProfileList/FeedSection.tsx
··· 7 8 import {isNative} from '#/platform/detection' 9 import {listenSoftReset} from '#/state/events' 10 - import {type FeedDescriptor} from '#/state/queries/post-feed' 11 - import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed' 12 import {PostFeed} from '#/view/com/posts/PostFeed' 13 import {EmptyState} from '#/view/com/util/EmptyState' 14 import {type ListRef} from '#/view/com/util/List' 15 import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn' 16 import {atoms as a} from '#/alf' 17 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 18 import {PersonPlus_Stroke2_Corner0_Rounded as PersonPlusIcon} from '#/components/icons/Person' 19 20 interface SectionRef { ··· 68 const renderPostsEmpty = useCallback(() => { 69 return ( 70 <View style={[a.gap_xl, a.align_center]}> 71 - <EmptyState icon="hashtag" message={_(msg`This feed is empty.`)} /> 72 {isOwner && ( 73 <Button 74 label={_(msg`Start adding people`)}
··· 7 8 import {isNative} from '#/platform/detection' 9 import {listenSoftReset} from '#/state/events' 10 + import { 11 + type FeedDescriptor, 12 + RQKEY as FEED_RQKEY, 13 + } from '#/state/queries/post-feed' 14 import {PostFeed} from '#/view/com/posts/PostFeed' 15 import {EmptyState} from '#/view/com/util/EmptyState' 16 import {type ListRef} from '#/view/com/util/List' 17 import {LoadLatestBtn} from '#/view/com/util/load-latest/LoadLatestBtn' 18 import {atoms as a} from '#/alf' 19 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 20 + import {HashtagWide_Stroke1_Corner0_Rounded as HashtagWideIcon} from '#/components/icons/Hashtag' 21 import {PersonPlus_Stroke2_Corner0_Rounded as PersonPlusIcon} from '#/components/icons/Person' 22 23 interface SectionRef { ··· 71 const renderPostsEmpty = useCallback(() => { 72 return ( 73 <View style={[a.gap_xl, a.align_center]}> 74 + <EmptyState 75 + icon={HashtagWideIcon} 76 + iconSize="2xl" 77 + message={_(msg`This feed is empty.`)} 78 + /> 79 {isOwner && ( 80 <Button 81 label={_(msg`Start adding people`)}
+2 -1
src/screens/Settings/AppPasswords.tsx
··· 24 import {Admonition, colors} from '#/components/Admonition' 25 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 26 import {useDialogControl} from '#/components/Dialog' 27 import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus' 28 import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash' 29 import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' ··· 102 </View> 103 ) : ( 104 <EmptyState 105 - icon="growth" 106 message={_(msg`No app passwords yet`)} 107 /> 108 )
··· 24 import {Admonition, colors} from '#/components/Admonition' 25 import {Button, ButtonIcon, ButtonText} from '#/components/Button' 26 import {useDialogControl} from '#/components/Dialog' 27 + import {Growth_Stroke2_Corner0_Rounded as Growth} from '#/components/icons/Growth' 28 import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus' 29 import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash' 30 import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' ··· 103 </View> 104 ) : ( 105 <EmptyState 106 + icon={Growth} 107 message={_(msg`No app passwords yet`)} 108 /> 109 )
+1
src/screens/Settings/components/SettingsList.tsx
··· 201 lg: 24, 202 xl: 28, 203 '2xl': 32, 204 }[size] 205 206 const color =
··· 201 lg: 24, 202 xl: 28, 203 '2xl': 32, 204 + '3xl': 40, 205 }[size] 206 207 const color =
+2 -1
src/state/gallery.ts
··· 18 import {openCropper} from '#/lib/media/picker' 19 import {type PickerImage} from '#/lib/media/picker.shared' 20 import {getDataUriSize} from '#/lib/media/util' 21 import {isNative} from '#/platform/detection' 22 23 export type ImageTransformation = { ··· 147 }, 148 } 149 } catch (e) { 150 - if (e instanceof Error && e.message.includes('User cancelled')) { 151 return img 152 } 153
··· 18 import {openCropper} from '#/lib/media/picker' 19 import {type PickerImage} from '#/lib/media/picker.shared' 20 import {getDataUriSize} from '#/lib/media/util' 21 + import {isCancelledError} from '#/lib/strings/errors' 22 import {isNative} from '#/platform/detection' 23 24 export type ImageTransformation = { ··· 148 }, 149 } 150 } catch (e) { 151 + if (!isCancelledError(e)) { 152 return img 153 } 154
+1 -1
src/view/com/composer/photos/Gallery.tsx
··· 241 accessibilityIgnoresInvertColors 242 cachePolicy="none" 243 autoplay={false} 244 /> 245 246 <MediaInsetBorder /> ··· 285 marginTop: 16, 286 }, 287 image: { 288 - resizeMode: 'cover', 289 borderRadius: tokens.borderRadius.md, 290 }, 291 imageControl: {
··· 241 accessibilityIgnoresInvertColors 242 cachePolicy="none" 243 autoplay={false} 244 + contentFit="cover" 245 /> 246 247 <MediaInsetBorder /> ··· 286 marginTop: 16, 287 }, 288 image: { 289 borderRadius: tokens.borderRadius.md, 290 }, 291 imageControl: {
+15 -4
src/view/com/feeds/ProfileFeedgens.tsx
··· 15 } from 'react-native' 16 import {msg} from '@lingui/macro' 17 import {useLingui} from '@lingui/react' 18 import {useQueryClient} from '@tanstack/react-query' 19 20 import {cleanError} from '#/lib/strings/errors' ··· 29 import {LoadMoreRetryBtn} from '#/view/com/util/LoadMoreRetryBtn' 30 import {atoms as a, ios, useTheme} from '#/alf' 31 import * as FeedCard from '#/components/FeedCard' 32 import {ListFooter} from '#/components/Lists' 33 34 const LOADING = {_reactKey: '__loading__'} ··· 78 } = useProfileFeedgensQuery(did, opts) 79 const isEmpty = !isPending && !data?.pages[0]?.feeds.length 80 const {data: preferences} = usePreferencesQuery() 81 82 const items = useMemo(() => { 83 let items: any[] = [] ··· 147 if (item === EMPTY) { 148 return ( 149 <EmptyState 150 - icon="hashtag" 151 - message={_(msg`You have no feeds.`)} 152 - testID="listsEmpty" 153 /> 154 ) 155 } else if (item === ERROR_ITEM) { ··· 183 } 184 return null 185 }, 186 - [_, t, error, refetch, onPressRetryLoadMore, preferences], 187 ) 188 189 useEffect(() => {
··· 15 } from 'react-native' 16 import {msg} from '@lingui/macro' 17 import {useLingui} from '@lingui/react' 18 + import {useNavigation} from '@react-navigation/native' 19 import {useQueryClient} from '@tanstack/react-query' 20 21 import {cleanError} from '#/lib/strings/errors' ··· 30 import {LoadMoreRetryBtn} from '#/view/com/util/LoadMoreRetryBtn' 31 import {atoms as a, ios, useTheme} from '#/alf' 32 import * as FeedCard from '#/components/FeedCard' 33 + import {HashtagWide_Stroke1_Corner0_Rounded as HashtagWideIcon} from '#/components/icons/Hashtag' 34 import {ListFooter} from '#/components/Lists' 35 36 const LOADING = {_reactKey: '__loading__'} ··· 80 } = useProfileFeedgensQuery(did, opts) 81 const isEmpty = !isPending && !data?.pages[0]?.feeds.length 82 const {data: preferences} = usePreferencesQuery() 83 + const navigation = useNavigation() 84 85 const items = useMemo(() => { 86 let items: any[] = [] ··· 150 if (item === EMPTY) { 151 return ( 152 <EmptyState 153 + style={{width: '100%'}} 154 + icon={HashtagWideIcon} 155 + message={_(msg`You haven't made any custom feeds yet.`)} 156 + textStyle={[t.atoms.text_contrast_medium, a.font_medium]} 157 + button={{ 158 + label: _(msg`Browse custom feeds`), 159 + text: _(msg`Browse custom feeds`), 160 + onPress: () => navigation.navigate('Feeds' as never), 161 + size: 'small', 162 + color: 'secondary', 163 + }} 164 /> 165 ) 166 } else if (item === ERROR_ITEM) { ··· 194 } 195 return null 196 }, 197 + [_, t, error, refetch, onPressRetryLoadMore, preferences, navigation], 198 ) 199 200 useEffect(() => {
+6 -7
src/view/com/lists/MyLists.tsx
··· 19 import {useModerationOpts} from '#/state/preferences/moderation-opts' 20 import {type MyListsFilter, useMyListsQuery} from '#/state/queries/my-lists' 21 import {atoms as a, useTheme} from '#/alf' 22 - import {BulletList_Stroke2_Corner0_Rounded as ListIcon} from '#/components/icons/BulletList' 23 import * as ListCard from '#/components/ListCard' 24 import {Text} from '#/components/Typography' 25 import {ErrorMessage} from '../util/error/ErrorMessage' ··· 71 switch (filter) { 72 case 'curate': 73 emptyText = _( 74 - msg`Public, sharable lists which can be used to drive feeds.`, 75 ) 76 break 77 case 'mod': ··· 104 ({item, index}: {item: any; index: number}) => { 105 if (item === EMPTY) { 106 return ( 107 - <View style={[a.flex_1, a.align_center, a.gap_sm, a.px_xl, a.pt_xl]}> 108 <View 109 style={[ 110 a.align_center, 111 a.justify_center, 112 enableSquareButtons ? a.rounded_sm : a.rounded_full, 113 - t.atoms.bg_contrast_25, 114 { 115 - width: 32, 116 - height: 32, 117 }, 118 ]}> 119 - <ListIcon size="md" fill={t.atoms.text_contrast_low.color} /> 120 </View> 121 <Text 122 style={[
··· 19 import {useModerationOpts} from '#/state/preferences/moderation-opts' 20 import {type MyListsFilter, useMyListsQuery} from '#/state/queries/my-lists' 21 import {atoms as a, useTheme} from '#/alf' 22 + import {BulletList_Stroke1_Corner0_Rounded as ListIcon} from '#/components/icons/BulletList' 23 import * as ListCard from '#/components/ListCard' 24 import {Text} from '#/components/Typography' 25 import {ErrorMessage} from '../util/error/ErrorMessage' ··· 71 switch (filter) { 72 case 'curate': 73 emptyText = _( 74 + msg`Lists allow you to see content from your favorite people.`, 75 ) 76 break 77 case 'mod': ··· 104 ({item, index}: {item: any; index: number}) => { 105 if (item === EMPTY) { 106 return ( 107 + <View style={[a.flex_1, a.align_center, a.gap_sm, a.px_xl, a.pt_3xl]}> 108 <View 109 style={[ 110 a.align_center, 111 a.justify_center, 112 enableSquareButtons ? a.rounded_sm : a.rounded_full, 113 { 114 + width: 64, 115 + height: 64, 116 }, 117 ]}> 118 + <ListIcon size="2xl" fill={t.atoms.text_contrast_medium.color} /> 119 </View> 120 <Text 121 style={[
+50 -33
src/view/com/lists/ProfileLists.tsx
··· 15 } from 'react-native' 16 import {msg} from '@lingui/macro' 17 import {useLingui} from '@lingui/react' 18 import {useQueryClient} from '@tanstack/react-query' 19 20 import {cleanError} from '#/lib/strings/errors' 21 import {logger} from '#/logger' 22 import {isIOS, isNative, isWeb} from '#/platform/detection' 23 - import {RQKEY, useProfileListsQuery} from '#/state/queries/profile-lists' 24 import {EmptyState} from '#/view/com/util/EmptyState' 25 import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' 26 import {List, type ListRef} from '#/view/com/util/List' 27 import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' 28 import {LoadMoreRetryBtn} from '#/view/com/util/LoadMoreRetryBtn' 29 import {atoms as a, ios, useTheme} from '#/alf' 30 - import * as ListCard from '#/components/ListCard' 31 import {ListFooter} from '#/components/Lists' 32 33 const LOADING = {_reactKey: '__loading__'} ··· 39 scrollToTop: () => void 40 } 41 42 - interface ProfileListsProps { 43 ref?: React.Ref<SectionRef> 44 did: string 45 scrollElRef: ListRef ··· 59 style, 60 testID, 61 setScrollViewTag, 62 - }: ProfileListsProps) { 63 const t = useTheme() 64 - const {_} = useLingui() 65 const {height} = useWindowDimensions() 66 - const [isPTRing, setIsPTRing] = useState(false) 67 const opts = useMemo(() => ({enabled}), [enabled]) 68 const { 69 data, 70 isPending, 71 hasNextPage, 72 fetchNextPage, 73 - isFetchingNextPage, 74 isError, 75 error, 76 refetch, 77 - } = useProfileListsQuery(did, opts) 78 - const isEmpty = !isPending && !data?.pages[0]?.lists.length 79 80 const items = useMemo(() => { 81 let items: any[] = [] ··· 88 items = items.concat([EMPTY]) 89 } else if (data?.pages) { 90 for (const page of data?.pages) { 91 - items = items.concat(page.lists) 92 } 93 - } 94 - if (isError && !isEmpty) { 95 items = items.concat([LOAD_MORE_ERROR_ITEM]) 96 } 97 return items ··· 119 try { 120 await refetch() 121 } catch (err) { 122 - logger.error('Failed to refresh lists', {message: err}) 123 } 124 setIsPTRing(false) 125 }, [refetch, setIsPTRing]) 126 127 const onEndReached = useCallback(async () => { 128 if (isFetchingNextPage || !hasNextPage || isError) return 129 try { 130 await fetchNextPage() 131 } catch (err) { 132 - logger.error('Failed to load more lists', {message: err}) 133 } 134 }, [isFetchingNextPage, hasNextPage, isError, fetchNextPage]) 135 ··· 140 // rendering 141 // = 142 143 - const renderItemInner = useCallback( 144 ({item, index}: ListRenderItemInfo<any>) => { 145 if (item === EMPTY) { 146 return ( 147 <EmptyState 148 - icon="list-ul" 149 - message={_(msg`You have no lists.`)} 150 - testID="listsEmpty" 151 /> 152 ) 153 } else if (item === ERROR_ITEM) { ··· 166 } else if (item === LOADING) { 167 return <FeedLoadingPlaceholder /> 168 } 169 - return ( 170 - <View 171 - style={[ 172 - (index !== 0 || isWeb) && a.border_t, 173 - t.atoms.border_contrast_low, 174 - a.px_lg, 175 - a.py_lg, 176 - ]}> 177 - <ListCard.Default view={item} /> 178 - </View> 179 - ) 180 }, 181 - [error, refetch, onPressRetryLoadMore, _, t.atoms.border_contrast_low], 182 ) 183 184 useEffect(() => { ··· 188 } 189 }, [enabled, scrollElRef, setScrollViewTag]) 190 191 - const ProfileListsFooter = useCallback(() => { 192 if (isEmpty) return null 193 return ( 194 <ListFooter ··· 215 ref={scrollElRef} 216 data={items} 217 keyExtractor={keyExtractor} 218 - renderItem={renderItemInner} 219 - ListFooterComponent={ProfileListsFooter} 220 refreshing={isPTRing} 221 onRefresh={onRefresh} 222 headerOffset={headerOffset}
··· 15 } from 'react-native' 16 import {msg} from '@lingui/macro' 17 import {useLingui} from '@lingui/react' 18 + import {useNavigation} from '@react-navigation/native' 19 import {useQueryClient} from '@tanstack/react-query' 20 21 import {cleanError} from '#/lib/strings/errors' 22 import {logger} from '#/logger' 23 import {isIOS, isNative, isWeb} from '#/platform/detection' 24 + import {usePreferencesQuery} from '#/state/queries/preferences' 25 + import {RQKEY, useProfileFeedgensQuery} from '#/state/queries/profile-feedgens' 26 import {EmptyState} from '#/view/com/util/EmptyState' 27 import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' 28 import {List, type ListRef} from '#/view/com/util/List' 29 import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' 30 import {LoadMoreRetryBtn} from '#/view/com/util/LoadMoreRetryBtn' 31 import {atoms as a, ios, useTheme} from '#/alf' 32 + import * as FeedCard from '#/components/FeedCard' 33 + import {BulletList_Stroke1_Corner0_Rounded as ListIcon} from '#/components/icons/BulletList' 34 import {ListFooter} from '#/components/Lists' 35 36 const LOADING = {_reactKey: '__loading__'} ··· 42 scrollToTop: () => void 43 } 44 45 + interface ProfileFeedgensProps { 46 ref?: React.Ref<SectionRef> 47 did: string 48 scrollElRef: ListRef ··· 62 style, 63 testID, 64 setScrollViewTag, 65 + }: ProfileFeedgensProps) { 66 + const {_} = useLingui() 67 const t = useTheme() 68 + const [isPTRing, setIsPTRing] = useState(false) 69 const {height} = useWindowDimensions() 70 const opts = useMemo(() => ({enabled}), [enabled]) 71 const { 72 data, 73 isPending, 74 + isFetchingNextPage, 75 hasNextPage, 76 fetchNextPage, 77 isError, 78 error, 79 refetch, 80 + } = useProfileFeedgensQuery(did, opts) 81 + const isEmpty = !isPending && !data?.pages[0]?.feeds.length 82 + const {data: preferences} = usePreferencesQuery() 83 + const navigation = useNavigation() 84 85 const items = useMemo(() => { 86 let items: any[] = [] ··· 93 items = items.concat([EMPTY]) 94 } else if (data?.pages) { 95 for (const page of data?.pages) { 96 + items = items.concat(page.feeds) 97 } 98 + } else if (isError && !isEmpty) { 99 items = items.concat([LOAD_MORE_ERROR_ITEM]) 100 } 101 return items ··· 123 try { 124 await refetch() 125 } catch (err) { 126 + logger.error('Failed to refresh feeds', {message: err}) 127 } 128 setIsPTRing(false) 129 }, [refetch, setIsPTRing]) 130 131 const onEndReached = useCallback(async () => { 132 if (isFetchingNextPage || !hasNextPage || isError) return 133 + 134 try { 135 await fetchNextPage() 136 } catch (err) { 137 + logger.error('Failed to load more feeds', {message: err}) 138 } 139 }, [isFetchingNextPage, hasNextPage, isError, fetchNextPage]) 140 ··· 145 // rendering 146 // = 147 148 + const renderItem = useCallback( 149 ({item, index}: ListRenderItemInfo<any>) => { 150 if (item === EMPTY) { 151 return ( 152 <EmptyState 153 + icon={ListIcon} 154 + message={_( 155 + msg`Lists allow you to see content from your favorite people.`, 156 + )} 157 + textStyle={[t.atoms.text_contrast_medium, a.font_medium]} 158 + button={{ 159 + label: _(msg`Create a list`), 160 + text: _(msg`Create a list`), 161 + onPress: () => navigation.navigate('Lists' as never), 162 + size: 'small', 163 + color: 'primary', 164 + }} 165 /> 166 ) 167 } else if (item === ERROR_ITEM) { ··· 180 } else if (item === LOADING) { 181 return <FeedLoadingPlaceholder /> 182 } 183 + if (preferences) { 184 + return ( 185 + <View 186 + style={[ 187 + (index !== 0 || isWeb) && a.border_t, 188 + t.atoms.border_contrast_low, 189 + a.px_lg, 190 + a.py_lg, 191 + ]}> 192 + <FeedCard.Default view={item} /> 193 + </View> 194 + ) 195 + } 196 + return null 197 }, 198 + [_, t, error, refetch, onPressRetryLoadMore, preferences, navigation], 199 ) 200 201 useEffect(() => { ··· 205 } 206 }, [enabled, scrollElRef, setScrollViewTag]) 207 208 + const ProfileFeedgensFooter = useCallback(() => { 209 if (isEmpty) return null 210 return ( 211 <ListFooter ··· 232 ref={scrollElRef} 233 data={items} 234 keyExtractor={keyExtractor} 235 + renderItem={renderItem} 236 + ListFooterComponent={ProfileFeedgensFooter} 237 refreshing={isPTRing} 238 onRefresh={onRefresh} 239 headerOffset={headerOffset}
+2 -1
src/view/com/notifications/NotificationFeed.tsx
··· 20 import {List, type ListProps, type ListRef} from '#/view/com/util/List' 21 import {NotificationFeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' 22 import {LoadMoreRetryBtn} from '#/view/com/util/LoadMoreRetryBtn' 23 import {NotificationFeedItem} from './NotificationFeedItem' 24 25 const EMPTY_FEED_ITEM = {_reactKey: '__empty__'} ··· 120 if (item === EMPTY_FEED_ITEM) { 121 return ( 122 <EmptyState 123 - icon="bell" 124 message={_(msg`No notifications yet!`)} 125 style={styles.emptyState} 126 />
··· 20 import {List, type ListProps, type ListRef} from '#/view/com/util/List' 21 import {NotificationFeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' 22 import {LoadMoreRetryBtn} from '#/view/com/util/LoadMoreRetryBtn' 23 + import {Bell_Stroke2_Corner0_Rounded as BellIcon} from '#/components/icons/Bell' 24 import {NotificationFeedItem} from './NotificationFeedItem' 25 26 const EMPTY_FEED_ITEM = {_reactKey: '__empty__'} ··· 121 if (item === EMPTY_FEED_ITEM) { 122 return ( 123 <EmptyState 124 + icon={BellIcon} 125 message={_(msg`No notifications yet!`)} 126 style={styles.emptyState} 127 />
+5 -2
src/view/com/posts/PostFeedErrorMessage.tsx
··· 15 import {logger} from '#/logger' 16 import {type FeedDescriptor} from '#/state/queries/post-feed' 17 import {useRemoveFeedMutation} from '#/state/queries/preferences' 18 import * as Prompt from '#/components/Prompt' 19 import {EmptyState} from '../util/EmptyState' 20 import {ErrorMessage} from '../util/error/ErrorMessage' ··· 50 () => detectKnownError(feedDesc, error), 51 [feedDesc, error], 52 ) 53 if ( 54 typeof knownError !== 'undefined' && 55 knownError !== KnownError.Unknown && ··· 68 if (knownError === KnownError.Block) { 69 return ( 70 <EmptyState 71 - icon="ban" 72 - message={_l(msgLingui`Skeets hidden`)} 73 style={{paddingVertical: 40}} 74 /> 75 )
··· 15 import {logger} from '#/logger' 16 import {type FeedDescriptor} from '#/state/queries/post-feed' 17 import {useRemoveFeedMutation} from '#/state/queries/preferences' 18 + import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' 19 import * as Prompt from '#/components/Prompt' 20 import {EmptyState} from '../util/EmptyState' 21 import {ErrorMessage} from '../util/error/ErrorMessage' ··· 51 () => detectKnownError(feedDesc, error), 52 [feedDesc, error], 53 ) 54 + 55 if ( 56 typeof knownError !== 'undefined' && 57 knownError !== KnownError.Unknown && ··· 70 if (knownError === KnownError.Block) { 71 return ( 72 <EmptyState 73 + icon={WarningIcon} 74 + iconSize="2xl" 75 + message={_l(msgLingui`Posts hidden`)} 76 style={{paddingVertical: 40}} 77 /> 78 )
+13 -1
src/view/com/profile/ProfileFollowers.tsx
··· 2 import {type AppBskyActorDefs as ActorDefs} from '@atproto/api' 3 import {msg} from '@lingui/macro' 4 import {useLingui} from '@lingui/react' 5 6 import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender' 7 import {cleanError} from '#/lib/strings/errors' ··· 9 import {useProfileFollowersQuery} from '#/state/queries/profile-followers' 10 import {useResolveDidQuery} from '#/state/queries/resolve-uri' 11 import {useSession} from '#/state/session' 12 import {ListFooter, ListMaybePlaceholder} from '#/components/Lists' 13 import {List} from '../util/List' 14 import {ProfileCardWithFollowBtn} from './ProfileCard' ··· 39 40 export function ProfileFollowers({name}: {name: string}) { 41 const {_} = useLingui() 42 const initialNumToRender = useInitialNumToRender() 43 const {currentAccount} = useSession() 44 ··· 129 emptyType="results" 130 emptyMessage={ 131 isMe 132 - ? _(msg`You do not have any followers.`) 133 : _(msg`This user doesn't have any followers.`) 134 } 135 errorMessage={cleanError(resolveError || error)} 136 onRetry={isError ? refetch : undefined} 137 sideBorders={false} 138 /> 139 ) 140 }
··· 2 import {type AppBskyActorDefs as ActorDefs} from '@atproto/api' 3 import {msg} from '@lingui/macro' 4 import {useLingui} from '@lingui/react' 5 + import {useNavigation} from '@react-navigation/native' 6 7 import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender' 8 import {cleanError} from '#/lib/strings/errors' ··· 10 import {useProfileFollowersQuery} from '#/state/queries/profile-followers' 11 import {useResolveDidQuery} from '#/state/queries/resolve-uri' 12 import {useSession} from '#/state/session' 13 + import {PeopleRemove2_Stroke1_Corner0_Rounded as PeopleRemoveIcon} from '#/components/icons/PeopleRemove2' 14 import {ListFooter, ListMaybePlaceholder} from '#/components/Lists' 15 import {List} from '../util/List' 16 import {ProfileCardWithFollowBtn} from './ProfileCard' ··· 41 42 export function ProfileFollowers({name}: {name: string}) { 43 const {_} = useLingui() 44 + const navigation = useNavigation() 45 const initialNumToRender = useInitialNumToRender() 46 const {currentAccount} = useSession() 47 ··· 132 emptyType="results" 133 emptyMessage={ 134 isMe 135 + ? _(msg`No followers yet`) 136 : _(msg`This user doesn't have any followers.`) 137 } 138 errorMessage={cleanError(resolveError || error)} 139 onRetry={isError ? refetch : undefined} 140 sideBorders={false} 141 + useEmptyState={true} 142 + emptyStateIcon={PeopleRemoveIcon} 143 + emptyStateButton={{ 144 + label: _(msg`Go back`), 145 + text: _(msg`Go back`), 146 + color: 'secondary', 147 + size: 'small', 148 + onPress: () => navigation.goBack(), 149 + }} 150 /> 151 ) 152 }
+24 -1
src/view/com/profile/ProfileFollows.tsx
··· 2 import {type AppBskyActorDefs as ActorDefs} from '@atproto/api' 3 import {msg} from '@lingui/macro' 4 import {useLingui} from '@lingui/react' 5 6 import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender' 7 import {cleanError} from '#/lib/strings/errors' 8 import {logger} from '#/logger' 9 import {useProfileFollowsQuery} from '#/state/queries/profile-follows' 10 import {useResolveDidQuery} from '#/state/queries/resolve-uri' 11 import {useSession} from '#/state/session' 12 import {ListFooter, ListMaybePlaceholder} from '#/components/Lists' 13 import {List} from '../util/List' 14 import {ProfileCardWithFollowBtn} from './ProfileCard' ··· 41 const {_} = useLingui() 42 const initialNumToRender = useInitialNumToRender() 43 const {currentAccount} = useSession() 44 45 const [isPTRing, setIsPTRing] = React.useState(false) 46 const { ··· 129 emptyType="results" 130 emptyMessage={ 131 isMe 132 - ? _(msg`You are not following anyone.`) 133 : _(msg`This user isn't following anyone.`) 134 } 135 errorMessage={cleanError(resolveError || error)} 136 onRetry={isError ? refetch : undefined} 137 sideBorders={false} 138 /> 139 ) 140 }
··· 2 import {type AppBskyActorDefs as ActorDefs} from '@atproto/api' 3 import {msg} from '@lingui/macro' 4 import {useLingui} from '@lingui/react' 5 + import {useNavigation} from '@react-navigation/native' 6 7 import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender' 8 + import {type NavigationProp} from '#/lib/routes/types' 9 import {cleanError} from '#/lib/strings/errors' 10 import {logger} from '#/logger' 11 + import {isWeb} from '#/platform/detection' 12 import {useProfileFollowsQuery} from '#/state/queries/profile-follows' 13 import {useResolveDidQuery} from '#/state/queries/resolve-uri' 14 import {useSession} from '#/state/session' 15 + import {PeopleRemove2_Stroke1_Corner0_Rounded as PeopleRemoveIcon} from '#/components/icons/PeopleRemove2' 16 import {ListFooter, ListMaybePlaceholder} from '#/components/Lists' 17 import {List} from '../util/List' 18 import {ProfileCardWithFollowBtn} from './ProfileCard' ··· 45 const {_} = useLingui() 46 const initialNumToRender = useInitialNumToRender() 47 const {currentAccount} = useSession() 48 + const navigation = useNavigation<NavigationProp>() 49 + 50 + const onPressFindAccounts = React.useCallback(() => { 51 + if (isWeb) { 52 + navigation.navigate('Search', {}) 53 + } else { 54 + navigation.navigate('SearchTab') 55 + navigation.popToTop() 56 + } 57 + }, [navigation]) 58 59 const [isPTRing, setIsPTRing] = React.useState(false) 60 const { ··· 143 emptyType="results" 144 emptyMessage={ 145 isMe 146 + ? _(msg`You are not following anyone yet`) 147 : _(msg`This user isn't following anyone.`) 148 } 149 errorMessage={cleanError(resolveError || error)} 150 onRetry={isError ? refetch : undefined} 151 sideBorders={false} 152 + useEmptyState={true} 153 + emptyStateIcon={PeopleRemoveIcon} 154 + emptyStateButton={{ 155 + label: _(msg`See suggested accounts`), 156 + text: _(msg`See suggested accounts`), 157 + onPress: onPressFindAccounts, 158 + size: 'tiny', 159 + color: 'primary', 160 + }} 161 /> 162 ) 163 }
+84 -49
src/view/com/util/EmptyState.tsx
··· 1 - import {type StyleProp, StyleSheet, View, type ViewStyle} from 'react-native' 2 - import {type IconProp} from '@fortawesome/fontawesome-svg-core' 3 - import { 4 - FontAwesomeIcon, 5 - type FontAwesomeIconStyle, 6 - } from '@fortawesome/react-native-fontawesome' 7 8 import {usePalette} from '#/lib/hooks/usePalette' 9 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 10 - import {UserGroupIcon} from '#/lib/icons' 11 - import {Growth_Stroke2_Corner0_Rounded as Growth} from '#/components/icons/Growth' 12 - import {Text} from './text/Text' 13 14 export function EmptyState({ 15 testID, 16 icon, 17 message, 18 style, 19 }: { 20 testID?: string 21 - icon: IconProp | 'user-group' | 'growth' 22 message: string 23 style?: StyleProp<ViewStyle> 24 }) { 25 const pal = usePalette('default') 26 const {isTabletOrDesktop} = useWebMediaQueries() 27 - const iconSize = isTabletOrDesktop ? 64 : 48 28 return ( 29 <View testID={testID} style={style}> 30 <View 31 style={[ 32 - styles.iconContainer, 33 - isTabletOrDesktop && styles.iconContainerBig, 34 - pal.viewLight, 35 ]}> 36 - {icon === 'user-group' ? ( 37 - <UserGroupIcon size={iconSize} /> 38 - ) : icon === 'growth' ? ( 39 - <Growth width={iconSize} fill={pal.colors.emptyStateIcon} /> 40 - ) : ( 41 - <FontAwesomeIcon 42 - icon={icon} 43 - size={iconSize} 44 - style={[{color: pal.colors.emptyStateIcon} as FontAwesomeIconStyle]} 45 - /> 46 - )} 47 </View> 48 - <Text type="xl" style={[{color: pal.colors.textLight}, styles.text]}> 49 {message} 50 </Text> 51 </View> 52 ) 53 } 54 - 55 - const styles = StyleSheet.create({ 56 - iconContainer: { 57 - flexDirection: 'row', 58 - alignItems: 'center', 59 - justifyContent: 'center', 60 - height: 80, 61 - width: 80, 62 - marginLeft: 'auto', 63 - marginRight: 'auto', 64 - borderRadius: 80, 65 - marginTop: 30, 66 - }, 67 - iconContainerBig: { 68 - width: 100, 69 - height: 100, 70 - marginTop: 50, 71 - }, 72 - text: { 73 - textAlign: 'center', 74 - paddingTop: 20, 75 - }, 76 - })
··· 1 + import React from 'react' 2 + import {type StyleProp, type TextStyle, type ViewStyle} from 'react-native' 3 + import {View} from 'react-native' 4 5 import {usePalette} from '#/lib/hooks/usePalette' 6 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 7 + import {atoms as a, useBreakpoints, useTheme} from '#/alf' 8 + import {Button, type ButtonProps, ButtonText} from '#/components/Button' 9 + import {EditBig_Stroke1_Corner0_Rounded as EditIcon} from '#/components/icons/EditBig' 10 + import {Text} from '#/components/Typography' 11 + 12 + export type EmptyStateButtonProps = Omit<ButtonProps, 'children' | 'label'> & { 13 + label: string 14 + text: string 15 + } 16 17 export function EmptyState({ 18 testID, 19 icon, 20 + iconSize = '3xl', 21 message, 22 style, 23 + textStyle, 24 + button, 25 }: { 26 testID?: string 27 + icon?: React.ComponentType<any> | React.ReactElement 28 + iconSize?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' 29 message: string 30 style?: StyleProp<ViewStyle> 31 + textStyle?: StyleProp<TextStyle> 32 + button?: EmptyStateButtonProps 33 }) { 34 const pal = usePalette('default') 35 const {isTabletOrDesktop} = useWebMediaQueries() 36 + const t = useTheme() 37 + const {gtMobile} = useBreakpoints() 38 + 39 + const placeholderIcon = ( 40 + <EditIcon size="2xl" fill={t.atoms.text_contrast_medium.color} /> 41 + ) 42 + 43 + const renderIcon = () => { 44 + if (!icon) { 45 + return placeholderIcon 46 + } 47 + 48 + if (React.isValidElement(icon)) { 49 + return icon 50 + } 51 + 52 + if ( 53 + typeof icon === 'function' || 54 + (typeof icon === 'object' && icon && 'render' in icon) 55 + ) { 56 + const IconComponent = icon 57 + return ( 58 + <IconComponent 59 + size={iconSize} 60 + fill={t.atoms.text_contrast_medium.color} 61 + style={{color: t.atoms.text_contrast_low.color}} 62 + /> 63 + ) 64 + } 65 + 66 + return placeholderIcon 67 + } 68 + 69 return ( 70 <View testID={testID} style={style}> 71 <View 72 style={[ 73 + a.flex_row, 74 + a.align_center, 75 + a.justify_center, 76 + a.self_center, 77 + a.rounded_full, 78 + a.mt_5xl, 79 + {height: 64, width: 64}, 80 + React.isValidElement(icon) 81 + ? a.bg_transparent 82 + : [isTabletOrDesktop && {marginTop: 50}], 83 ]}> 84 + {renderIcon()} 85 </View> 86 + <Text 87 + style={[ 88 + { 89 + color: pal.colors.textLight, 90 + maxWidth: gtMobile ? '40%' : '60%', 91 + }, 92 + a.pt_xs, 93 + a.font_medium, 94 + a.text_md, 95 + a.leading_snug, 96 + a.text_center, 97 + a.self_center, 98 + textStyle, 99 + ]}> 100 {message} 101 </Text> 102 + {button && ( 103 + <View style={[a.flex_shrink, a.mt_xl, a.self_center]}> 104 + <Button {...button}> 105 + <ButtonText>{button.text}</ButtonText> 106 + </Button> 107 + </View> 108 + )} 109 </View> 110 ) 111 }
+4 -3
src/view/com/util/UserAvatar.tsx
··· 26 import {type PickerImage} from '#/lib/media/picker.shared' 27 import {makeProfileLink} from '#/lib/routes/links' 28 import {sanitizeDisplayName} from '#/lib/strings/display-names' 29 import {sanitizeHandle} from '#/lib/strings/handles' 30 import {logger} from '#/logger' 31 import {isAndroid, isNative, isWeb} from '#/platform/detection' ··· 441 setRawImage(await createComposerImage(item)) 442 editImageDialogControl.open() 443 } 444 - } catch (e: any) { 445 // Don't log errors for cancelling selection to sentry on ios or android 446 - if (!String(e).toLowerCase().includes('cancel')) { 447 - logger.error('Failed to crop banner', {error: e}) 448 } 449 } 450 }, [
··· 26 import {type PickerImage} from '#/lib/media/picker.shared' 27 import {makeProfileLink} from '#/lib/routes/links' 28 import {sanitizeDisplayName} from '#/lib/strings/display-names' 29 + import {isCancelledError} from '#/lib/strings/errors' 30 import {sanitizeHandle} from '#/lib/strings/handles' 31 import {logger} from '#/logger' 32 import {isAndroid, isNative, isWeb} from '#/platform/detection' ··· 442 setRawImage(await createComposerImage(item)) 443 editImageDialogControl.open() 444 } 445 + } catch (e) { 446 // Don't log errors for cancelling selection to sentry on ios or android 447 + if (!isCancelledError(e)) { 448 + logger.error('Failed to crop avatar', {error: e}) 449 } 450 } 451 }, [
+4 -2
src/view/com/util/UserBanner.tsx
··· 12 import {compressIfNeeded} from '#/lib/media/manip' 13 import {openCamera, openCropper, openPicker} from '#/lib/media/picker' 14 import {type PickerImage} from '#/lib/media/picker.shared' 15 import {logger} from '#/logger' 16 import {isAndroid, isNative} from '#/platform/detection' 17 import { ··· 92 setRawImage(await createComposerImage(items[0])) 93 editImageDialogControl.open() 94 } 95 - } catch (e: any) { 96 - if (!String(e).includes('Canceled')) { 97 logger.error('Failed to crop banner', {error: e}) 98 } 99 }
··· 12 import {compressIfNeeded} from '#/lib/media/manip' 13 import {openCamera, openCropper, openPicker} from '#/lib/media/picker' 14 import {type PickerImage} from '#/lib/media/picker.shared' 15 + import {isCancelledError} from '#/lib/strings/errors' 16 import {logger} from '#/logger' 17 import {isAndroid, isNative} from '#/platform/detection' 18 import { ··· 93 setRawImage(await createComposerImage(items[0])) 94 editImageDialogControl.open() 95 } 96 + } catch (e) { 97 + // Don't log errors for cancelling selection to sentry on ios or android 98 + if (!isCancelledError(e)) { 99 logger.error('Failed to crop banner', {error: e}) 100 } 101 }
+10 -1
src/view/screens/Debug.tsx
··· 20 import * as Toast from '#/view/com/util/Toast' 21 import {ViewHeader} from '#/view/com/util/ViewHeader' 22 import {ViewSelector} from '#/view/com/util/ViewSelector' 23 import * as Layout from '#/components/Layout' 24 25 const MAIN_VIEWS = ['Base', 'Controls', 'Error', 'Notifs'] ··· 333 } 334 335 function EmptyStateView() { 336 - return <EmptyState icon="bars" message="This is an empty state" /> 337 } 338 339 function LoadingPlaceholderView() {
··· 20 import * as Toast from '#/view/com/util/Toast' 21 import {ViewHeader} from '#/view/com/util/ViewHeader' 22 import {ViewSelector} from '#/view/com/util/ViewSelector' 23 + import {HashtagWide_Stroke1_Corner0_Rounded as HashtagWideIcon} from '#/components/icons/Hashtag' 24 import * as Layout from '#/components/Layout' 25 26 const MAIN_VIEWS = ['Base', 'Controls', 'Error', 'Notifs'] ··· 334 } 335 336 function EmptyStateView() { 337 + const {_} = useLingui() 338 + 339 + return ( 340 + <EmptyState 341 + icon={HashtagWideIcon} 342 + iconSize="2xl" 343 + message={_(msg`This is an empty state`)} 344 + /> 345 + ) 346 } 347 348 function LoadingPlaceholderView() {
+63 -2
src/view/screens/Profile.tsx
··· 7 type ModerationOpts, 8 RichText as RichTextAPI, 9 } from '@atproto/api' 10 - import {msg} from '@lingui/macro' 11 import {useLingui} from '@lingui/react' 12 - import {useFocusEffect} from '@react-navigation/native' 13 import {useQueryClient} from '@tanstack/react-query' 14 15 import {useOpenComposer} from '#/lib/hooks/useOpenComposer' 16 import {useSetTitle} from '#/lib/hooks/useSetTitle' 17 import {ComposeIcon2} from '#/lib/icons' 18 import { 19 type CommonNavigatorParams, 20 type NativeStackScreenProps, 21 } from '#/lib/routes/types' 22 import {combinedDisplayName} from '#/lib/strings/display-names' 23 import {cleanError} from '#/lib/strings/errors' ··· 42 import {ProfileFeedSection} from '#/screens/Profile/Sections/Feed' 43 import {ProfileLabelsSection} from '#/screens/Profile/Sections/Labels' 44 import {atoms as a} from '#/alf' 45 import * as Layout from '#/components/Layout' 46 import {ScreenHider} from '#/components/moderation/ScreenHider' 47 import {ProfileStarterPacks} from '#/components/StarterPack/ProfileStarterPacks' ··· 169 const {hasSession, currentAccount} = useSession() 170 const setMinimalShellMode = useSetMinimalShellMode() 171 const {openComposer} = useOpenComposer() 172 const { 173 data: labelerInfo, 174 error: labelerError, ··· 334 scrollSectionToTop(index) 335 } 336 337 // rendering 338 // = 339 ··· 408 scrollElRef={scrollElRef as ListRef} 409 ignoreFilterFor={profile.did} 410 setScrollViewTag={setScrollViewTag} 411 /> 412 ) 413 : null} ··· 421 scrollElRef={scrollElRef as ListRef} 422 ignoreFilterFor={profile.did} 423 setScrollViewTag={setScrollViewTag} 424 /> 425 ) 426 : null} ··· 434 scrollElRef={scrollElRef as ListRef} 435 ignoreFilterFor={profile.did} 436 setScrollViewTag={setScrollViewTag} 437 /> 438 ) 439 : null} ··· 447 scrollElRef={scrollElRef as ListRef} 448 ignoreFilterFor={profile.did} 449 setScrollViewTag={setScrollViewTag} 450 /> 451 ) 452 : null} ··· 460 scrollElRef={scrollElRef as ListRef} 461 ignoreFilterFor={profile.did} 462 setScrollViewTag={setScrollViewTag} 463 /> 464 ) 465 : null} ··· 485 headerOffset={headerHeight} 486 enabled={isFocused} 487 setScrollViewTag={setScrollViewTag} 488 /> 489 ) 490 : null}
··· 7 type ModerationOpts, 8 RichText as RichTextAPI, 9 } from '@atproto/api' 10 + import {msg, Trans} from '@lingui/macro' 11 import {useLingui} from '@lingui/react' 12 + import {useFocusEffect, useNavigation} from '@react-navigation/native' 13 import {useQueryClient} from '@tanstack/react-query' 14 15 import {useOpenComposer} from '#/lib/hooks/useOpenComposer' 16 + import {useRequireEmailVerification} from '#/lib/hooks/useRequireEmailVerification' 17 import {useSetTitle} from '#/lib/hooks/useSetTitle' 18 import {ComposeIcon2} from '#/lib/icons' 19 import { 20 type CommonNavigatorParams, 21 type NativeStackScreenProps, 22 + type NavigationProp, 23 } from '#/lib/routes/types' 24 import {combinedDisplayName} from '#/lib/strings/display-names' 25 import {cleanError} from '#/lib/strings/errors' ··· 44 import {ProfileFeedSection} from '#/screens/Profile/Sections/Feed' 45 import {ProfileLabelsSection} from '#/screens/Profile/Sections/Labels' 46 import {atoms as a} from '#/alf' 47 + import {Circle_And_Square_Stroke1_Corner0_Rounded_Filled as CircleAndSquareIcon} from '#/components/icons/CircleAndSquare' 48 + import {Heart2_Stroke1_Corner0_Rounded as HeartIcon} from '#/components/icons/Heart2' 49 + import {Image_Stroke1_Corner0_Rounded as ImageIcon} from '#/components/icons/Image' 50 + import {Message_Stroke1_Corner0_Rounded_Filled as MessageIcon} from '#/components/icons/Message' 51 + import {VideoClip_Stroke1_Corner0_Rounded as VideoIcon} from '#/components/icons/VideoClip' 52 import * as Layout from '#/components/Layout' 53 import {ScreenHider} from '#/components/moderation/ScreenHider' 54 import {ProfileStarterPacks} from '#/components/StarterPack/ProfileStarterPacks' ··· 176 const {hasSession, currentAccount} = useSession() 177 const setMinimalShellMode = useSetMinimalShellMode() 178 const {openComposer} = useOpenComposer() 179 + const navigation = useNavigation<NavigationProp>() 180 + const requireEmailVerification = useRequireEmailVerification() 181 const { 182 data: labelerInfo, 183 error: labelerError, ··· 343 scrollSectionToTop(index) 344 } 345 346 + const navToWizard = useCallback(() => { 347 + navigation.navigate('StarterPackWizard', {}) 348 + }, [navigation]) 349 + const wrappedNavToWizard = requireEmailVerification(navToWizard, { 350 + instructions: [ 351 + <Trans key="nav"> 352 + Before creating a starter pack, you must first verify your email. 353 + </Trans>, 354 + ], 355 + }) 356 + 357 // rendering 358 // = 359 ··· 428 scrollElRef={scrollElRef as ListRef} 429 ignoreFilterFor={profile.did} 430 setScrollViewTag={setScrollViewTag} 431 + emptyStateMessage={_(msg`No posts yet`)} 432 + emptyStateButton={{ 433 + label: _(msg`Write a post`), 434 + text: _(msg`Write a post`), 435 + onPress: () => openComposer({}), 436 + size: 'small', 437 + color: 'primary', 438 + }} 439 /> 440 ) 441 : null} ··· 449 scrollElRef={scrollElRef as ListRef} 450 ignoreFilterFor={profile.did} 451 setScrollViewTag={setScrollViewTag} 452 + emptyStateMessage={_(msg`No replies yet`)} 453 + emptyStateIcon={MessageIcon} 454 /> 455 ) 456 : null} ··· 464 scrollElRef={scrollElRef as ListRef} 465 ignoreFilterFor={profile.did} 466 setScrollViewTag={setScrollViewTag} 467 + emptyStateMessage={_(msg`No media yet`)} 468 + emptyStateButton={{ 469 + label: _(msg`Post a photo`), 470 + text: _(msg`Post a photo`), 471 + onPress: () => openComposer({}), 472 + size: 'small', 473 + color: 'primary', 474 + }} 475 + emptyStateIcon={ImageIcon} 476 /> 477 ) 478 : null} ··· 486 scrollElRef={scrollElRef as ListRef} 487 ignoreFilterFor={profile.did} 488 setScrollViewTag={setScrollViewTag} 489 + emptyStateMessage={_(msg`No video posts yet`)} 490 + emptyStateButton={{ 491 + label: _(msg`Post a video`), 492 + text: _(msg`Post a video`), 493 + onPress: () => openComposer({}), 494 + size: 'small', 495 + color: 'primary', 496 + }} 497 + emptyStateIcon={VideoIcon} 498 /> 499 ) 500 : null} ··· 508 scrollElRef={scrollElRef as ListRef} 509 ignoreFilterFor={profile.did} 510 setScrollViewTag={setScrollViewTag} 511 + emptyStateMessage={_(msg`No likes yet`)} 512 + emptyStateIcon={HeartIcon} 513 /> 514 ) 515 : null} ··· 535 headerOffset={headerHeight} 536 enabled={isFocused} 537 setScrollViewTag={setScrollViewTag} 538 + emptyStateMessage={_( 539 + msg`Starter packs let you share your favorite feeds and people with your friends.`, 540 + )} 541 + emptyStateButton={{ 542 + label: _(msg`Create a Starter Pack`), 543 + text: _(msg`Create a Starter Pack`), 544 + onPress: wrappedNavToWizard, 545 + color: 'primary', 546 + size: 'small', 547 + }} 548 + emptyStateIcon={CircleAndSquareIcon} 549 /> 550 ) 551 : null}