From 041bfa22a99d8d6b4b17ad36c983e9e2b2444918 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Mon, 25 Jul 2022 23:08:24 -0500 Subject: [PATCH] Implement Web versions of the bottom sheet, toast, and progress circle --- package.json | 1 + public/index.html | 39 ++++++ src/App.web.tsx | 14 +- src/state/lib/api.ts | 4 +- src/view/com/composer/Composer.tsx | 127 +++++++++--------- src/view/com/feed/Feed.tsx | 6 +- src/view/com/feed/FeedItem.tsx | 2 +- .../SharePost.native.tsx} | 11 +- src/view/com/modals/SharePost.tsx | 57 ++++++++ src/view/com/modals/WebModal.tsx | 20 +++ src/view/com/post-thread/PostThread.tsx | 6 +- src/view/com/post-thread/PostThreadItem.tsx | 2 +- src/view/com/util/ProgressCircle.native.tsx | 3 + src/view/com/util/ProgressCircle.tsx | 20 +++ src/view/com/util/Toast.native.tsx | 2 + src/view/com/util/Toast.tsx | 62 +++++++++ src/view/index.ts | 2 + todos.txt | 4 +- yarn.lock | 5 + 19 files changed, 295 insertions(+), 92 deletions(-) rename src/view/com/{sheets/SharePost.tsx => modals/SharePost.native.tsx} (93%) create mode 100644 src/view/com/modals/SharePost.tsx create mode 100644 src/view/com/modals/WebModal.tsx create mode 100644 src/view/com/util/ProgressCircle.native.tsx create mode 100644 src/view/com/util/ProgressCircle.tsx create mode 100644 src/view/com/util/Toast.native.tsx create mode 100644 src/view/com/util/Toast.tsx diff --git a/package.json b/package.json index 93363c35..add0e37c 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 f6cb612b..54fb90ee 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 838b81ee..9a6fedd5 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 bb3ef5d1..df004799 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 c7ce3f4c..57dc0ef8 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 8283e275..6787b51a 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 018b5817..616fb0ac 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 b0f22c54..0e99bd4d 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 00000000..d6d4bb5c --- /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} +