diff options
| author | Mohamed Bassem <me@mbassem.com> | 2025-07-01 20:26:25 +0000 |
|---|---|---|
| committer | Mohamed Bassem <me@mbassem.com> | 2025-07-19 11:45:30 +0000 |
| commit | 49f38efdbe3718055d2c84847d7dab92ae359be9 (patch) | |
| tree | 17d4b6d062ce885fd2de3a05ced224ab49292586 /apps/web/components/dashboard/preview/ReaderView.tsx | |
| parent | 4a4ff37b6283df1d6327a3f8ddff8b74f989ec36 (diff) | |
| download | karakeep-49f38efdbe3718055d2c84847d7dab92ae359be9.tar.zst | |
feat: Add a proper reader mode
Diffstat (limited to 'apps/web/components/dashboard/preview/ReaderView.tsx')
| -rw-r--r-- | apps/web/components/dashboard/preview/ReaderView.tsx | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/apps/web/components/dashboard/preview/ReaderView.tsx b/apps/web/components/dashboard/preview/ReaderView.tsx new file mode 100644 index 00000000..bf4c27a5 --- /dev/null +++ b/apps/web/components/dashboard/preview/ReaderView.tsx @@ -0,0 +1,121 @@ +import { FullPageSpinner } from "@/components/ui/full-page-spinner"; +import { toast } from "@/components/ui/use-toast"; +import { api } from "@/lib/trpc"; + +import { + useCreateHighlight, + useDeleteHighlight, + useUpdateHighlight, +} from "@karakeep/shared-react/hooks/highlights"; +import { BookmarkTypes } from "@karakeep/shared/types/bookmarks"; + +import BookmarkHTMLHighlighter from "./BookmarkHtmlHighlighter"; + +export default function ReaderView({ + bookmarkId, + className, + style, +}: { + bookmarkId: string; + className?: string; + style?: React.CSSProperties; +}) { + const { data: highlights } = api.highlights.getForBookmark.useQuery({ + bookmarkId, + }); + const { data: cachedContent, isPending: isCachedContentLoading } = + api.bookmarks.getBookmark.useQuery( + { + bookmarkId, + includeContent: true, + }, + { + select: (data) => + data.content.type == BookmarkTypes.LINK + ? data.content.htmlContent + : null, + }, + ); + + const { mutate: createHighlight } = useCreateHighlight({ + onSuccess: () => { + toast({ + description: "Highlight has been created!", + }); + }, + onError: () => { + toast({ + variant: "destructive", + description: "Something went wrong", + }); + }, + }); + + const { mutate: updateHighlight } = useUpdateHighlight({ + onSuccess: () => { + toast({ + description: "Highlight has been updated!", + }); + }, + onError: () => { + toast({ + variant: "destructive", + description: "Something went wrong", + }); + }, + }); + + const { mutate: deleteHighlight } = useDeleteHighlight({ + onSuccess: () => { + toast({ + description: "Highlight has been deleted!", + }); + }, + onError: () => { + toast({ + variant: "destructive", + description: "Something went wrong", + }); + }, + }); + + let content; + if (isCachedContentLoading) { + content = <FullPageSpinner />; + } else if (!cachedContent) { + content = ( + <div className="text-destructive">Failed to fetch link content ...</div> + ); + } else { + content = ( + <BookmarkHTMLHighlighter + className={className} + style={style} + htmlContent={cachedContent || ""} + highlights={highlights?.highlights ?? []} + onDeleteHighlight={(h) => + deleteHighlight({ + highlightId: h.id, + }) + } + onUpdateHighlight={(h) => + updateHighlight({ + highlightId: h.id, + color: h.color, + }) + } + onHighlight={(h) => + createHighlight({ + startOffset: h.startOffset, + endOffset: h.endOffset, + color: h.color, + bookmarkId, + text: h.text, + note: null, + }) + } + /> + ); + } + return content; +} |
