@vertesia/ui 0.73.0 → 0.74.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/lib/esm/features/magic-pdf/DownloadPopover.js +17 -2
  2. package/lib/esm/features/magic-pdf/DownloadPopover.js.map +1 -1
  3. package/lib/esm/features/magic-pdf/MagicPdfView.js +26 -3
  4. package/lib/esm/features/magic-pdf/MagicPdfView.js.map +1 -1
  5. package/lib/esm/features/magic-pdf/PageSlider.js +21 -8
  6. package/lib/esm/features/magic-pdf/PageSlider.js.map +1 -1
  7. package/lib/esm/features/magic-pdf/PdfPageProvider.js +55 -0
  8. package/lib/esm/features/magic-pdf/PdfPageProvider.js.map +1 -1
  9. package/lib/esm/features/magic-pdf/TextPageView.js +21 -1
  10. package/lib/esm/features/magic-pdf/TextPageView.js.map +1 -1
  11. package/lib/esm/features/store/objects/layout/documentLayout.js +1 -1
  12. package/lib/esm/features/store/objects/layout/documentLayout.js.map +1 -1
  13. package/lib/tsconfig.tsbuildinfo +1 -1
  14. package/lib/types/features/magic-pdf/DownloadPopover.d.ts.map +1 -1
  15. package/lib/types/features/magic-pdf/PageSlider.d.ts +2 -1
  16. package/lib/types/features/magic-pdf/PageSlider.d.ts.map +1 -1
  17. package/lib/types/features/magic-pdf/PdfPageProvider.d.ts +10 -0
  18. package/lib/types/features/magic-pdf/PdfPageProvider.d.ts.map +1 -1
  19. package/lib/types/features/magic-pdf/TextPageView.d.ts.map +1 -1
  20. package/lib/types/features/magic-pdf/types.d.ts +1 -1
  21. package/lib/types/features/magic-pdf/types.d.ts.map +1 -1
  22. package/lib/vertesia-ui-features.js +1 -1
  23. package/lib/vertesia-ui-features.js.map +1 -1
  24. package/package.json +4 -4
  25. package/src/features/magic-pdf/DownloadPopover.tsx +38 -5
  26. package/src/features/magic-pdf/MagicPdfView.tsx +31 -5
  27. package/src/features/magic-pdf/PageSlider.tsx +44 -14
  28. package/src/features/magic-pdf/PdfPageProvider.tsx +81 -0
  29. package/src/features/magic-pdf/TextPageView.tsx +29 -1
  30. package/src/features/magic-pdf/types.ts +1 -1
  31. package/src/features/store/objects/layout/documentLayout.tsx +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertesia/ui",
3
- "version": "0.73.0",
3
+ "version": "0.74.0",
4
4
  "description": "Vertesia UI components and and hooks",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -58,9 +58,9 @@
58
58
  "remark-gfm": "^4.0.1",
59
59
  "tailwind-merge": "^3.3.0",
60
60
  "ts-md5": "^1.3.1",
61
- "@vertesia/client": "0.73.0",
62
- "@vertesia/common": "0.73.0",
63
- "@vertesia/json": "0.73.0"
61
+ "@vertesia/common": "0.74.0",
62
+ "@vertesia/client": "0.74.0",
63
+ "@vertesia/json": "0.74.0"
64
64
  },
