Skip to content

Commit f281f00

Browse files
authored
Merge pull request #57 from kleros/feat/file-viewer
Feat/file viewer
2 parents b3669b8 + bfc8900 commit f281f00

File tree

19 files changed

+707
-38
lines changed

19 files changed

+707
-38
lines changed

web/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
"vite-tsconfig-paths": "^5.0.1"
7373
},
7474
"dependencies": {
75+
"@cyntler/react-doc-viewer": "^1.17.0",
7576
"@filebase/client": "^0.0.5",
7677
"@kleros/curate-v2-templates": "workspace:^",
7778
"@kleros/ui-components-library": "^2.13.1",

web/src/app.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import SubmitItem from "./pages/SubmitItem";
1616
import SubmitList from "./pages/SubmitList";
1717
import { RegistryDetailsProvider } from "context/RegistryDetailsContext";
1818
import { SubmitListProvider } from "./context/SubmitListContext";
19+
import AttachmentDisplay from "./pages/AttachmentDisplay";
1920

2021
const App: React.FC = () => {
2122
return (
@@ -39,6 +40,7 @@ const App: React.FC = () => {
3940
}
4041
/>
4142
<Route path="submit-list/*" element={<SubmitList />} />
43+
<Route path="attachment/*" element={<AttachmentDisplay />} />
4244
<Route path="*" element={<h1>404 not found</h1>} />
4345
</Route>
4446
</SentryRoutes>
Lines changed: 10 additions & 0 deletions
Loading
Lines changed: 3 additions & 0 deletions
Loading
Lines changed: 17 additions & 0 deletions
Loading
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import React from "react";
2+
import styled from "styled-components";
3+
4+
import { type DocRenderer } from "@cyntler/react-doc-viewer";
5+
import ReactMarkdown from "react-markdown";
6+
7+
const Container = styled.div`
8+
padding: 16px;
9+
`;
10+
11+
const StyledMarkdown = styled(ReactMarkdown)`
12+
background-color: ${({ theme }) => theme.whiteBackground};
13+
a {
14+
font-size: 16px;
15+
}
16+
code {
17+
color: ${({ theme }) => theme.secondaryText};
18+
}
19+
`;
20+
21+
const MarkdownRenderer: DocRenderer = ({ mainState: { currentDocument } }) => {
22+
if (!currentDocument) return null;
23+
const base64String = (currentDocument.fileData as string).split(",")[1];
24+
25+
// Decode the base64 string
26+
const decodedData = atob(base64String);
27+
28+
return (
29+
<Container id="md-renderer">
30+
<StyledMarkdown>{decodedData}</StyledMarkdown>
31+
</Container>
32+
);
33+
};
34+
35+
MarkdownRenderer.fileTypes = ["md", "text/plain"];
36+
MarkdownRenderer.weight = 1;
37+
38+
export default MarkdownRenderer;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import React from "react";
2+
import styled from "styled-components";
3+
4+
import DocViewer, { DocViewerRenderers } from "@cyntler/react-doc-viewer";
5+
6+
import "@cyntler/react-doc-viewer/dist/index.css";
7+
8+
import MarkdownRenderer from "./Viewers/MarkdownViewer";
9+
import { customScrollbar } from "styles/customScrollbar";
10+
11+
const Wrapper = styled.div`
12+
background-color: ${({ theme }) => theme.whiteBackground};
13+
border-radius: 3px;
14+
box-shadow: 0px 2px 3px 0px rgba(0, 0, 0, 0.06);
15+
max-height: 1050px;
16+
overflow: scroll;
17+
18+
${customScrollbar}
19+
`;
20+
21+
const StyledDocViewer = styled(DocViewer)`
22+
background-color: ${({ theme }) => theme.whiteBackground} !important;
23+
`;
24+
25+
/**
26+
* @description this viewer supports loading multiple files, it can load urls, local files, etc
27+
* @param url The url of the file to be displayed
28+
* @returns renders the file
29+
*/
30+
const FileViewer: React.FC<{ url: string }> = ({ url }) => {
31+
const docs = [{ uri: url }];
32+
return (
33+
<Wrapper className="file-viewer-wrapper">
34+
<StyledDocViewer
35+
documents={docs}
36+
pluginRenderers={[...DocViewerRenderers, MarkdownRenderer]}
37+
config={{
38+
header: {
39+
disableHeader: true,
40+
disableFileName: true,
41+
},
42+
pdfZoom: {
43+
defaultZoom: 0.8,
44+
zoomJump: 0.1,
45+
},
46+
pdfVerticalScrollByDefault: true, // false as default
47+
}}
48+
/>
49+
</Wrapper>
50+
);
51+
};
52+
53+
export default FileViewer;

web/src/components/HistoryDisplay/Party/JustificationDetails.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { getIpfsUrl } from "utils/getIpfsUrl";
55
import AttachmentIcon from "svgs/icons/attachment.svg";
66
import { customScrollbar } from "styles/customScrollbar";
77
import { Evidence } from "src/graphql/graphql";
8+
import { Link } from "react-router-dom";
89

910
const Container = styled.div`
1011
width: 100%;
@@ -24,7 +25,7 @@ const DescriptionContainer = styled.div`
2425
${customScrollbar}
2526
`;
2627

27-
const StyledA = styled.a`
28+
const StyledA = styled(Link)`
2829
display: flex;
2930
gap: 6px;
3031
> svg {
@@ -43,7 +44,7 @@ const JustificationDetails: React.FC<{ justification: Justification }> = ({ just
4344
<ReactMarkdown>{justification.description ?? "Unable to determine description"}</ReactMarkdown>
4445
</DescriptionContainer>
4546
{justification?.fileURI && (
46-
<StyledA href={getIpfsUrl(justification.fileURI)}>
47+
<StyledA to={`/attachment/?url=${getIpfsUrl(justification.fileURI)}`}>
4748
<AttachmentIcon />
4849
View attached file
4950
</StyledA>

web/src/components/InformationCards/RegistryInformationCard/Policies.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { responsiveSize } from "styles/responsiveSize";
77
import { getIpfsUrl } from "utils/getIpfsUrl";
88
import { useRegistryDetailsQuery } from "queries/useRegistryDetailsQuery";
99
import { MAIN_CURATE_ADDRESS } from "src/consts";
10+
import { Link } from "react-router-dom";
1011

1112
const ShadeArea = styled.div`
1213
display: flex;
@@ -37,7 +38,7 @@ const StyledP = styled.p`
3738
)};
3839
`;
3940

40-
const StyledA = styled.a`
41+
const StyledA = styled(Link)`
4142
display: flex;
4243
align-items: center;
4344
gap: 4px;
@@ -69,11 +70,7 @@ export const Policies: React.FC<IPolicies> = ({ policyURI, isItem }) => {
6970
{!isItem ? (
7071
<>
7172
{parentRegistryDetails ? (
72-
<StyledA
73-
href={getIpfsUrl(parentRegistryDetails.registry.policyURI ?? "")}
74-
target="_blank"
75-
rel="noreferrer"
76-
>
73+
<StyledA to={`/attachment/?url=${getIpfsUrl(parentRegistryDetails.registry.policyURI ?? "")}`}>
7774
<StyledPolicyIcon />
7875
Curation Policy
7976
</StyledA>
@@ -83,7 +80,7 @@ export const Policies: React.FC<IPolicies> = ({ policyURI, isItem }) => {
8380
</>
8481
) : null}
8582
{policyURI ? (
86-
<StyledA href={getIpfsUrl(policyURI)} target="_blank" rel="noreferrer">
83+
<StyledA to={`/attachment/?url=${getIpfsUrl(policyURI)}`}>
8784
<StyledPolicyIcon />
8885
List Policy
8986
</StyledA>

web/src/components/InformationCards/RegistryInformationCard/TopInfo.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { isUndefined } from "src/utils";
1111
import { DEFAULT_LIST_LOGO } from "src/consts";
1212
import { getIpfsUrl } from "utils/getIpfsUrl";
1313
import { shortenAddress } from "utils/shortenAddress";
14+
import { Link } from "react-router-dom";
1415

1516
const TopInfoContainer = styled.div`
1617
display: flex;
@@ -122,12 +123,14 @@ const TopInfo: React.FC<ITopInfo> = ({
122123
{isUndefined(logoURI) ? (
123124
<SkeletonLogo />
124125
) : (
125-
<StyledLogo
126-
src={imageSrc}
127-
onError={() => setImageSrc(getIpfsUrl(DEFAULT_LIST_LOGO))}
128-
alt="List Img"
129-
isListView={false}
130-
/>
126+
<Link to={`/attachment/?url=${imageSrc}`}>
127+
<StyledLogo
128+
src={imageSrc}
129+
onError={() => setImageSrc(getIpfsUrl(DEFAULT_LIST_LOGO))}
130+
alt="List Img"
131+
isListView={false}
132+
/>
133+
</Link>
131134
)}
132135
{isUndefined(title) ? <SkeletonTitle /> : <StyledTitle>{title}</StyledTitle>}
133136
</LogoAndTitle>

0 commit comments

Comments
 (0)