Playing around

This commit is contained in:
Eric Bailey
2024-12-10 21:09:50 -06:00
parent 4d380a0da1
commit f58a7fafa1
3 changed files with 164 additions and 90 deletions
+1
View File
@@ -76,6 +76,7 @@ export type ButtonProps = Pick<
| 'onHoverOut' | 'onHoverOut'
| 'onPressIn' | 'onPressIn'
| 'onPressOut' | 'onPressOut'
| 'onLayout'
> & > &
AccessibilityProps & AccessibilityProps &
VariantProps & { VariantProps & {
+2 -1
View File
@@ -74,6 +74,7 @@ export function Content({
style={[ style={[
a.flex_1, a.flex_1,
a.justify_center, a.justify_center,
a.z_20,
isIOS && align === 'platform' && a.align_center, isIOS && align === 'platform' && a.align_center,
{minHeight: HEADER_SLOT_SIZE}, {minHeight: HEADER_SLOT_SIZE},
]}> ]}>
@@ -88,7 +89,7 @@ export function Slot({children}: {children?: React.ReactNode}) {
return ( return (
<View <View
style={[ style={[
a.z_50, a.z_10,
{ {
width: HEADER_SLOT_SIZE, width: HEADER_SLOT_SIZE,
}, },
@@ -1,16 +1,20 @@
import {useRef, useState} from 'react'
import {View, Text as RNText} from 'react-native' import {View, Text as RNText} from 'react-native'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {msg, plural, Trans} from '@lingui/macro' import {msg, plural, Trans} from '@lingui/macro'
import {useSafeAreaInsets} from 'react-native-safe-area-context' import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {isWeb} from '#/platform/detection'
import * as Layout from '#/components/Layout' import * as Layout from '#/components/Layout'
import {atoms as a, useTheme, useBreakpoints, web} from '#/alf' import {atoms as a, useTheme, useBreakpoints, web, useGutters} from '#/alf'
import {UserAvatar} from '#/view/com/util/UserAvatar' import {UserAvatar} from '#/view/com/util/UserAvatar'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {Pin_Stroke2_Corner0_Rounded as Pin} from '#/components/icons/Pin' import {Pin_Stroke2_Corner0_Rounded as Pin} from '#/components/icons/Pin'
import {ChevronBottom_Stroke2_Corner0_Rounded as ChevronDown} from '#/components/icons/Chevron' import {ChevronBottom_Stroke2_Corner0_Rounded as ChevronDown} from '#/components/icons/Chevron'
import {Button, ButtonIcon} from '#/components/Button' import {Button, ButtonIcon} from '#/components/Button'
import {sanitizeHandle} from '#/lib/strings/handles' import {sanitizeHandle} from '#/lib/strings/handles'
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
import * as Menu from '#/components/Menu'
export function ProfileSubpageHeader({ export function ProfileSubpageHeader({
title, title,
@@ -27,99 +31,167 @@ export function ProfileSubpageHeader({
const {gtPhone, gtMobile} = useBreakpoints() const {gtPhone, gtMobile} = useBreakpoints()
const {_} = useLingui() const {_} = useLingui()
const {top} = useSafeAreaInsets() const {top} = useSafeAreaInsets()
const [open, setOpen] = useState(false)
const baseGutters = useGutters(['compact'])
const outerSize = useRef({width: 0, height: 0})
const buttonSize = useRef({width: 0, height: 0})
const outerOffset = ((outerSize.current.width - buttonSize.current.width) / 2) - baseGutters.paddingLeft
return ( return (
<Layout.Center <>
style={[t.atoms.bg, a.z_10, {paddingTop: top}, web([a.sticky, a.z_10, {top: 0}])]} {open && !isWeb && (
> <View style={[
<Layout.Header.Outer> a.fixed,
<Layout.Header.BackButton /> a.inset_0,
<Layout.Header.Content align="left"> a.z_40,
<Button { backgroundColor: t.palette.black, opacity: 0.7 },
label={_(msg`Open feed info screen`)} ]} />
style={[ )}
a.justify_start,
{
paddingVertical: 6,
paddingHorizontal: 8,
paddingRight: 12,
},
]}>
{({hovered}) => (
<>
<View
style={[
a.absolute,
a.inset_0,
a.rounded_sm,
a.transition_transform,
t.atoms.bg_contrast_25,
hovered && {
transform: [{scaleX: 1.01}, {scaleY: 1.1}],
},
]}
/>
<View style={[a.flex_1, a.flex_row, a.align_center, a.gap_sm]}> <Layout.Center
{avatar && ( style={[t.atoms.bg, a.z_50, {paddingTop: top}, web([a.sticky, {top: 0}])]}
<UserAvatar size={32} type="algo" avatar={avatar} /> onLayout={({nativeEvent}) => {
)} outerSize.current = {
width: nativeEvent.layout.width,
<View style={[a.flex_1]}> height: nativeEvent.layout.height,
{/* Should roughly matchl Layout.Header.TitleText */} }
<Text }}
style={[ >
a.text_md, <Layout.Header.Outer>
a.font_heavy, <Layout.Header.BackButton />
a.leading_tight, <Layout.Header.Content align="left">
gtMobile && a.text_lg, <Button
]} label={_(msg`Open feed info screen`)}
numberOfLines={2}> style={[
{title} a.justify_start,
</Text> {
{/* Should roughly matchl Layout.Header.SubtitleText */} paddingVertical: 6,
<Text paddingHorizontal: 8,
style={[ paddingRight: 12,
a.flex_1, },
a.text_xs, ]}
a.leading_snug, onPress={() => setOpen(!open)}
t.atoms.text_contrast_medium, onLayout={({nativeEvent}) => {
gtPhone && a.text_sm, buttonSize.current = {
]}> width: nativeEvent.layout.width,
<RNText numberOfLines={1}> height: nativeEvent.layout.height,
<Trans>By {sanitizeHandle(creator.handle, '@')}</Trans> }
</RNText> }}
{' • '} >
<RNText numberOfLines={1}> {({hovered}) => (
{plural(likeCount, { <>
one: '# like', <View
other: '# likes', style={[
})} a.absolute,
</RNText> a.inset_0,
</Text> a.rounded_sm,
a.transition_transform,
t.atoms.bg_contrast_25,
(hovered && !open) && {
transform: [{scaleX: 1.01}, {scaleY: 1.1}],
},
]}
/>
<View
style={[
a.absolute,
a.inset_0,
a.rounded_sm,
a.transition_transform,
a.z_20,
t.atoms.bg_contrast_25,
{
opacity: 0,
},
open && [t.atoms.shadow_lg, {
opacity: 1,
bottom: 'auto',
left: outerOffset * -1,
right: outerOffset * -1,
}]
]}
>
{open && (
<View style={[baseGutters]}>
<View style={[a.flex_row, a.align_center, a.gap_sm]}>
<UserAvatar
type='algo'
size={58}
avatar={avatar}
/>
<View style={[
]}>
<Text style={[a.text_xl, a.font_heavy]}>{title}</Text>
</View>
</View>
</View>
)}
</View> </View>
<ChevronDown <View style={[a.flex_1, a.flex_row, a.align_center, a.gap_sm, open && {
size="md" left: outerOffset * -1,
fill={t.atoms.text_contrast_low.color} }]}>
/> {avatar && (
</View> <UserAvatar size={32} type="algo" avatar={avatar} />
</> )}
)}
</Button>
</Layout.Header.Content>
<Layout.Header.Slot> <View style={[a.flex_1]}>
<Button {/* Should roughly matchl Layout.Header.TitleText */}
label={_(msg`Pin ${title} to your home screen`)} <Text
size="small" style={[
variant="ghost" a.text_md,
shape="square" a.font_heavy,
color="secondary"> a.leading_tight,
<ButtonIcon icon={Pin} size="lg" /> gtMobile && a.text_lg,
</Button> ]}
</Layout.Header.Slot> numberOfLines={2}>
</Layout.Header.Outer> {title}
</Layout.Center> </Text>
{/* Should roughly matchl Layout.Header.SubtitleText */}
<Text
style={[
a.flex_1,
a.text_xs,
a.leading_snug,
t.atoms.text_contrast_medium,
gtPhone && a.text_sm,
]}>
<RNText numberOfLines={1}>
<Trans>By {sanitizeHandle(creator.handle, '@')}</Trans>
</RNText>
{' • '}
<RNText numberOfLines={1}>
{plural(likeCount, {
one: '# like',
other: '# likes',
})}
</RNText>
</Text>
</View>
<ChevronDown
size="md"
fill={t.atoms.text_contrast_low.color}
/>
</View>
</>
)}
</Button>
</Layout.Header.Content>
<Layout.Header.Slot>
<Button
label={_(msg`Pin ${title} to your home screen`)}
size="small"
variant="ghost"
shape="square"
color="secondary">
<ButtonIcon icon={Pin} size="lg" />
</Button>
</Layout.Header.Slot>
</Layout.Header.Outer>
</Layout.Center>
</>
) )
} }