Make StandardSiteEmbed peekable (#10866)
This commit is contained in:
@@ -617,11 +617,6 @@
|
|||||||
"count": 3
|
"count": 3
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"src/components/dialogs/InAppBrowserConsent.tsx": {
|
|
||||||
"@typescript-eslint/no-floating-promises": {
|
|
||||||
"count": 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"src/components/dialogs/LanguageSelectDialog.tsx": {
|
"src/components/dialogs/LanguageSelectDialog.tsx": {
|
||||||
"@typescript-eslint/no-explicit-any": {
|
"@typescript-eslint/no-explicit-any": {
|
||||||
"count": 1
|
"count": 1
|
||||||
@@ -629,7 +624,7 @@
|
|||||||
},
|
},
|
||||||
"src/components/dialogs/LinkWarning.tsx": {
|
"src/components/dialogs/LinkWarning.tsx": {
|
||||||
"@typescript-eslint/no-floating-promises": {
|
"@typescript-eslint/no-floating-promises": {
|
||||||
"count": 2
|
"count": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"src/components/dialogs/MutedWords.tsx": {
|
"src/components/dialogs/MutedWords.tsx": {
|
||||||
@@ -848,11 +843,6 @@
|
|||||||
"count": 1
|
"count": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"src/features/liveNow/components/LiveStatusDialog.tsx": {
|
|
||||||
"@typescript-eslint/no-floating-promises": {
|
|
||||||
"count": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"src/features/liveNow/index.tsx": {
|
"src/features/liveNow/index.tsx": {
|
||||||
"@typescript-eslint/no-explicit-any": {
|
"@typescript-eslint/no-explicit-any": {
|
||||||
"count": 3
|
"count": 3
|
||||||
@@ -975,14 +965,6 @@
|
|||||||
"count": 4
|
"count": 4
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"src/lib/hooks/useOpenLink.ts": {
|
|
||||||
"@typescript-eslint/no-floating-promises": {
|
|
||||||
"count": 2
|
|
||||||
},
|
|
||||||
"@typescript-eslint/require-await": {
|
|
||||||
"count": 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"src/lib/hooks/usePermissions.ts": {
|
"src/lib/hooks/usePermissions.ts": {
|
||||||
"@typescript-eslint/no-misused-promises": {
|
"@typescript-eslint/no-misused-promises": {
|
||||||
"count": 1
|
"count": 1
|
||||||
@@ -2394,9 +2376,6 @@
|
|||||||
"src/view/com/util/Link.tsx": {
|
"src/view/com/util/Link.tsx": {
|
||||||
"@typescript-eslint/no-explicit-any": {
|
"@typescript-eslint/no-explicit-any": {
|
||||||
"count": 2
|
"count": 2
|
||||||
},
|
|
||||||
"@typescript-eslint/no-misused-promises": {
|
|
||||||
"count": 2
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"src/view/com/util/LoadingPlaceholder.tsx": {
|
"src/view/com/util/LoadingPlaceholder.tsx": {
|
||||||
|
|||||||
@@ -127,7 +127,6 @@ export const StandardSiteEmbed = ({
|
|||||||
style={[
|
style={[
|
||||||
a.flex_col,
|
a.flex_col,
|
||||||
a.rounded_lg,
|
a.rounded_lg,
|
||||||
a.overflow_hidden,
|
|
||||||
a.w_full,
|
a.w_full,
|
||||||
a.border,
|
a.border,
|
||||||
t.atoms.bg,
|
t.atoms.bg,
|
||||||
@@ -135,126 +134,149 @@ export const StandardSiteEmbed = ({
|
|||||||
preview && a.pointer_events_none,
|
preview && a.pointer_events_none,
|
||||||
style,
|
style,
|
||||||
]}>
|
]}>
|
||||||
|
{/*
|
||||||
|
* The article is an in-flow `Link` wrapping the content so the iOS peek
|
||||||
|
* menu has something to lift. The publication footer below lives outside
|
||||||
|
* it - it has its own link (to the publication) and Subscribe button, so
|
||||||
|
* it can't be nested inside the article's peek.
|
||||||
|
*/}
|
||||||
<Link
|
<Link
|
||||||
|
peek
|
||||||
shouldProxy
|
shouldProxy
|
||||||
to={view.uri}
|
to={view.uri}
|
||||||
label={view.title || l`Open link to ${niceUrl}`}
|
label={view.title || l`Open link to ${niceUrl}`}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
onLongPress={onLongPress}
|
onLongPress={onLongPress}
|
||||||
style={[a.absolute, a.inset_0, a.z_10]}
|
style={[a.rounded_lg]}
|
||||||
{...web({
|
{...web({
|
||||||
onMouseEnter: onInteract,
|
onMouseEnter: onInteract,
|
||||||
onMouseLeave: onInteractOut,
|
onMouseLeave: onInteractOut,
|
||||||
})}
|
})}
|
||||||
onFocus={onInteract}
|
onFocus={onInteract}
|
||||||
onBlur={onInteractOut}>
|
onBlur={onInteractOut}>
|
||||||
<></>
|
{() => (
|
||||||
</Link>
|
|
||||||
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
a.w_full,
|
|
||||||
a.z_10,
|
|
||||||
a.pointer_events_none,
|
|
||||||
interacted && [t.atoms.bg_contrast_25],
|
|
||||||
]}>
|
|
||||||
{imageUri ? (
|
|
||||||
<Image
|
|
||||||
style={[a.aspect_card]}
|
|
||||||
source={{uri: imageUri}}
|
|
||||||
accessibilityIgnoresInvertColors
|
|
||||||
loading="lazy"
|
|
||||||
useAppleWebpCodec
|
|
||||||
/>
|
|
||||||
) : undefined}
|
|
||||||
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
a.flex_1,
|
|
||||||
a.pt_sm,
|
|
||||||
hasMedia && a.border_t,
|
|
||||||
interacted
|
|
||||||
? t.atoms.border_contrast_high
|
|
||||||
: t.atoms.border_contrast_low,
|
|
||||||
{gap: 3},
|
|
||||||
isStandard && a.pt_md,
|
|
||||||
]}>
|
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
a.pb_xs,
|
a.w_full,
|
||||||
a.px_md,
|
a.overflow_hidden,
|
||||||
{gap: 3},
|
// The container can't clip (overflow_hidden there breaks the peek
|
||||||
isStandard && [{gap: 5}, a.pb_sm],
|
// lift animation), so each half rounds its own outer corners to
|
||||||
|
// match the container border. The article rounds the top, plus the
|
||||||
|
// bottom when there's no footer beneath it.
|
||||||
|
{
|
||||||
|
borderTopLeftRadius: a.rounded_lg.borderRadius,
|
||||||
|
borderTopRightRadius: a.rounded_lg.borderRadius,
|
||||||
|
},
|
||||||
|
!view.source && {
|
||||||
|
borderBottomLeftRadius: a.rounded_lg.borderRadius,
|
||||||
|
borderBottomRightRadius: a.rounded_lg.borderRadius,
|
||||||
|
},
|
||||||
|
interacted ? t.atoms.bg_contrast_25 : t.atoms.bg,
|
||||||
]}>
|
]}>
|
||||||
<Text
|
{imageUri ? (
|
||||||
emoji
|
<Image
|
||||||
numberOfLines={3}
|
style={[a.aspect_card]}
|
||||||
style={[
|
source={{uri: imageUri}}
|
||||||
a.text_md,
|
accessibilityIgnoresInvertColors
|
||||||
a.font_semi_bold,
|
loading="lazy"
|
||||||
a.leading_snug,
|
useAppleWebpCodec
|
||||||
isStandard && [a.text_lg, a.font_bold],
|
/>
|
||||||
]}>
|
|
||||||
{view.title}
|
|
||||||
</Text>
|
|
||||||
{view.description ? (
|
|
||||||
<Text
|
|
||||||
emoji
|
|
||||||
numberOfLines={view.thumb ? 2 : 4}
|
|
||||||
style={[a.text_sm, a.leading_snug]}>
|
|
||||||
{view.description}
|
|
||||||
</Text>
|
|
||||||
) : undefined}
|
) : undefined}
|
||||||
|
|
||||||
{isStandard && (view.createdAt || view.readingTime) && (
|
<View
|
||||||
|
style={[
|
||||||
|
a.flex_1,
|
||||||
|
a.pt_sm,
|
||||||
|
hasMedia && a.border_t,
|
||||||
|
interacted
|
||||||
|
? t.atoms.border_contrast_high
|
||||||
|
: t.atoms.border_contrast_low,
|
||||||
|
{gap: 3},
|
||||||
|
isStandard && a.pt_md,
|
||||||
|
]}>
|
||||||
<View
|
<View
|
||||||
style={[a.flex_row, a.align_center, a.gap_md, {paddingTop: 2}]}>
|
style={[
|
||||||
{view.createdAt && (
|
a.pb_xs,
|
||||||
|
a.px_md,
|
||||||
|
{gap: 3},
|
||||||
|
isStandard && [{gap: 5}, a.pb_sm],
|
||||||
|
]}>
|
||||||
|
<Text
|
||||||
|
emoji
|
||||||
|
numberOfLines={3}
|
||||||
|
style={[
|
||||||
|
a.text_md,
|
||||||
|
a.font_semi_bold,
|
||||||
|
a.leading_snug,
|
||||||
|
isStandard && [a.text_lg, a.font_bold],
|
||||||
|
]}>
|
||||||
|
{view.title}
|
||||||
|
</Text>
|
||||||
|
{view.description ? (
|
||||||
<Text
|
<Text
|
||||||
style={[
|
emoji
|
||||||
a.text_xs,
|
numberOfLines={view.thumb ? 2 : 4}
|
||||||
a.leading_snug,
|
style={[a.text_sm, a.leading_snug]}>
|
||||||
t.atoms.text_contrast_medium,
|
{view.description}
|
||||||
]}>
|
|
||||||
{niceDate(i18n, view.createdAt, 'long', 'none')}
|
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
) : undefined}
|
||||||
{view.readingTime && (
|
|
||||||
<View style={[a.flex_row, a.align_center, a.gap_2xs]}>
|
{isStandard && (view.createdAt || view.readingTime) && (
|
||||||
<Clock size="xs" style={t.atoms.text_contrast_medium} />
|
<View
|
||||||
<Text
|
style={[
|
||||||
style={[
|
a.flex_row,
|
||||||
a.text_xs,
|
a.align_center,
|
||||||
a.leading_snug,
|
a.gap_md,
|
||||||
t.atoms.text_contrast_medium,
|
{paddingTop: 2},
|
||||||
]}>
|
]}>
|
||||||
{l({
|
{view.createdAt && (
|
||||||
message: plural(view.readingTime, {
|
<Text
|
||||||
one: '#m',
|
style={[
|
||||||
other: '#m',
|
a.text_xs,
|
||||||
}),
|
a.leading_snug,
|
||||||
comment: `How long it takes to read an article, in minutes. Displayed in a short form, e.g. "5m" for 5 minutes.`,
|
t.atoms.text_contrast_medium,
|
||||||
})}
|
]}>
|
||||||
</Text>
|
{niceDate(i18n, view.createdAt, 'long', 'none')}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
{view.readingTime && (
|
||||||
|
<View style={[a.flex_row, a.align_center, a.gap_2xs]}>
|
||||||
|
<Clock size="xs" style={t.atoms.text_contrast_medium} />
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
a.text_xs,
|
||||||
|
a.leading_snug,
|
||||||
|
t.atoms.text_contrast_medium,
|
||||||
|
]}>
|
||||||
|
{l({
|
||||||
|
message: plural(view.readingTime, {
|
||||||
|
one: '#m',
|
||||||
|
other: '#m',
|
||||||
|
}),
|
||||||
|
comment: `How long it takes to read an article, in minutes. Displayed in a short form, e.g. "5m" for 5 minutes.`,
|
||||||
|
})}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{!view.source && (
|
||||||
|
<View style={[a.px_md]}>
|
||||||
|
<Divider />
|
||||||
|
<View style={[a.py_sm]}>
|
||||||
|
<StandardSiteMetaRow preview={preview} view={view} />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
|
||||||
|
|
||||||
{!view.source && (
|
|
||||||
<View style={[a.px_md]}>
|
|
||||||
<Divider />
|
|
||||||
<View style={[a.py_sm]}>
|
|
||||||
<StandardSiteMetaRow preview={preview} view={view} />
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
)}
|
)}
|
||||||
</View>
|
</Link>
|
||||||
|
|
||||||
{view.source && (
|
{view.source && (
|
||||||
<View style={[a.z_20]}>
|
<View>
|
||||||
<Divider />
|
<Divider />
|
||||||
<PublicationFooter
|
<PublicationFooter
|
||||||
preview={preview}
|
preview={preview}
|
||||||
@@ -629,6 +651,14 @@ export function PublicationFooter({
|
|||||||
a.justify_between,
|
a.justify_between,
|
||||||
a.p_md,
|
a.p_md,
|
||||||
a.gap_md,
|
a.gap_md,
|
||||||
|
a.overflow_hidden,
|
||||||
|
// Rounds the bottom corners to match the container border, since the
|
||||||
|
// container itself can't clip (overflow_hidden there breaks the peek
|
||||||
|
// lift animation on the article above).
|
||||||
|
{
|
||||||
|
borderBottomLeftRadius: a.rounded_lg.borderRadius,
|
||||||
|
borderBottomRightRadius: a.rounded_lg.borderRadius,
|
||||||
|
},
|
||||||
gtPhone && [a.flex_row, a.gap_sm],
|
gtPhone && [a.flex_row, a.gap_sm],
|
||||||
interactedOuter && t.atoms.bg_contrast_25,
|
interactedOuter && t.atoms.bg_contrast_25,
|
||||||
preview && a.pointer_events_none,
|
preview && a.pointer_events_none,
|
||||||
|
|||||||
@@ -50,10 +50,10 @@ export function useGoogleTranslate() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (__DEV__) console.error(err)
|
if (__DEV__) console.error(err)
|
||||||
// most likely means they don't have the translate app
|
// most likely means they don't have the translate app
|
||||||
await openLink(translateUrl)
|
openLink(translateUrl)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
await openLink(translateUrl)
|
openLink(translateUrl)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[openLink],
|
[openLink],
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export function useOpenLink() {
|
|||||||
const {inAppBrowserConsentControl} = useGlobalDialogsControlContext()
|
const {inAppBrowserConsentControl} = useGlobalDialogsControlContext()
|
||||||
|
|
||||||
const openLink = useCallback(
|
const openLink = useCallback(
|
||||||
async (url: string, override?: boolean, shouldProxy?: boolean) => {
|
(url: string, override?: boolean, shouldProxy?: boolean) => {
|
||||||
if (isBskyRSSUrl(url) && isRelativeUrl(url)) {
|
if (isBskyRSSUrl(url) && isRelativeUrl(url)) {
|
||||||
url = createBskyAppAbsoluteUrl(url)
|
url = createBskyAppAbsoluteUrl(url)
|
||||||
}
|
}
|
||||||
@@ -66,12 +66,12 @@ export function useOpenLink() {
|
|||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
if (__DEV__)
|
if (__DEV__)
|
||||||
logger.error('Could not open web browser', {message: err})
|
logger.error('Could not open web browser', {message: err})
|
||||||
Linking.openURL(url)
|
void Linking.openURL(url)
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Linking.openURL(url)
|
void Linking.openURL(url)
|
||||||
},
|
},
|
||||||
[ax, enabled, inAppBrowserConsentControl, t, dialogContext],
|
[ax, enabled, inAppBrowserConsentControl, t, dialogContext],
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user