diff --git a/src/App.native.tsx b/src/App.native.tsx
index 8bb204923f..51090ae98c 100644
--- a/src/App.native.tsx
+++ b/src/App.native.tsx
@@ -9,7 +9,7 @@ import {observer} from 'mobx-react-lite'
import {ThemeProvider} from 'lib/ThemeContext'
import * as view from './view/index'
import {RootStoreModel, setupState, RootStoreProvider} from './state'
-import {MobileShell} from './view/shell/mobile'
+import {Shell} from './view/shell'
import {s} from 'lib/styles'
import * as notifee from 'lib/notifee'
import * as analytics from 'lib/analytics'
@@ -54,7 +54,7 @@ const App = observer(() => {
-
+
diff --git a/src/App.web.tsx b/src/App.web.tsx
index 84d3b6cd60..c67fc26411 100644
--- a/src/App.web.tsx
+++ b/src/App.web.tsx
@@ -3,7 +3,7 @@ import {SafeAreaProvider} from 'react-native-safe-area-context'
import {getInitialURL} from 'platform/urls'
import * as view from './view/index'
import {RootStoreModel, setupState, RootStoreProvider} from './state'
-import {WebShell} from './view/shell/web'
+import {Shell} from './view/shell/index'
import {ToastContainer} from './view/com/util/Toast.web'
function App() {
@@ -33,7 +33,7 @@ function App() {
return (
-
+
diff --git a/src/app.json b/src/app.json
deleted file mode 100644
index 1f9e391e0d..0000000000
--- a/src/app.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "xyz.blueskyweb.app",
- "displayName": "Bluesky"
-}
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
deleted file mode 100644
index 45a06f40a5..0000000000
--- a/src/index.js
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * @format
- */
-
-import {AppRegistry} from 'react-native'
-import App from './App'
-
-AppRegistry.registerComponent('App', () => App)
-
-AppRegistry.runApplication('App', {
- rootTag: document.getElementById('root'),
-})
diff --git a/src/lib/link-meta/bsky.ts b/src/lib/link-meta/bsky.ts
index c9c2ed31a5..0d8e8c69bf 100644
--- a/src/lib/link-meta/bsky.ts
+++ b/src/lib/link-meta/bsky.ts
@@ -1,19 +1,20 @@
import {LikelyType, LinkMeta} from './link-meta'
-import {match as matchRoute} from 'view/routes'
+// import {match as matchRoute} from 'view/routes'
import {convertBskyAppUrlIfNeeded, makeRecordUri} from '../strings/url-helpers'
import {RootStoreModel} from 'state/index'
import {PostThreadViewModel} from 'state/models/post-thread-view'
import {ComposerOptsQuote} from 'state/models/shell-ui'
-import {Home} from 'view/screens/Home'
-import {Search} from 'view/screens/Search'
-import {Notifications} from 'view/screens/Notifications'
-import {PostThread} from 'view/screens/PostThread'
-import {PostUpvotedBy} from 'view/screens/PostUpvotedBy'
-import {PostRepostedBy} from 'view/screens/PostRepostedBy'
-import {Profile} from 'view/screens/Profile'
-import {ProfileFollowers} from 'view/screens/ProfileFollowers'
-import {ProfileFollows} from 'view/screens/ProfileFollows'
+// TODO
+// import {Home} from 'view/screens/Home'
+// import {Search} from 'view/screens/Search'
+// import {Notifications} from 'view/screens/Notifications'
+// import {PostThread} from 'view/screens/PostThread'
+// import {PostUpvotedBy} from 'view/screens/PostUpvotedBy'
+// import {PostRepostedBy} from 'view/screens/PostRepostedBy'
+// import {Profile} from 'view/screens/Profile'
+// import {ProfileFollowers} from 'view/screens/ProfileFollowers'
+// import {ProfileFollows} from 'view/screens/ProfileFollows'
// NOTE
// this is a hack around the lack of hosted social metadata
@@ -24,77 +25,77 @@ export async function extractBskyMeta(
url: string,
): Promise {
url = convertBskyAppUrlIfNeeded(url)
- const route = matchRoute(url)
+ // const route = matchRoute(url)
let meta: LinkMeta = {
likelyType: LikelyType.AtpData,
url,
- title: route.defaultTitle,
+ // title: route.defaultTitle,
}
- if (route.Com === Home) {
- meta = {
- ...meta,
- title: 'Bluesky',
- description: 'A new kind of social network',
- }
- } else if (route.Com === Search) {
- meta = {
- ...meta,
- title: 'Search - Bluesky',
- description: 'A new kind of social network',
- }
- } else if (route.Com === Notifications) {
- meta = {
- ...meta,
- title: 'Notifications - Bluesky',
- description: 'A new kind of social network',
- }
- } else if (
- route.Com === PostThread ||
- route.Com === PostUpvotedBy ||
- route.Com === PostRepostedBy
- ) {
- // post and post-related screens
- const threadUri = makeRecordUri(
- route.params.name,
- 'app.bsky.feed.post',
- route.params.rkey,
- )
- const threadView = new PostThreadViewModel(store, {
- uri: threadUri,
- depth: 0,
- })
- await threadView.setup().catch(_err => undefined)
- const title = [
- route.Com === PostUpvotedBy
- ? 'Likes on a post by'
- : route.Com === PostRepostedBy
- ? 'Reposts of a post by'
- : 'Post by',
- threadView.thread?.post.author.displayName ||
- threadView.thread?.post.author.handle ||
- 'a bluesky user',
- ].join(' ')
- meta = {
- ...meta,
- title,
- description: threadView.thread?.postRecord?.text,
- }
- } else if (
- route.Com === Profile ||
- route.Com === ProfileFollowers ||
- route.Com === ProfileFollows
- ) {
- // profile and profile-related screens
- const profile = await store.profiles.getProfile(route.params.name)
- if (profile?.data) {
- meta = {
- ...meta,
- title: profile.data.displayName || profile.data.handle,
- description: profile.data.description,
- }
- }
- }
+ // if (route.Com === Home) {
+ // meta = {
+ // ...meta,
+ // title: 'Bluesky',
+ // description: 'A new kind of social network',
+ // }
+ // } else if (route.Com === Search) {
+ // meta = {
+ // ...meta,
+ // title: 'Search - Bluesky',
+ // description: 'A new kind of social network',
+ // }
+ // } else if (route.Com === Notifications) {
+ // meta = {
+ // ...meta,
+ // title: 'Notifications - Bluesky',
+ // description: 'A new kind of social network',
+ // }
+ // } else if (
+ // route.Com === PostThread ||
+ // route.Com === PostUpvotedBy ||
+ // route.Com === PostRepostedBy
+ // ) {
+ // // post and post-related screens
+ // const threadUri = makeRecordUri(
+ // route.params.name,
+ // 'app.bsky.feed.post',
+ // route.params.rkey,
+ // )
+ // const threadView = new PostThreadViewModel(store, {
+ // uri: threadUri,
+ // depth: 0,
+ // })
+ // await threadView.setup().catch(_err => undefined)
+ // const title = [
+ // route.Com === PostUpvotedBy
+ // ? 'Likes on a post by'
+ // : route.Com === PostRepostedBy
+ // ? 'Reposts of a post by'
+ // : 'Post by',
+ // threadView.thread?.post.author.displayName ||
+ // threadView.thread?.post.author.handle ||
+ // 'a bluesky user',
+ // ].join(' ')
+ // meta = {
+ // ...meta,
+ // title,
+ // description: threadView.thread?.postRecord?.text,
+ // }
+ // } else if (
+ // route.Com === Profile ||
+ // route.Com === ProfileFollowers ||
+ // route.Com === ProfileFollows
+ // ) {
+ // // profile and profile-related screens
+ // const profile = await store.profiles.getProfile(route.params.name)
+ // if (profile?.data) {
+ // meta = {
+ // ...meta,
+ // title: profile.data.displayName || profile.data.handle,
+ // description: profile.data.description,
+ // }
+ // }
+ // }
return meta
}
diff --git a/src/view/screens.tsx b/src/routes.tsx
similarity index 86%
rename from src/view/screens.tsx
rename to src/routes.tsx
index ab41aa650e..f90ecdc845 100644
--- a/src/view/screens.tsx
+++ b/src/routes.tsx
@@ -11,21 +11,21 @@ import {
State,
} from 'lib/routes/types'
-import {Drawer} from './shell/Drawer'
-import {BottomBar} from './shell/BottomBar'
+import {Drawer} from './view/shell/Drawer'
+import {BottomBar} from './view/shell/BottomBar'
-import {HomeScreen} from './screens/Home'
-import {SearchScreen} from './screens/Search'
-import {NotificationsScreen} from './screens/Notifications'
-import {SettingsScreen} from './screens/Settings'
-import {ProfileScreen} from './screens/Profile'
-import {ProfileFollowersScreen} from './screens/ProfileFollowers'
-import {ProfileFollowsScreen} from './screens/ProfileFollows'
-import {PostThreadScreen} from './screens/PostThread'
-import {PostUpvotedByScreen} from './screens/PostUpvotedBy'
-import {PostRepostedByScreen} from './screens/PostRepostedBy'
-import {DebugScreen} from './screens/Debug'
-import {LogScreen} from './screens/Log'
+import {HomeScreen} from './view/screens/Home'
+import {SearchScreen} from './view/screens/Search'
+import {NotificationsScreen} from './view/screens/Notifications'
+import {SettingsScreen} from './view/screens/Settings'
+import {ProfileScreen} from './view/screens/Profile'
+import {ProfileFollowersScreen} from './view/screens/ProfileFollowers'
+import {ProfileFollowsScreen} from './view/screens/ProfileFollows'
+import {PostThreadScreen} from './view/screens/PostThread'
+import {PostUpvotedByScreen} from './view/screens/PostUpvotedBy'
+import {PostRepostedByScreen} from './view/screens/PostRepostedBy'
+import {DebugScreen} from './view/screens/Debug'
+import {LogScreen} from './view/screens/Log'
const HomeDrawer = createDrawerNavigator()
const HomeTab = createNativeStackNavigator()
@@ -52,7 +52,7 @@ function r(pattern: string): Route {
match(path: string) {
const res = matcherRe.exec(path)
if (res) {
- return {params: res.groups}
+ return {params: res.groups || {}}
}
return undefined
},
@@ -101,7 +101,7 @@ export const LINKING = {
getPathFromState(state: State) {
// find the current node in the navigation tree
- let node = state.routes[state.index]
+ let node = state.routes[state.index || 0]
while (node.state?.routes && typeof node.state?.index === 'number') {
node = node.state?.routes[node.state?.index]
}
@@ -239,7 +239,7 @@ function SearchTabNavigator() {
)
}
-function TabsNavigator() {
+export function TabsNavigator() {
const tabBar = React.useCallback(props => , [])
return (
-
-
- )
+export function RoutesContainer({children}: React.PropsWithChildren<{}>) {
+ return {children}
}
diff --git a/src/view/com/util/Link.tsx b/src/view/com/util/Link.tsx
index 596c2147d1..75a914ae5c 100644
--- a/src/view/com/util/Link.tsx
+++ b/src/view/com/util/Link.tsx
@@ -15,7 +15,7 @@ import {useLinkProps, useNavigation} from '@react-navigation/native'
import {Text} from './text/Text'
import {TypographyVariant} from 'lib/ThemeContext'
import {NavigationProp} from 'lib/routes/types'
-import {matchPath} from 'view/screens'
+import {matchPath} from '../../../Routes'
import {useStores, RootStoreModel} from 'state/index'
import {convertBskyAppUrlIfNeeded} from 'lib/strings/url-helpers'
@@ -36,7 +36,7 @@ export const Link = observer(function Link({
children?: React.ReactNode
noFeedback?: boolean
}) {
- let {...props} = useLinkProps({to: href})
+ let {...props} = useLinkProps({to: href || ''})
const store = useStores()
const navigation = useNavigation()
diff --git a/src/view/routes.ts b/src/view/routes.ts
deleted file mode 100644
index cadf596f98..0000000000
--- a/src/view/routes.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-import React from 'react'
-import {IconProp} from '@fortawesome/fontawesome-svg-core'
-import {Home} from './screens/Home'
-import {Search} from './screens/Search'
-import {Notifications} from './screens/Notifications'
-import {NotFound} from './screens/NotFound'
-import {PostThread} from './screens/PostThread'
-import {PostUpvotedBy} from './screens/PostUpvotedBy'
-import {PostRepostedBy} from './screens/PostRepostedBy'
-import {Profile} from './screens/Profile'
-import {ProfileFollowers} from './screens/ProfileFollowers'
-import {ProfileFollows} from './screens/ProfileFollows'
-import {Settings} from './screens/Settings'
-import {Debug} from './screens/Debug'
-import {Log} from './screens/Log'
-
-export type ScreenParams = {
- navIdx: string
- params: Record
- visible: boolean
-}
-export type Route = [React.FC, string, IconProp, RegExp]
-export type MatchResult = {
- Com: React.FC
- defaultTitle: string
- icon: IconProp
- params: Record
- isNotFound?: boolean
-}
-
-const r = (pattern: string) => new RegExp('^' + pattern + '([?]|$)', 'i')
-export const routes: Route[] = [
- [Home, 'Home', 'house', r('/')],
- [Search, 'Search', 'magnifying-glass', r('/search')],
- [Notifications, 'Notifications', 'bell', r('/notifications')],
- [Settings, 'Settings', 'bell', r('/settings')],
- [Profile, 'User', ['far', 'user'], r('/profile/(?[^/]+)')],
- [
- ProfileFollowers,
- 'Followers',
- 'users',
- r('/profile/(?[^/]+)/followers'),
- ],
- [ProfileFollows, 'Follows', 'users', r('/profile/(?[^/]+)/follows')],
- [
- PostThread,
- 'Post',
- ['far', 'message'],
- r('/profile/(?[^/]+)/post/(?[^/]+)'),
- ],
- [
- PostUpvotedBy,
- 'Liked by',
- 'heart',
- r('/profile/(?[^/]+)/post/(?[^/]+)/upvoted-by'),
- ],
- [
- PostRepostedBy,
- 'Reposted by',
- 'retweet',
- r('/profile/(?[^/]+)/post/(?[^/]+)/reposted-by'),
- ],
- [Debug, 'Debug', 'house', r('/sys/debug')],
- [Log, 'Log', 'house', r('/sys/log')],
-]
-
-export function match(url: string): MatchResult {
- for (const [Com, defaultTitle, icon, pattern] of routes) {
- const res = pattern.exec(url)
- if (res) {
- // TODO: query params
- return {Com, defaultTitle, icon, params: res.groups || {}}
- }
- }
- return {
- Com: NotFound,
- defaultTitle: 'Not found',
- icon: 'magnifying-glass',
- params: {},
- isNotFound: true,
- }
-}
diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx
index 89a30c0467..505b1fcfe8 100644
--- a/src/view/screens/Home.tsx
+++ b/src/view/screens/Home.tsx
@@ -18,7 +18,7 @@ import {ComposeIcon2} from 'lib/icons'
const HEADER_HEIGHT = 42
type Props = NativeStackScreenProps
-export const HomeScreen = observer(function Home({}: Props) {
+export const HomeScreen = observer(function Home(_opts: Props) {
const store = useStores()
const onMainScroll = useOnMainScroll(store)
const {screen, track} = useAnalytics()
diff --git a/src/view/shell/mobile/Composer.tsx b/src/view/shell/Composer.tsx
similarity index 96%
rename from src/view/shell/mobile/Composer.tsx
rename to src/view/shell/Composer.tsx
index 5fca118bda..bb15053e78 100644
--- a/src/view/shell/mobile/Composer.tsx
+++ b/src/view/shell/Composer.tsx
@@ -1,7 +1,7 @@
import React, {useEffect} from 'react'
import {observer} from 'mobx-react-lite'
import {Animated, Easing, Platform, StyleSheet, View} from 'react-native'
-import {ComposePost} from '../../com/composer/ComposePost'
+import {ComposePost} from '../com/composer/ComposePost'
import {ComposerOpts} from 'state/models/shell-ui'
import {useAnimatedValue} from 'lib/hooks/useAnimatedValue'
import {usePalette} from 'lib/hooks/usePalette'
diff --git a/src/view/shell/web/Composer.tsx b/src/view/shell/Composer.web.tsx
similarity index 95%
rename from src/view/shell/web/Composer.tsx
rename to src/view/shell/Composer.web.tsx
index 0d84842621..0a16483c83 100644
--- a/src/view/shell/web/Composer.tsx
+++ b/src/view/shell/Composer.web.tsx
@@ -1,7 +1,7 @@
import React from 'react'
import {observer} from 'mobx-react-lite'
import {StyleSheet, View} from 'react-native'
-import {ComposePost} from '../../com/composer/ComposePost'
+import {ComposePost} from '../com/composer/ComposePost'
import {ComposerOpts} from 'state/models/shell-ui'
import {usePalette} from 'lib/hooks/usePalette'
diff --git a/src/view/shell/Drawer.tsx b/src/view/shell/Drawer.tsx
index b179b630a9..63994c72a9 100644
--- a/src/view/shell/Drawer.tsx
+++ b/src/view/shell/Drawer.tsx
@@ -318,7 +318,7 @@ const styles = StyleSheet.create({
flex: 1,
paddingTop: 20,
paddingBottom: 50,
- paddingLeft: 30,
+ paddingLeft: 20,
},
viewDarkMode: {
backgroundColor: '#1B1919',
diff --git a/src/view/shell/web/DesktopHeader.tsx b/src/view/shell/desktop/Header.tsx
similarity index 99%
rename from src/view/shell/web/DesktopHeader.tsx
rename to src/view/shell/desktop/Header.tsx
index 8748ebbdee..594249ed40 100644
--- a/src/view/shell/web/DesktopHeader.tsx
+++ b/src/view/shell/desktop/Header.tsx
@@ -16,7 +16,7 @@ import {
MagnifyingGlassIcon,
CogIcon,
} from 'lib/icons'
-import {DesktopSearch} from './DesktopSearch'
+import {DesktopSearch} from './Search'
interface NavItemProps {
count?: number
diff --git a/src/view/shell/web/DesktopSearch.tsx b/src/view/shell/desktop/Search.tsx
similarity index 98%
rename from src/view/shell/web/DesktopSearch.tsx
rename to src/view/shell/desktop/Search.tsx
index 43f13ca2bc..b8bfe59f7b 100644
--- a/src/view/shell/web/DesktopSearch.tsx
+++ b/src/view/shell/desktop/Search.tsx
@@ -5,7 +5,7 @@ import {observer} from 'mobx-react-lite'
import {useStores} from 'state/index'
import {usePalette} from 'lib/hooks/usePalette'
import {MagnifyingGlassIcon} from 'lib/icons'
-import {ProfileCard} from '../../com/profile/ProfileCard'
+import {ProfileCard} from '../com/profile/ProfileCard'
export const DesktopSearch = observer(function DesktopSearch() {
const store = useStores()
diff --git a/src/view/shell/mobile/index.tsx b/src/view/shell/index.tsx
similarity index 67%
rename from src/view/shell/mobile/index.tsx
rename to src/view/shell/index.tsx
index 24353486dd..e5258e9007 100644
--- a/src/view/shell/mobile/index.tsx
+++ b/src/view/shell/index.tsx
@@ -1,23 +1,28 @@
import React from 'react'
import {observer} from 'mobx-react-lite'
import {StatusBar, StyleSheet, useWindowDimensions, View} from 'react-native'
+import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {useStores} from 'state/index'
-import {Login} from '../../screens/Login'
-import {ModalsContainer} from '../../com/modals/Modal'
-import {Lightbox} from '../../com/lightbox/Lightbox'
-import {Text} from '../../com/util/text/Text'
+import {Login} from '../screens/Login'
+import {ModalsContainer} from '../com/modals/Modal'
+import {Lightbox} from '../com/lightbox/Lightbox'
+import {Text} from '../com/util/text/Text'
import {Composer} from './Composer'
import {s} from 'lib/styles'
import {useTheme} from 'lib/ThemeContext'
import {usePalette} from 'lib/hooks/usePalette'
+import {RoutesContainer, TabsNavigator} from '../../Routes'
-import {Screens} from '../../screens'
-
-export const MobileShell: React.FC = observer(() => {
+export const Shell: React.FC = observer(() => {
const theme = useTheme()
const pal = usePalette('default')
const store = useStores()
const winDim = useWindowDimensions()
+ const safeAreaInsets = useSafeAreaInsets()
+ const containerPadding = React.useMemo(
+ () => ({height: '100%', paddingTop: safeAreaInsets.top}),
+ [safeAreaInsets],
+ )
if (store.hackUpgradeNeeded) {
return (
@@ -73,18 +78,22 @@ export const MobileShell: React.FC = observer(() => {
theme.colorScheme === 'dark' ? 'light-content' : 'dark-content'
}
/>
-
-
-
- store.shell.closeComposer()}
- winHeight={winDim.height}
- replyTo={store.shell.composerOpts?.replyTo}
- imagesOpen={store.shell.composerOpts?.imagesOpen}
- onPost={store.shell.composerOpts?.onPost}
- quote={store.shell.composerOpts?.quote}
- />
+
+
+
+
+
+
+ store.shell.closeComposer()}
+ winHeight={winDim.height}
+ replyTo={store.shell.composerOpts?.replyTo}
+ imagesOpen={store.shell.composerOpts?.imagesOpen}
+ onPost={store.shell.composerOpts?.onPost}
+ quote={store.shell.composerOpts?.quote}
+ />
+
)
})
diff --git a/src/view/shell/web/index.tsx b/src/view/shell/index.web.tsx
similarity index 88%
rename from src/view/shell/web/index.tsx
rename to src/view/shell/index.web.tsx
index 22bd55434f..8566525ca3 100644
--- a/src/view/shell/web/index.tsx
+++ b/src/view/shell/index.web.tsx
@@ -3,23 +3,22 @@ import {observer} from 'mobx-react-lite'
import {View, StyleSheet} from 'react-native'
import {IconProp} from '@fortawesome/fontawesome-svg-core'
import {useStores} from 'state/index'
-import {NavigationModel} from 'state/models/navigation'
-import {match, MatchResult} from '../../routes'
-import {DesktopHeader} from './DesktopHeader'
-import {Login} from '../../screens/Login'
-import {ErrorBoundary} from '../../com/util/ErrorBoundary'
-import {Lightbox} from '../../com/lightbox/Lightbox'
-import {ModalsContainer} from '../../com/modals/Modal'
+import {match, MatchResult} from '../routes'
+import {DesktopHeader} from './desktop/Header'
+import {Login} from '../screens/Login'
+import {ErrorBoundary} from '../com/util/ErrorBoundary'
+import {Lightbox} from '../com/lightbox/Lightbox'
+import {ModalsContainer} from '../com/modals/Modal'
import {Text} from 'view/com/util/text/Text'
-import {Composer} from './Composer'
+import {Composer} from './Composer.web'
import {usePalette} from 'lib/hooks/usePalette'
import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle'
import {s, colors} from 'lib/styles'
import {isMobileWeb} from 'platform/detection'
-import {Screens} from '../../screens'
+import {RoutesContainer} from '../../Routes'
-export const WebShell: React.FC = observer(() => {
+export const Shell: React.FC = observer(() => {
const pageBg = useColorSchemeStyle(styles.bgLight, styles.bgDark)
const store = useStores()
const screenRenderDesc = constructScreenRenderDesc(store.nav)
@@ -28,7 +27,7 @@ export const WebShell: React.FC = observer(() => {
return
}
- return
+ return
if (!store.session.hasSession) {
return (