Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ yarn-debug.log*
yarn-error.log*

*storybook.log

# yarn pack output (local-test artifact)
*.tgz
Comment thread
kemuru marked this conversation as resolved.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@kleros/ui-components-library",
"version": "3.7.0",
"version": "3.8.0",
"description": "UI components library which implements the Kleros design system.",
"source": "./src/lib/index.ts",
"main": "./dist/index.js",
Expand Down Expand Up @@ -91,6 +91,7 @@
"tailwindcss": "^4.0.11"
},
"dependencies": {
"@cyntler/react-doc-viewer": "^1.17.0",
"@internationalized/date": "^3.7.0",
"bignumber.js": "^9.1.2",
"clsx": "^2.1.1",
Expand All @@ -99,6 +100,7 @@
"react-aria-components": "^1.7.1",
"react-dom": "^18.0.0",
"react-is": "^18.0.0",
"react-markdown": "^9.0.1",
"simplebar": "^5.3.6",
"simplebar-react": "^2.3.6",
"tailwind-merge": "^3.0.2",
Expand Down
76 changes: 76 additions & 0 deletions src/lib/file-viewer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React, { useMemo } from "react";
import DocViewer, {
DocViewerRenderers,
type IConfig,
} from "@cyntler/react-doc-viewer";

import { cn } from "../../utils";
import MarkdownDocRenderer from "./markdown-viewer";
import "@cyntler/react-doc-viewer/dist/index.css";
import "./styles.css";

interface FileViewerProps {
/** URL of the file to display. Supports URLs, blob URLs, data URIs, and IPFS URIs. */
url: string;
/** Optional file name override (used for download). Useful for IPFS URIs that lack one. */
fileName?: string;
/** Override the DocViewer config. Merged shallowly over the defaults. */
config?: IConfig;
/** Class applied to the outer wrapper. */
className?: string;
}

const defaultConfig: IConfig = {
header: {
disableHeader: true,
disableFileName: true,
},
pdfZoom: {
defaultZoom: 0.8,
zoomJump: 0.1,
},
pdfVerticalScrollByDefault: true,
};

/**
* In-app viewer for policies, evidence attachments, and arbitrary file-URI
Comment thread
kemuru marked this conversation as resolved.
Outdated
* links. Supports PDFs, images, markdown, plaintext, and common document
* formats via `@cyntler/react-doc-viewer`.
Comment thread
kemuru marked this conversation as resolved.
Outdated
*/
function FileViewer({
url,
fileName,
config,
className,
}: Readonly<FileViewerProps>) {
const docs = useMemo(() => [{ uri: url, fileName }], [url, fileName]);

const pluginRenderers = useMemo(
() => [...DocViewerRenderers, MarkdownDocRenderer],
[],
);

const mergedConfig = useMemo<IConfig>(
() => ({ ...defaultConfig, ...config }),
[config],
);

return (
<div
className={cn(
"bg-klerosUIComponentsWhiteBackground shadow-default",
"max-h-[80vh] overflow-auto rounded-[3px]",
Comment thread
kemuru marked this conversation as resolved.
Outdated
className,
)}
>
<DocViewer
documents={docs}
pluginRenderers={pluginRenderers}
config={mergedConfig}
className="kleros-file-viewer-doc"
/>
</div>
);
}

export default FileViewer;
29 changes: 29 additions & 0 deletions src/lib/file-viewer/markdown-viewer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from "react";
import { type DocRenderer } from "@cyntler/react-doc-viewer";
import ReactMarkdown from "react-markdown";

const MarkdownDocRenderer: DocRenderer = ({
mainState: { currentDocument },
}) => {
if (!currentDocument) return null;

const fileData = currentDocument.fileData as string;
const base64String = fileData.includes(",")
? fileData.split(",")[1]
: fileData;
const decodedData = atob(base64String);

Comment thread
kemuru marked this conversation as resolved.
Outdated
return (
<div
id="md-renderer"
className="text-klerosUIComponentsPrimaryText [&_code]:text-klerosUIComponentsSecondaryText p-4 [&_a]:text-base"
>
<ReactMarkdown>{decodedData}</ReactMarkdown>
</div>
);
};

MarkdownDocRenderer.fileTypes = ["md", "text/plain"];
MarkdownDocRenderer.weight = 1;

export default MarkdownDocRenderer;
11 changes: 11 additions & 0 deletions src/lib/file-viewer/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.kleros-file-viewer-doc {
Comment thread
kemuru marked this conversation as resolved.
Outdated
background-color: var(--klerosUIComponentsWhiteBackground) !important;
}

.kleros-file-viewer-doc #pdf-controls {
z-index: 3;
}

.kleros-file-viewer-doc [class*="--loading"] {
color: var(--klerosUIComponentsSecondaryText);
}
2 changes: 2 additions & 0 deletions src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,5 @@ export { default as ScrollbarContainer } from "../lib/scrollbar";
export { default as Copiable } from "../lib/copiable";

export { default as DraggableList } from "../lib/draggable-list";

export { default as FileViewer } from "../lib/file-viewer";
35 changes: 35 additions & 0 deletions src/stories/file-viewer.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { Meta, StoryObj } from "@storybook/react";

import { IPreviewArgs } from "./utils";

import FileViewerComponent from "../lib/file-viewer";

const meta = {
component: FileViewerComponent,
title: "File Viewer",
tags: ["autodocs"],
} satisfies Meta<typeof FileViewerComponent>;

export default meta;

type Story = StoryObj<typeof meta> & IPreviewArgs;

export const FileViewer: Story = {
args: {
themeUI: "light",
backgroundUI: "light",
className: "w-[800px]",
url: "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
},
};

export const Image: Story = {
args: {
themeUI: "light",
backgroundUI: "light",
className: "w-[800px]",
url:
"https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/" +
"PNG_transparency_demonstration_1.png/280px-PNG_transparency_demonstration_1.png",
},
};
Loading
Loading