[Lightbox] Add border radius to avatars (#6136)

* Preserve shape in lightbox

* Rename shapes to semantic meanings

It looks like after all I do want to fork based on those.

* Round avatars on the web

* Oops
This commit is contained in:
dan
2024-11-08 02:52:03 +00:00
committed by GitHub
parent 5d0610d419
commit 22dd4947f7
7 changed files with 108 additions and 61 deletions
+1
View File
@@ -64,6 +64,7 @@ let ProfileHeaderShell = ({
height: 1000, height: 1000,
width: 1000, width: 1000,
}, },
type: 'circle-avi',
}, },
], ],
index: 0, index: 0,
@@ -21,4 +21,5 @@ export type ImageSource = {
thumbUri: string thumbUri: string
alt?: string alt?: string
dimensions: Dimensions | null dimensions: Dimensions | null
type: 'image' | 'circle-avi' | 'rect-avi'
} }
@@ -302,6 +302,11 @@ const ImageItem = ({
committedTransform.value = withClampedSpring(finalTransform) committedTransform.value = withClampedSpring(finalTransform)
}) })
const innerStyle = useAnimatedStyle(() => ({
width: '100%',
aspectRatio: imageAspect,
}))
const composedGesture = isScrollViewBeingDragged const composedGesture = isScrollViewBeingDragged
? // If the parent is not at rest, provide a no-op gesture. ? // If the parent is not at rest, provide a no-op gesture.
Gesture.Manual() Gesture.Manual()
@@ -312,6 +317,9 @@ const ImageItem = ({
singleTap, singleTap,
) )
const type = imageSrc.type
const borderRadius =
type === 'circle-avi' ? 1e5 : type === 'rect-avi' ? 20 : 0
return ( return (
<GestureDetector gesture={composedGesture}> <GestureDetector gesture={composedGesture}>
<Animated.View style={imageStyle} renderToHardwareTextureAndroid> <Animated.View style={imageStyle} renderToHardwareTextureAndroid>
@@ -326,7 +334,7 @@ const ImageItem = ({
source={{uri: imageSrc.uri}} source={{uri: imageSrc.uri}}
placeholderContentFit="contain" placeholderContentFit="contain"
placeholder={{uri: imageSrc.thumbUri}} placeholder={{uri: imageSrc.thumbUri}}
style={[styles.image]} style={[innerStyle, {borderRadius}]}
accessibilityLabel={imageSrc.alt} accessibilityLabel={imageSrc.alt}
accessibilityHint="" accessibilityHint=""
accessibilityIgnoresInvertColors accessibilityIgnoresInvertColors
@@ -342,9 +350,7 @@ const styles = StyleSheet.create({
container: { container: {
height: '100%', height: '100%',
overflow: 'hidden', overflow: 'hidden',
}, justifyContent: 'center',
image: {
flex: 1,
}, },
loading: { loading: {
position: 'absolute', position: 'absolute',
@@ -143,6 +143,9 @@ const ImageItem = ({
singleTap, singleTap,
) )
const type = imageSrc.type
const borderRadius =
type === 'circle-avi' ? 1e5 : type === 'rect-avi' ? 20 : 0
return ( return (
<GestureDetector gesture={composedGesture}> <GestureDetector gesture={composedGesture}>
<Animated.ScrollView <Animated.ScrollView
@@ -163,7 +166,7 @@ const ImageItem = ({
source={{uri: imageSrc.uri}} source={{uri: imageSrc.uri}}
placeholderContentFit="contain" placeholderContentFit="contain"
placeholder={{uri: imageSrc.thumbUri}} placeholder={{uri: imageSrc.thumbUri}}
style={animatedStyle} style={[animatedStyle, {borderRadius}]}
accessibilityLabel={imageSrc.alt} accessibilityLabel={imageSrc.alt}
accessibilityHint="" accessibilityHint=""
enableLiveTextInteraction={showControls && !scaled} enableLiveTextInteraction={showControls && !scaled}
+87 -55
View File
@@ -21,13 +21,9 @@ import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {colors, s} from '#/lib/styles' import {colors, s} from '#/lib/styles'
import {useLightbox, useLightboxControls} from '#/state/lightbox' import {useLightbox, useLightboxControls} from '#/state/lightbox'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {ImageSource} from './ImageViewing/@types'
import ImageDefaultHeader from './ImageViewing/components/ImageDefaultHeader' import ImageDefaultHeader from './ImageViewing/components/ImageDefaultHeader'
interface Img {
uri: string
alt?: string
}
export function Lightbox() { export function Lightbox() {
const {activeLightbox} = useLightbox() const {activeLightbox} = useLightbox()
const {closeLightbox} = useLightboxControls() const {closeLightbox} = useLightboxControls()
@@ -54,7 +50,7 @@ function LightboxInner({
initialIndex = 0, initialIndex = 0,
onClose, onClose,
}: { }: {
imgs: Img[] imgs: ImageSource[]
initialIndex: number initialIndex: number
onClose: () => void onClose: () => void
}) { }) {
@@ -101,6 +97,8 @@ function LightboxInner({
return isTabletOrDesktop ? 32 : 24 return isTabletOrDesktop ? 32 : 24
}, [isTabletOrDesktop]) }, [isTabletOrDesktop])
const img = imgs[index]
const isAvi = img.type === 'circle-avi' || img.type === 'rect-avi'
return ( return (
<View style={styles.mask}> <View style={styles.mask}>
<TouchableWithoutFeedback <TouchableWithoutFeedback
@@ -109,55 +107,76 @@ function LightboxInner({
accessibilityLabel={_(msg`Close image viewer`)} accessibilityLabel={_(msg`Close image viewer`)}
accessibilityHint={_(msg`Exits image view`)} accessibilityHint={_(msg`Exits image view`)}
onAccessibilityEscape={onClose}> onAccessibilityEscape={onClose}>
<View style={styles.imageCenterer}> {isAvi ? (
<Image <View style={styles.aviCenterer}>
accessibilityIgnoresInvertColors <img
source={imgs[index]} src={img.uri}
style={styles.image as ImageStyle} // @ts-ignore web-only
accessibilityLabel={imgs[index].alt} style={
accessibilityHint="" {
/> ...styles.avi,
{canGoLeft && ( borderRadius:
<TouchableOpacity img.type === 'circle-avi'
onPress={onPressLeft} ? '50%'
style={[ : img.type === 'rect-avi'
styles.btn, ? '10%'
btnStyle, : 0,
styles.leftBtn, } as ImageStyle
styles.blurredBackground, }
]} alt={img.alt}
accessibilityRole="button" />
accessibilityLabel={_(msg`Previous image`)} </View>
accessibilityHint=""> ) : (
<FontAwesomeIcon <View style={styles.imageCenterer}>
icon="angle-left" <Image
style={styles.icon as FontAwesomeIconStyle} accessibilityIgnoresInvertColors
size={iconSize} source={img}
/> style={styles.image as ImageStyle}
</TouchableOpacity> accessibilityLabel={img.alt}
)} accessibilityHint=""
{canGoRight && ( />
<TouchableOpacity {canGoLeft && (
onPress={onPressRight} <TouchableOpacity
style={[ onPress={onPressLeft}
styles.btn, style={[
btnStyle, styles.btn,
styles.rightBtn, btnStyle,
styles.blurredBackground, styles.leftBtn,
]} styles.blurredBackground,
accessibilityRole="button" ]}
accessibilityLabel={_(msg`Next image`)} accessibilityRole="button"
accessibilityHint=""> accessibilityLabel={_(msg`Previous image`)}
<FontAwesomeIcon accessibilityHint="">
icon="angle-right" <FontAwesomeIcon
style={styles.icon as FontAwesomeIconStyle} icon="angle-left"
size={iconSize} style={styles.icon as FontAwesomeIconStyle}
/> size={iconSize}
</TouchableOpacity> />
)} </TouchableOpacity>
</View> )}
{canGoRight && (
<TouchableOpacity
onPress={onPressRight}
style={[
styles.btn,
btnStyle,
styles.rightBtn,
styles.blurredBackground,
]}
accessibilityRole="button"
accessibilityLabel={_(msg`Next image`)}
accessibilityHint="">
<FontAwesomeIcon
icon="angle-right"
style={styles.icon as FontAwesomeIconStyle}
size={iconSize}
/>
</TouchableOpacity>
)}
</View>
)}
</TouchableWithoutFeedback> </TouchableWithoutFeedback>
{imgs[index].alt ? ( {img.alt ? (
<View style={styles.footer}> <View style={styles.footer}>
<Pressable <Pressable
accessibilityLabel={_(msg`Expand alt text`)} accessibilityLabel={_(msg`Expand alt text`)}
@@ -171,7 +190,7 @@ function LightboxInner({
style={s.white} style={s.white}
numberOfLines={isAltExpanded ? 0 : 3} numberOfLines={isAltExpanded ? 0 : 3}
ellipsizeMode="tail"> ellipsizeMode="tail">
{imgs[index].alt} {img.alt}
</Text> </Text>
</Pressable> </Pressable>
</View> </View>
@@ -203,6 +222,19 @@ const styles = StyleSheet.create({
height: '100%', height: '100%',
resizeMode: 'contain', resizeMode: 'contain',
}, },
aviCenterer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
avi: {
// @ts-ignore web-only
maxWidth: `calc(min(400px, 100vw))`,
// @ts-ignore web-only
maxHeight: `calc(min(400px, 100vh))`,
padding: 16,
boxSizing: 'border-box',
},
icon: { icon: {
color: colors.white, color: colors.white,
}, },
@@ -80,6 +80,7 @@ export function ProfileSubpageHeader({
height: 1000, height: 1000,
width: 1000, width: 1000,
}, },
type: 'rect-avi',
}, },
], ],
index: 0, index: 0,
+4 -1
View File
@@ -152,7 +152,10 @@ export function PostEmbeds({
thumbDims: MeasuredDimensions | null, thumbDims: MeasuredDimensions | null,
) => { ) => {
openLightbox({ openLightbox({
images: items, images: items.map(item => ({
...item,
type: 'image',
})),
index, index,
thumbDims, thumbDims,
}) })