import React, { useState } from "react"; import { Keyboard, Pressable, Text } from "react-native"; import ImageView from "react-native-image-viewing"; import * as WebBrowser from "expo-web-browser"; import { useAssetUrl } from "@/lib/hooks"; import { cn } from "@/lib/utils"; import { BottomSheetBackdrop, BottomSheetModal, BottomSheetModalProps, BottomSheetScrollView, BottomSheetView, TouchableWithoutFeedback, } from "@gorhom/bottom-sheet"; import { ExternalLink } from "lucide-react-native"; import { useUpdateBookmark, useUpdateBookmarkText, } from "@hoarder/shared-react/hooks/bookmarks"; import { isBookmarkStillTagging } from "@hoarder/shared-react/utils/bookmarkUtils"; import { BookmarkTypes, ZBookmark } from "@hoarder/shared/types/bookmarks"; import { TailwindResolver } from "../TailwindResolver"; import { buttonVariants } from "../ui/Button"; import { Input } from "../ui/Input"; import PageTitle from "../ui/PageTitle"; import { Skeleton } from "../ui/Skeleton"; import { useToast } from "../ui/Toast"; import BookmarkAssetImage from "./BookmarkAssetImage"; import BookmarkTextMarkdown from "./BookmarkTextMarkdown"; import TagPill from "./TagPill"; function TagList({ bookmark }: { bookmark: ZBookmark }) { return ( Tags {isBookmarkStillTagging(bookmark) ? ( <> ) : bookmark.tags.length > 0 ? ( {bookmark.tags.map((t) => ( ))} ) : ( No tags )} ); } function NotesEditor({ bookmark }: { bookmark: ZBookmark }) { const { mutate, isPending } = useUpdateBookmark(); return ( Notes mutate({ bookmarkId: bookmark.id, note: ev.nativeEvent.text, }) } defaultValue={bookmark.note ?? ""} /> ); } function BookmarkLinkView({ bookmark }: { bookmark: ZBookmark }) { const [imageZoom, setImageZoom] = useState(false); if (bookmark.content.type !== BookmarkTypes.LINK) { throw new Error("Wrong content type rendered"); } const url = new URL(bookmark.content.url); const imageAssetId = bookmark.content.imageAssetId ?? bookmark.content.screenshotAssetId ?? ""; const assetSource = useAssetUrl(imageAssetId); return ( WebBrowser.openBrowserAsync(url.toString())} > {url.host} ( )} /> setImageZoom(false)} doubleTapToZoomEnabled={true} images={[assetSource]} /> setImageZoom(true)}> ); } function BookmarkTextView({ bookmark }: { bookmark: ZBookmark }) { if (bookmark.content.type !== BookmarkTypes.TEXT) { throw new Error("Wrong content type rendered"); } const { toast } = useToast(); const [isEditing, setIsEditing] = useState(false); const [content, setContent] = useState(bookmark.content.text); const { mutate, isPending } = useUpdateBookmarkText({ onError: () => { toast({ message: "Something went wrong", variant: "destructive", }); }, onSuccess: () => { setIsEditing(false); }, }); return ( {isEditing ? ( mutate({ bookmarkId: bookmark.id, text: content, }) } value={content} onChangeText={setContent} multiline autoFocus /> ) : ( setIsEditing(true)}> )} ); } function BookmarkAssetView({ bookmark }: { bookmark: ZBookmark }) { const [imageZoom, setImageZoom] = useState(false); if (bookmark.content.type !== BookmarkTypes.ASSET) { throw new Error("Wrong content type rendered"); } const assetSource = useAssetUrl(bookmark.content.assetId); return ( setImageZoom(false)} doubleTapToZoomEnabled={true} images={[assetSource]} /> setImageZoom(true)}> ); } const ViewBookmarkModal = React.forwardRef< BottomSheetModal, Omit< BottomSheetModalProps, "children" | "backdropComponent" | "onDismiss" > & { bookmark: ZBookmark; } >(({ bookmark, ...props }, ref) => { let comp; let title = null; switch (bookmark.content.type) { case BookmarkTypes.LINK: title = bookmark.title ?? bookmark.content.title; comp = ; break; case BookmarkTypes.TEXT: title = bookmark.title; comp = ; break; case BookmarkTypes.ASSET: title = bookmark.title ?? bookmark.content.fileName; comp = ; break; } return ( ( )} {...props} > {comp} ); }); ViewBookmarkModal.displayName = "ViewBookmarkModal"; export default ViewBookmarkModal;