diff options
| author | Mohamed Bassem <me@mbassem.com> | 2024-11-23 20:59:34 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-11-23 20:59:34 +0000 |
| commit | 5522e20104da6afe2e4667cf45dbbbbc0e838865 (patch) | |
| tree | 72f416fa83c97a8533eea431e25bd63bda1e7d81 /apps/mobile/components/bookmarks | |
| parent | 4bb74872fd518008afea16a136292037baf5b024 (diff) | |
| download | karakeep-5522e20104da6afe2e4667cf45dbbbbc0e838865.tar.zst | |
ui(mobile): Replace bottom sheet with native screens (#690)
* Remove bottom sheet from bookmark info page
* Remove bottom sheet from manage lists page
* Remove bottom sheet from new list page
* Remove bottom sheet from new bookmark page
* Drop bottom-sheets
* Improve the look of the modals
* Make the search page fade from bottom
Diffstat (limited to 'apps/mobile/components/bookmarks')
| -rw-r--r-- | apps/mobile/components/bookmarks/BookmarkCard.tsx | 15 | ||||
| -rw-r--r-- | apps/mobile/components/bookmarks/ListPickerModal.tsx | 117 | ||||
| -rw-r--r-- | apps/mobile/components/bookmarks/NewBookmarkModal.tsx | 98 | ||||
| -rw-r--r-- | apps/mobile/components/bookmarks/ViewBookmarkModal.tsx | 119 |
4 files changed, 2 insertions, 347 deletions
diff --git a/apps/mobile/components/bookmarks/BookmarkCard.tsx b/apps/mobile/components/bookmarks/BookmarkCard.tsx index 5d84ee6f..df5aa666 100644 --- a/apps/mobile/components/bookmarks/BookmarkCard.tsx +++ b/apps/mobile/components/bookmarks/BookmarkCard.tsx @@ -1,4 +1,3 @@ -import { useRef } from "react"; import { ActivityIndicator, Image, @@ -9,10 +8,9 @@ import { View, } from "react-native"; import * as Haptics from "expo-haptics"; -import { useRouter } from "expo-router"; +import { router, useRouter } from "expo-router"; import useAppSettings from "@/lib/settings"; import { api } from "@/lib/trpc"; -import { BottomSheetModal } from "@gorhom/bottom-sheet"; import { MenuView } from "@react-native-menu/menu"; import { Ellipsis, Star } from "lucide-react-native"; @@ -33,7 +31,6 @@ import { Skeleton } from "../ui/Skeleton"; import { useToast } from "../ui/Toast"; import BookmarkAssetImage from "./BookmarkAssetImage"; import BookmarkTextMarkdown from "./BookmarkTextMarkdown"; -import ListPickerModal from "./ListPickerModal"; import TagPill from "./TagPill"; function ActionBar({ bookmark }: { bookmark: ZBookmark }) { @@ -73,8 +70,6 @@ function ActionBar({ bookmark }: { bookmark: ZBookmark }) { onError, }); - const manageListsSheetRef = useRef<BottomSheetModal>(null); - return ( <View className="flex flex-row gap-4"> {(isArchivePending || isDeletionPending) && <ActivityIndicator />} @@ -94,12 +89,6 @@ function ActionBar({ bookmark }: { bookmark: ZBookmark }) { )} </Pressable> - <ListPickerModal - ref={manageListsSheetRef} - snapPoints={["50%", "90%"]} - bookmarkId={bookmark.id} - /> - <MenuView onPressAction={({ nativeEvent }) => { Haptics.selectionAsync(); @@ -113,7 +102,7 @@ function ActionBar({ bookmark }: { bookmark: ZBookmark }) { archived: !bookmark.archived, }); } else if (nativeEvent.event === "manage_list") { - manageListsSheetRef?.current?.present(); + router.push(`/dashboard/bookmarks/${bookmark.id}/manage_lists`); } }} actions={[ diff --git a/apps/mobile/components/bookmarks/ListPickerModal.tsx b/apps/mobile/components/bookmarks/ListPickerModal.tsx deleted file mode 100644 index 6079e53d..00000000 --- a/apps/mobile/components/bookmarks/ListPickerModal.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import React from "react"; -import { Pressable, Text, View } from "react-native"; -import Checkbox from "expo-checkbox"; -import { - BottomSheetFlatList, - BottomSheetModal, - BottomSheetModalProps, -} from "@gorhom/bottom-sheet"; - -import { - useAddBookmarkToList, - useBookmarkLists, - useRemoveBookmarkFromList, -} from "@hoarder/shared-react/hooks/lists"; -import { api } from "@hoarder/shared-react/trpc"; - -import PageTitle from "../ui/PageTitle"; -import { useToast } from "../ui/Toast"; - -const ListPickerModal = React.forwardRef< - BottomSheetModal, - Omit<BottomSheetModalProps, "children"> & { - bookmarkId: string; - } ->(({ bookmarkId, ...props }, ref) => { - const { toast } = useToast(); - const onError = () => { - toast({ - message: "Something went wrong", - variant: "destructive", - showProgress: false, - }); - }; - const { data: existingLists } = api.lists.getListsOfBookmark.useQuery( - { - bookmarkId, - }, - { - select: (data) => new Set(data.lists.map((l) => l.id)), - }, - ); - const { data } = useBookmarkLists(); - - const { mutate: addToList } = useAddBookmarkToList({ - onSuccess: () => { - toast({ - message: `The bookmark has been added to the list!`, - showProgress: false, - }); - }, - onError, - }); - - const { mutate: removeToList } = useRemoveBookmarkFromList({ - onSuccess: () => { - toast({ - message: `The bookmark has been removed from the list!`, - showProgress: false, - }); - }, - onError, - }); - - const toggleList = (listId: string) => { - if (!existingLists) { - return; - } - if (existingLists.has(listId)) { - removeToList({ bookmarkId, listId }); - } else { - addToList({ bookmarkId, listId }); - } - }; - - const { allPaths } = data ?? {}; - return ( - <View> - <BottomSheetModal ref={ref} {...props}> - <BottomSheetFlatList - ListHeaderComponent={<PageTitle title="Manage Lists" />} - className="h-full" - contentContainerStyle={{ - gap: 5, - }} - renderItem={(l) => ( - <View className="mx-2 flex flex-row items-center rounded-xl border border-input bg-white px-4 py-2 dark:bg-accent"> - <Pressable - key={l.item[l.item.length - 1].id} - onPress={() => toggleList(l.item[l.item.length - 1].id)} - className="flex w-full flex-row justify-between" - > - <Text className="text-lg text-accent-foreground"> - {l.item - .map((item) => `${item.icon} ${item.name}`) - .join(" / ")} - </Text> - <Checkbox - value={ - existingLists && - existingLists.has(l.item[l.item.length - 1].id) - } - onValueChange={() => { - toggleList(l.item[l.item.length - 1].id); - }} - /> - </Pressable> - </View> - )} - data={allPaths} - /> - </BottomSheetModal> - </View> - ); -}); -ListPickerModal.displayName = "ListPickerModal"; - -export default ListPickerModal; diff --git a/apps/mobile/components/bookmarks/NewBookmarkModal.tsx b/apps/mobile/components/bookmarks/NewBookmarkModal.tsx deleted file mode 100644 index 218c54b8..00000000 --- a/apps/mobile/components/bookmarks/NewBookmarkModal.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import React, { useState } from "react"; -import { Text, View } from "react-native"; -import { - BottomSheetBackdrop, - BottomSheetModal, - BottomSheetModalProps, - BottomSheetView, - useBottomSheetModal, -} from "@gorhom/bottom-sheet"; - -import { useCreateBookmark } from "@hoarder/shared-react/hooks/bookmarks"; -import { BookmarkTypes } from "@hoarder/shared/types/bookmarks"; - -import { Button } from "../ui/Button"; -import { Input } from "../ui/Input"; -import PageTitle from "../ui/PageTitle"; -import { useToast } from "../ui/Toast"; - -const NoteEditorModal = React.forwardRef< - BottomSheetModal, - Omit<BottomSheetModalProps, "children" | "backdropComponent" | "onDismiss"> ->(({ ...props }, ref) => { - const { dismiss } = useBottomSheetModal(); - - const [text, setText] = useState(""); - const [error, setError] = useState<string | undefined>(); - const { toast } = useToast(); - - const { mutate: createBookmark } = useCreateBookmark({ - onSuccess: (resp) => { - if (resp.alreadyExists) { - toast({ - message: "Bookmark already exists", - }); - } - setText(""); - dismiss(); - }, - onError: (e) => { - let message; - if (e.data?.zodError) { - const zodError = e.data.zodError; - message = JSON.stringify(zodError); - } else { - message = `Something went wrong: ${e.message}`; - } - setError(message); - }, - }); - - const onSubmit = () => { - const data = text.trim(); - try { - const url = new URL(data); - if (url.protocol != "http:" && url.protocol != "https:") { - throw new Error(`Unsupported URL protocol: ${url.protocol}`); - } - createBookmark({ type: BookmarkTypes.LINK, url: data }); - } catch (e: unknown) { - createBookmark({ type: BookmarkTypes.TEXT, text: data }); - } - }; - - return ( - <View> - <BottomSheetModal - ref={ref} - backdropComponent={(props) => ( - <BottomSheetBackdrop - appearsOnIndex={0} - disappearsOnIndex={-1} - {...props} - /> - )} - {...props} - > - <PageTitle title="New Bookmark" /> - <BottomSheetView className="gap-2 p-4"> - {error && ( - <Text className="w-full text-center text-red-500">{error}</Text> - )} - <Input - onChangeText={setText} - multiline - placeholder="What's on your mind?" - autoFocus - autoCapitalize={"none"} - textAlignVertical="top" - /> - <Button onPress={onSubmit} label="Save" /> - </BottomSheetView> - </BottomSheetModal> - </View> - ); -}); -NoteEditorModal.displayName = "NewBookmarkModal"; - -export default NoteEditorModal; diff --git a/apps/mobile/components/bookmarks/ViewBookmarkModal.tsx b/apps/mobile/components/bookmarks/ViewBookmarkModal.tsx deleted file mode 100644 index df513a89..00000000 --- a/apps/mobile/components/bookmarks/ViewBookmarkModal.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import React from "react"; -import { Keyboard, Text } from "react-native"; -import { - BottomSheetBackdrop, - BottomSheetModal, - BottomSheetModalProps, - BottomSheetScrollView, - BottomSheetView, - TouchableWithoutFeedback, -} from "@gorhom/bottom-sheet"; - -import { useUpdateBookmark } from "@hoarder/shared-react/hooks/bookmarks"; -import { isBookmarkStillTagging } from "@hoarder/shared-react/utils/bookmarkUtils"; -import { BookmarkTypes, ZBookmark } from "@hoarder/shared/types/bookmarks"; - -import { Input } from "../ui/Input"; -import PageTitle from "../ui/PageTitle"; -import { Skeleton } from "../ui/Skeleton"; -import TagPill from "./TagPill"; - -function TagList({ bookmark }: { bookmark: ZBookmark }) { - return ( - <BottomSheetView className="flex flex-row items-center gap-4"> - <Text>Tags</Text> - {isBookmarkStillTagging(bookmark) ? ( - <> - <Skeleton className="h-4 w-full" /> - <Skeleton className="h-4 w-full" /> - </> - ) : bookmark.tags.length > 0 ? ( - <BottomSheetView className="flex flex-row flex-wrap gap-2"> - {bookmark.tags.map((t) => ( - <TagPill key={t.id} tag={t} /> - ))} - </BottomSheetView> - ) : ( - <Text>No tags</Text> - )} - </BottomSheetView> - ); -} - -function NotesEditor({ bookmark }: { bookmark: ZBookmark }) { - const { mutate, isPending } = useUpdateBookmark(); - return ( - <BottomSheetView className="flex flex-row items-center gap-4"> - <Text>Notes</Text> - - <Input - className="flex-1" - editable={!isPending} - multiline={true} - numberOfLines={3} - loading={isPending} - placeholder="Notes" - textAlignVertical="top" - onEndEditing={(ev) => - mutate({ - bookmarkId: bookmark.id, - note: ev.nativeEvent.text, - }) - } - defaultValue={bookmark.note ?? ""} - /> - </BottomSheetView> - ); -} - -const ViewBookmarkModal = React.forwardRef< - BottomSheetModal, - Omit< - BottomSheetModalProps, - "children" | "backdropComponent" | "onDismiss" - > & { - bookmark: ZBookmark; - } ->(({ bookmark, ...props }, ref) => { - let title = null; - switch (bookmark.content.type) { - case BookmarkTypes.LINK: - title = bookmark.title ?? bookmark.content.title; - break; - case BookmarkTypes.TEXT: - title = bookmark.title; - break; - case BookmarkTypes.ASSET: - title = bookmark.title ?? bookmark.content.fileName; - break; - } - return ( - <BottomSheetModal - ref={ref} - backdropComponent={(props) => ( - <BottomSheetBackdrop - appearsOnIndex={0} - disappearsOnIndex={-1} - {...props} - /> - )} - {...props} - > - <BottomSheetScrollView className="flex flex-1"> - <TouchableWithoutFeedback onPress={Keyboard.dismiss}> - <BottomSheetView className="flex flex-1"> - <PageTitle title={title ?? "Untitled"} className="line-clamp-2" /> - <BottomSheetView className="gap-4 px-4"> - <TagList bookmark={bookmark} /> - <NotesEditor bookmark={bookmark} /> - </BottomSheetView> - </BottomSheetView> - </TouchableWithoutFeedback> - </BottomSheetScrollView> - </BottomSheetModal> - ); -}); - -ViewBookmarkModal.displayName = "ViewBookmarkModal"; - -export default ViewBookmarkModal; |
