From f84c85aac6811e76f58b12e8880e0897f4331d66 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Fri, 5 Jun 2026 00:37:42 +0300 Subject: [PATCH 01/11] Use Reanimated layout animations for Android composer (#8546) --- src/view/shell/Composer.ios.tsx | 23 ++++++++------- src/view/shell/Composer.tsx | 52 ++++++++++++++------------------- src/view/shell/Composer.web.tsx | 7 ++--- src/view/shell/index.tsx | 4 +-- src/view/shell/index.web.tsx | 2 +- 5 files changed, 38 insertions(+), 50 deletions(-) diff --git a/src/view/shell/Composer.ios.tsx b/src/view/shell/Composer.ios.tsx index 437e610b20..7a1f599374 100644 --- a/src/view/shell/Composer.ios.tsx +++ b/src/view/shell/Composer.ios.tsx @@ -1,29 +1,30 @@ -import {useEffect, useRef} from 'react' +import {useEffect} from 'react' import {Modal, View} from 'react-native' +import {SystemBars} from 'react-native-edge-to-edge' -import {useDialogStateControlContext} from '#/state/dialogs' import {useComposerState} from '#/state/shell/composer' import {ComposePost, useComposerCancelRef} from '#/view/com/composer/Composer' import {atoms as a, useTheme} from '#/alf' import {SheetCompatProvider as TooltipSheetCompatProvider} from '#/components/Tooltip' +import {IS_LIQUID_GLASS} from '#/env' -export function Composer({}: {winHeight: number}) { - const {setFullyExpandedCount} = useDialogStateControlContext() +export function Composer() { const t = useTheme() const state = useComposerState() const ref = useComposerCancelRef() const open = !!state - const prevOpen = useRef(open) useEffect(() => { - if (open && !prevOpen.current) { - setFullyExpandedCount(c => c + 1) - } else if (!open && prevOpen.current) { - setFullyExpandedCount(c => c - 1) + if (open && !IS_LIQUID_GLASS) { + const entry = SystemBars.pushStackEntry({ + style: { + statusBar: 'light', + }, + }) + return () => SystemBars.popStackEntry(entry) } - prevOpen.current = open - }, [open, setFullyExpandedCount]) + }, [open]) return ( { - if (state) { - Animated.timing(initInterp, { - toValue: 1, - duration: 300, - easing: Easing.out(Easing.exp), - useNativeDriver: true, - }).start() - } else { - initInterp.setValue(0) + if (open) { + const entry = SystemBars.pushStackEntry({ + style: { + statusBar: t.name !== 'light' ? 'light' : 'dark', + }, + }) + return () => SystemBars.popStackEntry(entry) } - }, [initInterp, state]) - const wrapperAnimStyle = { - transform: [ - { - translateY: initInterp.interpolate({ - inputRange: [0, 1], - outputRange: [winHeight, 0], - }), - }, - ], - } + }, [open, t.name]) - // rendering - // = - - if (!state) { + if (!open) { return null } return ( - - + diff --git a/src/view/shell/index.web.tsx b/src/view/shell/index.web.tsx index bfce0729d2..62dec9bcf7 100644 --- a/src/view/shell/index.web.tsx +++ b/src/view/shell/index.web.tsx @@ -64,7 +64,7 @@ function ShellInner() { - + From 2f61c0a7b4ab735bf7ace70aa85ffc09206388e1 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Thu, 4 Jun 2026 16:51:34 -0500 Subject: [PATCH 02/11] Gate StandardSite subscribe button custom theme on AAA contrast (#10735) Co-authored-by: Claude Opus 4.8 --- src/alf/index.tsx | 8 +- src/alf/util/colorGeneration.test.ts | 38 ++++++++- src/alf/util/colorGeneration.ts | 42 ++++++++++ .../Post/Embed/StandardSiteEmbed/index.tsx | 84 ++++++++++++------- 4 files changed, 141 insertions(+), 31 deletions(-) diff --git a/src/alf/index.tsx b/src/alf/index.tsx index 0cb5ceb3f7..a1a2d8adaa 100644 --- a/src/alf/index.tsx +++ b/src/alf/index.tsx @@ -9,7 +9,12 @@ import { setFontScale as persistFontScale, } from '#/alf/fonts' import {themes} from '#/alf/themes' -import {darken, lighten, rgbToHex} from '#/alf/util/colorGeneration' +import { + contrastRatio, + darken, + lighten, + rgbToHex, +} from '#/alf/util/colorGeneration' import {type Device} from '#/storage' export {type TextStyleProp, type Theme, type ViewStyleProp} from '@bsky.app/alf' @@ -26,6 +31,7 @@ export const utils = { rgbToHex, lighten, darken, + contrastRatio, } export type Alf = { diff --git a/src/alf/util/colorGeneration.test.ts b/src/alf/util/colorGeneration.test.ts index c4a2b0bbb5..8d330201e0 100644 --- a/src/alf/util/colorGeneration.test.ts +++ b/src/alf/util/colorGeneration.test.ts @@ -1,4 +1,10 @@ -import {darken, hexToRgb, lighten, rgbToHex} from './colorGeneration' +import { + contrastRatio, + darken, + hexToRgb, + lighten, + rgbToHex, +} from './colorGeneration' describe('hexToRgb', () => { it('parses 6-digit hex', () => { @@ -92,3 +98,33 @@ describe('lighten / darken', () => { expect(darken('#zzz', 10)).toBe('#zzz') }) }) + +describe('contrastRatio', () => { + it('returns 21 for black on white', () => { + expect(contrastRatio('#000000', '#ffffff')).toBeCloseTo(21, 5) + }) + + it('returns 1 for identical colors', () => { + expect(contrastRatio('#abcdef', '#abcdef')).toBeCloseTo(1, 5) + }) + + it('is symmetric regardless of argument order', () => { + expect(contrastRatio('#123456', '#fedcba')).toBeCloseTo( + contrastRatio('#fedcba', '#123456')!, + 5, + ) + }) + + it('clears AAA large text (4.5:1) for a high-contrast pairing', () => { + expect(contrastRatio('#1d3a5f', '#ffffff')!).toBeGreaterThanOrEqual(4.5) + }) + + it('fails AAA large text (4.5:1) for a low-contrast pairing', () => { + expect(contrastRatio('#777777', '#888888')!).toBeLessThan(4.5) + }) + + it('returns null for invalid hex input', () => { + expect(contrastRatio('not-a-color', '#ffffff')).toBeNull() + expect(contrastRatio('#ffffff', '#zzz')).toBeNull() + }) +}) diff --git a/src/alf/util/colorGeneration.ts b/src/alf/util/colorGeneration.ts index 85659af25f..f3be07d502 100644 --- a/src/alf/util/colorGeneration.ts +++ b/src/alf/util/colorGeneration.ts @@ -72,6 +72,48 @@ export function rgbToHex(r: number, g: number, b: number): string { .slice(1)}` } +/** + * Computes the WCAG contrast ratio between two colors, ranging from 1 (no + * contrast) to 21 (maximum contrast, i.e. black on white). Returns null if + * either argument is not a valid hex color. + * + * @see https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio + */ +export function contrastRatio(hexA: string, hexB: string): number | null { + const rgbA = hexToRgb(hexA) + const rgbB = hexToRgb(hexB) + if (!rgbA || !rgbB) return null + const luminanceA = relativeLuminance(rgbA) + const luminanceB = relativeLuminance(rgbB) + const lighter = Math.max(luminanceA, luminanceB) + const darker = Math.min(luminanceA, luminanceB) + return (lighter + 0.05) / (darker + 0.05) +} + +/** + * Computes the WCAG relative luminance of an RGB color, ranging from 0 (black) + * to 1 (white). + * + * @see https://www.w3.org/TR/WCAG21/#dfn-relative-luminance + */ +function relativeLuminance({ + r, + g, + b, +}: { + r: number + g: number + b: number +}): number { + const toLinear = (channel: number) => { + const normalized = channel / 255 + return normalized <= 0.03928 + ? normalized / 12.92 + : ((normalized + 0.055) / 1.055) ** 2.4 + } + return 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b) +} + function rgbToHsl( r: number, g: number, diff --git a/src/components/Post/Embed/StandardSiteEmbed/index.tsx b/src/components/Post/Embed/StandardSiteEmbed/index.tsx index c7b8abf88c..2c38f3806f 100644 --- a/src/components/Post/Embed/StandardSiteEmbed/index.tsx +++ b/src/components/Post/Embed/StandardSiteEmbed/index.tsx @@ -427,6 +427,26 @@ export function SubscribeButton({ ? l`Subscribe on ${highlightedPublisher.name}` : l`View publication` + /* + * The custom site theme paints the button background with `accent` and the + * text with `accentForeground`. Only honor it when that pairing clears WCAG + * AAA (4.5:1) for large text, which the button's bold label qualifies as. + * Otherwise we fall through to the default `secondary_inverted` styling, + * which is guaranteed to be legible. + */ + const {accentRGB, accentForegroundRGB} = view.source?.theme || {} + let useCustomTheme = false + if (accentRGB && accentForegroundRGB) { + const accent = utils.rgbToHex(accentRGB.r, accentRGB.g, accentRGB.b) + const accentForeground = utils.rgbToHex( + accentForegroundRGB.r, + accentForegroundRGB.g, + accentForegroundRGB.b, + ) + const ratio = utils.contrastRatio(accent, accentForeground) + useCustomTheme = ratio !== null && ratio >= 4.5 + } + if (!view.source) return null const publicationTitle = view.source.title @@ -468,36 +488,42 @@ export function SubscribeButton({ } } + const button = ( + + {highlightedPublisher ? ( + <> + + + + {cta} + + ) : ( + <> + {cta} + + + )} + + ) + + if (!useCustomTheme) { + return button + } + return ( - - - {highlightedPublisher ? ( - <> - - - - {cta} - - ) : ( - <> - {cta} - - - )} - - + {button} ) } From 68da7971806182cb99856c21954836b6facff0a9 Mon Sep 17 00:00:00 2001 From: Spence Pope Date: Thu, 4 Jun 2026 22:19:35 -0400 Subject: [PATCH 03/11] Add OTA fallback for gallery embed (#10734) Co-authored-by: Eric Bailey --- .../Post/Embed/GalleryFallbackEmbed.tsx | 99 +++++++++++++++++++ .../screens/Storybook/GalleryFallback.tsx | 25 +++++ src/view/screens/Storybook/Storybook.tsx | 2 + 3 files changed, 126 insertions(+) create mode 100644 src/components/Post/Embed/GalleryFallbackEmbed.tsx create mode 100644 src/view/screens/Storybook/GalleryFallback.tsx diff --git a/src/components/Post/Embed/GalleryFallbackEmbed.tsx b/src/components/Post/Embed/GalleryFallbackEmbed.tsx new file mode 100644 index 0000000000..38d7e4d013 --- /dev/null +++ b/src/components/Post/Embed/GalleryFallbackEmbed.tsx @@ -0,0 +1,99 @@ +import {Linking, View} from 'react-native' +import {plural} from '@lingui/core/macro' +import {Trans, useLingui} from '@lingui/react/macro' + +import {BSKY_DOWNLOAD_URL} from '#/lib/constants' +import {atoms as a, useTheme} from '#/alf' +import {Button, ButtonText} from '#/components/Button' +import {Sparkle_Stroke2_Corner0_Rounded as Sparkle} from '#/components/icons/Sparkle' +import {Text} from '#/components/Typography' +import {IS_NATIVE} from '#/env' + +/** + * OTA-able fallback that ships to native builds which don't yet know how to + * render the new gallery embed (>4 images, Photos v2). Final copy and visual + * treatment pending design from Darrin/Danielle/Alex. + * + * Native-only per APP-2308 - web builds receive the new gallery support in + * the same release that adds it. + */ +export function GalleryFallbackEmbed({count}: {count?: number}) { + const t = useTheme() + const {t: l} = useLingui() + + const bodyStyle = [ + a.text_sm, + a.text_center, + a.leading_snug, + t.atoms.text_contrast_high, + ] + + return ( + + + + Something new is here + + {count ? ( + + + {plural(count, { + one: 'This post has # photo.', + other: 'This post has # photos.', + })} + + {IS_NATIVE ? ( + + {plural(count, { + one: 'Update your app to see it.', + other: 'Update your app to see them all.', + })} + + ) : ( + + {plural(count, { + one: 'Refresh the page to see it.', + other: 'Refresh the page to see them all.', + })} + + )} + + ) : IS_NATIVE ? ( + + Update your app to see it. + + ) : ( + + Refresh the page to see it. + + )} + {IS_NATIVE && ( + + )} + + ) +} diff --git a/src/view/screens/Storybook/GalleryFallback.tsx b/src/view/screens/Storybook/GalleryFallback.tsx new file mode 100644 index 0000000000..7cca087dba --- /dev/null +++ b/src/view/screens/Storybook/GalleryFallback.tsx @@ -0,0 +1,25 @@ +import {View} from 'react-native' + +import {atoms as a} from '#/alf' +import {GalleryFallbackEmbed} from '#/components/Post/Embed/GalleryFallbackEmbed' +import {H1, H3} from '#/components/Typography' + +export function GalleryFallback() { + return ( + +

Gallery fallback (APP-2308)

+ +

No count

+ + +

1 photo

+ + +

5 photos

+ + +

10 photos

+ +
+ ) +} diff --git a/src/view/screens/Storybook/Storybook.tsx b/src/view/screens/Storybook/Storybook.tsx index 8fb85e8e0a..33c31a9ee6 100644 --- a/src/view/screens/Storybook/Storybook.tsx +++ b/src/view/screens/Storybook/Storybook.tsx @@ -16,6 +16,7 @@ import {Breakpoints} from './Breakpoints' import {Buttons} from './Buttons' import {Dialogs} from './Dialogs' import {Forms} from './Forms' +import {GalleryFallback} from './GalleryFallback' import {Icons} from './Icons' import {Links} from './Links' import {Menus} from './Menus' @@ -120,6 +121,7 @@ export default function Storybook() { + ) break } case Step.GENERATE: { const linkEnabled = joinLink?.enabledStatus === 'enabled' const linkHasChanged = linkEnabled && joinLinkRuleKey !== whoCanJoin header = linkEnabled ? l`Update invite link` : l`Generate invite link` content = ( <> Choose who can join this group chat and how. setWhoCanJoin(value)}> {whoCanJoinOptions.map(option => ( {({selected}) => ( )} ))} ) break } case Step.MANAGE: { const linkEnabled = joinLink?.enabledStatus === 'enabled' const linkDisabled = joinLink?.enabledStatus === 'disabled' const joinLinkURI = joinLink?.code ? `https://bsky.app/c/${joinLink.code}` : 'https://bsky.app/' const createdAt = joinLink ? new Date(joinLink.createdAt) : null const currentOption = whoCanJoinOptions.find( o => o.name === (joinLink ? joinLinkToKey(joinLink) : null), ) ?? whoCanJoinOptions[0] const ownerValue = currentOption?.owner ?? whoCanJoinOptions[0].owner const memberValue = currentOption?.member ?? whoCanJoinOptions[0].member header = linkEnabled ? l`Invite link` : l`Invite link disabled` content = ( <> {joinLinkURI} {createdAt ? ( Created{' '} {i18n.date(createdAt, { dateStyle: 'long', timeStyle: 'short', })} ) : null} {linkEnabled ? ( {isOwner ? ( setStep(Step.GENERATE)}> {ownerValue} ) : ( {memberValue} )} ) : null} {linkEnabled ? ( {isOwner ? ( setStep(Step.CONFIRM_DISABLE)}> Disable ) : null} { control.close(() => { openComposer({ text: joinLinkURI, logContext: 'Other', }) }) }}> Post link { void shareUrl(joinLinkURI) }}> Share ) : ( )} ) break } case Step.CONFIRM_DISABLE: { content = ( <> Disable this invite link? Anyone who has it will no longer be able to join or request to join. You can always create a new one. ) break } } if (!isOwner && (!joinLink || joinLink.enabledStatus === 'disabled')) { header = l`Invite link` content = ( <> There is no invite link for this group chat. ) } return ( { setStep(defaultStep) setWhoCanJoin(defaultWhoCanJoin) }}> {header} } label={l`Group chat invite link dialog`} style={web({maxWidth: 400})}> {content} ) } function joinLinkToKey(joinLink: ChatBskyGroupDefs.JoinLinkView): string { return `${joinLink.joinRule}${joinLink.requireApproval ? ':requireApproval' : ''}` } function keyToJoinLink( key: string, ): Pick { const [joinRule, requireApproval] = key.split(':') return { joinRule, requireApproval: requireApproval === 'requireApproval', } } -#: src/screens/Messages/components/InviteLinkDialog.tsx:179 -msgid "Group chats can only have a maximum of {0}." -msgstr "Group chats can only have a maximum of {0}." +#. placeholder {0}: convo.details.memberLimit +#: src/screens/Messages/components/InviteLinkDialog.tsx:178 +msgid "Group chats can only have a maximum of {0, plural, other {# people}}." +msgstr "Group chats can only have a maximum of {0, plural, other {# people}}." #: src/components/dialogs/SearchablePeopleList.tsx:569 msgid "Group is locked" @@ -5586,7 +5632,7 @@ msgstr "" msgid "Help" msgstr "" -#: src/screens/Onboarding/StepProfile/index.tsx:261 +#: src/screens/Onboarding/StepProfile/index.tsx:262 msgid "Help people know you're not a bot by uploading a picture or creating an avatar." msgstr "" @@ -5759,14 +5805,14 @@ msgstr "" msgid "Hold up! We’re gradually giving access to video, and you’re still waiting in line. Check back soon!" msgstr "" -#: src/screens/Messages/Conversation.tsx:337 +#: src/screens/Messages/Conversation.tsx:362 msgid "Hold your horses! This feature isn't available to you yet. Please check back later." msgstr "Hold your horses! This feature isn't available to you yet. Please check back later." #: src/Navigation.tsx:740 #: src/Navigation.tsx:761 -#: src/view/shell/bottom-bar/BottomBar.tsx:184 -#: src/view/shell/desktop/LeftNav.tsx:666 +#: src/view/shell/bottom-bar/BottomBar.tsx:185 +#: src/view/shell/desktop/LeftNav.tsx:667 #: src/view/shell/Drawer.tsx:443 msgid "Home" msgstr "" @@ -5824,7 +5870,7 @@ msgstr "" msgid "I'm on Bluesky as {0} - come find me! https://bsky.app/download" msgstr "" -#: src/components/Lightbox/Lightbox.web.tsx:242 +#: src/components/Lightbox/Lightbox.web.tsx:246 msgid "If alt text is long, toggles alt text expanded state" msgstr "" @@ -5889,32 +5935,32 @@ msgid "If you're trying to change your handle or email, do so before you deactiv msgstr "" #. Ignore a request to join a chat -#: src/screens/Messages/JoinRequests.tsx:485 +#: src/screens/Messages/JoinRequests.tsx:484 msgctxt "button" msgid "Ignore" msgstr "Ignore" -#: src/screens/Messages/JoinRequests.tsx:479 +#: src/screens/Messages/JoinRequests.tsx:478 msgid "Ignore join request" msgstr "Ignore join request" -#: src/components/images/ImageLayoutGridItem.tsx:93 +#: src/components/images/ImageLayoutGridItem.tsx:96 msgid "Image" msgstr "" #. placeholder {0}: index + 1 -#: src/components/images/Gallery/index.tsx:443 +#: src/components/images/Gallery/index.tsx:451 msgid "Image {0}" msgstr "Image {0}" #. placeholder {0}: index + 1 #. placeholder {1}: imgs.length -#: src/components/Lightbox/Lightbox.web.tsx:257 +#: src/components/Lightbox/Lightbox.web.tsx:261 msgid "Image {0} of {1}" msgstr "" #. placeholder {0}: index + 1 -#: src/components/images/Gallery/index.tsx:428 +#: src/components/images/Gallery/index.tsx:436 msgid "Image {0} of {imageCount}" msgstr "Image {0} of {imageCount}" @@ -5944,12 +5990,12 @@ msgid "Image is unavailable." msgstr "Image is unavailable." #: src/components/Lightbox/chrome/ImageMenu.tsx:73 -#: src/components/Lightbox/Lightbox.web.tsx:261 -#: src/components/Lightbox/Lightbox.web.tsx:269 +#: src/components/Lightbox/Lightbox.web.tsx:265 +#: src/components/Lightbox/Lightbox.web.tsx:273 msgid "Image options" msgstr "Image options" -#: src/components/Lightbox/Lightbox.web.tsx:312 +#: src/components/Lightbox/Lightbox.web.tsx:316 #: src/lib/media/save-image.ios.ts:25 #: src/lib/media/save-image.ts:29 msgid "Image saved" @@ -6075,7 +6121,7 @@ msgstr "" msgid "Invalid 2FA confirmation code." msgstr "" -#: src/components/intents/GroupChatJoinDialog.tsx:126 +#: src/components/intents/GroupChatJoinDialog.tsx:127 msgid "Invalid group chat code." msgstr "Invalid group chat code." @@ -6097,7 +6143,7 @@ msgstr "" msgid "Invalid report subject" msgstr "" -#: src/components/intents/GroupChatJoinDialog.tsx:157 +#: src/components/intents/GroupChatJoinDialog.tsx:158 msgid "Invalid rescind request." msgstr "Invalid rescind request." @@ -6130,10 +6176,10 @@ msgstr "" msgid "Invite friends <0/>" msgstr "" -#: src/screens/Messages/components/InviteLinkDialog.tsx:167 -#: src/screens/Messages/components/InviteLinkDialog.tsx:309 -#: src/screens/Messages/components/InviteLinkDialog.tsx:315 -#: src/screens/Messages/components/InviteLinkDialog.tsx:482 +#: src/screens/Messages/components/InviteLinkDialog.tsx:166 +#: src/screens/Messages/components/InviteLinkDialog.tsx:304 +#: src/screens/Messages/components/InviteLinkDialog.tsx:310 +#: src/screens/Messages/components/InviteLinkDialog.tsx:477 #: src/screens/Messages/components/MessagesListGroupInfoPanel.tsx:148 #: src/screens/Messages/ConversationSettings/index.tsx:490 msgid "Invite link" @@ -6144,7 +6190,7 @@ msgid "Invite link created" msgstr "Invite link created" #: src/components/dms/getSystemMessageInfo.ts:138 -#: src/screens/Messages/components/InviteLinkDialog.tsx:309 +#: src/screens/Messages/components/InviteLinkDialog.tsx:304 msgid "Invite link disabled" msgstr "Invite link disabled" @@ -6194,7 +6240,7 @@ msgid "It's just you right now! Add more people to your starter pack by searchin msgstr "" #. placeholder {0}: videoState.jobId -#: src/view/com/composer/Composer.tsx:2386 +#: src/view/com/composer/Composer.tsx:2452 msgid "Job ID: {0}" msgstr "" @@ -6203,7 +6249,8 @@ msgstr "" msgid "Jobs" msgstr "" -#: src/components/intents/GroupChatJoinDialog.tsx:253 +#: src/components/dms/ChatInvite/Root.tsx:98 +#: src/components/intents/GroupChatJoinDialog.tsx:254 msgid "Join" msgstr "Join" @@ -6215,11 +6262,11 @@ msgid "Join Bluesky" msgstr "" #: src/components/intents/GroupChatJoinDialog.tsx:63 -#: src/components/intents/GroupChatJoinDialog.tsx:415 +#: src/components/intents/GroupChatJoinDialog.tsx:419 msgid "Join group chat" msgstr "Join group chat" -#: src/components/intents/GroupChatJoinDialog.tsx:146 +#: src/components/intents/GroupChatJoinDialog.tsx:147 msgid "Join request rescinded." msgstr "Join request rescinded." @@ -6228,16 +6275,12 @@ msgstr "Join request rescinded." msgid "Join the conversation" msgstr "" -#: src/components/intents/GroupChatJoinDialog.tsx:420 -msgid "Join this group chat" -msgstr "Join this group chat" - #: src/lib/interests.ts:63 msgid "Journalism" msgstr "" -#: src/view/com/composer/Composer.tsx:1324 -#: src/view/com/composer/Composer.tsx:1334 +#: src/view/com/composer/Composer.tsx:1393 +#: src/view/com/composer/Composer.tsx:1403 #: src/view/com/composer/drafts/DraftsButton.tsx:135 msgid "Keep editing" msgstr "" @@ -6538,7 +6581,7 @@ msgstr "" msgid "Linear" msgstr "" -#: src/components/Lightbox/Lightbox.web.tsx:296 +#: src/components/Lightbox/Lightbox.web.tsx:300 msgid "Link copied to clipboard" msgstr "Link copied to clipboard" @@ -6632,7 +6675,7 @@ msgstr "" #: src/view/screens/Lists.tsx:60 #: src/view/screens/Profile.tsx:233 #: src/view/screens/Profile.tsx:241 -#: src/view/shell/desktop/LeftNav.tsx:721 +#: src/view/shell/desktop/LeftNav.tsx:722 #: src/view/shell/Drawer.tsx:548 msgid "Lists" msgstr "" @@ -6900,7 +6943,7 @@ msgstr "" msgid "Message {displayName}" msgstr "Message {displayName}" -#: src/screens/Messages/components/ChatListItem.tsx:325 +#: src/screens/Messages/components/ChatListItem.tsx:330 msgid "Message deleted" msgstr "" @@ -6909,7 +6952,7 @@ msgctxt "toast" msgid "Message deleted" msgstr "" -#: src/components/dms/MessageItem.tsx:522 +#: src/components/dms/MessageItem.tsx:535 msgid "Message failed to send." msgstr "Message failed to send." @@ -6946,11 +6989,11 @@ msgstr "" msgid "Messages" msgstr "" -#: src/components/dms/MessageItem.tsx:621 +#: src/components/dms/MessageItem.tsx:634 msgid "Messages from this person are hidden while they are blocking you." msgstr "Messages from this person are hidden while they are blocking you." -#: src/components/dms/MessageItem.tsx:616 +#: src/components/dms/MessageItem.tsx:629 msgid "Messages from this person are hidden while you are blocking them." msgstr "Messages from this person are hidden while you are blocking them." @@ -7344,7 +7387,7 @@ msgid "New post" msgstr "" #: src/view/com/feeds/FeedPage.tsx:179 -#: src/view/shell/desktop/LeftNav.tsx:597 +#: src/view/shell/desktop/LeftNav.tsx:598 msgctxt "action" msgid "New post" msgstr "" @@ -7479,7 +7522,7 @@ msgstr "" msgid "No media yet" msgstr "" -#: src/screens/Messages/components/ChatListItem.tsx:311 +#: src/screens/Messages/components/ChatListItem.tsx:316 msgid "No messages yet" msgstr "" @@ -7680,8 +7723,8 @@ msgstr "" #: src/screens/Settings/Settings.tsx:197 #: src/screens/Settings/Settings.tsx:200 #: src/view/screens/Notifications.tsx:128 -#: src/view/shell/bottom-bar/BottomBar.tsx:260 -#: src/view/shell/desktop/LeftNav.tsx:686 +#: src/view/shell/bottom-bar/BottomBar.tsx:261 +#: src/view/shell/desktop/LeftNav.tsx:687 #: src/view/shell/Drawer.tsx:496 msgid "Notifications" msgstr "" @@ -7724,7 +7767,7 @@ msgstr "" #: src/components/BotAccountAlert.tsx:52 #: src/components/BotAccountAlert.tsx:57 #: src/components/dms/InitiateChatFlow.tsx:677 -#: src/components/dms/MessageItem.tsx:628 +#: src/components/dms/MessageItem.tsx:641 #: src/screens/Login/PasswordUpdatedForm.tsx:37 #: src/screens/PostThread/components/ThreadItemAnchor.tsx:661 msgid "Okay" @@ -7757,27 +7800,27 @@ msgstr "One of the selected recipients does not allow group chats." msgid "One of the selected recipients has blocked you and cannot be messaged." msgstr "One of the selected recipients has blocked you and cannot be messaged." -#: src/view/com/composer/Composer.tsx:787 +#: src/view/com/composer/Composer.tsx:853 msgid "One or more GIFs is missing alt text." msgstr "" -#: src/view/com/composer/Composer.tsx:784 +#: src/view/com/composer/Composer.tsx:850 msgid "One or more images is missing alt text." msgstr "" -#: src/view/com/composer/SelectMediaButton.tsx:415 +#: src/view/com/composer/SelectMediaButton.tsx:417 msgid "One or more of your selected files are not supported." msgstr "" -#: src/view/com/composer/SelectMediaButton.tsx:438 +#: src/view/com/composer/SelectMediaButton.tsx:440 msgid "One or more of your selected files are too large. Maximum size is {VIDEO_MAX_SIZE_MB} MB." msgstr "One or more of your selected files are too large. Maximum size is {VIDEO_MAX_SIZE_MB} MB." -#: src/view/com/composer/Composer.tsx:589 +#: src/view/com/composer/Composer.tsx:648 msgid "One or more posts are too long to save as a draft. {MAX_DRAFT_GRAPHEME_LENGTH, plural, one {The maximum number of characters is # character.} other {The maximum number of characters is # characters.}}" msgstr "" -#: src/view/com/composer/Composer.tsx:794 +#: src/view/com/composer/Composer.tsx:860 msgid "One or more videos is missing alt text." msgstr "" @@ -7786,6 +7829,14 @@ msgstr "" msgid "Only {0} can reply." msgstr "" +#. Toast shown when adding images would exceed the post gallery cap; only the first N are kept +#. placeholder {0}: result.accepted.length +#. placeholder {1}: next.length +#. placeholder {2}: next.length +#: src/view/com/composer/Composer.tsx:223 +msgid "Only {0} of {1} {2, plural, one {image} other {images}} added; limit is {MAX_GALLERY_IMAGES}" +msgstr "Only {0} of {1} {2, plural, one {image} other {images}} added; limit is {MAX_GALLERY_IMAGES}" + #: src/screens/Messages/JoinRequests.tsx:196 msgid "Only admins can accept join requests." msgstr "Only admins can accept join requests." @@ -7794,7 +7845,7 @@ msgstr "Only admins can accept join requests." msgid "Only admins can ignore join requests." msgstr "Only admins can ignore join requests." -#: src/components/intents/GroupChatJoinDialog.tsx:124 +#: src/components/intents/GroupChatJoinDialog.tsx:125 msgid "Only followers can join this group chat." msgstr "Only followers can join this group chat." @@ -7813,7 +7864,8 @@ msgstr "" msgid "Only people {0} follows can join." msgstr "Only people {0} follows can join." -#: src/components/intents/GroupChatJoinDialog.tsx:268 +#: src/components/dms/ChatInvite/Root.tsx:113 +#: src/components/intents/GroupChatJoinDialog.tsx:269 msgid "Only people the chat owner follows can join" msgstr "Only people the chat owner follows can join" @@ -7834,7 +7886,7 @@ msgstr "" msgid "Oops!" msgstr "" -#: src/screens/Onboarding/StepProfile/index.tsx:310 +#: src/screens/Onboarding/StepProfile/index.tsx:311 msgid "Open avatar creator" msgstr "" @@ -7842,12 +7894,17 @@ msgstr "" msgid "Open camera" msgstr "" +#: src/components/dms/ChatInvite/Root.tsx:85 +#: src/components/intents/GroupChatJoinDialog.tsx:408 +msgid "Open chat" +msgstr "Open chat" + #: src/screens/Messages/ConversationSettings/MemberMenu.tsx:139 msgid "Open chat member options for {displayName}" msgstr "Open chat member options for {displayName}" -#: src/screens/Messages/components/ChatListItem.tsx:486 -#: src/screens/Messages/components/ChatListItem.tsx:490 +#: src/screens/Messages/components/ChatListItem.tsx:491 +#: src/screens/Messages/components/ChatListItem.tsx:495 msgid "Open conversation options" msgstr "" @@ -7861,7 +7918,7 @@ msgstr "" #: src/screens/Messages/components/MessageComposer.tsx:176 #: src/screens/Messages/components/MessageInput.web.tsx:148 -#: src/view/com/composer/Composer.tsx:2026 +#: src/view/com/composer/Composer.tsx:2092 msgid "Open emoji picker" msgstr "" @@ -7882,7 +7939,7 @@ msgstr "" msgid "Open Germ DM" msgstr "" -#: src/components/intents/GroupChatJoinDialog.tsx:399 +#: src/components/intents/GroupChatJoinDialog.tsx:401 msgid "Open group chat" msgstr "Open group chat" @@ -7943,7 +8000,7 @@ msgstr "" msgid "Open system log" msgstr "" -#: src/components/intents/GroupChatJoinDialog.tsx:400 +#: src/components/intents/GroupChatJoinDialog.tsx:402 msgid "Open this group chat" msgstr "Open this group chat" @@ -7968,7 +8025,7 @@ msgstr "" msgid "Opens alt text dialog" msgstr "" -#: src/view/com/composer/photos/OpenCameraBtn.tsx:71 +#: src/view/com/composer/photos/OpenCameraBtn.tsx:70 msgid "Opens camera on device" msgstr "" @@ -7988,10 +8045,10 @@ msgstr "" msgid "Opens device camera" msgstr "" -#. Accessibility hint for button in composer to add images, a video, or a GIF to a post. Maximum number of images that can be selected is currently 4 but may change. -#: src/view/com/composer/SelectMediaButton.tsx:509 -msgid "Opens device gallery to select up to {MAX_IMAGES, plural, other {# images}}, or a single video or GIF." -msgstr "" +#. Accessibility hint for button in composer to add images, a video, or a GIF to a post. +#: src/view/com/composer/SelectMediaButton.tsx:511 +msgid "Opens device gallery to select up to {MAX_GALLERY_IMAGES, plural, other {# images}}, or a single video or GIF." +msgstr "Opens device gallery to select up to {MAX_GALLERY_IMAGES, plural, other {# images}}, or a single video or GIF." #: src/screens/Messages/JoinRequest.tsx:295 #: src/view/com/auth/SplashScreen.tsx:102 @@ -8005,7 +8062,7 @@ msgstr "" msgid "Opens flow to sign in to your existing Bluesky account" msgstr "" -#: src/components/images/Gallery/index.tsx:444 +#: src/components/images/Gallery/index.tsx:452 msgid "Opens full image" msgstr "Opens full image" @@ -8022,7 +8079,7 @@ msgstr "" msgid "Opens link {0}" msgstr "" -#: src/view/com/util/UserAvatar.tsx:600 +#: src/view/com/util/UserAvatar.tsx:603 msgid "Opens live status dialog" msgstr "" @@ -8051,9 +8108,9 @@ msgstr "" msgid "Opens this draft in the composer" msgstr "" -#: src/components/dms/MessageItem.tsx:229 +#: src/components/dms/MessageItem.tsx:233 #: src/view/com/notifications/NotificationFeedItem.tsx:1019 -#: src/view/com/util/UserAvatar.tsx:618 +#: src/view/com/util/UserAvatar.tsx:621 msgid "Opens this profile" msgstr "" @@ -8197,11 +8254,11 @@ msgstr "" msgid "People" msgstr "" -#: src/screens/Messages/components/InviteLinkDialog.tsx:154 +#: src/screens/Messages/components/InviteLinkDialog.tsx:153 msgid "People {ownerName} follows can join instantly" msgstr "People {ownerName} follows can join instantly" -#: src/screens/Messages/components/InviteLinkDialog.tsx:159 +#: src/screens/Messages/components/InviteLinkDialog.tsx:158 msgid "People {ownerName} follows can request to join" msgstr "People {ownerName} follows can request to join" @@ -8220,11 +8277,11 @@ msgstr "" msgid "People I follow" msgstr "" -#: src/screens/Messages/components/InviteLinkDialog.tsx:153 +#: src/screens/Messages/components/InviteLinkDialog.tsx:152 msgid "People I follow can join instantly" msgstr "People I follow can join instantly" -#: src/screens/Messages/components/InviteLinkDialog.tsx:158 +#: src/screens/Messages/components/InviteLinkDialog.tsx:157 msgid "People I follow can request to join" msgstr "People I follow can request to join" @@ -8512,7 +8569,7 @@ msgstr "" msgid "Porn" msgstr "" -#: src/view/com/composer/Composer.tsx:1675 +#: src/view/com/composer/Composer.tsx:1740 msgctxt "action" msgid "Post" msgstr "" @@ -8532,12 +8589,12 @@ msgstr "" msgid "Post a video" msgstr "" -#: src/view/com/composer/Composer.tsx:1673 +#: src/view/com/composer/Composer.tsx:1738 msgctxt "action" msgid "Post All" msgstr "" -#: src/view/com/composer/Composer.tsx:1333 +#: src/view/com/composer/Composer.tsx:1402 msgid "Post anyway" msgstr "Post anyway" @@ -8558,7 +8615,7 @@ msgctxt "toast" msgid "Post deleted" msgstr "" -#: src/lib/api/index.ts:186 +#: src/lib/api/index.ts:189 msgid "Post failed to upload. Please check your Internet connection and try again." msgstr "" @@ -8593,8 +8650,8 @@ msgstr "" msgid "Post language selection" msgstr "" -#: src/screens/Messages/components/InviteLinkDialog.tsx:371 -#: src/screens/Messages/components/InviteLinkDialog.tsx:383 +#: src/screens/Messages/components/InviteLinkDialog.tsx:366 +#: src/screens/Messages/components/InviteLinkDialog.tsx:378 msgid "Post link" msgstr "Post link" @@ -8710,15 +8767,15 @@ msgstr "" msgid "Privacy violation of a minor" msgstr "" -#: src/view/com/composer/Composer.tsx:2460 +#: src/view/com/composer/Composer.tsx:2526 msgid "Processing GIF..." msgstr "" -#: src/view/com/composer/Composer.tsx:2462 +#: src/view/com/composer/Composer.tsx:2528 msgid "Processing video..." msgstr "" -#: src/lib/api/index.ts:60 +#: src/lib/api/index.ts:62 msgid "Processing..." msgstr "" @@ -8726,8 +8783,8 @@ msgstr "" msgid "profile" msgstr "" -#: src/view/shell/bottom-bar/BottomBar.tsx:303 -#: src/view/shell/desktop/LeftNav.tsx:744 +#: src/view/shell/bottom-bar/BottomBar.tsx:304 +#: src/view/shell/desktop/LeftNav.tsx:745 #: src/view/shell/Drawer.tsx:80 #: src/view/shell/Drawer.tsx:599 msgid "Profile" @@ -8759,22 +8816,22 @@ msgid "Public, sharable lists of users to mute or block in bulk." msgstr "" #. Accessibility label for button to publish a single post -#: src/view/com/composer/Composer.tsx:1659 +#: src/view/com/composer/Composer.tsx:1724 msgid "Publish post" msgstr "" #. Accessibility label for button to publish multiple posts in a thread -#: src/view/com/composer/Composer.tsx:1654 +#: src/view/com/composer/Composer.tsx:1719 msgid "Publish posts" msgstr "" #. Accessibility label for button to publish multiple replies in a thread -#: src/view/com/composer/Composer.tsx:1643 +#: src/view/com/composer/Composer.tsx:1708 msgid "Publish replies" msgstr "" #. Accessibility label for button to publish a single reply -#: src/view/com/composer/Composer.tsx:1648 +#: src/view/com/composer/Composer.tsx:1713 msgid "Publish reply" msgstr "" @@ -8853,11 +8910,11 @@ msgstr "" msgid "Re-attach quote" msgstr "" -#: src/screens/Messages/components/InviteLinkDialog.tsx:401 +#: src/screens/Messages/components/InviteLinkDialog.tsx:396 msgid "Re-enable invite link" msgstr "Re-enable invite link" -#: src/screens/Messages/components/InviteLinkDialog.tsx:408 +#: src/screens/Messages/components/InviteLinkDialog.tsx:403 msgid "Re-enable link" msgstr "Re-enable link" @@ -8961,6 +9018,10 @@ msgstr "" msgid "Reconnect" msgstr "" +#: src/components/Post/Embed/GalleryFallbackEmbed.tsx:80 +msgid "Refresh the page to see it." +msgstr "Refresh the page to see it." + #. Reject a chat request, this opens a menu with options #: src/screens/Messages/components/RequestButtons.tsx:131 msgid "Reject" @@ -9016,17 +9077,17 @@ msgstr "" msgid "Remove all contacts" msgstr "" -#: src/view/com/composer/ExternalEmbedRemoveBtn.tsx:19 +#: src/view/com/composer/ExternalEmbedRemoveBtn.tsx:18 msgid "Remove attachment" msgstr "" -#: src/view/com/util/UserAvatar.tsx:520 #: src/view/com/util/UserAvatar.tsx:523 +#: src/view/com/util/UserAvatar.tsx:526 msgid "Remove Avatar" msgstr "" -#: src/view/com/util/UserBanner.tsx:190 #: src/view/com/util/UserBanner.tsx:193 +#: src/view/com/util/UserBanner.tsx:196 msgid "Remove Banner" msgstr "" @@ -9034,8 +9095,9 @@ msgstr "" msgid "Remove caption file" msgstr "Remove caption file" -#: src/screens/Messages/components/MessageInputEmbed.tsx:192 -#: src/screens/Messages/components/MessageInputEmbed.tsx:248 +#: src/screens/Messages/components/MessageInputEmbed.tsx:234 +#: src/screens/Messages/components/MessageInputEmbed.tsx:289 +#: src/screens/Messages/components/MessageInputEmbed.tsx:355 msgid "Remove embed" msgstr "" @@ -9079,7 +9141,7 @@ msgstr "" msgid "Remove from your feeds?" msgstr "" -#: src/view/com/composer/photos/Gallery.tsx:225 +#: src/view/com/composer/photos/Gallery.tsx:227 msgid "Remove image" msgstr "" @@ -9129,11 +9191,11 @@ msgstr "" msgid "Remove your verification for this account?" msgstr "" -#: src/components/Post/Embed/index.tsx:225 +#: src/components/Post/Embed/index.tsx:244 msgid "Removed by author" msgstr "" -#: src/components/Post/Embed/index.tsx:223 +#: src/components/Post/Embed/index.tsx:242 msgid "Removed by you" msgstr "" @@ -9223,7 +9285,7 @@ msgstr "" msgid "Replies to this post are disabled." msgstr "" -#: src/view/com/composer/Composer.tsx:1671 +#: src/view/com/composer/Composer.tsx:1736 msgctxt "action" msgid "Reply" msgstr "" @@ -9408,14 +9470,10 @@ msgstr "" msgid "Reposts of your reposts" msgstr "" -#: src/components/intents/GroupChatJoinDialog.tsx:414 +#: src/components/intents/GroupChatJoinDialog.tsx:418 msgid "Request access to group chat" msgstr "Request access to group chat" -#: src/components/intents/GroupChatJoinDialog.tsx:419 -msgid "Request access to join this group chat" -msgstr "Request access to join this group chat" - #: src/screens/Messages/JoinRequests.tsx:178 msgid "Request approved." msgstr "Request approved." @@ -9429,10 +9487,15 @@ msgstr "" msgid "Request ignored." msgstr "Request ignored." -#: src/components/intents/GroupChatJoinDialog.tsx:252 +#: src/components/dms/ChatInvite/Root.tsx:98 +#: src/components/intents/GroupChatJoinDialog.tsx:253 msgid "Request to join" msgstr "Request to join" +#: src/components/dms/ChatInvite/Root.tsx:117 +msgid "Requested" +msgstr "Requested" + #. Incoming message requests #: src/screens/Messages/components/InboxRequests.tsx:24 msgid "Requests" @@ -9440,7 +9503,7 @@ msgstr "Requests" #: src/Navigation.tsx:495 #: src/screens/Messages/JoinRequests.tsx:58 -#: src/screens/Messages/JoinRequests.tsx:421 +#: src/screens/Messages/JoinRequests.tsx:420 msgid "Requests to join" msgstr "Requests to join" @@ -9461,7 +9524,7 @@ msgstr "" msgid "Required in your region" msgstr "" -#: src/components/intents/GroupChatJoinDialog.tsx:272 +#: src/components/intents/GroupChatJoinDialog.tsx:273 msgid "Rescind request" msgstr "Rescind request" @@ -9617,28 +9680,28 @@ msgstr "" #: src/screens/SavedFeeds.tsx:124 #: src/screens/SavedFeeds.tsx:311 #: src/screens/SavedFeeds.tsx:315 -#: src/view/com/composer/Composer.tsx:1314 +#: src/view/com/composer/Composer.tsx:1383 #: src/view/com/composer/drafts/DraftsButton.tsx:125 msgid "Save changes" msgstr "" -#: src/view/com/composer/Composer.tsx:1286 +#: src/view/com/composer/Composer.tsx:1355 #: src/view/com/composer/drafts/DraftsButton.tsx:93 msgid "Save changes?" msgstr "" -#: src/view/com/composer/Composer.tsx:1314 +#: src/view/com/composer/Composer.tsx:1383 #: src/view/com/composer/drafts/DraftsButton.tsx:125 msgid "Save draft" msgstr "" -#: src/view/com/composer/Composer.tsx:1288 +#: src/view/com/composer/Composer.tsx:1357 #: src/view/com/composer/drafts/DraftsButton.tsx:95 msgid "Save draft?" msgstr "" #: src/components/Lightbox/chrome/ImageMenu.tsx:99 -#: src/components/MediaPreview.tsx:197 +#: src/components/MediaPreview.tsx:229 #: src/components/Post/Embed/ImageContextMenu.tsx:70 #: src/components/StarterPack/ShareDialog.tsx:144 #: src/components/StarterPack/ShareDialog.tsx:150 @@ -9663,7 +9726,7 @@ msgstr "" msgid "Save to my feeds" msgstr "" -#: src/view/shell/desktop/LeftNav.tsx:731 +#: src/view/shell/desktop/LeftNav.tsx:732 #: src/view/shell/Drawer.tsx:574 msgctxt "link to bookmarks screen" msgid "Saved" @@ -9721,7 +9784,7 @@ msgstr "" #: src/components/forms/SearchInput.tsx:53 #: src/screens/Search/Shell.tsx:362 #: src/screens/Search/Shell.tsx:525 -#: src/view/shell/bottom-bar/BottomBar.tsx:204 +#: src/view/shell/bottom-bar/BottomBar.tsx:205 msgid "Search" msgstr "" @@ -10048,7 +10111,7 @@ msgstr "" msgid "Select your preferred notification channels" msgstr "" -#: src/view/com/composer/SelectMediaButton.tsx:418 +#: src/view/com/composer/SelectMediaButton.tsx:420 msgid "Selecting multiple media types is not supported." msgstr "" @@ -10079,7 +10142,7 @@ msgstr "Send error report" msgid "Send feedback" msgstr "" -#: src/screens/Messages/components/MessageComposer.tsx:284 +#: src/screens/Messages/components/MessageComposer.tsx:288 #: src/screens/Messages/components/MessageInput.web.tsx:225 msgid "Send message" msgstr "" @@ -10157,7 +10220,7 @@ msgstr "" #: src/Navigation.tsx:212 #: src/screens/Settings/Settings.tsx:98 -#: src/view/shell/desktop/LeftNav.tsx:754 +#: src/view/shell/desktop/LeftNav.tsx:755 #: src/view/shell/Drawer.tsx:612 msgid "Settings" msgstr "" @@ -10219,12 +10282,12 @@ msgstr "" msgid "Sexually Suggestive" msgstr "" -#: src/components/MediaPreview.tsx:203 +#: src/components/MediaPreview.tsx:235 #: src/components/Post/Embed/ImageContextMenu.tsx:74 #: src/components/StarterPack/QrCodeDialog.tsx:195 #: src/screens/Hashtag.tsx:130 -#: src/screens/Messages/components/InviteLinkDialog.tsx:387 -#: src/screens/Messages/components/InviteLinkDialog.tsx:394 +#: src/screens/Messages/components/InviteLinkDialog.tsx:382 +#: src/screens/Messages/components/InviteLinkDialog.tsx:389 #: src/screens/StarterPack/StarterPackScreen.tsx:447 #: src/screens/Topic.tsx:90 msgid "Share" @@ -10240,8 +10303,8 @@ msgid "Share author DID" msgstr "" #: src/components/Lightbox/chrome/ImageMenu.tsx:94 -#: src/components/Lightbox/Lightbox.web.tsx:277 -#: src/components/Lightbox/Lightbox.web.tsx:303 +#: src/components/Lightbox/Lightbox.web.tsx:281 +#: src/components/Lightbox/Lightbox.web.tsx:307 msgid "Share image" msgstr "Share image" @@ -10446,10 +10509,10 @@ msgstr "" #: src/view/com/auth/SplashScreen.tsx:124 #: src/view/com/auth/SplashScreen.web.tsx:122 #: src/view/com/auth/SplashScreen.web.tsx:130 -#: src/view/shell/bottom-bar/BottomBar.tsx:342 -#: src/view/shell/bottom-bar/BottomBar.tsx:347 -#: src/view/shell/bottom-bar/BottomBarWeb.tsx:245 +#: src/view/shell/bottom-bar/BottomBar.tsx:343 +#: src/view/shell/bottom-bar/BottomBar.tsx:348 #: src/view/shell/bottom-bar/BottomBarWeb.tsx:250 +#: src/view/shell/bottom-bar/BottomBarWeb.tsx:255 #: src/view/shell/NavSignupCard.tsx:58 #: src/view/shell/NavSignupCard.tsx:63 msgid "Sign in" @@ -10500,9 +10563,9 @@ msgstr "" #: src/screens/SignupQueued.tsx:94 #: src/screens/SignupQueued.tsx:97 #: src/screens/Takendown.tsx:88 -#: src/view/shell/desktop/LeftNav.tsx:226 -#: src/view/shell/desktop/LeftNav.tsx:281 -#: src/view/shell/desktop/LeftNav.tsx:284 +#: src/view/shell/desktop/LeftNav.tsx:227 +#: src/view/shell/desktop/LeftNav.tsx:282 +#: src/view/shell/desktop/LeftNav.tsx:285 msgid "Sign out" msgstr "" @@ -10511,7 +10574,7 @@ msgid "Sign Out" msgstr "" #: src/screens/Settings/Settings.tsx:296 -#: src/view/shell/desktop/LeftNav.tsx:223 +#: src/view/shell/desktop/LeftNav.tsx:224 msgid "Sign out?" msgstr "" @@ -10543,7 +10606,7 @@ msgstr "" msgid "Skip contact sharing and continue to the app" msgstr "" -#: src/view/com/composer/Composer.tsx:1331 +#: src/view/com/composer/Composer.tsx:1400 msgid "Skip empty posts?" msgstr "Skip empty posts?" @@ -10557,7 +10620,7 @@ msgstr "" msgid "Skip to next step" msgstr "" -#: src/components/images/Gallery/index.tsx:427 +#: src/components/images/Gallery/index.tsx:435 msgid "slide" msgstr "slide" @@ -10614,7 +10677,7 @@ msgid "Someone left the group" msgstr "Someone left the group" #. placeholder {0}: reaction.value -#: src/components/dms/MessageItem.tsx:270 +#: src/components/dms/MessageItem.tsx:274 msgid "Someone reacted {0}" msgstr "" @@ -10639,11 +10702,15 @@ msgstr "Someone was removed" msgid "Someone was removed from the group" msgstr "Someone was removed from the group" +#: src/components/Post/Embed/GalleryFallbackEmbed.tsx:48 +msgid "Something new is here" +msgstr "Something new is here" + #: src/components/moderation/ReportDialog/index.tsx:103 msgid "Something wasn't quite right with the data you're trying to report. Please contact support." msgstr "" -#: src/screens/Messages/Conversation.tsx:135 +#: src/screens/Messages/Conversation.tsx:137 #: src/screens/Messages/ConversationSettings/index.tsx:112 #: src/screens/Messages/JoinRequests.tsx:87 msgid "Something went wrong" @@ -10848,13 +10915,13 @@ msgid "Subscribe" msgstr "" #. placeholder {0}: highlightedPublisher.name -#: src/components/Post/Embed/StandardSiteEmbed/index.tsx:426 -#: src/components/Post/Embed/StandardSiteEmbed/index.tsx:435 +#: src/components/Post/Embed/StandardSiteEmbed/index.tsx:427 +#: src/components/Post/Embed/StandardSiteEmbed/index.tsx:456 msgid "Subscribe on {0}" msgstr "Subscribe on {0}" #. placeholder {0}: highlightedPublisher.name -#: src/components/Post/Embed/StandardSiteEmbed/index.tsx:434 +#: src/components/Post/Embed/StandardSiteEmbed/index.tsx:455 msgid "Subscribe to {publicationTitle} on {0}" msgstr "Subscribe to {publicationTitle} on {0}" @@ -10889,7 +10956,7 @@ msgstr "" msgid "Success!" msgstr "" -#: src/components/intents/GroupChatJoinDialog.tsx:100 +#: src/components/intents/GroupChatJoinDialog.tsx:101 msgid "Successfully joined the group chat!" msgstr "Successfully joined the group chat!" @@ -10950,7 +11017,7 @@ msgstr "Suspended accounts cannot participate in chat." #: src/screens/Settings/Settings.tsx:122 #: src/screens/Settings/Settings.tsx:134 #: src/screens/Settings/Settings.tsx:615 -#: src/view/shell/desktop/LeftNav.tsx:261 +#: src/view/shell/desktop/LeftNav.tsx:262 msgid "Switch account" msgstr "" @@ -10959,7 +11026,7 @@ msgid "Switch accounts" msgstr "" #. placeholder {0}: sanitizeHandle( profile?.handle ?? account.handle, '@', ) -#: src/view/shell/desktop/LeftNav.tsx:363 +#: src/view/shell/desktop/LeftNav.tsx:364 msgid "Switch to {0}" msgstr "" @@ -10985,7 +11052,7 @@ msgstr "" msgid "Tap below to allow Bluesky to access your GPS location. We will then use that data to more accurately determine the content and features available in your region." msgstr "" -#: src/components/dms/MessageItem.tsx:567 +#: src/components/dms/MessageItem.tsx:580 msgid "Tap for details" msgstr "Tap for details" @@ -11011,10 +11078,23 @@ msgstr "" msgid "Tap to close context menu" msgstr "" +#: src/components/dms/ChatInvite/Root.tsx:73 +msgid "Tap to copy this invite link" +msgstr "Tap to copy this invite link" + #: src/components/ProgressGuide/Toast.tsx:163 msgid "Tap to dismiss" msgstr "" +#: src/components/dms/ChatInvite/Root.tsx:126 +#: src/components/intents/GroupChatJoinDialog.tsx:424 +msgid "Tap to join this group chat immediately" +msgstr "Tap to join this group chat immediately" + +#: src/components/dms/ChatInvite/Root.tsx:86 +msgid "Tap to open this group chat" +msgstr "Tap to open this group chat" + #: src/components/dms/ReactionsDialog.tsx:196 msgid "Tap to remove" msgstr "Tap to remove" @@ -11024,7 +11104,12 @@ msgstr "Tap to remove" msgid "Tap to remove your {0} reaction" msgstr "Tap to remove your {0} reaction" -#: src/components/dms/MessageItem.tsx:532 +#: src/components/dms/ChatInvite/Root.tsx:125 +#: src/components/intents/GroupChatJoinDialog.tsx:423 +msgid "Tap to request access to join this group chat" +msgstr "Tap to request access to join this group chat" + +#: src/components/dms/MessageItem.tsx:545 msgid "Tap to retry" msgstr "Tap to retry" @@ -11037,7 +11122,7 @@ msgstr "Tap to show {0} reactions" msgid "Tap to show all reactions" msgstr "Tap to show all reactions" -#: src/components/dms/MessageItem.tsx:293 +#: src/components/dms/MessageItem.tsx:297 msgid "Tap to view reactions" msgstr "Tap to view reactions" @@ -11206,7 +11291,7 @@ msgstr "" msgid "The laws in your region require you to verify you're an adult to access certain features. Tap to learn more." msgstr "" -#: src/components/intents/GroupChatJoinDialog.tsx:134 +#: src/components/intents/GroupChatJoinDialog.tsx:135 #: src/screens/Messages/JoinRequests.tsx:201 msgid "The member limit has been reached." msgstr "The member limit has been reached." @@ -11263,7 +11348,7 @@ msgstr "" msgid "There is a limit to how often you can change your birthdate. You may need to wait a day or two before updating it again." msgstr "" -#: src/screens/Messages/components/InviteLinkDialog.tsx:487 +#: src/screens/Messages/components/InviteLinkDialog.tsx:482 msgid "There is no invite link for this group chat." msgstr "There is no invite link for this group chat." @@ -11277,8 +11362,8 @@ msgid "There was a problem loading GIFs. Check your connection and try again." msgstr "There was a problem loading GIFs. Check your connection and try again." #: src/components/contacts/screens/GetContacts.tsx:147 -#: src/components/intents/GroupChatJoinDialog.tsx:118 -#: src/components/intents/GroupChatJoinDialog.tsx:152 +#: src/components/intents/GroupChatJoinDialog.tsx:119 +#: src/components/intents/GroupChatJoinDialog.tsx:153 msgid "There was a problem with your internet connection, please try again" msgstr "" @@ -11435,11 +11520,12 @@ msgstr "" msgid "This chat has ended" msgstr "This chat has ended" -#: src/components/intents/GroupChatJoinDialog.tsx:263 +#: src/components/dms/ChatInvite/Root.tsx:108 +#: src/components/intents/GroupChatJoinDialog.tsx:264 msgid "This chat is full" msgstr "This chat is full" -#: src/screens/Messages/components/ChatListItem.tsx:375 +#: src/screens/Messages/components/ChatListItem.tsx:380 #: src/screens/Messages/components/ChatLocked.tsx:61 msgid "This chat is locked" msgstr "This chat is locked" @@ -11478,11 +11564,11 @@ msgstr "" msgid "This content is not viewable without a Bluesky account." msgstr "" -#: src/components/intents/GroupChatJoinDialog.tsx:120 +#: src/components/intents/GroupChatJoinDialog.tsx:121 msgid "This conversation is locked." msgstr "This conversation is locked." -#: src/screens/Messages/components/ChatListItem.tsx:155 +#: src/screens/Messages/components/ChatListItem.tsx:156 msgid "This conversation is with a deleted or a deactivated account. Press for options" msgstr "" @@ -11532,7 +11618,7 @@ msgstr "" msgid "This handle is reserved. Please try a different one." msgstr "" -#: src/screens/Onboarding/StepProfile/index.tsx:141 +#: src/screens/Onboarding/StepProfile/index.tsx:142 msgid "This image could not be used. Try a different format like .jpg or .png." msgstr "This image could not be used. Try a different format like .jpg or .png." @@ -11540,7 +11626,7 @@ msgstr "This image could not be used. Try a different format like .jpg or .png." msgid "This information is private and not shared with other users." msgstr "" -#: src/components/intents/GroupChatJoinDialog.tsx:130 +#: src/components/intents/GroupChatJoinDialog.tsx:131 msgid "This invite link has been disabled." msgstr "This invite link has been disabled." @@ -11548,7 +11634,7 @@ msgstr "This invite link has been disabled." msgid "This invite link has expired" msgstr "This invite link has expired" -#: src/components/intents/GroupChatJoinDialog.tsx:194 +#: src/components/intents/GroupChatJoinDialog.tsx:195 msgid "This invite link is invalid" msgstr "This invite link is invalid" @@ -11594,13 +11680,13 @@ msgstr "" msgid "This list is empty." msgstr "" -#: src/components/dms/MessageItem.tsx:565 -#: src/components/dms/MessageItem.tsx:594 +#: src/components/dms/MessageItem.tsx:578 +#: src/components/dms/MessageItem.tsx:607 msgid "This message is hidden because this user is blocking you." msgstr "This message is hidden because this user is blocking you." -#: src/components/dms/MessageItem.tsx:564 -#: src/components/dms/MessageItem.tsx:590 +#: src/components/dms/MessageItem.tsx:577 +#: src/components/dms/MessageItem.tsx:603 msgid "This message is hidden because you are blocking this user." msgstr "This message is hidden because you are blocking this user." @@ -11638,7 +11724,7 @@ msgstr "" msgid "This post will be hidden from feeds and threads. This cannot be undone." msgstr "" -#: src/view/com/composer/Composer.tsx:945 +#: src/view/com/composer/Composer.tsx:1013 msgid "This post's author has disabled quote posts." msgstr "" @@ -11980,7 +12066,7 @@ msgstr "" msgid "Unavailable feed information" msgstr "" -#: src/components/dms/MessageItem.tsx:632 +#: src/components/dms/MessageItem.tsx:645 #: src/components/dms/MessagesListBlockedFooter.tsx:97 #: src/components/dms/MessagesListBlockedFooter.tsx:104 #: src/screens/Messages/ConversationSettings/MemberMenu.tsx:222 @@ -12219,11 +12305,11 @@ msgstr "" msgid "Unsubscribed from list" msgstr "" -#: src/view/com/composer/text-input/TextInput.tsx:131 +#: src/view/com/composer/text-input/TextInput.tsx:128 msgid "Unsupported clipboard content" msgstr "Unsupported clipboard content" -#: src/view/com/composer/Composer.tsx:1424 +#: src/view/com/composer/Composer.tsx:1489 msgid "Unsupported video type: {mimeType}" msgstr "" @@ -12236,6 +12322,10 @@ msgstr "" msgid "Update <0>{displayName} in Lists" msgstr "" +#: src/components/Post/Embed/GalleryFallbackEmbed.tsx:93 +msgid "Update app" +msgstr "Update app" + #: src/components/dialogs/EmailDialog/screens/Update.tsx:296 #: src/components/dialogs/EmailDialog/screens/Update.tsx:308 #: src/screens/Settings/AccountSettings.tsx:112 @@ -12243,9 +12333,9 @@ msgstr "" msgid "Update email" msgstr "" -#: src/screens/Messages/components/InviteLinkDialog.tsx:217 -#: src/screens/Messages/components/InviteLinkDialog.tsx:255 -#: src/screens/Messages/components/InviteLinkDialog.tsx:283 +#: src/screens/Messages/components/InviteLinkDialog.tsx:212 +#: src/screens/Messages/components/InviteLinkDialog.tsx:250 +#: src/screens/Messages/components/InviteLinkDialog.tsx:278 msgid "Update invite link" msgstr "Update invite link" @@ -12254,7 +12344,15 @@ msgstr "Update invite link" msgid "Update to {domain}" msgstr "" -#: src/screens/Messages/Conversation.tsx:335 +#: src/components/Post/Embed/GalleryFallbackEmbed.tsx:85 +msgid "Update your app" +msgstr "Update your app" + +#: src/components/Post/Embed/GalleryFallbackEmbed.tsx:76 +msgid "Update your app to see it." +msgstr "Update your app to see it." + +#: src/screens/Messages/Conversation.tsx:360 msgid "Update your app to the latest version to join in!" msgstr "Update your app to the latest version to join in!" @@ -12279,7 +12377,7 @@ msgctxt "toast" msgid "Updating reply visibility failed" msgstr "" -#: src/screens/Onboarding/StepProfile/index.tsx:314 +#: src/screens/Onboarding/StepProfile/index.tsx:315 msgid "Upload a photo instead" msgstr "" @@ -12287,39 +12385,40 @@ msgstr "" msgid "Upload a text file to:" msgstr "" -#: src/view/com/util/UserAvatar.tsx:491 #: src/view/com/util/UserAvatar.tsx:494 -#: src/view/com/util/UserBanner.tsx:161 +#: src/view/com/util/UserAvatar.tsx:497 #: src/view/com/util/UserBanner.tsx:164 +#: src/view/com/util/UserBanner.tsx:167 msgid "Upload from Camera" msgstr "" -#: src/view/com/util/UserAvatar.tsx:508 -#: src/view/com/util/UserBanner.tsx:178 +#: src/view/com/util/UserAvatar.tsx:511 +#: src/view/com/util/UserBanner.tsx:181 msgid "Upload from Files" msgstr "" -#: src/view/com/util/UserAvatar.tsx:502 -#: src/view/com/util/UserAvatar.tsx:506 -#: src/view/com/util/UserBanner.tsx:172 -#: src/view/com/util/UserBanner.tsx:176 +#: src/view/com/util/UserAvatar.tsx:505 +#: src/view/com/util/UserAvatar.tsx:509 +#: src/view/com/util/UserBanner.tsx:175 +#: src/view/com/util/UserBanner.tsx:179 msgid "Upload from Library" msgstr "" -#: src/view/com/composer/Composer.tsx:2453 +#: src/view/com/composer/Composer.tsx:2519 msgid "Uploading GIF..." msgstr "" -#: src/lib/api/index.ts:322 +#: src/lib/api/index.ts:327 +#: src/lib/api/index.ts:354 msgid "Uploading images..." msgstr "" -#: src/lib/api/index.ts:390 -#: src/lib/api/index.ts:414 +#: src/lib/api/index.ts:426 +#: src/lib/api/index.ts:450 msgid "Uploading link thumbnail..." msgstr "" -#: src/view/com/composer/Composer.tsx:2455 +#: src/view/com/composer/Composer.tsx:2521 msgid "Uploading video..." msgstr "" @@ -12608,7 +12707,7 @@ msgstr "" msgid "Video settings" msgstr "" -#: src/view/com/composer/Composer.tsx:2473 +#: src/view/com/composer/Composer.tsx:2539 msgid "Video uploaded" msgstr "" @@ -12621,18 +12720,18 @@ msgstr "" msgid "Videos" msgstr "" -#: src/view/com/composer/SelectMediaButton.tsx:432 +#: src/view/com/composer/SelectMediaButton.tsx:434 msgid "Videos must be less than 3 minutes long." msgstr "" -#: src/view/com/composer/Composer.tsx:1037 +#: src/view/com/composer/Composer.tsx:1106 msgctxt "Action to view the post the user just created" msgid "View" msgstr "" #. placeholder {0}: view.source.title #: src/components/Post/Embed/StandardSiteEmbed/index.tsx:320 -#: src/components/Post/Embed/StandardSiteEmbed/index.tsx:589 +#: src/components/Post/Embed/StandardSiteEmbed/index.tsx:616 msgid "View {0}" msgstr "View {0}" @@ -12661,7 +12760,7 @@ msgstr "View {0}’s profile" msgid "View {displayName}’s profile" msgstr "View {displayName}’s profile" -#: src/components/Post/Embed/StandardSiteEmbed/index.tsx:437 +#: src/components/Post/Embed/StandardSiteEmbed/index.tsx:458 msgid "View {publicationTitle}" msgstr "View {publicationTitle}" @@ -12696,6 +12795,14 @@ msgstr "" msgid "View incoming group chat requests" msgstr "View incoming group chat requests" +#: src/screens/Messages/components/RequestStatus.tsx:54 +msgid "View incoming requests" +msgstr "View incoming requests" + +#: src/screens/Messages/components/RequestStatus.tsx:55 +msgid "View incoming requests to join this group chat" +msgstr "View incoming requests to join this group chat" + #: src/components/moderation/LabelsOnMe.tsx:56 msgid "View information about these labels" msgstr "" @@ -12711,7 +12818,7 @@ msgstr "" msgid "View more trending videos" msgstr "" -#: src/view/com/composer/Composer.tsx:1032 +#: src/view/com/composer/Composer.tsx:1101 msgid "View post" msgstr "" @@ -12729,9 +12836,9 @@ msgid "View profile banner" msgstr "View profile banner" #: src/components/Post/Embed/StandardSiteEmbed/index.tsx:320 -#: src/components/Post/Embed/StandardSiteEmbed/index.tsx:427 -#: src/components/Post/Embed/StandardSiteEmbed/index.tsx:438 -#: src/components/Post/Embed/StandardSiteEmbed/index.tsx:589 +#: src/components/Post/Embed/StandardSiteEmbed/index.tsx:428 +#: src/components/Post/Embed/StandardSiteEmbed/index.tsx:459 +#: src/components/Post/Embed/StandardSiteEmbed/index.tsx:616 msgid "View publication" msgstr "View publication" @@ -12854,7 +12961,7 @@ msgstr "" msgid "We couldn't find any results for that topic." msgstr "" -#: src/screens/Messages/Conversation.tsx:136 +#: src/screens/Messages/Conversation.tsx:138 msgid "We couldn't load this conversation" msgstr "" @@ -13007,7 +13114,7 @@ msgstr "We’re sorry, but your search could not be completed. Please try again msgid "We're sorry, you cannot access this screen at this time." msgstr "" -#: src/view/com/composer/Composer.tsx:943 +#: src/view/com/composer/Composer.tsx:1011 msgid "We're sorry! The post you are replying to has been deleted." msgstr "" @@ -13058,7 +13165,7 @@ msgid "What do you want to call your starter pack?" msgstr "" #: src/view/com/auth/SplashScreen.web.tsx:98 -#: src/view/com/composer/Composer.tsx:1384 +#: src/view/com/composer/Composer.tsx:1453 #: src/view/com/feeds/ComposerPrompt.tsx:193 msgid "What's up?" msgstr "" @@ -13071,7 +13178,7 @@ msgstr "" msgid "Who can interact with this post?" msgstr "" -#: src/screens/Messages/components/InviteLinkDialog.tsx:227 +#: src/screens/Messages/components/InviteLinkDialog.tsx:222 msgid "Who can join this group chat and how" msgstr "Who can join this group chat and how" @@ -13144,7 +13251,7 @@ msgstr "Would you like to block this user and/or leave this conversation?" msgid "Would you like to save this as a draft before viewing your drafts?" msgstr "" -#: src/view/com/composer/Composer.tsx:1302 +#: src/view/com/composer/Composer.tsx:1371 msgid "Would you like to save this as a draft to edit later?" msgstr "" @@ -13153,12 +13260,12 @@ msgstr "" msgid "Write a post" msgstr "" -#: src/view/com/composer/Composer.tsx:1484 +#: src/view/com/composer/Composer.tsx:1549 msgid "Write post" msgstr "" #: src/screens/PostThread/components/ThreadComposePrompt.tsx:91 -#: src/view/com/composer/Composer.tsx:1382 +#: src/view/com/composer/Composer.tsx:1451 msgid "Write your reply" msgstr "" @@ -13224,7 +13331,7 @@ msgid "You are accessing Bluesky from a region that legally requires us to verif msgstr "" #. placeholder {0}: sanitizeHandle(profile.handle, '@') -#: src/components/dms/MessageItem.tsx:605 +#: src/components/dms/MessageItem.tsx:618 msgid "You are blocking {0}" msgstr "You are blocking {0}" @@ -13325,7 +13432,12 @@ msgstr "" msgid "You can now sign in with your new password." msgstr "" -#: src/view/com/composer/Composer.tsx:1307 +#. Toast shown when the user tries to add more images but the post gallery is already at the cap +#: src/view/com/composer/Composer.tsx:212 +msgid "You can only add up to {MAX_GALLERY_IMAGES} images per post" +msgstr "You can only add up to {MAX_GALLERY_IMAGES} images per post" + +#: src/view/com/composer/Composer.tsx:1376 msgid "You can only save drafts up to 1000 characters." msgstr "" @@ -13333,11 +13445,11 @@ msgstr "" msgid "You can only save drafts up to 1000 characters. Would you like to discard this post before viewing your drafts?" msgstr "" -#: src/view/com/composer/SelectMediaButton.tsx:435 +#: src/view/com/composer/SelectMediaButton.tsx:437 msgid "You can only select one GIF at a time." msgstr "" -#: src/view/com/composer/SelectMediaButton.tsx:429 +#: src/view/com/composer/SelectMediaButton.tsx:431 msgid "You can only select one video at a time." msgstr "" @@ -13349,10 +13461,10 @@ msgstr "" msgid "You can read chat history but can’t send new messages." msgstr "You can read chat history but can’t send new messages." -#. Error message for maximum number of images that can be selected to add to a post, currently 4 but may change. -#: src/view/com/composer/SelectMediaButton.tsx:421 -msgid "You can select up to {MAX_IMAGES, plural, other {# images}} in total." -msgstr "" +#. Error message for maximum number of images that can be selected to add to a post. +#: src/view/com/composer/SelectMediaButton.tsx:423 +msgid "You can select up to {MAX_GALLERY_IMAGES, plural, other {# images}} in total." +msgstr "You can select up to {MAX_GALLERY_IMAGES, plural, other {# images}} in total." #: src/components/interstitials/Trending.tsx:132 #: src/components/interstitials/TrendingVideos.tsx:138 @@ -13391,9 +13503,9 @@ msgstr "" msgid "You got here first" msgstr "" -#: src/components/intents/GroupChatJoinDialog.tsx:136 -msgid "You have been removed from this group." -msgstr "You have been removed from this group." +#: src/components/intents/GroupChatJoinDialog.tsx:137 +msgid "You have been previously removed from this group and can’t join it using this link." +msgstr "You have been previously removed from this group and can’t join it using this link." #: src/components/moderation/ModerationDetailsDialog.tsx:77 #: src/lib/moderation/useModerationCauseDescription.ts:58 @@ -13464,7 +13576,7 @@ msgstr "" msgid "You have temporarily reached the limit for video uploads. Please try again later." msgstr "" -#: src/view/com/composer/Composer.tsx:1297 +#: src/view/com/composer/Composer.tsx:1366 msgid "You have unsaved changes to this draft, would you like to save them?" msgstr "" @@ -13534,7 +13646,7 @@ msgstr "" msgid "You must grant access to your photo library to save a QR code" msgstr "" -#: src/view/com/composer/SelectMediaButton.tsx:464 +#: src/view/com/composer/SelectMediaButton.tsx:466 msgid "You need to allow access to your media library." msgstr "" @@ -13552,7 +13664,7 @@ msgid "You probably want to restart the app now." msgstr "" #. placeholder {0}: reaction.value -#: src/components/dms/MessageItem.tsx:263 +#: src/components/dms/MessageItem.tsx:267 msgid "You reacted {0}" msgstr "" @@ -13567,7 +13679,7 @@ msgid "You recently changed your birthdate" msgstr "" #: src/screens/Settings/Settings.tsx:297 -#: src/view/shell/desktop/LeftNav.tsx:224 +#: src/view/shell/desktop/LeftNav.tsx:225 msgid "You will be signed out of all your accounts." msgstr "" @@ -13661,7 +13773,7 @@ msgstr "" msgid "You've reached the end of your feed! Find some more accounts to follow." msgstr "" -#: src/view/com/composer/Composer.tsx:576 +#: src/view/com/composer/Composer.tsx:635 msgid "You've reached the maximum number of drafts" msgstr "" @@ -13817,7 +13929,7 @@ msgstr "" msgid "Your muted words" msgstr "" -#: src/screens/Messages/components/InviteLinkDialog.tsx:189 +#: src/screens/Messages/components/InviteLinkDialog.tsx:184 msgid "Your name, avatar, the name of the group chat, and the number of members will be visible to everyone." msgstr "Your name, avatar, the name of the group chat, and the number of members will be visible to everyone." @@ -13829,11 +13941,11 @@ msgstr "" msgid "Your password must be at least 8 characters long." msgstr "" -#: src/view/com/composer/Composer.tsx:1028 +#: src/view/com/composer/Composer.tsx:1097 msgid "Your post was sent" msgstr "" -#: src/view/com/composer/Composer.tsx:1025 +#: src/view/com/composer/Composer.tsx:1094 msgid "Your posts were sent" msgstr "" @@ -13854,7 +13966,7 @@ msgstr "" msgid "Your profile, posts, feeds, and lists will no longer be visible to other Bluesky users. You can reactivate your account at any time by logging in." msgstr "" -#: src/view/com/composer/Composer.tsx:1027 +#: src/view/com/composer/Composer.tsx:1096 msgid "Your reply was sent" msgstr "" @@ -13867,7 +13979,7 @@ msgstr "" msgid "Your selected interests help us serve you content you care about." msgstr "" -#: src/view/com/composer/Composer.tsx:1332 +#: src/view/com/composer/Composer.tsx:1401 msgid "Your thread has empty posts that will be skipped. The remaining posts will be published as a thread." msgstr "Your thread has empty posts that will be skipped. The remaining posts will be published as a thread." From d3f073b3d29df83cc288ea6bb4ec0e24e22c87b3 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Fri, 5 Jun 2026 16:35:06 +0300 Subject: [PATCH 05/11] [Chat] Request screen tweaks (#10747) --- src/screens/Messages/Inbox.tsx | 45 ++----------------- .../Messages/components/ChatListItem.tsx | 18 ++++---- 2 files changed, 12 insertions(+), 51 deletions(-) diff --git a/src/screens/Messages/Inbox.tsx b/src/screens/Messages/Inbox.tsx index 55d3b0f4d7..59ca05bdba 100644 --- a/src/screens/Messages/Inbox.tsx +++ b/src/screens/Messages/Inbox.tsx @@ -26,10 +26,9 @@ import {useLeftConvos} from '#/state/queries/messages/leave-conversation' import {useListConvosQuery} from '#/state/queries/messages/list-conversations' import {useUpdateAllRead} from '#/state/queries/messages/update-all-read' import {EmptyState} from '#/view/com/util/EmptyState' -import {FAB} from '#/view/com/util/fab/FAB' import {List} from '#/view/com/util/List' import {ChatListLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' -import {atoms as a, useBreakpoints, useTheme, web} from '#/alf' +import {atoms as a, useTheme, web} from '#/alf' import {AgeRestrictedScreen} from '#/components/ageAssurance/AgeRestrictedScreen' import {useAgeAssuranceCopy} from '#/components/ageAssurance/useAgeAssuranceCopy' import {Button, ButtonIcon, ButtonText} from '#/components/Button' @@ -62,8 +61,6 @@ export function MessagesInboxScreen(props: Props) { } export function MessagesInboxScreenInner({}: Props) { - const {gtTablet} = useBreakpoints() - const listConvosQuery = useListConvosQuery({status: 'request'}) const {data} = listConvosQuery @@ -94,21 +91,16 @@ export function MessagesInboxScreenInner({}: Props) { - + Chat requests - {hasUnreadConvos && gtTablet ? ( - - ) : ( - - )} + {hasUnreadConvos ? : } ) @@ -117,14 +109,12 @@ export function MessagesInboxScreenInner({}: Props) { function RequestList({ listConvosQuery, conversations, - hasUnreadConvos, }: { listConvosQuery: UseInfiniteQueryResult< InfiniteData, Error > conversations: ChatBskyConvoDefs.ConvoView[] - hasUnreadConvos: boolean }) { const {t: l} = useLingui() const t = useTheme() @@ -285,7 +275,6 @@ function RequestList({ desktopFixedHeight sideBorders={false} /> - {hasUnreadConvos && } ) } @@ -298,34 +287,6 @@ function renderItem({item}: {item: ChatBskyConvoDefs.ConvoView}) { return } -function MarkAllReadFAB() { - const {t: l} = useLingui() - const t = useTheme() - const {mutate: markAllRead} = useUpdateAllRead('request', { - onMutate: () => { - Toast.show(l`Marked all as read`, { - type: 'success', - }) - }, - onError: () => { - Toast.show(l`Failed to mark all requests as read`, { - type: 'error', - }) - }, - }) - - return ( - markAllRead()} - icon={} - accessibilityRole="button" - accessibilityLabel={l`Mark all as read`} - accessibilityHint="" - /> - ) -} - function MarkAsReadHeaderButton() { const {t: l} = useLingui() const {mutate: markAllRead} = useUpdateAllRead('request', { diff --git a/src/screens/Messages/components/ChatListItem.tsx b/src/screens/Messages/components/ChatListItem.tsx index e8c0b9cc68..142ca4a971 100644 --- a/src/screens/Messages/components/ChatListItem.tsx +++ b/src/screens/Messages/components/ChatListItem.tsx @@ -122,7 +122,7 @@ function DirectChatItem({ }) { const {t: l} = useLingui() const profile = useProfileShadow(convo.primaryMember) - const {isWithinSplitView} = useIsWithinSplitView() + const {isWithinLeftPanel} = useIsWithinSplitView() const moderation = useMemo( () => moderateProfile(profile, moderationOpts), @@ -140,7 +140,7 @@ function DirectChatItem({ avatar={ } @@ -161,7 +161,7 @@ function DirectChatItem({ isBlockedAccount={moderation.blocked} showProfileBadges postAlerts={ - isWithinSplitView ? null : ( + isWithinLeftPanel ? null : ( @@ -205,7 +205,7 @@ function GroupChatItem({ avatar={ } @@ -278,7 +278,7 @@ function BaseChatItem({ const leaveConvoControl = useDialogControl() const {mutate: markAsRead} = useMarkAsReadMutation() const {gtMobile} = useBreakpoints() - const {isWithinSplitView} = useIsWithinSplitView() + const {isWithinLeftPanel} = useIsWithinSplitView() const playHaptic = useHaptics() const queryClient = useQueryClient() @@ -458,7 +458,7 @@ function BaseChatItem({ leftFirst: deleteAction, } - const avatarSize = isWithinSplitView ? 48 : 52 + const avatarSize = isWithinLeftPanel ? 48 : 52 return ( @@ -469,7 +469,7 @@ function BaseChatItem({ // @ts-expect-error web only onFocus={onFocus} onBlur={onMouseLeave} - style={[a.relative, t.atoms.bg, isWithinSplitView && a.mx_sm]}> + style={[a.relative, t.atoms.bg, isWithinLeftPanel && a.mx_sm]}> Date: Fri, 5 Jun 2026 16:38:23 +0300 Subject: [PATCH 06/11] [Chat] Fix stale reactions dialog after removing a reaction (#10743) Co-authored-by: Claude Opus 4.8 (1M context) --- src/components/dms/MessageOverlays.tsx | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/components/dms/MessageOverlays.tsx b/src/components/dms/MessageOverlays.tsx index 41228f2899..2384aad88d 100644 --- a/src/components/dms/MessageOverlays.tsx +++ b/src/components/dms/MessageOverlays.tsx @@ -125,6 +125,22 @@ export function MessageOverlays({children}: {children: React.ReactNode}) { [openDeleteMessage, openReportMessage, openReactions], ) + // `reactionsTarget` is a snapshot from when the dialog was opened. Read the + // live message out of the convo items so optimistic reaction changes (e.g. + // "Tap to remove") are reflected in the dialog without closing it first. + const reactionsMessage = useMemo(() => { + if (!reactionsTarget) return null + for (const item of convo.items) { + if ( + (item.type === 'message' || item.type === 'pending-message') && + item.message.id === reactionsTarget.id + ) { + return item.message + } + } + return reactionsTarget + }, [convo.items, reactionsTarget]) + const reportSubject = reportTarget ? ({ view: 'message', @@ -153,11 +169,11 @@ export function MessageOverlays({children}: {children: React.ReactNode}) { onClose={() => setAfterReportTarget(null)} /> )} - {reactionsTarget && ( + {reactionsMessage && ( setReactionsTarget(null)} /> )} From f81bb6f4942f6321837e5987d5c1dac51666eb35 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Fri, 5 Jun 2026 16:38:48 +0300 Subject: [PATCH 07/11] [Chat] Fix navigation stacking on messages links in split view (#10741) Co-authored-by: Claude Opus 4.8 (1M context) --- src/screens/Messages/ChatList.tsx | 8 ++++++++ src/screens/Messages/components/ChatListItem.tsx | 3 +++ src/screens/Messages/components/InboxRequests.tsx | 4 ++++ 3 files changed, 15 insertions(+) diff --git a/src/screens/Messages/ChatList.tsx b/src/screens/Messages/ChatList.tsx index 83c4b0c004..387fcd2bd1 100644 --- a/src/screens/Messages/ChatList.tsx +++ b/src/screens/Messages/ChatList.tsx @@ -451,6 +451,12 @@ export function Header({ const {gtMobile} = useBreakpoints() const requireEmailVerification = useRequireEmailVerification() const leftConvos = useLeftConvos() + const {isWithinSplitView} = useIsWithinSplitView() + + // In split view, the left column (and this header) stays mounted while the + // right column shows the selected route. Pushing would stack duplicate routes + // on repeated clicks, so navigate instead to dedupe by route + params. + const action = isWithinSplitView ? 'navigate' : 'push' const {data: unreadInboxData, hasNextPage: hasMoreRequests} = useListConvosQuery({ @@ -494,9 +500,11 @@ export function Header({ count={inboxAllConvos.length} more={hasMoreRequests} variant="solid" + action={action} /> From 7d4d7642fdcfe684076dbb4d13f48e36ac470071 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Fri, 5 Jun 2026 16:39:23 +0300 Subject: [PATCH 08/11] [Chat] Sync single-convo cache on chat lock firehose events (#10746) Co-authored-by: Claude Opus 4.8 (1M context) --- .../queries/messages/list-conversations.tsx | 63 +++++-------------- 1 file changed, 15 insertions(+), 48 deletions(-) diff --git a/src/state/queries/messages/list-conversations.tsx b/src/state/queries/messages/list-conversations.tsx index f026e57d33..dadf30bcdf 100644 --- a/src/state/queries/messages/list-conversations.tsx +++ b/src/state/queries/messages/list-conversations.tsx @@ -418,67 +418,34 @@ export function ListConvosProviderInner({ })), ) } else if (ChatBskyConvoDefs.isLogLockConvo(log)) { - queryClient.setQueriesData( - {queryKey: [RQKEY_ROOT]}, - (old?: ConvoListQueryData) => - optimisticUpdate(log.convoId, old, convo => { - if (ChatBskyConvoDefs.isGroupConvo(convo.kind)) { - return { - ...convo, - kind: { - ...convo.kind, - lockStatus: 'locked', - }, - rev: log.rev, - } - } - return { + mutateConvoView(log.convoId, convo => + ChatBskyConvoDefs.isGroupConvo(convo.kind) + ? { ...convo, + kind: {...convo.kind, lockStatus: 'locked'}, rev: log.rev, } - }), + : {...convo, rev: log.rev}, ) } else if (ChatBskyConvoDefs.isLogUnlockConvo(log)) { - queryClient.setQueriesData( - {queryKey: [RQKEY_ROOT]}, - (old?: ConvoListQueryData) => - optimisticUpdate(log.convoId, old, convo => { - if (ChatBskyConvoDefs.isGroupConvo(convo.kind)) { - return { - ...convo, - kind: { - ...convo.kind, - lockStatus: 'unlocked', - }, - rev: log.rev, - } - } - return { + mutateConvoView(log.convoId, convo => + ChatBskyConvoDefs.isGroupConvo(convo.kind) + ? { ...convo, + kind: {...convo.kind, lockStatus: 'unlocked'}, rev: log.rev, } - }), + : {...convo, rev: log.rev}, ) } else if (ChatBskyConvoDefs.isLogLockConvoPermanently(log)) { - queryClient.setQueriesData( - {queryKey: [RQKEY_ROOT]}, - (old?: ConvoListQueryData) => - optimisticUpdate(log.convoId, old, convo => { - if (ChatBskyConvoDefs.isGroupConvo(convo.kind)) { - return { - ...convo, - kind: { - ...convo.kind, - lockStatus: 'locked-permanently', - }, - rev: log.rev, - } - } - return { + mutateConvoView(log.convoId, convo => + ChatBskyConvoDefs.isGroupConvo(convo.kind) + ? { ...convo, + kind: {...convo.kind, lockStatus: 'locked-permanently'}, rev: log.rev, } - }), + : {...convo, rev: log.rev}, ) } else if ( ChatBskyConvoDefs.isLogCreateJoinLink(log) || From 67ed59fbcd85809ac135ae32ec3fa970d6a829ee Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Fri, 5 Jun 2026 18:10:14 +0300 Subject: [PATCH 09/11] Align group invite settings with eligibility logic (#10748) Co-authored-by: Claude Opus 4.8 (1M context) --- src/components/dms/util.ts | 16 +++++++++++ src/screens/Messages/Settings.tsx | 6 ++--- .../Messages/components/ChatListItem.tsx | 2 +- .../queries/messages/actor-declaration.ts | 27 +++++++++++++++---- 4 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/components/dms/util.ts b/src/components/dms/util.ts index 89b9c5b01f..7fe5f91dc3 100644 --- a/src/components/dms/util.ts +++ b/src/components/dms/util.ts @@ -47,6 +47,22 @@ export function canBeAddedToGroup(profile: bsky.profile.AnyProfileView) { } } +/** + * Resolves the effective `allowGroupInvites` value for a chat declaration. + * When unset, group invites follow the general DM preference + * (`allowIncoming`), which itself defaults to `following`. This mirrors the + * `undefined` fallthrough in canBeAddedToGroup, and is the single source of + * truth for both displaying and persisting the setting. + */ +export function resolveAllowGroupInvites( + chat: {allowIncoming?: string; allowGroupInvites?: string} | undefined, +): 'all' | 'none' | 'following' { + return (chat?.allowGroupInvites ?? chat?.allowIncoming ?? 'following') as + | 'all' + | 'none' + | 'following' +} + export function localDateString(date: Date) { // can't use toISOString because it should be in local time const mm = date.getMonth() diff --git a/src/screens/Messages/Settings.tsx b/src/screens/Messages/Settings.tsx index f49311b0da..91d9f879d5 100644 --- a/src/screens/Messages/Settings.tsx +++ b/src/screens/Messages/Settings.tsx @@ -13,6 +13,7 @@ import {AgeRestrictedScreen} from '#/components/ageAssurance/AgeRestrictedScreen import {useAgeAssuranceCopy} from '#/components/ageAssurance/useAgeAssuranceCopy' import * as Dialog from '#/components/Dialog' import {Divider} from '#/components/Divider' +import {resolveAllowGroupInvites} from '#/components/dms/util' import * as Toggle from '#/components/forms/Toggle' import {Bell_Stroke2_Corner0_Rounded as BellIcon} from '#/components/icons/Bell' import {Car_Stroke2_Corner2_Rounded as CarIcon} from '#/components/icons/Car' @@ -199,10 +200,7 @@ export function MessagesSettingsScreenInner({}: Props) { {allowGroupInvitesFromOptions.map(option => ( diff --git a/src/screens/Messages/components/ChatListItem.tsx b/src/screens/Messages/components/ChatListItem.tsx index 1f691290bf..b6d237f17d 100644 --- a/src/screens/Messages/components/ChatListItem.tsx +++ b/src/screens/Messages/components/ChatListItem.tsx @@ -483,7 +483,7 @@ function BaseChatItem({ to={`/messages/${convo.view.id}`} // In split view, this list stays mounted alongside the open convo, // so push would stack duplicate routes on repeated clicks. - action={isWithinSplitView ? 'navigate' : 'push'} + action={isWithinLeftPanel ? 'navigate' : 'push'} label={title} accessibilityHint={accessibilityHint} accessibilityActions={ diff --git a/src/state/queries/messages/actor-declaration.ts b/src/state/queries/messages/actor-declaration.ts index 53b493ab6a..f6cd2d51d5 100644 --- a/src/state/queries/messages/actor-declaration.ts +++ b/src/state/queries/messages/actor-declaration.ts @@ -7,6 +7,7 @@ import {useMutation, useQueryClient} from '@tanstack/react-query' import {logger} from '#/logger' import {useAgent, useSession} from '#/state/session' +import {resolveAllowGroupInvites} from '#/components/dms/util' import {RQKEY as PROFILE_RKEY} from '../profile' export function useUpdateActorDeclaration({ @@ -34,8 +35,12 @@ export function useUpdateActorDeclaration({ update.allowIncoming ?? current?.associated?.chat?.allowIncoming ?? 'following' - const allowGroupInvites = - update.allowGroupInvites ?? current?.associated?.chat?.allowGroupInvites + const allowGroupInvites = resolveAllowGroupInvites({ + allowIncoming, + allowGroupInvites: + update.allowGroupInvites ?? + current?.associated?.chat?.allowGroupInvites, + }) const result = await agent.com.atproto.repo.putRecord({ repo: currentAccount.did, collection: 'chat.bsky.actor.declaration', @@ -43,7 +48,7 @@ export function useUpdateActorDeclaration({ record: { $type: 'chat.bsky.actor.declaration', allowIncoming, - ...(allowGroupInvites && {allowGroupInvites}), + allowGroupInvites, }, }) return result @@ -54,14 +59,26 @@ export function useUpdateActorDeclaration({ PROFILE_RKEY(currentAccount?.did), (old?: AppBskyActorDefs.ProfileViewDetailed) => { if (!old) return old + const allowIncoming = + update.allowIncoming ?? + old.associated?.chat?.allowIncoming ?? + 'following' + // resolve the same concrete value the server will receive, so + // optimistic cache and persisted record stay aligned + const allowGroupInvites = resolveAllowGroupInvites({ + allowIncoming, + allowGroupInvites: + update.allowGroupInvites ?? + old.associated?.chat?.allowGroupInvites, + }) return { ...old, associated: { ...old.associated, chat: { - allowIncoming: 'following', ...old.associated?.chat, - ...update, + allowIncoming, + allowGroupInvites, }, }, } satisfies AppBskyActorDefs.ProfileViewDetailed From f8aae4a192eb81cbe551e0bf10e3f045e114eaee Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Fri, 5 Jun 2026 18:18:27 +0300 Subject: [PATCH 10/11] [Chat] Disable font scaling on fixed-height chat invite cards (#10744) Co-authored-by: Claude Opus 4.8 (1M context) --- src/components/Post/Embed/ChatInviteEmbed.tsx | 2 +- .../Post/Embed/JoinRequestEmbed.tsx | 5 ++- src/components/ProfileBadges.tsx | 12 ++++--- src/components/Typography.tsx | 4 ++- src/components/dms/ChatInvite/Card.tsx | 32 ++++++++++++------- src/components/dms/ChatInvite/Context.tsx | 2 ++ src/components/dms/ChatInvite/JoinButton.tsx | 4 +-- src/components/dms/ChatInvite/Root.tsx | 4 ++- src/components/dms/MessageItemInviteEmbed.tsx | 3 +- .../Messages/components/MessageInputEmbed.tsx | 2 +- 10 files changed, 46 insertions(+), 24 deletions(-) diff --git a/src/components/Post/Embed/ChatInviteEmbed.tsx b/src/components/Post/Embed/ChatInviteEmbed.tsx index f50085426f..387c3cfd9c 100644 --- a/src/components/Post/Embed/ChatInviteEmbed.tsx +++ b/src/components/Post/Embed/ChatInviteEmbed.tsx @@ -23,7 +23,7 @@ export function ChatInviteEmbed({ style?: StyleProp }) { return ( - + ) diff --git a/src/components/Post/Embed/JoinRequestEmbed.tsx b/src/components/Post/Embed/JoinRequestEmbed.tsx index db7ec589bb..e020bb9333 100644 --- a/src/components/Post/Embed/JoinRequestEmbed.tsx +++ b/src/components/Post/Embed/JoinRequestEmbed.tsx @@ -31,7 +31,10 @@ export function JoinRequestEmbed({ if (!resolvedCode) return null return ( - + ) diff --git a/src/components/ProfileBadges.tsx b/src/components/ProfileBadges.tsx index 22c682bbba..cb257e78b6 100644 --- a/src/components/ProfileBadges.tsx +++ b/src/components/ProfileBadges.tsx @@ -31,10 +31,12 @@ export function ProfileBadges({ interactive = false, size, style, + allowFontScaling = true, }: ViewStyleProp & { profile: bsky.profile.AnyProfileView interactive?: boolean size: Size + allowFontScaling?: boolean }) { const shadowed = useProfileShadow(profile) const verification = useSimpleVerificationState({profile}) @@ -48,10 +50,12 @@ export function ProfileBadges({ const isOnTheSmallSide = size === 'xs' || size === 'sm' - const verificationIconWidth = - verificationIconSizes[size] * nativeScaleMultiplier * alfScaleMultiplier - const botIconWidth = - botIconSizes[size] * nativeScaleMultiplier * alfScaleMultiplier + const scaleMultiplier = allowFontScaling + ? nativeScaleMultiplier * alfScaleMultiplier + : 1 + + const verificationIconWidth = verificationIconSizes[size] * scaleMultiplier + const botIconWidth = botIconSizes[size] * scaleMultiplier return ( + numberOfLines={1} + allowFontScaling={!hasFixedHeight}> {preview.name} + numberOfLines={1} + allowFontScaling={!hasFixedHeight}> Group chat + numberOfLines={1} + allowFontScaling={!hasFixedHeight}> {preview.memberCount}/{preview.memberLimit}{' '} + numberOfLines={1} + allowFontScaling={!hasFixedHeight}> - By {ownerDisplayName} + By{' '} + + {ownerDisplayName} + - + + numberOfLines={1} + allowFontScaling={!hasFixedHeight}> {ownerHandle} diff --git a/src/components/dms/ChatInvite/Context.tsx b/src/components/dms/ChatInvite/Context.tsx index 53c7a6cc22..cedcfd8d88 100644 --- a/src/components/dms/ChatInvite/Context.tsx +++ b/src/components/dms/ChatInvite/Context.tsx @@ -32,6 +32,8 @@ export type ChatInviteContextValue = { * preview to act on. */ action: ChatInviteAction | undefined + /** Whether the invite is rendered inside a fixed-height container; when true, text inside disables font scaling so the card doesn't overflow. */ + hasFixedHeight: boolean } const ChatInviteContext = createContext(null) diff --git a/src/components/dms/ChatInvite/JoinButton.tsx b/src/components/dms/ChatInvite/JoinButton.tsx index 0036391b0e..6f3b8c654d 100644 --- a/src/components/dms/ChatInvite/JoinButton.tsx +++ b/src/components/dms/ChatInvite/JoinButton.tsx @@ -17,7 +17,7 @@ export function JoinButton({ onPress?: () => void style?: StyleProp }) { - const {action} = useChatInvite() + const {action, hasFixedHeight} = useChatInvite() if (!action) return null @@ -35,7 +35,7 @@ export function JoinButton({ disabled={action.disabled} style={[a.w_full, style]}> {action.side === 'left' && } - {action.label} + {action.label} {action.side === 'right' && } ) diff --git a/src/components/dms/ChatInvite/Root.tsx b/src/components/dms/ChatInvite/Root.tsx index a9f2c54e3a..a2cfc558ea 100644 --- a/src/components/dms/ChatInvite/Root.tsx +++ b/src/components/dms/ChatInvite/Root.tsx @@ -30,6 +30,7 @@ export function Root({ code, initialPreview, currentConvoId, + hasFixedHeight, children, }: { code: string @@ -40,6 +41,7 @@ export function Root({ * open/join (you're already here). */ currentConvoId?: string + hasFixedHeight: boolean children: React.ReactNode }) { const {hasSession} = useSession() @@ -137,7 +139,7 @@ export function Root({ return ( + value={{code, loading, error: !!error, preview, action, hasFixedHeight}}> {children} ) diff --git a/src/components/dms/MessageItemInviteEmbed.tsx b/src/components/dms/MessageItemInviteEmbed.tsx index 43fd944822..d85e7fd08a 100644 --- a/src/components/dms/MessageItemInviteEmbed.tsx +++ b/src/components/dms/MessageItemInviteEmbed.tsx @@ -74,7 +74,8 @@ let MessageItemInviteEmbed = ({ + currentConvoId={convo.convo.view.id} + hasFixedHeight={false}> diff --git a/src/screens/Messages/components/MessageInputEmbed.tsx b/src/screens/Messages/components/MessageInputEmbed.tsx index a73a6564fb..21503ce8fa 100644 --- a/src/screens/Messages/components/MessageInputEmbed.tsx +++ b/src/screens/Messages/components/MessageInputEmbed.tsx @@ -273,7 +273,7 @@ function MessageInputInviteEmbed({ const {t: l} = useLingui() return ( - + Date: Fri, 5 Jun 2026 12:50:16 -0500 Subject: [PATCH 11/11] Fire embed:standardSite:view from feed viewability, not embed mount (#10736) Co-authored-by: Claude Opus 4.8 --- .../Post/Embed/StandardSiteEmbed/index.tsx | 7 ------- src/view/com/posts/PostFeed.tsx | 13 +++++++++++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/components/Post/Embed/StandardSiteEmbed/index.tsx b/src/components/Post/Embed/StandardSiteEmbed/index.tsx index 2c38f3806f..2bee7da91e 100644 --- a/src/components/Post/Embed/StandardSiteEmbed/index.tsx +++ b/src/components/Post/Embed/StandardSiteEmbed/index.tsx @@ -5,7 +5,6 @@ import {plural} from '@lingui/core/macro' import {useLingui} from '@lingui/react/macro' import {useHaptics} from '#/lib/haptics' -import {useCallOnce} from '#/lib/once' import {shareUrl} from '#/lib/sharing' import {niceDate} from '#/lib/strings/time' import {toNiceDomain} from '#/lib/strings/url-helpers' @@ -104,12 +103,6 @@ export const StandardSiteEmbed = ({ } } - useCallOnce(() => { - if (!preview) { - ax.metric('embed:standardSite:view', {url: view.uri}) - } - })() - if (isStandardPublication) { return ( >(new Set()) const seenPostUrisRef = useRef>(new Set()) + const seenStandardSiteUrisRef = useRef>(new Set()) // Helper to calculate position in feed (count only root posts, not interstitials or thread replies) const getPostPosition = useNonReactiveCallback( @@ -974,6 +977,16 @@ let PostFeed = ({ }) } } + + // Standard site embed view tracking + if ( + AppBskyEmbedExternal.isView(post.embed) && + isStandardSiteEmbed(post.embed.external) && + !seenStandardSiteUrisRef.current.has(post.embed.external.uri) + ) { + seenStandardSiteUrisRef.current.add(post.embed.external.uri) + ax.metric('embed:standardSite:view', {url: post.embed.external.uri}) + } } else if (item.type === 'videoGridRow') { // Track each video in the grid row for (let i = 0; i < item.items.length; i++) {