about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2023-01-26 11:25:52 -0600
committerPaul Frazee <pfrazee@gmail.com>2023-01-26 11:25:52 -0600
commit7e3f6f030680a8cf7b5baa3ce6f33acd5766fca8 (patch)
tree38ad7a0c586caa6cd0635653cb812d602210b718 /src
parentc4ba5e7fd507a2f5295fd3fcbcea0796223c744c (diff)
downloadvoidsky-7e3f6f030680a8cf7b5baa3ce6f33acd5766fca8.tar.zst
Fix all type errors
Diffstat (limited to 'src')
-rw-r--r--src/App.web.tsx4
-rw-r--r--src/lib/extractHtmlMeta.ts2
-rw-r--r--src/state/models/profile-ui.ts2
-rw-r--r--src/view/com/composer/ComposePost.tsx11
-rw-r--r--src/view/com/composer/PhotoCarouselPicker.tsx17
-rw-r--r--src/view/com/discover/SuggestedFollows.tsx7
-rw-r--r--src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.tsx21
-rw-r--r--src/view/com/lightbox/ImageViewing/hooks/useImageDimensions.ts2
-rw-r--r--src/view/com/lightbox/ImageViewing/hooks/usePanResponder.ts2
-rw-r--r--src/view/com/lightbox/ImageViewing/utils.ts1
-rw-r--r--src/view/com/lightbox/Lightbox.tsx11
-rw-r--r--src/view/com/login/CreateAccount.tsx13
-rw-r--r--src/view/com/login/Signin.tsx17
-rw-r--r--src/view/com/modals/EditProfile.tsx1
-rw-r--r--src/view/com/modals/Modal.tsx12
-rw-r--r--src/view/com/modals/ServerInput.tsx22
-rw-r--r--src/view/com/notifications/FeedItem.tsx27
-rw-r--r--src/view/com/onboard/FeatureExplainer.tsx26
-rw-r--r--src/view/com/post-thread/PostThreadItem.tsx12
-rw-r--r--src/view/com/post-thread/PostVotedBy.tsx6
-rw-r--r--src/view/com/post/PostText.tsx4
-rw-r--r--src/view/com/posts/FeedItem.tsx15
-rw-r--r--src/view/com/profile/ProfileFollows.tsx6
-rw-r--r--src/view/com/profile/ProfileHeader.tsx12
-rw-r--r--src/view/com/util/EmptyState.tsx10
-rw-r--r--src/view/com/util/LoadingPlaceholder.tsx2
-rw-r--r--src/view/com/util/PostCtrls.tsx18
-rw-r--r--src/view/com/util/ViewHeader.tsx11
-rw-r--r--src/view/com/util/error/ErrorMessage.tsx11
-rw-r--r--src/view/com/util/error/ErrorScreen.tsx11
-rw-r--r--src/view/com/util/forms/DropdownButton.tsx2
-rw-r--r--src/view/com/util/images/AutoSizedImage.tsx3
-rw-r--r--src/view/com/util/images/ImageLayoutGrid.tsx22
-rw-r--r--src/view/lib/icons.tsx13
-rw-r--r--src/view/routes.ts2
-rw-r--r--src/view/screens/Debug.tsx19
-rw-r--r--src/view/shell/desktop-web/left-column.tsx100
-rw-r--r--src/view/shell/mobile/TabsSelector.tsx11
-rw-r--r--src/view/shell/mobile/index.tsx60
39 files changed, 354 insertions, 194 deletions
diff --git a/src/App.web.tsx b/src/App.web.tsx
index cc6f3815b..0be05486c 100644
--- a/src/App.web.tsx
+++ b/src/App.web.tsx
@@ -2,7 +2,7 @@ import React, {useState, useEffect} from 'react'
 import * as view from './view/index'
 import {RootStoreModel, setupState, RootStoreProvider} from './state'
 import {DesktopWebShell} from './view/shell/desktop-web'
