diff options
| author | xuatz <xzlow10@gmail.com> | 2025-11-03 04:32:18 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-11-02 19:32:18 +0000 |
| commit | 33f407797213c56dd2f13e98228a5305efdf90fd (patch) | |
| tree | 149f477c1ab61b46bb0d9cc49c656a03b1c56f64 /apps/mobile | |
| parent | b63a49fc3980296c6a6ea6ac0624142e8af94d52 (diff) | |
| download | karakeep-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')
| -rw-r--r-- | apps/mobile/app/dashboard/(tabs)/settings.tsx | 14 | ||||
| -rw-r--r-- | apps/mobile/components/bookmarks/BookmarkCard.tsx | 10 | ||||
| -rw-r--r-- | apps/mobile/components/bookmarks/NotePreview.tsx | 83 | ||||
| -rw-r--r-- | apps/mobile/lib/settings.ts | 2 |
4 files changed, 107 insertions, 2 deletions
diff --git a/apps/mobile/app/dashboard/(tabs)/settings.tsx b/apps/mobile/app/dashboard/(tabs)/settings.tsx index 6d76308d..76216e00 100644 --- a/apps/mobile/app/dashboard/(tabs)/settings.tsx +++ b/apps/mobile/app/dashboard/(tabs)/settings.tsx @@ -1,5 +1,5 @@ import { useEffect } from "react"; -import { ActivityIndicator, Pressable, View } from "react-native"; +import { ActivityIndicator, Pressable, Switch, View } from "react-native"; import { Slider } from "react-native-awesome-slider"; import { useSharedValue } from "react-native-reanimated"; import { Link } from "expo-router"; @@ -87,6 +87,18 @@ export default function Dashboard() { </Pressable> </Link> </View> + <View className="flex w-full flex-row items-center justify-between gap-8 rounded-lg bg-card px-4 py-2"> + <Text>Show note preview in bookmark</Text> + <Switch + value={settings.showNotes} + onValueChange={(value) => + setSettings({ + ...settings, + showNotes: value, + }) + } + /> + </View> <Text className="w-full p-1 text-2xl font-bold text-foreground"> Upload Settings </Text> 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> + </> + ); +} diff --git a/apps/mobile/lib/settings.ts b/apps/mobile/lib/settings.ts index 51fa661f..4399e04a 100644 --- a/apps/mobile/lib/settings.ts +++ b/apps/mobile/lib/settings.ts @@ -14,6 +14,7 @@ const zSettingsSchema = z.object({ .enum(["reader", "browser"]) .optional() .default("reader"), + showNotes: z.boolean().optional().default(false), }); export type Settings = z.infer<typeof zSettingsSchema>; @@ -32,6 +33,7 @@ const useSettings = create<AppSettingsState>((set, get) => ({ imageQuality: 0.2, theme: "system", defaultBookmarkView: "reader", + showNotes: false, }, }, setSettings: async (settings) => { |
