aboutsummaryrefslogtreecommitdiffstats
path: root/apps/mobile/components/bookmarks
diff options
context:
space:
mode:
authorxuatz <xzlow10@gmail.com>2025-11-03 04:32:18 +0900
committerGitHub <noreply@github.com>2025-11-02 19:32:18 +0000
commit33f407797213c56dd2f13e98228a5305efdf90fd (patch)
tree149f477c1ab61b46bb0d9cc49c656a03b1c56f64 /apps/mobile/components/bookmarks
parentb63a49fc3980296c6a6ea6ac0624142e8af94d52 (diff)
downloadkarakeep-33f407797213c56dd2f13e98228a5305efdf90fd.tar.zst
feat: display notes on bookmark card (#2083)
* feat: display notes on bookmark card * apply styling * include mobile impl * apply pr comments * add display options menu into PR * put it under app setting * cleanup * address pr comments * change the default for show notes to false * make the in-card note font lighter --------- Co-authored-by: Mohamed Bassem <me@mbassem.com>
Diffstat (limited to 'apps/mobile/components/bookmarks')
-rw-r--r--apps/mobile/components/bookmarks/BookmarkCard.tsx10
-rw-r--r--apps/mobile/components/bookmarks/NotePreview.tsx83
2 files changed, 92 insertions, 1 deletions
diff --git a/apps/mobile/components/bookmarks/BookmarkCard.tsx b/apps/mobile/components/bookmarks/BookmarkCard.tsx
index 62e74e97..98d8d3e2 100644
--- a/apps/mobile/components/bookmarks/BookmarkCard.tsx
+++ b/apps/mobile/components/bookmarks/BookmarkCard.tsx
@@ -1,4 +1,3 @@
-import React from "react";
import {
ActivityIndicator,
Alert,
@@ -37,6 +36,7 @@ import { Skeleton } from "../ui/Skeleton";
import { useToast } from "../ui/Toast";
import BookmarkAssetImage from "./BookmarkAssetImage";
import BookmarkTextMarkdown from "./BookmarkTextMarkdown";
+import { NotePreview } from "./NotePreview";
import TagPill from "./TagPill";
function ActionBar({ bookmark }: { bookmark: ZBookmark }) {
@@ -285,6 +285,7 @@ function LinkCard({
throw new Error("Wrong content type rendered");
}
+ const note = settings.showNotes ? bookmark.note?.trim() : undefined;
const url = bookmark.content.url;
const parsedUrl = new URL(url);
@@ -329,6 +330,7 @@ function LinkCard({
>
{bookmark.title ?? bookmark.content.title ?? parsedUrl.host}
</Text>
+ {note && <NotePreview note={note} bookmarkId={bookmark.id} />}
<TagList bookmark={bookmark} />
<Divider orientation="vertical" className="mt-2 h-0.5 w-full" />
<View className="mt-2 flex flex-row justify-between px-2 pb-2">
@@ -347,9 +349,11 @@ function TextCard({
bookmark: ZBookmark;
onOpenBookmark: () => void;
}) {
+ const { settings } = useAppSettings();
if (bookmark.content.type !== BookmarkTypes.TEXT) {
throw new Error("Wrong content type rendered");
}
+ const note = settings.showNotes ? bookmark.note?.trim() : undefined;
const content = bookmark.content.text;
return (
<View className="flex max-h-96 gap-2 p-2">
@@ -365,6 +369,7 @@ function TextCard({
<BookmarkTextMarkdown text={content} />
</Pressable>
</View>
+ {note && <NotePreview note={note} bookmarkId={bookmark.id} />}
<TagList bookmark={bookmark} />
<Divider orientation="vertical" className="mt-2 h-0.5 w-full" />
<View className="flex flex-row justify-between p-2">
@@ -382,9 +387,11 @@ function AssetCard({
bookmark: ZBookmark;
onOpenBookmark: () => void;
}) {
+ const { settings } = useAppSettings();
if (bookmark.content.type !== BookmarkTypes.ASSET) {
throw new Error("Wrong content type rendered");
}
+ const note = settings.showNotes ? bookmark.note?.trim() : undefined;
const title = bookmark.title ?? bookmark.content.fileName;
const assetImage =
@@ -405,6 +412,7 @@ function AssetCard({
<Text className="line-clamp-2 text-xl font-bold">{title}</Text>
)}
</Pressable>
+ {note && <NotePreview note={note} bookmarkId={bookmark.id} />}
<TagList bookmark={bookmark} />
<Divider orientation="vertical" className="mt-2 h-0.5 w-full" />
<View className="mt-2 flex flex-row justify-between px-2 pb-2">
diff --git a/apps/mobile/components/bookmarks/NotePreview.tsx b/apps/mobile/components/bookmarks/NotePreview.tsx
new file mode 100644
index 00000000..d529d56e
--- /dev/null
+++ b/apps/mobile/components/bookmarks/NotePreview.tsx
@@ -0,0 +1,83 @@
+import { useState } from "react";
+import { Modal, Pressable, ScrollView, View } from "react-native";
+import { router } from "expo-router";
+import { ExternalLink, NotepadText, X } from "lucide-react-native";
+import { useColorScheme } from "nativewind";
+
+import { Button } from "../ui/Button";
+import { Text } from "../ui/Text";
+
+interface NotePreviewProps {
+ note: string;
+ bookmarkId: string;
+}
+
+export function NotePreview({ note, bookmarkId }: NotePreviewProps) {
+ const [isModalVisible, setIsModalVisible] = useState(false);
+ const { colorScheme } = useColorScheme();
+ const iconColor = colorScheme === "dark" ? "#9ca3af" : "#6b7280";
+ const modalIconColor = colorScheme === "dark" ? "#d1d5db" : "#374151";
+
+ if (!note?.trim()) {
+ return null;
+ }
+
+ return (
+ <>
+ <Pressable onPress={() => setIsModalVisible(true)}>
+ <View className="flex flex-row items-center gap-2">
+ <NotepadText size={24} color={iconColor} />
+ <Text
+ className="flex-1 text-sm italic text-gray-500 dark:text-gray-400"
+ numberOfLines={2}
+ >
+ {note}
+ </Text>
+ </View>
+ </Pressable>
+
+ <Modal
+ visible={isModalVisible}
+ transparent
+ animationType="slide"
+ onRequestClose={() => setIsModalVisible(false)}
+ >
+ <View className="flex-1 justify-end bg-black/50">
+ <View className="max-h-[80%] rounded-t-3xl bg-card p-6">
+ {/* Header */}
+ <View className="mb-4 flex flex-row items-center justify-between">
+ <Text className="text-lg font-semibold">Note</Text>
+ <Pressable
+ onPress={() => setIsModalVisible(false)}
+ className="p-2"
+ >
+ <X size={24} color={modalIconColor} />
+ </Pressable>
+ </View>
+
+ {/* Note Content */}
+ <ScrollView className="mb-4 max-h-96">
+ <Text className="text-sm text-gray-700 dark:text-gray-300">
+ {note}
+ </Text>
+ </ScrollView>
+
+ {/* Action Button */}
+ <View className="flex flex-row justify-end border-t border-border pt-4">
+ <Button
+ variant="secondary"
+ onPress={() => {
+ setIsModalVisible(false);
+ router.push(`/dashboard/bookmarks/${bookmarkId}/info`);
+ }}
+ >
+ <Text className="text-sm">Edit Notes</Text>
+ <ExternalLink size={14} color={modalIconColor} />
+ </Button>
+ </View>
+ </View>
+ </View>
+ </Modal>
+ </>
+ );
+}