Merge branch 'main' into 3p-moderators

This commit is contained in:
Paul Frazee
2024-03-07 23:02:14 -08:00
172 changed files with 9422 additions and 2463 deletions
+7 -4
View File
@@ -17,11 +17,12 @@ import {UsePreferencesQueryResponse} from '#/state/queries/preferences/types'
import {emitSoftReset} from '#/state/events'
import {useSession} from '#/state/session'
import {useSelectedFeed, useSetSelectedFeed} from '#/state/shell/selected-feed'
import {useSetTitle} from '#/lib/hooks/useSetTitle'
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'>
export function HomeScreen(props: Props) {
const {data: preferences} = usePreferencesQuery()
const {feeds: pinnedFeedInfos, isLoading: isPinnedFeedsLoading} =
const {data: pinnedFeedInfos, isLoading: isPinnedFeedsLoading} =
usePinnedFeedsInfos()
if (preferences && pinnedFeedInfos && !isPinnedFeedsLoading) {
return (
@@ -66,6 +67,8 @@ function HomeScreenReady({
const selectedIndex = Math.max(0, maybeFoundIndex)
const selectedFeed = allFeeds[selectedIndex]
useSetTitle(pinnedFeedInfos[selectedIndex]?.displayName)
const pagerRef = React.useRef<PagerRef>(null)
const lastPagerReportedIndexRef = React.useRef(selectedIndex)
React.useLayoutEffect(() => {
@@ -120,14 +123,14 @@ function HomeScreenReady({
return (
<HomeHeader
key="FEEDS_TAB_BAR"
selectedPage={props.selectedPage}
onSelect={props.onSelect}
{...props}
testID="homeScreenFeedTabs"
onPressSelected={onPressSelected}
feeds={pinnedFeedInfos}
/>
)
},
[onPressSelected],
[onPressSelected, pinnedFeedInfos],
)
const renderFollowingEmptyState = React.useCallback(() => {
+2
View File
@@ -488,6 +488,8 @@ const styles = StyleSheet.create({
container: {
flexDirection: 'column',
height: '100%',
// @ts-ignore Web-only.
overflowAnchor: 'none', // Fixes jumps when switching tabs while scrolled down.
},
loading: {
paddingVertical: 10,
+10 -5
View File
@@ -60,7 +60,7 @@ import {
import {logger} from '#/logger'
import {useAnalytics} from '#/lib/analytics/analytics'
import {listenSoftReset} from '#/state/events'
import {atoms as a} from '#/alf'
import {atoms as a, useTheme} from '#/alf'
const SECTION_TITLES_CURATE = ['Posts', 'About']
const SECTION_TITLES_MOD = ['About']
@@ -699,6 +699,7 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
ref,
) {
const pal = usePalette('default')
const t = useTheme()
const {_} = useLingui()
const {isMobile} = useWebMediaQueries()
const {currentAccount} = useSession()
@@ -792,7 +793,7 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
paddingBottom: isMobile ? 14 : 18,
},
]}>
<Text type="lg-bold">
<Text type="lg-bold" style={t.atoms.text}>
<Trans>Users</Trans>
</Text>
{isOwner && (
@@ -817,14 +818,18 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
</View>
)
}, [
pal,
list,
isMobile,
pal.border,
pal.textLight,
pal.colors.link,
pal.link,
descriptionRT,
isCurateList,
isOwner,
onPressAddUser,
list.creator,
t.atoms.text,
_,
onPressAddUser,
])
const renderEmptyState = useCallback(() => {
+26 -1
View File
@@ -16,7 +16,7 @@ import {
FontAwesomeIcon,
FontAwesomeIconStyle,
} from '@fortawesome/react-native-fontawesome'
import {useFocusEffect} from '@react-navigation/native'
import {useFocusEffect, useNavigation} from '@react-navigation/native'
import {logger} from '#/logger'
import {
@@ -53,6 +53,7 @@ import {listenSoftReset} from '#/state/events'
import {s} from '#/lib/styles'
import AsyncStorage from '@react-native-async-storage/async-storage'
import {augmentSearchQuery} from '#/lib/strings/helpers'
import {NavigationProp} from '#/lib/routes/types'
function Loader() {
const pal = usePalette('default')
@@ -448,6 +449,7 @@ export function SearchScreenInner({
export function SearchScreen(
props: NativeStackScreenProps<SearchTabNavigatorParams, 'Search'>,
) {
const navigation = useNavigation<NavigationProp>()
const theme = useTheme()
const textInput = React.useRef<TextInput>(null)
const {_} = useLingui()
@@ -472,6 +474,27 @@ export function SearchScreen(
React.useState(false)
const [searchHistory, setSearchHistory] = React.useState<string[]>([])
/**
* The Search screen's `q` param
*/
const queryParam = props.route?.params?.q
/**
* If `true`, this means we received new instructions from the router. This
* is handled in a effect, and used to update the value of `query` locally
* within this screen.
*/
const routeParamsMismatch = queryParam && queryParam !== query
React.useEffect(() => {
if (queryParam && routeParamsMismatch) {
// reset immediately and let local state take over
navigation.setParams({q: ''})
// update query for next search
setQuery(queryParam)
}
}, [queryParam, routeParamsMismatch, navigation])
React.useEffect(() => {
const loadSearchHistory = async () => {
try {
@@ -774,6 +797,8 @@ export function SearchScreen(
)}
</View>
</CenteredView>
) : routeParamsMismatch ? (
<ActivityIndicator />
) : (
<SearchScreenInner query={query} />
)}
+8 -20
View File
@@ -4,7 +4,7 @@ import {View} from 'react-native'
import {useTheme, atoms as a} from '#/alf'
import {ButtonText} from '#/components/Button'
import {InlineLink, Link} from '#/components/Link'
import {H1, H3, Text} from '#/components/Typography'
import {H1, Text} from '#/components/Typography'
export function Links() {
const t = useTheme()
@@ -13,31 +13,19 @@ export function Links() {
<H1>Links</H1>
<View style={[a.gap_md, a.align_start]}>
<InlineLink
to="https://bsky.social"
warnOnMismatchingTextChild
style={[a.text_md]}>
External
<InlineLink to="https://google.com" style={[a.text_lg]}>
https://google.com
</InlineLink>
<InlineLink to="https://bsky.social" style={[a.text_md, t.atoms.text]}>
<H3>External with custom children</H3>
<InlineLink to="https://google.com" style={[a.text_lg]}>
External with custom children (google.com)
</InlineLink>
<InlineLink
to="https://bsky.social"
style={[a.text_md, t.atoms.text_contrast_low]}>
External with custom children
Internal (bsky.social)
</InlineLink>
<InlineLink
to="https://bsky.social"
warnOnMismatchingTextChild
style={[a.text_lg]}>
https://bsky.social
</InlineLink>
<InlineLink
to="https://bsky.app/profile/bsky.app"
warnOnMismatchingTextChild
style={[a.text_md]}>
Internal
<InlineLink to="https://bsky.app/profile/bsky.app" style={[a.text_md]}>
Internal (bsky.app)
</InlineLink>
<Link
+79
View File
@@ -0,0 +1,79 @@
import React from 'react'
import {View} from 'react-native'
import {atoms as a, useTheme} from '#/alf'
import {Text} from '#/components/Typography'
import * as Menu from '#/components/Menu'
import {MagnifyingGlass2_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass2'
// import {useDialogStateControlContext} from '#/state/dialogs'
export function Menus() {
const t = useTheme()
const menuControl = Menu.useMenuControl()
// const {closeAllDialogs} = useDialogStateControlContext()
return (
<View style={[a.gap_md]}>
<View style={[a.flex_row, a.align_start]}>
<Menu.Root control={menuControl}>
<Menu.Trigger label="Open basic menu" style={[a.flex_1]}>
{({state, props}) => {
return (
<Text
{...props}
style={[
a.py_sm,
a.px_md,
a.rounded_sm,
t.atoms.bg_contrast_50,
(state.hovered || state.focused || state.pressed) && [
t.atoms.bg_contrast_200,
],
]}>
Open
</Text>
)
}}
</Menu.Trigger>
<Menu.Outer>
<Menu.Group>
<Menu.Item label="Click me" onPress={() => {}}>
<Menu.ItemIcon icon={Search} />
<Menu.ItemText>Click me</Menu.ItemText>
</Menu.Item>
<Menu.Item
label="Another item"
onPress={() => menuControl.close()}>
<Menu.ItemText>Another item</Menu.ItemText>
</Menu.Item>
</Menu.Group>
<Menu.Divider />
<Menu.Group>
<Menu.Item label="Click me" onPress={() => {}}>
<Menu.ItemIcon icon={Search} />
<Menu.ItemText>Click me</Menu.ItemText>
</Menu.Item>
<Menu.Item
label="Another item"
onPress={() => menuControl.close()}>
<Menu.ItemText>Another item</Menu.ItemText>
</Menu.Item>
</Menu.Group>
<Menu.Divider />
<Menu.Item label="Click me" onPress={() => {}}>
<Menu.ItemIcon icon={Search} />
<Menu.ItemText>Click me</Menu.ItemText>
</Menu.Item>
</Menu.Outer>
</Menu.Root>
</View>
</View>
)
}
+49 -44
View File
@@ -1,7 +1,6 @@
import React from 'react'
import {View} from 'react-native'
import * as tokens from '#/alf/tokens'
import {atoms as a, useTheme} from '#/alf'
export function Palette() {
@@ -28,79 +27,79 @@ export function Palette() {
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.blue_25},
{height: 60, backgroundColor: t.palette.primary_25},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.blue_50},
{height: 60, backgroundColor: t.palette.primary_50},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.blue_100},
{height: 60, backgroundColor: t.palette.primary_100},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.blue_200},
{height: 60, backgroundColor: t.palette.primary_200},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.blue_300},
{height: 60, backgroundColor: t.palette.primary_300},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.blue_400},
{height: 60, backgroundColor: t.palette.primary_400},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.blue_500},
{height: 60, backgroundColor: t.palette.primary_500},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.blue_600},
{height: 60, backgroundColor: t.palette.primary_600},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.blue_700},
{height: 60, backgroundColor: t.palette.primary_700},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.blue_800},
{height: 60, backgroundColor: t.palette.primary_800},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.blue_900},
{height: 60, backgroundColor: t.palette.primary_900},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.blue_950},
{height: 60, backgroundColor: t.palette.primary_950},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.blue_975},
{height: 60, backgroundColor: t.palette.primary_975},
]}
/>
</View>
@@ -108,153 +107,159 @@ export function Palette() {
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.green_25},
{height: 60, backgroundColor: t.palette.positive_25},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.green_50},
{height: 60, backgroundColor: t.palette.positive_50},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.green_100},
{height: 60, backgroundColor: t.palette.positive_100},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.green_200},
{height: 60, backgroundColor: t.palette.positive_200},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.green_300},
{height: 60, backgroundColor: t.palette.positive_300},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.green_400},
{height: 60, backgroundColor: t.palette.positive_400},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.green_500},
{height: 60, backgroundColor: t.palette.positive_500},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.green_600},
{height: 60, backgroundColor: t.palette.positive_600},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.green_700},
{height: 60, backgroundColor: t.palette.positive_700},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.green_800},
{height: 60, backgroundColor: t.palette.positive_800},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.green_900},
{height: 60, backgroundColor: t.palette.positive_900},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.green_950},
{height: 60, backgroundColor: t.palette.positive_950},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.green_975},
{height: 60, backgroundColor: t.palette.positive_975},
]}
/>
</View>
<View style={[a.flex_row, a.gap_md]}>
<View
style={[a.flex_1, {height: 60, backgroundColor: tokens.color.red_25}]}
/>
<View
style={[a.flex_1, {height: 60, backgroundColor: tokens.color.red_50}]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.red_100},
{height: 60, backgroundColor: t.palette.negative_25},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.red_200},
{height: 60, backgroundColor: t.palette.negative_50},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.red_300},
{height: 60, backgroundColor: t.palette.negative_100},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.red_400},
{height: 60, backgroundColor: t.palette.negative_200},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.red_500},
{height: 60, backgroundColor: t.palette.negative_300},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.red_600},
{height: 60, backgroundColor: t.palette.negative_400},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.red_700},
{height: 60, backgroundColor: t.palette.negative_500},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.red_800},
{height: 60, backgroundColor: t.palette.negative_600},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.red_900},
{height: 60, backgroundColor: t.palette.negative_700},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.red_950},
{height: 60, backgroundColor: t.palette.negative_800},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: tokens.color.red_975},
{height: 60, backgroundColor: t.palette.negative_900},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: t.palette.negative_950},
]}
/>
<View
style={[
a.flex_1,
{height: 60, backgroundColor: t.palette.negative_975},
]}
/>
</View>
+4 -2
View File
@@ -22,12 +22,14 @@ export function Typography() {
<Text style={[a.text_2xs]}>atoms.text_2xs</Text>
<RichText
resolveFacets
// TODO: This only supports already resolved facets.
// Resolving them on read is bad anyway.
value={`This is rich text. It can have mentions like @bsky.app or links like https://bsky.social`}
/>
<RichText
selectable
resolveFacets
// TODO: This only supports already resolved facets.
// Resolving them on read is bad anyway.
value={`This is rich text. It can have mentions like @bsky.app or links like https://bsky.social`}
style={[a.text_xl]}
/>
+3
View File
@@ -16,6 +16,7 @@ import {Dialogs} from './Dialogs'
import {Breakpoints} from './Breakpoints'
import {Shadows} from './Shadows'
import {Icons} from './Icons'
import {Menus} from './Menus'
export function Storybook() {
const t = useTheme()
@@ -84,6 +85,8 @@ export function Storybook() {
<Icons />
<Links />
<Forms />
<Dialogs />
<Menus />
<Breakpoints />
</View>
</CenteredView>