Updates to use dynamic/responsive styles on web (#1351)
* Move most responsive queries to the hook * Fix invalid CSS value * Fixes to tablet render of post thread * Fix overflow issues on web * Fix search header on tablet * Fix QP margin in web composer * Fix: only apply double gutter once to flatlist (close #1368) * Fix styles on discover feeds header * Fix double discover links in multifeedzio/stable
parent
be8084ae10
commit
764c7cd569
|
@ -2,13 +2,19 @@ import {useMediaQuery} from 'react-responsive'
|
|||
import {isNative} from 'platform/detection'
|
||||
|
||||
export function useWebMediaQueries() {
|
||||
const isDesktop = useMediaQuery({
|
||||
query: '(min-width: 1224px)',
|
||||
})
|
||||
const isTabletOrMobile = useMediaQuery({query: '(max-width: 1224px)'})
|
||||
const isMobile = useMediaQuery({query: '(max-width: 800px)'})
|
||||
const isDesktop = useMediaQuery({minWidth: 1300})
|
||||
const isTablet = useMediaQuery({minWidth: 800, maxWidth: 1300})
|
||||
const isMobile = useMediaQuery({maxWidth: 800})
|
||||
const isTabletOrMobile = isMobile || isTablet
|
||||
const isTabletOrDesktop = isDesktop || isTablet
|
||||
if (isNative) {
|
||||
return {isMobile: true, isTabletOrMobile: true, isDesktop: false}
|
||||
return {
|
||||
isMobile: true,
|
||||
isTablet: false,
|
||||
isTabletOrMobile: true,
|
||||
isTabletOrDesktop: false,
|
||||
isDesktop: false,
|
||||
}
|
||||
}
|
||||
return {isMobile, isTabletOrMobile, isDesktop}
|
||||
return {isMobile, isTablet, isTabletOrMobile, isTabletOrDesktop, isDesktop}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ export const isAndroid = Platform.OS === 'android'
|
|||
export const isNative = isIOS || isAndroid
|
||||
export const devicePlatform = isIOS ? 'ios' : isAndroid ? 'android' : 'web'
|
||||
export const isWeb = !isNative
|
||||
export const isMobileWebMediaQuery = 'only screen and (max-width: 1230px)'
|
||||
export const isMobileWebMediaQuery = 'only screen and (max-width: 1300px)'
|
||||
export const isMobileWeb =
|
||||
isWeb &&
|
||||
// @ts-ignore we know window exists -prf
|
||||
|
|
|
@ -111,7 +111,8 @@ export class PostsMultiFeedModel {
|
|||
uri: makeProfileLink(feedInfo.data.creator, 'feed', urip.rkey),
|
||||
})
|
||||
}
|
||||
if (!this.hasMore) {
|
||||
if (!this.hasMore && this.hasContent) {
|
||||
// only show if hasContent to avoid double discover-feed links
|
||||
items.push({_reactKey: '__footer__', type: 'footer'})
|
||||
}
|
||||
return items
|
||||
|
|
|
@ -16,9 +16,7 @@ type Props = {
|
|||
|
||||
export const WelcomeDesktop = observer(({next}: Props) => {
|
||||
const pal = usePalette('default')
|
||||
const horizontal = useMediaQuery({
|
||||
query: '(min-width: 1230px)',
|
||||
})
|
||||
const horizontal = useMediaQuery({minWidth: 1300})
|
||||
const title = (
|
||||
<>
|
||||
<Text
|
||||
|
|
|
@ -7,7 +7,6 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
|||
import {Button} from 'view/com/util/forms/Button'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {ViewHeader} from 'view/com/util/ViewHeader'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
|
||||
type Props = {
|
||||
next: () => void
|
||||
|
@ -95,7 +94,7 @@ export const WelcomeMobile = observer(({next, skip}: Props) => {
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
marginBottom: isDesktopWeb ? 30 : 60,
|
||||
marginBottom: 60,
|
||||
marginHorizontal: 16,
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
|
|
|
@ -37,9 +37,10 @@ import {toShortUrl} from 'lib/strings/url-helpers'
|
|||
import {SelectPhotoBtn} from './photos/SelectPhotoBtn'
|
||||
import {OpenCameraBtn} from './photos/OpenCameraBtn'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import QuoteEmbed from '../util/post-embeds/QuoteEmbed'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {useExternalLinkFetch} from './useExternalLinkFetch'
|
||||
import {isDesktopWeb, isAndroid, isIOS} from 'platform/detection'
|
||||
import {isWeb, isNative, isAndroid, isIOS} from 'platform/detection'
|
||||
import QuoteEmbed from '../util/post-embeds/QuoteEmbed'
|
||||
import {GalleryModel} from 'state/models/media/gallery'
|
||||
import {Gallery} from './photos/Gallery'
|
||||
import {MAX_GRAPHEME_LENGTH} from 'lib/constants'
|
||||
|
@ -61,6 +62,7 @@ export const ComposePost = observer(function ComposePost({
|
|||
}: Props) {
|
||||
const {track} = useAnalytics()
|
||||
const pal = usePalette('default')
|
||||
const {isDesktop, isMobile} = useWebMediaQueries()
|
||||
const store = useStores()
|
||||
const textInput = useRef<TextInputRef>(null)
|
||||
const [isKeyboardVisible] = useIsKeyboardVisible({iosUseWillEvents: true})
|
||||
|
@ -99,9 +101,9 @@ export const ComposePost = observer(function ComposePost({
|
|||
() => ({
|
||||
paddingBottom:
|
||||
isAndroid || (isIOS && !isKeyboardVisible) ? insets.bottom : 0,
|
||||
paddingTop: isAndroid ? insets.top : isDesktopWeb ? 0 : 15,
|
||||
paddingTop: isAndroid ? insets.top : isMobile ? 15 : 0,
|
||||
}),
|
||||
[insets, isKeyboardVisible],
|
||||
[insets, isKeyboardVisible, isMobile],
|
||||
)
|
||||
|
||||
const onPressCancel = useCallback(() => {
|
||||
|
@ -143,7 +145,7 @@ export const ComposePost = observer(function ComposePost({
|
|||
[onPressCancel],
|
||||
)
|
||||
useEffect(() => {
|
||||
if (isDesktopWeb) {
|
||||
if (isWeb) {
|
||||
window.addEventListener('keydown', onEscape)
|
||||
return () => window.removeEventListener('keydown', onEscape)
|
||||
}
|
||||
|
@ -240,7 +242,7 @@ export const ComposePost = observer(function ComposePost({
|
|||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
style={styles.outer}>
|
||||
<View style={[s.flex1, viewStyles]} aria-modal accessibilityViewIsModal>
|
||||
<View style={styles.topbar}>
|
||||
<View style={[styles.topbar, isDesktop && styles.topbarDesktop]}>
|
||||
<TouchableOpacity
|
||||
testID="composerDiscardButton"
|
||||
onPress={onPressCancel}
|
||||
|
@ -334,7 +336,12 @@ export const ComposePost = observer(function ComposePost({
|
|||
</View>
|
||||
) : undefined}
|
||||
|
||||
<View style={[pal.border, styles.textInputLayout]}>
|
||||
<View
|
||||
style={[
|
||||
pal.border,
|
||||
styles.textInputLayout,
|
||||
isNative && styles.textInputLayoutMobile,
|
||||
]}>
|
||||
<UserAvatar avatar={store.me.avatar} size={50} />
|
||||
<TextInput
|
||||
ref={textInput}
|
||||
|
@ -362,7 +369,7 @@ export const ComposePost = observer(function ComposePost({
|
|||
/>
|
||||
)}
|
||||
{quote ? (
|
||||
<View style={s.mt5}>
|
||||
<View style={[s.mt5, isWeb && s.mb10]}>
|
||||
<QuoteEmbed quote={quote} />
|
||||
</View>
|
||||
) : undefined}
|
||||
|
@ -395,7 +402,7 @@ export const ComposePost = observer(function ComposePost({
|
|||
<OpenCameraBtn gallery={gallery} />
|
||||
</>
|
||||
) : null}
|
||||
{isDesktopWeb ? <EmojiPickerButton /> : null}
|
||||
{isDesktop ? <EmojiPickerButton /> : null}
|
||||
<View style={s.flex1} />
|
||||
<SelectLangBtn />
|
||||
<CharProgress count={graphemeLength} />
|
||||
|
@ -414,11 +421,14 @@ const styles = StyleSheet.create({
|
|||
topbar: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingTop: isDesktopWeb ? 10 : undefined,
|
||||
paddingBottom: isDesktopWeb ? 10 : 4,
|
||||
paddingBottom: 4,
|
||||
paddingHorizontal: 20,
|
||||
height: 55,
|
||||
},
|
||||
topbarDesktop: {
|
||||
paddingTop: 10,
|
||||
paddingBottom: 10,
|
||||
},
|
||||
postBtn: {
|
||||
borderRadius: 20,
|
||||
paddingHorizontal: 20,
|
||||
|
@ -465,11 +475,13 @@ const styles = StyleSheet.create({
|
|||
paddingHorizontal: 15,
|
||||
},
|
||||
textInputLayout: {
|
||||
flex: isDesktopWeb ? undefined : 1,
|
||||
flexDirection: 'row',
|
||||
borderTopWidth: 1,
|
||||
paddingTop: 16,
|
||||
},
|
||||
textInputLayoutMobile: {
|
||||
flex: 1,
|
||||
},
|
||||
replyToLayout: {
|
||||
flexDirection: 'row',
|
||||
borderTopWidth: 1,
|
||||
|
|
|
@ -4,11 +4,12 @@ import {UserAvatar} from '../util/UserAvatar'
|
|||
import {Text} from '../util/text/Text'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useStores} from 'state/index'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
|
||||
export function ComposePrompt({onPressCompose}: {onPressCompose: () => void}) {
|
||||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
const {isDesktop} = useWebMediaQueries()
|
||||
return (
|
||||
<TouchableOpacity
|
||||
testID="replyPromptBtn"
|
||||
|
@ -22,7 +23,7 @@ export function ComposePrompt({onPressCompose}: {onPressCompose: () => void}) {
|
|||
type="xl"
|
||||
style={[
|
||||
pal.text,
|
||||
isDesktopWeb ? styles.labelDesktopWeb : styles.labelMobile,
|
||||
isDesktop ? styles.labelDesktopWeb : styles.labelMobile,
|
||||
]}>
|
||||
Write your reply
|
||||
</Text>
|
||||
|
|
|
@ -7,10 +7,10 @@ import {s, colors} from 'lib/styles'
|
|||
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import {Image} from 'expo-image'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {openAltTextModal} from 'lib/media/alt-text'
|
||||
import {useStores} from 'state/index'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
|
||||
interface Props {
|
||||
gallery: GalleryModel
|
||||
|
@ -19,13 +19,14 @@ interface Props {
|
|||
export const Gallery = observer(function ({gallery}: Props) {
|
||||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
|
||||
let side: number
|
||||
|
||||
if (gallery.size === 1) {
|
||||
side = 250
|
||||
} else {
|
||||
side = (isDesktopWeb ? 560 : 350) / gallery.size
|
||||
side = (isMobile ? 350 : 560) / gallery.size
|
||||
}
|
||||
|
||||
const imageStyle = {
|
||||
|
@ -33,14 +34,14 @@ export const Gallery = observer(function ({gallery}: Props) {
|
|||
width: side,
|
||||
}
|
||||
|
||||
const isOverflow = !isDesktopWeb && gallery.size > 2
|
||||
const isOverflow = isMobile && gallery.size > 2
|
||||
|
||||
const altTextControlStyle = isOverflow
|
||||
? {
|
||||
left: 4,
|
||||
bottom: 4,
|
||||
}
|
||||
: isDesktopWeb && gallery.size < 3
|
||||
: !isMobile && gallery.size < 3
|
||||
? {
|
||||
left: 8,
|
||||
top: 8,
|
||||
|
@ -60,7 +61,7 @@ export const Gallery = observer(function ({gallery}: Props) {
|
|||
right: 4,
|
||||
gap: 4,
|
||||
}
|
||||
: isDesktopWeb && gallery.size < 3
|
||||
: !isMobile && gallery.size < 3
|
||||
? {
|
||||
top: 8,
|
||||
right: 8,
|
||||
|
|
|
@ -22,9 +22,9 @@ import {TextLink} from '../util/Link'
|
|||
import {ListModel} from 'state/models/content/list'
|
||||
import {useAnalytics} from 'lib/analytics/analytics'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {useStores} from 'state/index'
|
||||
import {s} from 'lib/styles'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {ListActions} from './ListActions'
|
||||
import {makeProfileLink} from 'lib/routes/links'
|
||||
import {sanitizeHandle} from 'lib/strings/handles'
|
||||
|
@ -283,6 +283,7 @@ const ListHeader = observer(
|
|||
}) => {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {isDesktop} = useWebMediaQueries()
|
||||
const descriptionRT = React.useMemo(
|
||||
() =>
|
||||
list?.description &&
|
||||
|
@ -318,7 +319,7 @@ const ListHeader = observer(
|
|||
richText={descriptionRT}
|
||||
/>
|
||||
)}
|
||||
{isDesktopWeb && (
|
||||
{isDesktop && (
|
||||
<ListActions
|
||||
isOwner={isOwner}
|
||||
muted={list.viewer?.muted}
|
||||
|
@ -334,7 +335,8 @@ const ListHeader = observer(
|
|||
<UserAvatar type="list" avatar={list.avatar} size={64} />
|
||||
</View>
|
||||
</View>
|
||||
<View style={[styles.fakeSelector, pal.border]}>
|
||||
<View
|
||||
style={{flexDirection: 'row', paddingHorizontal: isDesktop ? 16 : 6}}>
|
||||
<View
|
||||
style={[styles.fakeSelectorItem, {borderColor: pal.colors.link}]}>
|
||||
<Text type="md-medium" style={[pal.text]}>
|
||||
|
@ -365,10 +367,6 @@ const styles = StyleSheet.create({
|
|||
gap: 8,
|
||||
marginTop: 12,
|
||||
},
|
||||
fakeSelector: {
|
||||
flexDirection: 'row',
|
||||
paddingHorizontal: isDesktopWeb ? 16 : 6,
|
||||
},
|
||||
fakeSelectorItem: {
|
||||
paddingHorizontal: 12,
|
||||
paddingBottom: 8,
|
||||
|
|
|
@ -5,7 +5,7 @@ import {Button} from '../util/forms/Button'
|
|||
import {s} from 'lib/styles'
|
||||
import {useStores} from 'state/index'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {isNative} from 'platform/detection'
|
||||
import {
|
||||
FontAwesomeIcon,
|
||||
FontAwesomeIconStyle,
|
||||
|
@ -205,7 +205,7 @@ export function Component({}: {}) {
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
paddingBottom: isDesktopWeb ? 0 : 50,
|
||||
paddingBottom: isNative ? 50 : 0,
|
||||
paddingHorizontal: 16,
|
||||
},
|
||||
textInputWrapper: {
|
||||
|
|
|
@ -18,7 +18,7 @@ import {useTheme} from 'lib/ThemeContext'
|
|||
import {Text} from '../util/text/Text'
|
||||
import LinearGradient from 'react-native-linear-gradient'
|
||||
import {useStores} from 'state/index'
|
||||
import {isDesktopWeb, isAndroid} from 'platform/detection'
|
||||
import {isAndroid, isWeb} from 'platform/detection'
|
||||
import {ImageModel} from 'state/models/media/image'
|
||||
|
||||
export const snapPoints = ['fullscreen']
|
||||
|
@ -35,7 +35,7 @@ export function Component({image}: Props) {
|
|||
const windim = useWindowDimensions()
|
||||
|
||||
const imageStyles = useMemo<ImageStyle>(() => {
|
||||
const maxWidth = isDesktopWeb ? 450 : windim.width
|
||||
const maxWidth = isWeb ? 450 : windim.width
|
||||
if (image.height > image.width) {
|
||||
return {
|
||||
resizeMode: 'contain',
|
||||
|
@ -137,12 +137,12 @@ const styles = StyleSheet.create({
|
|||
flex: 1,
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
paddingVertical: isDesktopWeb ? 0 : 18,
|
||||
paddingVertical: isWeb ? 0 : 18,
|
||||
},
|
||||
scrollContainer: {
|
||||
flex: 1,
|
||||
height: '100%',
|
||||
paddingHorizontal: isDesktopWeb ? 0 : 12,
|
||||
paddingHorizontal: isWeb ? 0 : 12,
|
||||
},
|
||||
scrollInner: {
|
||||
gap: 12,
|
||||
|
|
|
@ -11,7 +11,7 @@ import {s, colors} from 'lib/styles'
|
|||
import {ErrorMessage} from '../util/error/ErrorMessage'
|
||||
import {cleanError} from 'lib/strings/errors'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {isWeb} from 'platform/detection'
|
||||
import type {ConfirmModal} from 'state/models/ui/shell'
|
||||
|
||||
export const snapPoints = ['50%']
|
||||
|
@ -96,7 +96,7 @@ const styles = StyleSheet.create({
|
|||
container: {
|
||||
flex: 1,
|
||||
padding: 10,
|
||||
paddingBottom: isDesktopWeb ? 0 : 60,
|
||||
paddingBottom: isWeb ? 0 : 60,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
|
|
|
@ -11,13 +11,15 @@ import {TextLink} from '../util/Link'
|
|||
import {ToggleButton} from '../util/forms/ToggleButton'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {CONFIGURABLE_LABEL_GROUPS} from 'lib/labeling/const'
|
||||
import {isDesktopWeb, isIOS} from 'platform/detection'
|
||||
import {isIOS} from 'platform/detection'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import * as Toast from '../util/Toast'
|
||||
|
||||
export const snapPoints = ['90%']
|
||||
|
||||
export const Component = observer(({}: {}) => {
|
||||
const store = useStores()
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const pal = usePalette('default')
|
||||
|
||||
React.useEffect(() => {
|
||||
|
@ -88,9 +90,14 @@ export const Component = observer(({}: {}) => {
|
|||
<ContentLabelPref group="hate" />
|
||||
<ContentLabelPref group="spam" />
|
||||
<ContentLabelPref group="impersonation" />
|
||||
<View style={styles.bottomSpacer} />
|
||||
<View style={{height: isMobile ? 60 : 0}} />
|
||||
</ScrollView>
|
||||
<View style={[styles.btnContainer, pal.borderDark]}>
|
||||
<View
|
||||
style={[
|
||||
styles.btnContainer,
|
||||
isMobile && styles.btnContainerMobile,
|
||||
pal.borderDark,
|
||||
]}>
|
||||
<Pressable
|
||||
testID="sendReportBtn"
|
||||
onPress={onPressDone}
|
||||
|
@ -259,14 +266,13 @@ const styles = StyleSheet.create({
|
|||
flex: 1,
|
||||
paddingHorizontal: 10,
|
||||
},
|
||||
bottomSpacer: {
|
||||
height: isDesktopWeb ? 0 : 60,
|
||||
},
|
||||
btnContainer: {
|
||||
paddingTop: 10,
|
||||
paddingHorizontal: 10,
|
||||
paddingBottom: isDesktopWeb ? 0 : 40,
|
||||
borderTopWidth: isDesktopWeb ? 0 : 1,
|
||||
},
|
||||
btnContainerMobile: {
|
||||
paddingBottom: 40,
|
||||
borderTopWidth: 1,
|
||||
},
|
||||
|
||||
contentLabelPref: {
|
||||
|
|
|
@ -22,8 +22,8 @@ import {UserAvatar} from '../util/UserAvatar'
|
|||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useTheme} from 'lib/ThemeContext'
|
||||
import {useAnalytics} from 'lib/analytics/analytics'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {cleanError, isNetworkError} from 'lib/strings/errors'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
|
||||
const MAX_NAME = 64 // todo
|
||||
const MAX_DESCRIPTION = 300 // todo
|
||||
|
@ -38,6 +38,7 @@ export function Component({
|
|||
list?: ListModel
|
||||
}) {
|
||||
const store = useStores()
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const [error, setError] = useState<string>('')
|
||||
const pal = usePalette('default')
|
||||
const theme = useTheme()
|
||||
|
@ -130,7 +131,12 @@ export function Component({
|
|||
return (
|
||||
<KeyboardAvoidingView behavior="height">
|
||||
<ScrollView
|
||||
style={[pal.view, styles.container]}
|
||||
style={[
|
||||
pal.view,
|
||||
{
|
||||
paddingHorizontal: isMobile ? 16 : 0,
|
||||
},
|
||||
]}
|
||||
testID="createOrEditMuteListModal">
|
||||
<Text style={[styles.title, pal.text]}>
|
||||
{list ? 'Edit Mute List' : 'New Mute List'}
|
||||
|
@ -226,9 +232,6 @@ export function Component({
|
|||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
paddingHorizontal: isDesktopWeb ? 0 : 16,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
fontWeight: 'bold',
|
||||
|
|
|
@ -13,10 +13,10 @@ import {useStores} from 'state/index'
|
|||
import {s, colors, gradients} from 'lib/styles'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useTheme} from 'lib/ThemeContext'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {ErrorMessage} from '../util/error/ErrorMessage'
|
||||
import {cleanError} from 'lib/strings/errors'
|
||||
import {resetToTab} from '../../../Navigation'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
|
||||
export const snapPoints = ['60%']
|
||||
|
||||
|
@ -24,6 +24,7 @@ export function Component({}: {}) {
|
|||
const pal = usePalette('default')
|
||||
const theme = useTheme()
|
||||
const store = useStores()
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const [isEmailSent, setIsEmailSent] = React.useState<boolean>(false)
|
||||
const [confirmCode, setConfirmCode] = React.useState<string>('')
|
||||
const [password, setPassword] = React.useState<string>('')
|
||||
|
@ -78,7 +79,7 @@ export function Component({}: {}) {
|
|||
type="title-xl"
|
||||
numberOfLines={1}
|
||||
style={[
|
||||
isDesktopWeb ? styles.titleDesktop : styles.titleMobile,
|
||||
isMobile ? styles.titleMobile : styles.titleDesktop,
|
||||
pal.text,
|
||||
s.bold,
|
||||
]}>
|
||||
|
|
|
@ -7,6 +7,7 @@ import {useTheme} from 'lib/ThemeContext'
|
|||
import {Text} from '../util/text/Text'
|
||||
import LinearGradient from 'react-native-linear-gradient'
|
||||
import {useStores} from 'state/index'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import ImageEditor, {Position} from 'react-avatar-editor'
|
||||
import {TextInput} from './util'
|
||||
import {enforceLen} from 'lib/strings/helpers'
|
||||
|
@ -18,7 +19,6 @@ import {Slider} from '@miblanchard/react-native-slider'
|
|||
import {MaterialIcons} from '@expo/vector-icons'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {getKeys} from 'lib/type-assertions'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
|
||||
export const snapPoints = ['80%']
|
||||
|
||||
|
@ -51,6 +51,7 @@ export const Component = observer(function ({image, gallery}: Props) {
|
|||
const theme = useTheme()
|
||||
const store = useStores()
|
||||
const windowDimensions = useWindowDimensions()
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
|
||||
const {
|
||||
aspectRatio,
|
||||
|
@ -174,19 +175,28 @@ export const Component = observer(function ({image, gallery}: Props) {
|
|||
|
||||
const computedWidth =
|
||||
windowDimensions.width > 500 ? 410 : windowDimensions.width - 80
|
||||
const sideLength = isDesktopWeb ? 300 : computedWidth
|
||||
const sideLength = isMobile ? computedWidth : 300
|
||||
|
||||
const dimensions = image.getResizedDimensions(aspectRatio, sideLength)
|
||||
const imgContainerStyles = {width: sideLength, height: sideLength}
|
||||
|
||||
const imgControlStyles = {
|
||||
alignItems: 'center' as const,
|
||||
flexDirection: isDesktopWeb ? ('row' as const) : ('column' as const),
|
||||
gap: isDesktopWeb ? 5 : 0,
|
||||
flexDirection: isMobile ? ('column' as const) : ('row' as const),
|
||||
gap: isMobile ? 0 : 5,
|
||||
}
|
||||
|
||||
return (
|
||||
<View testID="editImageModal" style={[pal.view, styles.container, s.flex1]}>
|
||||
<View
|
||||
testID="editImageModal"
|
||||
style={[
|
||||
pal.view,
|
||||
styles.container,
|
||||
s.flex1,
|
||||
{
|
||||
paddingHorizontal: isMobile ? 16 : undefined,
|
||||
},
|
||||
]}>
|
||||
<Text style={[styles.title, pal.text]}>Edit image</Text>
|
||||
<View style={[styles.gap18, s.flexRow]}>
|
||||
<View>
|
||||
|
@ -213,7 +223,7 @@ export const Component = observer(function ({image, gallery}: Props) {
|
|||
/>
|
||||
</View>
|
||||
<View>
|
||||
{isDesktopWeb ? (
|
||||
{!isMobile ? (
|
||||
<Text type="sm-bold" style={pal.text}>
|
||||
Ratios
|
||||
</Text>
|
||||
|
@ -248,7 +258,7 @@ export const Component = observer(function ({image, gallery}: Props) {
|
|||
)
|
||||
})}
|
||||
</View>
|
||||
{isDesktopWeb ? (
|
||||
{!isMobile ? (
|
||||
<Text type="sm-bold" style={[pal.text, styles.subsection]}>
|
||||
Transformations
|
||||
</Text>
|
||||
|
@ -282,7 +292,14 @@ export const Component = observer(function ({image, gallery}: Props) {
|
|||
</Text>
|
||||
<TextInput
|
||||
testID="altTextImageInput"
|
||||
style={[styles.textArea, pal.border, pal.text]}
|
||||
style={[
|
||||
styles.textArea,
|
||||
pal.border,
|
||||
pal.text,
|
||||
{
|
||||
maxHeight: isMobile ? 50 : undefined,
|
||||
},
|
||||
]}
|
||||
keyboardAppearance={theme.colorScheme}
|
||||
multiline
|
||||
value={altText}
|
||||
|
@ -317,7 +334,6 @@ export const Component = observer(function ({image, gallery}: Props) {
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
gap: 18,
|
||||
paddingHorizontal: isDesktopWeb ? undefined : 16,
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
},
|
||||
|
@ -369,7 +385,6 @@ const styles = StyleSheet.create({
|
|||
fontSize: 16,
|
||||
height: 100,
|
||||
textAlignVertical: 'top',
|
||||
maxHeight: isDesktopWeb ? undefined : 50,
|
||||
},
|
||||
bottomSection: {
|
||||
borderTopWidth: 1,
|
||||
|
|
|
@ -12,7 +12,7 @@ import * as Toast from '../util/Toast'
|
|||
import {useStores} from 'state/index'
|
||||
import {ScrollView} from './util'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {isWeb} from 'platform/detection'
|
||||
|
||||
export const snapPoints = ['70%']
|
||||
|
||||
|
@ -127,7 +127,7 @@ const InviteCode = observer(
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
paddingBottom: isDesktopWeb ? 0 : 50,
|
||||
paddingBottom: isWeb ? 0 : 50,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
|
|
|
@ -19,7 +19,7 @@ import {sanitizeDisplayName} from 'lib/strings/display-names'
|
|||
import {sanitizeHandle} from 'lib/strings/handles'
|
||||
import {s} from 'lib/styles'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {isDesktopWeb, isAndroid} from 'platform/detection'
|
||||
import {isWeb, isAndroid} from 'platform/detection'
|
||||
import isEqual from 'lodash.isequal'
|
||||
|
||||
export const snapPoints = ['fullscreen']
|
||||
|
@ -231,7 +231,7 @@ export const Component = observer(
|
|||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
paddingHorizontal: isDesktopWeb ? 0 : 16,
|
||||
paddingHorizontal: isWeb ? 0 : 16,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
|
|
|
@ -3,8 +3,8 @@ import {TouchableWithoutFeedback, StyleSheet, View} from 'react-native'
|
|||
import {observer} from 'mobx-react-lite'
|
||||
import {useStores} from 'state/index'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import type {Modal as ModalIface} from 'state/models/ui/shell'
|
||||
import {isMobileWeb} from 'platform/detection'
|
||||
|
||||
import * as ConfirmModal from './Confirm'
|
||||
import * as EditProfileModal from './EditProfile'
|
||||
|
@ -47,6 +47,7 @@ export const ModalsContainer = observer(function ModalsContainer() {
|
|||
function Modal({modal}: {modal: ModalIface}) {
|
||||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
|
||||
if (!store.shell.isModalActive) {
|
||||
return null
|
||||
|
@ -119,7 +120,7 @@ function Modal({modal}: {modal: ModalIface}) {
|
|||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
isMobileWeb && styles.containerMobile,
|
||||
isMobile && styles.containerMobile,
|
||||
pal.view,
|
||||
pal.border,
|
||||
]}>
|
||||
|
|
|
@ -2,11 +2,12 @@ import React from 'react'
|
|||
import {StyleSheet, View} from 'react-native'
|
||||
import {ModerationUI} from '@atproto/api'
|
||||
import {useStores} from 'state/index'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {s} from 'lib/styles'
|
||||
import {Text} from '../util/text/Text'
|
||||
import {TextLink} from '../util/Link'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {isWeb} from 'platform/detection'
|
||||
import {listUriToHref} from 'lib/strings/url-helpers'
|
||||
import {Button} from '../util/forms/Button'
|
||||
|
||||
|
@ -20,6 +21,7 @@ export function Component({
|
|||
moderation: ModerationUI
|
||||
}) {
|
||||
const store = useStores()
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const pal = usePalette('default')
|
||||
|
||||
let name
|
||||
|
@ -64,7 +66,15 @@ export function Component({
|
|||
}
|
||||
|
||||
return (
|
||||
<View testID="moderationDetailsModal" style={[styles.container, pal.view]}>
|
||||
<View
|
||||
testID="moderationDetailsModal"
|
||||
style={[
|
||||
styles.container,
|
||||
{
|
||||
paddingHorizontal: isMobile ? 14 : 0,
|
||||
},
|
||||
pal.view,
|
||||
]}>
|
||||
<Text type="title-xl" style={[pal.text, styles.title]}>
|
||||
{name}
|
||||
</Text>
|
||||
|
@ -87,7 +97,6 @@ export function Component({
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
paddingHorizontal: isDesktopWeb ? 0 : 14,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
|
@ -99,7 +108,7 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
btn: {
|
||||
paddingVertical: 14,
|
||||
marginTop: isDesktopWeb ? 40 : 0,
|
||||
marginBottom: isDesktopWeb ? 0 : 40,
|
||||
marginTop: isWeb ? 40 : 0,
|
||||
marginBottom: isWeb ? 0 : 40,
|
||||
},
|
||||
})
|
||||
|
|
|
@ -5,7 +5,8 @@ import {Text} from '../util/text/Text'
|
|||
import {useStores} from 'state/index'
|
||||
import {s, colors} from 'lib/styles'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {isWeb} from 'platform/detection'
|
||||
import {Button} from '../util/forms/Button'
|
||||
import {SelectableBtn} from '../util/forms/SelectableBtn'
|
||||
import {ScrollView} from 'view/com/modals/util'
|
||||
|
@ -25,6 +26,7 @@ export const Component = observer(function Component({
|
|||
}) {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const [selected, setSelected] = useState(labels)
|
||||
|
||||
const toggleAdultLabel = (label: string) => {
|
||||
|
@ -54,7 +56,12 @@ export const Component = observer(function Component({
|
|||
</View>
|
||||
|
||||
<ScrollView>
|
||||
<View style={[styles.section, pal.border, {borderBottomWidth: 1}]}>
|
||||
<View
|
||||
style={[
|
||||
styles.section,
|
||||
pal.border,
|
||||
{borderBottomWidth: 1, paddingHorizontal: isMobile ? 20 : 0},
|
||||
]}>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
|
@ -152,11 +159,11 @@ export const Component = observer(function Component({
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
paddingBottom: isDesktopWeb ? 0 : 40,
|
||||
paddingBottom: isWeb ? 0 : 40,
|
||||
},
|
||||
titleSection: {
|
||||
paddingTop: isDesktopWeb ? 0 : 4,
|
||||
paddingBottom: isDesktopWeb ? 14 : 10,
|
||||
paddingTop: isWeb ? 0 : 4,
|
||||
paddingBottom: isWeb ? 14 : 10,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
|
@ -170,7 +177,6 @@ const styles = StyleSheet.create({
|
|||
section: {
|
||||
borderTopWidth: 1,
|
||||
paddingVertical: 20,
|
||||
paddingHorizontal: isDesktopWeb ? 0 : 20,
|
||||
},
|
||||
adultExplainer: {
|
||||
paddingLeft: 5,
|
||||
|
|
|
@ -2,8 +2,8 @@ import React from 'react'
|
|||
import {StyleSheet, Text, View, Pressable} from 'react-native'
|
||||
import LinearGradient from 'react-native-linear-gradient'
|
||||
import {s, colors, gradients} from 'lib/styles'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
|
||||
export const ConfirmLanguagesButton = ({
|
||||
onPress,
|
||||
|
@ -13,8 +13,17 @@ export const ConfirmLanguagesButton = ({
|
|||
extraText?: string
|
||||
}) => {
|
||||
const pal = usePalette('default')
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
return (
|
||||
<View style={[styles.btnContainer, pal.borderDark]}>
|
||||
<View
|
||||
style={[
|
||||
styles.btnContainer,
|
||||
pal.borderDark,
|
||||
isMobile && {
|
||||
paddingBottom: 40,
|
||||
borderTopWidth: 1,
|
||||
},
|
||||
]}>
|
||||
<Pressable
|
||||
testID="confirmContentLanguagesBtn"
|
||||
onPress={onPress}
|
||||
|
@ -37,8 +46,6 @@ const styles = StyleSheet.create({
|
|||
btnContainer: {
|
||||
paddingTop: 10,
|
||||
paddingHorizontal: 10,
|
||||
paddingBottom: isDesktopWeb ? 0 : 40,
|
||||
borderTopWidth: isDesktopWeb ? 0 : 1,
|
||||
},
|
||||
btn: {
|
||||
flexDirection: 'row',
|
||||
|
|
|
@ -4,7 +4,8 @@ import {ScrollView} from '../util'
|
|||
import {useStores} from 'state/index'
|
||||
import {Text} from '../../util/text/Text'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {isDesktopWeb, deviceLocales} from 'platform/detection'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {deviceLocales} from 'platform/detection'
|
||||
import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages'
|
||||
import {LanguageToggle} from './LanguageToggle'
|
||||
import {ConfirmLanguagesButton} from './ConfirmLanguagesButton'
|
||||
|
@ -14,6 +15,7 @@ export const snapPoints = ['100%']
|
|||
export function Component({}: {}) {
|
||||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const onPressDone = React.useCallback(() => {
|
||||
store.shell.closeModal()
|
||||
}, [store])
|
||||
|
@ -47,7 +49,19 @@ export function Component({}: {}) {
|
|||
)
|
||||
|
||||
return (
|
||||
<View testID="contentLanguagesModal" style={[pal.view, styles.container]}>
|
||||
<View
|
||||
testID="contentLanguagesModal"
|
||||
style={[
|
||||
pal.view,
|
||||
styles.container,
|
||||
isMobile
|
||||
? {
|
||||
paddingTop: 20,
|
||||
}
|
||||
: {
|
||||
maxHeight: '90vh',
|
||||
},
|
||||
]}>
|
||||
<Text style={[pal.text, styles.title]}>Content Languages</Text>
|
||||
<Text style={[pal.text, styles.description]}>
|
||||
Which languages would you like to see in your algorithmic feeds?
|
||||
|
@ -67,7 +81,11 @@ export function Component({}: {}) {
|
|||
}}
|
||||
/>
|
||||
))}
|
||||
<View style={styles.bottomSpacer} />
|
||||
<View
|
||||
style={{
|
||||
height: isMobile ? 60 : 0,
|
||||
}}
|
||||
/>
|
||||
</ScrollView>
|
||||
<ConfirmLanguagesButton onPress={onPressDone} />
|
||||
</View>
|
||||
|
@ -77,7 +95,6 @@ export function Component({}: {}) {
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
paddingTop: 20,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
|
@ -94,7 +111,4 @@ const styles = StyleSheet.create({
|
|||
flex: 1,
|
||||
paddingHorizontal: 10,
|
||||
},
|
||||
bottomSpacer: {
|
||||
height: isDesktopWeb ? 0 : 60,
|
||||
},
|
||||
})
|
||||
|
|
|
@ -5,7 +5,8 @@ import {ScrollView} from '../util'
|
|||
import {useStores} from 'state/index'
|
||||
import {Text} from '../../util/text/Text'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {isDesktopWeb, deviceLocales} from 'platform/detection'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {deviceLocales} from 'platform/detection'
|
||||
import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages'
|
||||
import {ConfirmLanguagesButton} from './ConfirmLanguagesButton'
|
||||
import {ToggleButton} from 'view/com/util/forms/ToggleButton'
|
||||
|
@ -15,6 +16,7 @@ export const snapPoints = ['100%']
|
|||
export const Component = observer(() => {
|
||||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const onPressDone = React.useCallback(() => {
|
||||
store.shell.closeModal()
|
||||
}, [store])
|
||||
|
@ -48,7 +50,19 @@ export const Component = observer(() => {
|
|||
)
|
||||
|
||||
return (
|
||||
<View testID="postLanguagesModal" style={[pal.view, styles.container]}>
|
||||
<View
|
||||
testID="postLanguagesModal"
|
||||
style={[
|
||||
pal.view,
|
||||
styles.container,
|
||||
isMobile
|
||||
? {
|
||||
paddingTop: 20,
|
||||
}
|
||||
: {
|
||||
maxHeight: '90vh',
|
||||
},
|
||||
]}>
|
||||
<Text style={[pal.text, styles.title]}>Post Languages</Text>
|
||||
<Text style={[pal.text, styles.description]}>
|
||||
Which languages are used in this post?
|
||||
|
@ -80,7 +94,11 @@ export const Component = observer(() => {
|
|||
/>
|
||||
)
|
||||
})}
|
||||
<View style={styles.bottomSpacer} />
|
||||
<View
|
||||
style={{
|
||||
height: isMobile ? 60 : 0,
|
||||
}}
|
||||
/>
|
||||
</ScrollView>
|
||||
<ConfirmLanguagesButton onPress={onPressDone} />
|
||||
</View>
|
||||
|
@ -90,7 +108,6 @@ export const Component = observer(() => {
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
paddingTop: 20,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
|
@ -107,9 +124,6 @@ const styles = StyleSheet.create({
|
|||
flex: 1,
|
||||
paddingHorizontal: 10,
|
||||
},
|
||||
bottomSpacer: {
|
||||
height: isDesktopWeb ? 0 : 60,
|
||||
},
|
||||
languageToggle: {
|
||||
borderTopWidth: 1,
|
||||
borderRadius: 0,
|
||||
|
|
|
@ -5,9 +5,9 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
|||
import {CharProgress} from '../../composer/char-progress/CharProgress'
|
||||
import {Text} from '../../util/text/Text'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {s} from 'lib/styles'
|
||||
import {SendReportButton} from './SendReportButton'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
|
||||
export function InputIssueDetails({
|
||||
details,
|
||||
|
@ -23,9 +23,13 @@ export function InputIssueDetails({
|
|||
isProcessing: boolean
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
|
||||
return (
|
||||
<View style={[styles.detailsContainer]}>
|
||||
<View
|
||||
style={{
|
||||
marginTop: isMobile ? 12 : 0,
|
||||
}}>
|
||||
<TouchableOpacity
|
||||
testID="addDetailsBtn"
|
||||
style={[s.mb10, styles.backBtn]}
|
||||
|
@ -63,9 +67,6 @@ export function InputIssueDetails({
|
|||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
detailsContainer: {
|
||||
marginTop: isDesktopWeb ? 0 : 12,
|
||||
},
|
||||
backBtn: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
|
|
|
@ -3,6 +3,7 @@ import {Linking, StyleSheet, TouchableOpacity, View} from 'react-native'
|
|||
import {ScrollView} from 'react-native-gesture-handler'
|
||||
import {AtUri} from '@atproto/api'
|
||||
import {useStores} from 'state/index'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {s} from 'lib/styles'
|
||||
import {Text} from '../../util/text/Text'
|
||||
import * as Toast from '../../util/Toast'
|
||||
|
@ -37,6 +38,7 @@ type ReportComponentProps =
|
|||
export function Component(content: ReportComponentProps) {
|
||||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const [isProcessing, setIsProcessing] = useState(false)
|
||||
const [showDetailsInput, setShowDetailsInput] = useState(false)
|
||||
const [error, setError] = useState<string>()
|
||||
|
@ -87,7 +89,13 @@ export function Component(content: ReportComponentProps) {
|
|||
|
||||
return (
|
||||
<ScrollView testID="reportModal" style={[s.flex1, pal.view]}>
|
||||
<View style={styles.container}>
|
||||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
isMobile && {
|
||||
paddingBottom: 40,
|
||||
},
|
||||
]}>
|
||||
{showDetailsInput ? (
|
||||
<InputIssueDetails
|
||||
details={details}
|
||||
|
@ -153,16 +161,14 @@ const SelectIssue = ({
|
|||
<Text style={[pal.textLight, styles.description]}>
|
||||
What is the issue with this {collectionName}?
|
||||
</Text>
|
||||
<ReportReasonOptions
|
||||
atUri={atUri}
|
||||
selectedIssue={issue}
|
||||
onSelectIssue={onSelectIssue}
|
||||
/>
|
||||
{error ? (
|
||||
<View style={s.mt10}>
|
||||
<ErrorMessage message={error} />
|
||||
</View>
|
||||
) : undefined}
|
||||
<View style={{marginBottom: 10}}>
|
||||
<ReportReasonOptions
|
||||
atUri={atUri}
|
||||
selectedIssue={issue}
|
||||
onSelectIssue={onSelectIssue}
|
||||
/>
|
||||
</View>
|
||||
{error ? <ErrorMessage message={error} /> : undefined}
|
||||
{/* If no atUri is present, the report would be for account in which case, we allow sending without specifying a reason */}
|
||||
{issue || !atUri ? (
|
||||
<>
|
||||
|
@ -188,7 +194,6 @@ const SelectIssue = ({
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
paddingHorizontal: 10,
|
||||
paddingBottom: 40,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
|
|
|
@ -13,8 +13,8 @@ export const FeedsTabBar = observer(
|
|||
(
|
||||
props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void},
|
||||
) => {
|
||||
const {isDesktop} = useWebMediaQueries()
|
||||
if (!isDesktop) {
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
if (isMobile) {
|
||||
return <FeedsTabBarMobile {...props} />
|
||||
} else {
|
||||
return <FeedsTabBarDesktop {...props} />
|
||||
|
|
|
@ -3,7 +3,8 @@ import {StyleSheet, View, ScrollView, LayoutChangeEvent} from 'react-native'
|
|||
import {Text} from '../util/text/Text'
|
||||
import {PressableWithHover} from '../util/PressableWithHover'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {isDesktopWeb, isMobileWeb} from 'platform/detection'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {isWeb} from 'platform/detection'
|
||||
import {DraggableScrollView} from './DraggableScrollView'
|
||||
|
||||
export interface TabBarProps {
|
||||
|
@ -30,6 +31,7 @@ export function TabBar({
|
|||
() => ({borderBottomColor: indicatorColor || pal.colors.link}),
|
||||
[indicatorColor, pal],
|
||||
)
|
||||
const {isDesktop, isTablet} = useWebMediaQueries()
|
||||
|
||||
// scrolls to the selected item when the page changes
|
||||
useEffect(() => {
|
||||
|
@ -61,6 +63,7 @@ export function TabBar({
|
|||
[],
|
||||
)
|
||||
|
||||
const styles = isDesktop || isTablet ? desktopStyles : mobileStyles
|
||||
return (
|
||||
<View testID={testID} style={[pal.view, styles.outer]}>
|
||||
<DraggableScrollView
|
||||
|
@ -78,7 +81,7 @@ export function TabBar({
|
|||
hoverStyle={pal.viewLight}
|
||||
onPress={() => onPressItem(i)}>
|
||||
<Text
|
||||
type={isDesktopWeb ? 'xl-bold' : 'lg-bold'}
|
||||
type={isDesktop || isTablet ? 'xl-bold' : 'lg-bold'}
|
||||
testID={testID ? `${testID}-${item}` : undefined}
|
||||
style={selected ? pal.text : pal.textLight}>
|
||||
{item}
|
||||
|
@ -91,46 +94,46 @@ export function TabBar({
|
|||
)
|
||||
}
|
||||
|
||||
const styles = isDesktopWeb
|
||||
? StyleSheet.create({
|
||||
outer: {
|
||||
flexDirection: 'row',
|
||||
width: 598,
|
||||
},
|
||||
contentContainer: {
|
||||
columnGap: 8,
|
||||
marginLeft: 14,
|
||||
paddingRight: 14,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
item: {
|
||||
paddingTop: 14,
|
||||
paddingBottom: 12,
|
||||
paddingHorizontal: 10,
|
||||
borderBottomWidth: 3,
|
||||
borderBottomColor: 'transparent',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
})
|
||||
: StyleSheet.create({
|
||||
outer: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
backgroundColor: 'transparent',
|
||||
maxWidth: '100%',
|
||||
},
|
||||
contentContainer: {
|
||||
columnGap: isMobileWeb ? 0 : 20,
|
||||
marginLeft: isMobileWeb ? 0 : 18,
|
||||
paddingRight: isMobileWeb ? 0 : 36,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
item: {
|
||||
paddingTop: 10,
|
||||
paddingBottom: 10,
|
||||
paddingHorizontal: isMobileWeb ? 8 : 0,
|
||||
borderBottomWidth: 3,
|
||||
borderBottomColor: 'transparent',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
})
|
||||
const desktopStyles = StyleSheet.create({
|
||||
outer: {
|
||||
flexDirection: 'row',
|
||||
width: 598,
|
||||
},
|
||||
contentContainer: {
|
||||
columnGap: 8,
|
||||
marginLeft: 14,
|
||||
paddingRight: 14,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
item: {
|
||||
paddingTop: 14,
|
||||
paddingBottom: 12,
|
||||
paddingHorizontal: 10,
|
||||
borderBottomWidth: 3,
|
||||
borderBottomColor: 'transparent',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
})
|
||||
|
||||
const mobileStyles = StyleSheet.create({
|
||||
outer: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
backgroundColor: 'transparent',
|
||||
maxWidth: '100%',
|
||||
},
|
||||
contentContainer: {
|
||||
columnGap: isWeb ? 0 : 20,
|
||||
marginLeft: isWeb ? 0 : 18,
|
||||
paddingRight: isWeb ? 0 : 36,
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
item: {
|
||||
paddingTop: 10,
|
||||
paddingBottom: 10,
|
||||
paddingHorizontal: isWeb ? 8 : 0,
|
||||
borderBottomWidth: 3,
|
||||
borderBottomColor: 'transparent',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
})
|
||||
|
|
|
@ -18,18 +18,24 @@ import {
|
|||
} from '@fortawesome/react-native-fontawesome'
|
||||
import {PostThreadItem} from './PostThreadItem'
|
||||
import {ComposePrompt} from '../composer/Prompt'
|
||||
import {ViewHeader} from '../util/ViewHeader'
|
||||
import {ErrorMessage} from '../util/error/ErrorMessage'
|
||||
import {Text} from '../util/text/Text'
|
||||
import {s} from 'lib/styles'
|
||||
import {isIOS, isDesktopWeb, isMobileWeb} from 'platform/detection'
|
||||
import {isIOS, isDesktopWeb} from 'platform/detection'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useSetTitle} from 'lib/hooks/useSetTitle'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||
|
||||
const MAINTAIN_VISIBLE_CONTENT_POSITION = {minIndexForVisible: 0}
|
||||
|
||||
const TOP_COMPONENT = {
|
||||
_reactKey: '__top_component__',
|
||||
_isHighlightedPost: false,
|
||||
}
|
||||
const PARENT_SPINNER = {
|
||||
_reactKey: '__parent_spinner__',
|
||||
_isHighlightedPost: false,
|
||||
|
@ -47,6 +53,7 @@ const BOTTOM_COMPONENT = {
|
|||
}
|
||||
type YieldedItem =
|
||||
| PostThreadItemModel
|
||||
| typeof TOP_COMPONENT
|
||||
| typeof PARENT_SPINNER
|
||||
| typeof REPLY_PROMPT
|
||||
| typeof DELETED
|
||||
|
@ -63,13 +70,14 @@ export const PostThread = observer(function PostThread({
|
|||
onPressReply: () => void
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
const {isTablet} = useWebMediaQueries()
|
||||
const ref = useRef<FlatList>(null)
|
||||
const hasScrolledIntoView = useRef<boolean>(false)
|
||||
const [isRefreshing, setIsRefreshing] = React.useState(false)
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const posts = React.useMemo(() => {
|
||||
if (view.thread) {
|
||||
const arr = Array.from(flattenThread(view.thread))
|
||||
const arr = [TOP_COMPONENT].concat(Array.from(flattenThread(view.thread)))
|
||||
if (view.isLoadingFromCache) {
|
||||
if (view.thread?.postRecord?.reply) {
|
||||
arr.unshift(PARENT_SPINNER)
|
||||
|
@ -158,7 +166,9 @@ export const PostThread = observer(function PostThread({
|
|||
|
||||
const renderItem = React.useCallback(
|
||||
({item, index}: {item: YieldedItem; index: number}) => {
|
||||
if (item === PARENT_SPINNER) {
|
||||
if (item === TOP_COMPONENT) {
|
||||
return isTablet ? <ViewHeader title="Post" /> : null
|
||||
} else if (item === PARENT_SPINNER) {
|
||||
return (
|
||||
<View style={styles.parentSpinner}>
|
||||
<ActivityIndicator />
|
||||
|
@ -186,19 +196,8 @@ export const PostThread = observer(function PostThread({
|
|||
// HACK
|
||||
// due to some complexities with how flatlist works, this is the easiest way
|
||||
// I could find to get a border positioned directly under the last item
|
||||
// -
|
||||
// addendum -- it's also the best way to get mobile web to add padding
|
||||
// at the bottom of the thread since paddingbottom is ignored. yikes.
|
||||
// -prf
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
styles.bottomBorder,
|
||||
pal.border,
|
||||
isMobileWeb && styles.bottomSpacer,
|
||||
]}
|
||||
/>
|
||||
)
|
||||
return <View style={[pal.border, styles.bottomSpacer]} />
|
||||
} else if (item === CHILD_SPINNER) {
|
||||
return (
|
||||
<View style={styles.childSpinner}>
|
||||
|
@ -219,7 +218,7 @@ export const PostThread = observer(function PostThread({
|
|||
}
|
||||
return <></>
|
||||
},
|
||||
[onRefresh, onPressReply, pal, posts],
|
||||
[onRefresh, onPressReply, pal, posts, isTablet],
|
||||
)
|
||||
|
||||
// loading
|
||||
|
@ -331,7 +330,6 @@ export const PostThread = observer(function PostThread({
|
|||
}
|
||||
onScrollToIndexFailed={onScrollToIndexFailed}
|
||||
style={s.hContentRegion}
|
||||
contentContainerStyle={styles.contentContainerExtra}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
@ -384,13 +382,8 @@ const styles = StyleSheet.create({
|
|||
paddingVertical: 10,
|
||||
},
|
||||
childSpinner: {},
|
||||
bottomBorder: {
|
||||
borderBottomWidth: 1,
|
||||
},
|
||||
bottomSpacer: {
|
||||
height: 400,
|
||||
},
|
||||
contentContainerExtra: {
|
||||
paddingBottom: 500,
|
||||
borderTopWidth: 1,
|
||||
},
|
||||
})
|
||||
|
|
|
@ -22,7 +22,7 @@ import {s} from 'lib/styles'
|
|||
import {useAnalytics} from 'lib/analytics/analytics'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useTheme} from 'lib/ThemeContext'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {CogIcon} from 'lib/icons'
|
||||
|
||||
export const MultiFeed = observer(function Feed({
|
||||
|
@ -48,6 +48,7 @@ export const MultiFeed = observer(function Feed({
|
|||
}) {
|
||||
const pal = usePalette('default')
|
||||
const theme = useTheme()
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const {track} = useAnalytics()
|
||||
const [isRefreshing, setIsRefreshing] = React.useState(false)
|
||||
|
||||
|
@ -80,19 +81,27 @@ export const MultiFeed = observer(function Feed({
|
|||
const renderItem = React.useCallback(
|
||||
({item}: {item: MultiFeedItem}) => {
|
||||
if (item.type === 'header') {
|
||||
if (isDesktopWeb) {
|
||||
if (!isMobile) {
|
||||
return (
|
||||
<View style={[pal.view, pal.border, styles.headerDesktop]}>
|
||||
<Text type="2xl-bold" style={pal.text}>
|
||||
My Feeds
|
||||
</Text>
|
||||
<Link href="/settings/saved-feeds">
|
||||
<CogIcon strokeWidth={1.5} style={pal.icon} size={28} />
|
||||
</Link>
|
||||
</View>
|
||||
<>
|
||||
<View style={[pal.view, pal.border, styles.headerDesktop]}>
|
||||
<Text type="2xl-bold" style={pal.text}>
|
||||
My Feeds
|
||||
</Text>
|
||||
<Link href="/settings/saved-feeds">
|
||||
<CogIcon strokeWidth={1.5} style={pal.icon} size={28} />
|
||||
</Link>
|
||||
</View>
|
||||
<DiscoverLink />
|
||||
</>
|
||||
)
|
||||
}
|
||||
return <View style={[styles.header, pal.border]} />
|
||||
return (
|
||||
<>
|
||||
<View style={[styles.header, pal.border]} />
|
||||
<DiscoverLink />
|
||||
</>
|
||||
)
|
||||
} else if (item.type === 'feed-header') {
|
||||
return (
|
||||
<View style={styles.feedHeader}>
|
||||
|
@ -124,18 +133,11 @@ export const MultiFeed = observer(function Feed({
|
|||
</Link>
|
||||
)
|
||||
} else if (item.type === 'footer') {
|
||||
return (
|
||||
<Link style={[styles.footerLink, pal.viewLight]} href="/search/feeds">
|
||||
<FontAwesomeIcon icon="search" size={18} color={pal.colors.text} />
|
||||
<Text type="xl-medium" style={pal.text}>
|
||||
Discover new feeds
|
||||
</Text>
|
||||
</Link>
|
||||
)
|
||||
return <DiscoverLink />
|
||||
}
|
||||
return null
|
||||
},
|
||||
[pal],
|
||||
[pal, isMobile],
|
||||
)
|
||||
|
||||
const ListFooter = React.useCallback(
|
||||
|
@ -150,17 +152,6 @@ export const MultiFeed = observer(function Feed({
|
|||
[multifeed.isLoading, isRefreshing, pal],
|
||||
)
|
||||
|
||||
const ListHeader = React.useCallback(() => {
|
||||
return (
|
||||
<Link style={[styles.footerLink, pal.viewLight]} href="/search/feeds">
|
||||
<FontAwesomeIcon icon="search" size={18} color={pal.colors.text} />
|
||||
<Text type="xl-medium" style={pal.text}>
|
||||
Discover new feeds
|
||||
</Text>
|
||||
</Link>
|
||||
)
|
||||
}, [pal])
|
||||
|
||||
return (
|
||||
<View testID={testID} style={style}>
|
||||
{multifeed.items.length > 0 && (
|
||||
|
@ -171,7 +162,6 @@ export const MultiFeed = observer(function Feed({
|
|||
keyExtractor={item => item._reactKey}
|
||||
renderItem={renderItem}
|
||||
ListFooterComponent={ListFooter}
|
||||
ListHeaderComponent={ListHeader}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={isRefreshing}
|
||||
|
@ -199,6 +189,18 @@ export const MultiFeed = observer(function Feed({
|
|||
)
|
||||
})
|
||||
|
||||
function DiscoverLink() {
|
||||
const pal = usePalette('default')
|
||||
return (
|
||||
<Link style={[styles.discoverLink, pal.viewLight]} href="/search/feeds">
|
||||
<FontAwesomeIcon icon="search" size={18} color={pal.colors.text} />
|
||||
<Text type="xl-medium" style={pal.text}>
|
||||
Discover new feeds
|
||||
</Text>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
height: '100%',
|
||||
|
@ -237,7 +239,7 @@ const styles = StyleSheet.create({
|
|||
borderTopWidth: 1,
|
||||
borderBottomWidth: 1,
|
||||
},
|
||||
footerLink: {
|
||||
discoverLink: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
|
|
|
@ -27,8 +27,9 @@ import {UserBanner} from '../util/UserBanner'
|
|||
import {ProfileHeaderAlerts} from '../util/moderation/ProfileHeaderAlerts'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useAnalytics} from 'lib/analytics/analytics'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
import {isDesktopWeb, isNative} from 'platform/detection'
|
||||
import {isNative} from 'platform/detection'
|
||||
import {FollowState} from 'state/models/cache/my-follows'
|
||||
import {shareUrl} from 'lib/sharing'
|
||||
import {formatCount} from '../util/numeric/format'
|
||||
|
@ -108,6 +109,7 @@ const ProfileHeaderLoaded = observer(
|
|||
const navigation = useNavigation<NavigationProp>()
|
||||
const {track} = useAnalytics()
|
||||
const invalidHandle = isInvalidHandle(view.handle)
|
||||
const {isDesktop} = useWebMediaQueries()
|
||||
|
||||
const onPressBack = React.useCallback(() => {
|
||||
navigation.goBack()
|
||||
|
@ -510,7 +512,7 @@ const ProfileHeaderLoaded = observer(
|
|||
)}
|
||||
<ProfileHeaderAlerts moderation={view.moderation} />
|
||||
</View>
|
||||
{!isDesktopWeb && !hideBackButton && (
|
||||
{!isDesktop && !hideBackButton && (
|
||||
<TouchableWithoutFeedback
|
||||
onPress={onPressBack}
|
||||
hitSlop={BACK_HITSLOP}
|
||||
|
|
|
@ -10,6 +10,7 @@ import {useTheme} from 'lib/ThemeContext'
|
|||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useStores} from 'state/index'
|
||||
import {useAnalytics} from 'lib/analytics/analytics'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {HITSLOP_10} from 'lib/constants'
|
||||
|
||||
interface Props {
|
||||
|
@ -37,6 +38,7 @@ export function HeaderWithInput({
|
|||
const pal = usePalette('default')
|
||||
const {track} = useAnalytics()
|
||||
const textInput = React.useRef<TextInput>(null)
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
|
||||
const onPressMenu = React.useCallback(() => {
|
||||
track('ViewHeader:MenuButtonClicked')
|
||||
|
@ -49,8 +51,14 @@ export function HeaderWithInput({
|
|||
}, [onPressCancelSearch, textInput])
|
||||
|
||||
return (
|
||||
<View style={[pal.view, pal.border, styles.header]}>
|
||||
{showMenu ? (
|
||||
<View
|
||||
style={[
|
||||
pal.view,
|
||||
pal.border,
|
||||
styles.header,
|
||||
!isMobile && styles.headerDesktop,
|
||||
]}>
|
||||
{showMenu && isMobile ? (
|
||||
<TouchableOpacity
|
||||
testID="viewHeaderBackOrMenuBtn"
|
||||
onPress={onPressMenu}
|
||||
|
@ -85,7 +93,7 @@ export function HeaderWithInput({
|
|||
onBlur={() => setIsInputFocused(false)}
|
||||
onChangeText={onChangeQuery}
|
||||
onSubmitEditing={onSubmitQuery}
|
||||
autoFocus={true}
|
||||
autoFocus={isMobile}
|
||||
accessibilityRole="search"
|
||||
accessibilityLabel="Search"
|
||||
accessibilityHint=""
|
||||
|
@ -127,6 +135,11 @@ const styles = StyleSheet.create({
|
|||
paddingHorizontal: 12,
|
||||
paddingVertical: 4,
|
||||
},
|
||||
headerDesktop: {
|
||||
borderWidth: 1,
|
||||
borderTopWidth: 0,
|
||||
paddingVertical: 10,
|
||||
},
|
||||
headerMenuBtn: {
|
||||
width: 30,
|
||||
height: 30,
|
||||
|
|
|
@ -13,13 +13,14 @@ import {
|
|||
} from 'view/com/util/LoadingPlaceholder'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {s} from 'lib/styles'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
|
||||
const SECTIONS = ['Posts', 'Users']
|
||||
|
||||
export const SearchResults = observer(({model}: {model: SearchUIModel}) => {
|
||||
const pal = usePalette('default')
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
|
||||
const renderTabBar = React.useCallback(
|
||||
(props: RenderTabBarFnProps) => {
|
||||
|
@ -39,10 +40,16 @@ export const SearchResults = observer(({model}: {model: SearchUIModel}) => {
|
|||
|
||||
return (
|
||||
<Pager renderTabBar={renderTabBar} tabBarPosition="top" initialPage={0}>
|
||||
<View style={[styles.results]}>
|
||||
<View
|
||||
style={{
|
||||
paddingTop: isMobile ? 42 : 50,
|
||||
}}>
|
||||
<PostResults key="0" model={model} />
|
||||
</View>
|
||||
<View style={[styles.results]}>
|
||||
<View
|
||||
style={{
|
||||
paddingTop: isMobile ? 42 : 50,
|
||||
}}>
|
||||
<Profiles key="1" model={model} />
|
||||
</View>
|
||||
</Pager>
|
||||
|
@ -128,7 +135,4 @@ const styles = StyleSheet.create({
|
|||
paddingHorizontal: 14,
|
||||
paddingVertical: 16,
|
||||
},
|
||||
results: {
|
||||
paddingTop: isDesktopWeb ? 50 : 42,
|
||||
},
|
||||
})
|
||||
|
|
|
@ -8,9 +8,9 @@ import {Text} from './text/Text'
|
|||
import {useStores} from 'state/index'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useAnimatedValue} from 'lib/hooks/useAnimatedValue'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {useAnalytics} from 'lib/analytics/analytics'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
|
||||
const BACK_HITSLOP = {left: 20, top: 20, right: 50, bottom: 20}
|
||||
|
||||
|
@ -35,6 +35,7 @@ export const ViewHeader = observer(function ({
|
|||
const store = useStores()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const {track} = useAnalytics()
|
||||
const {isDesktop, isTablet} = useWebMediaQueries()
|
||||
|
||||
const onPressBack = React.useCallback(() => {
|
||||
if (navigation.canGoBack()) {
|
||||
|
@ -49,7 +50,7 @@ export const ViewHeader = observer(function ({
|
|||
store.shell.openDrawer()
|
||||
}, [track, store])
|
||||
|
||||
if (isDesktopWeb) {
|
||||
if (isDesktop) {
|
||||
if (showOnDesktop) {
|
||||
return (
|
||||
<DesktopWebHeader
|
||||
|
@ -84,13 +85,13 @@ export const ViewHeader = observer(function ({
|
|||
icon="angle-left"
|
||||
style={[styles.backIcon, pal.text]}
|
||||
/>
|
||||
) : (
|
||||
) : !isTablet ? (
|
||||
<FontAwesomeIcon
|
||||
size={18}
|
||||
icon="bars"
|
||||
style={[styles.backIcon, pal.textLight]}
|
||||
/>
|
||||
)}
|
||||
) : null}
|
||||
</TouchableOpacity>
|
||||
) : null}
|
||||
<View style={styles.titleContainer} pointerEvents="none">
|
||||
|
@ -122,6 +123,7 @@ function DesktopWebHeader({
|
|||
<CenteredView
|
||||
style={[
|
||||
styles.header,
|
||||
styles.headerFixed,
|
||||
styles.desktopHeader,
|
||||
pal.border,
|
||||
{
|
||||
|
@ -178,6 +180,7 @@ const Container = observer(
|
|||
<View
|
||||
style={[
|
||||
styles.header,
|
||||
styles.headerFixed,
|
||||
pal.view,
|
||||
pal.border,
|
||||
showBorder && styles.border,
|
||||
|
@ -190,9 +193,9 @@ const Container = observer(
|
|||
<Animated.View
|
||||
style={[
|
||||
styles.header,
|
||||
styles.headerFloating,
|
||||
pal.view,
|
||||
pal.border,
|
||||
styles.headerFloating,
|
||||
transform,
|
||||
showBorder && styles.border,
|
||||
]}>
|
||||
|
@ -208,6 +211,12 @@ const styles = StyleSheet.create({
|
|||
alignItems: 'center',
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 6,
|
||||
width: '100%',
|
||||
},
|
||||
headerFixed: {
|
||||
maxWidth: 600,
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
},
|
||||
headerFloating: {
|
||||
position: 'absolute',
|
||||
|
|
|
@ -24,6 +24,7 @@ import {
|
|||
} from 'react-native'
|
||||
import {addStyle} from 'lib/styles'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
|
||||
interface AddedProps {
|
||||
desktopFixedHeight?: boolean
|
||||
|
@ -48,6 +49,7 @@ export const FlatList = React.forwardRef(function <ItemT>(
|
|||
ref: React.Ref<RNFlatList>,
|
||||
) {
|
||||
const pal = usePalette('default')
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
contentContainerStyle = addStyle(
|
||||
contentContainerStyle,
|
||||
styles.containerScroll,
|
||||
|
@ -67,6 +69,12 @@ export const FlatList = React.forwardRef(function <ItemT>(
|
|||
}
|
||||
if (desktopFixedHeight) {
|
||||
style = addStyle(style, styles.fixedHeight)
|
||||
if (!isMobile) {
|
||||
contentContainerStyle = addStyle(
|
||||
contentContainerStyle,
|
||||
styles.stableGutters,
|
||||
)
|
||||
}
|
||||
}
|
||||
return (
|
||||
<RNFlatList
|
||||
|
@ -126,6 +134,9 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
fixedHeight: {
|
||||
height: '100vh',
|
||||
},
|
||||
stableGutters: {
|
||||
// @ts-ignore web only -prf
|
||||
scrollbarGutter: 'stable both-edges',
|
||||
},
|
||||
})
|
||||
|
|
|
@ -5,7 +5,8 @@ import LinearGradient from 'react-native-linear-gradient'
|
|||
import {gradients} from 'lib/styles'
|
||||
import {useAnimatedValue} from 'lib/hooks/useAnimatedValue'
|
||||
import {useStores} from 'state/index'
|
||||
import {isMobileWeb} from 'platform/detection'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {isWeb} from 'platform/detection'
|
||||
|
||||
export interface FABProps
|
||||
extends ComponentProps<typeof TouchableWithoutFeedback> {
|
||||
|
@ -14,6 +15,7 @@ export interface FABProps
|
|||
}
|
||||
|
||||
export const FABInner = observer(({testID, icon, ...props}: FABProps) => {
|
||||
const {isTablet} = useWebMediaQueries()
|
||||
const store = useStores()
|
||||
const interp = useAnimatedValue(0)
|
||||
React.useEffect(() => {
|
||||
|
@ -24,18 +26,33 @@ export const FABInner = observer(({testID, icon, ...props}: FABProps) => {
|
|||
isInteraction: false,
|
||||
}).start()
|
||||
}, [interp, store.shell.minimalShellMode])
|
||||
const transform = {
|
||||
transform: [{translateY: Animated.multiply(interp, 60)}],
|
||||
}
|
||||
const transform = isTablet
|
||||
? undefined
|
||||
: {
|
||||
transform: [{translateY: Animated.multiply(interp, 60)}],
|
||||
}
|
||||
const size = isTablet ? styles.sizeLarge : styles.sizeRegular
|
||||
return (
|
||||
<TouchableWithoutFeedback testID={testID} {...props}>
|
||||
<Animated.View
|
||||
style={[styles.outer, isMobileWeb && styles.mobileWebOuter, transform]}>
|
||||
style={[
|
||||
styles.outer,
|
||||
size,
|
||||
isWeb && isTablet
|
||||
? {
|
||||
right: 50,
|
||||
bottom: 50,
|
||||
}
|
||||
: {
|
||||
bottom: 114,
|
||||
},
|
||||
transform,
|
||||
]}>
|
||||
<LinearGradient
|
||||
colors={[gradients.blueLight.start, gradients.blueLight.end]}
|
||||
start={{x: 0, y: 0}}
|
||||
end={{x: 1, y: 1}}
|
||||
style={styles.inner}>
|
||||
style={[styles.inner, size]}>
|
||||
{icon}
|
||||
</LinearGradient>
|
||||
</Animated.View>
|
||||
|
@ -44,22 +61,23 @@ export const FABInner = observer(({testID, icon, ...props}: FABProps) => {
|
|||
})
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
sizeRegular: {
|
||||
width: 60,
|
||||
height: 60,
|
||||
borderRadius: 30,
|
||||
},
|
||||
sizeLarge: {
|
||||
width: 70,
|
||||
height: 70,
|
||||
borderRadius: 35,
|
||||
},
|
||||
outer: {
|
||||
position: 'absolute',
|
||||
zIndex: 1,
|
||||
right: 24,
|
||||
bottom: 94,
|
||||
width: 60,
|
||||
height: 60,
|
||||
borderRadius: 30,
|
||||
},
|
||||
mobileWebOuter: {
|
||||
bottom: 114,
|
||||
},
|
||||
inner: {
|
||||
width: 60,
|
||||
height: 60,
|
||||
borderRadius: 30,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||
import {Pressable, ViewStyle, StyleProp, StyleSheet} from 'react-native'
|
||||
import {Text} from '../text/Text'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
|
||||
interface SelectableBtnProps {
|
||||
testID?: string
|
||||
|
@ -28,12 +28,16 @@ export function SelectableBtn({
|
|||
const pal = usePalette('default')
|
||||
const palPrimary = usePalette('inverted')
|
||||
const needsWidthStyles = !style || !('width' in style || 'flex' in style)
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
return (
|
||||
<Pressable
|
||||
testID={testID}
|
||||
style={[
|
||||
styles.btn,
|
||||
needsWidthStyles && styles.btnWidth,
|
||||
needsWidthStyles && {
|
||||
flex: isMobile ? 1 : undefined,
|
||||
width: !isMobile ? 100 : undefined,
|
||||
},
|
||||
left && styles.btnLeft,
|
||||
right && styles.btnRight,
|
||||
pal.border,
|
||||
|
@ -58,10 +62,6 @@ const styles = StyleSheet.create({
|
|||
paddingHorizontal: 10,
|
||||
paddingVertical: 10,
|
||||
},
|
||||
btnWidth: {
|
||||
flex: isDesktopWeb ? undefined : 1,
|
||||
width: isDesktopWeb ? 100 : undefined,
|
||||
},
|
||||
btnLeft: {
|
||||
borderTopLeftRadius: 8,
|
||||
borderBottomLeftRadius: 8,
|
||||
|
|
|
@ -2,18 +2,18 @@ import React from 'react'
|
|||
import MediaQuery from 'react-responsive'
|
||||
|
||||
export const Desktop = ({children}: React.PropsWithChildren<{}>) => (
|
||||
<MediaQuery minWidth={1224}>{children}</MediaQuery>
|
||||
<MediaQuery minWidth={1300}>{children}</MediaQuery>
|
||||
)
|
||||
export const TabletOrDesktop = ({children}: React.PropsWithChildren<{}>) => (
|
||||
<MediaQuery minWidth={800}>{children}</MediaQuery>
|
||||
)
|
||||
export const Tablet = ({children}: React.PropsWithChildren<{}>) => (
|
||||
<MediaQuery minWidth={800} maxWidth={1224}>
|
||||
<MediaQuery minWidth={800} maxWidth={1300}>
|
||||
{children}
|
||||
</MediaQuery>
|
||||
)
|
||||
export const TabletOrMobile = ({children}: React.PropsWithChildren<{}>) => (
|
||||
<MediaQuery maxWidth={1224}>{children}</MediaQuery>
|
||||
<MediaQuery maxWidth={1300}>{children}</MediaQuery>
|
||||
)
|
||||
export const Mobile = ({children}: React.PropsWithChildren<{}>) => (
|
||||
<MediaQuery maxWidth={800}>{children}</MediaQuery>
|
||||
|
|
|
@ -3,8 +3,8 @@ import {StyleSheet, TouchableOpacity} from 'react-native'
|
|||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {Text} from '../text/Text'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {LoadLatestBtn as LoadLatestBtnMobile} from './LoadLatestBtnMobile'
|
||||
import {isMobileWeb} from 'platform/detection'
|
||||
import {HITSLOP_20} from 'lib/constants'
|
||||
|
||||
export const LoadLatestBtn = ({
|
||||
|
@ -19,7 +19,8 @@ export const LoadLatestBtn = ({
|
|||
minimalShellMode?: boolean
|
||||
}) => {
|
||||
const pal = usePalette('default')
|
||||
if (isMobileWeb) {
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
if (isMobile) {
|
||||
return (
|
||||
<LoadLatestBtnMobile
|
||||
onPress={onPress}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import React from 'react'
|
||||
import {Pressable, StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {ModerationUI} from '@atproto/api'
|
||||
import {Text} from '../text/Text'
|
||||
import {ShieldExclamation} from 'lib/icons'
|
||||
import {describeModerationCause} from 'lib/moderation'
|
||||
import {useStores} from 'state/index'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
|
||||
export function ContentHider({
|
||||
testID,
|
||||
|
@ -24,6 +24,7 @@ export function ContentHider({
|
|||
}>) {
|
||||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const [override, setOverride] = React.useState(false)
|
||||
|
||||
if (!moderation.blur || (ignoreMute && moderation.cause?.type === 'muted')) {
|
||||
|
@ -54,6 +55,7 @@ export function ContentHider({
|
|||
accessibilityLabel=""
|
||||
style={[
|
||||
styles.cover,
|
||||
{paddingRight: isMobile ? 22 : 18},
|
||||
moderation.noOverride
|
||||
? {borderWidth: 1, borderColor: pal.colors.borderDark}
|
||||
: pal.viewLight,
|
||||
|
@ -96,7 +98,6 @@ const styles = StyleSheet.create({
|
|||
marginTop: 4,
|
||||
paddingVertical: 14,
|
||||
paddingLeft: 14,
|
||||
paddingRight: isDesktopWeb ? 18 : 22,
|
||||
},
|
||||
showBtn: {
|
||||
marginLeft: 'auto',
|
||||
|
|
|
@ -2,13 +2,13 @@ import React, {ComponentProps} from 'react'
|
|||
import {StyleSheet, Pressable, View} from 'react-native'
|
||||
import {ModerationUI} from '@atproto/api'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {Link} from '../Link'
|
||||
import {Text} from '../text/Text'
|
||||
import {addStyle} from 'lib/styles'
|
||||
import {describeModerationCause} from 'lib/moderation'
|
||||
import {ShieldExclamation} from 'lib/icons'
|
||||
import {useStores} from 'state/index'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
|
||||
interface Props extends ComponentProps<typeof Link> {
|
||||
// testID?: string
|
||||
|
@ -27,6 +27,7 @@ export function PostHider({
|
|||
}: Props) {
|
||||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const [override, setOverride] = React.useState(false)
|
||||
|
||||
if (!moderation.blur) {
|
||||
|
@ -55,7 +56,11 @@ export function PostHider({
|
|||
accessibilityRole="button"
|
||||
accessibilityHint={override ? 'Hide the content' : 'Show the content'}
|
||||
accessibilityLabel=""
|
||||
style={[styles.description, pal.viewLight]}>
|
||||
style={[
|
||||
styles.description,
|
||||
{paddingRight: isMobile ? 22 : 18},
|
||||
pal.viewLight,
|
||||
]}>
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
store.shell.openModal({
|
||||
|
@ -100,7 +105,6 @@ const styles = StyleSheet.create({
|
|||
gap: 4,
|
||||
paddingVertical: 14,
|
||||
paddingLeft: 18,
|
||||
paddingRight: isDesktopWeb ? 18 : 22,
|
||||
marginTop: 1,
|
||||
},
|
||||
showBtn: {
|
||||
|
|
|
@ -13,10 +13,10 @@ import {
|
|||
import {useNavigation} from '@react-navigation/native'
|
||||
import {ModerationUI} from '@atproto/api'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
import {Text} from '../text/Text'
|
||||
import {Button} from '../forms/Button'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {describeModerationCause} from 'lib/moderation'
|
||||
import {useStores} from 'state/index'
|
||||
|
||||
|
@ -39,6 +39,7 @@ export function ScreenHider({
|
|||
const palInverted = usePalette('inverted')
|
||||
const [override, setOverride] = React.useState(false)
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
|
||||
if (!moderation.blur || override) {
|
||||
return (
|
||||
|
@ -85,7 +86,7 @@ export function ScreenHider({
|
|||
</Text>
|
||||
</TouchableWithoutFeedback>
|
||||
</Text>
|
||||
{!isDesktopWeb && <View style={styles.spacer} />}
|
||||
{isMobile && <View style={styles.spacer} />}
|
||||
<View style={styles.btnContainer}>
|
||||
<Button
|
||||
type="inverted"
|
||||
|
|
|
@ -3,8 +3,8 @@ import {Image} from 'expo-image'
|
|||
import {Text} from '../text/Text'
|
||||
import {StyleSheet, View} from 'react-native'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {AppBskyEmbedExternal} from '@atproto/api'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {toNiceDomain} from 'lib/strings/url-helpers'
|
||||
|
||||
export const ExternalLinkEmbed = ({
|
||||
|
@ -15,10 +15,31 @@ export const ExternalLinkEmbed = ({
|
|||
imageChild?: React.ReactNode
|
||||
}) => {
|
||||
const pal = usePalette('default')
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
return (
|
||||
<View style={styles.extContainer}>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: isMobile ? 'column' : 'row',
|
||||
}}>
|
||||
{link.thumb ? (
|
||||
<View style={styles.extImageContainer}>
|
||||
<View
|
||||
style={
|
||||
!isMobile
|
||||
? {
|
||||
borderTopLeftRadius: 6,
|
||||
borderBottomLeftRadius: 6,
|
||||
width: 120,
|
||||
aspectRatio: 1,
|
||||
overflow: 'hidden',
|
||||
}
|
||||
: {
|
||||
borderTopLeftRadius: 6,
|
||||
borderTopRightRadius: 6,
|
||||
width: '100%',
|
||||
height: 200,
|
||||
overflow: 'hidden',
|
||||
}
|
||||
}>
|
||||
<Image
|
||||
style={styles.extImage}
|
||||
source={{uri: link.thumb}}
|
||||
|
@ -27,7 +48,13 @@ export const ExternalLinkEmbed = ({
|
|||
{imageChild}
|
||||
</View>
|
||||
) : undefined}
|
||||
<View style={styles.extInner}>
|
||||
<View
|
||||
style={{
|
||||
paddingHorizontal: isMobile ? 10 : 14,
|
||||
paddingTop: 8,
|
||||
paddingBottom: 10,
|
||||
flex: !isMobile ? 1 : undefined,
|
||||
}}>
|
||||
<Text
|
||||
type="sm"
|
||||
numberOfLines={1}
|
||||
|
@ -36,14 +63,14 @@ export const ExternalLinkEmbed = ({
|
|||
</Text>
|
||||
<Text
|
||||
type="lg-bold"
|
||||
numberOfLines={isDesktopWeb ? 2 : 4}
|
||||
numberOfLines={isMobile ? 4 : 2}
|
||||
style={[pal.text]}>
|
||||
{link.title || link.uri}
|
||||
</Text>
|
||||
{link.description ? (
|
||||
<Text
|
||||
type="md"
|
||||
numberOfLines={isDesktopWeb ? 2 : 4}
|
||||
numberOfLines={isMobile ? 4 : 2}
|
||||
style={[pal.text, styles.extDescription]}>
|
||||
{link.description}
|
||||
</Text>
|
||||
|
@ -54,30 +81,6 @@ export const ExternalLinkEmbed = ({
|
|||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
extContainer: {
|
||||
flexDirection: isDesktopWeb ? 'row' : 'column',
|
||||
},
|
||||
extInner: {
|
||||
paddingHorizontal: isDesktopWeb ? 14 : 10,
|
||||
paddingTop: 8,
|
||||
paddingBottom: 10,
|
||||
flex: isDesktopWeb ? 1 : undefined,
|
||||
},
|
||||
extImageContainer: isDesktopWeb
|
||||
? {
|
||||
borderTopLeftRadius: 6,
|
||||
borderBottomLeftRadius: 6,
|
||||
width: 120,
|
||||
aspectRatio: 1,
|
||||
overflow: 'hidden',
|
||||
}
|
||||
: {
|
||||
borderTopLeftRadius: 6,
|
||||
borderTopRightRadius: 6,
|
||||
width: '100%',
|
||||
height: 200,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
extImage: {
|
||||
width: '100%',
|
||||
height: 200,
|
||||
|
|
|
@ -22,6 +22,7 @@ import {ImageLayoutGrid} from '../images/ImageLayoutGrid'
|
|||
import {ImagesLightbox} from 'state/models/ui/shell'
|
||||
import {useStores} from 'state/index'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {YoutubeEmbed} from './YoutubeEmbed'
|
||||
import {ExternalLinkEmbed} from './ExternalLinkEmbed'
|
||||
import {getYoutubeVideoId} from 'lib/strings/url-helpers'
|
||||
|
@ -29,7 +30,6 @@ import {MaybeQuoteEmbed} from './QuoteEmbed'
|
|||
import {AutoSizedImage} from '../images/AutoSizedImage'
|
||||
import {CustomFeedEmbed} from './CustomFeedEmbed'
|
||||
import {ListEmbed} from './ListEmbed'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {isCauseALabelOnUri} from 'lib/moderation'
|
||||
|
||||
type Embed =
|
||||
|
@ -50,6 +50,7 @@ export function PostEmbeds({
|
|||
}) {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
|
||||
// quote post with media
|
||||
// =
|
||||
|
@ -111,7 +112,10 @@ export function PostEmbeds({
|
|||
uri={thumb}
|
||||
onPress={() => openLightbox(0)}
|
||||
onPressIn={() => onPressIn(0)}
|
||||
style={styles.singleImage}>
|
||||
style={[
|
||||
styles.singleImage,
|
||||
isMobile && styles.singleImageMobile,
|
||||
]}>
|
||||
{alt === '' ? null : (
|
||||
<View style={styles.altContainer}>
|
||||
<Text style={styles.alt} accessible={false}>
|
||||
|
@ -130,7 +134,11 @@ export function PostEmbeds({
|
|||
images={embed.images}
|
||||
onPress={openLightbox}
|
||||
onPressIn={onPressIn}
|
||||
style={embed.images.length === 1 ? styles.singleImage : undefined}
|
||||
style={
|
||||
embed.images.length === 1
|
||||
? [styles.singleImage, isMobile && styles.singleImageMobile]
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
|
@ -169,7 +177,10 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
singleImage: {
|
||||
borderRadius: 8,
|
||||
maxHeight: isDesktopWeb ? 1000 : 500,
|
||||
maxHeight: 1000,
|
||||
},
|
||||
singleImageMobile: {
|
||||
maxHeight: 500,
|
||||
},
|
||||
extOuter: {
|
||||
borderWidth: 1,
|
||||
|
|
|
@ -7,7 +7,7 @@ import {Button} from '../com/util/forms/Button'
|
|||
import * as Toast from '../com/util/Toast'
|
||||
import {useStores} from 'state/index'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||
|
@ -23,6 +23,7 @@ export const AppPasswords = withAuthRequired(
|
|||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {screen} = useAnalytics()
|
||||
const {isTabletOrDesktop} = useWebMediaQueries()
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
|
@ -41,7 +42,7 @@ export const AppPasswords = withAuthRequired(
|
|||
<CenteredView
|
||||
style={[
|
||||
styles.container,
|
||||
isDesktopWeb && styles.containerDesktop,
|
||||
isTabletOrDesktop && styles.containerDesktop,
|
||||
pal.view,
|
||||
pal.border,
|
||||
]}
|
||||
|
@ -53,11 +54,11 @@ export const AppPasswords = withAuthRequired(
|
|||
pressing the button below.
|
||||
</Text>
|
||||
</View>
|
||||
{!isDesktopWeb && <View style={styles.flex1} />}
|
||||
{!isTabletOrDesktop && <View style={styles.flex1} />}
|
||||
<View
|
||||
style={[
|
||||
styles.btnContainer,
|
||||
isDesktopWeb && styles.btnContainerDesktop,
|
||||
isTabletOrDesktop && styles.btnContainerDesktop,
|
||||
]}>
|
||||
<Button
|
||||
testID="appPasswordBtn"
|
||||
|
@ -77,7 +78,7 @@ export const AppPasswords = withAuthRequired(
|
|||
<CenteredView
|
||||
style={[
|
||||
styles.container,
|
||||
isDesktopWeb && styles.containerDesktop,
|
||||
isTabletOrDesktop && styles.containerDesktop,
|
||||
pal.view,
|
||||
pal.border,
|
||||
]}
|
||||
|
@ -87,7 +88,7 @@ export const AppPasswords = withAuthRequired(
|
|||
style={[
|
||||
styles.scrollContainer,
|
||||
pal.border,
|
||||
!isDesktopWeb && styles.flex1,
|
||||
!isTabletOrDesktop && styles.flex1,
|
||||
]}>
|
||||
{store.me.appPasswords.map((password, i) => (
|
||||
<AppPassword
|
||||
|
@ -97,7 +98,7 @@ export const AppPasswords = withAuthRequired(
|
|||
createdAt={password.createdAt}
|
||||
/>
|
||||
))}
|
||||
{isDesktopWeb && (
|
||||
{isTabletOrDesktop && (
|
||||
<View style={[styles.btnContainer, styles.btnContainerDesktop]}>
|
||||
<Button
|
||||
testID="appPasswordBtn"
|
||||
|
@ -110,7 +111,7 @@ export const AppPasswords = withAuthRequired(
|
|||
</View>
|
||||
)}
|
||||
</ScrollView>
|
||||
{!isDesktopWeb && (
|
||||
{!isTabletOrDesktop && (
|
||||
<View style={styles.btnContainer}>
|
||||
<Button
|
||||
testID="appPasswordBtn"
|
||||
|
@ -128,6 +129,7 @@ export const AppPasswords = withAuthRequired(
|
|||
)
|
||||
|
||||
function AppPasswordsHeader() {
|
||||
const {isTabletOrDesktop} = useWebMediaQueries()
|
||||
const pal = usePalette('default')
|
||||
return (
|
||||
<>
|
||||
|
@ -137,7 +139,7 @@ function AppPasswordsHeader() {
|
|||
style={[
|
||||
styles.description,
|
||||
pal.text,
|
||||
isDesktopWeb && styles.descriptionDesktop,
|
||||
isTabletOrDesktop && styles.descriptionDesktop,
|
||||
]}>
|
||||
Use app passwords to login to other Bluesky clients without giving full
|
||||
access to your account or password.
|
||||
|
@ -207,11 +209,12 @@ function AppPassword({
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
paddingBottom: isDesktopWeb ? 0 : 100,
|
||||
paddingBottom: 100,
|
||||
},
|
||||
containerDesktop: {
|
||||
borderLeftWidth: 1,
|
||||
borderRightWidth: 1,
|
||||
paddingBottom: 0,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
|
|
|
@ -22,7 +22,7 @@ import {ViewHeader} from 'view/com/util/ViewHeader'
|
|||
import {Button} from 'view/com/util/forms/Button'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import * as Toast from 'view/com/util/Toast'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {useSetTitle} from 'lib/hooks/useSetTitle'
|
||||
import {shareUrl} from 'lib/sharing'
|
||||
import {toShareUrl} from 'lib/strings/url-helpers'
|
||||
|
@ -122,6 +122,7 @@ export const CustomFeedScreenInner = observer(
|
|||
({route, feedOwnerDid}: Props & {feedOwnerDid: string}) => {
|
||||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
const {isTabletOrDesktop} = useWebMediaQueries()
|
||||
const {track} = useAnalytics()
|
||||
const {rkey, name: handleOrDid} = route.params
|
||||
const uri = useMemo(
|
||||
|
@ -357,7 +358,7 @@ export const CustomFeedScreenInner = observer(
|
|||
)}
|
||||
</Text>
|
||||
)}
|
||||
{isDesktopWeb && (
|
||||
{isTabletOrDesktop && (
|
||||
<View style={[styles.headerBtns, styles.headerBtnsDesktop]}>
|
||||
<Button
|
||||
type={currentFeed?.isSaved ? 'default' : 'inverted'}
|
||||
|
@ -452,7 +453,14 @@ export const CustomFeedScreenInner = observer(
|
|||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
<View style={[styles.fakeSelector, pal.border]}>
|
||||
<View
|
||||
style={[
|
||||
styles.fakeSelector,
|
||||
{
|
||||
paddingHorizontal: isTabletOrDesktop ? 16 : 6,
|
||||
},
|
||||
pal.border,
|
||||
]}>
|
||||
<View
|
||||
style={[styles.fakeSelectorItem, {borderColor: pal.colors.link}]}>
|
||||
<Text type="md-medium" style={[pal.text]}>
|
||||
|
@ -474,6 +482,7 @@ export const CustomFeedScreenInner = observer(
|
|||
rkey,
|
||||
isPinned,
|
||||
onTogglePinned,
|
||||
isTabletOrDesktop,
|
||||
])
|
||||
|
||||
const renderEmptyState = React.useCallback(() => {
|
||||
|
@ -486,7 +495,9 @@ export const CustomFeedScreenInner = observer(
|
|||
|
||||
return (
|
||||
<View style={s.hContentRegion}>
|
||||
<ViewHeader title="" renderButton={currentFeed && renderHeaderBtns} />
|
||||
{!isTabletOrDesktop && (
|
||||
<ViewHeader title="" renderButton={currentFeed && renderHeaderBtns} />
|
||||
)}
|
||||
<Feed
|
||||
scrollElRef={scrollElRef}
|
||||
feed={algoFeed}
|
||||
|
@ -495,6 +506,7 @@ export const CustomFeedScreenInner = observer(
|
|||
ListHeaderComponent={renderListHeaderComponent}
|
||||
renderEmptyState={renderEmptyState}
|
||||
extraData={[uri, isPinned]}
|
||||
style={!isTabletOrDesktop ? {flex: 1} : undefined}
|
||||
/>
|
||||
{isScrolledDown ? (
|
||||
<LoadLatestBtn
|
||||
|
@ -550,7 +562,6 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
fakeSelector: {
|
||||
flexDirection: 'row',
|
||||
paddingHorizontal: isDesktopWeb ? 16 : 6,
|
||||
},
|
||||
fakeSelectorItem: {
|
||||
paddingHorizontal: 12,
|
||||
|
|
|
@ -10,8 +10,8 @@ import {FeedsDiscoveryModel} from 'state/models/discovery/feeds'
|
|||
import {CenteredView, FlatList} from 'view/com/util/Views'
|
||||
import {CustomFeed} from 'view/com/feeds/CustomFeed'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {s} from 'lib/styles'
|
||||
import {CustomFeedModel} from 'state/models/feeds/custom-feed'
|
||||
import {HeaderWithInput} from 'view/com/search/HeaderWithInput'
|
||||
|
@ -23,6 +23,7 @@ export const DiscoverFeedsScreen = withAuthRequired(
|
|||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
const feeds = React.useMemo(() => new FeedsDiscoveryModel(store), [store])
|
||||
const {isTabletOrDesktop} = useWebMediaQueries()
|
||||
|
||||
// search stuff
|
||||
const [isInputFocused, setIsInputFocused] = React.useState<boolean>(false)
|
||||
|
@ -74,7 +75,7 @@ export const DiscoverFeedsScreen = withAuthRequired(
|
|||
<View style={styles.empty}>
|
||||
<Text type="lg" style={pal.textLight}>
|
||||
{feeds.isLoading
|
||||
? isDesktopWeb
|
||||
? isTabletOrDesktop
|
||||
? 'Loading...'
|
||||
: ''
|
||||
: query
|
||||
|
@ -100,23 +101,22 @@ export const DiscoverFeedsScreen = withAuthRequired(
|
|||
|
||||
return (
|
||||
<CenteredView style={[styles.container, pal.view]}>
|
||||
<View style={[isDesktopWeb && styles.containerDesktop, pal.border]}>
|
||||
<View
|
||||
style={[isTabletOrDesktop && styles.containerDesktop, pal.border]}>
|
||||
<ViewHeader title="Discover Feeds" showOnDesktop />
|
||||
<View style={{marginTop: isDesktopWeb ? 5 : 0, marginBottom: 4}}>
|
||||
<HeaderWithInput
|
||||
isInputFocused={isInputFocused}
|
||||
query={query}
|
||||
setIsInputFocused={setIsInputFocused}
|
||||
onChangeQuery={onChangeQuery}
|
||||
onPressClearQuery={onPressClearQuery}
|
||||
onPressCancelSearch={onPressCancelSearch}
|
||||
onSubmitQuery={onSubmitQuery}
|
||||
showMenu={false}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<HeaderWithInput
|
||||
isInputFocused={isInputFocused}
|
||||
query={query}
|
||||
setIsInputFocused={setIsInputFocused}
|
||||
onChangeQuery={onChangeQuery}
|
||||
onPressClearQuery={onPressClearQuery}
|
||||
onPressCancelSearch={onPressCancelSearch}
|
||||
onSubmitQuery={onSubmitQuery}
|
||||
showMenu={false}
|
||||
/>
|
||||
<FlatList
|
||||
style={[!isDesktopWeb && s.flex1]}
|
||||
style={[!isTabletOrDesktop && s.flex1]}
|
||||
data={feeds.feeds}
|
||||
keyExtractor={item => item.data.uri}
|
||||
contentContainerStyle={styles.contentContainer}
|
||||
|
|
|
@ -12,22 +12,23 @@ import {NativeStackScreenProps, FeedsTabNavigatorParams} from 'lib/routes/types'
|
|||
import {observer} from 'mobx-react-lite'
|
||||
import {PostsMultiFeedModel} from 'state/models/feeds/multi-feed'
|
||||
import {MultiFeed} from 'view/com/posts/MultiFeed'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useTimer} from 'lib/hooks/useTimer'
|
||||
import {useStores} from 'state/index'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {useOnMainScroll} from 'lib/hooks/useOnMainScroll'
|
||||
import {ComposeIcon2, CogIcon} from 'lib/icons'
|
||||
import {s} from 'lib/styles'
|
||||
|
||||
const LOAD_NEW_PROMPT_TIME = 60e3 // 60 seconds
|
||||
const HEADER_OFFSET = isDesktopWeb ? 0 : 40
|
||||
const MOBILE_HEADER_OFFSET = 40
|
||||
|
||||
type Props = NativeStackScreenProps<FeedsTabNavigatorParams, 'Feeds'>
|
||||
export const FeedsScreen = withAuthRequired(
|
||||
observer<Props>(({}: Props) => {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const flatListRef = React.useRef<FlatList>(null)
|
||||
const multifeed = React.useMemo<PostsMultiFeedModel>(
|
||||
() => new PostsMultiFeedModel(store),
|
||||
|
@ -105,14 +106,16 @@ export const FeedsScreen = withAuthRequired(
|
|||
multifeed={multifeed}
|
||||
onScroll={onMainScroll}
|
||||
scrollEventThrottle={100}
|
||||
headerOffset={HEADER_OFFSET}
|
||||
/>
|
||||
<ViewHeader
|
||||
title="My Feeds"
|
||||
canGoBack={false}
|
||||
hideOnScroll
|
||||
renderButton={renderHeaderBtn}
|
||||
headerOffset={isMobile ? MOBILE_HEADER_OFFSET : undefined}
|
||||
/>
|
||||
{isMobile && (
|
||||
<ViewHeader
|
||||
title="My Feeds"
|
||||
canGoBack={false}
|
||||
hideOnScroll
|
||||
renderButton={renderHeaderBtn}
|
||||
/>
|
||||
)}
|
||||
{isScrolledDown || loadPromptVisible ? (
|
||||
<LoadLatestBtn
|
||||
onPress={onSoftReset}
|
||||
|
|
|
@ -19,14 +19,11 @@ import {useStores} from 'state/index'
|
|||
import {s} from 'lib/styles'
|
||||
import {useOnMainScroll} from 'lib/hooks/useOnMainScroll'
|
||||
import {useAnalytics} from 'lib/analytics/analytics'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {ComposeIcon2} from 'lib/icons'
|
||||
import {isDesktopWeb, isMobileWebMediaQuery, isWeb} from 'platform/detection'
|
||||
|
||||
const HEADER_OFFSET_MOBILE = 78
|
||||
const HEADER_OFFSET_DESKTOP = 50
|
||||
const HEADER_OFFSET = isDesktopWeb
|
||||
? HEADER_OFFSET_DESKTOP
|
||||
: HEADER_OFFSET_MOBILE
|
||||
const POLL_FREQ = 30e3 // 30sec
|
||||
|
||||
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'>
|
||||
|
@ -158,10 +155,13 @@ const FeedPage = observer(
|
|||
renderEmptyState?: () => JSX.Element
|
||||
}) => {
|
||||
const store = useStores()
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const [onMainScroll, isScrolledDown, resetMainScroll] =
|
||||
useOnMainScroll(store)
|
||||
const {screen, track} = useAnalytics()
|
||||
const [headerOffset, setHeaderOffset] = React.useState(HEADER_OFFSET)
|
||||
const [headerOffset, setHeaderOffset] = React.useState(
|
||||
isMobile ? HEADER_OFFSET_MOBILE : HEADER_OFFSET_DESKTOP,
|
||||
)
|
||||
const scrollElRef = React.useRef<FlatList>(null)
|
||||
const {appState} = useAppState({
|
||||
onForeground: () => doPoll(true),
|
||||
|
@ -206,15 +206,9 @@ const FeedPage = observer(
|
|||
}, [isPageFocused, scrollToTop, feed])
|
||||
|
||||
// listens for resize events
|
||||
const listenForResize = React.useCallback(() => {
|
||||
// @ts-ignore we know window exists -prf
|
||||
const isMobileWeb = global.window.matchMedia(
|
||||
isMobileWebMediaQuery,
|
||||
)?.matches
|
||||
setHeaderOffset(
|
||||
isMobileWeb ? HEADER_OFFSET_MOBILE : HEADER_OFFSET_DESKTOP,
|
||||
)
|
||||
}, [])
|
||||
React.useEffect(() => {
|
||||
setHeaderOffset(isMobile ? HEADER_OFFSET_MOBILE : HEADER_OFFSET_DESKTOP)
|
||||
}, [isMobile])
|
||||
|
||||
// fires when page within screen is activated/deactivated
|
||||
// - check for latest
|
||||
|
@ -234,17 +228,10 @@ const FeedPage = observer(
|
|||
feed.update()
|
||||
}
|
||||
|
||||
if (isWeb) {
|
||||
window.addEventListener('resize', listenForResize)
|
||||
}
|
||||
|
||||
return () => {
|
||||
clearInterval(pollInterval)
|
||||
softResetSub.remove()
|
||||
feedCleanup()
|
||||
if (isWeb) {
|
||||
isWeb && window.removeEventListener('resize', listenForResize)
|
||||
}
|
||||
}
|
||||
}, [
|
||||
store,
|
||||
|
@ -254,7 +241,6 @@ const FeedPage = observer(
|
|||
feed,
|
||||
isPageFocused,
|
||||
isScreenFocused,
|
||||
listenForResize,
|
||||
])
|
||||
|
||||
const onPressCompose = React.useCallback(() => {
|
||||
|
|
|
@ -16,7 +16,7 @@ import {Link} from '../com/util/Link'
|
|||
import {Text} from '../com/util/text/Text'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useAnalytics} from 'lib/analytics/analytics'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Moderation'>
|
||||
export const ModerationScreen = withAuthRequired(
|
||||
|
@ -24,6 +24,7 @@ export const ModerationScreen = withAuthRequired(
|
|||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {screen, track} = useAnalytics()
|
||||
const {isTabletOrDesktop} = useWebMediaQueries()
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
|
@ -42,7 +43,7 @@ export const ModerationScreen = withAuthRequired(
|
|||
style={[
|
||||
s.hContentRegion,
|
||||
pal.border,
|
||||
isDesktopWeb ? styles.desktopContainer : pal.viewLight,
|
||||
isTabletOrDesktop ? styles.desktopContainer : pal.viewLight,
|
||||
]}
|
||||
testID="moderationScreen">
|
||||
<ViewHeader title="Moderation" showOnDesktop />
|
||||
|
|
|
@ -10,7 +10,7 @@ import {AppBskyActorDefs as ActorDefs} from '@atproto/api'
|
|||
import {Text} from '../com/util/text/Text'
|
||||
import {useStores} from 'state/index'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||
|
@ -30,6 +30,7 @@ export const ModerationBlockedAccounts = withAuthRequired(
|
|||
observer(({}: Props) => {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {isTabletOrDesktop} = useWebMediaQueries()
|
||||
const {screen} = useAnalytics()
|
||||
const blockedAccounts = useMemo(
|
||||
() => new BlockedAccountsModel(store),
|
||||
|
@ -72,7 +73,7 @@ export const ModerationBlockedAccounts = withAuthRequired(
|
|||
<CenteredView
|
||||
style={[
|
||||
styles.container,
|
||||
isDesktopWeb && styles.containerDesktop,
|
||||
isTabletOrDesktop && styles.containerDesktop,
|
||||
pal.view,
|
||||
pal.border,
|
||||
]}
|
||||
|
@ -83,14 +84,14 @@ export const ModerationBlockedAccounts = withAuthRequired(
|
|||
style={[
|
||||
styles.description,
|
||||
pal.text,
|
||||
isDesktopWeb && styles.descriptionDesktop,
|
||||
isTabletOrDesktop && styles.descriptionDesktop,
|
||||
]}>
|
||||
Blocked accounts cannot reply in your threads, mention you, or
|
||||
otherwise interact with you. You will not see their content and they
|
||||
will be prevented from seeing yours.
|
||||
</Text>
|
||||
{!blockedAccounts.hasContent ? (
|
||||
<View style={[pal.border, !isDesktopWeb && styles.flex1]}>
|
||||
<View style={[pal.border, !isTabletOrDesktop && styles.flex1]}>
|
||||
<View style={[styles.empty, pal.viewLight]}>
|
||||
<Text type="lg" style={[pal.text, styles.emptyText]}>
|
||||
You have not blocked any accounts yet. To block an account, go
|
||||
|
@ -101,7 +102,7 @@ export const ModerationBlockedAccounts = withAuthRequired(
|
|||
</View>
|
||||
) : (
|
||||
<FlatList
|
||||
style={[!isDesktopWeb && styles.flex1]}
|
||||
style={[!isTabletOrDesktop && styles.flex1]}
|
||||
data={blockedAccounts.blocks}
|
||||
keyExtractor={(item: ActorDefs.ProfileView) => item.did}
|
||||
refreshControl={
|
||||
|
@ -133,11 +134,12 @@ export const ModerationBlockedAccounts = withAuthRequired(
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
paddingBottom: isDesktopWeb ? 0 : 100,
|
||||
paddingBottom: 100,
|
||||
},
|
||||
containerDesktop: {
|
||||
borderLeftWidth: 1,
|
||||
borderRightWidth: 1,
|
||||
paddingBottom: 0,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
|
|
|
@ -15,9 +15,9 @@ import {ListsList} from 'view/com/lists/ListsList'
|
|||
import {Button} from 'view/com/util/forms/Button'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {CenteredView} from 'view/com/util/Views'
|
||||
import {ViewHeader} from 'view/com/util/ViewHeader'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
|
||||
type Props = NativeStackScreenProps<
|
||||
CommonNavigatorParams,
|
||||
|
@ -26,6 +26,7 @@ type Props = NativeStackScreenProps<
|
|||
export const ModerationMuteListsScreen = withAuthRequired(({}: Props) => {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {isTabletOrDesktop} = useWebMediaQueries()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
|
||||
const mutelists: ListsListModel = React.useMemo(
|
||||
|
@ -89,7 +90,7 @@ export const ModerationMuteListsScreen = withAuthRequired(({}: Props) => {
|
|||
styles.container,
|
||||
pal.view,
|
||||
pal.border,
|
||||
isDesktopWeb && styles.containerDesktop,
|
||||
isTabletOrDesktop && styles.containerDesktop,
|
||||
]}
|
||||
testID="moderationMutelistsScreen">
|
||||
<ViewHeader
|
||||
|
@ -99,7 +100,7 @@ export const ModerationMuteListsScreen = withAuthRequired(({}: Props) => {
|
|||
/>
|
||||
<ListsList
|
||||
listsList={mutelists}
|
||||
showAddBtns={isDesktopWeb}
|
||||
showAddBtns={isTabletOrDesktop}
|
||||
renderEmptyState={renderEmptyState}
|
||||
onPressCreateNew={onPressNewMuteList}
|
||||
/>
|
||||
|
@ -110,11 +111,12 @@ export const ModerationMuteListsScreen = withAuthRequired(({}: Props) => {
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
paddingBottom: isDesktopWeb ? 0 : 100,
|
||||
paddingBottom: 100,
|
||||
},
|
||||
containerDesktop: {
|
||||
borderLeftWidth: 1,
|
||||
borderRightWidth: 1,
|
||||
paddingBottom: 0,
|
||||
},
|
||||
createBtn: {
|
||||
width: 40,
|
||||
|
|
|
@ -10,7 +10,7 @@ import {AppBskyActorDefs as ActorDefs} from '@atproto/api'
|
|||
import {Text} from '../com/util/text/Text'
|
||||
import {useStores} from 'state/index'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||
|
@ -30,6 +30,7 @@ export const ModerationMutedAccounts = withAuthRequired(
|
|||
observer(({}: Props) => {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {isTabletOrDesktop} = useWebMediaQueries()
|
||||
const {screen} = useAnalytics()
|
||||
const mutedAccounts = useMemo(() => new MutedAccountsModel(store), [store])
|
||||
|
||||
|
@ -69,7 +70,7 @@ export const ModerationMutedAccounts = withAuthRequired(
|
|||
<CenteredView
|
||||
style={[
|
||||
styles.container,
|
||||
isDesktopWeb && styles.containerDesktop,
|
||||
isTabletOrDesktop && styles.containerDesktop,
|
||||
pal.view,
|
||||
pal.border,
|
||||
]}
|
||||
|
@ -80,13 +81,13 @@ export const ModerationMutedAccounts = withAuthRequired(
|
|||
style={[
|
||||
styles.description,
|
||||
pal.text,
|
||||
isDesktopWeb && styles.descriptionDesktop,
|
||||
isTabletOrDesktop && styles.descriptionDesktop,
|
||||
]}>
|
||||
Muted accounts have their posts removed from your feed and from your
|
||||
notifications. Mutes are completely private.
|
||||
</Text>
|
||||
{!mutedAccounts.hasContent ? (
|
||||
<View style={[pal.border, !isDesktopWeb && styles.flex1]}>
|
||||
<View style={[pal.border, !isTabletOrDesktop && styles.flex1]}>
|
||||
<View style={[styles.empty, pal.viewLight]}>
|
||||
<Text type="lg" style={[pal.text, styles.emptyText]}>
|
||||
You have not muted any accounts yet. To mute an account, go to
|
||||
|
@ -97,7 +98,7 @@ export const ModerationMutedAccounts = withAuthRequired(
|
|||
</View>
|
||||
) : (
|
||||
<FlatList
|
||||
style={[!isDesktopWeb && styles.flex1]}
|
||||
style={[!isTabletOrDesktop && styles.flex1]}
|
||||
data={mutedAccounts.mutes}
|
||||
keyExtractor={item => item.did}
|
||||
refreshControl={
|
||||
|
@ -129,11 +130,12 @@ export const ModerationMutedAccounts = withAuthRequired(
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
paddingBottom: isDesktopWeb ? 0 : 100,
|
||||
paddingBottom: 100,
|
||||
},
|
||||
containerDesktop: {
|
||||
borderLeftWidth: 1,
|
||||
borderRightWidth: 1,
|
||||
paddingBottom: 0,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
|
|
|
@ -12,7 +12,7 @@ import {useStores} from 'state/index'
|
|||
import {s} from 'lib/styles'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import {clamp} from 'lodash'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
|
||||
const SHELL_FOOTER_HEIGHT = 44
|
||||
|
||||
|
@ -26,6 +26,7 @@ export const PostThreadScreen = withAuthRequired(({route}: Props) => {
|
|||
() => new PostThreadModel(store, {uri}),
|
||||
[store, uri],
|
||||
)
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
|
@ -67,15 +68,15 @@ export const PostThreadScreen = withAuthRequired(({route}: Props) => {
|
|||
|
||||
return (
|
||||
<View style={s.hContentRegion}>
|
||||
<ViewHeader title="Post" />
|
||||
<View style={s.hContentRegion}>
|
||||
{isMobile && <ViewHeader title="Post" />}
|
||||
<View style={s.flex1}>
|
||||
<PostThreadComponent
|
||||
uri={uri}
|
||||
view={view}
|
||||
onPressReply={onPressReply}
|
||||
/>
|
||||
</View>
|
||||
{!isDesktopWeb && (
|
||||
{isMobile && (
|
||||
<View
|
||||
style={[
|
||||
styles.prompt,
|
||||
|
|
|
@ -6,7 +6,8 @@ import {Text} from '../com/util/text/Text'
|
|||
import {useStores} from 'state/index'
|
||||
import {s, colors} from 'lib/styles'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {isWeb, isDesktopWeb} from 'platform/detection'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {isWeb} from 'platform/detection'
|
||||
import {ToggleButton} from 'view/com/util/forms/ToggleButton'
|
||||
import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types'
|
||||
import {ViewHeader} from 'view/com/util/ViewHeader'
|
||||
|
@ -50,6 +51,7 @@ type Props = NativeStackScreenProps<
|
|||
export const PreferencesHomeFeed = observer(({navigation}: Props) => {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {isTabletOrDesktop} = useWebMediaQueries()
|
||||
|
||||
return (
|
||||
<CenteredView
|
||||
|
@ -58,10 +60,11 @@ export const PreferencesHomeFeed = observer(({navigation}: Props) => {
|
|||
pal.view,
|
||||
pal.border,
|
||||
styles.container,
|
||||
isDesktopWeb && styles.desktopContainer,
|
||||
isTabletOrDesktop && styles.desktopContainer,
|
||||
]}>
|
||||
<ViewHeader title="Home Feed Preferences" showOnDesktop />
|
||||
<View style={styles.titleSection}>
|
||||
<View
|
||||
style={[styles.titleSection, isTabletOrDesktop && {paddingTop: 20}]}>
|
||||
<Text type="xl" style={[pal.textLight, styles.description]}>
|
||||
Fine-tune the content you see on your home screen.
|
||||
</Text>
|
||||
|
@ -122,7 +125,12 @@ export const PreferencesHomeFeed = observer(({navigation}: Props) => {
|
|||
</View>
|
||||
</ScrollView>
|
||||
|
||||
<View style={[styles.btnContainer, pal.borderDark]}>
|
||||
<View
|
||||
style={[
|
||||
styles.btnContainer,
|
||||
!isTabletOrDesktop && {borderTopWidth: 1, paddingHorizontal: 20},
|
||||
pal.borderDark,
|
||||
]}>
|
||||
<TouchableOpacity
|
||||
testID="confirmBtn"
|
||||
onPress={() => {
|
||||
|
@ -130,7 +138,7 @@ export const PreferencesHomeFeed = observer(({navigation}: Props) => {
|
|||
? navigation.goBack()
|
||||
: navigation.navigate('Settings')
|
||||
}}
|
||||
style={[styles.btn, isDesktopWeb && styles.btnDesktop]}
|
||||
style={[styles.btn, isTabletOrDesktop && styles.btnDesktop]}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Confirm"
|
||||
accessibilityHint="">
|
||||
|
@ -144,15 +152,15 @@ export const PreferencesHomeFeed = observer(({navigation}: Props) => {
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
paddingBottom: isDesktopWeb ? 40 : 90,
|
||||
paddingBottom: 90,
|
||||
},
|
||||
desktopContainer: {
|
||||
borderLeftWidth: 1,
|
||||
borderRightWidth: 1,
|
||||
paddingBottom: 40,
|
||||
},
|
||||
titleSection: {
|
||||
paddingBottom: 30,
|
||||
paddingTop: isDesktopWeb ? 20 : 0,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
|
@ -184,7 +192,6 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
btnContainer: {
|
||||
paddingTop: 20,
|
||||
borderTopWidth: isDesktopWeb ? 0 : 1,
|
||||
},
|
||||
dimmed: {
|
||||
opacity: 0.3,
|
||||
|
|
|
@ -14,8 +14,8 @@ import {ListModel} from 'state/models/content/list'
|
|||
import {useStores} from 'state/index'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useSetTitle} from 'lib/hooks/useSetTitle'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {toShareUrl} from 'lib/strings/url-helpers'
|
||||
import {shareUrl} from 'lib/sharing'
|
||||
import {ListActions} from 'view/com/lists/ListActions'
|
||||
|
@ -26,6 +26,7 @@ export const ProfileListScreen = withAuthRequired(
|
|||
observer(({route}: Props) => {
|
||||
const store = useStores()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const {isTabletOrDesktop} = useWebMediaQueries()
|
||||
const pal = usePalette('default')
|
||||
const {name, rkey} = route.params
|
||||
|
||||
|
@ -131,7 +132,7 @@ export const ProfileListScreen = withAuthRequired(
|
|||
<CenteredView
|
||||
style={[
|
||||
styles.container,
|
||||
isDesktopWeb && styles.containerDesktop,
|
||||
isTabletOrDesktop && styles.containerDesktop,
|
||||
pal.view,
|
||||
pal.border,
|
||||
]}
|
||||
|
@ -155,10 +156,11 @@ export const ProfileListScreen = withAuthRequired(
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
paddingBottom: isDesktopWeb ? 0 : 100,
|
||||
paddingBottom: 100,
|
||||
},
|
||||
containerDesktop: {
|
||||
borderLeftWidth: 1,
|
||||
borderRightWidth: 1,
|
||||
paddingBottom: 0,
|
||||
},
|
||||
})
|
||||
|
|
|
@ -14,11 +14,12 @@ import {usePalette} from 'lib/hooks/usePalette'
|
|||
import {CommonNavigatorParams} from 'lib/routes/types'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {useStores} from 'state/index'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
|
||||
import {ViewHeader} from 'view/com/util/ViewHeader'
|
||||
import {CenteredView} from 'view/com/util/Views'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {isDesktopWeb, isWeb} from 'platform/detection'
|
||||
import {isWeb} from 'platform/detection'
|
||||
import {s, colors} from 'lib/styles'
|
||||
import DraggableFlatList, {
|
||||
ShadowDecorator,
|
||||
|
@ -37,6 +38,7 @@ export const SavedFeeds = withAuthRequired(
|
|||
observer(({}: Props) => {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {isMobile, isTabletOrDesktop} = useWebMediaQueries()
|
||||
const {screen} = useAnalytics()
|
||||
|
||||
const savedFeeds = useMemo(() => store.me.savedFeeds, [store])
|
||||
|
@ -53,7 +55,7 @@ export const SavedFeeds = withAuthRequired(
|
|||
<View
|
||||
style={[
|
||||
pal.border,
|
||||
!isDesktopWeb && s.flex1,
|
||||
isMobile && s.flex1,
|
||||
pal.viewLight,
|
||||
styles.empty,
|
||||
]}>
|
||||
|
@ -62,7 +64,7 @@ export const SavedFeeds = withAuthRequired(
|
|||
</Text>
|
||||
</View>
|
||||
)
|
||||
}, [pal])
|
||||
}, [pal, isMobile])
|
||||
|
||||
const renderListFooterComponent = useCallback(() => {
|
||||
return (
|
||||
|
@ -116,15 +118,11 @@ export const SavedFeeds = withAuthRequired(
|
|||
style={[
|
||||
s.hContentRegion,
|
||||
pal.border,
|
||||
isDesktopWeb && styles.desktopContainer,
|
||||
isTabletOrDesktop && styles.desktopContainer,
|
||||
]}>
|
||||
<ViewHeader
|
||||
title="Edit My Feeds"
|
||||
showOnDesktop
|
||||
showBorder={!isDesktopWeb}
|
||||
/>
|
||||
<ViewHeader title="Edit My Feeds" showOnDesktop showBorder />
|
||||
<DraggableFlatList
|
||||
containerStyle={[isDesktopWeb ? s.hContentRegion : s.flex1]}
|
||||
containerStyle={[isTabletOrDesktop ? s.hContentRegion : s.flex1]}
|
||||
data={savedFeeds.all}
|
||||
keyExtractor={item => item.data.uri}
|
||||
refreshing={savedFeeds.isRefreshing}
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
SearchTabNavigatorParams,
|
||||
} from 'lib/routes/types'
|
||||
import {useStores} from 'state/index'
|
||||
import {CenteredView} from 'view/com/util/Views'
|
||||
import * as Mobile from './SearchMobile'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
|
||||
|
@ -57,9 +58,9 @@ export const SearchScreen = withAuthRequired(
|
|||
|
||||
if (!isDesktop) {
|
||||
return (
|
||||
<View style={styles.scrollContainer}>
|
||||
<CenteredView style={styles.scrollContainer}>
|
||||
<Mobile.SearchScreen navigation={navigation} route={route} />
|
||||
</View>
|
||||
</CenteredView>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -35,10 +35,10 @@ import {ToggleButton} from 'view/com/util/forms/ToggleButton'
|
|||
import {SelectableBtn} from 'view/com/util/forms/SelectableBtn'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useCustomPalette} from 'lib/hooks/useCustomPalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {AccountData} from 'state/models/session'
|
||||
import {useAnalytics} from 'lib/analytics/analytics'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
import {isDesktopWeb} from 'platform/detection'
|
||||
import {pluralize} from 'lib/strings/helpers'
|
||||
import {formatCount} from 'view/com/util/numeric/format'
|
||||
import Clipboard from '@react-native-clipboard/clipboard'
|
||||
|
@ -58,6 +58,7 @@ export const SettingsScreen = withAuthRequired(
|
|||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const {screen, track} = useAnalytics()
|
||||
const [isSwitching, setIsSwitching] = React.useState(false)
|
||||
const [debugHeaderEnabled, toggleDebugHeader] = useDebugHeaderSetting(
|
||||
|
@ -203,7 +204,7 @@ export const SettingsScreen = withAuthRequired(
|
|||
<ViewHeader title="Settings" />
|
||||
<ScrollView
|
||||
style={[s.hContentRegion]}
|
||||
contentContainerStyle={!isDesktopWeb && pal.viewLight}
|
||||
contentContainerStyle={isMobile && pal.viewLight}
|
||||
scrollIndicatorInsets={{right: 1}}>
|
||||
<View style={styles.spacer20} />
|
||||
{store.session.currentSession !== undefined ? (
|
||||
|
@ -508,7 +509,7 @@ export const SettingsScreen = withAuthRequired(
|
|||
System log
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
{isDesktopWeb || __DEV__ ? (
|
||||
{__DEV__ ? (
|
||||
<ToggleButton
|
||||
type="default-light"
|
||||
label="Experiment: Use AppView Proxy"
|
||||
|
|
|
@ -4,7 +4,7 @@ import {StyleSheet, View} from 'react-native'
|
|||
import {ComposePost} from '../com/composer/Composer'
|
||||
import {ComposerOpts} from 'state/models/ui/shell'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {isMobileWeb} from 'platform/detection'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
|
||||
const BOTTOM_BAR_HEIGHT = 61
|
||||
|
||||
|
@ -26,6 +26,7 @@ export const Composer = observer(
|
|||
mention?: ComposerOpts['mention']
|
||||
}) => {
|
||||
const pal = usePalette('default')
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
|
||||
// rendering
|
||||
// =
|
||||
|
@ -36,7 +37,13 @@ export const Composer = observer(
|
|||
|
||||
return (
|
||||
<View style={styles.mask} aria-modal accessibilityViewIsModal>
|
||||
<View style={[styles.container, pal.view, pal.border]}>
|
||||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
isMobile && styles.containerMobile,
|
||||
pal.view,
|
||||
pal.border,
|
||||
]}>
|
||||
<ComposePost
|
||||
replyTo={replyTo}
|
||||
quote={quote}
|
||||
|
@ -66,11 +73,14 @@ const styles = StyleSheet.create({
|
|||
width: '100%',
|
||||
paddingVertical: 0,
|
||||
paddingHorizontal: 2,
|
||||
borderRadius: isMobileWeb ? 0 : 8,
|
||||
marginBottom: isMobileWeb ? BOTTOM_BAR_HEIGHT : 0,
|
||||
borderRadius: 8,
|
||||
marginBottom: 0,
|
||||
borderWidth: 1,
|
||||
maxHeight: isMobileWeb
|
||||
? `calc(100% - ${BOTTOM_BAR_HEIGHT}px)`
|
||||
: 'calc(100% - (40px * 2))',
|
||||
maxHeight: 'calc(100% - (40px * 2))',
|
||||
},
|
||||
containerMobile: {
|
||||
borderRadius: 0,
|
||||
marginBottom: BOTTOM_BAR_HEIGHT,
|
||||
maxHeight: `calc(100% - ${BOTTOM_BAR_HEIGHT}px)`,
|
||||
},
|
||||
})
|
||||
|
|
|
@ -17,6 +17,7 @@ import {Link} from 'view/com/util/Link'
|
|||
import {LoadingPlaceholder} from 'view/com/util/LoadingPlaceholder'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useStores} from 'state/index'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {s, colors} from 'lib/styles'
|
||||
import {
|
||||
HomeIcon,
|
||||
|
@ -41,18 +42,28 @@ import {makeProfileLink} from 'lib/routes/links'
|
|||
|
||||
const ProfileCard = observer(() => {
|
||||
const store = useStores()
|
||||
const {isDesktop} = useWebMediaQueries()
|
||||
const size = isDesktop ? 64 : 48
|
||||
return store.me.handle ? (
|
||||
<Link href={makeProfileLink(store.me)} style={styles.profileCard} asAnchor>
|
||||
<UserAvatar avatar={store.me.avatar} size={64} />
|
||||
<Link
|
||||
href={makeProfileLink(store.me)}
|
||||
style={[styles.profileCard, !isDesktop && styles.profileCardTablet]}
|
||||
asAnchor>
|
||||
<UserAvatar avatar={store.me.avatar} size={size} />
|
||||
</Link>
|
||||
) : (
|
||||
<View style={styles.profileCard}>
|
||||
<LoadingPlaceholder width={64} height={64} style={{borderRadius: 64}} />
|
||||
<View style={[styles.profileCard, !isDesktop && styles.profileCardTablet]}>
|
||||
<LoadingPlaceholder
|
||||
width={size}
|
||||
height={size}
|
||||
style={{borderRadius: size}}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
})
|
||||
|
||||
function BackBtn() {
|
||||
const {isTablet} = useWebMediaQueries()
|
||||
const pal = usePalette('default')
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const shouldShow = useNavigationState(state => !isStateAtTabRoot(state))
|
||||
|
@ -65,7 +76,7 @@ function BackBtn() {
|
|||
}
|
||||
}, [navigation])
|
||||
|
||||
if (!shouldShow) {
|
||||
if (!shouldShow || isTablet) {
|
||||
return <></>
|
||||
}
|
||||
return (
|
||||
|
@ -96,6 +107,7 @@ const NavItem = observer(
|
|||
({count, href, icon, iconFilled, label}: NavItemProps) => {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const {isDesktop, isTablet} = useWebMediaQueries()
|
||||
const [pathName] = React.useMemo(() => router.matchPath(href), [href])
|
||||
const currentRouteInfo = useNavigationState(state => {
|
||||
if (!state) {
|
||||
|
@ -137,17 +149,28 @@ const NavItem = observer(
|
|||
accessibilityRole="tab"
|
||||
accessibilityLabel={label}
|
||||
accessibilityHint="">
|
||||
<View style={[styles.navItemIconWrapper]}>
|
||||
<View
|
||||
style={[
|
||||
styles.navItemIconWrapper,
|
||||
isTablet && styles.navItemIconWrapperTablet,
|
||||
]}>
|
||||
{isCurrent ? iconFilled : icon}
|
||||
{typeof count === 'string' && count ? (
|
||||
<Text type="button" style={styles.navItemCount}>
|
||||
<Text
|
||||
type="button"
|
||||
style={[
|
||||
styles.navItemCount,
|
||||
isTablet && styles.navItemCountTablet,
|
||||
]}>
|
||||
{count}
|
||||
</Text>
|
||||
) : null}
|
||||
</View>
|
||||
<Text type="title" style={[isCurrent ? s.bold : s.normal, pal.text]}>
|
||||
{label}
|
||||
</Text>
|
||||
{isDesktop && (
|
||||
<Text type="title" style={[isCurrent ? s.bold : s.normal, pal.text]}>
|
||||
{label}
|
||||
</Text>
|
||||
)}
|
||||
</PressableWithHover>
|
||||
)
|
||||
},
|
||||
|
@ -156,6 +179,7 @@ const NavItem = observer(
|
|||
function ComposeBtn() {
|
||||
const store = useStores()
|
||||
const {getState} = useNavigation()
|
||||
const {isTablet} = useWebMediaQueries()
|
||||
|
||||
const getProfileHandle = () => {
|
||||
const {routes} = getState()
|
||||
|
@ -172,6 +196,9 @@ function ComposeBtn() {
|
|||
const onPressCompose = () =>
|
||||
store.shell.openComposer({mention: getProfileHandle()})
|
||||
|
||||
if (isTablet) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={[styles.newPostBtn]}
|
||||
|
@ -196,28 +223,43 @@ function ComposeBtn() {
|
|||
export const DesktopLeftNav = observer(function DesktopLeftNav() {
|
||||
const store = useStores()
|
||||
const pal = usePalette('default')
|
||||
const {isDesktop, isTablet} = useWebMediaQueries()
|
||||
|
||||
return (
|
||||
<View style={[styles.leftNav, pal.view]}>
|
||||
<View
|
||||
style={[
|
||||
styles.leftNav,
|
||||
isTablet && styles.leftNavTablet,
|
||||
pal.view,
|
||||
pal.border,
|
||||
]}>
|
||||
{store.session.hasSession && <ProfileCard />}
|
||||
<BackBtn />
|
||||
<NavItem
|
||||
href="/"
|
||||
icon={<HomeIcon size={24} style={pal.text} />}
|
||||
icon={<HomeIcon size={isDesktop ? 24 : 28} style={pal.text} />}
|
||||
iconFilled={
|
||||
<HomeIconSolid strokeWidth={4} size={24} style={pal.text} />
|
||||
<HomeIconSolid
|
||||
strokeWidth={4}
|
||||
size={isDesktop ? 24 : 28}
|
||||
style={pal.text}
|
||||
/>
|
||||
}
|
||||
label="Home"
|
||||
/>
|
||||
<NavItem
|
||||
href="/search"
|
||||
icon={
|
||||
<MagnifyingGlassIcon2 strokeWidth={2} size={24} style={pal.text} />
|
||||
<MagnifyingGlassIcon2
|
||||
strokeWidth={2}
|
||||
size={isDesktop ? 24 : 26}
|
||||
style={pal.text}
|
||||
/>
|
||||
}
|
||||
iconFilled={
|
||||
<MagnifyingGlassIcon2Solid
|
||||
strokeWidth={2}
|
||||
size={24}
|
||||
size={isDesktop ? 24 : 26}
|
||||
style={pal.text}
|
||||
/>
|
||||
}
|
||||
|
@ -229,14 +271,14 @@ export const DesktopLeftNav = observer(function DesktopLeftNav() {
|
|||
<SatelliteDishIcon
|
||||
strokeWidth={1.75}
|
||||
style={pal.text as FontAwesomeIconStyle}
|
||||
size={24}
|
||||
size={isDesktop ? 24 : 28}
|
||||
/>
|
||||
}
|
||||
iconFilled={
|
||||
<SatelliteDishIconSolid
|
||||
strokeWidth={1.75}
|
||||
style={pal.text as FontAwesomeIconStyle}
|
||||
size={24}
|
||||
size={isDesktop ? 24 : 28}
|
||||
/>
|
||||
}
|
||||
label="My Feeds"
|
||||
|
@ -244,9 +286,19 @@ export const DesktopLeftNav = observer(function DesktopLeftNav() {
|
|||
<NavItem
|
||||
href="/notifications"
|
||||
count={store.me.notifications.unreadCountLabel}
|
||||
icon={<BellIcon strokeWidth={2} size={24} style={pal.text} />}
|
||||
icon={
|
||||
<BellIcon
|
||||
strokeWidth={2}
|
||||
size={isDesktop ? 24 : 26}
|
||||
style={pal.text}
|
||||
/>
|
||||
}
|
||||
iconFilled={
|
||||
<BellIconSolid strokeWidth={1.5} size={24} style={pal.text} />
|
||||
<BellIconSolid
|
||||
strokeWidth={1.5}
|
||||
size={isDesktop ? 24 : 26}
|
||||
style={pal.text}
|
||||
/>
|
||||
}
|
||||
label="Notifications"
|
||||
/>
|
||||
|
@ -256,14 +308,14 @@ export const DesktopLeftNav = observer(function DesktopLeftNav() {
|
|||
<HandIcon
|
||||
strokeWidth={5.5}
|
||||
style={pal.text as FontAwesomeIconStyle}
|
||||
size={24}
|
||||
size={isDesktop ? 24 : 27}
|
||||
/>
|
||||
}
|
||||
iconFilled={
|
||||
<FontAwesomeIcon
|
||||
icon="hand"
|
||||
style={pal.text as FontAwesomeIconStyle}
|
||||
size={20}
|
||||
size={isDesktop ? 20 : 26}
|
||||
/>
|
||||
}
|
||||
label="Moderation"
|
||||
|
@ -271,18 +323,38 @@ export const DesktopLeftNav = observer(function DesktopLeftNav() {
|
|||
{store.session.hasSession && (
|
||||
<NavItem
|
||||
href={makeProfileLink(store.me)}
|
||||
icon={<UserIcon strokeWidth={1.75} size={28} style={pal.text} />}
|
||||
icon={
|
||||
<UserIcon
|
||||
strokeWidth={1.75}
|
||||
size={isDesktop ? 28 : 30}
|
||||
style={pal.text}
|
||||
/>
|
||||
}
|
||||
iconFilled={
|
||||
<UserIconSolid strokeWidth={1.75} size={28} style={pal.text} />
|
||||
<UserIconSolid
|
||||
strokeWidth={1.75}
|
||||
size={isDesktop ? 28 : 30}
|
||||
style={pal.text}
|
||||
/>
|
||||
}
|
||||
label="Profile"
|
||||
/>
|
||||
)}
|
||||
<NavItem
|
||||
href="/settings"
|
||||
icon={<CogIcon strokeWidth={1.75} size={28} style={pal.text} />}
|
||||
icon={
|
||||
<CogIcon
|
||||
strokeWidth={1.75}
|
||||
size={isDesktop ? 28 : 32}
|
||||
style={pal.text}
|
||||
/>
|
||||
}
|
||||
iconFilled={
|
||||
<CogIconSolid strokeWidth={1.5} size={28} style={pal.text} />
|
||||
<CogIconSolid
|
||||
strokeWidth={1.5}
|
||||
size={isDesktop ? 28 : 32}
|
||||
style={pal.text}
|
||||
/>
|
||||
}
|
||||
label="Settings"
|
||||
/>
|
||||
|
@ -300,12 +372,24 @@ const styles = StyleSheet.create({
|
|||
maxHeight: 'calc(100vh - 10px)',
|
||||
overflowY: 'auto',
|
||||
},
|
||||
leftNavTablet: {
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 'auto',
|
||||
borderRightWidth: 1,
|
||||
height: '100%',
|
||||
width: 76,
|
||||
alignItems: 'center',
|
||||
},
|
||||
|
||||
profileCard: {
|
||||
marginVertical: 10,
|
||||
width: 90,
|
||||
paddingLeft: 12,
|
||||
},
|
||||
profileCardTablet: {
|
||||
width: 70,
|
||||
},
|
||||
|
||||
backBtn: {
|
||||
position: 'absolute',
|
||||
|
@ -330,6 +414,10 @@ const styles = StyleSheet.create({
|
|||
height: 28,
|
||||
marginTop: 2,
|
||||
},
|
||||
navItemIconWrapperTablet: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
},
|
||||
navItemCount: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
|
@ -341,6 +429,10 @@ const styles = StyleSheet.create({
|
|||
paddingHorizontal: 4,
|
||||
borderRadius: 6,
|
||||
},
|
||||
navItemCountTablet: {
|
||||
left: 18,
|
||||
fontSize: 14,
|
||||
},
|
||||
|
||||
newPostBtn: {
|
||||
flexDirection: 'row',
|
||||
|
@ -354,10 +446,9 @@ const styles = StyleSheet.create({
|
|||
marginLeft: 12,
|
||||
marginTop: 20,
|
||||
marginBottom: 10,
|
||||
gap: 8,
|
||||
},
|
||||
newPostBtnIconWrapper: {
|
||||
marginRight: 8,
|
||||
},
|
||||
newPostBtnIconWrapper: {},
|
||||
newPostBtnLabel: {
|
||||
color: colors.white,
|
||||
fontSize: 16,
|
||||
|
|
|
@ -9,6 +9,7 @@ import {TextLink} from 'view/com/util/Link'
|
|||
import {FEEDBACK_FORM_URL, HELP_DESK_URL} from 'lib/constants'
|
||||
import {s} from 'lib/styles'
|
||||
import {useStores} from 'state/index'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {pluralize} from 'lib/strings/helpers'
|
||||
import {formatCount} from 'view/com/util/numeric/format'
|
||||
|
||||
|
@ -17,6 +18,11 @@ export const DesktopRightNav = observer(function DesktopRightNav() {
|
|||
const pal = usePalette('default')
|
||||
const palError = usePalette('error')
|
||||
|
||||
const {isTablet} = useWebMediaQueries()
|
||||
if (isTablet) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={[styles.rightNav, pal.view]}>
|
||||
{store.session.hasSession && <DesktopSearch />}
|
||||
|
|
|
@ -19,7 +19,7 @@ import {NavigationProp} from 'lib/routes/types'
|
|||
|
||||
const ShellInner = observer(() => {
|
||||
const store = useStores()
|
||||
const {isDesktop} = useWebMediaQueries()
|
||||
const {isDesktop, isMobile} = useWebMediaQueries()
|
||||
const navigator = useNavigation<NavigationProp>()
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -28,11 +28,11 @@ const ShellInner = observer(() => {
|
|||
})
|
||||
}, [navigator, store.shell])
|
||||
|
||||
const showBottomBar = !isDesktop && !store.onboarding.isActive
|
||||
const showBottomBar = isMobile && !store.onboarding.isActive
|
||||
const showSideNavs =
|
||||
isDesktop && store.session.hasSession && !store.onboarding.isActive
|
||||
!isMobile && store.session.hasSession && !store.onboarding.isActive
|
||||
return (
|
||||
<>
|
||||
<View style={[s.hContentRegion, {overflow: 'hidden'}]}>
|
||||
<View style={s.hContentRegion}>
|
||||
<ErrorBoundary>
|
||||
<FlatNavigator />
|
||||
|
@ -67,7 +67,7 @@ const ShellInner = observer(() => {
|
|||
</View>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</>
|
||||
</View>
|
||||
)
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in New Issue