diff --git a/src/analytics/metrics/types.ts b/src/analytics/metrics/types.ts
index 6e35ce317d..7c9f1bffb9 100644
--- a/src/analytics/metrics/types.ts
+++ b/src/analytics/metrics/types.ts
@@ -987,6 +987,17 @@ export type Events = {
'share:press:recentDm': {}
'share:press:embed': {}
+ 'embed:standardSite:view': {url: string}
+ 'embed:standardSite:article:press': {url: string}
+ 'embed:standardSite:article:longPress': {url: string}
+ 'embed:standardSite:publication:press': {url: string}
+ 'embed:standardSite:publication:longPress': {url: string}
+ 'embed:standardSite:publicationCta:press': {url: string}
+ 'embed:standardSite:publicationCta:longPress': {url: string}
+ 'embed:standardSite:subscribe:press': {url: string}
+ 'embed:standardSite:subscribe:longPress': {url: string}
+ 'embed:standardSite:authorHandle:press': {handle: string}
+
'thread:click:showOtherReplies': {}
'thread:click:hideReplyForMe': {}
'thread:click:hideReplyForEveryone': {}
diff --git a/src/components/Post/Embed/StandardSiteEmbed/StandardSiteMetaRow.tsx b/src/components/Post/Embed/StandardSiteEmbed/StandardSiteMetaRow.tsx
index 1541acfa0c..a36baf114c 100644
--- a/src/components/Post/Embed/StandardSiteEmbed/StandardSiteMetaRow.tsx
+++ b/src/components/Post/Embed/StandardSiteEmbed/StandardSiteMetaRow.tsx
@@ -16,14 +16,18 @@ import {
isStandardSitePublicationUri,
} from '#/components/Post/Embed/StandardSiteEmbed/utils'
import {Text} from '#/components/Typography'
+import {useAnalytics} from '#/analytics'
export function StandardSiteMetaRow({
+ preview,
type = 'document',
view,
}: {
+ preview?: boolean
type?: 'document' | 'publication'
view: AppBskyEmbedExternal.ViewExternal
}) {
+ const ax = useAnalytics()
const t = useTheme()
const {t: l} = useLingui()
const highlightedPublisher = !!matchStandardSitePublisher(view)
@@ -77,7 +81,15 @@ export function StandardSiteMetaRow({
+ style={[
+ metaTextStyle,
+ preview ? a.pointer_events_none : a.pointer_events_auto,
+ ]}
+ onPress={() => {
+ ax.metric('embed:standardSite:authorHandle:press', {
+ handle: authorProfile.handle,
+ })
+ }}>
@{authorProfile.handle}
diff --git a/src/components/Post/Embed/StandardSiteEmbed/index.tsx b/src/components/Post/Embed/StandardSiteEmbed/index.tsx
index e5294ef90b..7c84834536 100644
--- a/src/components/Post/Embed/StandardSiteEmbed/index.tsx
+++ b/src/components/Post/Embed/StandardSiteEmbed/index.tsx
@@ -5,6 +5,7 @@ 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'
@@ -22,6 +23,7 @@ import {StandardSiteMetaRow} from '#/components/Post/Embed/StandardSiteEmbed/Sta
import {StandardSiteThemeProvider} from '#/components/Post/Embed/StandardSiteEmbed/StandardSiteThemeProvider'
import {isStandardSitePublicationEmbed} from '#/components/Post/Embed/StandardSiteEmbed/utils'
import {Text} from '#/components/Typography'
+import {useAnalytics} from '#/analytics'
import {IS_NATIVE} from '#/env'
export type ThemeColors = {
@@ -35,14 +37,20 @@ const PUBLICATION_AVATAR_STYLE = {
}
export const StandardSiteEmbed = ({
+ preview,
view,
- onOpen,
+ onEmbedInteractionCallback,
style,
}: {
+ /**
+ * Indicates the card is showing the composer
+ */
+ preview?: boolean
view: AppBskyEmbedExternal.ViewExternal
- onOpen?: () => void
+ onEmbedInteractionCallback?: () => void
style?: StyleProp
}) => {
+ const ax = useAnalytics()
const {t: l, i18n} = useLingui()
const t = useTheme()
const playHaptic = useHaptics()
@@ -76,27 +84,51 @@ export const StandardSiteEmbed = ({
onIn: onInteract,
onOut: onInteractOut,
} = useInteractionState()
-
const onPress = () => {
playHaptic('Light')
- onOpen?.()
+ onEmbedInteractionCallback?.()
+ ax.metric('embed:standardSite:article:press', {url: view.uri})
}
-
const onLongPress = () => {
if (view.uri && IS_NATIVE) {
playHaptic('Heavy')
shareUrl(view.uri)
+ ax.metric('embed:standardSite:article:longPress', {url: view.uri})
}
}
+ const onPressPublication = () => {
+ playHaptic('Light')
+ onEmbedInteractionCallback?.()
+ ax.metric('embed:standardSite:publication:press', {
+ url: view.source?.uri || '',
+ })
+ }
+ const onLongPressPublication = () => {
+ if (view.source?.uri && IS_NATIVE) {
+ playHaptic('Heavy')
+ shareUrl(view.source.uri)
+ ax.metric('embed:standardSite:publication:longPress', {
+ url: view.source.uri,
+ })
+ }
+ }
+
+ useCallOnce(() => {
+ if (!preview) {
+ ax.metric('embed:standardSite:view', {url: view.uri})
+ }
+ })()
if (isStandardPublication) {
return (
)
}
@@ -111,6 +143,7 @@ export const StandardSiteEmbed = ({
a.border,
t.atoms.bg,
interacted ? t.atoms.border_contrast_high : t.atoms.border_contrast_low,
+ preview && a.pointer_events_none,
style,
]}>
-
+
)}
@@ -234,11 +267,13 @@ export const StandardSiteEmbed = ({
)}
@@ -247,17 +282,21 @@ export const StandardSiteEmbed = ({
}
export function PublicationCard({
+ preview,
view,
onPress,
onLongPress,
themeColors,
style,
+ onEmbedInteractionCallback,
}: {
+ preview?: boolean
view: AppBskyEmbedExternal.ViewExternal
onPress?: () => void
onLongPress?: () => void
themeColors: ThemeColors
style?: StyleProp
+ onEmbedInteractionCallback?: () => void
}) {
const t = useTheme()
const {t: l} = useLingui()
@@ -330,16 +369,20 @@ export function PublicationCard({
style={[a.text_md, a.font_semi_bold, t.atoms.text]}>
{view.source?.title}
-
+
{gtPhone && (
)}
@@ -356,10 +399,10 @@ export function PublicationCard({
{!gtPhone && (
)}
@@ -369,17 +412,20 @@ export function PublicationCard({
}
export function SubscribeButton({
+ preview,
view,
- onPress,
- onLongPress,
style,
+ onEmbedInteractionCallback,
}: {
+ preview?: boolean
view: AppBskyEmbedExternal.ViewExternal
- onPress?: () => void
- onLongPress?: () => void
style?: StyleProp
+ onEmbedInteractionCallback?: () => void
}) {
+ const ax = useAnalytics()
const {t: l} = useLingui()
+ const playHaptic = useHaptics()
+
const highlightedPublisher = matchStandardSitePublisher(view)
const cta = highlightedPublisher
? l`Subscribe on ${highlightedPublisher.name}`
@@ -396,6 +442,36 @@ export function SubscribeButton({
? l`View ${publicationTitle}`
: l`View publication`
+ const onPress = () => {
+ playHaptic('Light')
+ onEmbedInteractionCallback?.()
+ if (highlightedPublisher) {
+ ax.metric('embed:standardSite:subscribe:press', {
+ url: view.source?.uri || '',
+ })
+ } else {
+ ax.metric('embed:standardSite:publicationCta:press', {
+ url: view.source?.uri || '',
+ })
+ }
+ }
+
+ const onLongPress = () => {
+ if (view.source?.uri && IS_NATIVE) {
+ playHaptic('Heavy')
+ shareUrl(view.source.uri)
+ if (highlightedPublisher) {
+ ax.metric('embed:standardSite:subscribe:longPress', {
+ url: view.source?.uri || '',
+ })
+ } else {
+ ax.metric('embed:standardSite:publicationCta:longPress', {
+ url: view.source?.uri || '',
+ })
+ }
+ }
+ }
+
return (
{highlightedPublisher ? (
@@ -470,17 +550,21 @@ function PublicationIcon({
}
export function PublicationFooter({
+ preview,
view,
themeColors,
onPress,
onLongPress,
interactedOuter,
+ onEmbedInteractionCallback,
}: {
+ preview?: boolean
view: AppBskyEmbedExternal.ViewExternal
themeColors: ThemeColors
onPress?: () => void
onLongPress?: () => void
interactedOuter?: boolean
+ onEmbedInteractionCallback?: () => void
}) {
const t = useTheme()
const {t: l} = useLingui()
@@ -503,8 +587,8 @@ export function PublicationFooter({
a.gap_md,
gtPhone && [a.flex_row, a.gap_sm],
interactedOuter && t.atoms.bg_contrast_25,
- ]}
- testID="publication-embed-footer">
+ preview && a.pointer_events_none,
+ ]}>
{view.source?.title}
-
+
)
diff --git a/src/components/Post/Embed/index.tsx b/src/components/Post/Embed/index.tsx
index 2114904557..054558ad83 100644
--- a/src/components/Post/Embed/index.tsx
+++ b/src/components/Post/Embed/index.tsx
@@ -104,6 +104,7 @@ function MediaEmbed({
activeStyle={[a.mt_sm]}>
diff --git a/src/view/com/composer/ExternalEmbed.tsx b/src/view/com/composer/ExternalEmbed.tsx
index ef58054e07..cc7b983c31 100644
--- a/src/view/com/composer/ExternalEmbed.tsx
+++ b/src/view/com/composer/ExternalEmbed.tsx
@@ -91,6 +91,7 @@ export const ExternalEmbedLink = ({
if (data.view && isStandardSiteEmbed(data.view.external)) {
return (