Use title case for Starter Pack (#11653)

This commit is contained in:
DS Boyce
2026-09-03 12:26:51 -07:00
committed by GitHub
parent 23d8fcf5ea
commit edcd363fcb
39 changed files with 295 additions and 393 deletions
@@ -2,8 +2,7 @@ import {forwardRef, useCallback, useImperativeHandle, useState} from 'react'
import {type ListRenderItemInfo, View} from 'react-native'
import {AtUri} from '@atproto/syntax'
import {type ModerationOpts} from '@bsky/sdk/moderation'
import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'
import {useLingui} from '@lingui/react/macro'
import {Trans} from '@lingui/react/macro'
import {useBottomBarOffset} from '#/lib/hooks/useBottomBarOffset'
@@ -107,6 +106,12 @@ export const ProfilesList = forwardRef<SectionRef, ProfilesListProps>(
)
}
const onRefresh = async () => {
setIsPTRing(true)
await refetch()
setIsPTRing(false)
}
if (!data) {
return (
<View
@@ -140,11 +145,7 @@ export const ProfilesList = forwardRef<SectionRef, ProfilesListProps>(
desktopFixedHeight
initialNumToRender={initialNumToRender}
refreshing={isPTRing}
onRefresh={async () => {
setIsPTRing(true)
await refetch()
setIsPTRing(false)
}}
onRefresh={() => void onRefresh()}
/>
)
},
@@ -159,14 +160,14 @@ function OptedOutControls({
listUri: string
canRemove: boolean
}) {
const {_} = useLingui()
const {t: l} = useLingui()
const ax = useAnalytics()
const [isRemoved, setIsRemoved] = useState(false)
const {mutate: removeMembership, isPending} = useListMembershipRemoveMutation(
{
onSuccess: () => {
setIsRemoved(true)
Toast.show(_(msg`Removed from starter pack`))
Toast.show(l`Removed from Starter Pack`)
},
onError: error =>
Toast.show(cleanError(error), {
@@ -183,12 +184,12 @@ function OptedOutControls({
<Admonition.Icon />
<Admonition.Content>
<Admonition.Text>
<Trans>Opted out of this starter pack</Trans>
<Trans>Opted out of this Starter Pack</Trans>
</Admonition.Text>
</Admonition.Content>
{canRemove ? (
<Admonition.Button
label={_(msg`Remove user from starter pack`)}
label={l`Remove user from Starter Pack`}
color="secondary"
disabled={isPending}
onPress={() => {
@@ -6,9 +6,7 @@ import {
View,
type ViewStyle,
} from 'react-native'
import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro'
import {Trans, useLingui} from '@lingui/react/macro'
import {useNavigation} from '@react-navigation/native'
import {useGenerateStarterPackMutation} from '#/lib/generate-starterpack'
@@ -54,7 +52,7 @@ interface ProfileFeedgensProps {
isMe: boolean
emptyStateMessage?: string
emptyStateButton?: EmptyStateButtonProps
emptyStateIcon?: React.ComponentType<any> | React.ReactElement
emptyStateIcon?: React.ComponentType | React.ReactElement
}
function keyExtractor(item: app.bsky.graph.defs.StarterPackViewBasic) {
@@ -90,7 +88,7 @@ export function ProfileStarterPacks({
const {isTabletOrDesktop} = useWebMediaQueries()
const items = data?.pages.flatMap(page => page.starterPacks)
const {_} = useLingui()
const {t: l} = useLingui()
const EmptyComponent = useCallback(() => {
if (emptyStateMessage || emptyStateButton || emptyStateIcon) {
@@ -101,9 +99,7 @@ export function ProfileStarterPacks({
iconSize="3xl"
message={
emptyStateMessage ??
_(
msg`Starter packs let you share your favorite feeds and people with your friends.`,
)
l`Starter Packs let you share your favorite feeds and people with your friends.`
}
button={emptyStateButton}
/>
@@ -111,7 +107,7 @@ export function ProfileStarterPacks({
)
}
return <Empty />
}, [_, emptyStateMessage, emptyStateButton, emptyStateIcon])
}, [l, emptyStateMessage, emptyStateButton, emptyStateIcon])
useImperativeHandle(ref, () => ({
scrollToTop: () => {},
@@ -122,7 +118,7 @@ export function ProfileStarterPacks({
try {
await refetch()
} catch (err) {
logger.error('Failed to refresh starter packs', {message: err})
logger.error('Failed to refresh Starter Packs', {message: err})
}
setIsPTRing(false)
}, [refetch, setIsPTRing])
@@ -132,7 +128,7 @@ export function ProfileStarterPacks({
try {
await fetchNextPage()
} catch (err) {
logger.error('Failed to load more starter packs', {message: err})
logger.error('Failed to load more Starter Packs', {message: err})
}
}, [isFetchingNextPage, hasNextPage, isError, fetchNextPage])
@@ -179,8 +175,8 @@ export function ProfileStarterPacks({
}}
removeClippedSubviews={true}
desktopFixedHeight
onEndReached={onEndReached}
onRefresh={onRefresh}
onEndReached={() => void onEndReached()}
onRefresh={() => void onRefresh()}
ListEmptyComponent={
data ? (isMe ? EmptyComponent : undefined) : FeedLoadingPlaceholder
}
@@ -193,7 +189,7 @@ export function ProfileStarterPacks({
}
function CreateAnother() {
const {_} = useLingui()
const {t: l} = useLingui()
const t = useTheme()
const navigation = useNavigation<NavigationProp>()
@@ -207,7 +203,7 @@ function CreateAnother() {
t.atoms.border_contrast_low,
]}>
<Button
label={_(msg`Create a starter pack`)}
label={l`Create a Starter Pack`}
variant="solid"
color="secondary"
size="small"
@@ -223,7 +219,7 @@ function CreateAnother() {
}
function Empty() {
const {_} = useLingui()
const {t: l} = useLingui()
const navigation = useNavigation<NavigationProp>()
const confirmDialogControl = useDialogControl()
const followersDialogControl = useDialogControl()
@@ -244,7 +240,7 @@ function Empty() {
setIsGenerating(false)
},
onError: e => {
logger.error('Failed to generate starter pack', {safeMessage: e})
logger.error('Failed to generate Starter Pack', {safeMessage: e})
setIsGenerating(false)
if (e.message.includes('NOT_ENOUGH_FOLLOWERS')) {
followersDialogControl.open()
@@ -265,7 +261,7 @@ function Empty() {
const wrappedOpenConfirmDialog = requireEmailVerification(openConfirmDialog, {
instructions: [
<Trans key="confirm">
Before creating a starter pack, you must first verify your email.
Before creating a Starter Pack, you must first verify your email.
</Trans>,
],
})
@@ -275,7 +271,7 @@ function Empty() {
const wrappedNavToWizard = requireEmailVerification(navToWizard, {
instructions: [
<Trans key="nav">
Before creating a starter pack, you must first verify your email.
Before creating a Starter Pack, you must first verify your email.
</Trans>,
],
})
@@ -292,18 +288,18 @@ function Empty() {
]}>
<View style={[a.gap_xs]}>
<Text style={[a.font_semi_bold, a.text_lg, {color: 'white'}]}>
<Trans>You haven't created a starter pack yet!</Trans>
<Trans>You haven't created a Starter Pack yet!</Trans>
</Text>
<Text style={[a.text_md, {color: 'white'}]}>
<Trans>
Starter packs let you easily share your favorite feeds and people
Starter Packs let you easily share your favorite feeds and people
with your friends.
</Trans>
</Text>
</View>
<View style={[a.flex_row, a.gap_md, {marginLeft: 'auto'}]}>
<Button
label={_(msg`Create a starter pack for me`)}
label={l`Create a Starter Pack for me`}
variant="ghost"
color="primary"
size="small"
@@ -316,7 +312,7 @@ function Empty() {
{isGenerating && <Loader size="md" />}
</Button>
<Button
label={_(msg`Create a starter pack`)}
label={l`Create a Starter Pack`}
variant="ghost"
color="primary"
size="small"
@@ -333,11 +329,10 @@ function Empty() {
</ButtonText>
</Button>
</View>
<Prompt.Outer control={confirmDialogControl}>
<Prompt.Content>
<Prompt.TitleText>
<Trans>Generate a starter pack</Trans>
<Trans>Generate a Starter Pack</Trans>
</Prompt.TitleText>
<Prompt.DescriptionText>
<Trans>
@@ -349,12 +344,12 @@ function Empty() {
<Prompt.Actions>
<Prompt.Action
color="primary"
cta={_(msg`Choose for me`)}
cta={l`Choose for me`}
onPress={generate}
/>
<Prompt.Action
color="secondary"
cta={_(msg`Let me choose`)}
cta={l`Let me choose`}
onPress={() => {
navigation.navigate('StarterPackWizard', {})
}}
@@ -363,21 +358,17 @@ function Empty() {
</Prompt.Outer>
<Prompt.Basic
control={followersDialogControl}
title={_(msg`Oops!`)}
description={_(
msg`You must be following at least seven other people to generate a starter pack.`,
)}
title={l`Oops!`}
description={l`You must be following at least seven other people to generate a Starter Pack.`}
onConfirm={() => {}}
showCancel={false}
/>
<Prompt.Basic
control={errorDialogControl}
title={_(msg`Oops!`)}
description={_(
msg`An error occurred while generating your starter pack. Want to try again?`,
)}
title={l`Oops!`}
description={l`An error occurred while generating your Starter Pack. Want to try again?`}
onConfirm={generate}
confirmButtonCta={_(msg`Retry`)}
confirmButtonCta={l`Retry`}
/>
</LinearGradientBackground>
)
+1 -1
View File
@@ -164,7 +164,7 @@ export function QrCodeDialog({
<Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}>
<Dialog.Handle />
<Dialog.ScrollableInner
label={_(msg`Create a QR code for a starter pack`)}>
label={_(msg`Create a QR code for a Starter Pack`)}>
<View style={[a.flex_1, a.align_center, a.gap_5xl]}>
<Suspense fallback={<Loading />}>
{!link ? (
+2 -2
View File
@@ -81,11 +81,11 @@ function ShareDialogInner({
<View style={[!gtMobile && a.gap_lg]}>
<View style={[a.gap_sm, gtMobile && a.pb_lg]}>
<Text style={[a.font_semi_bold, a.text_2xl]}>
<Trans>Invite people to this starter pack!</Trans>
<Trans>Invite people to this Starter Pack!</Trans>
</Text>
<Text style={[a.text_md, t.atoms.text_contrast_medium]}>
<Trans>
Share this starter pack and help people join your community on
Share this Starter Pack and help people join your community on
Bluesky.
</Trans>
</Text>
+10 -12
View File
@@ -2,9 +2,7 @@ import {useMemo} from 'react'
import {View} from 'react-native'
import {Image} from 'expo-image'
import {AtUri} from '@atproto/syntax'
import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'
import {Plural, Trans} from '@lingui/react/macro'
import {Plural, Trans, useLingui} from '@lingui/react/macro'
import {useQueryClient} from '@tanstack/react-query'
import {sanitizeHandle} from '#/lib/strings/handles'
@@ -59,7 +57,7 @@ export function Card({
}) {
const {record, creator, joinedAllTimeCount} = starterPack
const {_} = useLingui()
const {t: l} = useLingui()
const t = useTheme()
const {currentAccount} = useSession()
const isOwnStarterPack = creator?.did === currentAccount?.did
@@ -84,8 +82,8 @@ export function Card({
style={[a.leading_snug, t.atoms.text_contrast_medium]}
numberOfLines={1}>
{isOwnStarterPack
? _(msg`Starter pack by you`)
: _(msg`Starter pack by ${sanitizeHandle(creator.handle, '@')}`)}
? l`Starter Pack by you`
: l`Starter Pack by ${sanitizeHandle(creator.handle, '@')}`}
</Text>
</View>
</View>
@@ -96,7 +94,7 @@ export function Card({
) : null}
{!!joinedAllTimeCount && joinedAllTimeCount >= 50 && (
<Text style={[a.font_semi_bold, t.atoms.text_contrast_medium]}>
<Trans comment="Number of users (always at least 50) who have joined Bluesky using a specific starter pack">
<Trans comment="Number of users (always at least 50) who have joined Bluesky using a specific Starter Pack">
<Plural value={joinedAllTimeCount} other="# users have" /> joined!
</Trans>
</Text>
@@ -110,7 +108,7 @@ export function useStarterPackLink({
}: {
view: bsky.starterPack.AnyStarterPackView
}) {
const {_} = useLingui()
const {t: l} = useLingui()
const qc = useQueryClient()
const {rkey, handleOrDid} = useMemo(() => {
const rkey = new AtUri(view.uri).rkey
@@ -125,8 +123,8 @@ export function useStarterPackLink({
return {
to: `/starter-pack/${handleOrDid}/${rkey}`,
label: bsky.isType(app.bsky.graph.starterpack, view.record)
? _(msg`Navigate to ${view.record.name}`)
: _(msg`Navigate to starter pack`),
? l`Navigate to ${view.record.name}`
: l`Navigate to Starter Pack`,
precache,
}
}
@@ -139,7 +137,7 @@ export function Link({
onPress?: () => void
children: BaseLinkProps['children']
}) {
const {_} = useLingui()
const {t: l} = useLingui()
const queryClient = useQueryClient()
const {record} = starterPack
const {rkey, handleOrDid} = useMemo(() => {
@@ -155,7 +153,7 @@ export function Link({
return (
<BaseLink
to={`/starter-pack/${handleOrDid}/${rkey}`}
label={_(msg`Navigate to ${record.name}`)}
label={l`Navigate to ${record.name}`}
onPress={() => {
precacheResolvedUri(
queryClient,
@@ -5,9 +5,7 @@ import {
type ModerationOpts,
type ModerationUI,
} from '@bsky/sdk/moderation'
import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro'
import {Trans, useLingui} from '@lingui/react/macro'
import {DISCOVER_FEED_URI, STARTER_PACK_MAX_SIZE} from '#/lib/constants'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
@@ -53,15 +51,15 @@ function WizardListCard({
moderationUi: ModerationUI
}) {
const t = useTheme()
const {_} = useLingui()
const {t: l} = useLingui()
return (
<Toggle.Item
name={type === 'user' ? _(msg`Person toggle`) : _(msg`Feed toggle`)}
name={type === 'user' ? l`Person toggle` : l`Feed toggle`}
label={
included
? _(msg`Remove ${displayName} from starter pack`)
: _(msg`Add ${displayName} to starter pack`)
? l`Remove ${displayName} from Starter Pack`
: l`Add ${displayName} to Starter Pack`
}
value={included}
disabled={btnType === 'remove' || disabled}
@@ -109,7 +107,7 @@ function WizardListCard({
<Checkbox />
) : !disabled ? (
<Button
label={_(msg`Remove`)}
label={l`Remove`}
variant="solid"
color="secondary"
size="small"
@@ -142,7 +140,7 @@ export function WizardProfileCard({
const ax = useAnalytics()
const {currentAccount} = useSession()
// Determine the "main" profile for this starter pack - either targetDid or current account
// Determine the "main" profile for this Starter Pack - either targetDid or current account
const targetProfileDid = state.targetDid || currentAccount?.did
const isTarget = profile.did === targetProfileDid
const included = isTarget || state.profiles.some(p => p.did === profile.did)