diff --git a/package.json b/package.json
index 93363c354e..add0e37ce9 100644
--- a/package.json
+++ b/package.json
@@ -34,6 +34,7 @@
"mobx-react-lite": "^3.4.0",
"moment": "^2.29.4",
"react": "17.0.2",
+ "react-circular-progressbar": "^2.1.0",
"react-dom": "17.0.2",
"react-native": "0.68.2",
"react-native-gesture-handler": "^2.5.0",
diff --git a/public/index.html b/public/index.html
index f6cb612b6d..54fb90eead 100644
--- a/public/index.html
+++ b/public/index.html
@@ -11,6 +11,45 @@
body { overflow: hidden; }
/* These styles make the root element full-height */
#root { display:flex; height:100%; }
+
+ /* These styles are for src/view/com/modals/WebModal */
+ div[data-modal-overlay] {
+ position: fixed;
+ top: 0;
+ left: 0;
+ background: #0004;
+ width: 100vw;
+ height: 100vh;
+ }
+ div[data-modal-container] {
+ position: fixed;
+ top: 20vh;
+ left: calc(50vw - 300px);
+ width: 600px;
+ padding: 20px;
+ background: #fff;
+ border-radius: 10px;
+ box-shadow: 0 5px 10px #0005;
+ }
+
+ /* These styles are for src/view/com/util/Toast */
+ div[data-toast-container] {
+ position: fixed;
+ bottom: 5vh;
+ right: 5vh;
+ width: 350px;
+ padding: 20px;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ background: #fff;
+ border-radius: 10px;
+ box-shadow: 0 5px 10px #0005;
+ }
+ div[data-toast-container] > div {
+ font-size: 18px;
+ margin-left: 10px;
+ }
diff --git a/src/App.web.tsx b/src/App.web.tsx
index 838b81ee28..9a6fedd5a7 100644
--- a/src/App.web.tsx
+++ b/src/App.web.tsx
@@ -1,9 +1,8 @@
import React, {useState, useEffect} from 'react'
-import {RootSiblingParent} from 'react-native-root-siblings'
-import {GestureHandlerRootView} from 'react-native-gesture-handler'
import * as view from './view/index'
import {RootStoreModel, setupState, RootStoreProvider} from './state'
import * as Routes from './view/routes'
+import Toast from './view/com/util/Toast'
function App() {
const [rootStore, setRootStore] = useState(
@@ -22,13 +21,10 @@ function App() {
}
return (
-
-
-
-
-
-
-
+
+
+
+
)
}
diff --git a/src/state/lib/api.ts b/src/state/lib/api.ts
index bb3ef5d1ad..df0047991d 100644
--- a/src/state/lib/api.ts
+++ b/src/state/lib/api.ts
@@ -97,7 +97,7 @@ export async function unrepost(adx: AdxClient, user: string, uri: string) {
return numDels > 0
}
-type WherePred = (record: GetRecordResponseValidated) => Boolean
+type WherePred = (_record: GetRecordResponseValidated) => Boolean
async function deleteWhere(
coll: AdxRepoCollectionClient,
schema: SchemaOpt,
@@ -115,7 +115,7 @@ async function deleteWhere(
return toDelete.length
}
-type IterateAllCb = (record: GetRecordResponseValidated) => void
+type IterateAllCb = (_record: GetRecordResponseValidated) => void
async function iterateAll(
coll: AdxRepoCollectionClient,
schema: SchemaOpt,
diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx
index c7ce3f4c7d..57dc0ef865 100644
--- a/src/view/com/composer/Composer.tsx
+++ b/src/view/com/composer/Composer.tsx
@@ -1,9 +1,8 @@
import React, {useState, forwardRef, useImperativeHandle} from 'react'
import {observer} from 'mobx-react-lite'
import {KeyboardAvoidingView, StyleSheet, TextInput, View} from 'react-native'
-import Toast from 'react-native-root-toast'
-// @ts-ignore no type definition -prf
-import ProgressCircle from 'react-native-progress/Circle'
+import Toast from '../util/Toast'
+import ProgressCircle from '../util/ProgressCircle'
import {useStores} from '../../../state'
import {s} from '../../lib/styles'
import * as apilib from '../../../state/lib/api'
@@ -12,75 +11,71 @@ const MAX_TEXT_LENGTH = 256
const WARNING_TEXT_LENGTH = 200
const DANGER_TEXT_LENGTH = 255
-export const Composer = observer(
- forwardRef(function Composer(
- {
- replyTo,
- }: {
- replyTo: string | undefined
- },
- ref,
- ) {
- const store = useStores()
- const [text, setText] = useState('')
+export const Composer = forwardRef(function Composer(
+ {
+ replyTo,
+ }: {
+ replyTo: string | undefined
+ },
+ ref,
+) {
+ const store = useStores()
+ const [text, setText] = useState('')
- const onChangeText = (newText: string) => {
- if (newText.length > MAX_TEXT_LENGTH) {
- setText(newText.slice(0, MAX_TEXT_LENGTH))
- } else {
- setText(newText)
- }
+ const onChangeText = (newText: string) => {
+ if (newText.length > MAX_TEXT_LENGTH) {
+ setText(newText.slice(0, MAX_TEXT_LENGTH))
+ } else {
+ setText(newText)
}
+ }
- useImperativeHandle(ref, () => ({
- async publish() {
- if (text.trim().length === 0) {
- return false
- }
- await apilib.post(store.api, 'alice.com', text, replyTo)
- Toast.show(`Your ${replyTo ? 'reply' : 'post'} has been created`, {
- duration: Toast.durations.LONG,
- position: Toast.positions.TOP,
- shadow: true,
- animation: true,
- hideOnPress: true,
- })
- return true
- },
- }))
+ useImperativeHandle(ref, () => ({
+ async publish() {
+ if (text.trim().length === 0) {
+ return false
+ }
+ await apilib.post(store.api, 'alice.com', text, replyTo)
+ Toast.show(`Your ${replyTo ? 'reply' : 'post'} has been created`, {
+ duration: Toast.durations.LONG,
+ position: Toast.positions.TOP,
+ shadow: true,
+ animation: true,
+ hideOnPress: true,
+ })
+ return true
+ },
+ }))
- const progressColor =
- text.length > DANGER_TEXT_LENGTH
- ? '#e60000'
- : text.length > WARNING_TEXT_LENGTH
- ? '#f7c600'
- : undefined
+ const progressColor =
+ text.length > DANGER_TEXT_LENGTH
+ ? '#e60000'
+ : text.length > WARNING_TEXT_LENGTH
+ ? '#f7c600'
+ : undefined
- return (
-
- onChangeText(text)}
- value={text}
- placeholder={
- replyTo ? 'Write your reply' : "What's new in the scene?"
- }
- style={styles.textInput}
- />
-
-
-
-
-
+ return (
+
+ onChangeText(text)}
+ value={text}
+ placeholder={replyTo ? 'Write your reply' : "What's new in the scene?"}
+ style={styles.textInput}
+ />
+
+
+
+
-
- )
- }),
-)
+
+
+ )
+})
const styles = StyleSheet.create({
outer: {
diff --git a/src/view/com/feed/Feed.tsx b/src/view/com/feed/Feed.tsx
index 8283e275e8..6787b51aef 100644
--- a/src/view/com/feed/Feed.tsx
+++ b/src/view/com/feed/Feed.tsx
@@ -4,7 +4,7 @@ import {Text, View, FlatList} from 'react-native'
import {OnNavigateContent} from '../../routes/types'
import {FeedViewModel, FeedViewItemModel} from '../../../state/models/feed-view'
import {FeedItem} from './FeedItem'
-import {ShareBottomSheet} from '../sheets/SharePost'
+import {ShareModal} from '../modals/SharePost'
export const Feed = observer(function Feed({
feed,
@@ -13,7 +13,7 @@ export const Feed = observer(function Feed({
feed: FeedViewModel
onNavigateContent: OnNavigateContent
}) {
- const shareSheetRef = useRef<{open: (uri: string) => void}>()
+ const shareSheetRef = useRef<{open: (_uri: string) => void}>()
const onPressShare = (uri: string) => {
shareSheetRef.current?.open(uri)
@@ -52,7 +52,7 @@ export const Feed = observer(function Feed({
/>
)}
{feed.isEmpty && This feed is empty!}
-
+
)
})
diff --git a/src/view/com/feed/FeedItem.tsx b/src/view/com/feed/FeedItem.tsx
index 018b581790..616fb0acae 100644
--- a/src/view/com/feed/FeedItem.tsx
+++ b/src/view/com/feed/FeedItem.tsx
@@ -16,7 +16,7 @@ export const FeedItem = observer(function FeedItem({
}: {
item: FeedViewItemModel
onNavigateContent: OnNavigateContent
- onPressShare: (uri: string) => void
+ onPressShare: (_uri: string) => void
}) {
const record = item.record as unknown as bsky.Post.Record
diff --git a/src/view/com/sheets/SharePost.tsx b/src/view/com/modals/SharePost.native.tsx
similarity index 93%
rename from src/view/com/sheets/SharePost.tsx
rename to src/view/com/modals/SharePost.native.tsx
index b0f22c54e2..0e99bd4d19 100644
--- a/src/view/com/sheets/SharePost.tsx
+++ b/src/view/com/modals/SharePost.native.tsx
@@ -19,14 +19,11 @@ import Animated, {
interpolate,
useAnimatedStyle,
} from 'react-native-reanimated'
-import Toast from 'react-native-root-toast'
+import Toast from '../util/Toast'
import Clipboard from '@react-native-clipboard/clipboard'
import {s} from '../../lib/styles'
-export const ShareBottomSheet = forwardRef(function ShareBottomSheet(
- {}: {},
- ref,
-) {
+export const ShareModal = forwardRef(function ShareModal({}: {}, ref) {
const [isOpen, setIsOpen] = useState(false)
const [uri, setUri] = useState('')
const bottomSheetRef = useRef(null)
@@ -41,6 +38,9 @@ export const ShareBottomSheet = forwardRef(function ShareBottomSheet(
const onPressCopy = () => {
Clipboard.setString(uri)
+ console.log('showing')
+ console.log(Toast)
+ console.log(Toast.show)
Toast.show('Link copied', {
position: Toast.positions.TOP,
})
@@ -56,7 +56,6 @@ export const ShareBottomSheet = forwardRef(function ShareBottomSheet(
}
const CustomBackdrop = ({animatedIndex, style}: BottomSheetBackdropProps) => {
- console.log('hit!', animatedIndex.value)
// animated variables
const opacity = useAnimatedStyle(() => ({
opacity: interpolate(
diff --git a/src/view/com/modals/SharePost.tsx b/src/view/com/modals/SharePost.tsx
new file mode 100644
index 0000000000..d6d4bb5c18
--- /dev/null
+++ b/src/view/com/modals/SharePost.tsx
@@ -0,0 +1,57 @@
+import React, {forwardRef, useState, useImperativeHandle} from 'react'
+import {Button, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
+import {Modal} from './WebModal'
+import Toast from '../util/Toast'
+import {s} from '../../lib/styles'
+
+export const ShareModal = forwardRef(function ShareModal({}: {}, ref) {
+ const [isOpen, setIsOpen] = useState(false)
+ const [uri, setUri] = useState('')
+
+ useImperativeHandle(ref, () => ({
+ open(uri: string) {
+ console.log('sharing', uri)
+ setUri(uri)
+ setIsOpen(true)
+ },
+ }))
+
+ const onPressCopy = () => {
+ // TODO
+ Toast.show('Link copied', {
+ position: Toast.positions.TOP,
+ })
+ }
+ const onClose = () => {
+ setIsOpen(false)
+ }
+
+ return (
+ <>
+ {isOpen && (
+
+
+ Share this post
+ {uri}
+
+
+
+ Close
+
+
+
+
+ )}
+ >
+ )
+})
+
+const styles = StyleSheet.create({
+ closeBtn: {
+ width: '100%',
+ borderColor: '#000',
+ borderWidth: 1,
+ borderRadius: 4,
+ padding: 10,
+ },
+})
diff --git a/src/view/com/modals/WebModal.tsx b/src/view/com/modals/WebModal.tsx
new file mode 100644
index 0000000000..fed2fae91f
--- /dev/null
+++ b/src/view/com/modals/WebModal.tsx
@@ -0,0 +1,20 @@
+/**
+ * Use this for the Web build only.
+ * It's intended to replace the BottomSheet.
+ *
+ * Note: the dataSet properties are used to leverage custom CSS in public/index.html
+ */
+import React from 'react'
+// @ts-ignore no declarations available -prf
+import {TouchableWithoutFeedback, View} from 'react-native-web'
+
+type Props = {onClose: () => void}
+export const Modal: React.FC = ({onClose, children}) => {
+ return (
+
+
+ {children}
+
+
+ )
+}
diff --git a/src/view/com/post-thread/PostThread.tsx b/src/view/com/post-thread/PostThread.tsx
index 784cc39d2c..6191875c7e 100644
--- a/src/view/com/post-thread/PostThread.tsx
+++ b/src/view/com/post-thread/PostThread.tsx
@@ -9,7 +9,7 @@ import {
} from '../../../state/models/post-thread-view'
import {useStores} from '../../../state'
import {PostThreadItem} from './PostThreadItem'
-import {ShareBottomSheet} from '../sheets/SharePost'
+import {ShareModal} from '../modals/SharePost'
import {s} from '../../lib/styles'
const UPDATE_DELAY = 2e3 // wait 2s before refetching the thread for updates
@@ -24,7 +24,7 @@ export const PostThread = observer(function PostThread({
const store = useStores()
const [view, setView] = useState()
const [lastUpdate, setLastUpdate] = useState(Date.now())
- const shareSheetRef = useRef<{open: (uri: string) => void}>()
+ const shareSheetRef = useRef<{open: (_uri: string) => void}>()
useEffect(() => {
if (view?.params.uri === uri) {
@@ -94,7 +94,7 @@ export const PostThread = observer(function PostThread({
refreshing={view.isRefreshing}
onRefresh={onRefresh}
/>
-
+
)
})
diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx
index 30a64bc0e9..7ed00403b9 100644
--- a/src/view/com/post-thread/PostThreadItem.tsx
+++ b/src/view/com/post-thread/PostThreadItem.tsx
@@ -25,7 +25,7 @@ export const PostThreadItem = observer(function PostThreadItem({
}: {
item: PostThreadViewPostModel
onNavigateContent: OnNavigateContent
- onPressShare: (uri: string) => void
+ onPressShare: (_uri: string) => void
}) {
const record = item.record as unknown as bsky.Post.Record
const hasEngagement = item.likeCount || item.repostCount
diff --git a/src/view/com/util/ProgressCircle.native.tsx b/src/view/com/util/ProgressCircle.native.tsx
new file mode 100644
index 0000000000..a09232b4b9
--- /dev/null
+++ b/src/view/com/util/ProgressCircle.native.tsx
@@ -0,0 +1,3 @@
+// @ts-ignore no type definition -prf
+import ProgressCircle from 'react-native-progress/Circle'
+export default ProgressCircle
diff --git a/src/view/com/util/ProgressCircle.tsx b/src/view/com/util/ProgressCircle.tsx
new file mode 100644
index 0000000000..0e425a6e65
--- /dev/null
+++ b/src/view/com/util/ProgressCircle.tsx
@@ -0,0 +1,20 @@
+import {View} from 'react-native'
+import {CircularProgressbar, buildStyles} from 'react-circular-progressbar'
+
+const ProgressCircle = ({
+ color,
+ progress,
+}: {
+ color?: string
+ progress: number
+}) => {
+ return (
+
+
+
+ )
+}
+export default ProgressCircle
diff --git a/src/view/com/util/Toast.native.tsx b/src/view/com/util/Toast.native.tsx
new file mode 100644
index 0000000000..4b9fd7f80d
--- /dev/null
+++ b/src/view/com/util/Toast.native.tsx
@@ -0,0 +1,2 @@
+import Toast from 'react-native-root-toast'
+export default Toast
diff --git a/src/view/com/util/Toast.tsx b/src/view/com/util/Toast.tsx
new file mode 100644
index 0000000000..1726b71b3f
--- /dev/null
+++ b/src/view/com/util/Toast.tsx
@@ -0,0 +1,62 @@
+/*
+ * Note: the dataSet properties are used to leverage custom CSS in public/index.html
+ */
+
+import React, {useState, useEffect} from 'react'
+// @ts-ignore no declarations available -prf
+import {Text, View} from 'react-native-web'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+
+interface ActiveToast {
+ text: string
+}
+type GlobalSetActiveToast = (_activeToast: ActiveToast | undefined) => void
+
+// globals
+// =
+let globalSetActiveToast: GlobalSetActiveToast | undefined
+let toastTimeout: NodeJS.Timeout | undefined
+
+// components
+// =
+type ToastContainerProps = {}
+const ToastContainer: React.FC = ({}) => {
+ const [activeToast, setActiveToast] = useState()
+ useEffect(() => {
+ globalSetActiveToast = (t: ActiveToast | undefined) => {
+ setActiveToast(t)
+ }
+ })
+ return (
+ <>
+ {activeToast && (
+
+
+ {activeToast.text}
+
+ )}
+ >
+ )
+}
+
+// exports
+// =
+export default {
+ show(text: string, _opts: any) {
+ console.log('TODO: toast', text)
+ if (toastTimeout) {
+ clearTimeout(toastTimeout)
+ }
+ globalSetActiveToast?.({text})
+ toastTimeout = setTimeout(() => {
+ globalSetActiveToast?.(undefined)
+ }, 2e3)
+ },
+ positions: {
+ TOP: 0,
+ },
+ durations: {
+ LONG: 0,
+ },
+ ToastContainer,
+}
diff --git a/src/view/index.ts b/src/view/index.ts
index 4a469d2635..645aa425bc 100644
--- a/src/view/index.ts
+++ b/src/view/index.ts
@@ -4,6 +4,7 @@ import {library} from '@fortawesome/fontawesome-svg-core'
import {faArrowLeft} from '@fortawesome/free-solid-svg-icons/faArrowLeft'
import {faBars} from '@fortawesome/free-solid-svg-icons/faBars'
import {faBell} from '@fortawesome/free-solid-svg-icons/faBell'
+import {faCheck} from '@fortawesome/free-solid-svg-icons/faCheck'
import {faComment} from '@fortawesome/free-regular-svg-icons/faComment'
import {faHeart} from '@fortawesome/free-regular-svg-icons/faHeart'
import {faHeart as fasHeart} from '@fortawesome/free-solid-svg-icons/faHeart'
@@ -39,6 +40,7 @@ export function setup() {
faArrowLeft,
faBars,
faBell,
+ faCheck,
faComment,
faHeart,
fasHeart,
diff --git a/todos.txt b/todos.txt
index 70807cfe2b..221de14f38 100644
--- a/todos.txt
+++ b/todos.txt
@@ -11,4 +11,6 @@ Paul's todo list
- *
- Linking
- Web linking
- - App linking
\ No newline at end of file
+ - App linking
+- Housekeeping
+ - Remove moment.js -- it's too heavy a dependency
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 231bea5115..082f054ff8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -11300,6 +11300,11 @@ react-app-polyfill@^3.0.0:
regenerator-runtime "^0.13.9"
whatwg-fetch "^3.6.2"
+react-circular-progressbar@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/react-circular-progressbar/-/react-circular-progressbar-2.1.0.tgz#99e5ae499c21de82223b498289e96f66adb8fa3a"
+ integrity sha512-xp4THTrod4aLpGy68FX/k1Q3nzrfHUjUe5v6FsdwXBl3YVMwgeXYQKDrku7n/D6qsJA9CuunarAboC2xCiKs1g==
+
react-dev-utils@^12.0.1:
version "12.0.1"
resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-12.0.1.tgz#ba92edb4a1f379bd46ccd6bcd4e7bc398df33e73"