diff options
Diffstat (limited to 'src/view/com')
41 files changed, 469 insertions, 302 deletions
diff --git a/src/view/com/auth/onboarding/WelcomeDesktop.tsx b/src/view/com/auth/onboarding/WelcomeDesktop.tsx index e63693443..7b7555ace 100644 --- a/src/view/com/auth/onboarding/WelcomeDesktop.tsx +++ b/src/view/com/auth/onboarding/WelcomeDesktop.tsx @@ -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 diff --git a/src/view/com/auth/onboarding/WelcomeMobile.tsx b/src/view/com/auth/onboarding/WelcomeMobile.tsx index eb72de836..0f627ad0b 100644 --- a/src/view/com/auth/onboarding/WelcomeMobile.tsx +++ b/src/view/com/auth/onboarding/WelcomeMobile.tsx @@ -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', }, diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index c801c47bf..8ed0bb378 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -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, diff --git a/src/view/com/composer/Prompt.tsx b/src/view/com/composer/Prompt.tsx index 98a10b0f5..01fd7d1fa 100644 --- a/src/view/com/composer/Prompt.tsx +++ b/src/view/com/composer/Prompt.tsx @@ -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> diff --git a/src/view/com/composer/photos/Gallery.tsx b/src/view/com/composer/photos/Gallery.tsx index 6dba2f011..d5465f79a 100644 --- a/src/view/com/composer/photos/Gallery.tsx +++ b/src/view/com/composer/photos/Gallery.tsx @@ -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, diff --git a/src/view/com/lists/ListItems.tsx b/src/view/com/lists/ListItems.tsx index 7f2173d78..d611bc504 100644 --- a/src/view/com/lists/ListItems.tsx +++ b/src/view/com/lists/ListItems.tsx @@ -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, diff --git a/src/view/com/modals/AddAppPasswords.tsx b/src/view/com/modals/AddAppPasswords.tsx index 6117924ae..2a8672131 100644 --- a/src/view/com/modals/AddAppPasswords.tsx +++ b/src/view/com/modals/AddAppPasswords.tsx @@ -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: { diff --git a/src/view/com/modals/AltImage.tsx b/src/view/com/modals/AltImage.tsx index e1145a0fe..c084e84a3 100644 --- a/src/view/com/modals/AltImage.tsx +++ b/src/view/com/modals/AltImage.tsx @@ -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, diff --git a/src/view/com/modals/Confirm.tsx b/src/view/com/modals/Confirm.tsx index f9bc0de14..270177182 100644 --- a/src/view/com/modals/Confirm.tsx +++ b/src/view/com/modals/Confirm.tsx @@ -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', diff --git a/src/view/com/modals/ContentFilteringSettings.tsx b/src/view/com/modals/ContentFilteringSettings.tsx index f39351feb..588b21353 100644 --- a/src/view/com/modals/ContentFilteringSettings.tsx +++ b/src/view/com/modals/ContentFilteringSettings.tsx @@ -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: { diff --git a/src/view/com/modals/CreateOrEditMuteList.tsx b/src/view/com/modals/CreateOrEditMuteList.tsx index 09048b5db..3f3cfc5f0 100644 --- a/src/view/com/modals/CreateOrEditMuteList.tsx +++ b/src/view/com/modals/CreateOrEditMuteList.tsx @@ -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', diff --git a/src/view/com/modals/DeleteAccount.tsx b/src/view/com/modals/DeleteAccount.tsx index b4933a1f2..98482457c 100644 --- a/src/view/com/modals/DeleteAccount.tsx +++ b/src/view/com/modals/DeleteAccount.tsx @@ -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, ]}> diff --git a/src/view/com/modals/EditImage.tsx b/src/view/com/modals/EditImage.tsx index a4e06b955..e4cfbac35 100644 --- a/src/view/com/modals/EditImage.tsx +++ b/src/view/com/modals/EditImage.tsx @@ -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, diff --git a/src/view/com/modals/InviteCodes.tsx b/src/view/com/modals/InviteCodes.tsx index d46579f09..ba3cc382b 100644 --- a/src/view/com/modals/InviteCodes.tsx +++ b/src/view/com/modals/InviteCodes.tsx @@ -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', diff --git a/src/view/com/modals/ListAddRemoveUser.tsx b/src/view/com/modals/ListAddRemoveUser.tsx index bfb7e4dc0..e00509285 100644 --- a/src/view/com/modals/ListAddRemoveUser.tsx +++ b/src/view/com/modals/ListAddRemoveUser.tsx @@ -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', diff --git a/src/view/com/modals/Modal.web.tsx b/src/view/com/modals/Modal.web.tsx index 5cfdd6bb3..b3a79221d 100644 --- a/src/view/com/modals/Modal.web.tsx +++ b/src/view/com/modals/Modal.web.tsx @@ -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, ]}> diff --git a/src/view/com/modals/ModerationDetails.tsx b/src/view/com/modals/ModerationDetails.tsx index b0e68e61b..bd51845c6 100644 --- a/src/view/com/modals/ModerationDetails.tsx +++ b/src/view/com/modals/ModerationDetails.tsx @@ -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, }, }) diff --git a/src/view/com/modals/SelfLabel.tsx b/src/view/com/modals/SelfLabel.tsx index 42863fd33..820f2895b 100644 --- a/src/view/com/modals/SelfLabel.tsx +++ b/src/view/com/modals/SelfLabel.tsx @@ -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, diff --git a/src/view/com/modals/lang-settings/ConfirmLanguagesButton.tsx b/src/view/com/modals/lang-settings/ConfirmLanguagesButton.tsx index e1ecce589..c2d0c222a 100644 --- a/src/view/com/modals/lang-settings/ConfirmLanguagesButton.tsx +++ b/src/view/com/modals/lang-settings/ConfirmLanguagesButton.tsx @@ -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', diff --git a/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx b/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx index 4f7bbc9c7..e577991c5 100644 --- a/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx +++ b/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx @@ -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, - }, }) diff --git a/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx b/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx index 0f336e7bc..c80f8731c 100644 --- a/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx +++ b/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx @@ -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, diff --git a/src/view/com/modals/report/InputIssueDetails.tsx b/src/view/com/modals/report/InputIssueDetails.tsx index a2e5069a8..70a8f7b24 100644 --- a/src/view/com/modals/report/InputIssueDetails.tsx +++ b/src/view/com/modals/report/InputIssueDetails.tsx @@ -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', diff --git a/src/view/com/modals/report/Modal.tsx b/src/view/com/modals/report/Modal.tsx index f386b110d..8aabe0871 100644 --- a/src/view/com/modals/report/Modal.tsx +++ b/src/view/com/modals/report/Modal.tsx @@ -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', diff --git a/src/view/com/pager/FeedsTabBar.web.tsx b/src/view/com/pager/FeedsTabBar.web.tsx index 0df915950..6e94ab60e 100644 --- a/src/view/com/pager/FeedsTabBar.web.tsx +++ b/src/view/com/pager/FeedsTabBar.web.tsx @@ -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} /> diff --git a/src/view/com/pager/TabBar.tsx b/src/view/com/pager/TabBar.tsx index d454e89f1..319d28f95 100644 --- a/src/view/com/pager/TabBar.tsx +++ b/src/view/com/pager/TabBar.tsx @@ -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', + }, +}) diff --git a/src/view/com/post-thread/PostThread.tsx b/src/view/com/post-thread/PostThread.tsx index 3e951dbf0..f7766dfb7 100644 --- a/src/view/com/post-thread/PostThread.tsx +++ b/src/view/com/post-thread/PostThread.tsx @@ -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, }, }) diff --git a/src/view/com/posts/MultiFeed.tsx b/src/view/com/posts/MultiFeed.tsx index 97899e554..9c8f4f246 100644 --- a/src/view/com/posts/MultiFeed.tsx +++ b/src/view/com/posts/MultiFeed.tsx @@ -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', diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx index dd3fb530e..8786fd0b9 100644 --- a/src/view/com/profile/ProfileHeader.tsx +++ b/src/view/com/profile/ProfileHeader.tsx @@ -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} diff --git a/src/view/com/search/HeaderWithInput.tsx b/src/view/com/search/HeaderWithInput.tsx index f825c578e..7a8676602 100644 --- a/src/view/com/search/HeaderWithInput.tsx +++ b/src/view/com/search/HeaderWithInput.tsx @@ -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, diff --git a/src/view/com/search/SearchResults.tsx b/src/view/com/search/SearchResults.tsx index 984277705..e74a8cfe4 100644 --- a/src/view/com/search/SearchResults.tsx +++ b/src/view/com/search/SearchResults.tsx @@ -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, - }, }) diff --git a/src/view/com/util/ViewHeader.tsx b/src/view/com/util/ViewHeader.tsx index 7482db8eb..91cdb08c7 100644 --- a/src/view/com/util/ViewHeader.tsx +++ b/src/view/com/util/ViewHeader.tsx @@ -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', diff --git a/src/view/com/util/Views.web.tsx b/src/view/com/util/Views.web.tsx index 3313492e1..58a367f20 100644 --- a/src/view/com/util/Views.web.tsx +++ b/src/view/com/util/Views.web.tsx @@ -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', }, }) diff --git a/src/view/com/util/fab/FABInner.tsx b/src/view/com/util/fab/FABInner.tsx index 76824e575..afd172c82 100644 --- a/src/view/com/util/fab/FABInner.tsx +++ b/src/view/com/util/fab/FABInner.tsx @@ -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', }, diff --git a/src/view/com/util/forms/SelectableBtn.tsx b/src/view/com/util/forms/SelectableBtn.tsx index 4b494264e..f09d063a1 100644 --- a/src/view/com/util/forms/SelectableBtn.tsx +++ b/src/view/com/util/forms/SelectableBtn.tsx @@ -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, diff --git a/src/view/com/util/layouts/Breakpoints.web.tsx b/src/view/com/util/layouts/Breakpoints.web.tsx index 7031a1735..5cf73df0c 100644 --- a/src/view/com/util/layouts/Breakpoints.web.tsx +++ b/src/view/com/util/layouts/Breakpoints.web.tsx @@ -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> diff --git a/src/view/com/util/load-latest/LoadLatestBtn.web.tsx b/src/view/com/util/load-latest/LoadLatestBtn.web.tsx index c90e5dfb1..c9576e56b 100644 --- a/src/view/com/util/load-latest/LoadLatestBtn.web.tsx +++ b/src/view/com/util/load-latest/LoadLatestBtn.web.tsx @@ -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} diff --git a/src/view/com/util/moderation/ContentHider.tsx b/src/view/com/util/moderation/ContentHider.tsx index 853f7840c..6cf1cefd0 100644 --- a/src/view/com/util/moderation/ContentHider.tsx +++ b/src/view/com/util/moderation/ContentHider.tsx @@ -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', diff --git a/src/view/com/util/moderation/PostHider.tsx b/src/view/com/util/moderation/PostHider.tsx index 2a52561d4..443885dfa 100644 --- a/src/view/com/util/moderation/PostHider.tsx +++ b/src/view/com/util/moderation/PostHider.tsx @@ -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: { diff --git a/src/view/com/util/moderation/ScreenHider.tsx b/src/view/com/util/moderation/ScreenHider.tsx index b76b1101c..0224b9fee 100644 --- a/src/view/com/util/moderation/ScreenHider.tsx +++ b/src/view/com/util/moderation/ScreenHider.tsx @@ -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" diff --git a/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx b/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx index 81f1ca560..d5bb38fb2 100644 --- a/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx +++ b/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx @@ -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, diff --git a/src/view/com/util/post-embeds/index.tsx b/src/view/com/util/post-embeds/index.tsx index bf2365f18..ce6da4a1b 100644 --- a/src/view/com/util/post-embeds/index.tsx +++ b/src/view/com/util/post-embeds/index.tsx @@ -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, |