diff --git a/eslint-suppressions.json b/eslint-suppressions.json
index acbd6f39cf..20427ab32b 100644
--- a/eslint-suppressions.json
+++ b/eslint-suppressions.json
@@ -59,11 +59,6 @@
"count": 1
}
},
- "src/components/Layout/const.ts": {
- "@typescript-eslint/no-explicit-any": {
- "count": 2
- }
- },
"src/components/Lists.tsx": {
"@typescript-eslint/no-explicit-any": {
"count": 1
diff --git a/src/components/Layout/Header/index.tsx b/src/components/Layout/Header/index.tsx
index 3d2ee0acda..3840b34d69 100644
--- a/src/components/Layout/Header/index.tsx
+++ b/src/components/Layout/Header/index.tsx
@@ -24,6 +24,7 @@ import {Menu_Stroke2_Corner0_Rounded as Menu} from '#/components/icons/Menu'
import {
BUTTON_VISUAL_ALIGNMENT_OFFSET,
CENTER_COLUMN_OFFSET,
+ CENTER_COLUMN_WIDTH,
HEADER_SLOT_SIZE,
SCROLLBAR_OFFSET,
} from '#/components/Layout/const'
@@ -65,7 +66,7 @@ export function Outer({
web: [a.py_xs, {minHeight: 52}],
}),
t.atoms.border_contrast_low,
- gtMobile && [a.mx_auto, {maxWidth: 600}],
+ gtMobile && [a.mx_auto, {maxWidth: CENTER_COLUMN_WIDTH}],
!isWithinOffsetView &&
!isWithinSplitView && {
transform: [
diff --git a/src/components/Layout/const.ts b/src/components/Layout/const.ts
index 2721bed21e..7bcfd545bd 100644
--- a/src/components/Layout/const.ts
+++ b/src/components/Layout/const.ts
@@ -1,7 +1,7 @@
export const SCROLLBAR_OFFSET =
- 'calc(-1 * var(--removed-body-scroll-bar-size, 0px) / 2)' as any
+ 'calc(-1 * var(--removed-body-scroll-bar-size, 0px) / 2)' as `${number}%`
export const SCROLLBAR_OFFSET_POSITIVE =
- 'calc(var(--removed-body-scroll-bar-size, 0px) / 2)' as any
+ 'calc(var(--removed-body-scroll-bar-size, 0px) / 2)' as `${number}%`
/**
* Useful for visually aligning icons within header buttons with the elements
@@ -19,3 +19,8 @@ export const HEADER_SLOT_SIZE = 33
* How far to shift the center column when in the tablet breakpoint
*/
export const CENTER_COLUMN_OFFSET = -105
+
+/**
+ * How wide the center column is
+ */
+export const CENTER_COLUMN_WIDTH = 600
diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx
index abda8fdf44..c98dd7aed8 100644
--- a/src/components/Layout/index.tsx
+++ b/src/components/Layout/index.tsx
@@ -22,7 +22,11 @@ import {
web,
} from '#/alf'
import {useDialogContext} from '#/components/Dialog'
-import {CENTER_COLUMN_OFFSET, SCROLLBAR_OFFSET} from '#/components/Layout/const'
+import {
+ CENTER_COLUMN_OFFSET,
+ CENTER_COLUMN_WIDTH,
+ SCROLLBAR_OFFSET,
+} from '#/components/Layout/const'
import {ScrollbarOffsetContext} from '#/components/Layout/context'
import {IS_WEB} from '#/env'
@@ -152,7 +156,7 @@ export const Center = memo(function LayoutCenter({
a.w_full,
!isWithinSplitView && a.mx_auto,
gtMobile && {
- maxWidth: 600,
+ maxWidth: CENTER_COLUMN_WIDTH,
},
!isWithinOffsetView &&
!isWithinSplitView && {
diff --git a/src/screens/Messages/components/splitView/MessagesSplitViewLayout.tsx b/src/screens/Messages/components/splitView/MessagesSplitViewLayout.tsx
index 91428a08eb..a3f2314e85 100644
--- a/src/screens/Messages/components/splitView/MessagesSplitViewLayout.tsx
+++ b/src/screens/Messages/components/splitView/MessagesSplitViewLayout.tsx
@@ -7,10 +7,11 @@ import {type NativeStackNavigationProp} from '@react-navigation/native-stack'
import {type FlatNavigatorParams} from '#/lib/routes/types'
import {ScrollProvider} from '#/lib/ScrollContext'
import {type NativeStackNavigationOptionsWithAuth} from '#/view/shell/createNativeStackNavigatorWithAuth'
+import {LEFT_NAV_MINIMAL_WIDTH} from '#/view/shell/desktop/LeftNav'
import {atoms as a, useLayoutBreakpoints, useTheme, web} from '#/alf'
import {useDialogControl} from '#/components/Dialog'
import {NewChat} from '#/components/dms/dialogs/NewChatDialog'
-import {SCROLLBAR_OFFSET} from '#/components/Layout'
+import {CENTER_COLUMN_WIDTH, SCROLLBAR_OFFSET} from '#/components/Layout'
import {LockScroll} from '#/components/LockScroll'
import {useAgeAssurance} from '#/ageAssurance'
import {IS_WEB} from '#/env'
@@ -18,12 +19,6 @@ import {ChatList, Header as ChatListHeader} from '../../ChatList'
import {SplitViewProvider} from './context'
import {splitViewLeftScroll} from './leftColumnScroll'
-const CENTER_COLUMN_WIDTH = 600
-const LEFT_NAV_FULL_WIDTH = 245
-const LEFT_NAV_MINIMAL_WIDTH = 86
-const RIGHT_NAV_FULL_WIDTH = 330
-const RIGHT_NAV_MINIMAL_WIDTH = 280
-
type MessageScreens =
| 'Messages'
| 'MessagesConversation'
@@ -72,25 +67,14 @@ function MessagesSplitViewLayout({children, navigation, route}: LayoutProps) {
? route.params.conversation
: undefined
- const rightNavWidth = centerColumnOffset
- ? RIGHT_NAV_MINIMAL_WIDTH
- : RIGHT_NAV_FULL_WIDTH
+ const halfLeftNavWidth = LEFT_NAV_MINIMAL_WIDTH / 2
- const leftNavWidth = centerColumnOffset
- ? LEFT_NAV_MINIMAL_WIDTH
- : LEFT_NAV_FULL_WIDTH - LEFT_NAV_MINIMAL_WIDTH
+ const leftColumnWidth = 360
- // slight reduce width for smaller breakpoint
- const centerColumnWidth = centerColumnOffset
- ? CENTER_COLUMN_WIDTH - 50
- : CENTER_COLUMN_WIDTH
+ const rightColumnWidth =
+ CENTER_COLUMN_WIDTH - (centerColumnOffset ? halfLeftNavWidth + 30 : 0)
- // nasty magic numbers here, sorry :(
- const offset = centerColumnOffset
- ? LEFT_NAV_MINIMAL_WIDTH - 34
- : LEFT_NAV_MINIMAL_WIDTH + 5
-
- const containerWidth = leftNavWidth + centerColumnWidth + rightNavWidth
+ const containerWidth = leftColumnWidth + rightColumnWidth
return (
@@ -129,7 +117,7 @@ function MessagesSplitViewLayout({children, navigation, route}: LayoutProps) {
style={[
a.border_x,
t.atoms.border_contrast_low,
- {width: centerColumnWidth},
+ {width: rightColumnWidth},
]}>
{children}
diff --git a/src/view/com/util/Views.web.tsx b/src/view/com/util/Views.web.tsx
index 416dfe55f5..cc09fccf4e 100644
--- a/src/view/com/util/Views.web.tsx
+++ b/src/view/com/util/Views.web.tsx
@@ -28,7 +28,7 @@ import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {addStyle} from '#/lib/styles'
import {useLayoutBreakpoints} from '#/alf'
import {useDialogContext} from '#/components/Dialog'
-import {CENTER_COLUMN_OFFSET} from '#/components/Layout'
+import {CENTER_COLUMN_OFFSET, CENTER_COLUMN_WIDTH} from '#/components/Layout'
interface AddedProps {
desktopFixedHeight?: boolean | number
@@ -175,7 +175,7 @@ const styles = StyleSheet.create({
},
container: {
width: '100%',
- maxWidth: 600,
+ maxWidth: CENTER_COLUMN_WIDTH,
marginLeft: 'auto',
marginRight: 'auto',
},
@@ -184,7 +184,7 @@ const styles = StyleSheet.create({
},
containerScroll: {
width: '100%',
- maxWidth: 600,
+ maxWidth: CENTER_COLUMN_WIDTH,
marginLeft: 'auto',
marginRight: 'auto',
},
diff --git a/src/view/shell/desktop/LeftNav.tsx b/src/view/shell/desktop/LeftNav.tsx
index 37c32f231a..0c7f63b829 100644
--- a/src/view/shell/desktop/LeftNav.tsx
+++ b/src/view/shell/desktop/LeftNav.tsx
@@ -1,9 +1,8 @@
-import {type JSX, useCallback, useMemo, useState} from 'react'
+import {useCallback, useMemo, useState} from 'react'
import {StyleSheet, View} from 'react-native'
import {type AppBskyActorDefs} from '@atproto/api'
-import {msg, plural} from '@lingui/core/macro'
-import {useLingui} from '@lingui/react'
-import {Trans} from '@lingui/react/macro'
+import {plural} from '@lingui/core/macro'
+import {Trans, useLingui} from '@lingui/react/macro'
import {useNavigation, useNavigationState} from '@react-navigation/native'
import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher'
@@ -40,42 +39,46 @@ import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import {type DialogControlProps} from '#/components/Dialog'
import {ArrowBoxLeft_Stroke2_Corner0_Rounded as LeaveIcon} from '#/components/icons/ArrowBoxLeft'
import {
- Bell_Filled_Corner0_Rounded as BellFilled,
- Bell_Stroke2_Corner0_Rounded as Bell,
+ Bell_Filled_Corner0_Rounded as BellFilledIcon,
+ Bell_Stroke2_Corner0_Rounded as BellIcon,
} from '#/components/icons/Bell'
-import {Bookmark, BookmarkFilled} from '#/components/icons/Bookmark'
import {
- BulletList_Filled_Corner0_Rounded as ListFilled,
- BulletList_Stroke2_Corner0_Rounded as List,
+ Bookmark as BookmarkIcon,
+ BookmarkFilled as BookmarkFilledIcon,
+} from '#/components/icons/Bookmark'
+import {
+ BulletList_Filled_Corner0_Rounded as ListFilledIcon,
+ BulletList_Stroke2_Corner0_Rounded as ListIcon,
} from '#/components/icons/BulletList'
+import {type Props as SVGIconProps} from '#/components/icons/common'
import {DotGrid3x1_Stroke2_Corner0_Rounded as EllipsisIcon} from '#/components/icons/DotGrid'
import {EditBig_Stroke2_Corner2_Rounded as EditBigIcon} from '#/components/icons/EditBig'
import {
- Hashtag_Filled_Corner0_Rounded as HashtagFilled,
- Hashtag_Stroke2_Corner0_Rounded as Hashtag,
+ Hashtag_Filled_Corner0_Rounded as HashtagFilledIcon,
+ Hashtag_Stroke2_Corner0_Rounded as HashtagIcon,
} from '#/components/icons/Hashtag'
import {
- HomeOpen_Filled_Corner0_Rounded as HomeFilled,
- HomeOpen_Stoke2_Corner0_Rounded as Home,
+ HomeOpen_Filled_Corner0_Rounded as HomeFilledIcon,
+ HomeOpen_Stoke2_Corner0_Rounded as HomeIcon,
} from '#/components/icons/HomeOpen'
import {
- MagnifyingGlass_Filled_Stroke2_Corner0_Rounded as MagnifyingGlassFilled,
- MagnifyingGlass_Stroke2_Corner0_Rounded as MagnifyingGlass,
+ MagnifyingGlass_Filled_Stroke2_Corner0_Rounded as MagnifyingGlassFilledIcon,
+ MagnifyingGlass_Stroke2_Corner0_Rounded as MagnifyingGlassIcon,
} from '#/components/icons/MagnifyingGlass'
import {
- Message_Stroke2_Corner0_Rounded as Message,
- Message_Stroke2_Corner0_Rounded_Filled as MessageFilled,
+ Message_Stroke2_Corner0_Rounded as MessageIcon,
+ Message_Stroke2_Corner0_Rounded_Filled as MessageFilledIcon,
} from '#/components/icons/Message'
import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus'
import {
- SettingsGear2_Filled_Corner0_Rounded as SettingsFilled,
- SettingsGear2_Stroke2_Corner0_Rounded as Settings,
+ SettingsGear2_Filled_Corner0_Rounded as SettingsFilledIcon,
+ SettingsGear2_Stroke2_Corner0_Rounded as SettingsIcon,
} from '#/components/icons/SettingsGear2'
import {
- UserCircle_Filled_Corner0_Rounded as UserCircleFilled,
- UserCircle_Stroke2_Corner0_Rounded as UserCircle,
+ UserCircle_Filled_Corner0_Rounded as UserCircleFilledIcon,
+ UserCircle_Stroke2_Corner0_Rounded as UserCircleIcon,
} from '#/components/icons/UserCircle'
-import {CENTER_COLUMN_OFFSET} from '#/components/Layout'
+import {CENTER_COLUMN_OFFSET, CENTER_COLUMN_WIDTH} from '#/components/Layout'
import * as Menu from '#/components/Menu'
import * as Prompt from '#/components/Prompt'
import {Text} from '#/components/Typography'
@@ -84,8 +87,13 @@ import {useActorStatus} from '#/features/liveNow'
import {router} from '#/routes'
import {PlatformInfo} from '../../../../modules/expo-bluesky-swiss-army'
+const LARGE_ELEMENT_SIZE = 48
const NAV_ICON_WIDTH = 28
+export const LEFT_NAV_STANDARD_WIDTH = 240
+export const LEFT_NAV_MINIMAL_WIDTH = 80
+const LEFT_NAV_PWI_WIDTH = 245
+
function ProfileCard({minimal}: {minimal: boolean}) {
const {currentAccount, accounts} = useSession()
const {logoutEveryAccount} = useSessionApi()
@@ -94,11 +102,9 @@ function ProfileCard({minimal}: {minimal: boolean}) {
})
const profiles = data?.profiles
const signOutPromptControl = Prompt.usePromptControl()
- const {_} = useLingui()
+ const {t: l} = useLingui()
const t = useTheme()
- const size = 48
-
const profile = profiles?.find(p => p.did === currentAccount!.did)
const otherAccounts = accounts
.filter(acc => acc.did !== currentAccount!.did)
@@ -110,10 +116,10 @@ function ProfileCard({minimal}: {minimal: boolean}) {
const {isActive: live} = useActorStatus(profile)
return (
-
+
{!isLoading && profile ? (
-
+
{({props, state, control}) => {
const active = state.hovered || state.focused || control.isOpen
return (
@@ -149,7 +155,7 @@ function ProfileCard({minimal}: {minimal: boolean}) {
]}>
@@ -205,18 +211,18 @@ function ProfileCard({minimal}: {minimal: boolean}) {
) : (
)}
logoutEveryAccount('Settings')}
- confirmButtonCta={_(msg`Sign out`)}
- cancelButtonCta={_(msg`Cancel`)}
+ confirmButtonCta={l`Sign out`}
+ cancelButtonCta={l`Cancel`}
confirmButtonColor="negative"
/>
@@ -235,7 +241,7 @@ function SwitchMenuItems({
| undefined
signOutPromptControl: DialogControlProps
}) {
- const {_} = useLingui()
+ const {t: l} = useLingui()
const {setShowLoggedOut} = useLoggedOutViewControls()
const closeEverything = useCloseAllActiveElements()
@@ -264,15 +270,13 @@ function SwitchMenuItems({
>
)}
-
+
Add another account
-
+
Sign out
@@ -283,7 +287,7 @@ function SwitchMenuItems({
}
function SwitcherMenuProfileLink() {
- const {_} = useLingui()
+ const {t: l} = useLingui()
const {currentAccount} = useSession()
const navigation = useNavigation()
const context = Menu.useMenuContext()
@@ -326,11 +330,11 @@ function SwitcherMenuProfileLink() {
)
return (
-
+
Go to profile
@@ -345,7 +349,7 @@ function SwitchMenuItem({
account: SessionAccount
profile: AppBskyActorDefs.ProfileViewDetailed | undefined
}) {
- const {_} = useLingui()
+ const {t: l} = useLingui()
const {onPressSwitchAccount, pendingDid} = useAccountSwitcher()
const {isActive: live} = useActorStatus(profile)
@@ -354,12 +358,10 @@ function SwitchMenuItem({
disabled={!!pendingDid}
style={[a.gap_sm, {minWidth: 150}]}
key={account.did}
- label={_(
- msg`Switch to ${sanitizeHandle(
- profile?.handle ?? account.handle,
- '@',
- )}`,
- )}
+ label={l`Switch to ${sanitizeHandle(
+ profile?.handle ?? account.handle,
+ '@',
+ )}`}
onPress={() => void onPressSwitchAccount(account, 'SwitchAccount')}>
+ active: React.ComponentType
+ }
label: string
minimal: boolean
}
-function NavItem({
- count,
- hasNew,
- href,
- icon,
- iconFilled,
- label,
- minimal,
-}: NavItemProps) {
+function NavItem({count, hasNew, href, icons, label, minimal}: NavItemProps) {
const t = useTheme()
- const {_} = useLingui()
+ const {t: l} = useLingui()
const {currentAccount} = useSession()
const [pathName] = useMemo(() => router.matchPath(href), [href])
@@ -431,6 +427,8 @@ function NavItem({
[navigation, href, isCurrent],
)
+ const Icon = isCurrent || isRelated ? icons.active : icons.inactive
+
return (
- {isCurrent || isRelated ? iconFilled : icon}
+
{typeof count === 'string' && count ? (
) : null}
-
{hasSession && (
<>
- }
- iconFilled={
-
- }
- label={_(msg`Home`)}
+ icons={{
+ inactive: HomeIcon,
+ active: HomeFilledIcon,
+ }}
/>
- }
- iconFilled={
-
- }
- label={_(msg`Explore`)}
+ icons={{
+ inactive: MagnifyingGlassIcon,
+ active: MagnifyingGlassFilledIcon,
+ }}
/>
- }
- iconFilled={
-
- }
- label={_(msg`Notifications`)}
+ icons={{
+ inactive: BellIcon,
+ active: BellFilledIcon,
+ }}
/>
-
+
- }
- iconFilled={
-
- }
- label={_(msg`Feeds`)}
+ icons={{
+ inactive: HashtagIcon,
+ active: HashtagFilledIcon,
+ }}
/>
- }
- iconFilled={
-
- }
- label={_(msg`Lists`)}
+ icons={{
+ inactive: ListIcon,
+ active: ListFilledIcon,
+ }}
/>
- }
- iconFilled={
-
- }
- label={_(
- msg({
- message: 'Saved',
- context: 'link to bookmarks screen',
- }),
- )}
+ icons={{
+ inactive: BookmarkIcon,
+ active: BookmarkFilledIcon,
+ }}
/>
- }
- iconFilled={
-
- }
- label={_(msg`Profile`)}
+ icons={{
+ inactive: UserCircleIcon,
+ active: UserCircleFilledIcon,
+ }}
/>
- }
- iconFilled={
-
- }
- label={_(msg`Settings`)}
+ icons={{
+ inactive: SettingsIcon,
+ active: SettingsFilledIcon,
+ }}
/>
@@ -843,31 +747,11 @@ export function DesktopLeftNav({routeName}: {routeName: string}) {
const styles = StyleSheet.create({
leftNav: {
- ...a.fixed,
- top: 0,
- paddingTop: 10,
- paddingBottom: 10,
left: '50%',
- width: 240,
+ width: LEFT_NAV_STANDARD_WIDTH,
// @ts-expect-error web only
maxHeight: '100vh',
overflowY: 'auto',
scrollbarWidth: 'thin',
},
- leftNavWide: {
- width: 245,
- },
- leftNavMinimal: {
- height: '100%',
- width: 86,
- alignItems: 'center',
- ...web({overflowX: 'hidden'}),
- },
- backBtn: {
- position: 'absolute',
- top: 12,
- right: 12,
- width: 30,
- height: 30,
- },
})