[Chat] Split view layout for web (#10258)
This commit is contained in:
@@ -811,14 +811,15 @@ export function ButtonIcon({
|
||||
* also so that we can calculate transforms.
|
||||
*/
|
||||
const iconSize = {
|
||||
'2xs': 8,
|
||||
xs: 12,
|
||||
sm: 16,
|
||||
md: 18,
|
||||
lg: 24,
|
||||
xl: 28,
|
||||
'2xs': 8,
|
||||
'2xl': 32,
|
||||
'3xl': 40,
|
||||
'4xl': 48,
|
||||
}[iconSizeShorthand]
|
||||
|
||||
/*
|
||||
|
||||
@@ -7,6 +7,7 @@ import {useNavigation} from '@react-navigation/native'
|
||||
import {HITSLOP_30} from '#/lib/constants'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {useSetDrawerOpen} from '#/state/shell'
|
||||
import {useIsWithinSplitView} from '#/screens/Messages/components/splitView/context'
|
||||
import {
|
||||
atoms as a,
|
||||
platform,
|
||||
@@ -46,6 +47,7 @@ export function Outer({
|
||||
const {gtMobile} = useBreakpoints()
|
||||
const {isWithinOffsetView} = useContext(ScrollbarOffsetContext)
|
||||
const {centerColumnOffset} = useLayoutBreakpoints()
|
||||
const {isWithinSplitView} = useIsWithinSplitView()
|
||||
|
||||
return (
|
||||
<View
|
||||
@@ -64,12 +66,13 @@ export function Outer({
|
||||
}),
|
||||
t.atoms.border_contrast_low,
|
||||
gtMobile && [a.mx_auto, {maxWidth: 600}],
|
||||
!isWithinOffsetView && {
|
||||
transform: [
|
||||
{translateX: centerColumnOffset ? CENTER_COLUMN_OFFSET : 0},
|
||||
{translateX: web(SCROLLBAR_OFFSET) ?? 0},
|
||||
],
|
||||
},
|
||||
!isWithinOffsetView &&
|
||||
!isWithinSplitView && {
|
||||
transform: [
|
||||
{translateX: centerColumnOffset ? CENTER_COLUMN_OFFSET : 0},
|
||||
{translateX: web(SCROLLBAR_OFFSET) ?? 0},
|
||||
],
|
||||
},
|
||||
]}>
|
||||
{children}
|
||||
</View>
|
||||
@@ -108,6 +111,7 @@ export function Slot({children}: {children?: React.ReactNode}) {
|
||||
export function BackButton({onPress, style, ...props}: Partial<ButtonProps>) {
|
||||
const {_} = useLingui()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const {isWithinRightPanel} = useIsWithinSplitView()
|
||||
|
||||
const onPressBack = useCallback(
|
||||
(evt: GestureResponderEvent) => {
|
||||
@@ -122,6 +126,10 @@ export function BackButton({onPress, style, ...props}: Partial<ButtonProps>) {
|
||||
[onPress, navigation],
|
||||
)
|
||||
|
||||
if (isWithinRightPanel) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Slot>
|
||||
<Button
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
import {forwardRef, memo, useContext, useMemo} from 'react'
|
||||
import {
|
||||
type StyleProp,
|
||||
StyleSheet,
|
||||
View,
|
||||
type ViewProps,
|
||||
type ViewStyle,
|
||||
} from 'react-native'
|
||||
import {
|
||||
KeyboardAwareScrollView,
|
||||
type KeyboardAwareScrollViewProps,
|
||||
} from 'react-native-keyboard-controller'
|
||||
import Animated, {
|
||||
type AnimatedScrollViewProps,
|
||||
useAnimatedProps,
|
||||
@@ -18,6 +13,7 @@ import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
|
||||
import {useEnableMinimalShellModeForScreen} from '#/state/shell'
|
||||
import {useShellLayout} from '#/state/shell/shell-layout'
|
||||
import {useIsWithinSplitView} from '#/screens/Messages/components/splitView/context'
|
||||
import {
|
||||
atoms as a,
|
||||
useBreakpoints,
|
||||
@@ -49,14 +45,20 @@ export const Screen = memo(function Screen({
|
||||
...props
|
||||
}: ScreenProps) {
|
||||
const {top} = useSafeAreaInsets()
|
||||
const {isWithinSplitView} = useIsWithinSplitView()
|
||||
|
||||
useEnableMinimalShellModeForScreen({enabled: minimalShell})
|
||||
|
||||
return (
|
||||
<>
|
||||
{IS_WEB && <WebCenterBorders />}
|
||||
{IS_WEB && !isWithinSplitView && <WebCenterBorders />}
|
||||
<View
|
||||
style={[a.util_screen_outer, {paddingTop: noInsetTop ? 0 : top}, style]}
|
||||
style={[
|
||||
a.util_screen_outer,
|
||||
{paddingTop: noInsetTop ? 0 : top},
|
||||
isWithinSplitView && {maxHeight: '100%'},
|
||||
style,
|
||||
]}
|
||||
{...props}
|
||||
/>
|
||||
</>
|
||||
@@ -85,6 +87,7 @@ export const Content = memo(
|
||||
) {
|
||||
const t = useTheme()
|
||||
const {footerHeight} = useShellLayout()
|
||||
const {isWithinSplitView} = useIsWithinSplitView()
|
||||
const animatedProps = useAnimatedProps(() => {
|
||||
return {
|
||||
scrollIndicatorInsets: {
|
||||
@@ -103,11 +106,18 @@ export const Content = memo(
|
||||
indicatorStyle={t.scheme === 'dark' ? 'white' : 'black'}
|
||||
// sets the scroll inset to the height of the footer
|
||||
animatedProps={animatedProps}
|
||||
style={[scrollViewStyles.common, style]}
|
||||
contentContainerStyle={[
|
||||
scrollViewStyles.contentContainer,
|
||||
contentContainerStyle,
|
||||
style={[
|
||||
a.w_full,
|
||||
isWithinSplitView &&
|
||||
web({
|
||||
flex: 1,
|
||||
overflowY: 'scroll',
|
||||
scrollbarWidth: 'thin',
|
||||
scrollbarColor: `${t.palette.contrast_100} transparent`,
|
||||
}),
|
||||
style,
|
||||
]}
|
||||
contentContainerStyle={[contentContainerStyle]}
|
||||
{...props}>
|
||||
{IS_WEB ? (
|
||||
<Center ignoreTabletLayoutOffset={ignoreTabletLayoutOffset}>
|
||||
@@ -122,45 +132,6 @@ export const Content = memo(
|
||||
}),
|
||||
)
|
||||
|
||||
const scrollViewStyles = StyleSheet.create({
|
||||
common: {
|
||||
width: '100%',
|
||||
},
|
||||
contentContainer: {
|
||||
paddingBottom: 100,
|
||||
},
|
||||
})
|
||||
|
||||
export type KeyboardAwareContentProps = KeyboardAwareScrollViewProps & {
|
||||
children: React.ReactNode
|
||||
contentContainerStyle?: StyleProp<ViewStyle>
|
||||
}
|
||||
|
||||
/**
|
||||
* Default scroll view for simple pages.
|
||||
*
|
||||
* BE SURE TO TEST THIS WHEN USING, it's untested as of writing this comment.
|
||||
*/
|
||||
export const KeyboardAwareContent = memo(function LayoutKeyboardAwareContent({
|
||||
children,
|
||||
style,
|
||||
contentContainerStyle,
|
||||
...props
|
||||
}: KeyboardAwareContentProps) {
|
||||
return (
|
||||
<KeyboardAwareScrollView
|
||||
style={[scrollViewStyles.common, style]}
|
||||
contentContainerStyle={[
|
||||
scrollViewStyles.contentContainer,
|
||||
contentContainerStyle,
|
||||
]}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
{...props}>
|
||||
{IS_WEB ? <Center>{children}</Center> : children}
|
||||
</KeyboardAwareScrollView>
|
||||
)
|
||||
})
|
||||
|
||||
/**
|
||||
* Utility component to center content within the screen
|
||||
*/
|
||||
@@ -174,28 +145,30 @@ export const Center = memo(function LayoutCenter({
|
||||
const {gtMobile} = useBreakpoints()
|
||||
const {centerColumnOffset} = useLayoutBreakpoints()
|
||||
const {isWithinDialog} = useDialogContext()
|
||||
const {isWithinSplitView} = useIsWithinSplitView()
|
||||
const ctx = useMemo(() => ({isWithinOffsetView: true}), [])
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
a.w_full,
|
||||
a.mx_auto,
|
||||
!isWithinSplitView && a.mx_auto,
|
||||
gtMobile && {
|
||||
maxWidth: 600,
|
||||
},
|
||||
!isWithinOffsetView && {
|
||||
transform: [
|
||||
{
|
||||
translateX:
|
||||
centerColumnOffset &&
|
||||
!ignoreTabletLayoutOffset &&
|
||||
!isWithinDialog
|
||||
? CENTER_COLUMN_OFFSET
|
||||
: 0,
|
||||
},
|
||||
{translateX: web(SCROLLBAR_OFFSET) ?? 0},
|
||||
],
|
||||
},
|
||||
!isWithinOffsetView &&
|
||||
!isWithinSplitView && {
|
||||
transform: [
|
||||
{
|
||||
translateX:
|
||||
centerColumnOffset &&
|
||||
!ignoreTabletLayoutOffset &&
|
||||
!isWithinDialog
|
||||
? CENTER_COLUMN_OFFSET
|
||||
: 0,
|
||||
},
|
||||
{translateX: web(SCROLLBAR_OFFSET) ?? 0},
|
||||
],
|
||||
},
|
||||
style,
|
||||
]}
|
||||
{...props}>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {createSinglePathSVG} from './TEMPLATE'
|
||||
import {createMultiPathSVG, createSinglePathSVG} from './TEMPLATE'
|
||||
|
||||
export const BubbleQuestion_Stroke2_Corner0_Rounded = createSinglePathSVG({
|
||||
path: 'M5.002 17.036V5h14v12.036h-3.986a1 1 0 0 0-.639.23l-2.375 1.968-2.344-1.965a1 1 0 0 0-.643-.233H5.002ZM20.002 3h-16a1 1 0 0 0-1 1v14.036a1 1 0 0 0 1 1h4.65l2.704 2.266a1 1 0 0 0 1.28.004l2.74-2.27h4.626a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1Zm-7.878 3.663c-1.39 0-2.5 1.135-2.5 2.515a1 1 0 0 0 2 0c0-.294.232-.515.5-.515a.507.507 0 0 1 .489.6.174.174 0 0 1-.027.048 1.1 1.1 0 0 1-.267.226c-.508.345-1.128.923-1.286 1.978a1 1 0 1 0 1.978.297.762.762 0 0 1 .14-.359c.063-.086.155-.169.293-.262.436-.297 1.18-.885 1.18-2.013 0-1.38-1.11-2.515-2.5-2.515ZM12 15.75a1.25 1.25 0 1 1 0-2.5 1.25 1.25 0 0 1 0 2.5Z',
|
||||
@@ -15,3 +15,12 @@ export const Bubble_Stroke2_Corner3_Rounded = createSinglePathSVG({
|
||||
export const Bubbles_Stroke2_Corner2_Rounded = createSinglePathSVG({
|
||||
path: 'M6.002 6a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3h-1v1a3 3 0 0 1-3 3h-4.24l-4.274 2.374a1 1 0 0 1-1.486-.874V19a3 3 0 0 1-3-3v-6a3 3 0 0 1 3-3h1V6Zm-1 3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h1a1 1 0 0 1 1 1v.8l3.015-1.674a1 1 0 0 1 .485-.126h4.5a1 1 0 0 0 1-1v-1.933a1 1 0 0 1 0-.134V10a1 1 0 0 0-1-1h-10Zm13 4v-3a3 3 0 0 0-3-3h-7V6a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-1Z',
|
||||
})
|
||||
|
||||
export const BubbleSmile_Stroke2_Corner2_Rounded_Large = createMultiPathSVG({
|
||||
viewBox: '0 0 64 64',
|
||||
paths: [
|
||||
'M55 32C55 19.298 44.703 9 32 9S9 19.298 9 32c0 3.463.765 6.745 2.134 9.688.358.769.479 1.658.267 2.525l-2.076 8.51a1.667 1.667 0 0 0 1.987 2.02l8.876-2.005a3.84 3.84 0 0 1 2.412.26A22.9 22.9 0 0 0 32 55c12.703 0 23-10.297 23-23Zm2 0c0 13.807-11.193 25-25 25-3.638 0-7.098-.778-10.219-2.177a1.84 1.84 0 0 0-1.152-.133l-8.877 2.004c-2.655.6-5.015-1.802-4.37-4.446l2.077-8.51c.094-.384.046-.809-.139-1.207A24.9 24.9 0 0 1 7 32C7 18.193 18.193 7 32 7s25 11.193 25 25Z',
|
||||
'M17.667 32a2.333 2.333 0 1 0 4.667 0 2.333 2.333 0 0 0-4.667 0Zm24 0a2.334 2.334 0 1 0 4.667 0 2.334 2.334 0 0 0-4.667 0Z',
|
||||
'M35.137 37.215a1 1 0 0 1 1.414 1.414 6.143 6.143 0 0 1-8.687 0 1 1 0 0 1 1.415-1.414 4.14 4.14 0 0 0 5.858 0Z',
|
||||
],
|
||||
})
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import {createSinglePathSVG} from './TEMPLATE'
|
||||
|
||||
export const Inbox_Stroke2_Corner2_Rounded = createSinglePathSVG({
|
||||
path: 'M19 14h-2.417a5 5 0 0 1-9.166 0H5v4a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-4Zm0-8a1 1 0 0 0-.898-.995L18 5H6a1 1 0 0 0-1 1v6h3.126a1 1 0 0 1 .969.751 3.001 3.001 0 0 0 5.81 0l.056-.16a1 1 0 0 1 .913-.591H19V6Zm2 12a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3h12l.154.004A3 3 0 0 1 21 6v12Z',
|
||||
})
|
||||
|
||||
export const Inbox_Stroke2_Corner2_Rounded_Large = createSinglePathSVG({
|
||||
viewBox: '0 0 64 64',
|
||||
path: 'M57.666 33.416q-.001-.21-.022-.419L57.6 33H44a4.33 4.33 0 0 0-3.466 1.734l-.8 1.066a6.34 6.34 0 0 1-5.068 2.533h-5.333a6.33 6.33 0 0 1-5.066-2.533l-.8-1.066A4.33 4.33 0 0 0 20 33H6.4l-.045-.003a4 4 0 0 0-.022.42v11.916a4.333 4.333 0 0 0 4.333 4.333h42.667a4.333 4.333 0 0 0 4.333-4.333V33.416Zm-38.57-19.083a4.33 4.33 0 0 0-3.764 2.184L7.057 31H20c1.994 0 3.87.939 5.067 2.533l.8 1.067a4.33 4.33 0 0 0 3.466 1.733h5.333a4.33 4.33 0 0 0 3.467-1.733l.8-1.067A6.34 6.34 0 0 1 44 31h12.944l-8.277-14.483a4.33 4.33 0 0 0-3.762-2.184h-25.81Zm40.57 31a6.333 6.333 0 0 1-6.333 6.333H10.666a6.333 6.333 0 0 1-6.333-6.333V33.416c0-1.102.288-2.185.835-3.142l8.428-14.75a6.33 6.33 0 0 1 5.5-3.19h25.809a6.33 6.33 0 0 1 5.499 3.19l8.427 14.75h.001c.547.957.834 2.04.834 3.142v11.917Z',
|
||||
})
|
||||
@@ -51,7 +51,7 @@ export function createSinglePathSVG({
|
||||
fill="none"
|
||||
{...rest}
|
||||
ref={ref}
|
||||
viewBox={viewBox || '0 0 24 24'}
|
||||
viewBox={viewBox ?? '0 0 24 24'}
|
||||
width={size}
|
||||
height={size}
|
||||
style={[style]}>
|
||||
@@ -71,7 +71,13 @@ export function createSinglePathSVG({
|
||||
})
|
||||
}
|
||||
|
||||
export function createSinglePathSVG2({path}: {path: string}) {
|
||||
export function createMultiPathSVG({
|
||||
paths,
|
||||
viewBox,
|
||||
}: {
|
||||
paths: string[]
|
||||
viewBox?: string
|
||||
}) {
|
||||
return forwardRef<Svg, Props>(function LogoImpl(props, ref) {
|
||||
const {fill, size, style, gradient, ...rest} = useCommonSVGProps(props)
|
||||
|
||||
@@ -80,27 +86,7 @@ export function createSinglePathSVG2({path}: {path: string}) {
|
||||
fill="none"
|
||||
{...rest}
|
||||
ref={ref}
|
||||
viewBox="0 0 24 24"
|
||||
width={size}
|
||||
height={size}
|
||||
style={style}>
|
||||
{gradient}
|
||||
<Path fill={fill} fillRule="evenodd" clipRule="evenodd" d={path} />
|
||||
</Svg>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export function createMultiPathSVG({paths}: {paths: string[]}) {
|
||||
return forwardRef<Svg, Props>(function LogoImpl(props, ref) {
|
||||
const {fill, size, style, gradient, ...rest} = useCommonSVGProps(props)
|
||||
|
||||
return (
|
||||
<Svg
|
||||
fill="none"
|
||||
{...rest}
|
||||
ref={ref}
|
||||
viewBox="0 0 24 24"
|
||||
viewBox={viewBox ?? '0 0 24 24'}
|
||||
width={size}
|
||||
height={size}
|
||||
style={[style]}>
|
||||
|
||||
@@ -21,6 +21,7 @@ export const sizes = {
|
||||
xl: 28,
|
||||
'2xl': 32,
|
||||
'3xl': 48,
|
||||
'4xl': 64,
|
||||
} as const
|
||||
|
||||
export function useCommonSVGProps(props: Props) {
|
||||
|
||||
Reference in New Issue
Block a user