-import Toast from 'react-native-root-toast'
+// import Toast from 'react-native-root-toast' TODO
 
 function App() {
   const [rootStore, setRootStore] = useState<RootStoreModel | undefined>(
@@ -23,9 +23,9 @@ function App() {
   return (
     <RootStoreProvider value={rootStore}>
       <DesktopWebShell />
-      <Toast.ToastContainer />
     </RootStoreProvider>
   )
+  // <Toast.ToastContainer /> TODO
 }
 
 export default App
diff --git a/src/lib/extractHtmlMeta.ts b/src/lib/extractHtmlMeta.ts
index 038ca81c6..70387f71d 100644
--- a/src/lib/extractHtmlMeta.ts
+++ b/src/lib/extractHtmlMeta.ts
@@ -63,7 +63,7 @@ export const extractHtmlMeta = ({
   // Workaround for some websites not having a title or description in the meta tags in the initial serve
   if (isYoutubeUrl) {
     res = {...res, ...extractYoutubeMeta(html)}
-  } else if (isTwitterUrl) {
+  } else if (isTwitterUrl && pathname) {
     res = {...extractTwitterMeta({pathname})}
   }
 
diff --git a/src/state/models/profile-ui.ts b/src/state/models/profile-ui.ts
index 55fb25061..89723361a 100644
--- a/src/state/models/profile-ui.ts
+++ b/src/state/models/profile-ui.ts
@@ -98,8 +98,6 @@ export class ProfileUiModel {
     const view = this.currentView
     if (view instanceof FeedModel) {
       await view.update()
-    } else {
-      await view.refresh()
     }
   }
 
diff --git a/src/view/com/composer/ComposePost.tsx b/src/view/com/composer/ComposePost.tsx
index a414a7562..64e75328a 100644
--- a/src/view/com/composer/ComposePost.tsx
+++ b/src/view/com/composer/ComposePost.tsx
@@ -16,7 +16,10 @@ import PasteInput, {
   PasteInputRef,
 } from '@mattermost/react-native-paste-input'
 import LinearGradient from 'react-native-linear-gradient'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {
+  FontAwesomeIcon,
+  FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
 import {useAnalytics} from '@segment/analytics-react-native'
 import {UserAutocompleteViewModel} from '../../../state/models/user-autocomplete-view'
 import {Autocomplete} from './Autocomplete'
@@ -438,7 +441,11 @@ export const ComposePost = observer(function ComposePost({
               hitSlop={HITSLOP}>
               <FontAwesomeIcon
                 icon={['far', 'image']}
-                style={selectedPhotos.length < 4 ? pal.link : pal.textLight}
+                style={
+                  (selectedPhotos.length < 4
+                    ? pal.link
+                    : pal.textLight) as FontAwesomeIconStyle
+                }
                 size={24}
               />
             </TouchableOpacity>
diff --git a/src/view/com/composer/PhotoCarouselPicker.tsx b/src/view/com/composer/PhotoCarouselPicker.tsx
index 5a5b1cc3b..383027de3 100644
--- a/src/view/com/composer/PhotoCarouselPicker.tsx
+++ b/src/view/com/composer/PhotoCarouselPicker.tsx
@@ -1,6 +1,9 @@
 import React, {useCallback} from 'react'
 import {Image, StyleSheet, TouchableOpacity, ScrollView} from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {
+  FontAwesomeIcon,
+  FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
 import {
   openPicker,
   openCamera,
@@ -131,13 +134,21 @@ export const PhotoCarouselPicker = ({
         testID="openCameraButton"
         style={[styles.galleryButton, pal.border, styles.photo]}
         onPress={handleOpenCamera}>
-        <FontAwesomeIcon icon="camera" size={24} style={pal.link} />
+        <FontAwesomeIcon
+          icon="camera"
+          size={24}
+          style={pal.link as FontAwesomeIconStyle}
+        />
       </TouchableOpacity>
       <TouchableOpacity
         testID="openGalleryButton"
         style={[styles.galleryButton, pal.border, styles.photo]}
         onPress={handleOpenGallery}>
-        <FontAwesomeIcon icon="image" style={pal.link} size={24} />
+        <FontAwesomeIcon
+          icon="image"
+          style={pal.link as FontAwesomeIconStyle}
+          size={24}
+        />
       </TouchableOpacity>
       {localPhotos.photos.map((item: PhotoIdentifier, index: number) => (
         <TouchableOpacity
diff --git a/src/view/com/discover/SuggestedFollows.tsx b/src/view/com/discover/SuggestedFollows.tsx
index bfc82b369..f2dc0ce48 100644
--- a/src/view/com/discover/SuggestedFollows.tsx
+++ b/src/view/com/discover/SuggestedFollows.tsx
@@ -7,7 +7,10 @@ import {
   View,
 } from 'react-native'
 import LinearGradient from 'react-native-linear-gradient'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {
+  FontAwesomeIcon,
+  FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
 import {observer} from 'mobx-react-lite'
 import _omit from 'lodash.omit'
 import {ErrorScreen} from '../util/error/ErrorScreen'
@@ -199,7 +202,7 @@ const User = ({
                 style={[styles.btn, styles.gradientBtn]}>
                 <FontAwesomeIcon
                   icon="plus"
-                  style={[s.white, s.mr5]}
+                  style={[s.white as FontAwesomeIconStyle, s.mr5]}
                   size={15}
                 />
                 <Text style={[s.white, s.fw600, s.f15]}>Follow</Text>
diff --git a/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.tsx b/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.tsx
new file mode 100644
index 000000000..fd377dde2
--- /dev/null
+++ b/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.tsx
@@ -0,0 +1,21 @@
+// default implementation fallback for web
+
+import React from 'react'
+import {View} from 'react-native'
+import {ImageSource} from '../../@types'
+
+type Props = {
+  imageSrc: ImageSource
+  onRequestClose: () => void
+  onZoom: (scaled: boolean) => void
+  onLongPress: (image: ImageSource) => void
+  delayLongPress: number
+  swipeToCloseEnabled?: boolean
+  doubleTapToZoomEnabled?: boolean
+}
+
+const ImageItem = (_props: Props) => {
+  return <View />
+}
+
+export default React.memo(ImageItem)
diff --git a/src/view/com/lightbox/ImageViewing/hooks/useImageDimensions.ts b/src/view/com/lightbox/ImageViewing/hooks/useImageDimensions.ts
index bab136c50..a5b0b6bd4 100644
--- a/src/view/com/lightbox/ImageViewing/hooks/useImageDimensions.ts
+++ b/src/view/com/lightbox/ImageViewing/hooks/useImageDimensions.ts
@@ -47,8 +47,8 @@ const useImageDimensions = (image: ImageSource): Dimensions | null => {
         if (imageDimensions) {
           resolve(imageDimensions)
         } else {
-          // @ts-ignore
           Image.getSizeWithHeaders(
+            // @ts-ignore
             source.uri,
             source.headers,
             (width: number, height: number) => {
diff --git a/src/view/com/lightbox/ImageViewing/hooks/usePanResponder.ts b/src/view/com/lightbox/ImageViewing/hooks/usePanResponder.ts
index 4600cf1a8..036e7246f 100644
--- a/src/view/com/lightbox/ImageViewing/hooks/usePanResponder.ts
+++ b/src/view/com/lightbox/ImageViewing/hooks/usePanResponder.ts
@@ -61,7 +61,7 @@ const usePanResponder = ({
   let tmpTranslate: Position | null = null
   let isDoubleTapPerformed = false
   let lastTapTS: number | null = null
-  let longPressHandlerRef: number | null = null
+  let longPressHandlerRef: NodeJS.Timeout | null = null
 
   const meaningfulShift = MIN_DIMENSION * 0.01
   const scaleValue = new Animated.Value(initialScale)
diff --git a/src/view/com/lightbox/ImageViewing/utils.ts b/src/view/com/lightbox/ImageViewing/utils.ts
index 7fcdc84cf..8c9c1b34c 100644
--- a/src/view/com/lightbox/ImageViewing/utils.ts
+++ b/src/view/com/lightbox/ImageViewing/utils.ts
@@ -77,6 +77,7 @@ export const getImageStyles = (
   const transform = translate.getTranslateTransform()
 
   if (scale) {
+    // @ts-ignore TODO - is scale incorrect? might need to remove -prf
     transform.push({scale}, {perspective: new Animated.Value(1000)})
   }
 
diff --git a/src/view/com/lightbox/Lightbox.tsx b/src/view/com/lightbox/Lightbox.tsx
index c777a5528..df5839783 100644
--- a/src/view/com/lightbox/Lightbox.tsx
+++ b/src/view/com/lightbox/Lightbox.tsx
@@ -5,6 +5,7 @@ import ImageView from './ImageViewing'
 import {useStores} from '../../../state'
 import * as models from '../../../state/models/shell-ui'
 import {saveImageModal} from '../../../lib/images'
+import {ImageSource} from './ImageViewing/@types'
 
 export const Lightbox = observer(function Lightbox() {
   const store = useStores()
@@ -15,8 +16,14 @@ export const Lightbox = observer(function Lightbox() {
   const onClose = () => {
     store.shell.closeLightbox()
   }
-  const onLongPress = ({uri}: {uri: string}) => {
-    saveImageModal({uri})
+  const onLongPress = (image: ImageSource) => {
+    if (
+      typeof image === 'object' &&
+      'uri' in image &&
+      typeof image.uri === 'string'
+    ) {
+      saveImageModal({uri: image.uri})
+    }
   }
 
   if (store.shell.activeLightbox?.name === 'profile-image') {
diff --git a/src/view/com/login/CreateAccount.tsx b/src/view/com/login/CreateAccount.tsx
index c5507b760..be5074eee 100644
--- a/src/view/com/login/CreateAccount.tsx
+++ b/src/view/com/login/CreateAccount.tsx
@@ -9,7 +9,10 @@ import {
   TouchableOpacity,
   View,
 } from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {
+  FontAwesomeIcon,
+  FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
 import {ComAtprotoAccountCreate} from '@atproto/api'
 import * as EmailValidator from 'email-validator'
 import {useAnalytics} from '@segment/analytics-react-native'
@@ -264,7 +267,7 @@ export const CreateAccount = ({onPressBack}: {onPressBack: () => void}) => {
                   <Picker
                     style={[pal.text, styles.picker]}
                     labelStyle={styles.pickerLabel}
-                    iconStyle={pal.textLight}
+                    iconStyle={pal.textLight as FontAwesomeIconStyle}
                     value={userDomain}
                     items={serviceDescription.availableUserDomains.map(d => ({
                       label: `.${d}`,
@@ -371,7 +374,11 @@ const Policies = ({
     return (
       <View style={styles.policies}>
         <View style={[styles.errorIcon, {borderColor: pal.colors.text}, s.mt2]}>
-          <FontAwesomeIcon icon="exclamation" style={pal.textLight} size={10} />
+          <FontAwesomeIcon
+            icon="exclamation"
+            style={pal.textLight as FontAwesomeIconStyle}
+            size={10}
+          />
         </View>
         <Text style={[pal.textLight, s.pl5, s.flex1]}>
           This service has not provided terms of service or a privacy policy.
diff --git a/src/view/com/login/Signin.tsx b/src/view/com/login/Signin.tsx
index 2dfb012e8..1c8a54ad8 100644
--- a/src/view/com/login/Signin.tsx
+++ b/src/view/com/login/Signin.tsx
@@ -8,7 +8,10 @@ import {
   TouchableOpacity,
   View,
 } from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {
+  FontAwesomeIcon,
+  FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
 import * as EmailValidator from 'email-validator'
 import {sessionClient as AtpApi, SessionServiceClient} from '@atproto/api'
 import {useAnalytics} from '@segment/analytics-react-native'
@@ -337,7 +340,11 @@ const LoginForm = ({
               {toNiceDomain(serviceUrl)}
             </Text>
             <View style={[pal.btn, styles.textBtnFakeInnerBtn]}>
-              <FontAwesomeIcon icon="pen" size={12} style={pal.textLight} />
+              <FontAwesomeIcon
+                icon="pen"
+                size={12}
+                style={pal.textLight as FontAwesomeIconStyle}
+              />
             </View>
           </TouchableOpacity>
         </View>
@@ -514,7 +521,11 @@ const ForgotPasswordForm = ({
               {toNiceDomain(serviceUrl)}
             </Text>
             <View style={[pal.btn, styles.textBtnFakeInnerBtn]}>
-              <FontAwesomeIcon icon="pen" size={12} style={pal.text} />
+              <FontAwesomeIcon
+                icon="pen"
+                size={12}
+                style={pal.text as FontAwesomeIconStyle}
+              />
             </View>
           </TouchableOpacity>
           <View style={[pal.borderDark, styles.groupContent]}>
diff --git a/src/view/com/modals/EditProfile.tsx b/src/view/com/modals/EditProfile.tsx
index ba99feb32..8449fda68 100644
--- a/src/view/com/modals/EditProfile.tsx
+++ b/src/view/com/modals/EditProfile.tsx
@@ -108,7 +108,6 @@ export function Component({
           <UserBanner
             banner={userBanner}
             onSelectNewBanner={onSelectNewBanner}
-            handle={profileView.handle}
           />
           <View style={styles.avi}>
             <UserAvatar
diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx
index e0e18d54a..d0b40d56d 100644
--- a/src/view/com/modals/Modal.tsx
+++ b/src/view/com/modals/Modal.tsx
@@ -62,18 +62,10 @@ export const Modal = observer(function Modal() {
     )
   } else if (store.shell.activeModal?.name === 'report-post') {
     snapPoints = ReportPostModal.snapPoints
-    element = (
-      <ReportPostModal.Component
-        {...(store.shell.activeModal as models.ReportPostModal)}
-      />
-    )
+    element = <ReportPostModal.Component />
   } else if (store.shell.activeModal?.name === 'report-account') {
     snapPoints = ReportAccountModal.snapPoints
-    element = (
-      <ReportAccountModal.Component
-        {...(store.shell.activeModal as models.ReportAccountModal)}
-      />
-    )
+    element = <ReportAccountModal.Component />
   } else {
     element = <View />
   }
diff --git a/src/view/com/modals/ServerInput.tsx b/src/view/com/modals/ServerInput.tsx
index 31ef4b12d..85c0d70b7 100644
--- a/src/view/com/modals/ServerInput.tsx
+++ b/src/view/com/modals/ServerInput.tsx
@@ -1,6 +1,9 @@
 import React, {useState} from 'react'
 import {Platform, StyleSheet, TouchableOpacity, View} from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {
+  FontAwesomeIcon,
+  FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
 import {BottomSheetScrollView, BottomSheetTextInput} from '@gorhom/bottom-sheet'
 import {Text} from '../util/text/Text'
 import {useStores} from '../../../state'
@@ -37,13 +40,19 @@ export function Component({onSelect}: {onSelect: (url: string) => void}) {
                 style={styles.btn}
                 onPress={() => doSelect(LOCAL_DEV_SERVICE)}>
                 <Text style={styles.btnText}>Local dev server</Text>
-                <FontAwesomeIcon icon="arrow-right" style={s.white} />
+                <FontAwesomeIcon
+                  icon="arrow-right"
+                  style={s.white as FontAwesomeIconStyle}
+                />
               </TouchableOpacity>
               <TouchableOpacity
                 style={styles.btn}
                 onPress={() => doSelect(STAGING_SERVICE)}>
                 <Text style={styles.btnText}>Staging</Text>
-                <FontAwesomeIcon icon="arrow-right" style={s.white} />
+                <FontAwesomeIcon
+                  icon="arrow-right"
+                  style={s.white as FontAwesomeIconStyle}
+                />
               </TouchableOpacity>
             </>
           ) : undefined}
@@ -51,7 +60,10 @@ export function Component({onSelect}: {onSelect: (url: string) => void}) {
             style={styles.btn}
             onPress={() => doSelect(PROD_SERVICE)}>
             <Text style={styles.btnText}>Bluesky.Social</Text>
-            <FontAwesomeIcon icon="arrow-right" style={s.white} />
+            <FontAwesomeIcon
+              icon="arrow-right"
+              style={s.white as FontAwesomeIconStyle}
+            />
           </TouchableOpacity>
         </View>
         <View style={styles.group}>
@@ -74,7 +86,7 @@ export function Component({onSelect}: {onSelect: (url: string) => void}) {
               onPress={() => doSelect(customUrl)}>
               <FontAwesomeIcon
                 icon="check"
-                style={[s.black, styles.checkIcon]}
+                style={[s.black as FontAwesomeIconStyle, styles.checkIcon]}
                 size={18}
               />
             </TouchableOpacity>
diff --git a/src/view/com/notifications/FeedItem.tsx b/src/view/com/notifications/FeedItem.tsx
index 48c8b9a1f..da6fc7d35 100644
--- a/src/view/com/notifications/FeedItem.tsx
+++ b/src/view/com/notifications/FeedItem.tsx
@@ -9,7 +9,11 @@ import {
 } from 'react-native'
 import {AppBskyEmbedImages} from '@atproto/api'
 import {AtUri} from '../../../third-party/uri'
-import {FontAwesomeIcon, Props} from '@fortawesome/react-native-fontawesome'
+import {
+  FontAwesomeIcon,
+  FontAwesomeIconStyle,
+  Props,
+} from '@fortawesome/react-native-fontawesome'
 import {NotificationsViewItemModel} from '../../../state/models/notifications-view'
 import {PostThreadViewModel} from '../../../state/models/post-thread-view'
 import {s, colors} from '../../lib/styles'
@@ -98,18 +102,21 @@ export const FeedItem = observer(function FeedItem({
   if (item.isUpvote) {
     action = 'liked your post'
     icon = 'HeartIconSolid'
-    iconStyle = [s.red3, {position: 'relative', top: -4}]
+    iconStyle = [
+      s.red3 as FontAwesomeIconStyle,
+      {position: 'relative', top: -4},
+    ]
   } else if (item.isRepost) {
     action = 'reposted your post'
     icon = 'retweet'
-    iconStyle = [s.green3]
+    iconStyle = [s.green3 as FontAwesomeIconStyle]
   } else if (item.isReply) {
     action = 'replied to your post'
     icon = ['far', 'comment']
   } else if (item.isFollow) {
     action = 'followed you'
     icon = 'user-plus'
-    iconStyle = [s.blue3]
+    iconStyle = [s.blue3 as FontAwesomeIconStyle]
   } else {
     return <></>
   }
@@ -292,7 +299,6 @@ function ExpandedAuthorsList({
     authors.length * (EXPANDED_AUTHOR_EL_HEIGHT + 10) /*10=margin*/
   const heightStyle = {
     height: Animated.multiply(heightInterp, targetHeight),
-    overflow: 'hidden',
   }
   React.useEffect(() => {
     Animated.timing(heightInterp, {
@@ -302,7 +308,12 @@ function ExpandedAuthorsList({
     }).start()
   }, [heightInterp, visible])
   return (
-    <Animated.View style={[heightStyle, visible ? s.mb10 : undefined]}>
+    <Animated.View
+      style={[
+        heightStyle,
+        styles.overflowHidden,
+        visible ? s.mb10 : undefined,
+      ]}>
       {authors.map(author => (
         <Link
           key={author.href}
@@ -360,6 +371,10 @@ function AdditionalPostText({
 }
 
 const styles = StyleSheet.create({
+  overflowHidden: {
+    overflow: 'hidden',
+  },
+
   outer: {
     padding: 10,
     paddingRight: 15,
diff --git a/src/view/com/onboard/FeatureExplainer.tsx b/src/view/com/onboard/FeatureExplainer.tsx
index 03e050883..d8d502cfb 100644
--- a/src/view/com/onboard/FeatureExplainer.tsx
+++ b/src/view/com/onboard/FeatureExplainer.tsx
@@ -9,13 +9,23 @@ import {
   View,
 } from 'react-native'
 import {TabView, SceneMap, Route, TabBarProps} from 'react-native-tab-view'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {
+  FontAwesomeIcon,
+  FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
 import {Text} from '../util/text/Text'
 import {useStores} from '../../../state'
 import {s} from '../../lib/styles'
 import {TABS_EXPLAINER} from '../../lib/assets'
 import {TABS_ENABLED} from '../../../build-flags'
 
+const ROUTES = TABS_ENABLED
+  ? [
+      {key: 'intro', title: 'Intro'},
+      {key: 'tabs', title: 'Tabs'},
+    ]
+  : [{key: 'intro', title: 'Intro'}]
+
 const Intro = () => (
   <View style={styles.explainer}>
     <Text
@@ -37,7 +47,7 @@ const Tabs = () => (
       <View style={s.flex1} />
       <FontAwesomeIcon
         icon={['far', 'clone']}
-        style={[s.black, s.mb5]}
+        style={[s.black as FontAwesomeIconStyle, s.mb5]}
         size={36}
       />
       <View style={s.flex1} />
@@ -62,14 +72,10 @@ export const FeatureExplainer = () => {
   const layout = useWindowDimensions()
   const store = useStores()
   const [index, setIndex] = useState(0)
-  const routes = [
-    {key: 'intro', title: 'Intro'},
-    TABS_ENABLED ? {key: 'tabs', title: 'Tabs'} : undefined,
-  ].filter(Boolean)
 
   const onPressSkip = () => store.onboard.next()
   const onPressNext = () => {
-    if (index >= routes.length - 1) {
+    if (index >= ROUTES.length - 1) {
       store.onboard.next()
     } else {
       setIndex(index + 1)
@@ -103,12 +109,12 @@ export const FeatureExplainer = () => {
     )
   }
 
-  const FirstExplainer = SCENE_MAP[routes[0]?.key as keyof typeof SCENE_MAP]
+  const FirstExplainer = SCENE_MAP[ROUTES[0]?.key as keyof typeof SCENE_MAP]
   return (
     <SafeAreaView style={styles.container}>
-      {routes.length > 1 ? (
+      {ROUTES.length > 1 ? (
         <TabView
-          navigationState={{index, routes}}
+          navigationState={{index, routes: ROUTES}}
           renderScene={renderScene}
           renderTabBar={renderTabBar}
           onIndexChange={setIndex}
diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx
index 92f7acc03..d39296285 100644
--- a/src/view/com/post-thread/PostThreadItem.tsx
+++ b/src/view/com/post-thread/PostThreadItem.tsx
@@ -3,7 +3,10 @@ import {observer} from 'mobx-react-lite'
 import {StyleSheet, View} from 'react-native'
 import Clipboard from '@react-native-clipboard/clipboard'
 import {AtUri} from '../../../third-party/uri'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {
+  FontAwesomeIcon,
+  FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
 import {PostThreadViewPostModel} from '../../../state/models/post-thread-view'
 import {Link} from '../util/Link'
 import {RichText} from '../util/text/RichText'
@@ -59,7 +62,7 @@ export const PostThreadItem = observer(function PostThreadItem({
       replyTo: {
         uri: item.post.uri,
         cid: item.post.cid,
-        text: record.text as string,
+        text: record?.text as string,
         author: {
           handle: item.post.author.handle,
           displayName: item.post.author.displayName,
@@ -103,7 +106,10 @@ export const PostThreadItem = observer(function PostThreadItem({
   if (deleted) {
     return (
       <View style={[styles.outer, pal.border, pal.view, s.p20, s.flexRow]}>
-        <FontAwesomeIcon icon={['far', 'trash-can']} style={pal.icon} />
+        <FontAwesomeIcon
+          icon={['far', 'trash-can']}
+          style={pal.icon as FontAwesomeIconStyle}
+        />
         <Text style={[pal.textLight, s.ml10]}>This post has been deleted.</Text>
       </View>
     )
diff --git a/src/view/com/post-thread/PostVotedBy.tsx b/src/view/com/post-thread/PostVotedBy.tsx
index f167a3ab7..9fd53da5e 100644
--- a/src/view/com/post-thread/PostVotedBy.tsx
+++ b/src/view/com/post-thread/PostVotedBy.tsx
@@ -1,7 +1,7 @@
 import React, {useEffect} from 'react'
 import {observer} from 'mobx-react-lite'
 import {ActivityIndicator, FlatList, StyleSheet, View} from 'react-native'
-import {VotesViewModel, VotesItem} from '../../../state/models/votes-view'
+import {VotesViewModel, VoteItem} from '../../../state/models/votes-view'
 import {Link} from '../util/Link'
 import {Text} from '../util/text/Text'
 import {ErrorMessage} from '../util/error/ErrorMessage'
@@ -56,7 +56,7 @@ export const PostVotedBy = observer(function PostVotedBy({
 
   // loaded
   // =
-  const renderItem = ({item}: {item: VotesItem}) => <LikedByItem item={item} />
+  const renderItem = ({item}: {item: VoteItem}) => <LikedByItem item={item} />
   return (
     <FlatList
       data={view.votes}
@@ -76,7 +76,7 @@ export const PostVotedBy = observer(function PostVotedBy({
   )
 })
 
-const LikedByItem = ({item}: {item: VotesItem}) => {
+const LikedByItem = ({item}: {item: VoteItem}) => {
   const pal = usePalette('default')
 
   return (
diff --git a/src/view/com/post/PostText.tsx b/src/view/com/post/PostText.tsx
index 0cdc875a9..a3bcfed68 100644
--- a/src/view/com/post/PostText.tsx
+++ b/src/view/com/post/PostText.tsx
@@ -1,6 +1,6 @@
 import React, {useState, useEffect} from 'react'
 import {observer} from 'mobx-react-lite'
-import {StyleSheet, View} from 'react-native'
+import {StyleProp, StyleSheet, TextStyle, View} from 'react-native'
 import {LoadingPlaceholder} from '../util/LoadingPlaceholder'
 import {ErrorMessage} from '../util/error/ErrorMessage'
 import {Text} from '../util/text/Text'
@@ -12,7 +12,7 @@ export const PostText = observer(function PostText({
   style,
 }: {
   uri: string
-  style?: StyleProp
+  style?: StyleProp<TextStyle>
 }) {
   const store = useStores()
   const [model, setModel] = useState<PostModel | undefined>()
diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx
index 584fa0973..cda2ac0b0 100644
--- a/src/view/com/posts/FeedItem.tsx
+++ b/src/view/com/posts/FeedItem.tsx
@@ -4,7 +4,10 @@ import {StyleSheet, View} from 'react-native'
 import Clipboard from '@react-native-clipboard/clipboard'
 import Svg, {Circle, Line} from 'react-native-svg'
 import {AtUri} from '../../../third-party/uri'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {
+  FontAwesomeIcon,
+  FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
 import {FeedItemModel} from '../../../state/models/feed-view'
 import {Link} from '../util/Link'
 import {Text} from '../util/text/Text'
@@ -137,7 +140,10 @@ export const FeedItem = observer(function ({
             }>
             <FontAwesomeIcon
               icon="retweet"
-              style={[styles.includeReasonIcon, {color: pal.colors.textLight}]}
+              style={[
+                styles.includeReasonIcon,
+                {color: pal.colors.textLight} as FontAwesomeIconStyle,
+              ]}
             />
             <Text type="sm-bold" style={pal.textLight}>
               Reposted by{' '}
@@ -167,7 +173,10 @@ export const FeedItem = observer(function ({
                 <FontAwesomeIcon
                   icon="reply"
                   size={9}
-                  style={[{color: pal.colors.textLight}, s.mr5]}
+                  style={[
+                    {color: pal.colors.textLight} as FontAwesomeIconStyle,
+                    s.mr5,
+                  ]}
                 />
                 <Text type="md" style={[pal.textLight, s.mr2]}>
                   Reply to
diff --git a/src/view/com/profile/ProfileFollows.tsx b/src/view/com/profile/ProfileFollows.tsx
index 2e67873c8..bd7e7a3ce 100644
--- a/src/view/com/profile/ProfileFollows.tsx
+++ b/src/view/com/profile/ProfileFollows.tsx
@@ -97,7 +97,11 @@ const User = ({item}: {item: FollowItem}) => {
             size={40}
             displayName={item.displayName}
             handle={item.handle}
-            avatar={item.avatar}
+            avatar={
+              item.avatar as
+                | string
+                | undefined /* HACK: type signature is wrong in the api */
+            }
           />
         </View>
         <View style={styles.layoutContent}>
diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx
index 2f98fce2d..d0cf49769 100644
--- a/src/view/com/profile/ProfileHeader.tsx
+++ b/src/view/com/profile/ProfileHeader.tsx
@@ -8,7 +8,10 @@ import {
   View,
 } from 'react-native'
 import LinearGradient from 'react-native-linear-gradient'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {
+  FontAwesomeIcon,
+  FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
 import {BlurView} from '@react-native-community/blur'
 import {ProfileViewModel} from '../../../state/models/profile-view'
 import {useStores} from '../../../state'
@@ -142,7 +145,7 @@ export const ProfileHeader = observer(function ProfileHeader({
   }
   return (
     <View style={pal.view}>
-      <UserBanner handle={view.handle} banner={view.banner} />
+      <UserBanner banner={view.banner} />
       <View style={styles.content}>
         <View style={[styles.buttonsLine]}>
           {isMe ? (
@@ -181,7 +184,10 @@ export const ProfileHeader = observer(function ProfileHeader({
                     start={{x: 0, y: 0}}
                     end={{x: 1, y: 1}}
                     style={[styles.btn, styles.gradientBtn]}>
-                    <FontAwesomeIcon icon="plus" style={[s.white, s.mr5]} />
+                    <FontAwesomeIcon
+                      icon="plus"
+                      style={[s.white as FontAwesomeIconStyle, s.mr5]}
+                    />
                     <Text type="button" style={[s.white, s.bold]}>
                       Follow
                     </Text>
diff --git a/src/view/com/util/EmptyState.tsx b/src/view/com/util/EmptyState.tsx
index 6218027d2..6c5c3f342 100644
--- a/src/view/com/util/EmptyState.tsx
+++ b/src/view/com/util/EmptyState.tsx
@@ -1,7 +1,10 @@
 import React from 'react'
 import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
 import {IconProp} from '@fortawesome/fontawesome-svg-core'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {
+  FontAwesomeIcon,
+  FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
 import {Text} from './text/Text'
 import {UserGroupIcon} from '../../lib/icons'
 import {usePalette} from '../../lib/hooks/usePalette'
@@ -25,7 +28,10 @@ export function EmptyState({
           <FontAwesomeIcon
             icon={icon}
             size={64}
-            style={[styles.icon, {color: pal.colors.emptyStateIcon}]}
+            style={[
+              styles.icon,
+              {color: pal.colors.emptyStateIcon} as FontAwesomeIconStyle,
+            ]}
           />
         )}
       </View>
diff --git a/src/view/com/util/LoadingPlaceholder.tsx b/src/view/com/util/LoadingPlaceholder.tsx
index 9828058e8..9bb200d50 100644
--- a/src/view/com/util/LoadingPlaceholder.tsx
+++ b/src/view/com/util/LoadingPlaceholder.tsx
@@ -63,7 +63,7 @@ export function PostLoadingPlaceholder({
           </View>
           <View style={s.flex1}>
             <HeartIcon
-              style={{color: theme.palette.default.icon}}
+              style={{color: theme.palette.default.icon} as ViewStyle}
               size={17}
               strokeWidth={1.7}
             />
diff --git a/src/view/com/util/PostCtrls.tsx b/src/view/com/util/PostCtrls.tsx
index bde44abab..fca70b687 100644
--- a/src/view/com/util/PostCtrls.tsx
+++ b/src/view/com/util/PostCtrls.tsx
@@ -7,7 +7,10 @@ import {
   View,
   ViewStyle,
 } from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {
+  FontAwesomeIcon,
+  FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
 import ReactNativeHapticFeedback from 'react-native-haptic-feedback'
 import {Text} from './text/Text'
 import {PostDropdownBtn} from './forms/DropdownButton'
@@ -147,7 +150,9 @@ export function PostCtrls(opts: PostCtrlsOpts) {
           <Animated.View style={anim1Style}>
             <RepostIcon
               style={
-                opts.isReposted ? styles.ctrlIconReposted : defaultCtrlColor
+                (opts.isReposted
+                  ? styles.ctrlIconReposted
+                  : defaultCtrlColor) as ViewStyle
               }
               strokeWidth={2.4}
               size={opts.big ? 24 : 20}
@@ -173,12 +178,15 @@ export function PostCtrls(opts: PostCtrlsOpts) {
           <Animated.View style={anim2Style}>
             {opts.isUpvoted ? (
               <HeartIconSolid
-                style={[styles.ctrlIconUpvoted]}
+                style={styles.ctrlIconUpvoted as ViewStyle}
                 size={opts.big ? 22 : 16}
               />
             ) : (
               <HeartIcon
-                style={[defaultCtrlColor, opts.big ? styles.mt1 : undefined]}
+                style={[
+                  defaultCtrlColor as ViewStyle,
+                  opts.big ? styles.mt1 : undefined,
+                ]}
                 strokeWidth={3}
                 size={opts.big ? 20 : 16}
               />
@@ -214,7 +222,7 @@ export function PostCtrls(opts: PostCtrlsOpts) {
                 {
                   color:
                     theme.colorScheme === 'light' ? colors.gray4 : colors.gray5,
-                },
+                } as FontAwesomeIconStyle,
               ]}
             />
           </PostDropdownBtn>
diff --git a/src/view/com/util/ViewHeader.tsx b/src/view/com/util/ViewHeader.tsx
index c8b1b2d97..472db7ee0 100644
--- a/src/view/com/util/ViewHeader.tsx
+++ b/src/view/com/util/ViewHeader.tsx
@@ -6,7 +6,10 @@ import {
   TouchableOpacity,
   View,
 } from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {
+  FontAwesomeIcon,
+  FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
 import {UserAvatar} from './UserAvatar'
 import {Text} from './text/Text'
 import {MagnifyingGlassIcon} from '../../lib/icons'
@@ -92,7 +95,11 @@ export const ViewHeader = observer(function ViewHeader({
             <ActivityIndicator />
           ) : (
             <>
-              <FontAwesomeIcon icon="signal" style={pal.text} size={16} />
+              <FontAwesomeIcon
+                icon="signal"
+                style={pal.text as FontAwesomeIconStyle}
+                size={16}
+              />
               <FontAwesomeIcon
                 icon="x"
                 style={[
diff --git a/src/view/com/util/error/ErrorMessage.tsx b/src/view/com/util/error/ErrorMessage.tsx
index 684e93fca..a6d77326e 100644
--- a/src/view/com/util/error/ErrorMessage.tsx
+++ b/src/view/com/util/error/ErrorMessage.tsx
@@ -6,7 +6,10 @@ import {
   View,
   ViewStyle,
 } from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {
+  FontAwesomeIcon,
+  FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
 import {Text} from '../text/Text'
 import {useTheme} from '../../../lib/ThemeContext'
 import {usePalette} from '../../../lib/hooks/usePalette'
@@ -28,7 +31,11 @@ export function ErrorMessage({
     <View testID="errorMessageView" style={[styles.outer, pal.view, style]}>
       <View
         style={[styles.errorIcon, {backgroundColor: theme.palette.error.icon}]}>
-        <FontAwesomeIcon icon="exclamation" style={pal.text} size={16} />
+        <FontAwesomeIcon
+          icon="exclamation"
+          style={pal.text as FontAwesomeIconStyle}
+          size={16}
+        />
       </View>
       <Text
         type="sm"
diff --git a/src/view/com/util/error/ErrorScreen.tsx b/src/view/com/util/error/ErrorScreen.tsx
index 0500b206d..f316dbcc6 100644
--- a/src/view/com/util/error/ErrorScreen.tsx
+++ b/src/view/com/util/error/ErrorScreen.tsx
@@ -1,6 +1,9 @@
 import React from 'react'
 import {StyleSheet, TouchableOpacity, View} from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {
+  FontAwesomeIcon,
+  FontAwesomeIconStyle,
+} from '@fortawesome/react-native-fontawesome'
 import {Text} from '../text/Text'
 import {colors} from '../../../lib/styles'
 import {useTheme} from '../../../lib/ThemeContext'
@@ -58,7 +61,11 @@ export function ErrorScreen({
             testID="errorScreenTryAgainButton"
             style={[styles.btn, {backgroundColor: theme.palette.error.icon}]}
             onPress={onPressTryAgain}>
-            <FontAwesomeIcon icon="arrows-rotate" style={pal.text} size={16} />
+            <FontAwesomeIcon
+              icon="arrows-rotate"
+              style={pal.text as FontAwesomeIconStyle}
+              size={16}
+            />
             <Text type="button" style={[styles.btnText, pal.text]}>
               Try again
             </Text>
diff --git a/src/view/com/util/forms/DropdownButton.tsx b/src/view/com/util/forms/DropdownButton.tsx
index 33387f894..1fa03f4c7 100644
--- a/src/view/com/util/forms/DropdownButton.tsx
+++ b/src/view/com/util/forms/DropdownButton.tsx
@@ -37,7 +37,7 @@ export function DropdownButton({
   menuWidth,
   children,
 }: {
-  type: DropdownButtonType
+  type?: DropdownButtonType
   style?: StyleProp<ViewStyle>
   items: DropdownItem[]
   label?: string
diff --git a/src/view/com/util/images/AutoSizedImage.tsx b/src/view/com/util/images/AutoSizedImage.tsx
index cedd3bc90..cdefc7123 100644
--- a/src/view/com/util/images/AutoSizedImage.tsx
+++ b/src/view/com/util/images/AutoSizedImage.tsx
@@ -30,6 +30,7 @@ export function AutoSizedImage({
 }: {
   uri: string
   onPress?: () => void
+  onLongPress?: () => void
   style?: StyleProp<ImageStyle>
   containerStyle?: StyleProp<ViewStyle>
 }) {
@@ -68,7 +69,7 @@ export function AutoSizedImage({
     })
   }
 
-  let calculatedStyle: StyleProp<ViewStyle> | undefined
+  let calculatedStyle: StyleProp<ImageStyle> | undefined
   if (imgInfo && containerInfo) {
     // imgInfo.height / imgInfo.width = x / containerInfo.width
     // x = imgInfo.height / imgInfo.width * containerInfo.width
diff --git a/src/view/com/util/images/ImageLayoutGrid.tsx b/src/view/com/util/images/ImageLayoutGrid.tsx
index dd0ea3775..97ad9d700 100644
--- a/src/view/com/util/images/ImageLayoutGrid.tsx
+++ b/src/view/com/util/images/ImageLayoutGrid.tsx
@@ -13,7 +13,7 @@ import {DELAY_PRESS_IN} from './constants'
 
 interface Dim {
   width: number
-  height: numberPressIn
+  height: number
 }
 
 export type ImageLayoutGridType = 'two' | 'three' | 'four'
@@ -28,6 +28,7 @@ export function ImageLayoutGrid({
   type: ImageLayoutGridType
   uris: string[]
   onPress?: (index: number) => void
+  onLongPress?: (index: number) => void
   style?: StyleProp<ViewStyle>
 }) {
   const [containerInfo, setContainerInfo] = React.useState<Dim | undefined>()
@@ -64,6 +65,7 @@ function ImageLayoutGridInner({
   type: ImageLayoutGridType
   uris: string[]
   onPress?: (index: number) => void
+  onLongPress?: (index: number) => void
   containerInfo: Dim
 }) {
   const size1 = React.useMemo<ImageStyle>(() => {
@@ -91,14 +93,14 @@ function ImageLayoutGridInner({
         <TouchableOpacity
           delayPressIn={DELAY_PRESS_IN}
           onPress={() => onPress?.(0)}
-          onLongPress={() => onLongPress(0)}>
+          onLongPress={() => onLongPress?.(0)}>
           <Image source={{uri: uris[0]}} style={size1} />
         </TouchableOpacity>
         <View style={styles.wSpace} />
         <TouchableOpacity
           delayPressIn={DELAY_PRESS_IN}
           onPress={() => onPress?.(1)}
-          onLongPress={() => onLongPress(1)}>
+          onLongPress={() => onLongPress?.(1)}>
           <Image source={{uri: uris[1]}} style={size1} />
         </TouchableOpacity>
       </View>
@@ -110,7 +112,7 @@ function ImageLayoutGridInner({
         <TouchableOpacity
           delayPressIn={DELAY_PRESS_IN}
           onPress={() => onPress?.(0)}
-          onLongPress={() => onLongPress(0)}>
+          onLongPress={() => onLongPress?.(0)}>
           <Image source={{uri: uris[0]}} style={size2} />
         </TouchableOpacity>
         <View style={styles.wSpace} />
@@ -118,14 +120,14 @@ function ImageLayoutGridInner({
           <TouchableOpacity
             delayPressIn={DELAY_PRESS_IN}
             onPress={() => onPress?.(1)}
-            onLongPress={() => onLongPress(1)}>
+            onLongPress={() => onLongPress?.(1)}>
             <Image source={{uri: uris[1]}} style={size1} />
           </TouchableOpacity>
           <View style={styles.hSpace} />
           <TouchableOpacity
             delayPressIn={DELAY_PRESS_IN}
             onPress={() => onPress?.(2)}
-            onLongPress={() => onLongPress(2)}>
+            onLongPress={() => onLongPress?.(2)}>
             <Image source={{uri: uris[2]}} style={size1} />
           </TouchableOpacity>
         </View>
@@ -139,14 +141,14 @@ function ImageLayoutGridInner({
           <TouchableOpacity
             delayPressIn={DELAY_PRESS_IN}
             onPress={() => onPress?.(0)}
-            onLongPress={() => onLongPress(0)}>
+            onLongPress={() => onLongPress?.(0)}>
             <Image source={{uri: uris[0]}} style={size1} />
           </TouchableOpacity>
           <View style={styles.hSpace} />
           <TouchableOpacity
             delayPressIn={DELAY_PRESS_IN}
             onPress={() => onPress?.(1)}
-            onLongPress={() => onLongPress(1)}>
+            onLongPress={() => onLongPress?.(1)}>
             <Image source={{uri: uris[1]}} style={size1} />
           </TouchableOpacity>
         </View>
@@ -155,14 +157,14 @@ function ImageLayoutGridInner({
           <TouchableOpacity
             delayPressIn={DELAY_PRESS_IN}
             onPress={() => onPress?.(2)}
-            onLongPress={() => onLongPress(2)}>
+            onLongPress={() => onLongPress?.(2)}>
             <Image source={{uri: uris[2]}} style={size1} />
           </TouchableOpacity>
           <View style={styles.hSpace} />
           <TouchableOpacity
             delayPressIn={DELAY_PRESS_IN}
             onPress={() => onPress?.(3)}
-            onLongPress={() => onLongPress(3)}>
+            onLongPress={() => onLongPress?.(3)}>
             <Image source={{uri: uris[3]}} style={size1} />
           </TouchableOpacity>
         </View>
diff --git a/src/view/lib/icons.tsx b/src/view/lib/icons.tsx
index bfcbb26bd..f4224ea20 100644
--- a/src/view/lib/icons.tsx
+++ b/src/view/lib/icons.tsx
@@ -1,5 +1,5 @@
 import React from 'react'
-import {StyleProp, ViewStyle} from 'react-native'
+import {StyleProp, TextStyle, ViewStyle} from 'react-native'
 import Svg, {Path} from 'react-native-svg'
 
 export function GridIcon({
@@ -428,12 +428,21 @@ export function CommentBottomArrow({
   size?: string | number
   strokeWidth?: number
 }) {
+  let color = 'currentColor'
+  if (
+    style &&
+    typeof style === 'object' &&
+    'color' in style &&
+    typeof style.color === 'string'
+  ) {
+    color = style.color
+  }
   return (
     <Svg
       fill="none"
       viewBox="0 0 24 24"
       strokeWidth={strokeWidth || 2.5}
-      stroke={style?.color || 'currentColor'}
+      stroke={color}
       width={size || 24}
       height={size || 24}
       style={style}>
diff --git a/src/view/routes.ts b/src/view/routes.ts
index b5cc014ff..98e8111b3 100644
--- a/src/view/routes.ts
+++ b/src/view/routes.ts
@@ -21,7 +21,7 @@ export type ScreenParams = {
   navIdx: string
   params: Record<string, any>
   visible: boolean
-  scrollElRef?: MutableRefObject<FlatList<any> | undefined>
+  scrollElRef?: MutableRefObject<FlatList<any> | null>
 }
 export type Route = [React.FC<ScreenParams>, string, IconProp, RegExp]
 export type MatchResult = {
diff --git a/src/view/screens/Debug.tsx b/src/view/screens/Debug.tsx
index 865f62dc6..0223e631d 100644
--- a/src/view/screens/Debug.tsx
+++ b/src/view/screens/Debug.tsx
@@ -5,14 +5,13 @@ import {ThemeProvider} from '../lib/ThemeContext'
 import {PaletteColorName} from '../lib/ThemeContext'
 import {usePalette} from '../lib/hooks/usePalette'
 import {s} from '../lib/styles'
-import {DEF_AVATAR} from '../lib/assets'
 import {displayNotification} from '../lib/notifee'
 
 import {Text} from '../com/util/text/Text'
 import {ViewSelector} from '../com/util/ViewSelector'
 import {EmptyState} from '../com/util/EmptyState'
 import * as LoadingPlaceholder from '../com/util/LoadingPlaceholder'
-import {Button} from '../com/util/forms/Button'
+import {Button, ButtonType} from '../com/util/forms/Button'
 import {DropdownButton, DropdownItem} from '../com/util/forms/DropdownButton'
 import {ToggleButton} from '../com/util/forms/ToggleButton'
 import {RadioGroup} from '../com/util/forms/RadioGroup'
@@ -48,9 +47,9 @@ function DebugInner({
   const [currentView, setCurrentView] = React.useState<number>(0)
   const pal = usePalette('default')
 
-  const renderItem = (item, i) => {
+  const renderItem = (item: any) => {
     return (
-      <View key={`view-${i}`}>
+      <View key={`view-${item.currentView}`}>
         <View style={[s.pt10, s.pl10, s.pr10]}>
           <ToggleButton
             type="default-light"
@@ -179,18 +178,10 @@ function NotifsView() {
       "Hello world! This is a test of the notifications card. The text is long to see how that's handled.",
     )
   }
-  const triggerImg = () => {
-    displayNotification(
-      'Paul Frazee liked your post',
-      "Hello world! This is a test of the notifications card. The text is long to see how that's handled.",
-      DEF_AVATAR,
-    )
-  }
   return (
     <View style={s.p10}>
       <View style={s.flexRow}>
         <Button onPress={trigger} label="Trigger" />
-        <Button onPress={triggerImg} label="Trigger w/image" style={s.ml5} />
       </View>
     </View>
   )
@@ -484,14 +475,14 @@ const RADIO_BUTTON_ITEMS = [
 ]
 function RadioButtonsView() {
   const defaultPal = usePalette('default')
-  const [rgType, setRgType] = React.useState('default-light')
+  const [rgType, setRgType] = React.useState<ButtonType>('default-light')
   return (
     <View style={[defaultPal.view]}>
       <RadioGroup
         type={rgType}
         items={RADIO_BUTTON_ITEMS}
         initialSelection="default-light"
-        onSelect={setRgType}
+        onSelect={v => setRgType(v as ButtonType)}
       />
     </View>
   )
diff --git a/src/view/shell/desktop-web/left-column.tsx b/src/view/shell/desktop-web/left-column.tsx
index fabb8bc94..3ce6c2eca 100644
--- a/src/view/shell/desktop-web/left-column.tsx
+++ b/src/view/shell/desktop-web/left-column.tsx
@@ -1,55 +1,57 @@
 import React from 'react'
-import {Pressable, View, StyleSheet} from 'react-native'
+import {View} from 'react-native'
 
-export const NavItem: React.FC<{label: string; screen: string}> = ({
-  label,
-  screen,
-}) => {
-  const Link = <></> // TODO
-  return (
-    <View>
-      <Pressable
-        style={state => [
-          // @ts-ignore it does exist! (react-native-web) -prf
-          state.hovered && styles.navItemHovered,
-        ]}>
-        <Link
-          style={[
-            styles.navItemLink,
-            false /* TODO route.name === screen*/ && styles.navItemLinkSelected,
-          ]}
-          to={{screen, params: {}}}>
-          {label}
-        </Link>
-      </Pressable>
-    </View>
-  )
-}
+// export const NavItem: React.FC<{label: string; screen: string}> = ({
+//   label,
+//   screen,
+// }) => {
+//   const Link = <></> // TODO
+//   return (
+//     <View>
+//       <Pressable
+//         style={state => [
+//           // @ts-ignore it does exist! (react-native-web) -prf
+//           state.hovered && styles.navItemHovered,
+//         ]}>
+//         <Link
+//           style={[
+//             styles.navItemLink,
+//             false /* TODO route.name === screen*/ && styles.navItemLinkSelected,
+//           ]}
+//           to={{screen, params: {}}}>
+//           {label}
+//         </Link>
+//       </Pressable>
+//     </View>
+//   )
+// }
 
 export const DesktopLeftColumn: React.FC = () => {
-  return (
-    <View style={styles.container}>
-      <NavItem screen="Home" label="Home" />
-      <NavItem screen="Search" label="Search" />
-      <NavItem screen="Notifications" label="Notifications" />
-    </View>
-  )
+  // TODO
+  return <View />
+  // return (
+  //   <View style={styles.container}>
+  //     <NavItem screen="Home" label="Home" />
+  //     <NavItem screen="Search" label="Search" />
+  //     <NavItem screen="Notifications" label="Notifications" />
+  //   </View>
+  // )
 }
 
-const styles = StyleSheet.create({
-  container: {
-    position: 'absolute',
-    left: 'calc(50vw - 500px)',
-    width: '200px',
-    height: '100%',
-  },
-  navItemHovered: {
-    backgroundColor: 'gray',
-  },
-  navItemLink: {
-    padding: '1rem',
-  },
-  navItemLinkSelected: {
-    color: 'blue',
-  },
-})
+// const styles = StyleSheet.create({
+//   container: {
+//     position: 'absolute',
+//     left: 'calc(50vw - 500px)',
+//     width: '200px',
+//     height: '100%',
+//   },
+//   navItemHovered: {
+//     backgroundColor: 'gray',
+//   },
+//   navItemLink: {
+//     padding: '1rem',
+//   },
+//   navItemLinkSelected: {
+//     color: 'blue',
+//   },
+// })
diff --git a/src/view/shell/mobile/TabsSelector.tsx b/src/view/shell/mobile/TabsSelector.tsx
index 433471602..921a0c85b 100644
--- a/src/view/shell/mobile/TabsSelector.tsx
+++ b/src/view/shell/mobile/TabsSelector.tsx
@@ -36,11 +36,12 @@ export const TabsSelector = observer(
       undefined,
     )
     const closeInterp = useAnimatedValue(0)
+    const tabsContainerRef = useRef<View>(null)
     const tabsRef = useRef<ScrollView>(null)
     const tabRefs = useMemo(
       () =>
         Array.from({length: store.nav.tabs.length}).map(() =>
-          createRef<Animated.View>(),
+          createRef<View>(),
         ),
       [store.nav.tabs.length],
     )
@@ -90,9 +91,9 @@ export const TabsSelector = observer(
     const onLayout = () => {
       // focus the current tab
       const targetTab = tabRefs[store.nav.tabIndex]
-      if (tabsRef.current && targetTab.current) {
+      if (tabsContainerRef.current && tabsRef.current && targetTab.current) {
         targetTab.current.measureLayout?.(
-          tabsRef.current,
+          tabsContainerRef.current,
           (_left: number, top: number) => {
             tabsRef.current?.scrollTo({y: top, animated: false})
           },
@@ -162,7 +163,9 @@ export const TabsSelector = observer(
               </TouchableWithoutFeedback>
             </View>
           </View>
-          <View style={[s.p10, styles.section, styles.sectionGrayBg]}>
+          <View
+            ref={tabsContainerRef}
+            style={[s.p10, styles.section, styles.sectionGrayBg]}>
             <ScrollView ref={tabsRef} style={styles.tabs}>
               {store.nav.tabs.map((tab, tabIndex) => {
                 const {icon} = match(tab.current.url)
diff --git a/src/view/shell/mobile/index.tsx b/src/view/shell/mobile/index.tsx
index 62ab7a2ad..b0b83b12e 100644
--- a/src/view/shell/mobile/index.tsx
+++ b/src/view/shell/mobile/index.tsx
@@ -67,29 +67,36 @@ const Btn = ({
   onLongPress?: (event: GestureResponderEvent) => void
 }) => {
   const pal = usePalette('default')
-  let size = 24
-  let addedStyles
-  let IconEl
+  let iconEl
   if (icon === 'menu') {
-    IconEl = GridIcon
+    iconEl = <GridIcon style={[styles.ctrlIcon, pal.text]} />
   } else if (icon === 'menu-solid') {
-    IconEl = GridIconSolid
+    iconEl = <GridIconSolid style={[styles.ctrlIcon, pal.text]} />
   } else if (icon === 'home') {
-    IconEl = HomeIcon
-    size = 27
+    iconEl = <HomeIcon size={27} style={[styles.ctrlIcon, pal.text]} />
   } else if (icon === 'home-solid') {
-    IconEl = HomeIconSolid
-    size = 27
+    iconEl = <HomeIconSolid size={27} style={[styles.ctrlIcon, pal.text]} />
   } else if (icon === 'bell') {
-    IconEl = BellIcon
-    size = 27
-    addedStyles = {position: 'relative', top: -1} as ViewStyle
+    const addedStyles = {position: 'relative', top: -1} as ViewStyle
+    iconEl = (
+      <BellIcon size={27} style={[styles.ctrlIcon, pal.text, addedStyles]} />
+    )
   } else if (icon === 'bell-solid') {
-    IconEl = BellIconSolid
-    size = 27
-    addedStyles = {position: 'relative', top: -1} as ViewStyle
+    const addedStyles = {position: 'relative', top: -1} as ViewStyle
+    iconEl = (
+      <BellIconSolid
+        size={27}
+        style={[styles.ctrlIcon, pal.text, addedStyles]}
+      />
+    )
   } else {
-    IconEl = FontAwesomeIcon
+    iconEl = (
+      <FontAwesomeIcon
+        size={24}
+        icon={icon}
+        style={[styles.ctrlIcon, pal.text]}
+      />
+    )
   }
 
   return (
@@ -108,11 +115,7 @@ const Btn = ({
           <Text style={styles.tabCountLabel}>{tabCount}</Text>
         </View>
       ) : undefined}
-      <IconEl
-        size={size}
-        style={[styles.ctrlIcon, pal.text, addedStyles]}
-        icon={icon}
-      />
+      {iconEl}
     </TouchableOpacity>
   )
 }
@@ -122,7 +125,7 @@ export const MobileShell: React.FC = observer(() => {
   const pal = usePalette('default')
   const store = useStores()
   const [isTabsSelectorActive, setTabsSelectorActive] = useState(false)
-  const scrollElRef = useRef<FlatList | undefined>()
+  const scrollElRef = useRef<FlatList>(null)
   const winDim = useWindowDimensions()
   const [menuSwipingDirection, setMenuSwipingDirection] = useState(0)
   const swipeGestureInterp = useAnimatedValue(0)
@@ -292,9 +295,11 @@ export const MobileShell: React.FC = observer(() => {
     )
     shouldRenderMenu = true
   }
-  const menuSwipeTransform = {
-    transform: [{translateX: menuTranslateX}],
-  }
+  const menuSwipeTransform = menuTranslateX
+    ? {
+        transform: [{translateX: menuTranslateX}],
+      }
+    : undefined
   const swipeOpacity = {
     opacity: swipeGestureInterp.interpolate({
       inputRange: [-1, 0, 1],
@@ -417,10 +422,7 @@ export const MobileShell: React.FC = observer(() => {
           ) : undefined}
           {shouldRenderMenu && (
             <Animated.View style={[styles.menuDrawer, menuSwipeTransform]}>
-              <Menu
-                visible={isMenuActive}
-                onClose={() => store.shell.setMainMenuOpen(false)}
-              />
+              <Menu onClose={() => store.shell.setMainMenuOpen(false)} />
             </Animated.View>
           )}
         </HorzSwipe>