Refactor sidebar (#6971)
* Refactor RightNav (cherry picked from commit 96bb02acfd2d7452df18a0e7410e6a7169a583ed) * Better gutter handling * Clean up styles * Memoize breakpoints * Format * Comment * Loosen spacing, handle overflow, smaller text to match prod * Fix circular imports on native * Return 0 instead of undefined for easier calculations * Re-assign * Fix * Port over fix from subs/base * Space out right nav feeds, widen sidebar to match prod * Fix lost padding on home header * Fix perf by not actually linking to new URL * Remove underline on focus * Foramt --------- Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
This commit is contained in:
@@ -0,0 +1,28 @@
|
|||||||
|
import {useMemo} from 'react'
|
||||||
|
import {useMediaQuery} from 'react-responsive'
|
||||||
|
|
||||||
|
export type Breakpoint = 'gtPhone' | 'gtMobile' | 'gtTablet'
|
||||||
|
|
||||||
|
export function useBreakpoints(): Record<Breakpoint, boolean> & {
|
||||||
|
activeBreakpoint: Breakpoint | undefined
|
||||||
|
} {
|
||||||
|
const gtPhone = useMediaQuery({minWidth: 500})
|
||||||
|
const gtMobile = useMediaQuery({minWidth: 800})
|
||||||
|
const gtTablet = useMediaQuery({minWidth: 1300})
|
||||||
|
return useMemo(() => {
|
||||||
|
let active: Breakpoint | undefined
|
||||||
|
if (gtTablet) {
|
||||||
|
active = 'gtTablet'
|
||||||
|
} else if (gtMobile) {
|
||||||
|
active = 'gtMobile'
|
||||||
|
} else if (gtPhone) {
|
||||||
|
active = 'gtPhone'
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
activeBreakpoint: active,
|
||||||
|
gtPhone,
|
||||||
|
gtMobile,
|
||||||
|
gtTablet,
|
||||||
|
}
|
||||||
|
}, [gtPhone, gtMobile, gtTablet])
|
||||||
|
}
|
||||||
+2
-13
@@ -1,5 +1,4 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {useMediaQuery} from 'react-responsive'
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
computeFontScaleMultiplier,
|
computeFontScaleMultiplier,
|
||||||
@@ -14,13 +13,14 @@ import {BLUE_HUE, GREEN_HUE, RED_HUE} from '#/alf/util/colorGeneration'
|
|||||||
import {Device} from '#/storage'
|
import {Device} from '#/storage'
|
||||||
|
|
||||||
export {atoms} from '#/alf/atoms'
|
export {atoms} from '#/alf/atoms'
|
||||||
|
export * from '#/alf/breakpoints'
|
||||||
export * from '#/alf/fonts'
|
export * from '#/alf/fonts'
|
||||||
export * as tokens from '#/alf/tokens'
|
export * as tokens from '#/alf/tokens'
|
||||||
export * from '#/alf/types'
|
export * from '#/alf/types'
|
||||||
export * from '#/alf/util/flatten'
|
export * from '#/alf/util/flatten'
|
||||||
export * from '#/alf/util/platform'
|
export * from '#/alf/util/platform'
|
||||||
export * from '#/alf/util/themeSelector'
|
export * from '#/alf/util/themeSelector'
|
||||||
export * from '#/alf/util/useGutterStyles'
|
export * from '#/alf/util/useGutters'
|
||||||
|
|
||||||
export type Alf = {
|
export type Alf = {
|
||||||
themeName: ThemeName
|
themeName: ThemeName
|
||||||
@@ -142,14 +142,3 @@ export function useTheme(theme?: ThemeName) {
|
|||||||
return theme ? alf.themes[theme] : alf.theme
|
return theme ? alf.themes[theme] : alf.theme
|
||||||
}, [theme, alf])
|
}, [theme, alf])
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useBreakpoints() {
|
|
||||||
const gtPhone = useMediaQuery({minWidth: 500})
|
|
||||||
const gtMobile = useMediaQuery({minWidth: 800})
|
|
||||||
const gtTablet = useMediaQuery({minWidth: 1300})
|
|
||||||
return {
|
|
||||||
gtPhone,
|
|
||||||
gtMobile,
|
|
||||||
gtTablet,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
import {atoms as a, useBreakpoints, ViewStyleProp} from '#/alf'
|
|
||||||
|
|
||||||
export function useGutterStyles({
|
|
||||||
top,
|
|
||||||
bottom,
|
|
||||||
}: {
|
|
||||||
top?: boolean
|
|
||||||
bottom?: boolean
|
|
||||||
} = {}) {
|
|
||||||
const {gtMobile} = useBreakpoints()
|
|
||||||
return React.useMemo<ViewStyleProp['style']>(() => {
|
|
||||||
return [
|
|
||||||
a.px_lg,
|
|
||||||
top && a.pt_md,
|
|
||||||
bottom && a.pb_md,
|
|
||||||
gtMobile && [a.px_xl, top && a.pt_lg, bottom && a.pb_lg],
|
|
||||||
]
|
|
||||||
}, [gtMobile, top, bottom])
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import {Breakpoint, useBreakpoints} from '#/alf/breakpoints'
|
||||||
|
import * as tokens from '#/alf/tokens'
|
||||||
|
|
||||||
|
type Gutter = 'compact' | 'base' | 'wide' | 0
|
||||||
|
|
||||||
|
const gutters: Record<
|
||||||
|
Exclude<Gutter, 0>,
|
||||||
|
Record<Breakpoint | 'default', number>
|
||||||
|
> = {
|
||||||
|
compact: {
|
||||||
|
default: tokens.space.sm,
|
||||||
|
gtPhone: tokens.space.sm,
|
||||||
|
gtMobile: tokens.space.md,
|
||||||
|
gtTablet: tokens.space.md,
|
||||||
|
},
|
||||||
|
base: {
|
||||||
|
default: tokens.space.lg,
|
||||||
|
gtPhone: tokens.space.lg,
|
||||||
|
gtMobile: tokens.space.xl,
|
||||||
|
gtTablet: tokens.space.xl,
|
||||||
|
},
|
||||||
|
wide: {
|
||||||
|
default: tokens.space.xl,
|
||||||
|
gtPhone: tokens.space.xl,
|
||||||
|
gtMobile: tokens.space._3xl,
|
||||||
|
gtTablet: tokens.space._3xl,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type Gutters = {
|
||||||
|
paddingTop: number
|
||||||
|
paddingRight: number
|
||||||
|
paddingBottom: number
|
||||||
|
paddingLeft: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useGutters([all]: [Gutter]): Gutters
|
||||||
|
export function useGutters([vertical, horizontal]: [Gutter, Gutter]): Gutters
|
||||||
|
export function useGutters([top, right, bottom, left]: [
|
||||||
|
Gutter,
|
||||||
|
Gutter,
|
||||||
|
Gutter,
|
||||||
|
Gutter,
|
||||||
|
]): Gutters
|
||||||
|
export function useGutters([top, right, bottom, left]: Gutter[]) {
|
||||||
|
const {activeBreakpoint} = useBreakpoints()
|
||||||
|
if (right === undefined) {
|
||||||
|
right = bottom = left = top
|
||||||
|
} else if (bottom === undefined) {
|
||||||
|
bottom = top
|
||||||
|
left = right
|
||||||
|
}
|
||||||
|
return React.useMemo(() => {
|
||||||
|
return {
|
||||||
|
paddingTop: top === 0 ? 0 : gutters[top][activeBreakpoint || 'default'],
|
||||||
|
paddingRight:
|
||||||
|
right === 0 ? 0 : gutters[right][activeBreakpoint || 'default'],
|
||||||
|
paddingBottom:
|
||||||
|
bottom === 0 ? 0 : gutters[bottom][activeBreakpoint || 'default'],
|
||||||
|
paddingLeft:
|
||||||
|
left === 0 ? 0 : gutters[left][activeBreakpoint || 'default'],
|
||||||
|
}
|
||||||
|
}, [activeBreakpoint, top, right, bottom, left])
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
platform,
|
platform,
|
||||||
TextStyleProp,
|
TextStyleProp,
|
||||||
useBreakpoints,
|
useBreakpoints,
|
||||||
useGutterStyles,
|
useGutters,
|
||||||
useTheme,
|
useTheme,
|
||||||
} from '#/alf'
|
} from '#/alf'
|
||||||
import {Button, ButtonIcon, ButtonProps} from '#/components/Button'
|
import {Button, ButtonIcon, ButtonProps} from '#/components/Button'
|
||||||
@@ -34,7 +34,7 @@ export function Outer({
|
|||||||
noBottomBorder?: boolean
|
noBottomBorder?: boolean
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const gutter = useGutterStyles()
|
const gutters = useGutters([0, 'base'])
|
||||||
const {gtMobile} = useBreakpoints()
|
const {gtMobile} = useBreakpoints()
|
||||||
const {isWithinOffsetView} = useContext(ScrollbarOffsetContext)
|
const {isWithinOffsetView} = useContext(ScrollbarOffsetContext)
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ export function Outer({
|
|||||||
a.flex_row,
|
a.flex_row,
|
||||||
a.align_center,
|
a.align_center,
|
||||||
a.gap_sm,
|
a.gap_sm,
|
||||||
gutter,
|
gutters,
|
||||||
platform({
|
platform({
|
||||||
native: [a.pb_sm, a.pt_xs],
|
native: [a.pb_sm, a.pt_xs],
|
||||||
web: [a.py_sm],
|
web: [a.py_sm],
|
||||||
|
|||||||
@@ -237,7 +237,9 @@ export function Link({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type InlineLinkProps = React.PropsWithChildren<
|
export type InlineLinkProps = React.PropsWithChildren<
|
||||||
BaseLinkProps & TextStyleProp & Pick<TextProps, 'selectable'>
|
BaseLinkProps &
|
||||||
|
TextStyleProp &
|
||||||
|
Pick<TextProps, 'selectable' | 'numberOfLines'>
|
||||||
> &
|
> &
|
||||||
Pick<ButtonProps, 'label'> & {
|
Pick<ButtonProps, 'label'> & {
|
||||||
disableUnderline?: boolean
|
disableUnderline?: boolean
|
||||||
@@ -273,7 +275,6 @@ export function InlineLinkText({
|
|||||||
onIn: onHoverIn,
|
onIn: onHoverIn,
|
||||||
onOut: onHoverOut,
|
onOut: onHoverOut,
|
||||||
} = useInteractionState()
|
} = useInteractionState()
|
||||||
const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState()
|
|
||||||
const flattenedStyle = flatten(style) || {}
|
const flattenedStyle = flatten(style) || {}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -284,7 +285,7 @@ export function InlineLinkText({
|
|||||||
{...rest}
|
{...rest}
|
||||||
style={[
|
style={[
|
||||||
{color: t.palette.primary_500},
|
{color: t.palette.primary_500},
|
||||||
(hovered || focused) &&
|
hovered &&
|
||||||
!disableUnderline && {
|
!disableUnderline && {
|
||||||
...web({
|
...web({
|
||||||
outline: 0,
|
outline: 0,
|
||||||
@@ -298,8 +299,6 @@ export function InlineLinkText({
|
|||||||
role="link"
|
role="link"
|
||||||
onPress={download ? undefined : onPress}
|
onPress={download ? undefined : onPress}
|
||||||
onLongPress={onLongPress}
|
onLongPress={onLongPress}
|
||||||
onFocus={onFocus}
|
|
||||||
onBlur={onBlur}
|
|
||||||
onMouseEnter={onHoverIn}
|
onMouseEnter={onHoverIn}
|
||||||
onMouseLeave={onHoverOut}
|
onMouseLeave={onHoverOut}
|
||||||
accessibilityRole="link"
|
accessibilityRole="link"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {useSession} from '#/state/session'
|
|||||||
import {useShellLayout} from '#/state/shell/shell-layout'
|
import {useShellLayout} from '#/state/shell/shell-layout'
|
||||||
import {HomeHeaderLayoutMobile} from '#/view/com/home/HomeHeaderLayoutMobile'
|
import {HomeHeaderLayoutMobile} from '#/view/com/home/HomeHeaderLayoutMobile'
|
||||||
import {Logo} from '#/view/icons/Logo'
|
import {Logo} from '#/view/icons/Logo'
|
||||||
import {atoms as a, useBreakpoints, useGutterStyles, useTheme} from '#/alf'
|
import {atoms as a, useBreakpoints, useGutters, useTheme} from '#/alf'
|
||||||
import {ButtonIcon} from '#/components/Button'
|
import {ButtonIcon} from '#/components/Button'
|
||||||
import {Hashtag_Stroke2_Corner0_Rounded as FeedsIcon} from '#/components/icons/Hashtag'
|
import {Hashtag_Stroke2_Corner0_Rounded as FeedsIcon} from '#/components/icons/Hashtag'
|
||||||
import * as Layout from '#/components/Layout'
|
import * as Layout from '#/components/Layout'
|
||||||
@@ -41,14 +41,14 @@ function HomeHeaderLayoutDesktopAndTablet({
|
|||||||
const {hasSession} = useSession()
|
const {hasSession} = useSession()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const kawaii = useKawaiiMode()
|
const kawaii = useKawaiiMode()
|
||||||
const gutter = useGutterStyles()
|
const gutters = useGutters([0, 'base'])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{hasSession && (
|
{hasSession && (
|
||||||
<Layout.Center>
|
<Layout.Center>
|
||||||
<View
|
<View
|
||||||
style={[a.flex_row, a.align_center, a.pt_md, gutter, t.atoms.bg]}>
|
style={[a.flex_row, a.align_center, gutters, a.pt_md, t.atoms.bg]}>
|
||||||
<View style={{width: 34}} />
|
<View style={{width: 34}} />
|
||||||
<View style={[a.flex_1, a.align_center, a.justify_center]}>
|
<View style={[a.flex_1, a.align_center, a.justify_center]}>
|
||||||
<Logo width={kawaii ? 60 : 28} />
|
<Logo width={kawaii ? 60 : 28} />
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import {StyleSheet, View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useNavigation, useNavigationState} from '@react-navigation/native'
|
import {useNavigation, useNavigationState} from '@react-navigation/native'
|
||||||
|
|
||||||
import {usePalette} from '#/lib/hooks/usePalette'
|
|
||||||
import {getCurrentRoute} from '#/lib/routes/helpers'
|
import {getCurrentRoute} from '#/lib/routes/helpers'
|
||||||
import {NavigationProp} from '#/lib/routes/types'
|
import {NavigationProp} from '#/lib/routes/types'
|
||||||
import {emitSoftReset} from '#/state/events'
|
import {emitSoftReset} from '#/state/events'
|
||||||
import {usePinnedFeedsInfos} from '#/state/queries/feed'
|
import {usePinnedFeedsInfos} from '#/state/queries/feed'
|
||||||
import {useSelectedFeed, useSetSelectedFeed} from '#/state/shell/selected-feed'
|
import {useSelectedFeed, useSetSelectedFeed} from '#/state/shell/selected-feed'
|
||||||
import {TextLink} from '#/view/com/util/Link'
|
import {atoms as a, useTheme, web} from '#/alf'
|
||||||
|
import {createStaticClick, InlineLinkText} from '#/components/Link'
|
||||||
|
|
||||||
export function DesktopFeeds() {
|
export function DesktopFeeds() {
|
||||||
const pal = usePalette('default')
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {data: pinnedFeedInfos} = usePinnedFeedsInfos()
|
const {data: pinnedFeedInfos} = usePinnedFeedsInfos()
|
||||||
const selectedFeed = useSelectedFeed()
|
const selectedFeed = useSelectedFeed()
|
||||||
@@ -24,76 +24,60 @@ export function DesktopFeeds() {
|
|||||||
}
|
}
|
||||||
return getCurrentRoute(state)
|
return getCurrentRoute(state)
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!pinnedFeedInfos) {
|
if (!pinnedFeedInfos) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[styles.container, pal.view]}>
|
<View
|
||||||
|
style={[
|
||||||
|
a.flex_1,
|
||||||
|
web({
|
||||||
|
gap: 10,
|
||||||
|
/*
|
||||||
|
* Small padding prevents overflow prior to actually overflowing the
|
||||||
|
* height of the screen with lots of feeds.
|
||||||
|
*/
|
||||||
|
paddingVertical: 2,
|
||||||
|
overflowY: 'auto',
|
||||||
|
}),
|
||||||
|
]}>
|
||||||
{pinnedFeedInfos.map(feedInfo => {
|
{pinnedFeedInfos.map(feedInfo => {
|
||||||
const feed = feedInfo.feedDescriptor
|
const feed = feedInfo.feedDescriptor
|
||||||
|
const current = route.name === 'Home' && feed === selectedFeed
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FeedItem
|
<InlineLinkText
|
||||||
key={feed}
|
key={feedInfo.uri}
|
||||||
href={'/?' + new URLSearchParams([['feed', feed]])}
|
label={feedInfo.displayName}
|
||||||
title={feedInfo.displayName}
|
{...createStaticClick(() => {
|
||||||
current={route.name === 'Home' && feed === selectedFeed}
|
|
||||||
onPress={() => {
|
|
||||||
setSelectedFeed(feed)
|
setSelectedFeed(feed)
|
||||||
navigation.navigate('Home')
|
navigation.navigate('Home')
|
||||||
if (route.name === 'Home' && feed === selectedFeed) {
|
if (route.name === 'Home' && feed === selectedFeed) {
|
||||||
emitSoftReset()
|
emitSoftReset()
|
||||||
}
|
}
|
||||||
}}
|
})}
|
||||||
/>
|
style={[
|
||||||
|
a.text_md,
|
||||||
|
a.leading_snug,
|
||||||
|
current
|
||||||
|
? [a.font_heavy, t.atoms.text]
|
||||||
|
: [t.atoms.text_contrast_medium],
|
||||||
|
]}
|
||||||
|
numberOfLines={1}>
|
||||||
|
{feedInfo.displayName}
|
||||||
|
</InlineLinkText>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
<View style={{paddingTop: 8, paddingBottom: 6}}>
|
|
||||||
<TextLink
|
<InlineLinkText
|
||||||
type="lg"
|
to="/feeds"
|
||||||
href="/feeds"
|
label={_(msg`More feeds`)}
|
||||||
text={_(msg`More feeds`)}
|
style={[a.text_md, a.leading_snug]}
|
||||||
style={[pal.link]}
|
numberOfLines={1}>
|
||||||
/>
|
{_(msg`More feeds`)}
|
||||||
</View>
|
</InlineLinkText>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function FeedItem({
|
|
||||||
title,
|
|
||||||
href,
|
|
||||||
current,
|
|
||||||
onPress,
|
|
||||||
}: {
|
|
||||||
title: string
|
|
||||||
href: string
|
|
||||||
current: boolean
|
|
||||||
onPress: () => void
|
|
||||||
}) {
|
|
||||||
const pal = usePalette('default')
|
|
||||||
return (
|
|
||||||
<View style={{paddingVertical: 6}}>
|
|
||||||
<TextLink
|
|
||||||
type="xl"
|
|
||||||
href={href}
|
|
||||||
text={title}
|
|
||||||
onPress={onPress}
|
|
||||||
style={[
|
|
||||||
current ? pal.text : pal.textLight,
|
|
||||||
{letterSpacing: 0.15, fontWeight: current ? '600' : '400'},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
// @ts-ignore web only -prf
|
|
||||||
overflowY: 'auto',
|
|
||||||
width: 300,
|
|
||||||
paddingHorizontal: 12,
|
|
||||||
paddingVertical: 18,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|||||||
@@ -1,26 +1,24 @@
|
|||||||
import {StyleSheet, View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {FEEDBACK_FORM_URL, HELP_DESK_URL} from '#/lib/constants'
|
import {FEEDBACK_FORM_URL, HELP_DESK_URL} from '#/lib/constants'
|
||||||
import {usePalette} from '#/lib/hooks/usePalette'
|
|
||||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||||
import {s} from '#/lib/styles'
|
|
||||||
import {useKawaiiMode} from '#/state/preferences/kawaii'
|
import {useKawaiiMode} from '#/state/preferences/kawaii'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {TextLink} from '#/view/com/util/Link'
|
import {DesktopFeeds} from '#/view/shell/desktop/Feeds'
|
||||||
import {Text} from '#/view/com/util/text/Text'
|
import {DesktopSearch} from '#/view/shell/desktop/Search'
|
||||||
import {atoms as a} from '#/alf'
|
import {atoms as a, useGutters, useTheme, web} from '#/alf'
|
||||||
|
import {InlineLinkText} from '#/components/Link'
|
||||||
import {ProgressGuideList} from '#/components/ProgressGuide/List'
|
import {ProgressGuideList} from '#/components/ProgressGuide/List'
|
||||||
import {DesktopFeeds} from './Feeds'
|
import {Text} from '#/components/Typography'
|
||||||
import {DesktopSearch} from './Search'
|
|
||||||
|
|
||||||
export function DesktopRightNav({routeName}: {routeName: string}) {
|
export function DesktopRightNav({routeName}: {routeName: string}) {
|
||||||
const pal = usePalette('default')
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {hasSession, currentAccount} = useSession()
|
const {hasSession, currentAccount} = useSession()
|
||||||
|
|
||||||
const kawaii = useKawaiiMode()
|
const kawaii = useKawaiiMode()
|
||||||
|
const gutters = useGutters(['base', 0, 'base', 'wide'])
|
||||||
|
|
||||||
const {isTablet} = useWebMediaQueries()
|
const {isTablet} = useWebMediaQueries()
|
||||||
if (isTablet) {
|
if (isTablet) {
|
||||||
@@ -28,122 +26,81 @@ export function DesktopRightNav({routeName}: {routeName: string}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[a.px_xl, styles.rightNav]}>
|
<View
|
||||||
<View style={{paddingVertical: 20}}>
|
style={[
|
||||||
{routeName === 'Search' ? (
|
gutters,
|
||||||
<View style={{marginBottom: 18}}>
|
web({
|
||||||
|
position: 'fixed',
|
||||||
|
left: '50%',
|
||||||
|
transform: [
|
||||||
|
{
|
||||||
|
translateX: 300,
|
||||||
|
},
|
||||||
|
...a.scrollbar_offset.transform,
|
||||||
|
],
|
||||||
|
width: 300 + gutters.paddingLeft,
|
||||||
|
maxHeight: '100%',
|
||||||
|
overflowY: 'auto',
|
||||||
|
}),
|
||||||
|
]}>
|
||||||
|
{routeName !== 'Search' && (
|
||||||
|
<View style={[a.pb_lg]}>
|
||||||
|
<DesktopSearch />
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
{hasSession && (
|
||||||
|
<>
|
||||||
|
<ProgressGuideList style={[a.pb_xl]} />
|
||||||
|
<View
|
||||||
|
style={[a.pb_lg, a.mb_lg, a.border_b, t.atoms.border_contrast_low]}>
|
||||||
<DesktopFeeds />
|
<DesktopFeeds />
|
||||||
</View>
|
</View>
|
||||||
) : (
|
</>
|
||||||
<>
|
)}
|
||||||
<DesktopSearch />
|
|
||||||
|
|
||||||
{hasSession && (
|
<Text style={[a.leading_snug, t.atoms.text_contrast_low]}>
|
||||||
<>
|
{hasSession && (
|
||||||
<ProgressGuideList style={[{marginTop: 22, marginBottom: 8}]} />
|
<>
|
||||||
<View style={[pal.border, styles.desktopFeedsContainer]}>
|
<InlineLinkText
|
||||||
<DesktopFeeds />
|
to={FEEDBACK_FORM_URL({
|
||||||
</View>
|
email: currentAccount?.email,
|
||||||
</>
|
handle: currentAccount?.handle,
|
||||||
)}
|
})}
|
||||||
|
label={_(msg`Feedback`)}>
|
||||||
|
{_(msg`Feedback`)}
|
||||||
|
</InlineLinkText>
|
||||||
|
{' • '}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
<InlineLinkText
|
||||||
|
to="https://bsky.social/about/support/privacy-policy"
|
||||||
|
label={_(msg`Privacy`)}>
|
||||||
|
{_(msg`Privacy`)}
|
||||||
|
</InlineLinkText>
|
||||||
|
{' • '}
|
||||||
|
<InlineLinkText
|
||||||
|
to="https://bsky.social/about/support/tos"
|
||||||
|
label={_(msg`Terms`)}>
|
||||||
|
{_(msg`Terms`)}
|
||||||
|
</InlineLinkText>
|
||||||
|
{' • '}
|
||||||
|
<InlineLinkText label={_(msg`Help`)} to={HELP_DESK_URL}>
|
||||||
|
{_(msg`Help`)}
|
||||||
|
</InlineLinkText>
|
||||||
|
</Text>
|
||||||
|
|
||||||
<View
|
{kawaii && (
|
||||||
style={[
|
<Text style={[t.atoms.text_contrast_medium, {marginTop: 12}]}>
|
||||||
styles.message,
|
<Trans>
|
||||||
{
|
Logo by{' '}
|
||||||
paddingTop: hasSession ? 0 : 18,
|
<InlineLinkText
|
||||||
},
|
label={_(msg`Logo by @sawaratsuki.bsky.social`)}
|
||||||
]}>
|
to="/profile/sawaratsuki.bsky.social">
|
||||||
<View style={[{flexWrap: 'wrap'}, s.flexRow, a.gap_xs]}>
|
@sawaratsuki.bsky.social
|
||||||
{hasSession && (
|
</InlineLinkText>
|
||||||
<>
|
</Trans>
|
||||||
<TextLink
|
</Text>
|
||||||
type="md"
|
)}
|
||||||
style={pal.link}
|
|
||||||
href={FEEDBACK_FORM_URL({
|
|
||||||
email: currentAccount?.email,
|
|
||||||
handle: currentAccount?.handle,
|
|
||||||
})}
|
|
||||||
text={_(msg`Feedback`)}
|
|
||||||
/>
|
|
||||||
<Text type="md" style={pal.textLight}>
|
|
||||||
·
|
|
||||||
</Text>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<TextLink
|
|
||||||
type="md"
|
|
||||||
style={pal.link}
|
|
||||||
href="https://bsky.social/about/support/privacy-policy"
|
|
||||||
text={_(msg`Privacy`)}
|
|
||||||
/>
|
|
||||||
<Text type="md" style={pal.textLight}>
|
|
||||||
·
|
|
||||||
</Text>
|
|
||||||
<TextLink
|
|
||||||
type="md"
|
|
||||||
style={pal.link}
|
|
||||||
href="https://bsky.social/about/support/tos"
|
|
||||||
text={_(msg`Terms`)}
|
|
||||||
/>
|
|
||||||
<Text type="md" style={pal.textLight}>
|
|
||||||
·
|
|
||||||
</Text>
|
|
||||||
<TextLink
|
|
||||||
type="md"
|
|
||||||
style={pal.link}
|
|
||||||
href={HELP_DESK_URL}
|
|
||||||
text={_(msg`Help`)}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
{kawaii && (
|
|
||||||
<Text type="md" style={[pal.textLight, {marginTop: 12}]}>
|
|
||||||
<Trans>
|
|
||||||
Logo by{' '}
|
|
||||||
<TextLink
|
|
||||||
type="md"
|
|
||||||
href="/profile/sawaratsuki.bsky.social"
|
|
||||||
text="@sawaratsuki.bsky.social"
|
|
||||||
style={pal.link}
|
|
||||||
/>
|
|
||||||
</Trans>
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
rightNav: {
|
|
||||||
// @ts-ignore web only
|
|
||||||
position: 'fixed',
|
|
||||||
// @ts-ignore web only
|
|
||||||
left: '50%',
|
|
||||||
transform: [
|
|
||||||
{
|
|
||||||
translateX: 300,
|
|
||||||
},
|
|
||||||
...a.scrollbar_offset.transform,
|
|
||||||
],
|
|
||||||
maxHeight: '100%',
|
|
||||||
overflowY: 'auto',
|
|
||||||
},
|
|
||||||
|
|
||||||
message: {
|
|
||||||
paddingVertical: 18,
|
|
||||||
paddingHorizontal: 12,
|
|
||||||
},
|
|
||||||
messageLine: {
|
|
||||||
marginBottom: 10,
|
|
||||||
},
|
|
||||||
desktopFeedsContainer: {
|
|
||||||
borderTopWidth: StyleSheet.hairlineWidth,
|
|
||||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
|
||||||
marginTop: 18,
|
|
||||||
marginBottom: 18,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|||||||
@@ -225,12 +225,12 @@ export function DesktopSearch() {
|
|||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
width: 300,
|
width: '100%',
|
||||||
},
|
},
|
||||||
resultsContainer: {
|
resultsContainer: {
|
||||||
marginTop: 10,
|
marginTop: 10,
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
width: 300,
|
width: '100%',
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderRadius: 6,
|
borderRadius: 6,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user