Better tablet layout (#7656)

* better tablet layout

* adjust left nav spacing

* add right nav to pwi

* clearer logic

* fix a couple screens that don't need the tablet layout

* fix horiz scroll bar

* fix double trending

* fix ts-ignore

* fix labeller screen

* don't offset things within dialogs

* fix load latest button (and add scale animation)

* center loader on home screen

* adjust break points

* adjust left nav spacing

* fix load latest btn (again)

* add lang select to right nav if left nav is minimal

* fix double scrollbar on tiny screens

* fix scrollbar

* fix type errors
This commit is contained in:
Samuel Newman
2025-02-25 09:20:37 -08:00
committed by GitHub
parent 0437838649
commit cc8369e868
17 changed files with 211 additions and 122 deletions
+27 -6
View File
@@ -26,6 +26,8 @@ import Animated from 'react-native-reanimated'
import {usePalette} from '#/lib/hooks/usePalette'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {addStyle} from '#/lib/styles'
import {useLayoutBreakpoints} from '#/alf'
import {useDialogContext} from '#/components/Dialog'
interface AddedProps {
desktopFixedHeight?: boolean | number
@@ -46,9 +48,14 @@ export const CenteredView = React.forwardRef(function CenteredView(
) {
const pal = usePalette('default')
const {isMobile} = useWebMediaQueries()
const {centerColumnOffset} = useLayoutBreakpoints()
const {isWithinDialog} = useDialogContext()
if (!isMobile) {
style = addStyle(style, styles.container)
}
if (centerColumnOffset && !isWithinDialog) {
style = addStyle(style, styles.containerOffset)
}
if (topBorder) {
style = addStyle(style, {
borderTopWidth: 1,
@@ -71,12 +78,17 @@ export const FlatList_INTERNAL = React.forwardRef(function FlatListImpl<ItemT>(
ref: React.Ref<FlatList<ItemT>>,
) {
const {isMobile} = useWebMediaQueries()
const {centerColumnOffset} = useLayoutBreakpoints()
const {isWithinDialog} = useDialogContext()
if (!isMobile) {
contentContainerStyle = addStyle(
contentContainerStyle,
styles.containerScroll,
)
}
if (centerColumnOffset && !isWithinDialog) {
style = addStyle(style, styles.containerOffset)
}
if (contentOffset && contentOffset?.y !== 0) {
// NOTE
// we use paddingTop & contentOffset to space around the floating header
@@ -92,7 +104,7 @@ export const FlatList_INTERNAL = React.forwardRef(function FlatListImpl<ItemT>(
}
if (desktopFixedHeight) {
if (typeof desktopFixedHeight === 'number') {
// @ts-ignore Web only -prf
// @ts-expect-error Web only -prf
style = addStyle(style, {
height: `calc(100vh - ${desktopFixedHeight}px)`,
})
@@ -108,9 +120,9 @@ export const FlatList_INTERNAL = React.forwardRef(function FlatListImpl<ItemT>(
// around this, we set data-stable-gutters which can then be
// styled in our external CSS.
// -prf
// @ts-ignore web only -prf
// @ts-expect-error web only -prf
props.dataSet = props.dataSet || {}
// @ts-ignore web only -prf
// @ts-expect-error web only -prf
props.dataSet.stableGutters = '1'
}
}
@@ -133,16 +145,22 @@ export const ScrollView = React.forwardRef(function ScrollViewImpl(
ref: React.Ref<Animated.ScrollView>,
) {
const {isMobile} = useWebMediaQueries()
const {centerColumnOffset} = useLayoutBreakpoints()
if (!isMobile) {
contentContainerStyle = addStyle(
contentContainerStyle,
styles.containerScroll,
)
}
if (centerColumnOffset) {
contentContainerStyle = addStyle(
contentContainerStyle,
styles.containerOffset,
)
}
return (
<Animated.ScrollView
contentContainerStyle={[styles.contentContainer, contentContainerStyle]}
// @ts-ignore something is wrong with the reanimated types -prf
ref={ref}
{...props}
/>
@@ -151,7 +169,7 @@ export const ScrollView = React.forwardRef(function ScrollViewImpl(
const styles = StyleSheet.create({
contentContainer: {
// @ts-ignore web only
// @ts-expect-error web only
minHeight: '100vh',
},
container: {
@@ -160,6 +178,9 @@ const styles = StyleSheet.create({
marginLeft: 'auto',
marginRight: 'auto',
},
containerOffset: {
transform: [{translateX: -150}],
},
containerScroll: {
width: '100%',
maxWidth: 600,
@@ -167,7 +188,7 @@ const styles = StyleSheet.create({
marginRight: 'auto',
},
fixedHeight: {
// @ts-ignore web only
// @ts-expect-error web only
height: '100vh',
},
})
+36 -28
View File
@@ -1,10 +1,11 @@
import {StyleSheet, TouchableOpacity, View} from 'react-native'
import {StyleSheet, View} from 'react-native'
import Animated from 'react-native-reanimated'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {useMediaQuery} from 'react-responsive'
import {HITSLOP_20} from '#/lib/constants'
import {PressableScale} from '#/lib/custom-animations/PressableScale'
import {useMinimalShellFabTransform} from '#/lib/hooks/useMinimalShellTransform'
import {usePalette} from '#/lib/hooks/usePalette'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
@@ -13,9 +14,7 @@ import {useGate} from '#/lib/statsig/statsig'
import {colors} from '#/lib/styles'
import {isWeb} from '#/platform/detection'
import {useSession} from '#/state/session'
const AnimatedTouchableOpacity =
Animated.createAnimatedComponent(TouchableOpacity)
import {useLayoutBreakpoints} from '#/alf'
export function LoadLatestBtn({
onPress,
@@ -29,6 +28,7 @@ export function LoadLatestBtn({
const pal = usePalette('default')
const {hasSession} = useSession()
const {isDesktop, isTablet, isMobile, isTabletOrMobile} = useWebMediaQueries()
const {centerColumnOffset} = useLayoutBreakpoints()
const fabMinimalShellTransform = useMinimalShellFabTransform()
const insets = useSafeAreaInsets()
@@ -49,33 +49,37 @@ export function LoadLatestBtn({
: {bottom: clamp(insets.bottom, 15, 60) + 15}
return (
<AnimatedTouchableOpacity
style={[
styles.loadLatest,
isDesktop &&
(isTallViewport
? styles.loadLatestOutOfLine
: styles.loadLatestInline),
isTablet && styles.loadLatestInline,
pal.borderDark,
pal.view,
bottomPosition,
showBottomBar && fabMinimalShellTransform,
]}
onPress={onPress}
hitSlop={HITSLOP_20}
accessibilityRole="button"
accessibilityLabel={label}
accessibilityHint="">
<FontAwesomeIcon icon="angle-up" color={pal.colors.text} size={19} />
{showIndicator && <View style={[styles.indicator, pal.borderDark]} />}
</AnimatedTouchableOpacity>
<Animated.View style={[showBottomBar && fabMinimalShellTransform]}>
<PressableScale
style={[
styles.loadLatest,
isDesktop &&
(isTallViewport
? styles.loadLatestOutOfLine
: styles.loadLatestInline),
isTablet &&
(centerColumnOffset
? styles.loadLatestInlineOffset
: styles.loadLatestInline),
pal.borderDark,
pal.view,
bottomPosition,
]}
onPress={onPress}
hitSlop={HITSLOP_20}
accessibilityLabel={label}
accessibilityHint=""
targetScale={0.9}>
<FontAwesomeIcon icon="angle-up" color={pal.colors.text} size={19} />
{showIndicator && <View style={[styles.indicator, pal.borderDark]} />}
</PressableScale>
</Animated.View>
)
}
const styles = StyleSheet.create({
loadLatest: {
// @ts-ignore 'fixed' is web only -prf
zIndex: 20,
position: isWeb ? 'fixed' : 'absolute',
left: 18,
borderWidth: StyleSheet.hairlineWidth,
@@ -87,11 +91,15 @@ const styles = StyleSheet.create({
justifyContent: 'center',
},
loadLatestInline: {
// @ts-ignore web only
// @ts-expect-error web only
left: 'calc(50vw - 282px)',
},
loadLatestInlineOffset: {
// @ts-expect-error web only
left: 'calc(50vw - 432px)',
},
loadLatestOutOfLine: {
// @ts-ignore web only
// @ts-expect-error web only
left: 'calc(50vw - 382px)',
},
indicator: {