[Layout] Base (#6907)
* Add common gutter styles as hook * Add computed scrollbar gutter CSS vars * Add new layout components * Replace layout components in settings screens * Remove old back button * Invert web border logic for easier migration * Clean up Slot API * Port over FF handling of scrollbar offset * Trade boilerplate for ease of use * Limit to one line * Allow two lines, fix wrapping * Fix alignment * sticky headers * set max with on header and center * [Layout] Notifications Header (#6910) * Replace notifications screen header * fix cropped indicator --------- Co-authored-by: Samuel Newman <mozzius@protonmail.com> * Replace Hashtag header (#6928) * [Layout] ChatList header (#6929) * Replace ChatList header * update chat settings as well --------- Co-authored-by: Samuel Newman <mozzius@protonmail.com> * Add web borders to Chat settings * Remove unused var * Move ChatList header outside center * Replace empty chat layout * fix breakpoints * [Layout] Scrollbar gutters (#6908) * Fix sidebar alignment * Make sure scrollbars don't hide * Gift left nav more space * Use stable one-edge, update logic in RightNav * Ope * Increase width * Reset * Add transform to sidebars * Remove bg in sidebars * Handle shifts in layout components * Replace scroll-removal handling * Make react-remove-scroll an explicit dep * Remove unused script * use correct scroll insets (#6950) * [Layout] Feeds headers (#6913) * Replace ViewHeader internals, duplicate old ViewHeader * Replace Feeds header * Replace SavedFeeds header * Visual alignment * Uglier but clear * Use old ViewHeader for SavedFeeds * use Layout.Center instead of Layout.Content * use left-aligned header for feed edit * delete unused old view header --------- Co-authored-by: Samuel Newman <mozzius@protonmail.com> * [Layout] Every other screen (#6953) * attempt to fix double borders on every other screen * delete ListHeaderDesktop * delete `SimpleViewHeader` and fix screens (#6956) * Make Layout.Center not full height * Refactor List to use Layout.Center, remove built-in borders * Fix Home screen * Refactor PagerWithHeader to use Layout components * Replace components in ProfileFeed and ProfileList * Borders on Profile * Search screen replacements * use new header for profile subpage header (#6958) * Search AutocompleteResults * use new header for starter pack wizard (#6957) * Fix post thread * Enable borders by default * Moderation muted and blocked accounts * Fix scrollbar offset on Labeler * Remove ScrollView from Moderation * Remove ScrollView from Deactivated * Remove ScrollView from onboarding * Remove ScrollView from SignupQueued * Mark deprecations * fix lint * Fix double borders on profile load * Remove unneeded CenteredView from noty Feed * Remove double Center layout on Notifications screen * Remove double Center layout on ChatList screen * Handle scrollbar offset in chat * Use new atom for other scrollbar offsets * Remove borders from old views * Better doc * Remove temp migration prop * Fix new atom usage on native * Clean up Hashtag screen * Layout docs * Clarify usage in Pager * Handle nested offset contexts * Clean up Layout * fix feeds page * asymmetric header on native (#6969) * Reusable header const * Fix up home header * Add back button to convo * Add hitslop to header buttons * Comment * Better handling on native for new atom * Format * Fix nested flatlist on mod screens * Use react-remove-scroll-bar directly * Fix notification count overflow on web * Clarify doc --------- Co-authored-by: Samuel Newman <mozzius@protonmail.com>
This commit is contained in:
@@ -3,8 +3,8 @@ import {StyleSheet, View} from 'react-native'
|
||||
import {DismissableLayer} from '@radix-ui/react-dismissable-layer'
|
||||
import {useFocusGuards} from '@radix-ui/react-focus-guards'
|
||||
import {FocusScope} from '@radix-ui/react-focus-scope'
|
||||
import {RemoveScrollBar} from 'react-remove-scroll-bar'
|
||||
|
||||
import {useWebBodyScrollLock} from '#/lib/hooks/useWebBodyScrollLock'
|
||||
import {useModals} from '#/state/modals'
|
||||
import {ComposerOpts, useComposerState} from '#/state/shell/composer'
|
||||
import {
|
||||
@@ -20,8 +20,6 @@ export function Composer({}: {winHeight: number}) {
|
||||
const state = useComposerState()
|
||||
const isActive = !!state
|
||||
|
||||
useWebBodyScrollLock(isActive)
|
||||
|
||||
// rendering
|
||||
// =
|
||||
|
||||
@@ -29,7 +27,12 @@ export function Composer({}: {winHeight: number}) {
|
||||
return <View />
|
||||
}
|
||||
|
||||
return <Inner state={state} />
|
||||
return (
|
||||
<>
|
||||
<RemoveScrollBar />
|
||||
<Inner state={state} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function Inner({state}: {state: ComposerOpts}) {
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import React from 'react'
|
||||
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import {
|
||||
FontAwesomeIcon,
|
||||
FontAwesomeIconStyle,
|
||||
} from '@fortawesome/react-native-fontawesome'
|
||||
import {StyleSheet, View} from 'react-native'
|
||||
import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {
|
||||
@@ -14,9 +11,9 @@ import {
|
||||
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||
import {getCurrentRoute, isStateAtTabRoot, isTab} from '#/lib/routes/helpers'
|
||||
import {getCurrentRoute, isTab} from '#/lib/routes/helpers'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {CommonNavigatorParams, NavigationProp} from '#/lib/routes/types'
|
||||
import {CommonNavigatorParams} from '#/lib/routes/types'
|
||||
import {isInvalidHandle} from '#/lib/strings/handles'
|
||||
import {emitSoftReset} from '#/state/events'
|
||||
import {useFetchHandle} from '#/state/queries/handle'
|
||||
@@ -101,47 +98,6 @@ function ProfileCard() {
|
||||
)
|
||||
}
|
||||
|
||||
const HIDDEN_BACK_BNT_ROUTES = ['StarterPackWizard', 'StarterPackEdit']
|
||||
|
||||
function BackBtn() {
|
||||
const {isTablet} = useWebMediaQueries()
|
||||
const pal = usePalette('default')
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const {_} = useLingui()
|
||||
const shouldShow = useNavigationState(
|
||||
state =>
|
||||
!isStateAtTabRoot(state) &&
|
||||
!HIDDEN_BACK_BNT_ROUTES.includes(getCurrentRoute(state).name),
|
||||
)
|
||||
|
||||
const onPressBack = React.useCallback(() => {
|
||||
if (navigation.canGoBack()) {
|
||||
navigation.goBack()
|
||||
} else {
|
||||
navigation.navigate('Home')
|
||||
}
|
||||
}, [navigation])
|
||||
|
||||
if (!shouldShow || isTablet) {
|
||||
return <></>
|
||||
}
|
||||
return (
|
||||
<TouchableOpacity
|
||||
testID="viewHeaderBackOrMenuBtn"
|
||||
onPress={onPressBack}
|
||||
style={styles.backBtn}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={_(msg`Go back`)}
|
||||
accessibilityHint="">
|
||||
<FontAwesomeIcon
|
||||
size={24}
|
||||
icon="angle-left"
|
||||
style={pal.text as FontAwesomeIconStyle}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
interface NavItemProps {
|
||||
count?: string
|
||||
href: string
|
||||
@@ -220,35 +176,44 @@ function NavItem({count, href, icon, iconFilled, label}: NavItemProps) {
|
||||
]}>
|
||||
{isCurrent ? iconFilled : icon}
|
||||
{typeof count === 'string' && count ? (
|
||||
<Text
|
||||
accessibilityLabel={_(msg`${count} unread items`)}
|
||||
accessibilityHint=""
|
||||
accessible={true}
|
||||
<View
|
||||
style={[
|
||||
a.absolute,
|
||||
a.text_xs,
|
||||
a.font_bold,
|
||||
a.rounded_full,
|
||||
a.text_center,
|
||||
{
|
||||
top: '-10%',
|
||||
left: count.length === 1 ? '50%' : '40%',
|
||||
backgroundColor: t.palette.primary_500,
|
||||
color: t.palette.white,
|
||||
lineHeight: a.text_sm.fontSize,
|
||||
paddingHorizontal: 4,
|
||||
paddingVertical: 1,
|
||||
minWidth: 16,
|
||||
},
|
||||
isTablet && [
|
||||
{
|
||||
top: '10%',
|
||||
left: count.length === 1 ? '50%' : '40%',
|
||||
},
|
||||
],
|
||||
a.inset_0,
|
||||
{right: -20}, // more breathing room
|
||||
]}>
|
||||
{count}
|
||||
</Text>
|
||||
<Text
|
||||
accessibilityLabel={_(msg`${count} unread items`)}
|
||||
accessibilityHint=""
|
||||
accessible={true}
|
||||
numberOfLines={1}
|
||||
style={[
|
||||
a.absolute,
|
||||
a.text_xs,
|
||||
a.font_bold,
|
||||
a.rounded_full,
|
||||
a.text_center,
|
||||
a.leading_tight,
|
||||
{
|
||||
top: '-10%',
|
||||
left: count.length === 1 ? 12 : 8,
|
||||
backgroundColor: t.palette.primary_500,
|
||||
color: t.palette.white,
|
||||
lineHeight: a.text_sm.fontSize,
|
||||
paddingHorizontal: 4,
|
||||
paddingVertical: 1,
|
||||
minWidth: 16,
|
||||
},
|
||||
isTablet && [
|
||||
{
|
||||
top: '10%',
|
||||
left: count.length === 1 ? 20 : 16,
|
||||
},
|
||||
],
|
||||
]}>
|
||||
{count}
|
||||
</Text>
|
||||
</View>
|
||||
) : null}
|
||||
</View>
|
||||
{gtTablet && (
|
||||
@@ -366,9 +331,9 @@ export function DesktopLeftNav() {
|
||||
<View
|
||||
role="navigation"
|
||||
style={[
|
||||
a.px_xl,
|
||||
styles.leftNav,
|
||||
isTablet && styles.leftNavTablet,
|
||||
pal.view,
|
||||
pal.border,
|
||||
]}>
|
||||
{hasSession ? (
|
||||
@@ -381,8 +346,6 @@ export function DesktopLeftNav() {
|
||||
|
||||
{hasSession && (
|
||||
<>
|
||||
<BackBtn />
|
||||
|
||||
<NavItem
|
||||
href="/"
|
||||
icon={
|
||||
@@ -525,8 +488,17 @@ const styles = StyleSheet.create({
|
||||
position: 'fixed',
|
||||
top: 10,
|
||||
// @ts-ignore web only
|
||||
left: 'calc(50vw - 300px - 220px - 20px)',
|
||||
width: 220,
|
||||
left: '50%',
|
||||
transform: [
|
||||
{
|
||||
translateX: -300,
|
||||
},
|
||||
{
|
||||
translateX: '-100%',
|
||||
},
|
||||
...a.scrollbar_offset.transform,
|
||||
],
|
||||
width: 240,
|
||||
// @ts-ignore web only
|
||||
maxHeight: 'calc(100vh - 10px)',
|
||||
overflowY: 'auto',
|
||||
@@ -538,7 +510,10 @@ const styles = StyleSheet.create({
|
||||
borderRightWidth: 1,
|
||||
height: '100%',
|
||||
width: 76,
|
||||
paddingLeft: 0,
|
||||
paddingRight: 0,
|
||||
alignItems: 'center',
|
||||
transform: [],
|
||||
},
|
||||
|
||||
profileCard: {
|
||||
|
||||
@@ -28,7 +28,7 @@ export function DesktopRightNav({routeName}: {routeName: string}) {
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={[styles.rightNav, pal.view]}>
|
||||
<View style={[a.px_xl, styles.rightNav]}>
|
||||
<View style={{paddingVertical: 20}}>
|
||||
{routeName === 'Search' ? (
|
||||
<View style={{marginBottom: 18}}>
|
||||
@@ -122,8 +122,13 @@ const styles = StyleSheet.create({
|
||||
// @ts-ignore web only
|
||||
position: 'fixed',
|
||||
// @ts-ignore web only
|
||||
left: 'calc(50vw + 300px + 20px)',
|
||||
width: 300,
|
||||
left: '50%',
|
||||
transform: [
|
||||
{
|
||||
translateX: 300,
|
||||
},
|
||||
...a.scrollbar_offset.transform,
|
||||
],
|
||||
maxHeight: '100%',
|
||||
overflowY: 'auto',
|
||||
},
|
||||
|
||||
@@ -3,10 +3,10 @@ import {StyleSheet, TouchableWithoutFeedback, View} from 'react-native'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useNavigation} from '@react-navigation/native'
|
||||
import {RemoveScrollBar} from 'react-remove-scroll-bar'
|
||||
|
||||
import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle'
|
||||
import {useIntentHandler} from '#/lib/hooks/useIntentHandler'
|
||||
import {useWebBodyScrollLock} from '#/lib/hooks/useWebBodyScrollLock'
|
||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||
import {NavigationProp} from '#/lib/routes/types'
|
||||
import {colors} from '#/lib/styles'
|
||||
@@ -34,7 +34,6 @@ function ShellInner() {
|
||||
const {_} = useLingui()
|
||||
const showDrawer = !isDesktop && isDrawerOpen
|
||||
|
||||
useWebBodyScrollLock(showDrawer)
|
||||
useComposerKeyboardShortcut()
|
||||
useIntentHandler()
|
||||
|
||||
@@ -58,31 +57,34 @@ function ShellInner() {
|
||||
<PortalOutlet />
|
||||
|
||||
{showDrawer && (
|
||||
<TouchableWithoutFeedback
|
||||
onPress={ev => {
|
||||
// Only close if press happens outside of the drawer
|
||||
if (ev.target === ev.currentTarget) {
|
||||
setDrawerOpen(false)
|
||||
}
|
||||
}}
|
||||
accessibilityLabel={_(msg`Close navigation footer`)}
|
||||
accessibilityHint={_(msg`Closes bottom navigation bar`)}>
|
||||
<View
|
||||
style={[
|
||||
styles.drawerMask,
|
||||
{
|
||||
backgroundColor: select(t.name, {
|
||||
light: 'rgba(0, 57, 117, 0.1)',
|
||||
dark: 'rgba(1, 82, 168, 0.1)',
|
||||
dim: 'rgba(10, 13, 16, 0.8)',
|
||||
}),
|
||||
},
|
||||
]}>
|
||||
<View style={styles.drawerContainer}>
|
||||
<DrawerContent />
|
||||
<>
|
||||
<RemoveScrollBar />
|
||||
<TouchableWithoutFeedback
|
||||
onPress={ev => {
|
||||
// Only close if press happens outside of the drawer
|
||||
if (ev.target === ev.currentTarget) {
|
||||
setDrawerOpen(false)
|
||||
}
|
||||
}}
|
||||
accessibilityLabel={_(msg`Close navigation footer`)}
|
||||
accessibilityHint={_(msg`Closes bottom navigation bar`)}>
|
||||
<View
|
||||
style={[
|
||||
styles.drawerMask,
|
||||
{
|
||||
backgroundColor: select(t.name, {
|
||||
light: 'rgba(0, 57, 117, 0.1)',
|
||||
dark: 'rgba(1, 82, 168, 0.1)',
|
||||
dim: 'rgba(10, 13, 16, 0.8)',
|
||||
}),
|
||||
},
|
||||
]}>
|
||||
<View style={styles.drawerContainer}>
|
||||
<DrawerContent />
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
</TouchableWithoutFeedback>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user