aboutsummaryrefslogtreecommitdiffstats
path: root/apps/mobile/app/dashboard/bookmarks
diff options
context:
space:
mode:
Diffstat (limited to 'apps/mobile/app/dashboard/bookmarks')
-rw-r--r--apps/mobile/app/dashboard/bookmarks/[slug]/index.tsx41
-rw-r--r--apps/mobile/app/dashboard/bookmarks/[slug]/info.tsx6
-rw-r--r--apps/mobile/app/dashboard/bookmarks/[slug]/manage_lists.tsx100
-rw-r--r--apps/mobile/app/dashboard/bookmarks/[slug]/manage_tags.tsx42
-rw-r--r--apps/mobile/app/dashboard/bookmarks/new.tsx37
5 files changed, 138 insertions, 88 deletions
diff --git a/apps/mobile/app/dashboard/bookmarks/[slug]/index.tsx b/apps/mobile/app/dashboard/bookmarks/[slug]/index.tsx
index 7bf0f118..efb82b1e 100644
--- a/apps/mobile/app/dashboard/bookmarks/[slug]/index.tsx
+++ b/apps/mobile/app/dashboard/bookmarks/[slug]/index.tsx
@@ -1,7 +1,7 @@
import { useState } from "react";
-import { KeyboardAvoidingView } from "react-native";
+import { KeyboardAvoidingView, Pressable, View } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
-import { Stack, useLocalSearchParams } from "expo-router";
+import { Stack, useLocalSearchParams, useRouter } from "expo-router";
import BookmarkAssetView from "@/components/bookmarks/BookmarkAssetView";
import BookmarkLinkTypeSelector, {
BookmarkLinkType,
@@ -12,17 +12,21 @@ import BottomActions from "@/components/bookmarks/BottomActions";
import FullPageError from "@/components/FullPageError";
import FullPageSpinner from "@/components/ui/FullPageSpinner";
import useAppSettings from "@/lib/settings";
-import { api } from "@/lib/trpc";
+import { useQuery } from "@tanstack/react-query";
+import { Settings } from "lucide-react-native";
import { useColorScheme } from "nativewind";
+import { useTRPC } from "@karakeep/shared-react/trpc";
import { BookmarkTypes } from "@karakeep/shared/types/bookmarks";
export default function BookmarkView() {
const insets = useSafeAreaInsets();
+ const router = useRouter();
const { slug } = useLocalSearchParams();
const { colorScheme } = useColorScheme();
const isDark = colorScheme === "dark";
const { settings } = useAppSettings();
+ const api = useTRPC();
const [bookmarkLinkType, setBookmarkLinkType] = useState<BookmarkLinkType>(
settings.defaultBookmarkView,
@@ -36,10 +40,12 @@ export default function BookmarkView() {
data: bookmark,
error,
refetch,
- } = api.bookmarks.getBookmark.useQuery({
- bookmarkId: slug,
- includeContent: false,
- });
+ } = useQuery(
+ api.bookmarks.getBookmark.queryOptions({
+ bookmarkId: slug,
+ includeContent: false,
+ }),
+ );
if (error) {
return <FullPageError error={error.message} onRetry={refetch} />;
@@ -87,11 +93,22 @@ export default function BookmarkView() {
headerTintColor: isDark ? "#fff" : "#000",
headerRight: () =>
bookmark.content.type === BookmarkTypes.LINK ? (
- <BookmarkLinkTypeSelector
- type={bookmarkLinkType}
- onChange={(type) => setBookmarkLinkType(type)}
- bookmark={bookmark}
- />
+ <View className="flex-row items-center gap-3">
+ {bookmarkLinkType === "reader" && (
+ <Pressable
+ onPress={() =>
+ router.push("/dashboard/settings/reader-settings")
+ }
+ >
+ <Settings size={20} color="gray" />
+ </Pressable>
+ )}
+ <BookmarkLinkTypeSelector
+ type={bookmarkLinkType}
+ onChange={(type) => setBookmarkLinkType(type)}
+ bookmark={bookmark}
+ />
+ </View>
) : undefined,
}}
/>
diff --git a/apps/mobile/app/dashboard/bookmarks/[slug]/info.tsx b/apps/mobile/app/dashboard/bookmarks/[slug]/info.tsx
index c4b76aef..744b7f7d 100644
--- a/apps/mobile/app/dashboard/bookmarks/[slug]/info.tsx
+++ b/apps/mobile/app/dashboard/bookmarks/[slug]/info.tsx
@@ -477,14 +477,14 @@ const ViewBookmarkPage = () => {
</Button>
</View>
)}
- <View className="gap-2">
- <Text className="items-center text-center">
+ <View className="gap-1">
+ <Text className="text-center text-xs text-muted-foreground">
Created {bookmark.createdAt.toLocaleString()}
</Text>
{bookmark.modifiedAt &&
bookmark.modifiedAt.getTime() !==
bookmark.createdAt.getTime() && (
- <Text className="items-center text-center">
+ <Text className="text-center text-xs text-muted-foreground">
Modified {bookmark.modifiedAt.toLocaleString()}
</Text>
)}
diff --git a/apps/mobile/app/dashboard/bookmarks/[slug]/manage_lists.tsx b/apps/mobile/app/dashboard/bookmarks/[slug]/manage_lists.tsx
index c502c07f..1070207b 100644
--- a/apps/mobile/app/dashboard/bookmarks/[slug]/manage_lists.tsx
+++ b/apps/mobile/app/dashboard/bookmarks/[slug]/manage_lists.tsx
@@ -1,19 +1,22 @@
import React from "react";
-import { FlatList, Pressable, View } from "react-native";
+import { ActivityIndicator, FlatList, Pressable, View } from "react-native";
import Checkbox from "expo-checkbox";
import { useLocalSearchParams } from "expo-router";
import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
import { Text } from "@/components/ui/Text";
import { useToast } from "@/components/ui/Toast";
+import { useQuery } from "@tanstack/react-query";
+import type { ZBookmarkList } from "@karakeep/shared/types/lists";
import {
useAddBookmarkToList,
useBookmarkLists,
useRemoveBookmarkFromList,
} from "@karakeep/shared-react/hooks/lists";
-import { api } from "@karakeep/shared-react/trpc";
+import { useTRPC } from "@karakeep/shared-react/trpc";
const ListPickerPage = () => {
+ const api = useTRPC();
const { slug: bookmarkId } = useLocalSearchParams();
if (typeof bookmarkId !== "string") {
throw new Error("Unexpected param type");
@@ -26,17 +29,24 @@ const ListPickerPage = () => {
showProgress: false,
});
};
- const { data: existingLists } = api.lists.getListsOfBookmark.useQuery(
- {
- bookmarkId,
- },
- {
- select: (data) => new Set(data.lists.map((l) => l.id)),
- },
+ const { data: existingLists } = useQuery(
+ api.lists.getListsOfBookmark.queryOptions(
+ {
+ bookmarkId,
+ },
+ {
+ select: (data: { lists: ZBookmarkList[] }) =>
+ new Set(data.lists.map((l) => l.id)),
+ },
+ ),
);
const { data } = useBookmarkLists();
- const { mutate: addToList } = useAddBookmarkToList({
+ const {
+ mutate: addToList,
+ isPending: isAddingToList,
+ variables: addVariables,
+ } = useAddBookmarkToList({
onSuccess: () => {
toast({
message: `The bookmark has been added to the list!`,
@@ -46,7 +56,11 @@ const ListPickerPage = () => {
onError,
});
- const { mutate: removeToList } = useRemoveBookmarkFromList({
+ const {
+ mutate: removeToList,
+ isPending: isRemovingFromList,
+ variables: removeVariables,
+ } = useRemoveBookmarkFromList({
onSuccess: () => {
toast({
message: `The bookmark has been removed from the list!`,
@@ -67,6 +81,13 @@ const ListPickerPage = () => {
}
};
+ const isListLoading = (listId: string) => {
+ return (
+ (isAddingToList && addVariables?.listId === listId) ||
+ (isRemovingFromList && removeVariables?.listId === listId)
+ );
+ };
+
const { allPaths } = data ?? {};
// Filter out lists where user is a viewer (can't add/remove bookmarks)
const filteredPaths = allPaths?.filter(
@@ -77,30 +98,41 @@ const ListPickerPage = () => {
<FlatList
className="h-full"
contentContainerStyle={{
- gap: 5,
+ gap: 6,
+ }}
+ renderItem={(l) => {
+ const listId = l.item[l.item.length - 1].id;
+ const isLoading = isListLoading(listId);
+ const isChecked = existingLists && existingLists.has(listId);
+
+ return (
+ <View className="mx-2 flex flex-row items-center rounded-xl bg-card px-4 py-2">
+ <Pressable
+ key={listId}
+ onPress={() => !isLoading && toggleList(listId)}
+ disabled={isLoading}
+ className="flex w-full flex-row items-center justify-between"
+ >
+ <Text className="shrink">
+ {l.item
+ .map((item) => `${item.icon} ${item.name}`)
+ .join(" / ")}
+ </Text>
+ {isLoading ? (
+ <ActivityIndicator size="small" />
+ ) : (
+ <Checkbox
+ value={isChecked}
+ onValueChange={() => {
+ toggleList(listId);
+ }}
+ disabled={isLoading}
+ />
+ )}
+ </Pressable>
+ </View>
+ );
}}
- renderItem={(l) => (
- <View className="mx-2 flex flex-row items-center rounded-xl border border-input bg-card px-4 py-2">
- <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>
- {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={filteredPaths}
/>
</CustomSafeAreaView>
diff --git a/apps/mobile/app/dashboard/bookmarks/[slug]/manage_tags.tsx b/apps/mobile/app/dashboard/bookmarks/[slug]/manage_tags.tsx
index a4575b27..64d057f2 100644
--- a/apps/mobile/app/dashboard/bookmarks/[slug]/manage_tags.tsx
+++ b/apps/mobile/app/dashboard/bookmarks/[slug]/manage_tags.tsx
@@ -6,17 +6,19 @@ import FullPageSpinner from "@/components/ui/FullPageSpinner";
import { Text } from "@/components/ui/Text";
import { useToast } from "@/components/ui/Toast";
import { useColorScheme } from "@/lib/useColorScheme";
+import { useQuery } from "@tanstack/react-query";
import { Check, Plus } from "lucide-react-native";
import {
useAutoRefreshingBookmarkQuery,
useUpdateBookmarkTags,
} from "@karakeep/shared-react/hooks/bookmarks";
-import { api } from "@karakeep/shared-react/trpc";
+import { useTRPC } from "@karakeep/shared-react/trpc";
const NEW_TAG_ID = "new-tag";
const ListPickerPage = () => {
+ const api = useTRPC();
const { colors } = useColorScheme();
const { slug: bookmarkId } = useLocalSearchParams();
@@ -34,22 +36,24 @@ const ListPickerPage = () => {
});
};
- const { data: allTags, isPending: isAllTagsPending } = api.tags.list.useQuery(
- {},
- {
- select: React.useCallback(
- (data: { tags: { id: string; name: string }[] }) => {
- return data.tags
- .map((t) => ({
- id: t.id,
- name: t.name,
- lowered: t.name.toLowerCase(),
- }))
- .sort((a, b) => a.lowered.localeCompare(b.lowered));
- },
- [],
- ),
- },
+ const { data: allTags, isPending: isAllTagsPending } = useQuery(
+ api.tags.list.queryOptions(
+ {},
+ {
+ select: React.useCallback(
+ (data: { tags: { id: string; name: string }[] }) => {
+ return data.tags
+ .map((t) => ({
+ id: t.id,
+ name: t.name,
+ lowered: t.name.toLowerCase(),
+ }))
+ .sort((a, b) => a.lowered.localeCompare(b.lowered));
+ },
+ [],
+ ),
+ },
+ ),
);
const { data: existingTags } = useAutoRefreshingBookmarkQuery({
bookmarkId,
@@ -165,7 +169,7 @@ const ListPickerPage = () => {
contentInsetAdjustmentBehavior="automatic"
keyExtractor={(t) => t.id}
contentContainerStyle={{
- gap: 5,
+ gap: 6,
}}
SectionSeparatorComponent={() => <View className="h-1" />}
sections={[
@@ -207,7 +211,7 @@ const ListPickerPage = () => {
})
}
>
- <View className="mx-2 flex flex-row items-center gap-2 rounded-xl border border-input bg-card px-4 py-2">
+ <View className="mx-2 flex flex-row items-center gap-2 rounded-xl bg-card px-4 py-2">
{t.section.title == "Existing Tags" && (
<Check color={colors.foreground} />
)}
diff --git a/apps/mobile/app/dashboard/bookmarks/new.tsx b/apps/mobile/app/dashboard/bookmarks/new.tsx
index 25882d7f..f7be22e1 100644
--- a/apps/mobile/app/dashboard/bookmarks/new.tsx
+++ b/apps/mobile/app/dashboard/bookmarks/new.tsx
@@ -2,7 +2,6 @@ import React, { useState } from "react";
import { View } from "react-native";
import { router } from "expo-router";
import { Button } from "@/components/ui/Button";
-import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
import { Input } from "@/components/ui/Input";
import { Text } from "@/components/ui/Text";
import { useToast } from "@/components/ui/Toast";
@@ -59,25 +58,23 @@ const NoteEditorPage = () => {
};
return (
- <CustomSafeAreaView>
- <View className="gap-2 px-4">
- {error && (
- <Text className="w-full text-center text-red-500">{error}</Text>
- )}
- <Input
- onChangeText={setText}
- className="bg-card"
- multiline
- placeholder="What's on your mind?"
- autoFocus
- autoCapitalize={"none"}
- textAlignVertical="top"
- />
- <Button onPress={onSubmit} disabled={isPending}>
- <Text>Save</Text>
- </Button>
- </View>
- </CustomSafeAreaView>
+ <View className="flex-1 gap-2 px-4 pt-4">
+ {error && (
+ <Text className="w-full text-center text-red-500">{error}</Text>
+ )}
+ <Input
+ onChangeText={setText}
+ className="bg-card"
+ multiline
+ placeholder="What's on your mind?"
+ autoFocus
+ autoCapitalize={"none"}
+ textAlignVertical="top"
+ />
+ <Button onPress={onSubmit} disabled={isPending}>
+ <Text>Save</Text>
+ </Button>
+ </View>
);
};