"use client"; import Link from "next/link"; import { isBookmarkStillCrawling, isBookmarkStillLoading, } from "@/lib/bookmarkUtils"; import { api } from "@/lib/trpc"; import type { ZBookmarkTypeLink } from "@hoarder/shared/types/bookmarks"; import { BookmarkLayoutAdaptingCard } from "./BookmarkLayoutAdaptingCard"; function LinkTitle({ bookmark }: { bookmark: ZBookmarkTypeLink }) { const link = bookmark.content; const parsedUrl = new URL(link.url); return ( {bookmark.title ?? link?.title ?? parsedUrl.host} ); } function LinkImage({ bookmark, className, }: { bookmark: ZBookmarkTypeLink; className?: string; }) { const link = bookmark.content; // A dummy white pixel for when there's no image. // TODO: Better handling for cards with no images const image = link.imageUrl ?? "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAA1JREFUGFdj+P///38ACfsD/QVDRcoAAAAASUVORK5CYII="; return ( {/* eslint-disable-next-line @next/next/no-img-element */} card banner ); } function LinkUrl({ bookmark }: { bookmark: ZBookmarkTypeLink }) { const link = bookmark.content; const parsedUrl = new URL(link.url); return ( {parsedUrl.host} ); } export default function LinkCard({ bookmark: initialData, className, }: { bookmark: ZBookmarkTypeLink; className?: string; }) { const { data: bookmark } = api.bookmarks.getBookmark.useQuery( { bookmarkId: initialData.id, }, { initialData, refetchInterval: (query) => { const data = query.state.data; if (!data) { return false; } // If the link is not crawled or not tagged if (isBookmarkStillLoading(data)) { return 1000; } return false; }, }, ); if (bookmark.content.type !== "link") { throw new Error("Invalid bookmark type"); } const bookmarkLink = { ...bookmark, content: bookmark.content }; return ( } footer={} bookmark={bookmarkLink} wrapTags={false} image={(_layout, className) => ( )} className={className} /> ); }