Mimic image cropping for videos on web

This commit is contained in:
Eric Bailey
2025-01-15 14:00:58 -06:00
parent e01fc2fbaf
commit 0429397867
2 changed files with 67 additions and 36 deletions
@@ -5,7 +5,7 @@ import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {isFirefox} from '#/lib/browser' import {isFirefox} from '#/lib/browser'
import {clamp} from '#/lib/numbers' import {ConstrainedImage} from '#/view/com/util/images/AutoSizedImage'
import { import {
HLSUnsupportedError, HLSUnsupportedError,
VideoEmbedInnerWeb, VideoEmbedInnerWeb,
@@ -18,7 +18,13 @@ import {ErrorBoundary} from '../ErrorBoundary'
import {useActiveVideoWeb} from './ActiveVideoWebContext' import {useActiveVideoWeb} from './ActiveVideoWebContext'
import * as VideoFallback from './VideoEmbedInner/VideoFallback' import * as VideoFallback from './VideoEmbedInner/VideoFallback'
export function VideoEmbed({embed}: {embed: AppBskyEmbedVideo.View}) { export function VideoEmbed({
embed,
crop,
}: {
embed: AppBskyEmbedVideo.View
crop?: 'none' | 'square' | 'constrained'
}) {
const ref = useRef<HTMLDivElement>(null) const ref = useRef<HTMLDivElement>(null)
const {active, setActive, sendPosition, currentActiveView} = const {active, setActive, sendPosition, currentActiveView} =
useActiveVideoWeb() useActiveVideoWeb()
@@ -52,24 +58,25 @@ export function VideoEmbed({embed}: {embed: AppBskyEmbedVideo.View}) {
[key], [key],
) )
let aspectRatio = 16 / 9 let aspectRatio: number | undefined
const dims = embed.aspectRatio
if (embed.aspectRatio) { if (dims) {
const {width, height} = embed.aspectRatio aspectRatio = dims.width / dims.height
// min: 3/1, max: square if (Number.isNaN(aspectRatio)) {
aspectRatio = clamp(width / height, 1 / 1, 3 / 1) aspectRatio = undefined
}
} }
return ( let constrained: number | undefined
<View let max: number | undefined
style={[ if (aspectRatio !== undefined) {
a.w_full, const ratio = 1 / 2 // max of 1:2 ratio in feeds
{aspectRatio}, constrained = Math.max(aspectRatio, ratio)
{backgroundColor: 'black'}, max = Math.max(aspectRatio, 0.25) // max of 1:4 in thread
a.relative, }
a.rounded_md, const cropDisabled = crop === 'none'
a.mt_xs,
]}> const contents = (
<div <div
ref={ref} ref={ref}
style={{display: 'flex', flex: 1, cursor: 'default'}} style={{display: 'flex', flex: 1, cursor: 'default'}}
@@ -88,6 +95,21 @@ export function VideoEmbed({embed}: {embed: AppBskyEmbedVideo.View}) {
</ViewportObserver> </ViewportObserver>
</ErrorBoundary> </ErrorBoundary>
</div> </div>
)
return (
<View style={[a.pt_xs]}>
{cropDisabled ? (
<View style={[a.w_full, a.overflow_hidden, {aspectRatio: max ?? 1}]}>
{contents}
</View>
) : (
<ConstrainedImage
fullBleed={crop === 'square'}
aspectRatio={constrained || 1}>
{contents}
</ConstrainedImage>
)}
</View> </View>
) )
} }
+10 -1
View File
@@ -237,7 +237,16 @@ export function PostEmbeds({
if (AppBskyEmbedVideo.isView(embed)) { if (AppBskyEmbedVideo.isView(embed)) {
return ( return (
<ContentHider modui={moderation?.ui('contentMedia')}> <ContentHider modui={moderation?.ui('contentMedia')}>
<VideoEmbed embed={embed} /> <VideoEmbed
embed={embed}
crop={
viewContext === PostEmbedViewContext.ThreadHighlighted
? 'none'
: viewContext === PostEmbedViewContext.FeedEmbedRecordWithMedia
? 'square'
: 'constrained'
}
/>
</ContentHider> </ContentHider>
) )
} }