Files
bsky-social-app/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx
T
Samuel Newman c33c3b7d1e Alt text for gifs (#3876)
* add alt text dialog

* multiline alt text input

* add pressable alt text badge

* rename `ALT: ` to `Alt text: ` to avoid including old bad ones

* reuse alt text reminder

* reuse alt text reminder in gallery

* add alt text reminder in the dialog itself

* autofocus text input

* reorder components to fix tab order

* fix close btn position
2024-05-06 17:28:38 +01:00

133 lines
3.7 KiB
TypeScript

import React, {useCallback} from 'react'
import {StyleProp, View, ViewStyle} from 'react-native'
import {Image} from 'expo-image'
import {AppBskyEmbedExternal} from '@atproto/api'
import {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {shareUrl} from 'lib/sharing'
import {parseEmbedPlayerFromUrl} from 'lib/strings/embed-player'
import {toNiceDomain} from 'lib/strings/url-helpers'
import {isNative} from 'platform/detection'
import {useExternalEmbedsPrefs} from 'state/preferences'
import {Link} from 'view/com/util/Link'
import {ExternalGifEmbed} from 'view/com/util/post-embeds/ExternalGifEmbed'
import {ExternalPlayer} from 'view/com/util/post-embeds/ExternalPlayerEmbed'
import {GifEmbed} from 'view/com/util/post-embeds/GifEmbed'
import {atoms as a, useTheme} from '#/alf'
import {Text} from '../text/Text'
export const ExternalLinkEmbed = ({
link,
style,
hideAlt,
}: {
link: AppBskyEmbedExternal.ViewExternal
style?: StyleProp<ViewStyle>
hideAlt?: boolean
}) => {
const pal = usePalette('default')
const {isMobile} = useWebMediaQueries()
const externalEmbedPrefs = useExternalEmbedsPrefs()
const embedPlayerParams = React.useMemo(() => {
const params = parseEmbedPlayerFromUrl(link.uri)
if (params && externalEmbedPrefs?.[params.source] !== 'hide') {
return params
}
}, [link.uri, externalEmbedPrefs])
if (embedPlayerParams?.source === 'tenor') {
return <GifEmbed params={embedPlayerParams} link={link} hideAlt={hideAlt} />
}
return (
<View style={[a.flex_col, a.rounded_sm, a.overflow_hidden, a.mt_sm]}>
<LinkWrapper link={link} style={style}>
{link.thumb && !embedPlayerParams ? (
<Image
style={{
aspectRatio: 1.91,
borderTopRightRadius: 6,
borderTopLeftRadius: 6,
}}
source={{uri: link.thumb}}
accessibilityIgnoresInvertColors
/>
) : undefined}
{embedPlayerParams?.isGif ? (
<ExternalGifEmbed link={link} params={embedPlayerParams} />
) : embedPlayerParams ? (
<ExternalPlayer link={link} params={embedPlayerParams} />
) : undefined}
<View
style={[
a.flex_1,
a.py_sm,
{
paddingHorizontal: isMobile ? 10 : 14,
},
]}>
<Text
type="sm"
numberOfLines={1}
style={[pal.textLight, {marginVertical: 2}]}>
{toNiceDomain(link.uri)}
</Text>
{!embedPlayerParams?.isGif && !embedPlayerParams?.dimensions && (
<Text type="lg-bold" numberOfLines={3} style={[pal.text]}>
{link.title || link.uri}
</Text>
)}
{link.description ? (
<Text
type="md"
numberOfLines={link.thumb ? 2 : 4}
style={[pal.text, a.mt_xs]}>
{link.description}
</Text>
) : undefined}
</View>
</LinkWrapper>
</View>
)
}
function LinkWrapper({
link,
style,
children,
}: {
link: AppBskyEmbedExternal.ViewExternal
style?: StyleProp<ViewStyle>
children: React.ReactNode
}) {
const t = useTheme()
const onShareExternal = useCallback(() => {
if (link.uri && isNative) {
shareUrl(link.uri)
}
}, [link.uri])
return (
<Link
asAnchor
anchorNoUnderline
href={link.uri}
style={[
a.flex_1,
a.border,
a.rounded_sm,
t.atoms.border_contrast_medium,
style,
]}
hoverStyle={t.atoms.border_contrast_high}
onLongPress={onShareExternal}>
{children}
</Link>
)
}