Playing around
This commit is contained in:
@@ -76,6 +76,7 @@ export type ButtonProps = Pick<
|
|||||||
| 'onHoverOut'
|
| 'onHoverOut'
|
||||||
| 'onPressIn'
|
| 'onPressIn'
|
||||||
| 'onPressOut'
|
| 'onPressOut'
|
||||||
|
| 'onLayout'
|
||||||
> &
|
> &
|
||||||
AccessibilityProps &
|
AccessibilityProps &
|
||||||
VariantProps & {
|
VariantProps & {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user