aboutsummaryrefslogtreecommitdiffstats
path: root/apps/mobile/components
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2024-11-23 20:59:34 +0000
committerGitHub <noreply@github.com>2024-11-23 20:59:34 +0000
commit5522e20104da6afe2e4667cf45dbbbbc0e838865 (patch)
tree72f416fa83c97a8533eea431e25bd63bda1e7d81 /apps/mobile/components
parent4bb74872fd518008afea16a136292037baf5b024 (diff)
downloadkarakeep-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')
-rw-r--r--apps/mobile/components/bookmarks/BookmarkCard.tsx15
-rw-r--r--apps/mobile/components/bookmarks/ListPickerModal.tsx117
-rw-r--r--apps/mobile/components/bookmarks/NewBookmarkModal.tsx98
-rw-r--r--apps/mobile/components/bookmarks/ViewBookmarkModal.tsx119
-rw-r--r--apps/mobile/components/lists/NewListModal.tsx80
5 files changed, 2 insertions, 427 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;
diff --git a/apps/mobile/components/lists/NewListModal.tsx b/apps/mobile/components/lists/NewListModal.tsx
deleted file mode 100644
index d31ac362..00000000
--- a/apps/mobile/components/lists/NewListModal.tsx
+++ /dev/null
@@ -1,80 +0,0 @@
-import React, { useState } from "react";
-import { Text, View } from "react-native";
-import {
- BottomSheetBackdrop,
- BottomSheetModal,
- BottomSheetModalProps,
- BottomSheetView,
- useBottomSheetModal,
-} from "@gorhom/bottom-sheet";
-
-import { useCreateBookmarkList } from "@hoarder/shared-react/hooks/lists";
-
-import { Button } from "../ui/Button";
-import { Input } from "../ui/Input";
-import PageTitle from "../ui/PageTitle";
-import { useToast } from "../ui/Toast";
-
-const NewListModal = React.forwardRef<
- BottomSheetModal,
- Omit<BottomSheetModalProps, "children" | "backdropComponent" | "onDismiss">
->(({ ...props }, ref) => {
- const { dismiss } = useBottomSheetModal();
- const { toast } = useToast();
- const [text, setText] = useState("");
-
- const { mutate, isPending } = useCreateBookmarkList({
- onSuccess: () => {
- dismiss();
- },
- onError: () => {
- toast({
- message: "Something went wrong",
- variant: "destructive",
- });
- },
- });
-
- const onSubmit = () => {
- mutate({
- name: text,
- icon: "🚀",
- });
- };
-
- return (
- <View>
- <BottomSheetModal
- ref={ref}
- onDismiss={() => setText("")}
- backdropComponent={(props) => (
- <BottomSheetBackdrop
- appearsOnIndex={0}
- disappearsOnIndex={-1}
- {...props}
- />
- )}
- {...props}
- >
- <PageTitle title="New List" />
- <BottomSheetView className="gap-2 px-4">
- <BottomSheetView className="flex flex-row items-center gap-1">
- <Text className="shrink p-2">🚀</Text>
- <Input
- className="flex-1"
- onChangeText={setText}
- placeholder="List Name"
- autoFocus
- autoCapitalize={"none"}
- />
- </BottomSheetView>
- <Button disabled={isPending} onPress={onSubmit} label="Save" />
- </BottomSheetView>
- </BottomSheetModal>
- </View>
- );
-});
-
-NewListModal.displayName = "NewListModal";
-
-export default NewListModal;