65
65
  "devDependencies": {
66
66
  "@eslint/js": "^9.27.0",
@@ -1,4 +1,4 @@
1
- import { ContentObject } from "@vertesia/common";
1
+ import { ContentObject, DocumentMetadata } from "@vertesia/common";
2
2
  import { useUserSession } from "@vertesia/ui/session";
3
3
  import { Popover } from "@vertesia/ui/widgets";
4
4
  import { CloudDownload } from "lucide-react";
@@ -12,18 +12,51 @@ export function DownloadPopover({ object }: DownloadPopoverProps) {
12
12
  const onDownload = (name: string) => {
13
13
  getResourceUrl(client, object.id, name).then(url => window.open(url, '_blank'));
14
14
  }
15
+
16
+ const getProcessorType = (): string => {
17
+ if (object.metadata?.type === "document") {
18
+ const docMetadata = object.metadata as DocumentMetadata;
19
+ return docMetadata.content_processor?.type || "xml";
20
+ }
21
+ return "xml"; // default
22
+ };
23
+
24
+ const processorType = getProcessorType();
25
+
26
+ const renderDownloadOptions = () => {
27
+ if (processorType === "markdown") {
28
+ return (
29
+ <button className="p-2 cursor-pointer hover:bg-slate-50 dark:hover:bg-slate-100" onClick={() => onDownload("document.md")}>
30
+ document.md
31
+ </button>
32
+ );
33
+ }
34
+
35
+ // Default XML processor options
36
+ return (
37
+ <>
38
+ <button className="p-2 cursor-pointer hover:bg-slate-50 dark:hover:bg-slate-100" onClick={() => onDownload("annotated.pdf")}>
39
+ annotated.pdf
40
+ </button>
41
+ <button className="p-2 cursor-pointer hover:bg-slate-50 dark:hover:bg-slate-100" onClick={() => onDownload("document.xml")}>
42
+ document.xml
43
+ </button>
44
+ <button className="p-2 cursor-pointer hover:bg-slate-50 dark:hover:bg-slate-100" onClick={() => onDownload("analyzed-pages.json")}>
45
+ analyzed-pages.json
46
+ </button>
47
+ </>
48
+ );
49
+ };
50
+
15
51
  return (
16
52
  <div className="absolute bottom-[58px] right-[20px] w-[36px] h-[36px] cursor-pointer text-indigo-400 border-indigo-400 hover:border-indigo-500 hover:text-indigo-500 border-2 rounded-full shadow-xs flex items-center justify-center">
17
53
  <Popover strategy='absolute' placement='top-end' zIndex={100} offset={20}>
18
54
  <Popover.Trigger click>
19
55
  <CloudDownload className='size-6' />
20
-
21
56
  </Popover.Trigger>
22
57
  <Popover.Content>
23
58
  <div className="rounded-md shadow-md border border-gray-100 bg-white dark:bg-slate-50 dark:border-slate-100 min-w-[200px] flex flex-col divide-y">
24
- <button className="p-2 cursor-pointer hover:bg-slate-50 dark:hover:bg-slate-100" onClick={() => onDownload("annotated.pdf")}>annotated.pdf</button>
25
- <button className="p-2 cursor-pointer hover:bg-slate-50 dark:hover:bg-slate-100" onClick={() => onDownload("document.xml")}>document.xml</button>
26
- <button className="p-2 cursor-pointer hover:bg-slate-50 dark:hover:bg-slate-100" onClick={() => onDownload("analyzed-pages.json")}>analyzed-pages.json</button>
59
+ {renderDownloadOptions()}
27
60
  </div>
28
61
  </Popover.Content>
29
62
  </Popover>
@@ -1,4 +1,4 @@
1
- import { ContentObject } from "@vertesia/common";
1
+ import { ContentObject, DocumentMetadata } from "@vertesia/common";
2
2
  import { ErrorBox, useFetch } from "@vertesia/ui/core";
3
3
  import { useUserSession } from "@vertesia/ui/session";
4
4
  import { X } from "lucide-react";
@@ -39,8 +39,27 @@ interface _MagicPdfViewProps {
39
39
  onClose?: () => void;
40
40
  }
41
41
  function MagicPdfViewImpl({ object, onClose }: _MagicPdfViewProps) {
42
- const [viewType, setViewType] = useState<ViewType>("xml");
42
+ const getInitialViewType = (): ViewType => {
43
+ if (object.metadata?.type === "document") {
44
+ const docMetadata = object.metadata as DocumentMetadata;
45
+ const processorType = docMetadata.content_processor?.type;
46
+ if (processorType === "markdown") return "markdown";
47
+ if (processorType === "xml") return "xml";
48
+ }
49
+ return "xml"; // default
50
+ };
51
+
52
+ const getProcessorType = (): string => {
53
+ if (object.metadata?.type === "document") {
54
+ const docMetadata = object.metadata as DocumentMetadata;
55
+ return docMetadata.content_processor?.type || "xml";
56
+ }
57
+ return "xml"; // default
58
+ };
59
+
60
+ const [viewType, setViewType] = useState<ViewType>(getInitialViewType());
43
61
  const [pageNumber, setPageNumber] = useState(1);
62
+ const processorType = getProcessorType();
44
63
  const handler = useRef<HTMLDivElement>(null);
45
64
  const left = useRef<HTMLDivElement>(null);
46
65
  const right = useRef<HTMLDivElement>(null);
@@ -51,14 +70,14 @@ function MagicPdfViewImpl({ object, onClose }: _MagicPdfViewProps) {
51
70
  return (
52
71
  <>
53
72
  <div ref={left} className={`absolute top-0 left-0 bottom-0 w-[50%] bg-gray-100 dark:bg-slate-800 flex items-stretch justify-stretch py-2`}>
54
- <PageSlider className="flex-1" currentPage={pageNumber} onChange={setPageNumber} />
73
+ <PageSlider className="flex-1" currentPage={pageNumber} onChange={setPageNumber} object={object} />
55
74
  <div ref={handler} className='w-[2px] p-[2px] m-0 bg-slate-300 cursor-ew-resize'></div>
56
75
  </div>
57
76
  <div ref={right} className={`absolute top-0 left-[50%] right-0 bottom-0 flex items-stretch justify-stretch overflow-auto p-2`}>
58
77
  <TextPageView pageNumber={pageNumber} viewType={viewType} />
59
78
  </div>
60
79
  <DownloadPopover object={object} />
61
- <ContentSwitcher type={viewType} onSwitch={setViewType} />
80
+ {processorType === "xml" && <ContentSwitcher type={viewType} onSwitch={setViewType} />}
62
81
  {!!onClose &&
63
82
  <div className="absolute top-6 right-7 w-9 h-9 cursor-pointer text-red-400 border-red-400 hover:border-red-500 hover:text-red-500 border-2 rounded-full shadow-xs flex items-center justify-center"
64
83
  onClick={onClose}>
@@ -80,6 +99,8 @@ function ContentSwitcher({ type = "xml", onSwitch }: ContentSwitcherProps) {
80
99
  if (type === "xml") {
81
100
  onSwitch("json");
82
101
  } else if (type === "json") {
102
+ onSwitch("markdown");
103
+ } else if (type === "markdown") {
83
104
  onSwitch("xml");
84
105
  }
85
106
  }
@@ -87,7 +108,8 @@ function ContentSwitcher({ type = "xml", onSwitch }: ContentSwitcherProps) {
87
108
  <div className="absolute bottom-[16px] right-[20px] w-[36px] h-[36px] cursor-pointer text-indigo-400 border-indigo-400 hover:border-indigo-500 hover:text-indigo-500 border-2 rounded-full shadow-xs flex items-center justify-center"
88
109
  onClick={_onSwitch}>
89
110
  {type === "xml" && JSON}
90
- {type === "json" && XML}
111
+ {type === "json" && MARKDOWN}
112
+ {type === "markdown" && XML}
91
113
  </div>
92
114
  )
93
115
 
@@ -100,3 +122,7 @@ const JSON = <svg width="16px" height="16px" viewBox="0 0 16 16" xmlns="http://w
100
122
  const XML = <svg width="16px" height="16px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor">
101
123
  <path d="M4.708 5.578L2.061 8.224l2.647 2.646-.708.708-3-3V7.87l3-3 .708.708zm7-.708L11 5.578l2.647 2.646L11 10.87l.708.708 3-3V7.87l-3-3zM4.908 13l.894.448 5-10L9.908 3l-5 10z" />
102
124
  </svg>
125
+
126
+ const MARKDOWN = <svg width="16px" height="16px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="currentColor">
127
+ <path d="M14.85 3H1.15C.52 3 0 3.52 0 4.15v7.69C0 12.48.52 13 1.15 13h13.69c.64 0 1.15-.52 1.15-1.15v-7.7C16 3.52 15.48 3 14.85 3zM9 11H7.5L5.5 9l-1 1.5H3V5h1.5l1 2 2-2H9v6zm2.99.5L9.5 8H11V5h1v3h1.5l-2.51 3.5z"/>
128
+ </svg>
@@ -1,3 +1,4 @@
1
+ import { DocumentMetadata } from "@vertesia/common";
1
2
  import { Center } from "@vertesia/ui/core";
2
3
  import clsx from "clsx";
3
4
  import { AtSignIcon, ChevronsDown, ChevronsUp, ImageIcon, InfoIcon } from "lucide-react";
@@ -6,7 +7,8 @@ import { usePdfPagesInfo } from "./PdfPageProvider";
6
7
 
7
8
  enum ImageType {
8
9
  default,
9
- instrumented,
10
+ original,
11
+ instrumented,
10
12
  annotated,
11
13
  }
12
14
 
@@ -14,11 +16,25 @@ interface PageSliderProps {
14
16
  currentPage: number;
15
17
  onChange: (pageNumber: number) => void;
16
18
  className?: string;
19
+ object: any; // ContentObject type
17
20
  }
18
- export function PageSlider({ className, currentPage, onChange }: PageSliderProps) {
19
- const [imageType, setImageType] = useState<ImageType>(ImageType.default);
21
+ export function PageSlider({ className, currentPage, onChange, object }: PageSliderProps) {
22
+ const getProcessorType = (): string => {
23
+ if (object.metadata?.type === "document") {
24
+ const docMetadata = object.metadata as DocumentMetadata;
25
+ return docMetadata.content_processor?.type || "xml";
26
+ }
27
+ return "xml"; // default
28
+ };
29
+
30
+ const getDefaultImageType = (): ImageType => {
31
+ const processorType = getProcessorType();
32
+ return processorType === "markdown" ? ImageType.original : ImageType.default;
33
+ };
34
+
35
+ const [imageType, setImageType] = useState<ImageType>(getDefaultImageType());
20
36
  const ref = useRef<HTMLDivElement>(null);
21
- const { urls, annotatedUrls, instrumentedUrls } = usePdfPagesInfo();
37
+ const { urls, originalUrls, annotatedUrls, instrumentedUrls } = usePdfPagesInfo();
22
38
  const goPrev = () => {
23
39
  if (currentPage > 1) {
24
40
  onChange(currentPage - 1);
@@ -46,7 +62,8 @@ export function PageSlider({ className, currentPage, onChange }: PageSliderProps
46
62
  }
47
63
 
48
64
  const actualUrls = imageType === ImageType.instrumented ? instrumentedUrls :
49
- (imageType === ImageType.annotated ? annotatedUrls : urls);
65
+ (imageType === ImageType.annotated ? annotatedUrls :
66
+ (imageType === ImageType.original ? originalUrls : urls));
50
67
 
51
68
  return (
52
69
  <div ref={ref} className={clsx('flex flex-col items-stretch gap-y-2', className)}>
@@ -56,15 +73,28 @@ export function PageSlider({ className, currentPage, onChange }: PageSliderProps
56
73
  <ChevronsUp className='w-5 h-5' />
57
74
  </button>
58
75
  <div className="absolute right-3 flex gap-x-1">
59
- <button className={getRadioButtonClass(ImageType.default, imageType)}
60
- onClick={() => setImageType(ImageType.default)}
61
- ><ImageIcon className="w-5 h-5 mt-1" /></button>
62
- <button className={getRadioButtonClass(ImageType.instrumented, imageType)}
63
- onClick={() => setImageType(ImageType.instrumented)}
64
- ><InfoIcon className="w-5 h-5 mt-1" /></button>
65
- <button className={getRadioButtonClass(ImageType.annotated, imageType)}
66
- onClick={() => setImageType(ImageType.annotated)}
67
- ><AtSignIcon className="w-5 h-5 mt-1" /></button>
76
+ {getProcessorType() === "markdown" ? (
77
+ <>
78
+ <button className={getRadioButtonClass(ImageType.original, imageType)}
79
+ onClick={() => setImageType(ImageType.original)}
80
+ ><ImageIcon className="w-5 h-5 mt-1" /></button>
81
+ <button className={getRadioButtonClass(ImageType.instrumented, imageType)}
82
+ onClick={() => setImageType(ImageType.instrumented)}
83
+ ><InfoIcon className="w-5 h-5 mt-1" /></button>
84
+ </>
85
+ ) : (
86
+ <>
87
+ <button className={getRadioButtonClass(ImageType.default, imageType)}
88
+ onClick={() => setImageType(ImageType.default)}
89
+ ><ImageIcon className="w-5 h-5 mt-1" /></button>
90
+ <button className={getRadioButtonClass(ImageType.instrumented, imageType)}
91
+ onClick={() => setImageType(ImageType.instrumented)}
92
+ ><InfoIcon className="w-5 h-5 mt-1" /></button>
93
+ <button className={getRadioButtonClass(ImageType.annotated, imageType)}
94
+ onClick={() => setImageType(ImageType.annotated)}
95
+ ><AtSignIcon className="w-5 h-5 mt-1" /></button>
96
+ </>
97
+ )}
68
98
  </div>
69
99
  </div>
70
100
  <div className='flex flex-col items-center gap-2 flex-1 overflow-y-auto px-2'>
@@ -13,9 +13,11 @@ const ADVANCED_PROCESSING_PREFIX = "magic-pdf";
13
13
  interface PdfPagesInfo {
14
14
  count: number;
15
15
  urls: string[];
16
+ originalUrls: string[];
16
17
  annotatedUrls: string[];
17
18
  instrumentedUrls: string[];
18
19
  layoutProvider: PageLayoutProvider;
20
+ markdownProvider: PageMarkdownProvider;
19
21
  xml: string;
20
22
  xmlPages: string[];
21
23
  }
@@ -54,6 +56,40 @@ class PageLayoutProvider {
54
56
  }
55
57
  }
56
58
 
59
+ class PageMarkdownProvider {
60
+ markdownUrls: string[] = [];
61
+ cache: string[];
62
+ constructor(public totalPages: number) {
63
+ this.cache = new Array<string>(totalPages);
64
+ }
65
+ async loadUrls(vertesia: VertesiaClient, objectId: string) {
66
+ const markdownPromises: Promise<GetFileUrlResponse>[] = [];
67
+ for (let i = 0; i < this.totalPages; i++) {
68
+ markdownPromises.push(getMarkdownUrlForPage(vertesia, objectId, i + 1));
69
+ }
70
+ const markdownUrls = await Promise.all(markdownPromises);
71
+ this.markdownUrls = markdownUrls.map((r) => r.url);
72
+ }
73
+ async getPageMarkdown(page: number) {
74
+ const index = page - 1;
75
+ let content = this.cache[index];
76
+ if (content === undefined) {
77
+ const url = this.markdownUrls[index];
78
+ content = await fetch(url, { method: "GET" }).then((r) => {
79
+ if (r.ok) {
80
+ return r.text();
81
+ } else {
82
+ throw new Error(
83
+ "Failed to fetch markdown: " + r.statusText,
84
+ );
85
+ }
86
+ });
87
+ this.cache[index] = content;
88
+ }
89
+ return content;
90
+ }
91
+ }
92
+
57
93
  const PdfPageContext = createContext<PdfPagesInfo | undefined>(undefined);
58
94
 
59
95
  interface PdfPageProviderProps {
@@ -103,10 +139,22 @@ function getPageInstrumentedImagePath(
103
139
  return `${getBasePath(objectId)}/pages/page-${pageNumber}.instrumented${ext}`;
104
140
  }
105
141
 
142
+ function getPageOriginalImagePath(
143
+ objectId: string,
144
+ pageNumber: number,
145
+ ext = ".jpg",
146
+ ) {
147
+ return `${getBasePath(objectId)}/pages/page-${pageNumber}.original${ext}`;
148
+ }
149
+
106
150
  function getLayoutJsonPath(objectId: string, pageNumber: number) {
107
151
  return `${getBasePath(objectId)}/pages/page-${pageNumber}.layout.json`;
108
152
  }
109
153
 
154
+ function getMarkdownPath(objectId: string, pageNumber: number) {
155
+ return `${getBasePath(objectId)}/pages/page-${pageNumber}.md`;
156
+ }
157
+
110
158
  export function getResourceUrl(
111
159
  vertesia: VertesiaClient,
112
160
  objectId: string,
@@ -147,6 +195,16 @@ function getInstrumentedImageUrlForPage(
147
195
  );
148
196
  }
149
197
 
198
+ function getOriginalImageUrlForPage(
199
+ vertesia: VertesiaClient,
200
+ objectId: string,
201
+ pageNumber: number,
202
+ ): Promise<GetFileUrlResponse> {
203
+ return vertesia.files.getDownloadUrl(
204
+ getPageOriginalImagePath(objectId, pageNumber),
205
+ );
206
+ }
207
+
150
208
  function getLayoutUrlForPage(
151
209
  vertesia: VertesiaClient,
152
210
  objectId: string,
@@ -157,6 +215,16 @@ function getLayoutUrlForPage(
157
215
  );
158
216
  }
159
217
 
218
+ function getMarkdownUrlForPage(
219
+ vertesia: VertesiaClient,
220
+ objectId: string,
221
+ pageNumber: number,
222
+ ): Promise<GetFileUrlResponse> {
223
+ return vertesia.files.getDownloadUrl(
224
+ getMarkdownPath(objectId, pageNumber),
225
+ );
226
+ }
227
+
160
228
  async function getPdfPagesInfo(
161
229
  vertesia: VertesiaClient,
162
230
  object: ContentObject,
@@ -186,17 +254,30 @@ async function getPdfPagesInfo(
186
254
  instrumentedImageUrlPromises,
187
255
  );
188
256
 
257
+ const originalImageUrlPromises: Promise<GetFileUrlResponse>[] = [];
258
+ for (let i = 0; i < page_count; i++) {
259
+ originalImageUrlPromises.push(
260
+ getOriginalImageUrlForPage(vertesia, object.id, i + 1),
261
+ );
262
+ }
263
+ const originalImageUrls = await Promise.all(originalImageUrlPromises);
264
+
189
265
  const layoutProvider = new PageLayoutProvider(page_count);
190
266
  await layoutProvider.loadUrls(vertesia, object.id);
191
267
 
268
+ const markdownProvider = new PageMarkdownProvider(page_count);
269
+ await markdownProvider.loadUrls(vertesia, object.id);
270
+
192
271
  const xml = object.text ? cleanXml(object.text) : "";
193
272
 
194
273
  return {
195
274
  count: page_count,
196
275
  urls: imageUrls.map((r) => r.url),
276
+ originalUrls: originalImageUrls.map((r) => r.url),
197
277
  annotatedUrls: annotatedImageUrls.map((r) => r.url),
198
278
  instrumentedUrls: instrumentedImageUrls.map((r) => r.url),
199
279
  layoutProvider,
280
+ markdownProvider,
200
281
  xml,
201
282
  xmlPages: object.text ? extractXmlPages(xml) : [],
202
283
  };
@@ -1,5 +1,7 @@
1
1
  import { JSONCode, Theme, XMLViewer } from '@vertesia/ui/widgets';
2
2
  import { useEffect, useLayoutEffect, useState } from "react";
3
+ import Markdown from "react-markdown";
4
+ import remarkGfm from "remark-gfm";
3
5
  import { usePdfPagesInfo } from "./PdfPageProvider";
4
6
  import { ViewType } from "./types";
5
7
 
@@ -19,7 +21,14 @@ interface TextPageViewProps {
19
21
  viewType: ViewType;
20
22
  }
21
23
  export function TextPageView({ viewType, pageNumber }: TextPageViewProps) {
22
- return viewType === "json" ? <JsonPageLayoutView pageNumber={pageNumber} /> : <XmlPageView pageNumber={pageNumber} />
24
+ switch (viewType) {
25
+ case "json":
26
+ return <JsonPageLayoutView pageNumber={pageNumber} />;
27
+ case "markdown":
28
+ return <MarkdownPageView pageNumber={pageNumber} />;
29
+ default:
30
+ return <XmlPageView pageNumber={pageNumber} />;
31
+ }
23
32
  }
24
33
 
25
34
  interface XmlPageViewProps {
@@ -62,3 +71,22 @@ function JsonPageLayoutView({ pageNumber }: JsonPageLayoutViewProps) {
62
71
  content && <JSONCode className="w-full" data={content} />
63
72
  )
64
73
  }
74
+
75
+ interface MarkdownPageViewProps {
76
+ pageNumber: number;
77
+ }
78
+ function MarkdownPageView({ pageNumber }: MarkdownPageViewProps) {
79
+ const [content, setContent] = useState<string>();
80
+ const { markdownProvider } = usePdfPagesInfo();
81
+ useEffect(() => {
82
+ markdownProvider.getPageMarkdown(pageNumber).then(setContent).catch((err: any) => {
83
+ console.error(err);
84
+ setContent(undefined);
85
+ });
86
+ }, [pageNumber]);
87
+ return (
88
+ <div className="px-4 py-2 prose prose-sm max-w-none dark:prose-invert">
89
+ {content ? <Markdown remarkPlugins={[remarkGfm]}>{content}</Markdown> : <div>No markdown content available</div>}
90
+ </div>
91
+ )
92
+ }
@@ -1 +1 @@
1
- export type ViewType = "xml" | "json";
1
+ export type ViewType = "xml" | "json" | "markdown";
@@ -28,7 +28,7 @@ export function DocumentTableView({ objects, selection, isLoading, onRowClick, c
28
28
  ))}
29
29
  </tr>
30
30
  </thead>
31
- <TBody isLoading={isLoading} columns={columns.length}>
31
+ <TBody isLoading={isLoading} columns={columns.length + 1}>
32
32
  {
33
33
  objects?.map((obj: ContentObjectItem) => {
34
34
  return (