[Explore] Design tweaks (#8131)
* Fix interests card spacing * Space out AvatarStack * SP icon size * Visual alignment of tab bar and headers * Tweak spacing around search input * Drop text size in sp card overflow count * Tweak
This commit is contained in:
@@ -19,7 +19,7 @@ export function AvatarStack({
|
|||||||
numPending?: number
|
numPending?: number
|
||||||
backgroundColor?: string
|
backgroundColor?: string
|
||||||
}) {
|
}) {
|
||||||
const halfSize = size / 2
|
const translation = size / 3 // overlap by 1/3
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const moderationOpts = useModerationOpts()
|
const moderationOpts = useModerationOpts()
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ export function AvatarStack({
|
|||||||
a.flex_row,
|
a.flex_row,
|
||||||
a.align_center,
|
a.align_center,
|
||||||
a.relative,
|
a.relative,
|
||||||
{width: size + (items.length - 1) * halfSize},
|
{width: size + (items.length - 1) * (size - translation)},
|
||||||
]}>
|
]}>
|
||||||
{items.map((item, i) => (
|
{items.map((item, i) => (
|
||||||
<View
|
<View
|
||||||
@@ -54,7 +54,7 @@ export function AvatarStack({
|
|||||||
{
|
{
|
||||||
width: size,
|
width: size,
|
||||||
height: size,
|
height: size,
|
||||||
left: i * -halfSize,
|
left: i * -translation,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderColor: backgroundColor ?? t.atoms.bg.backgroundColor,
|
borderColor: backgroundColor ?? t.atoms.bg.backgroundColor,
|
||||||
borderRadius: 999,
|
borderRadius: 999,
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
import {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react'
|
import {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react'
|
||||||
import {ScrollView, TextInput, useWindowDimensions, View} from 'react-native'
|
import {
|
||||||
|
ScrollView,
|
||||||
|
type StyleProp,
|
||||||
|
TextInput,
|
||||||
|
useWindowDimensions,
|
||||||
|
View,
|
||||||
|
type ViewStyle,
|
||||||
|
} from 'react-native'
|
||||||
import Animated, {
|
import Animated, {
|
||||||
LayoutAnimationConfig,
|
LayoutAnimationConfig,
|
||||||
LinearTransition,
|
LinearTransition,
|
||||||
@@ -453,6 +460,7 @@ let Tabs = ({
|
|||||||
hasSearchText,
|
hasSearchText,
|
||||||
interestsDisplayNames,
|
interestsDisplayNames,
|
||||||
TabComponent = Tab,
|
TabComponent = Tab,
|
||||||
|
contentContainerStyle,
|
||||||
}: {
|
}: {
|
||||||
onSelectTab: (tab: string) => void
|
onSelectTab: (tab: string) => void
|
||||||
interests: string[]
|
interests: string[]
|
||||||
@@ -460,6 +468,7 @@ let Tabs = ({
|
|||||||
hasSearchText: boolean
|
hasSearchText: boolean
|
||||||
interestsDisplayNames: Record<string, string>
|
interestsDisplayNames: Record<string, string>
|
||||||
TabComponent?: React.ComponentType<React.ComponentProps<typeof Tab>>
|
TabComponent?: React.ComponentType<React.ComponentProps<typeof Tab>>
|
||||||
|
contentContainerStyle?: StyleProp<ViewStyle>
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const listRef = useRef<ScrollView>(null)
|
const listRef = useRef<ScrollView>(null)
|
||||||
const [scrollX, setScrollX] = useState(0)
|
const [scrollX, setScrollX] = useState(0)
|
||||||
@@ -520,7 +529,7 @@ let Tabs = ({
|
|||||||
<ScrollView
|
<ScrollView
|
||||||
ref={listRef}
|
ref={listRef}
|
||||||
horizontal
|
horizontal
|
||||||
contentContainerStyle={[a.gap_sm, a.px_lg]}
|
contentContainerStyle={[a.gap_sm, a.px_lg, contentContainerStyle]}
|
||||||
showsHorizontalScrollIndicator={false}
|
showsHorizontalScrollIndicator={false}
|
||||||
decelerationRate="fast"
|
decelerationRate="fast"
|
||||||
snapToOffsets={
|
snapToOffsets={
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import {Button} from '#/components/Button'
|
|||||||
import * as FeedCard from '#/components/FeedCard'
|
import * as FeedCard from '#/components/FeedCard'
|
||||||
import {ChevronBottom_Stroke2_Corner0_Rounded as ChevronDownIcon} from '#/components/icons/Chevron'
|
import {ChevronBottom_Stroke2_Corner0_Rounded as ChevronDownIcon} from '#/components/icons/Chevron'
|
||||||
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
|
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
|
||||||
|
import {type Props as IcoProps} from '#/components/icons/common'
|
||||||
import {type Props as SVGIconProps} from '#/components/icons/common'
|
import {type Props as SVGIconProps} from '#/components/icons/common'
|
||||||
import {ListSparkle_Stroke2_Corner0_Rounded as ListSparkle} from '#/components/icons/ListSparkle'
|
import {ListSparkle_Stroke2_Corner0_Rounded as ListSparkle} from '#/components/icons/ListSparkle'
|
||||||
import {StarterPack} from '#/components/icons/StarterPack'
|
import {StarterPack} from '#/components/icons/StarterPack'
|
||||||
@@ -110,6 +111,7 @@ type ExploreScreenItems =
|
|||||||
key: string
|
key: string
|
||||||
title: string
|
title: string
|
||||||
icon: React.ComponentType<SVGIconProps>
|
icon: React.ComponentType<SVGIconProps>
|
||||||
|
iconSize?: IcoProps['size']
|
||||||
searchButton?: {
|
searchButton?: {
|
||||||
label: string
|
label: string
|
||||||
metricsTag: MetricEvents['explore:module:searchButtonPress']['module']
|
metricsTag: MetricEvents['explore:module:searchButtonPress']['module']
|
||||||
@@ -461,6 +463,7 @@ export function Explore({
|
|||||||
key: 'suggested-starterPacks-header',
|
key: 'suggested-starterPacks-header',
|
||||||
title: _(msg`Starter Packs`),
|
title: _(msg`Starter Packs`),
|
||||||
icon: StarterPack,
|
icon: StarterPack,
|
||||||
|
iconSize: 'xl',
|
||||||
})
|
})
|
||||||
|
|
||||||
if (isLoadingSuggestedSPs) {
|
if (isLoadingSuggestedSPs) {
|
||||||
@@ -562,7 +565,7 @@ export function Explore({
|
|||||||
case 'header': {
|
case 'header': {
|
||||||
return (
|
return (
|
||||||
<ModuleHeader.Container>
|
<ModuleHeader.Container>
|
||||||
<ModuleHeader.Icon icon={item.icon} />
|
<ModuleHeader.Icon icon={item.icon} size={item.iconSize} />
|
||||||
<ModuleHeader.TitleText>{item.title}</ModuleHeader.TitleText>
|
<ModuleHeader.TitleText>{item.title}</ModuleHeader.TitleText>
|
||||||
{item.searchButton && (
|
{item.searchButton && (
|
||||||
<ModuleHeader.SearchButton
|
<ModuleHeader.SearchButton
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ export function SearchScreenShell({
|
|||||||
</Layout.Header.Outer>
|
</Layout.Header.Outer>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
<View style={[a.px_md, a.pt_sm, a.pb_sm, a.overflow_hidden]}>
|
<View style={[a.px_lg, a.pt_sm, a.pb_sm, a.overflow_hidden]}>
|
||||||
<View style={[a.gap_sm]}>
|
<View style={[a.gap_sm]}>
|
||||||
<View style={[a.w_full, a.flex_row, a.align_stretch, a.gap_xs]}>
|
<View style={[a.w_full, a.flex_row, a.align_stretch, a.gap_xs]}>
|
||||||
<View style={[a.flex_1]}>
|
<View style={[a.flex_1]}>
|
||||||
|
|||||||
@@ -6,14 +6,7 @@ import {PressableScale} from '#/lib/custom-animations/PressableScale'
|
|||||||
import {makeCustomFeedLink} from '#/lib/routes/links'
|
import {makeCustomFeedLink} from '#/lib/routes/links'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||||
import {
|
import {atoms as a, native, useTheme, type ViewStyleProp, web} from '#/alf'
|
||||||
atoms as a,
|
|
||||||
native,
|
|
||||||
useGutters,
|
|
||||||
useTheme,
|
|
||||||
type ViewStyleProp,
|
|
||||||
web,
|
|
||||||
} from '#/alf'
|
|
||||||
import {Button, ButtonIcon} from '#/components/Button'
|
import {Button, ButtonIcon} from '#/components/Button'
|
||||||
import * as FeedCard from '#/components/FeedCard'
|
import * as FeedCard from '#/components/FeedCard'
|
||||||
import {sizes as iconSizes} from '#/components/icons/common'
|
import {sizes as iconSizes} from '#/components/icons/common'
|
||||||
@@ -27,13 +20,12 @@ export function Container({
|
|||||||
headerHeight,
|
headerHeight,
|
||||||
}: {children: React.ReactNode; headerHeight?: number} & ViewStyleProp) {
|
}: {children: React.ReactNode; headerHeight?: number} & ViewStyleProp) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const gutters = useGutters([0, 'base'])
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
gutters,
|
|
||||||
a.flex_row,
|
a.flex_row,
|
||||||
a.align_center,
|
a.align_center,
|
||||||
|
a.px_lg,
|
||||||
a.pt_2xl,
|
a.pt_2xl,
|
||||||
a.pb_md,
|
a.pb_md,
|
||||||
a.gap_sm,
|
a.gap_sm,
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ export function AvatarStack({
|
|||||||
{computedTotal > 0 ? (
|
{computedTotal > 0 ? (
|
||||||
<Text
|
<Text
|
||||||
style={[
|
style={[
|
||||||
gtPhone ? a.text_md : a.text_sm,
|
gtPhone ? a.text_md : a.text_xs,
|
||||||
a.font_bold,
|
a.font_bold,
|
||||||
a.leading_snug,
|
a.leading_snug,
|
||||||
{color: 'white'},
|
{color: 'white'},
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {useLingui} from '@lingui/react'
|
|||||||
import {Nux, useSaveNux} from '#/state/queries/nuxs'
|
import {Nux, useSaveNux} from '#/state/queries/nuxs'
|
||||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||||
import {useInterestsDisplayNames} from '#/screens/Onboarding/state'
|
import {useInterestsDisplayNames} from '#/screens/Onboarding/state'
|
||||||
import {atoms as a, useGutters, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||||
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
||||||
import {Link} from '#/components/Link'
|
import {Link} from '#/components/Link'
|
||||||
@@ -16,7 +16,6 @@ import {Text} from '#/components/Typography'
|
|||||||
export function ExploreInterestsCard() {
|
export function ExploreInterestsCard() {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const gutters = useGutters([0, 'base'])
|
|
||||||
const {data: preferences} = usePreferencesQuery()
|
const {data: preferences} = usePreferencesQuery()
|
||||||
const interestsDisplayNames = useInterestsDisplayNames()
|
const interestsDisplayNames = useInterestsDisplayNames()
|
||||||
const {mutateAsync: saveNux} = useSaveNux()
|
const {mutateAsync: saveNux} = useSaveNux()
|
||||||
@@ -53,7 +52,7 @@ export function ExploreInterestsCard() {
|
|||||||
onConfirm={onConfirmClose}
|
onConfirm={onConfirmClose}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<View style={[gutters, a.pt_lg, a.pb_2xs]}>
|
<View style={[a.p_lg, a.pb_2xs]}>
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
a.p_lg,
|
a.p_lg,
|
||||||
|
|||||||
@@ -87,6 +87,12 @@ export function SuggestedAccountsTabBar({
|
|||||||
...interestsDisplayNames,
|
...interestsDisplayNames,
|
||||||
}}
|
}}
|
||||||
TabComponent={Tab}
|
TabComponent={Tab}
|
||||||
|
contentContainerStyle={[
|
||||||
|
{
|
||||||
|
// visual alignment
|
||||||
|
paddingLeft: a.px_md.paddingLeft,
|
||||||
|
},
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
</BlockDrawerGesture>
|
</BlockDrawerGesture>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user